TowardsDataScience-博客中文翻译-2020-七十-
TowardsDataScience 博客中文翻译 2020(七十)
在 TensorFlow 中实现点柱
点柱是一个非常著名的三维物体检测算法,由于其快速的推理速度,在激光雷达上生成点云。在本文中,我们将在 TensorFlow 中浏览它的实现代码。
如果你想开始 3D 物体检测,更具体地说是点柱,我有一系列的帖子专门为此写的。下面是环节。此外,直接阅读的要点文章会对更好地理解这篇文章很有帮助,然而,这不是先决条件。
本教程 github Repo:【https://github.com/tyagi-iiitv/PointPillars】T4。感谢弗朗西斯科·费乐理提供的初始代码。
内容
- 定义初始配置
- 建筑点柱网络
- 损失函数
- Kitti 数据集的数据读取器
- 培养
- 推理
定义初始配置(config.py)

在 config.py 文件中定义配置
我们定义初始配置,包括 x,y,z 维度的限制。这些限制定义了我们将要预测边界框的感兴趣区域。由于激光雷达的范围通常很大,我们将重点放在这个空间中由这些限制定义的较小区域。其他配置包括支柱的最大数量、每个支柱的最大点数等。

关于点柱网络的配置。
这些配置通常用于将点云从 3D 坐标转换为点柱检测管道中的点柱坐标,如下一节所述。现在,只要记住所有的配置都是在这个文件中定义的。
构建点柱网络(network.py)
点柱的整体架构包含三个组件:一个柱特征网、一个主干 2D CNN 和一个探测头。我们将分别讨论这三个组件。

点柱式建筑。它由三部分组成:一个支柱特征网,一个骨干 2D CNN 和一个探测头。(来源)
支柱特征网

支柱特征网络架构。
- 柱子/输入(输入层)(4,12000,100,7)指——批量大小(4),最大柱子数(12000),每个柱子最大点数(100),7 dim 向量:[x,y,z,intensity,Xc,Yc,Zc]。 X、y、z 是点云中某个点的 3D 坐标,激光雷达设备测得的该点的强度存储在“强度”中,Xc、Yc、Zc 存储该点在每个维度上与柱子中心的距离。
- 这个输入现在从 7 维转换到 64 维向量,使用 CNN 提取特征。
- 柱子/索引(InputLayer) (4,12000,3)指的是— 批量大小,最大柱子数,以及每个柱子的中心,即 x,y 和 z 坐标。该层包含每个支柱的中心,用于将每个支柱的学习特征映射回支柱/散射 _ nd(λ)层中的 x-y 网格。
- pillars/scatter _ nd(Lambda)-使用上述图层中的 X,y 坐标,将点云空间划分为(504 X 504) x-y 格网,每个格网单元包含相应支柱的 64 个要素。
骨干 2D 有线电视新闻网
这是一个非常简单的图层,输入是编码在 x-y 格网中的支柱要素,如前一节所述。该网格被视为一幅图像,并被转换成不同的尺度,在这些尺度上提取特征并最终连接起来。我们试图从不同尺度的点云中捕捉特征,并将它们连接成一个单一的张量。


骨干 2D CNN。具有编码的柱子特征的 x-y 网格被变换成不同的尺度,其特征被提取和连接。
探测头

探测头网络结构。
在这一部分中,我们预测锚盒的回归目标,如下所述。所有这些预测都是针对 x-y 坐标(252 X 252)中的每个网格单元的。在这种情况下,边界框不是直接预测的,而是调整初始锚框的大小以生成预测的边界框。初始定位框在 config.py 文件中提供。
- 占用-预测标注是否包含元素。1 —是或否。因此,我们只需要在占用率为 1 时检查其他预测(位置、大小、角度、航向和 clf)。
- Loc 包含相应锚定框的 x,y,z 增量。
- 大小—包含相应锚定框的长度、宽度和高度的增量。
- 角度-包含偏航差值。
- 航向—如果角度> 90 度,则包含此选项,以检查对象的航向角度。
- Clf 包含每个预测的分类 id 和置信度得分。
注意,检测头预测每个网格单元 4 个边界框,并且每个边界框具有上面列出的属性。
损失函数(loss.py)
一旦我们决定了网络体系结构,我们就创建损失函数来完成训练过程定义。正如您在 loss.py 文件中看到的,我们正在计算每个回归目标的损失值,并将它们与分配给每个误差的权重相加。因此,最终损失值将是每个损失值的加权和。

分配给每个损失值的权重。(Config.py 文件)
focal_weight*focal_loss + loc_weight*loc_loss + size_weight*size_loss + angle_weight*angle_loss +
...
Kitti 数据集的数据读取器(readers.py)
我们设计了一个类来读取 Kitti 数据集中的文件,并从标签(txt)文件中提取 3D 边界框尺寸。标签文件中的每一行都包含以下信息:

Kitti 数据集中的标签文件
- 物体的类型(汽车、卡车等。)
- 截断浮点数,0 表示截断,1 表示未截断
- 遮挡状态,0 =完全可见,1 =部分遮挡,2 =大部分遮挡,3 =未知
- 阿尔法观察角
- 4 2D 边界框参数(中心、长度、宽度)
- 3D 对象尺寸(高度、宽度、长度)
- 相机坐标中的 3D 对象位置(x,y,z)
- 偏航角
培训(point_pillars_training_run.py,processors.py,src/point_pillars.cpp)
在为 Kitti 数据集中的每个数据点定义损失函数、配置和数据生成器之后, processor.py 文件中的 SimpleDataGenerator 生成训练示例。这一过程的主要步骤是:
- 生成立柱和立柱 id(data processor . make _ point _ Pillars在 processor.py 文件中)
- 从标签文件和 config.py 文件中给定的锚定框生成回归目标(如上所述)。(data processor . make _ ground _ truthinside processor . py 文件)
这两个任务的助手函数在 src/ point_pillars.cpp 文件中提供,该文件包含在使用 Pybind 的当前 python 代码中。
- create pillars(src/point _ pillars . CPP)-生成最大数量的支柱,并为每个支柱指定支柱中心。如果柱内的点数小于最大点数,则使用零填充,否则使用随机采样。每个支柱将有 100 个点,每个点有 7 个值(x,y,z,强度,Xc,Yc,Zc)。我们从(0,0)激光雷达坐标开始,并在视野中径向扩展,直到我们达到最大数量的柱子。

我们从视野中的起点开始扩展,为每个网格单元生成支柱。重复这个过程,直到我们编码了最大数量的柱子。
- createPillarsTarget(src/point _ pillars . CPP)-生成可用于稍后计算损失值的回归目标。对于标签文件中给定的每个 3D 边界框,它将与锚框进行比较。首先,基于对象尺寸(下面网格上的红色圆圈)在原始边界框周围创建一个搜索半径。然后,对于该半径内的每个网格单元,放置锚框,并在每个锚框和原始边界框之间计算 IoU。

给定实际边界框,生成回归目标的过程。

计算并集上的交集。这是通过在训练期间比较锚框和实际边界框来生成回归目标的关键步骤。(来源:pyimagesearch.com)
如果 IoU 值高于某个阈值,则目标(x、y、z、长度、宽度、高度、偏航等。)被存储用于该边界框。否则,如果没有锚超过阈值,则为该网格单元选择并存储基于 IoU 分数的最佳锚。如上所述,这些值随后用于计算损失值。
推论(point_pillars_prediction.py)
这个代码库的最后一部分是用于推理的point _ pillars _ prediction . py文件。在我们已经基于前面描述的损失函数训练了网络之后,在推断阶段,网络的输出是每个预测的回归目标、占用指数和分类置信度值。您可以验证对于每个格网像元,网络输出 4 个边界框及其各自的参数。
我们可以基于占用率指数移除大多数预测的框,因为我们只想要占用率为 1 的框,这意味着网络实际上已经预测了该网格单元上的边界框。尽管如此,对于相同的对象,可能有许多由网络预测的边界框。为了过滤这些,我们可以使用非最大值抑制,并得出最终的边界框预测。非最大值抑制基于 IoU 及其分类置信度值对边界框进行排序,并选择具有最佳值的边界框作为最终边界框。参考这个帖子阅读更多关于非最大抑制。

当多个边界框被对象检测算法预测时,非最大值抑制收敛到最终的边界框。(来源:towardsdatascience.com)
结论
这篇文章详细介绍了 Tensorflow 上点支柱的实现。包括配置文件、模型实现、数据生成器、训练和推理在内的所有代码细节都用代码示例进行了解释。代码可以在这个 Github repo 中找到,可以用来试验本文中给出的细节。作为下一步,我们正致力于在 Kitti 数据上生成推理结果,这些结果将发布在 Github repo 上。
如果你有兴趣参与这个项目,请查看 GitHub repo 上的问题。
用 Numpy 实现递归神经网络
入门
关于如何使用 Numpy 实现递归神经网络的综合教程

介绍
递归神经网络(RNN)是最早能够在自然语言处理领域提供突破的神经网络之一。这个网络的美妙之处在于它能够存储以前序列的记忆,因此它们也被广泛用于时间序列任务。像 Tensorflow 和 PyTorch 这样的高级框架抽象了这些神经网络背后的数学,使得任何人工智能爱好者都难以用正确的参数和层知识来编码深度学习架构。为了解决这些类型的低效率,这些网络背后的数学知识是必要的。通过帮助人工智能爱好者理解研究论文中的不同符号并在实践中实现它们,从头开始编写这些算法具有额外的优势。
如果你对 RNN 的概念不熟悉,请参考 MIT 6。S191 课程,这是最好的讲座之一,让你直观地了解 RNN 是如何运作的。这些知识将帮助您理解本教程中解释的不同符号和概念实现。
最终目标
这个博客的最终目标是让 AI 爱好者对他们从深度学习领域的研究论文中获得的理论知识进行编码。
参数初始化
与传统的神经网络不同,RNN 拥有 3 个权参数,即输入权、内部状态权(用于存储记忆)和输出权。我们首先用随机值初始化这些参数。我们将 word_embedding 维数和 output 维数分别初始化为 100 和 80。输出维度是词汇表中出现的唯一单词的总数。
权重初始化器
变量 prev_memory 指的是 internal_state(这些是前面序列的内存)。用于更新权重的梯度等其他参数也已初始化。输入 _ 权重梯度、内部 _ 状态 _ 权重梯度和输出 _ 权重梯度分别被命名为杜 、 dW 和 dV 。变量bptt _ truncate指的是网络在反向传播时必须回顾的时间戳的数量,这样做是为了克服消失梯度问题。
正向传播直觉:
输入和输出向量:
考虑到我们有一句话 “我喜欢玩。”。词汇表中的 假设 I 映射到索引 2, 像 映射到索引 45 , 到 在索引 10 和 在索引 64 和标点符号在索引 1 处。为了获得从输入到输出的真实场景,让我们为每个单词随机初始化 word_embedding。
注意 : 你也可以尝试对每个单词使用一个 hot 编码向量,并将其作为输入传递。
现在我们已经完成了输入,我们需要考虑每个单词输入的输出。RNN 单元应该输出当前输入的下一个最可能的单词。为了训练 RNN,我们提供了第 t+1 个 字作为第 个 输入值的输出,例如:RNN 单元格应该输出字 ,就像给定的输入字一样**
既然输入是以嵌入向量的形式,那么计算损失所需的输出格式应该是一次性编码的向量。对于输入字符串中除第一个单词之外的每个单词都要这样做,因为我们只考虑这个神经网络要学习的一个例句,而初始输入是句子的第一个单词。**
我们为什么要对输出的字进行一次性编码?
原因是,原始输出只是每个单词的分数,它们对我们来说并不重要。相反,我们需要每个单词相对于前一个单词的 概率 。
我们如何从原始输出值中找到概率?
为了解决这个问题,在得分向量上使用了一个 softmax 激活函数,使得所有这些概率加起来等于 1。 Img 1 显示单个时间戳的输入输出管道。顶行是 ground _truth 输出,第二行表示预测输出。

img 1:RNN 的输入和输出管道,图片由作者提供
注意: 在实现过程中我们需要注意 output_mapper 的键值。我们需要用其时间戳值重置键值,以便算法知道在特定时间戳需要使用哪个基本事实字来计算损失。
***Before reset:
45: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])After reset:
{0: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])***
RNN 盒子计算:
现在我们有了权重,也知道了如何传递输入,也知道了预期的输出,我们将从正向传播计算开始。训练神经网络需要以下计算。

Img 2:作者图片
这里的 U 表示输入 _ 权重, W 表示内部 _ 状态 _ 权重, V 表示输出权重。输入权重乘以输入( x ),内部 _ 状态 _ 权重乘以之前的激活,在我们的符号中是 prev_memory 。层间使用的激活函数是 Tanh。它提供非线性,最终有助于学习。
注意: 在本教程中,不使用 RNN 计算的偏差术语,因为它会导致更复杂的理解。
由于上面的代码只计算一个特定时间戳的输出,我们现在必须对整个单词序列的前向传播进行编码。
在下面的代码中, 输出字符串 包含每个时间戳的输出向量列表。 内存 是一个字典,其中包含每个时间戳的参数,这些参数在反向传播期间是必不可少的。
损失计算:
我们还将损失或误差定义为交叉熵损失,由下式给出:**

Img 3:作者图片
最重要的是,我们需要在上面的代码中查看第 行和第 行。众所周知,地面真实输出( y )的形式为[0,0,…。,1,..0]和 predicted _ output()的形式是[0.34,0.03,…,0.45],我们需要损失是一个单一的值来从中推断总损失。为此,我们使用 求和函数 来获得该特定时间戳的 y 和 y^hat 向量中每个值的差值/误差之和。total_loss 是包括所有时间戳在内的整个模型的损失。**
反向传播
如果你听说过反向传播,那么你一定听说过链式法则,它是计算梯度的重要方面。

Img 4:作者图片

Img 5:作者图片
根据上面的 Img 4 ,成本 C 表示误差,这是 y^hat 达到 y 所需的变化。由于成本是激活 a、 的函数输出,激活反映的变化由 dCost/da 表示。 实际上是指从激活节点 的角度看的变化(误差)值。 类似地,激活相对于的变化由 da/dz 和 z 相对于wdw/dz 给出。我们关心的是重量的变化(误差)有多大。由于重量和成本之间没有直接关系,所以从成本到重量的中间变化值会相乘(如上述等式所示)。********
RNN 反向传播:
因为 RNN 有三个重量,我们需要三个梯度。input _ weights(dLoss/dU)、internal _ state _ weights(dLoss/dW)和 output _ weights(dLoss/dV)的渐变。**
这三个梯度的链可以表示如下:

:

img 6:RNN 使用的权重梯度方程,图片由作者提供
注意 :这里的 T 代表转置。
dLoss/dy _ unactivated编码如下:
为了了解更多关于损失衍生品的信息,请参考这篇博客。我们将计算两个梯度函数,一个是乘法 _ 后退,另一个是加法 _ 后退。在乘法 _ 反向的情况下,我们返回 2 个参数,一个是关于权重的梯度( dLoss/dV ),另一个是链梯度,其将是链的一部分以计算另一个权重梯度。在加法向后的情况下,在计算导数时,我们发现加法函数(ht _ unactivated)中单个分量的导数为 1。例如:DH _ unactivated/dU _ frd= 1 as(h _ unactivated=U _ frd+W _ frd _)以及dU _ frd/dU _ frd= 1。但是 1 的个数是相对于 U_frd 的维数而言的。要了解更多关于渐变的信息,你可以参考这个源。就是这样,计算梯度只需要这两个函数。 乘法 _ 后退 函数用于包含矢量点积的方程,而 加法 _ 后退 函数用于包含两个矢量相加的方程。**

Img 7:下面编码的梯度函数背后的数学直觉,图片由作者提供
现在,您已经分析并理解了 RNN 的反向传播,是时候为单个时间戳实现它了,这将在以后用于计算所有时间戳的梯度。如下面的代码所示, forward_params_t 是一个包含网络在特定时间步长的前向参数的列表。变量 ds 是一个至关重要的部分,因为这行代码考虑了先前时间戳的隐藏状态,这将有助于提取反向传播时所需的足够有用的信息。
对于 RNN,由于消失梯度问题,我们将使用截断反向传播,而不是使用普通反向传播。在这种技术中,当前单元将向后看 k 个时间戳,而不是只向后看一个时间戳,其中 k 表示要向后看的先前单元的数量,以便检索更多的知识。
更新权重:
一旦我们使用反向传播计算了梯度,我们必须更新权重,这是使用批量梯度下降方法完成的。
训练序列:
一旦我们把所有的功能都准备好了,我们就可以进入高潮了,也就是训练神经网络。考虑用于训练的学习率是静态的,您甚至可以使用基于使用步长衰减的动态方法来改变学习率。

Img 7:损失-产出,按作者分类的图像
结论:
现在你已经实现了一个递归神经网络,是时候向前迈出一步,使用像 LSTM 和 GRU 这样的高级架构,以更有效的方式利用隐藏状态来保留更长序列的含义。还有很长的路要走。随着 NLP 领域的大量进步,出现了高度复杂的算法,如 Elmo 和 Bert。理解它们,并尝试自己实现。它遵循同样的记忆概念,但引入了加权单词的元素。由于这些模型高度复杂,使用 Numpy 是不够的,而是灌输 PyTorch 或 TensorFlow 的技能来实现它们,并构建可以服务于社区的惊人的 AI 系统。
创建本教程的灵感来自这个 github 博客。
你可以在这里访问本教程的笔记本。
希望你们都喜欢这个教程!
参考文献:
[1]萨古尔·斯里哈里,RNN-Gradients,https://cedar . buffalo . edu/~斯里哈里/CSE 676/10 . 2 . 2% 20 rnn-Gradients . pdf
[2]https://github.com/pangolulu/rnn-from-scratch 龚玉【RNN】从无到有
从头开始实施 SGD
无 SKlearn 的随机梯度下降的自定义实现
在实现随机梯度下降之前,让我们来谈谈什么是梯度下降。
梯度下降算法是一种用于求解优化问题的迭代算法。在几乎每个机器学习和深度学习模型中,梯度下降都被积极地用于改善我们算法的学习。
读完这篇博客后,你会知道梯度下降算法实际上是如何工作的。在这篇博客的最后,我们将比较我们的自定义 SGD 实现和 SKlearn 的 SGD 实现。
梯度下降算法是如何工作的?
- 选取一个初始随机点 x0。
- x1 = x0 - r [(df/dx) of x0]
- x2 = x1- r [(df/dx) of x1]
- 类似地,我们发现对于 x0,x1,x2 ……。x[k-1]
这里 r 是学习率,df/dx 是最小化我们损失的梯度函数。


用小批量实现线性 SGD
在小批量 SGD 中,在计算关于训练集子集的误差梯度之后,更新参数。
让我们以 Kaggle 的波士顿住房数据集为例。
首先,我们将导入所有必需的库。
**import** **warnings**
warnings.filterwarnings("ignore")
**from** **sklearn.datasets** **import** load_boston
**from** **random** **import** seed
**from** **random** **import** randrange
**from** **csv** **import** reader
**from** **math** **import** sqrt
**from** **sklearn** **import** preprocessing
**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**
**import** **matplotlib.pyplot** **as** **plt**
**from** **prettytable** **import** PrettyTable
**from** **sklearn.linear_model** **import** SGDRegressor
**from** **sklearn** **import** preprocessing
**from** **sklearn.metrics** **import** mean_squared_error
**from** **sklearn.model_selection** **import** train_test_split
现在,我们将加载数据集。这里,X 包含我们拥有的数据集,Y 包含我们需要预测的标签。
X = load_boston().data
Y = load_boston().target
记得在缩放之前拆分数据,以避免数据泄漏问题。
*# split the data set into train and test*
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=0)
使用标准标量函数来标准化数据集。在这里,我们只拟合训练数据,因为我们不希望我们的模型在此之前看到这些数据,以避免过度拟合。
scaler = preprocessing.StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
使用 pandas 创建数据框架。
X_train = pd.DataFrame(data = X_train, columns=load_boston().feature_names)
X_train['Price'] = list(y_train)
X_test = pd.DataFrame(data = X_test, columns=load_boston().feature_names)
X_test['Price'] = list(y_test)
让我们看看我们的 X_train 是什么样子的。
X_train.head()

下面是我们需要最小化的线性模型的损失函数。

现在,我们计算损失函数 L w.r.t 权重(W)和截距(b)的梯度。以下是计算梯度的方程式,


在计算梯度后,我们不断改变我们的权重和截距值。


最后,我们将实现 SGD 函数。
**def** sgd_regressor(X, y, learning_rate=0.2, n_epochs=1000, k=40):
w = np.random.randn(1,13) *# Randomly initializing weights*
b = np.random.randn(1,1) *# Random intercept value*
epoch=1
**while** epoch <= n_epochs:
temp = X.sample(k)
X_tr = temp.iloc[:,0:13].values
y_tr = temp.iloc[:,-1].values
Lw = w
Lb = b
loss = 0
y_pred = []
sq_loss = []
**for** i **in** range(k):
Lw = (-2/k * X_tr[i]) * (y_tr[i] - np.dot(X_tr[i],w.T) - b)
Lb = (-2/k) * (y_tr[i] - np.dot(X_tr[i],w.T) - b)
w = w - learning_rate * Lw
b = b - learning_rate * Lb
y_predicted = np.dot(X_tr[i],w.T)
y_pred.append(y_predicted)
loss = mean_squared_error(y_pred, y_tr)
print("Epoch: **%d**, Loss: **%.3f**" %(epoch, loss))
epoch+=1
learning_rate = learning_rate/1.02
**return** w,b
我们保持学习率= 0.2,次数= 1000,批量= 40。我们可以相应地改变参数来最小化我们的 MSE。
我们通过除以 1.02 来不断降低我们的学习率,你可以选择任何你想要的值。
我选择了 MSE 作为我的误差度量,我们也可以选择 RMSE。
现在,我们创建一个预测函数并计算我们的预测值。
**def** predict(x,w,b):
y_pred=[]
**for** i **in** range(len(x)):
temp_ = x
X_test = temp_.iloc[:,0:13].values
y = np.asscalar(np.dot(w,X_test[i])+b)
y_pred.append(y)
**return** np.array(y_pred)w,b = sgd_regressor(X_train,y_train)
y_pred_customsgd = predict(X_test,w,b)
比较我们的预测值和实际值
**from** **matplotlib.pyplot** **import** figure
plt.figure(figsize=(25,6))
plt.plot(y_test, label='Actual')
plt.plot(y_pred_customsgd, label='Predicted')
plt.legend(prop={'size': 16})
plt.show()
print('Mean Squared Error :',mean_squared_error(y_test, y_pred_customsgd))

正如我们看到的,我们得到了 26.8 的 MSE,这是相当不错的。
实施 SKlearn 的 SGD 回归器
**from** **sklearn.linear_model** **import** SGDRegressor
clf = SGDRegressor(max_iter=1000, tol=1e-3)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
比较我们的预测值和实际值
**import** **matplotlib.pyplot** **as** **plt**
**from** **matplotlib.pyplot** **import** figure
plt.figure(figsize=(25,6))
plt.plot(y_test, label='Actual')
plt.plot(y_pred, label='Predicted')
plt.legend(prop={'size': 16})
plt.show()
print('Mean Squared Error :',mean_squared_error(y_test, y_pred))

SKlearn 的 SGD 实现比我们的自定义实现要好得多。
比较两个 SGD 分类器的预测值
**import** **matplotlib.pyplot** **as** **plt**
**from** **matplotlib.pyplot** **import** figure
plt.figure(figsize=(25,6))
plt.plot(y_pred, label='SGD')
plt.plot(y_pred_customsgd, label='Custom SGD')
plt.legend(prop={'size': 16})
plt.show()
print('Mean Squared Error of Custom SGD :',mean_squared_error(y_test, y_pred_customsgd))
print("Mean Squared Error of SKlearn's SGD :",mean_squared_error(y_test, y_pred))

嗯,我们的自定义 SGD 做了一个相当不错的工作相比,SKlearn 的,我们总是可以做一些超参数调整,以改善我们的自定义模型。
从头开始实现算法需要很多时间,但是如果我们使用库,那么它对我们来说仍然是黑箱。请在评论区告诉我你对此的看法。
感谢你阅读这篇博客,希望你对 SGD 的实际运作有所了解。
在 PyTorch 中实现 TabNet

https://unsplash.com/photos/Wpnoqo2plFA
深度学习已经接管了视觉、自然语言处理、语音识别和许多其他领域,取得了惊人的成果,甚至在某些领域取得了超人的表现。然而,使用深度学习对表格数据进行建模相对有限。
对于表格数据,最常见的方法是使用基于树的模型及其集成。基于树的模型全局选择减少熵最多的特征。像 bagging、boosting 这样的集成方法通过减少模型方差来进一步改进这些基于树的方法。最近基于树的组合,如 XGBoost 和 LightGBM,已经主导了 Kaggle 竞赛。
TabNet 是谷歌云 AI 研究团队开发的神经架构。它能够在回归和分类问题中的几个数据集上实现最先进的结果。它结合了神经网络的特性以适应非常复杂的函数和基于树的算法的特性选择属性。换句话说,模型在训练过程中学习只选择相关的特征。此外,与只能进行全局特征选择的基于树的模型相反,TabNet 中的特征选择过程是基于实例的。TabNet 的另一个令人满意的特性是可解释性。与大多数深度学习相反,在深度学习中,神经网络的行为就像黑盒一样,我们可以解释模型在 TabNet 的情况下选择了哪些特征。
在这篇博客中,我将带您一步一步地体验 PyTorch 中对初学者友好的 TabNet 实现。我们开始吧!!
TabNet 架构。

1)资料来源:https://arxiv.org/pdf/1908.07442v1.pdf
图(1)取自最初的 TabNet 论文。我们将单独构建图像的每个组件,并在最后将它们组装起来。首先,让我们来看一下这个模型中使用的两个基本概念- Ghost 批处理规范化(GBN) 和 Sparsemax 。
Ghost 批量标准化(GBN):
GBN 让我们可以训练大批量的数据,同时也可以更好地进行归纳。简而言之,我们将输入批次分成大小相等的子批次(虚拟批次大小),并对它们应用相同的批次规范化层。除了应用于输入要素的第一个批处理规范化图层之外,模型中使用的所有批处理规范化图层都是 GBN 图层。它可以在 PyTorch 中实现,如下所示:
class **GBN**(nn.Module):
def __init__(self,inp,vbs=128,momentum=0.01):
super().__init__()
self.bn = nn.BatchNorm1d(inp,momentum=momentum)
self.vbs = vbs
def forward(self,x):
chunk = torch.chunk(x,x.size(0)//self.vbs,0)
res = [self.bn(y) for y **in** chunk]
return torch.cat(res,0)
稀疏最大值:
就像 softmax 一样,Sparsemax 是一个非线性归一化函数,但是顾名思义,分布是“更稀疏”的。也就是说,与 softmax 相比,输出概率分布中的一些数字更接近 1,而其他数字更接近 0。这使得模型能够在每个决策步骤中更有效地选择相关特征。我们将使用 sparsemax 将特征选择步骤的掩码投影到一个更稀疏的空间。sparsemax 的实现可以在 https://github.com/gokceneraslan/SparseMax.torch的找到
为了进一步增加遮罩中的稀疏性,我们还将添加稀疏性正则化技术来惩罚不太稀疏的遮罩。这可以在每个决策步骤中实现,如下所示:
(mask*torch.log(mask+1e-10)).mean() #F(**x**)= -**∑x**log(**x+eps**)
所有决策步骤上的该值的总和可以被添加到总损失中(在乘以正则化常数λ之后)。
注意力转换器:
这是模型学习相关特征之间的关系并决定将哪些特征传递给当前决策步骤的特征转换器的地方。每个注意力转换器由一个全连接层、一个 Ghost 批处理规范化层和一个 Sparsemax 层组成。每个决策步骤中的注意力转换器接收输入特征、来自前一步骤的已处理特征以及关于已用特征的先验信息。先验信息由大小为 batch_size x input_features 的矩阵表示。它被初始化为 1,并在每个决策步骤的注意力转换器处被传递和更新。还有一个松弛参数,用于限制某个特性在向前传递中可以使用的次数。较大的值意味着模型可以多次重复使用同一要素。我认为守则把一切都讲清楚了。
class **AttentionTransformer**(nn.Module):
def __init__(self,d_a,inp_dim,relax,vbs=128):
super().__init__()
self.fc = nn.Linear(d_a,inp_dim)
self.bn = GBN(out_dim,vbs=vbs)
self.smax = Sparsemax()
self.r = relax #a:feature from previous decision step
def forward(self,a,priors):
a = self.bn(self.fc(a))
mask = self.smax(a*priors)
priors =priors*(self.r-mask) #updating the prior
return mask
然后将该掩膜乘以(按元素)归一化的输入要素。
特征转换器:
要素转换器是处理所有选定要素以生成最终输出的地方。每个特征变换器由多个门控线性单元块组成。GLU 控制哪些信息必须被允许在网络中进一步流动。为了实现一个 GLU 模块,首先我们使用一个完全连接的层将 GLU 的输入特征的尺寸加倍。我们使用一个 GBN 层来标准化结果矩阵。然后,我们将一个 sigmoid 应用于结果特征的第二部分,并将结果乘以第一部分。结果乘以一个比例因子(本例中为 sqrt(0.5))并添加到输入中。该求和结果是序列中下一个 GLU 模块的输入。
在所有决策步骤中共享一定数量的 GLU 块,以提高模型容量和效率(可选)。第一共享 GLU 块(或者第一独立块,如果没有块被共享的话)是唯一的,因为它将输入特征的维数减少到等于 n_a+n_d 的维数。n_a 是输入到下一步骤的注意力转换器的特征的维数,n_d 是用于计算最终结果的特征的维数。这些特征被一起处理,直到它们到达分割器。ReLU 激活应用于 n_d 维向量。所有决策步骤的输出相加在一起,并通过完全连接的层将它们映射到输出维度。
class **GLU**(nn.Module):
def __init__(self,inp_dim,out_dim,fc=None,vbs=128):
super().__init__()
if fc:
self.fc = fc
else:
self.fc = nn.Linear(inp_dim,out_dim*2)
self.bn = GBN(out_dim*2,vbs=vbs)
self.od = out_dim
def forward(self,x):
x = self.bn(self.fc(x))
return x[:,:self.od]*torch.sigmoid(x[:,self.od:])class **FeatureTransformer**(nn.Module):
def __init__(self,inp_dim,out_dim,shared,n_ind,vbs=128):
super().__init__()
first = True
self.shared = nn.ModuleList()
if shared:
self.shared.append(GLU(inp_dim,out_dim,shared[0],vbs=vbs))
first= False
for fc **in** shared[1:]:
self.shared.append(GLU(out_dim,out_dim,fc,vbs=vbs))
else:
self.shared = None
self.independ = nn.ModuleList()
if first:
self.independ.append(GLU(inp,out_dim,vbs=vbs))
for x **in** range(first, n_ind):
self.independ.append(GLU(out_dim,out_dim,vbs=vbs))
self.scale = torch.sqrt(torch.tensor([.5],device=device))
def forward(self,x):
if self.shared:
x = self.shared[0](x)
for glu **in** self.shared[1:]:
x = torch.add(x, glu(x))
x = x*self.scale
for glu **in** self.independ:
x = torch.add(x, glu(x))
x = x*self.scale
return x
接下来,让我们将注意力转换器和特征转换器结合成一个决策步骤:
class **DecisionStep**(nn.Module):
def __init__(self,inp_dim,n_d,n_a,shared,n_ind,relax,vbs=128):
super().__init__()
self.fea_tran = FeatureTransformer(inp_dim,n_d+n_a,shared,n_ind,vbs)
self.atten_tran = AttentionTransformer(n_a,inp_dim,relax,vbs)
def forward(self,x,a,priors):
mask = self.atten_tran(a,priors)
sparse_loss = ((-1)*mask*torch.log(mask+1e-10)).mean()
x = self.fea_tran(x*mask)
return x,sparse_loss
最后,我们可以通过将几个决策步骤结合在一起来完成模型:
class **TabNet**(nn.Module):
def __init__(self,inp_dim,final_out_dim,n_d=64,n_a=64,
n_shared=2,n_ind=2,n_steps=5,relax=1.2,vbs=128):
super().__init__()
if n_shared>0:
self.shared = nn.ModuleList()
self.shared.append(nn.Linear(inp_dim,2*(n_d+n_a)))
for x **in** range(n_shared-1):
self.shared.append(nn.Linear(n_d+n_a,2*(n_d+n_a)))
else:
self.shared=None
self.first_step = FeatureTransformer(inp_dim,n_d+n_a,self.shared,n_ind)
self.steps = nn.ModuleList()
for x **in** range(n_steps-1):
self.steps.append(DecisionStep(inp_dim,n_d,n_a,self.shared,n_ind,relax,vbs))
self.fc = nn.Linear(n_d,final_out_dim)
self.bn = nn.BatchNorm1d(inp_dim)
self.n_d = n_d
def forward(self,x):
x = self.bn(x)
x_a = self.first_step(x)[:,self.n_d:]
sparse_loss = torch.zeros(1).to(x.device)
out = torch.zeros(x.size(0),self.n_d).to(x.device)
priors = torch.ones(x.shape).to(x.device)
for step **in** self.steps:
x_te,l = step(x,x_a,priors)
out += F.relu(x_te[:,:self.n_d])
x_a = x_te[:,self.n_d:]
sparse_loss += l
return self.fc(out),sparse_loss
模型超参数的近似范围: n_d,n_a: 8 到 512
批量:256 到 32768
虚拟批量:128 到 2048
稀疏正则化常数:0 到 0.00001
共享 GLU 块数:2 到 10
独立判决块数:2 到 10
松弛常数:1 到 2.5
判决步数)
这个 TabNet 模块可以扩展用于分类和回归任务。您可以为分类变量添加嵌入,将 Sigmoid 或 Softmax 函数应用于输出,等等。尝试一下,看看什么最适合你。在示例笔记本中,我尝试用 Sigmoid 替换 Sparsemax,并能够获得稍好的精度。
关于行动机制(MoA)预测数据集的用例示例,你可以在这里找到我的笔记本:https://www.kaggle.com/samratthapa/drug-prediction。这是目前正在 Kaggle 上举行的一场比赛的数据集。
我对 TabNet 的实现是对 DreamQuark 慷慨的人们的工作的一个简短的改编。他们对 TabNet 的完整实现可以在:
https://github . com/dream quark-ai/TabNet/tree/develop/py torch _ TabNet找到。
你应该考虑阅读论文以获得对 TabNet 更详细的描述。
感谢您的阅读。我希望我能帮上忙。
参考文献:
1)塞尔詹·奥鲁克,托马斯·菲斯特。2020.TabNet:专注的可解释表格学习https://arxiv.org/abs/1908.07442v4
2)扬·n·多芬、安吉拉·范、迈克尔·奥利和大卫·格兰吉尔。2016.用门控卷积网络进行语言建模。https://arxiv.org/pdf/1612.08083.pdf、埃拉德·霍弗、伊泰·胡巴拉和丹尼尔·苏德里。2017.训练时间越长,推广效果越好:缩小神经网络大批量训练中的推广差距。
https://arxiv.org/pdf/1705.08741.pdf
4)安德烈·马丁斯和拉蒙·费尔南德斯·阿斯图迪略。2016.从 Softmax 到 Sparsemax:注意力和多标签分类的稀疏模型。
https://arxiv.org/abs/1602.02068
5)Sparsemax 实现https://github.com/gokceneraslan/SparseMax.torch
6)完成 PyTorch TabNet 实现
https://github . com/dream quark-ai/TabNet/tree/develop/py torch _ TabNet
在 python 中实现通用树和深度优先搜索(DFS )!(从头开始)

信用:Pixabay
最近,我在《走向数据科学》上发表了一篇关于从零开始实现链表的文章。阅读之前的故事对于理解这里的核心概念是不必要的,但是之前使用的代码将被引用;因此,我将把 GitHub Gists 链接到链表和一般的树实现。
作为一名数据科学领域的研究生,我经常发现统计概念得到了大量的课程介绍,但基本的 CS 概念往往被抽象掉了。也许有充分的理由;知道如何实现一棵树对于训练一个随机的森林来说是不必要的。更高级的 API 允许我们利用基本概念,而不会被细节所困扰。
那么什么是一般的树——你为什么要关心呢?
到目前为止,二叉树在 CS 基础中更常见。每棵树都有三个强制元素:一个值、一个左子引用和一个右子引用。实现的任何其他东西都是为了满足程序员预见的独特目的。
另一方面,一般的树不限于有确切地说是两个孩子。这尤其有用,因为分层数据在 web 上非常普遍。例如,考虑探索 API 查询结果的任务。XML 和 JSON 数据都是树状数据。通用树会给你工具来快速搜索特定字符串、数值等的查询结果。
我们的数据结构不局限于两个或零个孩子,将比二叉树灵活得多,但它也将迫使我们做出重要的设计决策。其中最重要的是——树节点必须有有限数量的属性。如果任何节点都可以有任意数量的子节点,我们该如何解决这个难题呢?列表、元组和字典是自然的选择;单个通用树节点可以将其children属性设置为单个变量,该变量可以引用可变数量的通用树节点。
但是我承诺从头实现它,因为我最近从头实现了链表,我们将继续以同样的势头向前冲。简单回顾一下——链表是由节点组成的。每个节点引用序列中的下一个节点(也可以是前一个节点——也就是双向链表)。)第一个节点是头,因此,必须从头遍历到序列中的任何其他节点。在头部位置的插入是微不足道的(与动态数组相比),您只需实例化一个引用头部的新节点,并将 head 属性设置为链表的新头部。
我们将以两种方式构建链表:我们将直接使用链表来跟踪我们已经访问过的树节点;我们将借用链表的精神来指导我们的设计选择。
考虑下图。典型的通用树将允许任何子节点被给定的父节点访问。因为我们的数据结构将建立在一个链表上,一个给定的父节点将只引用一个子节点,,特别是最左边的子节点。要访问它的其他子节点,我们必须遍历兄弟节点。只要我们意识到这一点,并且我们的设计选择考虑到这一点,这就不是问题。另外,我们没有借用 python 的内置数据类型,这意味着我们最大化了我们的学习体验。

让我们从一般的树节点开始,它将有以下参数:值、父节点、左兄弟节点、右兄弟节点和子节点。这本质上是一个双向链表,因为它在水平和垂直方向上都是双向链接的。很像链表,我们需要定义getter和setter。这些函数将设置一个节点对另一个节点的引用属性,或者获取这个值的值(如果存在的话)。
到目前为止,我们已经讨论了体系结构,但是通用树的真正用途来自于搜索它的能力。有多种策略来遍历一般的树;最常见的两种是广度优先搜索(BFS)和深度优先搜索(DFS)。我们今天将只实现后者。在高层次上,策略是尽可能深入第一个分支;当我们不能再往下走时,我们退回到前面的父节点,并遍历它的第一个兄弟节点。我们能下去吗?如果是这样,我们探索这个分支的深度。如果不能,我们探索下一个兄弟姐妹。这听起来极其复杂,但是当我们从基于条件的策略的角度来考虑时,就容易多了。
DFS 的五个场景:
- 如果一个子节点存在并且还没有被浏览,那么遍历到这个子节点。
- 如果右兄弟存在且尚未被浏览,则向右遍历。
- 如果我们在最右边的孩子,我们可以退回到左边,那么遍历到左边。 【撤退】
- 如果我们不在最左边的子节点上,但是我们已经在右边的和上找到了的兄弟节点,那么遍历到左边。 (撤退)
- 否则,遍历父项。 【撤退】
这里真正的技巧是使用递归,这是每个程序员都应该努力掌握的技能。递归函数有两个元素:终止条件和其他一切。如果终止条件被触发,函数将存在并返回一些期望的输出。如果终止条件不满足,该函数将采取措施向终止条件推进,然后调用自身。
出于我们的目的,我们需要对和有一些概念,为此我们将定义current_node和current_value变量。每当我们遍历到另一个节点时,我们就更新这些值。我们的终止条件是这样的:如果当前值是 根节点值 或 搜索值 ,我们退出 。(显然,每个节点有一个唯一的名称很重要,让我们过早退出。)如果不满足这个条件,我们观察上面的五个条件规则,根据当前节点执行任何合适的规则/策略,并重复直到满足终止条件。这就是全部了。
我们将在下面定义三种截然不同但非常相似的方法。第一个是depth_first_traversal。这里,我们将根据 DFS 协议研究整个树。没有搜索值,因此我们仅在到达根节点时终止(即,我们已经探索了所有子节点的所有子节点。)其次我们来定义depth_first_search。这里,我们将提供一个搜索值。如果达到这个值,我们将退出循环。如果我们一直追溯到根节点,这个值在树中就不存在了。值得注意的是,这两个函数将通知程序员节点实际被遍历的顺序。换句话说,兄弟遍历将被考虑。
我们需要定义第三个函数,它对真实的层次数据有用。例如,在文件存储系统中。一旦您将目录更改为给定的文件夹,您就不需要遍历所有文件和文件夹,直到您到达所需的文件夹后再打开它。相反,您只需遍历parent -> child并重复,直到您到达所需的子目录。对我们的影响:使用我们的架构,我们需要清除兄弟遍历,这样我们的输出就和任何其他通用树的输出一样。
这种改变没有你想象的那么困难。但是在我们讨论它之前,我们需要谈谈上面讨论的所有三种方法的共性。需要创建一个visited 类属性。正如前面所讨论的,这将是一个链表,其中一旦一个树节点被访问,它的值将被追加到链表的末尾。这使得这三种方法避免了从父到子到父的无限遍历…一次又一次。
后两种方法使用了 path 类属性的变体,这是——您猜对了——另一个链表(持续给予的礼物!)这里的想法是只维护不涉及撤退的节点,不像被访问的属性。path和child_path最大的区别在于,前者包括对兄弟姐妹的遍历,而后者不包括。子路径是最令人感兴趣的,因为它在真实世界的数据中很有用,而 path 属性只在我们程序的上下文中有用。在任一情况下,使用我们上面的五个 DFS 条件规则/策略,条件 3、4、& 5 都是撤退,这意味着当撤退时我们从我们的路径/子路径中清除这些节点值。(如果推理还不明显,当我们回顾代码时,它会更有意义。简单地说,这些分支是死胡同,我们从路径/子路径变量中剪除。)
重新考虑终止条件,我们做的最后一件事是为将来的迭代重置。这是通过将我们的路径复制到一个临时变量,将所有其他变量重新定义到它们的起始条件,然后返回临时变量来实现的。过一会儿这就更有意义了——我保证!(如果我们不重置,我们将需要重新实例化我们的通用树类,以便搜索不同的值,因为我们的变量将存在于非启动条件下,从而触发错误。)
现在——代码!让我们回顾一下链表。
并在一般的树(最后!!)
考虑下面的树:
a1
|
b1 - b2 - b3
| |
d1 c1
如果我们运行下面的单元格,我们将把这个树实例化到通用树类对象中,然后找到从根到节点 c1 的最短路径(有和没有兄弟)。
a1 = GeneralTreeNode(value='a1')
b1 = GeneralTreeNode(value='b1')
b2 = GeneralTreeNode(value='b2')
b3 = GeneralTreeNode(value='b3')
a1.set_child(b1)
b1.set_parent(a1)
b1.set_right(b2)
b2.set_left(b1)
b2.set_right(b3)
b3.set_left(b2)c1 = GeneralTreeNode(value='c1')
c1.set_parent(b3)
b3.set_child(c1)d1 = GeneralTreeNode(value='d1')
d1.set_parent(b1)
b1.set_child(d1)r = GeneralTree(root=a1)r.depth_first_search(search_val='c1')
>>>>
Node: a1
Node: b1
Node: b2
Node: b3
Node: c1r.child_depth_first_search(search_val='c1')
>>>>
Node: a1
Node: b3
Node: c1
看到depth_first_search和child_depth_first_search的区别了吗?在后者中,节点 b1 和 b2 被省略,因为它们在一般树的传统定义中不是必需的遍历。后一种方法是您想要在现实世界问题中使用的方法(就像我们之前的文件系统导航示例一样。)
如果你对本教程如何更有帮助有想法,对扩展有想法,请求合作等,请联系我。名义上,我计划要么创建一个 XML 解析器、JSON 解析器,要么使用树来搜索嵌套字典,等等。
我希望你喜欢今天和我一起深入研究基本面!
用 python 实现链表和选择排序!(从头开始)

信用:PixaBay.com
在这篇文章中,我将从头开始实现链表,并构建重要的功能,如插入(和 insert_at)、删除、交换和排序。作为数据科学的研究生,我发现大部分材料都集中在机器学习背后的统计学和数学上。毫无疑问,在这里取得成功对数据科学领域的职业生涯至关重要。然而,计算机科学基础的重要性往往被边缘化。
那么什么是链表呢?
链表是一个由节点组成的对象,节点(你猜对了)也是对象。这两者我们都需要实现。每个节点都包含一个值和一个到后续节点的链接。这是强制性的。一个双向链表(我们在这里只涉及定性术语)是一个类似的对象,它的节点也包含到它们之前节点的链接。一个头是必不可少的。它是链表中的第一个条目。默认情况下,它的下一个节点属性设置为“无”。当我们添加第二个项目时,我们实例化一个节点对象并设置 heads 的 next 属性来引用我们刚刚创建的(新)节点。如果我们向链表中添加第三个节点,我们将实例化一个新的节点对象,并将第二个节点的 next 属性设置为引用新创建的节点。并且对于我们想要插入到链表中的任意数量的值,重复这个过程。
当我们想在列表中间插入一个值时,事情变得更加棘手。假设我们有一个由三个元素0,2,3组成的链表,我们希望将值1插入到索引位置1。目前,头部是0,它的下一个属性引用了2。我们需要实例化一个节点对象,将值设置为1。从这里开始,我们需要将头部的 next 属性设置为1,将1的 next 属性设置为2。
听起来很简单,对吗?您会注意到,为了通过索引到达一个节点,我们需要遍历所有以前的节点,从头部开始。虽然没有明确说明,但是我们需要定义一个名为get_next()的类方法,它将引用下面的节点。当我们在最后一个节点时会发生什么?除非我们考虑到这一点,否则我们会触发一个错误。有必要考虑链表的长度以及从头部开始我们已经走了多远。我们将通过创建一个名为count的类属性来做到这一点,它将引用链表的长度或其中最后一项的索引(在这个实现中,我选择了后一个选项。)
当我们删除一个值时,我们需要将计数减 1;同样,当我们插入一个值时,我们需要将计数增加 1。当我们交换值时,这个过程变得更加棘手。我们需要删除和插入值;因此,链表中的计数和相对位置可以根据我们执行这些过程的顺序而变化。跟踪我们所处的位置需要注意细节。
最困难的任务是对链表进行排序。我选择使用选择排序作为算法的选择。优秀的排序算法确实存在,但是我们将把重点放在选择排序上,因为它是排序算法中相对简单的。该算法通过建立排序值的索引位置来工作。当我们开始时,这个索引被设置为 0。我们将 selection 设置为后续值,并遍历列表的剩余部分,在和sorted_idx的右边寻找最小值。如果一个节点的值小于selection,那么我们将选择设置为这个值,并跟踪它的索引。遍历链表并找到最小值后,我们删除这个节点,实例化一个值等于选择的新节点,并将这个节点插入到sorted_idx。最后,我们将sorted_idx增加 1,并重复直到这个索引等于 count 属性减 1(因为在我们到达最后一个节点后,没有节点可遍历。)
您会注意到,这个过程从将sorted_idx设置为 0 开始,并将selection设置为紧跟着头部的节点的值。在 head 是最大值的情况下,当进程终止时,它将被推到列表的末尾,这没有问题。但如果头不是最大值,还是会被推到底;但这是一个不完整的排序。我们需要构建最后一个步骤来计算最后一个条目的值,并遍历整个链表。在每一步,节点的值将与最终条目进行比较。如果大于节点的值,我们将遍历到下一个节点并再次比较。这个过程一直重复,直到我们到达一个节点,这个节点的值大于条目的最终值,这是我们前面提到的。当达到一个更高的值时(并且因为所有先前的值都更小),我们现在知道最后一个条目的真正家在哪里。我们删除最后一个条目,并将其值插入索引中,直到第一个值大于我们的选择。如果我们遍历列表的长度(除了最后一个条目),并且所有的值都较小,那么我们可以有把握地得出结论,最后一个条目是最大值,并且已经在它适当的位置。咻!
让我们来看看代码!
https://gist . github . com/jdmoore 7/6 F9 FBC 76139 DDB 0 c 7d 485 f 97349 B3 bbf
完整的资源库可以在这里找到:https://github . com/jdmoore 7/linked _ list/blob/master/linked list . py
感谢阅读!
为语言建模实现转换器
使用 Fairseq 训练变压器模型

图片由作者提供(Fairseq logo: 来源
介绍
自然语言处理的最新趋势是建立在该领域历史上最大的突破之一之上的: 转换器 。Transformer 是主要由 Google Brain 和 Google Research 研究的模型架构。它最初被证明在翻译任务中达到了最先进的水平,但后来当它被大规模采用时,被证明在几乎任何 NLP 任务中都是有效的。transformer 架构由一系列编码器和解码器组成,具有自我关注层,有助于模型关注各自的输入。你可以在原文这里了解更多关于变形金刚的知识。
在这篇文章中,我们将向您展示如何实现语言建模任务的转换器。语言建模是给语言中的句子分配概率的任务。语言建模的目标是让模型将高概率分配给我们数据集中的真实句子,以便它能够通过解码器方案生成接近人类水平的流畅句子。我们将使用 Fairseq 库来实现转换器。
第一步:准备数据集(来自我之前的博文)
使用 Pytorch 和 Huggingface 微调用于文本生成的 GPT2。我们在 CMU 图书摘要数据集上进行训练,以生成…
towardsdatascience.com](/fine-tuning-gpt2-for-text-generation-using-pytorch-2ee61a4f1ba7)
在本文中,我们将再次使用 CMU 图书摘要数据集来训练 Transformer 模型。可以参考博文的步骤 1 来获取和准备数据集。准备好数据集后,您应该准备好与数据集的三个分区相对应的 train.txt 、 valid.txt 和 test.txt 文件。
步骤 2:下载并安装 Fairseq
如果你没有听说过 Fairseq ,它是一个流行的 NLP 库,由脸书 AI 开发,用于实现翻译、摘要、语言建模和其他生成任务的定制模型。你可以在这里查看我对 Fairseq 的评论。
现在,为了下载并安装 Fairseq,运行以下命令:
git clone https://github.com/pytorch/fairseq
cd fairseq
pip install --editable ./
如果您的 GPU 允许,您还可以选择安装 NVIDIA 的 apex 库来加快训练速度:
git clone https://github.com/NVIDIA/apex
cd apex
pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" \
--global-option="--deprecated_fused_adam" --global-option="--xentropy" \
--global-option="--fast_multihead_attn" ./
现在,您已经成功安装了 Fairseq,我们终于可以开始了!
步骤 3:预处理数据集
为了预处理数据集,我们可以使用 fairseq 命令行工具,这使得开发人员和研究人员可以很容易地从终端直接运行操作。为了预处理我们的数据,我们可以使用fairseq-preprocess来构建我们的词汇表,并对训练数据进行二进制化。
cd fairseq/
DATASET=/path/to/dataset
fairseq-preprocess \
--only-source \
--trainpref $DATASET/train.txt \
--validpref $DATASET/valid.txt \
--testpref $DATASET/test.txt \
--destdir data-bin/summary \
--workers 20

预处理的命令输出
执行上述命令后,预处理后的数据将保存在--destdir指定的目录下。
步骤 4:训练变压器
终于可以开始训练变形金刚了!要训练一个模型,我们可以使用fairseq-train命令:
CUDA_VISIBLE_DEVICES=0 fairseq-train --task language_modeling \
data-bin/summary \
--save-dir checkpoints/transformer_summary \
--arch transformer_lm --share-decoder-input-output-embed \
--dropout 0.1 \
--optimizer adam --adam-betas '(0.9, 0.98)' --weight-decay 0.01 --clip-norm 0.0 \
--lr 0.0005 --lr-scheduler inverse_sqrt --warmup-updates 4000 --warmup-init-lr 1e-07 \
--tokens-per-sample 512 --sample-break-mode none \
--max-tokens 2048 --update-freq 16 \
--fp16 \
--max-update 50000 \
--max-epoch 12
在我们的例子中,我们将 GPU 指定为第 0 个(CUDA_VISIBLE_DEVICES),将任务指定为语言建模(--task),将数据指定为data-bin/summary,将架构指定为转换器语言模型(--arch),将历元数指定为 12 ( --max-epoch,以及其他超参数。训练完成后,模型的最佳检查点将保存在--save-dir指定的目录下。
12 个纪元需要一段时间,所以当你的模型训练时请坐好!当然,你也可以根据自己的需要减少历元数来训练。训练完成后,将显示以下输出:

训练结束时的命令输出
请注意,在每个历元中,会显示相关的数字,例如丢失和困惑。这些可能有助于在训练过程中评估模型。
步骤 5:评估语言模型
在您的模型完成训练之后,您可以使用fairseq-eval-lm评估生成的语言模型:
fairseq-eval-lm data-bin/summary \
--path checkpoints/transformer_summary/checkpoint_best.pt \
--max-sentences 2 \
--tokens-per-sample 512 \
--context-window 400
在这里,将评估测试数据以对语言模型进行评分(在训练阶段使用训练和验证数据来寻找模型的优化超参数)。下面显示了评估后的命令输出:

用于评估的命令输出
如你所见,我们模型的损失是 9.8415,困惑度是 917.48(以 2 为基数)。
第六步:终于!让我们生成一些文本:D
在训练模型之后,我们可以尝试使用我们的语言模型生成一些样本。要生成,我们可以使用fairseq-interactive命令创建一个交互会话来生成:
fairseq-interactive data-bin/summary \
--task language_modeling \
--path checkpoints/transformer_summary/checkpoint_best.pt \
--beam 5
在交互式会话期间,程序将提示您输入文本。输入文本后,模型将在输入后生成标记。一个代样给定书发生地作为输入T7 是这样的:
这本书发生在故事的故事,故事的故事,故事的故事,故事的人物…
生成是重复的,这意味着模型需要用更好的参数来训练。上述命令使用光束尺寸为 5 的光束搜索。我们还可以使用采样技术,如 top-k 采样:
fairseq-interactive data-bin/summary \
--task language_modeling \
--path checkpoints/transformer_summary/checkpoint_best.pt \
--sampling --beam 1 --sampling-topk 10
以及 top-p 采样:
fairseq-interactive data-bin/summary \
--task language_modeling \
--path checkpoints/transformer_summary/checkpoint_best.pt \
--sampling --beam 1 --sampling-topp 0.8
注意,当使用 top-k 或 top-sampling 时,我们必须添加beam=1来抑制当--beam不等于--nbest时产生的误差。这好像是个 bug。
结论
在这篇博文中,我们使用流行的 Fairseq 库在书籍摘要上训练了一个经典的 transformer 模型!虽然生成示例是重复的,但是本文可以作为一个指南,带您在语言建模上运行一个转换器。如果:D 感兴趣,看看我的其他帖子
AllenNLP,Fast.ai,Spacy,NLTK,TorchText,Huggingface,Gensim,OpenNMT,ParlAI,DeepPavlov
towardsdatascience.com](/top-nlp-libraries-to-use-2020-4f700cdb841f) [## 使用 Pytorch 微调用于文本生成的 GPT2
使用 Pytorch 和 Huggingface 微调用于文本生成的 GPT2。我们在 CMU 图书摘要数据集上进行训练,以生成…
towardsdatascience.com](/fine-tuning-gpt2-for-text-generation-using-pytorch-2ee61a4f1ba7) [## 控制语言模型的文本生成
控制机器生成文本的样式和内容的实际操作方法
towardsdatascience.com](/controlling-text-generation-from-language-models-6334935e80cf) [## 使用 Pytorch 的 BERT 文本分类
文本分类是自然语言处理中的一项常见任务。我们应用 BERT,一个流行的变压器模型,对假新闻检测使用…
towardsdatascience.com](/bert-text-classification-using-pytorch-723dfb8b6b5b)
参考
[1] A .瓦斯瓦尼,n .沙泽尔,n .帕尔马等。,注意力是你需要的全部 (2017),第 31 届神经信息处理系统会议
[2] L .邵、s .古乌斯、d .布里兹等。,用序列对序列模型生成高质量、信息量大的会话响应 (2017),自然语言处理中的经验方法
[3] A. Fan,M. Lewis,Y. Dauphin,【分层神经故事生成】 (2018),计算语言学协会
[4] A .霍尔茨曼、j .买斯、l .杜等。,神经文本退化的好奇案例 (2019),国际学习表征会议
[5] Fairseq Github ,脸书艾研究
[6] Fairseq 文档,脸书艾研究
从头开始实现 XGBoost
使用 numpy 实现一个最流行的机器学习模型的逐步指南

安妮·斯普拉特在 Unsplash 上的照片
XGBoost 是一个优化的分布式梯度增强库,旨在高效、灵活和可移植。
它已经被用于几乎每一个机器学习黑客马拉松,并且通常是选择模型时的首选。
但是理解它实际上是如何工作的总是困难的部分。起初,复杂的数学很难理解,所以我决定使用 Numpy 编写 XGBoost 的代码。这将有助于以简单的方式理解它。

这是通过临时代码理解 XGBoost 的另一种方法。下面的代码是一个使用 numpy 开发的简单 XGBoost 模型。这段代码的主要目的是揭示 XGBoost 背后的数学原理。
导入基本库:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
numpy——实现 xgboost
Pandas 背后的数学运算——将列表值转换为 data frame
Matplotlib——绘制最终输出以可视化结果
样本数据:
考虑以下数据,其中工作年限是预测变量,工资是目标。
year = [5,7,12,23,25,28,29,34,35,40]
salary = [82,80,103,118,172,127,204,189,99,166]
需要记住的几件重要事情:
使用回归树作为基础学习器,我们可以创建一个模型来预测工资。
为了简单起见,我们可以选择平方损失作为损失函数,我们的目标是最小化平方误差。
作为第一步,模型应该用函数 F0(x)初始化。F0(x)应该是使函数 F 在平均值处最小化的损失函数或 MSE(均方误差)最小化的函数
如果我们取 MAE,函数会在中间值最小化
数据构建
df = pd.DataFrame(columns=['Years','Salary'])
df.Years = year
df.Salary = salary
df.head()

上述代码片段的输出
几件更重要的事情:
残差是 y 和 f0 之差,即(y-f0)
我们可以使用 F0(x)的残差来创建 h1(x)。h1(x)将是一棵回归树,它将尝试减少上一步的残差。h1(x)的输出不会是 y 的预测;相反,它将有助于预测将降低残差的连续函数 F1(x)。
加法模型 h1(x)计算树的每个叶子处的残差(y-F0)的平均值。
分割完成后,计算上半部分和下半部分的平均值,我选择了一个随机分割点。
模型构建:
for i in range(2):
f = df.Salary.mean()
if(i>0):
df['f'+str(i)] = df['f'+str(i-1)] + df['h'+str(i)]
else:
df['f'+str(i)] = f
df['y-f'+str(i)] = df.Salary - df['f'+str(i)]
splitIndex = np.random.randint(0,df.shape[0]-1)
a= []
h_upper = df['y-f'+str(i)][0:splitIndex].mean()
h_bottom = df['y-f'+str(i)][splitIndex:].mean()
for j in range(splitIndex):
a.append(h_upper)
for j in range(df.shape[0]-splitIndex):
a.append(h_bottom)
df['h'+str(i+1)] = a
df.head()

2 次迭代后的输出
如果我们继续迭代 100 次,我们可以看到 MSE(Fi)的损失大幅下降
for i in range(100):
f = df.Salary.mean()
if(i>0):
df['f'+str(i)] = df['f'+str(i-1)] + df['h'+str(i)]
else:
df['f'+str(i)] = f
df['y-f'+str(i)] = df.Salary - df['f'+str(i)]
splitIndex = np.random.randint(0,df.shape[0]-1)
a= []
h_upper = df['y-f'+str(i)][0:splitIndex].mean()
h_bottom = df['y-f'+str(i)][splitIndex:].mean()
for j in range(splitIndex):
a.append(h_upper)
for j in range(df.shape[0]-splitIndex):
a.append(h_bottom)
df['h'+str(i+1)] = a
df.head()

100 次迭代后的输出
我们可以看到,随着迭代次数的增加,损失在减少,模型在适应数据集
可视化结果:
plt.figure(figsize=(15,10))
plt.scatter(df.Years,df.Salary)
plt.plot(df.Years,df.f1,label = 'f1')
plt.plot(df.Years,df.f10,label = 'f10')
plt.plot(df.Years,df.f99,label = 'f99')
plt.legend()

上述代码片段的绘图
蓝线表示 1 次迭代后的输出,可以理解为随机。当我们到达第 100 次迭代时,模型适应数据,损失减少,从而使输出接近实际点。
代码可以在我的 github 回购上找到:【https://github.com/Sid11/XGBoost-Using-Numpy/】T2
希望你喜欢!
在 PyTorch 中实现 Yann LeCun 的 LeNet-5

安妮·尼加德在 Unsplash 上拍摄的照片
最近,我看了由 Dataiku 制作的数据科学先锋电影,其中几位数据科学家讲述了他们的工作以及他们如何在日常工作中应用数据科学。在其中一次会谈中,他们提到了 Yann LeCun 的卷积神经网络架构(也称为 LeNet-5) 如何被美国邮政局用于自动识别手写的邮政编码。该架构的另一个现实应用是识别银行系统写在支票上的数字。指出 LeNet-5 论文发表于 1998 年是有意义的。这就是为什么在转向更复杂、更现代的架构之前,理解 CNN 如何工作是一个很好的起点的原因之一。
在本文中,我简要描述了该架构,并展示了如何在 PyTorch 中实现 LeNet-5。本文假设对卷积神经网络的基础有一个大致的了解,包括卷积层、池层、全连接层等概念。
理论介绍
LeNet-5 是一个 7 层卷积神经网络,针对大小为 32 x 32 像素的灰度图像进行训练。

为了解码上面的图像,我给出了作者使用的命名约定:
- Cx —卷积层,
- Sx —子采样(池化)层,
- Fx —全连接层,
- x-层的索引。
鉴于现代标准,LeNet-5 相对简单,因此我们可以分别研究每一层,以便更好地理解该架构。然而,在继续之前,提醒一下计算卷积层输出大小的公式也是有意义的。
公式如下所示:
,其中 W 是输入的高度/宽度(正常情况下图像是正方形,所以不需要区分两者), F 是滤镜/内核大小, P 是填充, S 是步幅。
看到上面的架构模式和公式后,我们可以检查 LeNet-5 的每一层。
- 第 1 层(C1) :第一个卷积层,有 6 个大小为 5×5 的核,步长为 1。给定输入大小(32×32×1),该层的输出大小为 28×28×6。
- 第 2 层(S2) :具有 6 个大小为 2×2 的内核和步长为 2 的子采样/池层。原始架构中的子采样层比传统使用的最大/平均池层要复杂一些。我将引用[1]:“S2 单位的四个输入相加,然后乘以一个可训练的系数,并加到一个可训练的偏差。结果通过一个 s 形函数传递。。作为非重叠感受野的结果,该层的输入大小减半(14×14×6)。
- 第三层(C3): 第二个卷积层,配置与第一个相同,不过这次有 16 个滤波器。该层的输出为 10×10×16。
- 第四层(S4): 第二个汇集层。逻辑与前一个相同,但这一次该层有 16 个过滤器。该层的输出大小为 5×5×16。
- 第 5 层(C5): 最后一个卷积层,120 个 5×5 核。假设该层的输入大小为 5×5×16,内核大小为 5×5,则输出为 1×1×120。因此,层 S4 和 C5 是完全连接的。这也是为什么在 LeNet-5 的一些实现中,实际上使用全连接层而不是卷积层作为第五层。将这一层保持为卷积层的原因是,如果网络的输入大于[1]中使用的输入(初始输入,在这种情况下为 32×32),这一层将不是全连接层,因为每个内核的输出将不是 1×1。
- 第 6 层(F6): 第一个全连接层,接受 120 个单元的输入并返回 84 个单元。在最初的论文中,作者使用了一个定制的激活函数——tanh 激活函数的变体。关于详细的解释,请参考[1]中的附录 A。
- 第 7 层(F7): 最后一个密集层,输出 10 个单位。在[1]中,作者使用欧几里德径向基函数神经元作为该层的激活函数。
有关架构背后的推理和一些选择(如非标准激活函数)的更多详细信息,请参考[1]。
PyTorch 实现
我现在将展示如何在 PyTorch 中实现 LeNet-5(做了一些小的简化)。为了保持 LeNet-5 最初应用的精神,我们将在 MNIST 数据集上训练网络。我们从导入所有需要的库开始。
此外,我们检查 GPU 是否可用,并相应地设置DEVICE变量。在下一步中,我们设置一些参数(如随机种子、学习速率、批量大小、时期数等。),我们将在稍后设置神经网络时使用它。
下一步,我们在 PyTorch 中定义一些用于训练神经网络的辅助函数。由于在大多数情况下,总体思想非常相似,因此您可以根据自己的需要稍微修改这些函数,并将其用于训练各种网络。我们从负责培训部分的功能开始:
我将快速描述一下在train函数中发生了什么。对于每批观察,我们执行以下步骤:
- 执行正向传递-使用当前权重获取批次的预测
- 计算损失函数的值
- 执行反向传递,其中权重根据损失进行调整。这是“学习”的一步。
请注意,在训练阶段,模型处于训练模式(model.train()),我们还需要将每批的梯度归零。此外,我们计算训练步骤中的跑步损失。
然后,我们定义负责验证的函数。
验证功能与训练功能非常相似,不同之处在于缺少实际的学习步骤(反向传递)。请注意,我们需要说明我们仅使用模型进行评估— model.eval()。我们不需要担心梯度,因为在下一个函数中,您将看到我们在验证步骤中禁用了它们。最后,我们在训练循环中将它们结合在一起:
在训练循环中,对于每个时期,我们运行train和validate函数,后者与torch.no_grad()一起运行,以便不更新权重并节省一些计算时间。除了用于训练的损失函数之外,我们还使用定制的get_accuracy函数计算训练和验证步骤的模型精度。我们将使用的数据集是平衡的,因此使用准确性作为衡量标准没有问题。为了简洁起见,我在这里没有包括所有的助手函数,你可以在 GitHub 上找到get_accuracy和plot_losses的定义。
定义了助手函数之后,是时候准备数据了。由于 MNIST 数据集的普及(如果你不熟悉它,你可以在这里阅读一些背景),它很容易作为torchvision内的数据集之一。
在上面的代码片段中,我们首先定义了一组要应用于源图像的变换。我们首先将图像的大小调整为 32×32(LeNet-5 的输入大小),然后将它们转换为张量。transforms.ToTensor()自动将图像缩放至[0,1]范围。我们也可以对图像应用某种填充,而不是调整图像的大小。在最简单的情况下,我们只需在原始图像的两边添加两个零。
第二步是定义数据集。对于训练对象,我们指定了download=True,以便下载数据集。在定义数据集时,我们还指出了先前定义的转换以及特定对象是否将用于训练。
最后,我们通过提供数据集、批量大小和在每个时期混洗数据集的愿望来实例化DataLoaders。为了验证,这没有区别,所以我们把它设置为False。
下面你可以看到来自训练集的 50 张图片的预览。

最后,是时候定义 LeNet-5 架构了。
从上面的类定义中,您可以看到与原始网络相比的一些简化:
- 使用常规 tanh 激活功能,而不是[1]中描述的自定义功能。
- 使用普通的池层而不是原始架构中使用的更复杂的对等层,
- 用 softmax 函数替换输出图层中的欧氏径向基函数激活。
定义了类之后,我们需要实例化模型(并将其发送到正确的设备)、优化器(本例中为 ADAM)和损失函数(交叉熵)。最后两个不同于最初在[1]中使用的方法。
一切就绪后,我们可以通过运行以下命令来训练网络:
model, optimizer, _ = training_loop(model, criterion, optimizer, train_loader, valid_loader, N_EPOCHS, DEVICE)
什么会产生以下输出:


训练损失趋于平稳,而验证损失有时表现出小的起伏(增加的值)。总的来说,我相信表现可以用中规中矩来形容。最好的结果(在验证集上)是在第 11 个时期获得的。
为了评估我们模型的预测,我们可以运行下面的代码,该代码显示一组来自验证集的数字,以及预测的标签和网络分配给该标签的概率(换句话说,网络在预测中的可信度)。

从上面的图片中我们可以看到,网络几乎总是确定这个标签,唯一的疑问出现在数字 3(第二行,右起第三个)中,而它只有 54%的把握是 3。这很可能是因为这个数字确实类似于 8。
作为最后一步,我们运行以下命令来删除下载的数据集:
!rm -r mnist_data
结论
在本文中,我描述了 LeNet-5 的架构,并展示了如何实现它,以及如何使用著名的 MNIST 数据集对它进行训练。由于这是最早的 CNN 架构之一,它相对简单易懂,这使得它成为学习卷积神经网络的良好开端。
为了进一步提高网络的性能,尝试一些数据扩充可能是值得的。为此,我们可以对图像应用旋转或剪切(使用torchvision.transforms)等变换,以创建更加多样化的数据集。我们还应该注意,并不是所有的变换都适用于数字识别的情况。这种不正确变换的一个例子是翻转图像以创建镜像反射。
你可以在我的 GitHub 上找到本文使用的代码。一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。
参考文献
[1] Y. LeCun、L. Bottou、Y. Bengio 和 P. Haffner。基于梯度的学习在文档识别中的应用。IEEE 会议录,1998 年 11 月。—此处可用
R 中的隐含波动率—正确评估期权风险
使用免费提供的数据和 R 来计算和可视化隐含波动率表面,以提高您对期权的风险评估

在 Unsplash 上由 Ishant Mishra 拍摄的照片
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
放弃
本文不提供投资建议,其中的任何内容都不应被理解为投资建议。它为那些不需要建议就能做出投资决定的个人提供信息和教育。
本文包含的信息不是也不应被解读为购买或出售任何证券的要约或建议,或征求购买或出售任何证券的要约或建议。它不是,也不应该被视为使用任何特定投资策略的建议。
最近像 Robinhood 这样的低收费或免费经纪公司的兴起,导致交易期权合约的散户投资者大幅增加。这些金融工具本身比它们的基础股票风险更高,并且这种风险不能通过仅仅使用期权的价格直接测量。因此,必须使用不同的方法来充分评估风险。一个这样的措施是隐含波动率表面。
在本文中,我将描述使用免费提供的数据和 r 获得股票期权的当前隐含波动率表面的过程。结果可用于比较不同股票的风险,并为期权合约定价。我还将演示我们如何创建一个交互式的波动率表面图表,用于即时分析或在仪表板中显示它。
1.介绍

苹果股票的隐含波动率表面(图片由作者提供)
在我们经历必要的步骤来获得和绘制如上图所示的隐含波动率表面之前,我们需要先回答几个问题:
- 什么是隐含波动率,为什么它很重要?
- 隐含波动率是如何计算的?
- 什么是波动表面?
注: 如果你已经熟悉隐含波动率曲面和期权定价的概念,可以跳到第 2 节。下一节将介绍一些关键概念、符号和代码片段,它们将贯穿本文的其余部分。然而,完整的代码可以在文章的结尾找到。
什么是隐含波动率,为什么它很重要?
根据维基百科,隐含波动率定义如下:
期权合约的隐含波动率 ( IV )是基础工具的波动率的值,当输入期权定价模型时,将返回等于所述期权的当前市场价格的理论值。
简单来说,IV 是基于股票当前交易期权价格的股票价格预期未来波动的度量。通常用百分比值来表示股票的预期年标准差范围。
例如,如果苹果(AAPL)目前的交易价格为 119.02,IV 为 25%,这将意味着,预计从现在起一年内,其股价以 68%的概率(对应于正态分布的 1 个标准差)介于 89.27(119.02 *(1-0.25))和 148.78 (119.02 * (1 + 0.25))之间。
那么为什么隐含波动率很重要呢?IV 让我们了解市场参与者如何评估股票价格的不确定性。因此,它是一只股票总体潜在风险的良好指标,也是预期交易范围的预测指标。此外,股票的 IV 允许我们用目前在市场上看不到的参数化期权定价。最后,IV 可用于评估不同股票期权之间的相对价值。由于期权的价格取决于标的的价格,因此不适合比较不同股票的期权。这就是为什么期权价格也经常以波动性而不是价格来报价。
隐含波动率是如何计算的?
隐含波动率一般是通过求解期权定价模型的逆定价公式来计算的。这意味着,不是使用定价模型来计算期权的价格,而是在市场上观察到的价格被用作输入,输出是波动率。
最著名的期权定价模型是广义布莱克-斯科尔斯-默顿模型。虽然这一模型多年来受到了相当多的批评,但由于其简单性和封闭形式的解决方案,它在实践中被广泛使用,我们将在本文中通篇使用它。
欧式看涨期权和看跌期权的封闭解是:

欧式看涨和看跌期权的封闭解
在哪里

d1 和 d2 的公式(图片由作者提供)
- s 是当前的股票价格
- x 是期权执行价格
- σ是隐含波动率
- b 是广义持有成本参数(包括例如无风险利率、股息收益率,如果适用)
- t 是以年为单位的成熟时间
- N(x)是累积正态分布函数

累积正态分布函数(图片由作者提供)
这在 r 中很容易实现。
虽然定价模型为我们提供了一个封闭形式的解决方案,但用于获得 IV 的反向定价模型没有这样的解决方案。因此,我们需要使用优化器来计算 IV。为此,我们在 R 中实现一个目标函数,然后使用优化函数来获得 IV。
让我们通过使用一些真实世界的数据来检查我们的实现是否有效。我们将以苹果公司(AAPL)为例。我们可以从雅虎财经获得我们需要的所有数据,股票数据在这里是,最新的期权价格在这里可以找到。下面是我们将在示例中使用的数据截图。

AAPL 股票的样本数据(截图来自雅虎财经)
从截图中我们可以看到,目前的股价(10 月 16 日)是 119.02,列表中的第一个执行价格是 125,期权价格(我们用的是要价)是 3.55,到期时间是 28 天,显示的 IV 是 45.12%。我们自己计算 IV 所缺少的就是无风险利率。作为近似值,我们将采用 3 个月美国国债利率,目前为 0.11%(你可以在这里找到数据)。
将这些值代入我们的优化函数会产生以下结果:

隐含波动率计算的样本结果(图片由作者提供)
我们的优化产生了 45.11%的 IV,而雅虎财经显示的 IV 为 45.12%。相当不错的搭配(而且好像雅虎财经也在用广义布莱克·斯科尔斯模型)。
注: 你大概已经意识到我们在优化中把股息率 q 设为 0,得到了和雅虎财经一样的结果。当检查苹果的股息率时,可以看到它不是 0。这表明雅虎财经提供的数据可能不完全准确。因此,我们将坚持我们自己的计算。
看着上面的样本数据,你可能已经观察到隐含波动率随着执行价格以及选择不同的到期日而变化。这一观察最终将我们引向隐含波动率表面。
什么是波动表面?
Black Scholes Merton 原始模型的一个主要缺点是,它假设执行价格的波动是恒定的。然而,在实践中,可以观察到不同履约价格的不同波动性。这就是所谓的波动微笑。不同到期日的期权也是如此。因此,隐含波动率沿两个维度变化,即执行价格和到期时间。由于行权价格取决于标的股价,因此不适合跨不同股票进行比较。使用期权货币来代替执行价格。这就是买入期权的股价/执行价和卖出期权的执行价/股价的比值。
这就产生了波动率表面,这是准确定价期权和评估股票价格的潜在不确定性所必需的。
在这个相当长的介绍之后,我们将最后看看如何从实际市场数据中获得隐含波动率表面,并在不同股票之间进行比较。
2.数据
与历史股票数据不同,历史期权链不是那么容易得到的(尤其不是免费的)。然而,由于我们最关心的是用于定价和风险评估的隐含波动率表面的当前状态,所以当前数据也可以。
如简介部分所示,雅虎财经涵盖了我们,例如,你可以在这里找到苹果目前的期权链。为了加载 R 中的数据,我们可以使用 quantmod 包中的 getOptionChain 函数,或者自己抓取。我决定采用后者,因为 getOptionChain 函数没有返回 yahoo finance 提供的 IV 列,我想将这些值与我自己计算的值进行比较。此外,练习网络抓取总是好的!
下面的代码使用 quantmod 包来获取一般的股票信息,使用 rvest 包来抓取期权链。为了避免不可靠的数据点,我们删除了股票上个交易日的最后 5 分钟内没有交易的期权(因为我们将使用股票收盘价来计算 IV ),并设定了资金边界(在 0.85 和 1.15 之间)和到期时间(在 7 天和 6 个月之间)。
这给了我们两个数据框架,一个是看涨期权,一个是看跌期权。

AAPL 看涨和看跌期权的数据框(图片由作者提供)
3.隐含波动率计算
接下来我们自己根据给定的数据计算隐含波动率。你可能会问自己,如果我们可以从雅虎财经获得数据,我们为什么要这样做。我们这样做的原因如下:
- 我们希望能够自己进行这种计算,这样我们就可以在没有 IV 可用的情况下对选项使用相同的方法
- 如介绍中所述,数据计算似乎没有使用股息率
我们将继续以苹果为例,使用引言中描述的方法计算 IV,而不使用股息率。提醒一下,这是我们将要使用的代码。
作为检查,我们可以绘制通过我们的计算获得的 IV 和来自 yahoo finance 的数据之间的差异。

AAPL 电话的计算 IV 与雅虎财经的价值的比较(图片由作者提供)

AAPL 看跌期权的计算 IV 与雅虎财经的价值比较(图片由作者提供)
我们可以观察到隐含波动率之间的绝对差异很小,并且随着到期时间的推移而减小。这是由于前面提到的事实,即我们基于收盘价计算 IV,而最后交易的期权价格基于略有不同的股票价格。这种效应在成熟前的时间越短越强。
在这个例子中,我们没有包括股息收益率。但是,展望未来,我们将包括它。幸运的是,可以使用 quantmod 包中的 getQuote 函数轻松获得数据。我们现在可以重新运行 IV 计算,并使用 reshape2 包中的 acast 函数来创建买入和卖出的 IV 网格。
检查生成的网格会发现,由于没有针对所有履约/到期日的期权价格,我们有相当多的 NAs:

AAPL 看涨期权的波动率网格(图片由作者提供)
为了填补缺失值,我们需要对曲面进行插值。
4.曲面插值
为了执行插值,我们将使用 akima 包中的 interp 函数。它实现了不规则数据的网格二元插值,基本上正是我们需要的。
为了获得完整的表面,我们需要采取的步骤如下:
- 获取每个缺失值的坐标
- 在缺失值周围获取一个最大尺寸为 11x11 的网格
- 使用此格网通过线性或样条插值对缺失值进行插值
- 用插值替换缺失的值
下面是一个代码示例,对缺失的调用值做了进一步的解释。
现在我们有了苹果股票看涨期权的完整隐含波动率表面!我们可以使用 plotly 包在一个漂亮的交互式图表中绘制我们的结果。

苹果股票的隐含波动率表面(图片由作者提供)
我们可以使用相同的代码来获得其他股票的表面,例如特斯拉。

特斯拉股票的隐含波动率表面(图片由作者提供)
我们可以立即看到这两只股票之间的差异,特斯拉本来就比苹果更不稳定,这表现在波动性表面。简单地看期权价格不会显示这一点,因为它们取决于基础股票价格,并且不可能在不同股票之间进行比较。
5.结论
在本文中,我详细介绍了使用免费提供的数据和 r 来获得股票期权的当前隐含波动率表面的过程。这可以用来比较不同股票和定价期权合约的风险。使用 plotly ,我们可以创建一个交互式的波动率表面图表,用于即时分析或在仪表板中显示。
请务必让我知道,如果你有任何反馈或建议,以改善我在这篇文章中所描述的!
完整代码
使用 skiprows、skipfooter、usecols、index_col 和 header 选项将 CSV 文件导入为 Pandas DataFrame
学习使用 read_csv 函数及其提供的一些非常有用的参数
来源:作者
CSV 文件是一种非常常见和流行的数据存储格式。数据科学家几乎定期处理 CSV 文件。Pandas 不仅可以选择将数据集导入为常规的 Pandas 数据帧,还可以选择在导入时清理和调整数据帧。在这里,我想讨论其中的几个选项:
使用 read_csv 方法将 pandas 和数据集作为数据帧导入:
import pandas as pddf = pd.read_csv(‘olympics.csv’)
df.head()

来源:作者
在本教程中,我使用了数据集“olympics.csv”。请 c 点击此处 为数据集。
df.head()只给出数据帧的前五行,因此我们可以看到数据帧的一些属性。df.tail()返回数据帧的最后五行。也可以指定行数。像 df.head(8)将返回前 8 行。您可以使用数据帧长度范围内的任何数字。可以用同样的方式在 df.tail()中指定行数。
df.tail()

来源:作者,数据框的最后五行
看数据集。在顶部,有一个不必要的行。这不是标题。有一个名为 skiprows 的选项可以去掉不必要的行。
df1 = pd.read_csv(‘olympics.csv’, skiprows = 1)
df1.head()

来源:作者,在 skiprows 中使用 read_csv
这里 skiprows = 1,意味着删除一行。默认情况下,它将从顶部删除一行。您可以使用 skiprows 删除 2、3、4 或任意数量的行。但是您可能不想从顶部删除所有行。比如你可能想删除第一行,第三行,第四行。在这种情况下,您可以在列表中指定行。
df2 = pd.read_csv(‘olympics.csv’, skiprows = [0, 2, 3])
有时在 CSV 文件中,没有标题,只有值。但默认情况下,熊猫以第一行为表头。为了避免这种情况,我们可以使用“header = None”。在这个数据集中,有一个头。但是为了这个例子,让我们假设没有标题。
df3 = pd.read_csv(‘olympics.csv’, header = None)df3.head()

来源:作者,使用 read_csv,标题=无
看,熊猫在顶部多加了一行标签来增加标题。它没有将原始数据集中的任何一行作为标题。但是,在这个数据集中,有一个标题。第二行,这意味着行索引 1 是一个标题。让我们通过添加 header = 1 将第二行的第一行指定为标题。
df4 = pd.read_csv(‘olympics.csv’, header = 1)df4.head()

来源:作者,使用 header=1 的 read_csv
在此数据框架中,默认索引列是一个通用序列。有一个有意义的索引是有用的。导入时,您可以将索引设置为您想要的任何列。我选择第一列的国名。所以列索引为零。请记住,索引列被视为一个列。
df5 = pd.read_csv(‘olympics.csv’, index_col = 0, skiprows = 1)df5.head()

来源:作者,将 read_csv 与 skiprows 和 index_col 一起使用
有时数据集的所有列对于分析来说可能不是必需的。尤其是当数据集太大时,呈现一部分总是有意义的。不然就变得太难理解了。这里有一种导入几列的方法。
df6 = pd.read_csv(‘olympics.csv’, skiprows = 1, usecols = [‘Unnamed: 0′,’№ Summer’, ‘№ Winter’, ‘№ Games’], index_col = 0)df6.head()

来源:作者、使用 skiprows 的 read_csv、使用列和 index_col
让我们再次回到 skiprows。使用“for 循环”可以跳过任何范围的行。这个选项有时非常有用。我在这里使用了一个简单的 for 循环。
df7 = pd.read_csv(‘olympics.csv’, skip_blank_lines = False, skiprows = [i for i in range(2, 5)] )df7.head()

来源:作者,read_csv 的使用,其中 skiprows 采用 for 循环
另一个非常动态的想法是定义一个函数,并使用该函数跳过或保留您需要的行。对于这个例子,我在这里定义了一个简单的函数。仅返回偶数索引行的函数。然后,在 skiprows 中使用它来跳过偶数索引行。
def even_rows(index):
if index%2 == 0:
return True
return Falsedf8 = pd.read_csv(‘olympics.csv’, skiprows = lambda x: even_rows(x) )df8.head()
最后,我应该谈谈 skipfooter。Skipfooter 从数据帧的底部跳过行。在这里,我对 skipfooter 使用值 3。因此,它将从页脚跳过三行。
df10 = pd.read_csv(‘olympics.csv’, header = 1, skipfooter = 3)df10.tail()
这就是我想分享的关于使用熊猫图书馆在笔记本中导入 CSV 文件的全部内容。我希望它有帮助。
将 HTML 表格轻松导入 Google Sheets。
了解如何使用 Google Sheets 中的IMPORTHTML功能,从网站导入表格和列表。

"从互联网上获取信息就像从消防水管里喝水一样."— 米切尔·卡普尔
互联网上充斥着大量数据。然而,以正确的格式获取数据才是真正的大事。将数据转换成适合分析的格式需要一定的清理和过滤。上周,我在维基百科上偶然发现了一些非常好的表格数据集。和往常一样,我把数据复制粘贴到 excel 表格上。在大多数情况下,它工作得很好,但是典型的复制-粘贴方法很少失败:
- 当表格通常很长并且遍布整个网页时
- 当数据不是静态的,也就是说,它定期更新。因此,每次原始数据集发生变化时,我都必须再次获取数据集。
对于这种情况,简单的复制粘贴是不够的。抓取是另一个选择,但是我在寻找一个快速简单并且不需要太多代码的东西。就在那时,我在 Google Sheets 中发现了一个叫做**IMPORTHTML**, 的便利功能,它非常适合从 HTML 页面的表格或列表中导入数据。在本文中,我将描述将表格(和列表)提取到 google sheets 的端到端过程。
在提取或导入尚未由您管理的数据之前,请确保您拥有必要的权限。此外,这种方法只有在数据公开的情况下才有效,这意味着不应该有授权等要求。
这篇文章是寻找好数据集的完整系列文章的一部分。以下是该系列中包含的所有文章:
第 1 部分 : 为数据分析任务获取数据集—高级谷歌搜索
第二部分 : 为数据分析任务寻找数据集的有用站点
第 3 部分 : 为深度学习项目创建定制图像数据集
第 4 部分 : 毫不费力地将 HTML 表格导入 Google Sheets
第 5 部分 : 使用 Camelot,从 pdf 中提取表格数据变得很容易。
第六部分 : 从 XML 文件中提取信息到熊猫数据框架
第 7 部分 : 5 个真实世界数据集,用于磨练您的探索性数据分析技能
句法

作者图片
在使用函数之前,我们先快速了解一下IMPORTHTML函数的语法。IMPORTHTML函数接受三个不同的参数,编写如下:
IMPORTHTML(**URL**, query, index)
因素
- URL :指表格所在页面的 URL。不要忘记添加协议(例如 http://).) ,并确保 URL 在引号内。
- 查询:查询可以是表格,也可以是项目列表。例如,如果您想要导入一个表,请在引号中提到表,否则请提到一个列表。
- 索引:指表格在网页上的位置,从 1 开始。
用法:导入表格
现在让我们看看如何快速无缝地将维基百科文章中引用的 HTML 表格导入到 Google sheet 中。页面标题为: 网飞原创电影列表 ,包含美国全球点播互联网流媒体提供商发行的各类电影和节目信息。
第一步:复制网址

图片来源:维基百科
第 2 步:选择要导入的表
假设我们想要导入所有的故事片,这是页面上的第一个表。

图片来源:维基百科
第三步:在谷歌表单中添加公式
创建一个新的 Google 工作表,或者在现有的工作表中创建一个新的标签。在指定 URL、查询和索引号的单元格中输入以下公式。
*=IMPORTHTML("https://en.wikipedia.org/wiki/List_of_Netflix_original_films_(2012%E2%80%932019)","table",1)*
瞧啊。整个表格被提取并填充到电子表格中。以下是你在谷歌表单中看到的内容:

作者图片
让我们结合以上三个步骤,看看下面的端到端演示:

作者图片
您可以用同样的方式导入列表。唯一的变化是用函数参数中的列表替换单词 table。
定制输出:使用查询功能
您可以做很多事情来定制导入的数据。这可以通过结合使用[**Query**](https://support.google.com/docs/answer/3093343?hl=en-GB) 函数和IMPORTHTML.函数来实现。**Query**函数跨数据运行谷歌可视化 API 查询。让我们来看看实现这一点的一些方法:
限制导入列的数量
假设您不想导入所有的列,而是选择几列。您可以传递所需列的索引。例如,如果我们只需要前三列,我们的函数如下:
=query(IMPORTHTML("https://en.wikipedia.org/wiki/List_of_Netflix_original_films","table",1),"Select Col1,Col2,Col3")

作者图片
看看我们是如何用query函数包围IMPORTHTML函数并指定列索引的。
基于列筛选数据
另一种情况是当我们想要一些特定的数据时,即只关于喜剧类型的数据。这可以很容易地做到,如下所示:
=query(IMPORTHTML("https://en.wikipedia.org/wiki/List_of_Netflix_original_films","table",1),"Select * where Col2='Comedy'")

作者图片
查看QUERY功能的官方文档,了解使用它的其他方法。
结论
在本文中,我们看到了IMPORTHTML函数的强大功能,以及如何使用它将来自网站、博客和其他 HTML 源的表格和列表直接导入 google 电子表格。从那里,您可以对数据集执行几个分析任务,并从中获取有意义的信息。您还可以提取数据并与他人共享,这样他们也可以利用这些数据。
数据可视化的重要性——Anscombe 的四重奏。
进入现实世界
四个数据集欺骗了线性回归模型。

作者图片
安斯科姆的四重奏由四个数据集组成,它们具有几乎相同的简单描述性统计,然而具有非常不同的分布,并且在绘制时显得非常不同。
—维基百科
Anscombe 的四重奏可以定义为一组四个数据集,它们在简单的描述统计学中几乎相同,但是数据集中有一些特性,如果建立的话会欺骗回归模型。它们具有非常不同的分布,并且在散点图上绘制时呈现不同的。
它是由统计学家 Francis Anscombe 在 1973 年构建的,用以说明在分析和建模之前绘制图表的重要性,以及其他观测对统计特性的影响。这四个数据集图具有几乎相同的统计观察值,提供相同的统计信息,包括所有四个数据集中所有 x,y 点的方差和均值。
这告诉我们,在应用各种算法来构建模型之前,可视化数据的重要性,这表明必须绘制数据特征,以便查看样本的分布,这可以帮助您识别数据中存在的各种异常,如异常值、数据的多样性、数据的线性可分性等。此外,线性回归只能被视为适合具有线性关系的数据,不能处理任何其他类型的数据集。这四个图可以定义如下:

作者图片
所有这四个数据集的统计信息大致相似,可以计算如下:

作者图片
当这些模型绘制在散点图上时,所有数据集都会生成不同类型的图,任何回归算法都无法对其进行解释,这些算法会被这些特性所迷惑,如下所示:

作者图片
这四个数据集可以描述为:
- 数据集 1: 这个非常符合线性回归模型。
- 数据集 2: 该无法很好地拟合数据的线性回归模型,因为数据是非线性的。
- 数据集 3: 显示了数据集中涉及的异常值,这些异常值不能用线性回归模型处理
- 数据集 4: 显示数据集中涉及的异常值,这些异常值不能用线性回归模型处理
结论:
我们已经描述了四个数据集,这四个数据集旨在描述数据可视化的重要性,以及任何回归算法如何被数据可视化所欺骗。因此,在对数据集中的所有重要特征实施任何机器学习算法之前,必须将其可视化,这将有助于建立良好的拟合模型。
感谢阅读。你可以在这里找到我的其他机器学习相关的帖子。
希望这篇帖子有用。我感谢反馈和建设性的批评。如果你想谈论这篇文章或其他相关话题,你可以在这里或在 LinkedIn 给我发短信。
模型应该符合这些假设,以产生与数据的最佳线性回归拟合。
towardsdatascience.com](/assumptions-in-linear-regression-528bb7b0495d) [## 机器学习中最常见的损失函数
每个机器学习工程师都应该了解机器学习中这些常见的损失函数,以及何时使用…
towardsdatascience.com](/most-common-loss-functions-in-machine-learning-c7212a99dae0)
软件设计在数据科学中的重要性
意见
为什么不应该忽视数据科学和机器学习中的软件设计和开发原则

更新,2021 年 2 月 26 日:我会继续在帖子底部添加链接,以证明我的观点,这篇博文看起来可能像一篇观点文章,但它不是。当涉及到生产中的数据科学时,软件设计是一个事实。
背景
大家都把 R、Python、统计学、数据分析、机器学习的需求作为求职数据科学家的首要技能。我学过很多入门和高级的数据科学和机器学习课程。是的,你需要知道如何编码,但没人谈论的是“软件设计原则”。
软件设计和开发
我们要在任何数据科学或机器学习项目中写代码。生产环境需要大量代码。人们不能认为“加入几个 for 循环,创建一些变量,写一个列表理解”就是数据科学中编码的终结。数据科学中的大多数课程都是一样的,它们侧重于基本的 Python,并以列表理解结束。我们需要知道一般的软件设计原则,还需要了解我们正在使用的编程语言的不同特性。你可以创建一个工具,你可以分析一些东西,单个源代码文件可以是 100-500 行代码(或者更多)。你不能仅仅用基本变量和循环把这么多行代码拼凑在一起。实际上你可以,但这不会对所有人都有好处:对你、你的团队和你的组织(这反而会是一场噩梦)。这就是像面向对象编程这样的设计的用武之地。我每天都读书,到目前为止,唯一写过这方面文章的人是丽贝卡·维克里:
一个完整的学习路径,包括不花你一分钱的资源
towardsdatascience.com](/how-to-learn-data-science-for-free-eda10f04d083)
这就是为什么我们也需要理解生成器和上下文管理器。随着数据科学和机器学习变得自动化,焦点转向云,我们甚至可能不需要知道编程语言(再过 15 年)。但是现在,我认为一个人需要知道基本的软件设计原则。您可以从一些资源开始:
[## 大 O 批注|面试蛋糕
最后简单解释一下大 O 记数法。我会向你展示你在技术面试中所需要的一切…
www.interviewcake.com](https://www.interviewcake.com/article/python/big-o-notation-time-and-space-complexity) [## 面向对象编程
编辑描述
en.wikipedia.org](https://en.wikipedia.org/wiki/Object-oriented_programming) [## 过程程序设计
过程化编程是一种编程范式,源于结构化编程,基于…
en.wikipedia.org](https://en.wikipedia.org/wiki/Procedural_programming)
生产软件
然后就是数据科学行业的现实工作。一个很好的例子就是生产中的机器学习。是的,我们知道模型,知道如何在我们的机器和云上运行它们,知道如何让它们在黑客马拉松中更有效,这很好。但是生产环境是完全不同的。如果你是一名软件开发人员,那么你应该知道我在说什么:分段故障、崩溃、集成问题、版本控制问题等等。幸运的是,有几个人讨论过这个问题,我甚至看到了 Luigi Patruno 的博客:
[## 为什么我开始生产 MLinProduction - ML
有没有发现自己在开始前应该多读一本书或者多上几门在线课程…
mlinproduction.com](https://mlinproduction.com/why-i-started-mlinproduction/)
结论
是的,更大的图景是关于数据的。我们能从中得到什么,以及我们如何向利益相关者展示我们的见解,并告诉决策者从数据中能获得什么样的商业价值。所以你需要首先关注这一点。完成这些之后,不要忘记编码部分,它是产生所有这些结果的部分。它经常被忽视,但却是重要的一部分。您的预测和您的数据一样好,运行这些预测的软件和您对软件设计和开发的理解一样好。你不需要像软件开发人员一样掌握它,但你肯定需要知道基础知识。
2020 年 11 月 12 日更新:我刚刚发现了丽贝卡·维克里的一个帖子,她在里面详细讲述了软件工程原理。比我写的还要好。在这里找到它:
…以及如何学习它们
towardsdatascience.com](/the-essential-skills-most-data-science-courses-wont-teach-you-5ceb0c4d17ce)
2021 年 2 月 26 日更新:找到了软件工程(我称之为软件设计)在数据科学中真正重要的另一个证据。弗拉基米尔·伊格洛维科夫:
本文是对 analyticsindiamag.com 的采访全文。从 2002 年到 2004 年,我在俄罗斯服役…
ternaus.blog](https://ternaus.blog/interview/2020/08/27/interview-to-analyticsindia-full-version.html)
2021 年 3 月 12 日更新:这是 Kurtis Pykes 关于软件工程实践对数据科学有多重要的另一个观点:
成为不可或缺的数据科学家
towardsdatascience.com](/data-scientist-should-know-software-engineering-best-practices-f964ec44cada)
使用表格数据进行预测建模时的重要考虑事项
我对 Coursera.org“如何赢得顶级 Kagglers 的数据科学竞赛”的笔记

https://www.kaggle.com/progression
总的来说,我觉得这门课很有帮助,也很有见地,4.79/5。有许多我以前没有考虑过的想法,所以我在这里贴了一些我的笔记。很有可能,你已经看到了这些想法的大部分,所以我将试着把重点放在最有趣的。这是课程的链接。
火车运行公司
- 数据探索清单
- 验证
- 目标泄漏
- 度量和损失函数
- 指标优化
- 表示编码
- 编码提示
- 高级特征工程
- 群策群力
- 堆叠网
- 创建一套多样化的模型
- 元学习和堆叠技巧
- XG boost 中基于文本的功能
- 序列特征提取(XGBoost)
- 半监督&伪标签
- 我的看法
数据探索清单
- 检查缺失值和异常值
- 检查分类变量的唯一计数
- 分割出数据类型,即数值型、分类型
- 创建“大于”列级比较矩阵
- 寻找相关变量的聚类
- 创建图以找到强大的功能交互
步骤 1、2、3 是几乎每个数据探索管道的一部分。步骤 4、5、6 涉及绘制和比较特征,即,使用 pd.crosstab、相关矩阵或聚合数据。
确认
K-Fold 验证可以说是建模过程中最重要的步骤。出折叠(OOF)样本的预测用于评估模型的平均性能。这也用于超参数调整和模型性能比较。有趣的是,跨 K 个折叠的性能变化也可用于诊断目的,即检查每个折叠中预测的波动性。
目标泄漏
目标泄漏是一个负载话题。基本上,我们不希望模型从生产环境中不可用的信息中学习。索引功能或索引功能的组合可能会导致目标泄漏。更一般地说,目标漏损可以是导致良好模型性能和低附加值的任何东西。
度量和损失函数
这里总结了常见的损失函数和指标。
- MAE——平均绝对误差——当数据集包含大多数数据集不常见的异常值时,优于 MSE
- RMSLE——均方根对数误差——倾向于过度预测,而不是不足预测
- MAPE-平均绝对百分比误差-对较大目标值的误差惩罚较少
- MSPE —均方百分比误差
- AUC——曲线下面积——估计高于随机的模型准确度百分比
- 混淆矩阵-分类器如何在类之间分配预测
- Weight Cohen's Kappa —使用误差矩阵和混淆矩阵来估计(加权误差)除以加权基线,以估计分类器性能。评分者同意系数。
度量优化
- MAPE 和 MSPE 可通过样本权重或重采样进行优化,即 MAPE 的 1/y_i/sum(1/y_i)
- 在分类模型中,模型的输出概率可能与目标变量的分布不匹配。概率可以用模型叠加来校准。校准可以用目标的分类概率和滚动平均值的 CDF 来可视化。
- 当期望的度量在验证数据集上变得更差时,可以利用早期停止来停止训练。
平均编码
均值编码是一个潜在的强大工具,但它也很有可能增加偏差。可以通过使用 K 倍插补、留一插补、平滑平均编码和扩展平均编码来减轻偏倚。这些策略的一些示例代码可以在我的 GitHub 这里找到。
K 倍 CV 均值编码策略可总结如下:
- 分离训练和测试装置
- 分裂训练→ K 折叠训练和 OOF 验证,
- 对 K-fold 训练进行均值编码,然后将值映射到 OOF 验证
- 组合来自 OOF 数据集的均值编码,然后追加到训练数据集
- 估计整个训练的编码,然后映射到测试集
分类变量之间的相互作用也可以进行均值编码。显然,从 XGBoost 中挖掘特性交互是可能的,这里是链接。通过计算两个要素在随机森林中同时出现的次数,您可以创建自己的函数来实现这一点。
编码技巧
- 使用宏加速编码和编辑
- 尝试各种理论,并试图理解为什么一个理论行得通/行不通
- 建立一个快速基线模型,并专注于功能开发
- 修复模型的随机种子
- 将验证训练/测试分割保存在单独的文件中
- 把预测建模想象成一个难题
- 寻找团队成员,整合结果并分享见解
- 将所有不同的模型保存在不同的文件中
高级特征工程
- 计算分类组中的最小值、最大值、平均值和标准值(类似于平均值编码)
- 最近邻统计,N 个最近邻的平均值:平均目标变量,聚类中的平均距离,到分类值的平均距离
- 矩阵分解/降维/t-SNE
整体策略
集成策略使用几个模型的输出到单个预测模型中,通常可以改善结果。
- 加权平均
- 制袋材料
- 加权推进
- 梯度推进
- 堆垛
将模型输出一起平均可以降低任何一个模型中的噪声。可以使用 K 倍 CV 来调整集合权重。权重也可以针对特定类别或目标类进行调整。
Bagging: 创建同一模型的不同版本,并将结果平均在一起。通过改变随机种子、模型参数、行选择和/或列选择来创建不同的模型。
Boosting: 通过一个接一个地顺序训练 ML 模型,将许多弱学习器转换为强估计器,其中每个模型被建立以校正前一个模型的错误。在梯度增强决策树(即 XGBoost)中,梯度和 Hessian 矩阵用于确定哪些特征值得分裂。下面是一些关于 XGBoost 如何工作的有用链接:简明解释,文档,原始论文。
下面是 boosting 算法的简短总结:第一次迭代根据目标的平均值计算误差,其中平均值是预测堆栈中的第一个模型。所有后续模型通过学习速率η*来缩放。模型估计器的数量应该与学习率成反比。
Scikit-learn 有一个为定制模型 sk learn . ensemble . adaboostclassifier 创建增强解决方案的实现。
堆叠:将一组不同的模型组合到另一个模型中,即随机森林、线性模型等。这个过程需要减少目标泄漏。第一组模型的输出不应用于训练第二层第一层以前已经“看到”的数据。对于各种情况,有各种不同的堆叠策略。
以下是本课程第四周的摘录:
a)简单维持方案
- 将列车数据分为三部分:partA、partB 和 partC。
- 在 partA 上拟合 N 个不同的模型,分别为 partB、partC、test_data 获得元特征 partB_meta、partC_meta 和 test_meta。
- 将元模型拟合到零件 B_meta,同时在零件 C_meta 上验证其超参数。
- 当元模型被验证后,将其拟合到[零件 b _ 元,零件 c _ 元]并预测测试 _ 元。
b)具有 OOF 元功能的元维持方案
- 将训练数据分成 K 份。遍历每个褶皱:在除当前褶皱之外的所有褶皱上重新训练 N 个不同的模型,预测当前褶皱。在这个步骤之后,对于 train_data 中的每个对象,我们将有 N 个元特征(也称为非折叠预测,OOF )。让我们称它们为 train_meta。
- 将模型拟合到全列车数据,并对测试数据进行预测。我们姑且称这些特性为test_meta。
- 将 train_meta 拆分成两部分:train_metaA 和 train_metaB。将元模型拟合到 train_metaA,同时在 train_metaB 上验证其超参数。
- 当元模型被验证后,将其拟合到 train_meta 并预测 test_meta。
具有 OOF 元特征的元文件夹方案
- 使用 b.1 和 b.2. 获取 OOF 预测 train_meta 并测试元特性 test_meta
- 使用 train_meta 上的 KFold 方案来验证元模型的超参数。一种常见的做法是将此 KFold 的种子固定为与用于获得 OOF 预测的 KFold 的种子相同。
- 当元模型被验证后,将其拟合到 train_meta 并预测 test_meta。
d)具有 OOF 元功能的维持方案
- 将训练数据分成两部分:部分 a 和部分 b。
- 将 partA 拆分成 K 个折叠。遍历每个折叠:在除当前折叠之外的所有折叠上重新训练 N 个不同的模型,预测当前折叠。在这个步骤之后,对于 partA 中的每个对象,我们将有 N 个元特征(也称为折叠外预测,OOF )。让我们称它们为 partA_meta。
- 将模型拟合到整个 partA,并预测 partB 和 test_data,分别得到 partB_meta 和 test_meta。
- 将元模型拟合到零件 A_meta,使用零件 B_meta 验证其超参数。
- 当元模型通过验证后,基本上执行 2。第三。而不用把 train_data 分成几个部分,然后训练一个元模型。也就是说,首先使用模型获得 train_data 的出叠预测 train_meta 。然后在 train_data 上训练模型,预测 test_data,得到 test_meta。在 train_meta 上训练元模型并预测 test_meta。
e)具有 OOF 元特征的 k 文件夹方案
- 为了验证模型,我们基本上做 d.1 — d.4 ,但是我们使用具有 M 个折叠的 k 折叠策略将训练数据分成部分 partA 和 partB M 次。
- 元模型通过验证后,执行 d.5.
f)时间序列中的 k 折叠方案
在时间序列任务中,我们通常需要预测一段固定的时间。如日、周、月或持续时间为 T 的任意时段。
- 将列车数据分割成持续时间为 T 的数据块。选择第一个 M 块。
- 在这些 M 个块上拟合 N 个不同的模型,并对块 M+1 进行预测。然后将这些模型拟合到第一个 M+1 组块上,并预测组块 M+2 等等,直到你到达终点。之后,使用所有训练数据来拟合模型并获得测试预测。现在,我们将拥有从编号 M+1 开始的组块的元特征,以及用于测试的元特征。
- 现在我们可以从第一个 K 个组块[ M+1 个, M+2 个,.., M+K 来拟合 2 级模型,并在组块 M+K+1 上验证它们。本质上,我们又回到了第一步。用较少的块和元特征代替特征。
g)数据量有限的时间序列中的 k 折叠方案
我们可能经常遇到这样的情况,方案 f) 不适用,尤其是在数据量有限的情况下。例如,当我们只有 2014 年、2015 年、2016 年的数据,而我们需要预测 2017 年全年的数据。在这种情况下,scheme c) 可能会有所帮助,但是有一个限制:KFold 拆分应该在时间部分完成。例如,对于有几年数据的情况,我们将每年视为一个文件夹。
- 将训练数据集分成两部分 A & B,测试数据 C
- 在 A 上训练多个学习者,输出对 B 和 C 预测
- 使用先前模型的堆叠预测,在 B 上定型新模型
- 时间元素应该在 A B 和 C 上单调增加
StackNet
- 多层元学习者可以堆叠在一起
- K-fold 训练,生成每个 K-Fold 的预测,以便创建数据集 B,可以以这种方式创建多个层
- 每个图层都可以使用任何先前图层/模型的输出,甚至可以使用输入数据集
- 创建数据集 C 有两个选项 1)模型可以使用整个训练数据进行训练,然后创建测试集的预测 2)每个 k-fold 模型的每个模型将在测试数据集上进行预测,将对这些模型取平均值
创建一套多样化的模型
- 创建一组多样化的模型
- 2-3 个梯度提升树(在不同深度调整)
- 2–3 个神经网络(不同的架构)
- 1 棵额外的树/随机森林
- 1–2k 邻居模型
- 1 因式分解机(所有成对交互)
- 用于回归的 RBF SVM
- 创建一组多样化的数据管道
- 使用不同的样本
- 使用不同的编码
- 对数值变量使用不同的预处理
- 使用不同的交互变量
元学习和堆叠技巧
- 具有较低深度/较高正则化约束元模型
- 使用具有布雷柯蒂斯距离的 KNN
- 考虑通过交叉验证强力寻找线性权重
- 第二级特征应包括新信息,即元模型输出之间的成对差异、平均编码特征的 KNN 平均距离、分类组内的平均模型预测
- 交叉验证中的高 K 值可能导致目标泄漏,请检查测试性能
- 最终层可以用线性模型来训练,而不用 CV,因为它不会引入太多偏差
XGBoost 中基于文本的功能
- XGBoost 可用于大型 N 元语法特征的特征选择
- 可以在多个文本字段之间创建文本相似性特征,即搜索查询、标题、描述:比较(查询、标题)(查询、描述)、查找匹配单词的数量、TFIDF 表示之间的余弦距离、平均单词之间的距离 2vec、Levenstien 距离
序列特征提取
- 滑动窗口上熵的分布统计
- 具有特征选择的 n 元文法
- 特定关键字功能
- 总序列长度、子序列长度
- 树模型特征选择和转换
- 非负矩阵分解(用于计数数据)
- 移除罕见的一次性编码功能
- L1 正则化的线性/SVM 模型
- 基于 OOF 中最容易出错的数据点创建新要素
- 对目标变量分布使用替换抽样
- 多个(20)样本横截面的平均模型结果
半监督和伪标记
可以使用伪标记方法将测试集包含到训练中(数据越多越好)。使用预测类别(半监督)或从类别分布中随机分配类别。测试集预测也是通过交叉验证计算的。
我的看法
对这些概念进行编码是相当容易的,但是对它们进行灵活编码以测试多个假设是困难的。在 2020 年,在表格数据竞赛中获得大师级地位是非常困难的。获得金牌需要达到排行榜上的前 0.2%。我目前在所有 Kaggle 竞争者中排名 4400,仅获得 2 枚铜牌。通常,有成千上万的竞争者可以使用相似的方法或策略。对于前 10%的人来说,总体策略可能是相似的,但分数可能会随着功能开发、强力超参数调整和随机种子的微小变化而大幅变化。拥有灵活的工作流程非常重要。这些竞赛的最低计算门槛在过去几年里已经大大提高了。为了具有竞争力,您需要高端规格,即 32GB+ RAM、6 核+和 2080 TI GPU+。我认为做一些表格数据竞赛来提高你的预测建模技能是值得的。
数据科学家的重要 GIT 命令
了解数据科学家的重要版本控制基础知识

作为一家商业公司的数据科学家,我们可以独立工作,也可以与团队合作。这是不可避免的,因为很多作品有团队在后面解决会更好。
数据科学团队合作通常会出现问题,主要是历史工作流和编程代码冲突。这就是为什么我们需要一个版本控制来让团队之间有更好的协作。
现在,什么是版本控制?版本控制是一个管理源代码、文件和目录变更的概念。一个流行的版本控制系统是 GIT 。
虽然软件工程师经常使用版本控制,但数据科学家需要在某种程度上了解版本控制。事实上,协作是数据科学家使用版本控制的主要卖点。没有它,我们的工作就会一团糟。
出于上述原因,我想展示 Git 中的几个重要术语和命令,每个人都应该知道。
Git
就像我上面提到的,Git 是一个免费和开源的分布式版本控制系统。Git 被世界上许多公司使用,并被认为是日常编程生活中的一个主要部分。
为了准备这篇文章,我们需要两件东西:
你可能想知道为什么我们会使用 GitHub 这是因为我们需要 workplace 来展示 Git 在协作环境中是如何工作的,GitHub 为我们提供了这一点。
现在,让我们尝试几个可以用 Git 执行的命令。
储存库
在你的 GitHub 账户中,你会发现一个按钮来创建一个新的存储库,它会显示一些类似下图的表单。

虽然,什么是储存库?
当我们使用 Git 管理我们的项目时,Git 会管理两件事情:
- 您的文件(脚本、模型等。)和目录,以及
- Git 信息来维护您的项目随时间的历史变化。
当我们把上面的两部分结合起来,我们就有了我们所说的存储库或回购。
现在,让我们尝试在 GitHub 中创建自己的存储库,看起来应该是这样的。

在一个新的回购之后,我们将尝试利用 Git 命令让您尝试这一次。
GIT 命令
在开始之前,让我们尝试在您的本地驱动器上创建一个新文件夹。你想去哪里都可以。然后在新文件夹里面,尽量有你想要的任何文件;对我来说,这是一个 jupyter 笔记本。

之后,尝试右键单击新文件夹并选择“Git Bash Here”

会出现一个命令提示符,这是您第一次使用,可能需要您输入凭证信息。只要按照步骤,我们就可以开始了。
1.Git 初始化
每个英雄都有开始,Git 也是。当您在本地使用 Git 进行版本控制时,您需要首先设置环境。
Git init 就是用来做这个的。尝试在您的命令提示符下运行git init,其中的目录位于您想要的文件夹中。应该有一个类似这样的消息。

现在,我们已经在本地文件夹中设置了环境或 repo,准备接受任何 git 命令。
2.Git 状态
我们要做的下一步是检查我们的 git 环境状态。这里的状态是指检查暂存区中是否有文件。
那么,什么是集结地呢?这基本上是一个区域,在对文件进行任何更改之前,您可以在这里放置或跟踪文件。如果您要发送、删除或添加任何新文件,这是文件排序的位置。这被称为集结地,因为过了这个区域,它将是永久的。
要尝试这个命令,我们可以在命令提示符下运行git status。它应该显示类似这样的内容。

使用这个命令,可以显示我们文件的状态。我们只有未跟踪的文件,这意味着该文件尚未添加到临时区域。那么,下一步该怎么办呢?我们需要将这些文件添加到暂存区。
3。Git 添加
正如您在上面看到的,我们通过运行git add命令将文件添加到暂存区。具体来说,我们需要键入git add <filename>,其中<filename>是您想要添加到暂存区的文件的名称。
手动添加每个文件名会很麻烦。想象一下,如果本地文件夹中有一千个文件,输入每个文件需要多长时间。在这种情况下,我们可以通过在命令提示符下运行git add .将文件夹中的所有文件添加到暂存区。
当您将每个文件添加到暂存区时,尝试再次运行git status。应该是这样的。

文件夹中的每个文件现在都在临时区域中。
4.Git 提交
当我们已经将所有文件放在临时区域中时,如果我们想要临时区域文件是我们想要的,我们需要提交。
如果您确定,那么我们需要运行git commit命令。完整的命令是git commit -m "<your comment>",其中<您的注释>是您的日志消息或一些让您记住的简单注释。
让我们试着跑一下git commit。完成后,它应该是这样的。

在我的文件夹中,有两个文件,所以这就是为什么有两个文件提交。
5。Git 日志
如果您需要查看您在回购中所做的每一次提交,我们可以运行git log。它可以显示您的存储库的提交历史。作为作者,应该有重要的信息,提交键、提交日期和日志消息。
6。Git 推送
当您在 GitHub 中创建一个新的 repo 时,您会看到一系列类似这样的消息。

您可以从头到尾运行这个命令,但是现在唯一重要的部分是了解什么是git push。
这个git push命令将您的回购从本地放到 Git Hub 的在线回购中。它就是喜欢这个名字,推回购。
在这一步,我将跳过运行git branch -M main命令,因为我们现在不需要它。
你需要首先运行的是git remote add origin <your git domain>,其中<你的 git 域名>是你的 git 回购的地址。
因此,我们在上面的命令中使用变量 object are
当您创建了‘origin’变量后,我们需要将本地回购推送到‘origin’回购。我们接下来需要做的是运行git push -u origin master。这个命令会将我们的本地 repo(称为 master)推到“原点”完成后,它应该是这样的。

你的 GitHub repo 应该是这样的。

我们知道已经使用 Git 跟踪了我们文件和数据的历史版本,并且历史也存储在 GitHub 的本地 repo 中。
结论
Git 对数据科学家很重要,因为数据科学团队合作通常会出现问题;主要是历史工作流程和编程代码冲突。Git 可以帮助我们解决这些问题。
在本文中,我向您介绍了基本的 Git 命令,它们是:
- Git 初始化
- Git 状态
- Git 添加
- Git 提交
- Git 日志
- Git 推送
希望有帮助!
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
重要信息熊猫系列和数据框架方法
你需要知道的一些最有用的方法

尼克·希利尔在 Unsplash 上的照片
无论您是刚刚学习数据科学,还是拥有多年使用 Python 作为主要编程语言经验的专业人士,Pandas 模块都将是您的主要武器。我们使用 Pandas 的主要原因之一是因为这个库拥有称为系列和数据框的对象。我将使用 seaborn 模块中的 mpg 数据集示例来解释整篇文章。
import pandas as pd
import seaborn as sns
import numpy as np#Load the mpg dataset
mpg = sns.load_dataset('mpg')
这就是系列的样子,一个很好的变量/列/特征;取决于你喜欢怎么称呼他们。

系列对象的示例
这是一个数据框,一个由许多系列组合成一个对象的数据集。

数据框对象的示例
只要看一下对象,我们就知道系列和数据框是我们分析数据的地方。这就是这两个对象对数据科学家的重要性。因此,我想介绍这些对象的一些重要方法,以获得在您的数据科学日常工作中肯定会有帮助的信息。
我喜欢数列和数据框方法的原因是我能多快地获得我需要的信息。这里有几个我觉得知道很重要的方法。
1.DataFrame.info
。info 方法是针对数据框对象的方法。它会给你下图所示的所有重要信息。
mpg.info()

只用一行字,我就能一次获得大量信息。这些信息是数据的总数,有多少列,列名与有多少数据不为空,数据类型,以及内存使用量。
2.Series.describe 或 DataFrame.describe
。描述方法既可以在序列对象中实现,也可以在数据框对象中实现。让我们看看通过使用。描述方法。
mpg.describe()

从上图中,我们可以看到我们得到的所有数值数据的基本统计;也就是计数,均值,标准差,最小值, 25%分位数, 50%分位数(中位数), 75%分位数,以及最大值。
如果我们想得到非数值型数据的基本统计数据呢?我们也可以这样做。
#Input exclude parameter as 'number' to exclude all the numerical columnsmpg.describe(exclude = 'number')

在这种情况下,我们排除所有的数字列(数字包括布尔列),并以非数字列结束。我们可以看到,这些信息包括 Count 、 Unique (唯一值的个数)、 Top (最频繁的值)、以及 Freq (最频繁的值)。
的。描述方法也存在于系列对象中;更具体地说。描述方法输出的数据框对象是系列对象的统称。
mpg['mpg'].describe()

这是我们使用。通过列基本统计的系列对象描述方法。
3.Series.agg 或 DataFrame.agg
如果我们只需要一个特定的统计数据,并希望将它包含在一个地方,该怎么办?这是我们使用。agg 方法。此方法用于将许多统计数据聚合到一个系列或数据框对象中。我们就举个例子试试吧。
mpg.agg('mean')#we could also use function here, e.g. Numpy
#mpg.agg(np.mean)

。agg 方法接受函数和/或字符串作为参数输入。在上面的图片中,我们从所有的数字列中得到一系列的平均值。
现在,如果我们想要不止一种类型的信息,我们可以做到这一点。我在下面的例子中展示了它。
mpg.agg(['mean', 'std'])

代替字符串或函数,我们用一个包含所有我们想要的信息的列表对象来输入参数。这一次,我们得到了一个数据框对象,其中包含了我们需要的所有信息。
系列也有。我们可以使用的 agg 方法。
mpg['mpg'].agg(['mean', 'std'])

结果将是我们在列表对象中包含的基本统计数据的一个数字或一系列对象。
4.数据框架
该方法用于获得数值列之间的相关性矩阵。如果你想了解更多,你可以在这里阅读我关于相关性的文章。
以及在我们的分析中如何解释它
towardsdatascience.com](/what-it-takes-to-be-correlated-ce41ad0d8d7f)
让我们用一个例子来试试这个方法。
mpg.corr()

默认情况下,相关性方法会计算数值列之间的皮尔逊相关性。我们可以将参数更改为我们自己定义的 Spearman 相关性、 Kendall 相关性或可调用函数。
5.DataFrame.groupby
该方法根据分类列的类别对所有数字列进行分组。输出是一个 groupby 对象。下面我们通过一个例子来试试。例如,我想按来源对 mpg 数据进行分组。
mpg_groupby_origin = mpg.groupby('origin')#Groupby object have many method similar to the series or dataframe; for example .meanmpg_groupby_origin.mean()

从上面的代码中,我们得到了所有数字列的平均值,但是是按照原点的类别分组的。我们也可以使用。groupby 对象的 agg 方法。
# .T is a method to transpose the DataFrame
mpg_groupby_origin.agg(['mean', 'std']).T

的。agg 方法类似于我们上面使用的方法。我们输入参数或者是一个字符串/函数,或者是以字符串/函数为值的列表对象。
结论
我试图解释熊猫系列和 DataFrame 对象的一些信息方法。这些包括:
- 。信息
- 。形容
- 。集料
- 。corr
- 。分组依据
希望有帮助!
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您没有订阅为中等会员,请考虑通过我的介绍订阅。
数据工程熊猫简明指南—第 1 部分
数据工程是数据科学的一个方面,侧重于数据采集和分析来源的实际应用。他们建立的管道对数据科学家转换数据非常有用。他们需要了解无数的技术,并为这项工作选择合适的工具。

癌症患者的数据图表
内容:
- 进口
- 出口
- 看法
- 索引
- 子集化
- 提取行和列
- 取代
- 添加/删除
- 排序和重命名
- 结合
- 聚集
导入:
导入 pandas 库以将 CSV 文件或 XLSX 格式的文件转换为 dataframe。
import pandas as pd
import numy as npcancer_df = pd.read_excel("cancer_patient_data_sets.xlsx")
cancer_df = pd.read_csv("cancer_patient_data_sets.csv")
要成功运行以上代码行,请确保将文件上传到 Google Colab 的content文件夹中,或者当您在 Jupyter Notebook 中工作时上传到您的本地文件夹中。你也可以从 S3 或谷歌硬盘上读取文件。
谷歌驱动:
I)将您的 google drive 安装到 colab
from google.colab import drive
drive.mount('/content/gdrive')
ii)现在,您将在左侧窗格(文件浏览器)中看到您的 Google Drive 文件。右键单击需要导入的文件,选择复制路径。然后在 pandas 中照常导入,使用这个复制的路径。
import pandas as pd
cancer_df = pd.read_csv('gdrive/My Drive/cancer_patient_data_sets.csv')
AWS S3:现在熊猫可以处理 AWS S3 网址了。简单地做
import pandas as pd
import s3fs
cancer_df = pd.read_csv('s3://bucket-name/file_name.csv')
构建数据框架:如果你有数据,想构建一个数据框架,你可以这么做。
sample_df = pd.DataFrame([[1,'Bob','M','31','Builder'],
[2,'Sally','F','29','Baker'],
[3,'Scott','M','28','Candle Stick Maker']],
columns=['id','name','gender','age','occupation'])
导出:
您可以通过以下代码行将最终输出保存为 CSV 或 EXCEL 格式
output_df.to_csv('saved_patients.csv', index=False)
output_df.to_excel('saved_patients.xlsx', index=False)
查看:
显示数据帧顶部或底部的几条记录
sample_df.head(5)
sample_df.tail(5)
索引:
索引您的数据帧:
- 仅索引数据帧中的一个列:
sample_df = sample_df.set_index('id')
sample_df
- 对数据帧中的多列进行索引:
sample_df = sample_df.set_index(['id','age'])
sample_df
- 要重置数据帧中的索引:
sample_df.reset_index(inplace = True)
sample_df
子集化:
- 要从现有数据框架中选择有限数量的列并将其存储在新数据框架中:
df = sample_df[['age', 'name', 'occupation']]
df
- 要对行进行子集划分并考虑所有列:
#Select first 3 rows :
df[0:3]*# Select first 5 rows (rows 0, 1, 2, 3, 4)* df[:5]*# Select the last element in the list
# (the slice starts at the last element, and ends at the end of the list)* df[-1:]
- 使用
loc方法从我们的数据帧中选择行和列:这个命令通过行和列的标签选择数据。
*# Select all columns for specific rows of index values 0 and 2 where no specific column in the dataframe has any index*data = pd.read_csv("nba.csv")
df = data.loc[[0, 2], :]*# Select all columns for a specific row or multiple rows where a column is set as an index* data = pd.read_csv("nba.csv", index="name")
df **=** data.loc[["Avery Bradley"]]
OR
df **=** data.loc[["Avery Bradley", "R.J. Hunter"]]# *Select specific rows and specific columns*data = pd.read_csv("nba.csv", index="name")
df = [["Avery Bradley", "R.J. Hunter"],["Team", "Number", "Position"]]*# Select only one or multiple specific row/rows and multiple columns after resetting index*data.reset_index(inplace = True)
df = data.loc[0, ['Name', 'Number', 'Age', 'Position']]
OR
df = data.loc[[0,5], ['Name', 'Number', 'Age', 'Position']]
- 使用
iloc方法从我们的数据帧中提取行和列的子集:这个命令允许我们按位置检索行和列。
# *Slice certain number of rows and columns*
df = sample_df.iloc[0:3, 1:4]
*# Select the value of second row and third column* df = sample_df.iloc[2, 3]*# Select all rows and selected columns* df = sample_df.iloc [:, [1, 2]]# *Select certain range of rows and all columns*
df = sample_df.iloc[[0, 2]]
- 要根据标准选择数据帧:
# Select dataframe where the value of a column is given
df[df.year == 2002]# Select dataframe on multiple conditions
df[(df.year >= 1980) & (df.year <= 1985)]ORdf = df[(df.year >= 2000) & (df.gender == 'M')]
- 使用
isin命令:Pandasisin()方法有助于选择特定列中具有特定值或多个值的行。
new = sample_df["gender"].isin(["M"])
sample_df[new]ORfilter1 **=** sample_df["gender"].isin(["M"])
filter2 **=** sample_df["occupation"].isin(["Baker", "Builder"])# displaying data with both filter applied and mandatory
sample_df[filter1 & filter2]
- 要选择数据帧中包含空值的行:
*# To select just the rows with NaN values, we can use the 'any()' method* sample_df[pd.isnull(sample_df).any(axis=1)]
- 使用 lookup()函数:lookup()函数为 DataFrame 返回基于标签的“花式索引”函数:

更换:
替换数据帧中的值:
- 函数
mask()用于替换标准数据框中的所有值
# replace all the values greater than 10 with -25
df.mask(df > 10, **-**25)# replace the Na values with 1000
df.mask(df.isna(), 1000))
- 使用
where()函数根据一个或多个特定标准过滤数据集
filter **=** sample_df["gender"]**==**"M"
data.where(filter, inplace **=** True)ORfilter1 **=** sample_df["gender"]**==**"M"
filter2 **=** sample_df["age"]>24
sample_df.where(filter1 & filter2, inplace **=** True)
提取行或列:
- 使用
get()函数从数据帧中提取一列或多列
sample_df.get("occupation")ORsample_df.get(["name", "age", "occupation"])
- 使用
pop()功能删除一列或多列
# Remove one column from the original dataframe
popped_col **=** sample_df.pop("occupation")
sample_df# make a copy of the data frame and insert the popped column at the end of the other data frame
new **=** sample_df.copy()
popped_col **=** new.pop("name")
# creating new col and passing popped col
new["New Col"]**=** popped_col
new
添加/删除:
删除列:
del sample_df['column_name']
- 使用
drop()功能删除一行或多行或多列
df = data.drop('column_1', axis=1)# Delete multiple columns from the dataframe
df = data.drop(["column_1", "column_2", "column_3"], axis=1)# Delete multiple rows from the dataframe
data = df.drop([0,1], axis=0)
data# drop rows where age is less than 25
df_filtered **=** df[df['Age'] >**=** 25]# drop rows with null values
df **=** df.dropna(how **=** 'all')
- 向现有数据框架添加新列或新行
# Add a new column in the existing dataframe by providing the values manually in a list format
sample_df['salary'] = [250000, 150000, 100000]
sample_df# Add a new column by performing simple calculation on any other existing column
sample_df['new_col'] = sample_df['salary']*2
sample_df# Add a new column having same constant values
sample_df['new'] = 'y'
sample_df
OR
sample_df['new'] = sample_df.apply(lambda x: 'y', axis=1)# Insert a new row in an existing dataframe:
sample_df.loc[3] = [4, 'Mike', 26, 'Delivery boy']
sample_dfOR

在现有数据框架中插入新行
排序和重命名:
按行和列对数据帧进行排序:
# use sort_index() to sort by row index or names
sample_df = sample_df.set_index('name')
sample_df.sort_index(inplace**=**True)# sort on multiple columns by descending order
sort_by_age_occ **=** sample_df.sort_values(by = ['age','occupation'], ascending = False)# sort a column in ascending order
a **=** sample_df.sort_values(by **=**'age', ascending **=** True)
重命名数据帧中的列:
sample_df.rename(columns **=** {'occupation':'Occupation', 'age':'Age', 'name':'Name'}, inplace **=** True)
结合:
有各种类型的连接:
- 一对一连接:例如当连接索引上的两个对象时(必须包含唯一值)。
- 多对一连接:例如,将一个索引(唯一的)连接到不同数据框架中的一个或多个列。
- 多对多联接:联接列上的列。
- 使用 merge()连接两个数据帧
'''
There are 3 dataframes (df1, df2, df3) having similar column names - 'id', 'Feature1', 'Feature2'. You can merge 2 dataframes on a specific column.
'''
df_merge = pd.merge(df1, df2, on='id') # Combine two dataframes which will contain all the records
df_outer = pd.merge(df1, df2, on='id', how='outer')# Combine two dataframes which will contain only the common records between the them
df_inner = pd.merge(df1, df2, on='id', how='inner')# Combine two dataframes which will contain the common records between the them along with all the records of first dataframe
df_left = pd.merge(df1, df2, on='id', how='left')# Combine two dataframes which will contain the common records between the them along with all the records of second dataframe
df_right = pd.merge(df1, df2, on='id', how='right')#Combine two dataframes on the records present in the index column
df_index = pd.merge(df1, df2, right_index=True, left_index=True) df_index
- 使用 concat()连接相似列名的两个数据帧

我们也可以使用append()通过使用result = df1.append(df2)得到上面的结果
- 使用 concat()连接不同列名和不同行的两个数据帧

聚合:
可以将 max()、min()、mean()、first()、last()等函数快速应用于 GroupBy 对象,以获得数据帧中每个组的汇总统计信息。
如果你喜欢这篇文章,你可能也会喜欢下一篇文章,它将更加关注一些重要的函数以及它们在数据工程中的用途。
感谢阅读。😃希望你能像我准备这篇文章时一样喜欢它..
每个数据科学家都必须知道的机器学习的重要主题
评估机器学习的基础

图片作者:特里斯特·约瑟夫
机器学习(ML)是“人工智能的一种应用,它为系统提供了自动学习和根据经验改进的能力,而无需显式编程。”ML 算法用于在数据中寻找产生洞察力的模式,并帮助做出数据驱动的决策和预测。这些类型的算法每天都在医疗诊断、股票交易、交通运输、法律事务等领域被用来做出关键决策。所以可以看出数据科学家为什么把 ML 放在这么高的基座上;它为高优先级决策提供了一个媒介,可以在没有人工干预的情况下实时指导更好的业务和智能行动。
现在,人工智能模型不一定像人类那样“学习”。相反,这些算法使用计算方法来直接从数据中理解信息,而不依赖于预先确定的方程作为模型。为此,使算法确定数据中的模式并开发目标函数,该目标函数最佳地将输入变量 x 映射到目标变量 y 。这里必须注意,目标函数的真实形式通常是未知的。如果函数是已知的,那么就不需要 ML。
因此,其思想是通过对样本数据进行合理的推断来确定该目标函数的最佳估计,然后针对当前情况应用和优化适当的 ML 技术。不同的情况要求对被估计函数的形式作出不同的假设。此外,不同的最大似然算法对函数的形状做出不同的假设,因此,它应该如何被优化。可以理解的是,人们很容易被 ML 的学习内容所淹没。因此,在这篇文章中,我讨论了每个数据科学家都应该知道的两个重要的 ML 主题。

图片作者:特里斯特·约瑟夫
- 学习的类型
最大似然算法通常分为监督的或非监督的,这广义上指的是数据集是否被标记。监督 ML 算法通过使用标签化的例子来预测未来的结果,将过去学到的知识应用到新的数据中。本质上,对于这些类型的问题,正确的答案是已知的,并且基于预测的输出是否正确来判断估计模型的性能。相比之下,无监督 ML 算法指的是当用于训练模型的信息既没有被分类也没有被标记时开发的算法。这些算法试图通过提取样本中的特征和模式来理解数据。
现在半监督学习确实存在,它采取了监督和非监督学习之间的中间地带。也就是说,数据的一小部分可能被标记,而其余部分没有被标记。

图片作者:特里斯特·约瑟夫
当给定的任务是分类或回归问题时,监督学习是有用的。分类问题指的是根据模型开发的特定标准将观察结果或输入数据分组到离散的“类”中。一个典型的例子是预测一封电子邮件是垃圾邮件还是非垃圾邮件。该模型将在包含垃圾邮件和非垃圾邮件的数据集上开发和训练,其中每个观察都被适当地标记。
另一方面,回归问题是指接受一组输入数据并确定一个连续量作为输出的过程。一个常见的例子是根据个人的教育水平、性别和总工作时间来预测个人的收入。

图片作者:特里斯特·约瑟夫
当特定问题的答案或多或少未知时,无监督学习是最合适的。这些算法主要用于聚类和异常检测,因为有可能在不确切知道观察指的是什么的情况下检测整个观察的相似性。例如,人们可以观察各种花的颜色、大小和形状,然后粗略地将它们分成几组,而不必真正知道每种花的种类。此外,假设一家信用卡公司正在监控消费者行为。通过监控交易发生的地点,有可能发现欺诈性交易。例如,假设在纽约经常使用信用卡。如果在某一天,该卡在纽约、洛杉矶和香港使用,那么它可能被认为是一种异常,系统应该向相关方发出警报。

图片作者:特里斯特·约瑟夫
- 模型拟合
拟合模型是指让算法确定预测值和结果之间的关系,以便可以预测未来值。回想一下,模型是使用训练数据开发的,训练数据是精确反映总体的理想的大型随机样本。这一必要的行动伴随着一些非常不可取的风险。完全精确的模型很难估计,因为样本数据会受到随机噪声的影响。这种随机噪声,以及研究人员做出的大量假设,有可能导致 ML 模型学习数据中的虚假模式。如果试图通过做很少的假设来应对这种风险,就会导致模型无法从数据中获取足够的信息。这些问题被称为过拟合和欠拟合,目标是确定简单性和复杂性之间的适当组合。

图片作者:特里斯特·约瑟夫
过度拟合发生在模型从训练数据中学习“太多”时,包括随机噪声。然后,模型能够确定数据中非常复杂的模式,但这会对新数据的性能产生负面影响。训练数据中拾取的噪声不适用于新的或看不见的数据,并且该模型不能概括所发现的模式。某些最大似然模型比其他模型更容易过度拟合,这些模型包括非线性和非参数模型。对于这些类型的模型,可以通过改变模型本身来克服过度拟合。考虑一个非线性方程的 4 次幂。一旦仍然产生可接受的结果,可以通过将模型的幂降低到可能的 3 次方来降低过拟合。或者,可以通过对模型参数应用交叉验证或正则化来限制过拟合。

图片作者:特里斯特·约瑟夫
另一方面,欠拟合发生在模型无法从训练数据中学习到足够多的信息时。然后,模型就无法确定数据中合适的模式,这会对新数据的性能产生负面影响。由于所知甚少,该模型无法对看不见的数据应用太多,也无法对手头的研究问题进行概括观察。通常,欠拟合是由于模型设定错误造成的,可以通过使用更合适的 ML 算法来解决。例如,如果用一个线性方程来估计一个非线性问题,就会出现欠拟合。虽然这是真的,但欠拟合也可以通过交叉验证和参数正则化来纠正。
交叉验证是一种用于评估模型拟合度的技术,通过在样本数据集的不同子集上训练几个模型,然后在训练集的互补子集上评估它们。
规则化指的是向模型参数添加信息的过程,以应对模型性能不佳的问题。这可以通过指定参数遵循特定分布来实现,例如正态分布对均匀分布;或者通过给出参数必须落入的值的范围。

图片作者:特里斯特·约瑟夫
机器学习模型非常强大,但强大的能力也意味着巨大的责任。开发最合适的 ML 模型要求研究者充分理解手头的问题以及在给定的情况下什么技术是合适的。理解一个问题是被监督的还是未被监督的将提供一些关于将使用什么类型的 ML 算法的洞察力;而了解模型拟合度可以防止部署时模型性能不佳。快乐造型!
参考文献:
machine learning mastery . com/how-machine-learning-algorithms-work/
其他有用的素材:
simpli learn . com/机器学习对数据科学家的重要性-文章
towards data science . com/important-topics-in-machine-learning-you-need-to-know-21 ad 02 cc 6 be 5
scikit-learn.org/stable/modules/cross_validation.html
nintyzeros.com/2020/03/regularization-machine-learning.html
导入错误:没有名为“XYZ”的模块
Jupyter 笔记本找不到你已经安装的软件包?让我们解决问题。

如果你像我一样使用 Python 处理数据,那么你应该对标题中的错误信息再熟悉不过了。对你来说,这可能是最容易解决的问题之一。
我一直是这么想的,直到我在我的 Jupyter 笔记本上看到这条错误信息,它几乎让我发疯。
在这篇文章中,我将与你分享我遇到的问题和解决方法。希望能帮你在遇到同样的问题时节省一些时间。
模块导入问题
错误信息是找不到模块,所以我试着通过 pip install 、 easy_install 和 conda install 安装软件包,并重启 Jupyter 笔记本几次。
该包仍然无法导入笔记本。
为了确保我已经安装了这个包,我还通过在终端中键入“ python ”并导入这个包来检查我的 python 环境。这样做没有错误,这表明软件包安装正确。
因此,我很确定只有我的 Jupyter 笔记本有问题。
我想更好地框架如下问题。
为什么我不能导入已经安装在我的 Jupyter 笔记本上的 Python 包?
检查
要检查的是 Jupyter 笔记本使用的是哪种 python。因此,在 Jupyter 笔记本中键入下面的命令来提取可执行路径。
import sys
sys.path
这是我得到的,
'/Users/yufeng/anaconda3/envs/py33/lib/python36.zip',
'/Users/yufeng/anaconda3/envs/py33/lib/python3.6',
'/Users/yufeng/anaconda3/envs/py33/lib/python3.6/lib-dynload',
'/Users/yufeng/anaconda3/envs/py33/lib/python3.6/site-packages',
'/Users/yufeng/anaconda3/envs/py33/lib/python3.6/site-packages/aeosa',
'/Users/yufeng/anaconda3/envs/py33/lib/python3.6/site-packages/IPython/extensions',
'/Users/yufeng/.ipython'
然而,如果我在系统的 Python 中键入相同的命令,我会得到以下结果,
'/Users/yufeng/anaconda3/lib/python37.zip', '/Users/yufeng/anaconda3/lib/python3.7', '/Users/yufeng/anaconda3/lib/python3.7/lib-dynload', '/Users/yufeng/anaconda3/lib/python3.7/site-packages'
到现在为止,我们可以看到 Jupyter 笔记本 和 系统默认 Python 在 Python 环境上的区别。所有的包安装都通过 pip 安装和 conda 安装定向到系统默认的Python/3.7 和而不是py33 和笔记本所使用的环境。
解决方案
从头开始重新构建整个环境肯定是可行的,但是最简单的解决方案是将目标包安装到 Jupyter 笔记本的正确环境中。
在我的例子中,如上所示,Jupyter Notebook 中的可执行 python 是
/Users/yufeng/anaconda3/envs/py33/lib/python3.6
所以,我用它自己的 pip 重新安装包。通常自己的 pip 安装在同一个根目录下名为 /bin/ 的文件夹中。
/Users/yufeng/anaconda3/envs/py33/bin/python -m pip install plotly
在那之后,我能够成功地在我的 Jupyter 笔记本中导入新包(“plotyly”,可以更改为您的目标包名称)。
就是这样,简单又有用的一招。
通过分享这个经验,祝你不要像我一样在问题上浪费很多时间。

斯科特·沃曼在 Unsplash 上拍摄的照片
将数据导入 Google Colab——干净利落的方式
因为干净的代码很重要!
在这篇文章中,我将介绍:
- Google Colab 简介
- 2 种常用的“快速而肮脏”的方法将数据上传到 Colab
- 2 种自动化的“干净”方法将数据上传到 Colab
Google Colab 是什么?
现在还很难相信,但这是真的。我们可以在 Google Colab 上免费运行重型数据科学笔记本。

Google Colabs
Colab 是一项云服务,这意味着谷歌的服务器将运行笔记本电脑,而不是你自己的本地电脑。
也许更令人惊讶的是,****它背后的硬件相当不错!****
Colab 是完美的新笔记本解决方案吗?
Google Colab 有一个大问题,以前经常讨论,那就是你数据的存储。笔记本电脑,例如 Jupyter 笔记本电脑,通常使用存储在本地计算机上的数据文件。这通常使用简单的 read_csv 语句或类似语句来完成。
云的本地不是你的本地。
但是谷歌合作实验室正在云中运行。云的本地不是你的本地。因此 read_csv 语句将在 Google 端搜索文件,而不是在您端。然后它就找不到了。
如何将您的数据输入 Colab——手动方式?

乌云因为手动上传不是最好的做法!由 LoboStudio Hamburg 在 Unsplash 上拍摄的照片
为了将您的数据输入到您的 Colab 笔记本中,我首先讨论两种最常见的方法,以及它们的优缺点。之后,我讨论了两个备选解决方案,它们可能更合适,尤其是当您的代码必须易于工业化时。
手动方法 1 —使用 files.upload()将数据上传到 Colab
- 直接在 Colab 笔记本中使用 files.upload() 会给你一个传统的上传按钮,允许你将文件从你的计算机移动到 Colab 环境中。

直接在 Colab 笔记本中使用 files.upload()会给您一个传统的上传按钮,允许您将文件移动到 Colab 环境中
2.然后你用木卫一。StringIO()和 pd.read_csv 一起将上传的文件读入数据帧

然后你用木卫一。StringIO 与 pd.read_csv 一起将上传的文件读入数据帧
使用 files.upload()将数据上传到 Colab 的优势: 这是所有方法中最简单的方法,尽管它需要几行代码。
使用 files.upload()上传数据到 Colab 的缺点: 对于大文件,上传可能需要一段时间。然后每当笔记本电脑重新启动时(例如,如果它失败或其他原因…),必须手动重新上传。这不是最好的解决方案,因为首先我们的代码在重启时不会自动重新执行,其次在笔记本出现故障的情况下需要繁琐的手动操作。****
手动方法 2——将 Google Drive 安装到 Colab 上
在开始使用笔记本电脑之前,请将您的数据上传到 Google Drive。然后将 Google Drive 安装到 Colab 环境中:这意味着 Colab 笔记本现在可以访问 Google Drive 中的文件。
- 使用 drive.mount()挂载您的驱动器

2.直接访问 Google Drive 中的任何内容

把你的 Google Drive 挂载到 Colab 上的优势: 这也是相当容易的。Google Drive 非常用户友好,对大多数人来说,将你的数据上传到 Google Drive 没有问题。此外,上传完成后,重启笔记本时不需要手动重新加载。所以比方法 1 好。
将你的 Google Drive 挂载到 Colab 上的缺点: 我从这种方法中看到的主要缺点主要是公司/工业使用。只要您在从事相对较小的项目,这种方法就很棒。但是如果访问管理和安全处于危险之中,你会发现这种方法很难产业化。****
此外,您可能不希望处于 100%谷歌的环境中,因为多云解决方案让您更加独立于不同的云供应商。
干净利落的方式—使用外部数据存储

干净的数据存储是最佳实践!Em bé khóc nhè 在 Unsplash 上拍摄的照片
如果您的项目很小,并且您知道它将永远只是一个笔记本,那么以前的方法是可以接受的。但是对于任何未来可能会变得更大的项目,将数据存储从您的笔记本电脑中分离出来是朝着更好的架构迈出的良好一步。
如果你想在你的 Google Colab 笔记本上建立一个更干净的数据存储架构,尝试一个合适的数据存储解决方案。
Python 中有许多与数据存储连接的可能性。我在这里提出两个解决方案: AWS S3 用于文件存储和 SQL 用于关系数据库存储:
清洁方法 1 —连接一个 AWS S3 桶
S3 是 AWS 的文件存储,其优势在于与之前描述的向 Google Colab 输入数据的方式非常相似。如果你不熟悉 AWS S3,不要犹豫,看看这里。

亚马逊 S3 是 AWS 简单存储服务——一种易于使用的云中文件存储
从 Python 访问 S3 文件存储是非常干净的代码,并且非常高效。添加认证是可能的。

Pandas 允许使用 s3fs 直接从 s3 读取数据
配合 Colab 使用 S3 的优势:
S3 作为一种数据存储解决方案受到软件社区的重视,而 Google Drive 虽然更受个人用户的青睐,但被许多开发者青睐只是为了与其他 Google 服务的集成。
因此,这种方法改善了你的代码和架构!
将 S3 与 Colab 一起使用的缺点: 要应用这种方法,您将需要使用 AWS。这很容易,但在某些情况下(如公司政策),这可能仍然是一个缺点。此外,每次加载数据都需要时间。这可能比从 Google Drive 加载要长,因为数据源是独立的。
清理方法 2 —将 SQL 数据库连接到 Colab
如果您的数据已经存在于 MySQL 或其他关系数据库中,那么将您的 Colab 笔记本直接插入数据库也是一个不错的解决方案。

SQLAlchemy 是一个包,它允许您将 SQL 查询发送到您的关系数据库,这将允许在这个单独的 SQL 环境中拥有组织良好的数据,同时仅将您的 Python 操作保存在您的 Colab 笔记本中。

将 SQL 数据库连接到 Colab 的优点: 当您开始使用更重要的应用程序,并且希望在开发过程中已经有了良好的数据存储时,这是一个好主意。
将 SQL 数据库连接到 Colab 的缺点:
将关系型数据存储用于非结构化数据是不可能的,但是非关系型数据库可能是这种情况下的答案。在数据量非常大的情况下,更严重的问题可能是查询执行时间。管理数据库也是一种负担(如果您没有数据库或者如果您不能轻松地共享访问权限)。
结论
谷歌 Colab 笔记本电脑很棒,但要将数据输入和输出可能是一场真正的斗争。
谷歌 Colab 笔记本电脑很棒,但要将数据输入和输出可能是一场真正的斗争。
手动上传导入数据或者挂载 Google Drive 都是好用但是产业化难度大。像 AWS S3 或关系数据库这样的选择会让你的系统更少手工操作,因此更好。
2 个手动方法非常适合小型短期项目,当项目需要一个干净的数据存储时,应该使用带有外部存储的两个方法。
在为时已晚之前,仔细考虑你的架构!
每种方法都有其优点和缺点,只有您才能决定哪种方法适合您的使用情况。无论您使用何种存储,但请务必在为时已晚之前全面考虑您的架构!
我希望这篇文章能帮助你构建你的项目。敬请期待更多内容,感谢您的阅读!
使用 Amazon EMR 上的 Apache Hive 导入 DynamoDB 数据
使用 Amazon EMR 和 Hive,您可以快速高效地处理大量数据

本文描述了将数据导入 AWS DynamoDB 数据库的多种方法之一。这里解释的选项使用 Amazon EMR 和 Hive。使用 Amazon EMR 和 Hive,您可以快速有效地处理大量数据,例如将数据从 Amazon S3 导入 DynamoDB 表。
这个例子实现了什么?
- 每天,一个外部数据源都会向 S3·巴特发送一个包含大约 1000 条记录的 csv 文件。
- 将 csv 对象放入 S3 存储桶时将被触发的 lambda 函数。
- Lambda 函数将启动 EMR 作业,步骤包括:
- 创建一个引用 DynamoDB 中存储的数据的配置单元表。
- 创建一个引用亚马逊 S3 的位置的配置单元表。
- 将数据从 S3 表加载到 DynamoDB 表。
下图显示了该流程的架构。

先决条件
- 对云形成的基本了解。
- 对电子病历的基本理解。
- 设置 AWS 帐户。
- 安装无服务器框架。
现在,我们开始吧
在开始之前,安装 无服务器框架 。打开一个终端,输入npm install -g serverless。
项目目录下有一个yml文件(serverless.yml))。让我们开始在模板文件中定义一组对象,如下所示:
S3 水桶
有两个 S3 桶, LogBucket 用于 EMR 日志, S3BucketCsvimport 用于存储 csv 文件。
DynamoDB 表
从 S3 加载 csv 数据的 DynamoDB 表。
λ函数配置
向serverless.yml添加 lambda 功能配置。它将由 S3 新创建的对象事件触发,lambda 函数将启动一个 EMR 作业流来处理数据导入。
IAM 角色
我们还需要为 lambda 函数创建 IAM 角色,这样我们的 lambda 函数就有权限启动 EMR 作业流。
添加 lambda 函数
让我们添加一个 lambda 函数来创建一个 AWS EMR 集群,并添加步骤细节,如配置单元脚本的位置、参数等。我们可以为 EMR 使用 boto3 库,以便创建一个集群,并从 lambda 函数动态提交作业。
配置单元脚本
Ad 最后…让我们添加 Hive 脚本。
第一步。创建配置单元和 S3 之间的映射
我们将创建一个映射到 csv 数据文件的外部配置单元表。
第二步。正在创建配置单元和 DynamoDB 之间的映射
在配置单元和 DynamoDB 中的 Features 表之间建立映射。
第三步。用 S3 的数据加载表
将当前日期添加为分区,并在 S3 加载包含 csv 数据的表。
第四步。从亚马逊 S3 导入一个表格到 DynamoDB
使用下面的配置单元脚本将数据从亚马逊 S3 写到 DynamoDB。
请注意,DynamoDB 表上的 Amazon EMR 操作算作读/写操作,并且受表的调配吞吐量设置的限制。更多详情请访问电子病历文件。
现在让我们部署服务并进行测试!
$sls deploy --stage dev
在脚本部署后,将一个 csv 文件复制到带有created_date={CURRENT_DATE}前缀的 S3 存储桶,例如
$aws s3 cp csv/contacts.csv s3://myemr.csv.import.dev/uploads/created_date=2020-02-03/contacts.csv
然后,我们可以转到 AWS EMR 控制台,检查 EMR 步骤的进度。

完成所有步骤需要几分钟时间,运行上述步骤后,群集将自动终止。
接下来,我们可以转到 AWS DynamoDB 控制台,验证数据是否已经加载到 DynamoDB 中:

最终,导入过程花费了大约 6 分钟的时间,将 1000 条总共 76kb 的记录加载到 DynamoDB 表中,写入容量单位为 10,没有启用自动缩放。
大概就这些,感谢阅读!
希望你觉得这篇文章有用,你可以在我的 GitHub repo 中找到完整的项目。
大数据世界中数据最小化原则的引入
不合规的代价很大
大数据时代,数据的价值与日俱增。随着数据环境每天每秒都在扩大;并且数据变得无处不在并且更容易收集,个人数据被大量挖掘和存储,以便在位置跟踪、医疗保健、预测性警务、预测性司法、欺诈检测、广告、媒体和娱乐的应用中被重新利用。但是,与此同时,它也引发了一些与大数据效应相关的新问题,,例如。数据和隐私泄露等。
这样的新问题可以用一些问题来举例:如果你不做危险的工作,你的雇主应该询问你的血型吗?当你接受医疗服务时,医生应该询问你的宗教信仰或种族吗?如果你申请的不是体力工作,招聘人员可以询问你健康状况的细节吗?
在处理数据海洋中类似的问题时,数据最小化原则可以帮助你脱颖而出。作为核心隐私原则和标准程序,数据最小化原则实际上是作为减轻数据海啸风险的解决方案而出现的。因此,在我们现在生活的大数据世界中,该原则的重要性正随着热情而增强。

摄影:卢卡斯·布拉塞克/Unsplash
大数据!什么是?
“大数据”不是我讨论的主要内容。然而,为了澄清上下文,可以在一个简短的对话中进行。这个术语基本上是指包括政府和企业在内的组织结合不同的数字数据集,然后使用统计学和其他数据挖掘技术从中提取隐藏的信息和令人惊讶的相关性的新方法。
大数据实际上是一种方法论,涉及基于人工智能和机器学习技术的新分析技术,其目标是找到揭示新见解或真理的“小模式”或“隐藏的相关性”。此外,大数据现在因其“4v 特征”而更为人所知,即。数量、准确性、速度、多样性(数据融合)和机器学习。
为了说明问题,大数据中的“大”不一定是数据库的大小,而是大量的数据源,它是大的(混合数据,参见 Steward 等人的)。2019),因为大量的实时数据是通过随机采样、处理和产生的各种来源存储的,以数据融合的方式创建完整的自动化见解。
大数据的来源就在我们身边,大致可以分为业务数据、人的数据和来自物联网的机器数据。令人惊讶的是,当大数据应用于法律环境时,它引发了严重的深层次问题,并引发了关于其偏见、不透明和歧视性影响的严重辩论。
数据最小化原理是什么?
数据最小化原则是数据保护的一般原则之一,理想情况下,这意味着收集的数据量应该是开展业务所需的最小数据量。
该原则主要假设将个人资料的收集和保留限制在与实现特定目的直接相关和必要的范围内;也就是说,组织应该尽可能只收集和保留最少量的数据。
例如,如果是医疗服务,性别可能比宗教或种族更相关。 申请办公室工作的人不应该被问及健康状况的细节。
在个人数据保护的背景下,应优先考虑采用数据最小化政策,而不是“保存一切”的方法,不必要的数据将被丢弃,同时仅保留相关和必要的数据。此外,这些数据只应根据法律或法规的需要或要求保留。
将该原则纳入法律文书:
作为欧盟数据保护价值观之一,数据最小化在 2018 年《一般数据保护条例(GDPR)》第 5、25、47、89 条中进行了实例化。在欧盟数据保护法的七项基本数据保护原则中,这些原则是体现监管框架精神的法律的核心[GDPR,第 2 章,第 5 (1)条]。
根据该法规,个人数据应“充分、相关,并限于”与处理这些数据的“目的”相关的“必要”范围内(数据最小化)。研究者不应该收集对特定研究问题没有价值的信息。该原则是法律的核心,体现了监管框架的精神。
在建立电子邮件订阅列表时,收集除姓名和电子邮件之外的任何信息(如出生日期、宗教信仰等)。),可能不符合 GDPR 。可能需要来自 有害作业 的员工的血型明细。但是,由雇主掌握其余劳动力的这种数据可能是不相关的和多余的。
根据《GDPR 》,如果认为个人资料不完整或不足以达到处理的目的,则该资料是“不充分的”;并且考虑到上下文和性质,个人有权完成该数据(纠正权;例如第 16 条,GDPR)。然而,如果新的目的与旧的目的不矛盾,甚至进一步的处理也是允许的。
个人也有权让您删除对您的目的不必要的任何数据(擦除权或被遗忘权)。因此,在违反数据最小化原则的情况下,个人也将有权删除(例如)。第 17 条,GDPR)。在违约情况下,个人可以采取法律行动。
GDPR 还规定了数据最小化原则的例外情况,允许出于“统计目的”更长时间地保留个人数据。那些不再需要保留的数据将被删除。这一义务使数据最小化的原则更加有力。
数据最小化原则也纳入了 2018 年加州消费者隐私法(CCPA),以及其他法规,如 1988 年(澳大利亚)隐私法。事实上,第一个监管问题涉及个人数据保护和消费者保护;然后是确保消费者法律在大数据技术上的应用。
不合规后果:
在欧洲,违反基本数据保护原则可能导致巨额罚款,最高可达 2,000 万€,或全球年营业额的 4%,以较高者为准(GDPR 第 83(5)(a)条)。因此,该原则或多或少是严格的,这取决于数据处理权限可能带来的后果。
此后,原则要求,存储的每一个数据都需要通过一系列目标进行过滤。如果数据不符合任何预期目的,那么数据应该被丢弃。
在土耳其,一家银行因违反数据最小化原则而面临制裁,因为该银行向民事法院提供了其客户六个月的账户对账单,而法院只要求提供最近三个月的对账单。一所意大利学校因非法数据处理而被罚款(根据该原则),也就是说,因在没有充分法律依据的情况下,通过在大门张贴来传播学生(未成年人)的个人数据。
作为 2018 年 3 月 GDP 下的第一个案件,丹麦数据保护局对出租车公司 Taxa 罚款 120 万克朗(18 万美元),用于保存与约 900 万次单独出租车乘坐有关的个人数据,超过了合法的两年保留政策。当局还应检查数据保留政策是否制定得当并得到认真遵守。
在法国,今年 8 月,一家在线零售商“Spartoo”因违反数据最小化原则而被罚款 250,000 欧元,其中,对客户服务员工接听的电话进行完整和永久记录被认为是过度的。
在线卖家记录和保存通过电话下单时交流的客户银行详细信息也“对于预期目的而言是不必要的”。甚至,在打击欺诈的背景下,除了要求提供身份证之外,收集客户的健康卡副本被认为是过度和不相关的,因为健康卡副本包含的数据比身份证多。
少即是多,有时:
虽然数据最小化方法据称对大数据分析有严重影响,但它有许多好处。它基本上降低了成本,防止数据泄露造成灾难性后果,并受到刑事过失的指控。事实上,持有不必要的数据对你来说弊大于利。
当仅存储必要的数据时,数据丢失和计算机黑客攻击的风险也被最小化。因此,数据分类、在处理、保留和访问方面拥有清晰和合理的数据策略(通过设计或默认)以及定期审查数据可以将 venture 从数据爆炸中解救出来。
该原则还建议个人采用 DIY(自己动手)方法来保护其个人数据,方法是通过数据匿名化(在不可能的情况下)或假名化,或者通过使用加密技术、管理 cookies 的浏览器插件或块跟踪,以及其他用于最小化数据收集的工具,尽管也存在重新识别匿名个人数据的风险。从今以后,现在可以有把握地认为,这一原则对公司和个人都有利。
需要提供的“更少的数据”也可以使在线交易变得更加容易、快捷和用户友好。值得注意的是,隐私政策因此在商业网站上迅速扩大,成为包括数据最小化方法在内的公平做法,以通知用户有关其个人数据的收集和使用,即使没有任何全面的法律来规范隐私政策的实质内容。
这就是为什么;不可否认的是,在这种情况下,数据最小化原则限制了作为合法处理个人数据的基础的充分性要求,也是民主社会中必要和相称的组成部分。
本月关于 AI/ML 的令人印象深刻的中型文章
随着十月即将结束,这里有一些你不应该错过的与人工智能和机器学习相关的顶级文章。

在 Unsplash 上由 Varun Gaba 拍摄的照片
10 月一直是 2020 年最短的月份之一;不管怎样,人工智能和机器学习领域已经有了很多发展,让媒体作家们忙得不可开交。
以下是这几个月推荐的文章;所有这些文章肯定会吸引人工智能爱好者和机器学习实践者。
如果你遇到任何人工智能/人工智能相关的文章,希望我阅读并包含在我的每周/每月文章报道中,请随时在文章的评论部分给我加标签,我会做一个评论。或者在LinkedIn上连接并发送文章链接。
下面是对预期结果的快速总结。一定要检查每一篇文章。
- Awais Bajwa 提供了关于中国如何利用人工智能应对当代最糟糕的疫情的见解。
- Andre Ye 描述了研究人员在开发算法和机器学习模型时采用的一种方法,这些算法和模型可以模仿人类用来学习的过程。
- 在阅读了妮可·詹韦·比尔兹的文章后,准备好停止使用“人工智能”这个术语。
- 丹·麦卡里 写了一篇短文,重点介绍了最近购买英伟达 的好处。
- 道格拉斯·拉什科夫 提供了他的著作《 团队人类 》中的摘录,其中他谈到了人类与技术之间似乎是依赖性适应的逆转。
成功人工智能的关键?持续的人类干预。作者道格拉斯·拉什科夫
道格拉斯·拉什科夫(Douglas Rushkoff)提供了他的书“ Team Human ”中的摘录,他在书中谈到了人类和技术之间的依赖适应的逆转。
根据道格拉斯的说法,接受任何解决问题的技术方案作为默认方案,开启了一个世界,在这个世界里,我们试图让人类的行为和偏好符合算法。反过来,我们也接近了优化技术以满足人类需求的最初前提。
在当今世界,我们将任何技术失败都归咎于人为错误,而不是系统故障,这似乎很奇怪,道格拉斯正确地指出,人类现在已经适应了技术,而不是相反。
如果整本书与道格拉斯在这篇文章中介绍的一样,那么《人类团队》似乎是一个大开眼界的故事,我们都需要意识到,软件和硬件可能不是大多数人类问题的绝对答案。
中国如何利用人工智能对抗新冠肺炎作者阿瓦斯·巴杰瓦
Awais 简要探讨了中国政府机构为遏制 Covid19 的传播而招募的人工智能应用和技术,同时为其公民维持一种正常运作的社会形式。
在处理个人隐私时,中国使用大规模监控系统一直是一个有争议的话题。
Awais 探讨了曾经不受欢迎的公民治理和监控方法的好处,这是中国处理新冠肺炎危机优于全球某些国家的原因,尽管最初报道的新冠肺炎病例来自中国。
人工智能技术、大数据和机器人在有效应对新冠肺炎病毒在中国的传播方面发挥了更大的作用。Awais 提到利用各种形式的基于人工智能的技术,如面部识别,面具检测和热量读取,以监测,警告和通知市民在他们当地附近的所有新冠肺炎相关病例。
阅读这篇文章时,我惊讶于阿里巴巴和腾讯等大型科技公司与其他小型创业公司合作,提供开源工具和研究成果,帮助新冠肺炎应用程序和解决方案的快速发展。其中一些解决方案被公共部门使用,如医疗保健和警察机构。
深度学习的最新研究,包括计算机视觉和自然语言处理(NLP),使人工智能提供了…
medium.com。](https://medium.com/datadriveninvestor/how-china-used-artificial-intelligence-to-combat-covid-19-f5ebc1ef93d)**
深度学习迫切需要的人类大脑:零起点学习指南作者安德烈·叶
向对探索未开发的研究领域感兴趣的机器学习从业者推荐 read】
Andre Ye 的文章描述了研究人员在开发算法和机器学习模型时采用的方法,这些算法和模型可以模拟人类用来学习的过程。
更具体地说,安德烈在本文中描述的技术旨在以某种方式复制人类幼儿所拥有的理解和学习能力的有效衍生。
这篇信息丰富的描述性文章是对正在进行的研究的世界的一个可访问的介绍,这些研究还没有发展成成熟的可应用的技术。
也就是说,Andre 提出和描述的方法可能是机器学习中尚未发现的未来发展起源的一个窗口。
零拍学习技巧对我来说一直是个谜。尽管如此,Andre 还是展示了相关研究论文的关键要点,并通过简单易懂的例子将直觉归纳到技术范式中。
以及令人尴尬的简单 ZSL 算法
medium.com](https://medium.com/@andre_ye/what-the-human-brain-has-that-deep-learning-desperately-needs-a-guide-to-zero-shot-learning-2e296741ce51)**
我们能消灭“人工智能”这个术语吗?由妮可·珍妮薇买单
一篇深入探讨被广泛滥用的术语“人工智能”呈现给不知情观众的隐藏期望和虚假现实的文章。
Nicole 提供了人工智能作为学习和研究领域的初始信息。
涵盖人工智能的历史将提到该领域经历的以往人工智能冬天。妮可也暗示了第三次人工智能冬天的可能性和重现的可能性。
在文章中,Nicole 暂时离开了人工智能这个术语,转而使用一个更容易接受的术语:机器学习。
在这篇文章中提到了 ML 专长,但是 Nicole 很快解释了机器学习的缺点,包括婴儿拥有的更广泛的学习能力。婴儿的学习能力是我们今天使用的机器学习技术目前无法实现的壮举。
读完这篇文章后,你可能会羞于使用人工智能这个术语,Nicole 对这个术语可能造成的误导提出了一些很好的观点。
尽管唱反调,我还是要说,人工智能这个术语给人工智能领域带来了耳目,这导致了更多的金融投资和对该领域的兴趣。
人工智能一词可以被视为我们用来娱乐每个人的吉祥物,而真正的工作和进展正在后台进行。
阅读这篇文章并分享你的想法。
我们正在加深数据科学的可信度危机
medium.com](https://medium.com/better-programming/kill-artificial-intelligence-7bc02f85ea70)**
英伟达收购 ARM 对 Graph Technologies 的影响
Dan McCreary 写了一篇短文,重点讲述了最近由 NVIDIA 收购 Arm Holding 的好处。
NVIDIA 是大多数机器学习从业者熟悉的公司,另一方面,Arm 可能不那么知名,但 Dan 在这篇文章中做了很好的工作,简要介绍了 Arm 和该公司的目的。
大多数机器学习实践者并不完全关心 GPU 的硬件细节。无论如何,Dan 提供了深度学习领域中 GPU 应用的相关性和影响的简要历史。
Dan 阐述了 GPU 对图像数据处理加速的影响,包括当前硬件在处理稀疏矩阵方面的局限性。
丹在他的文章中提到,英伟达收购 Arm 的原因是,英伟达正在为开发硬件奠定基础,这些硬件可以处理人工智能等领域使用的更复杂的数据表示格式。
本文是广大机器学习从业者的必读之作。Dan 为 ML 工程师日常使用的硬件的未来状态提供了重要的见解和信息。
非常适合阅读:
- 机器学习从业者
- 硬件架构师
** [## 英伟达收购 ARM 对 Graph Technologies 的影响
在本文中,我们将关注 NVIDIA 最近以 400 亿美元收购 Arm Holdings。然后我们会看…
medium.com](https://medium.com/@dmccreary/the-impact-of-nvidia-acquisition-of-arm-on-graph-technologies-76449c8b45f9)**
我希望这篇文章对你有用。
要联系我或找到更多类似本文的内容,请执行以下操作:
本月关于 AI/ML 的令人印象深刻的中型文章
随着九月即将结束,这里有一些你不应该错过的与人工智能和机器学习相关的顶级文章。

在 Unsplash 上由 Varun Gaba 拍摄的照片
九月的最后一天就要到了,就像任何其他月份一样,有大量关于人工智能和人工智能主题的高质量文章。
在这篇文章中,你会发现一个中型文章的策展,这些文章有令人印象深刻的内容和关键要点,机器学习从业者和人工智能爱好者将会欣赏。
如果你遇到任何 AI/ML 相关的文章,想让我阅读并包含在我的每周/每月文章报道中,请随时在文章的评论部分给我加标签,我会做一个评论。或者在LinkedIn上连接并发送文章链接
人工智能解释大爆炸前发生的事情柯克·奥密特
GPT-3 赫然解释了一切的起源
柯克·奥密特的文章是他自己和 GPT-3 的对话,被称为‘智慧存在’。
对话的内容是围绕大爆炸的起源和其他相关的话题,如时间,空间和宇宙。
我真的以为会很无聊,或者至少会对对话中“明智的存在”的输出留下一点印象。
读完对话和文章的全部内容后,我不得不承认来自“智慧生物”的回应感觉几乎像人类,并且超出了我最初的预期。这些回答被很好地组织在一起,并具有某种形式的逻辑,以及在回答超出人类想象范围的问题时尽可能多的逻辑。
我从这篇文章中得到的关键是,GPT 3 语言模型显然非常健壮,能够模仿创造性。它还能够利用来自其训练数据的相关文本源来提供一些适当的响应。
尽管应该指出,GPT-3 的反应实际上并不是唯一的,也不是推理的产物。反正现在不会。
非常适合阅读:
- AI 爱好者
下面是我与 OpenAI 的 GPT-3 的语言模型的对话。我给了 GPT-3“智慧生物”的角色所有的…
T4Claire d . Costa 人工智能为谷歌产品提供动力
简要了解人工智能在几款谷歌产品中是如何被利用的
根据 Claire D. Costa 的说法,谷歌声称其旗舰搜索引擎和其他广泛使用的产品的大部分进步都源于采用基于人工智能的技术和技巧。
带着“将人工智能的好处带给每个人”的首要目标,克莱尔的文章简要探讨了谷歌投资人工智能的最初驱动力。
Claire 文章的主要内容探索了 12 个具有某种形式的嵌入式人工智能的谷歌知名产品。文章中包含的产品从硬件到软件都有,每个产品都以一个类似于简介的形式呈现,包括发布日期、开发语言、访问 URL 等等。
这篇文章简要介绍了人工智能在谷歌的几个产品中是如何被利用的。
每个产品的描述都是用通俗易懂的语言编写的,这使得大多数读者都可以轻松地阅读本文的内容。
适合阅读:
- 技术专家
看看 AI 是如何深度融入谷歌产品的
towardsdatascience.com](/artificial-intelligence-powering-google-products-18e191da88d0)
为什么我要从 Ken Jee 开始数据科学
数据科学运动,邀请您参加
Ken Jee 是数据科学社区中杰出的 YouTuber ,他发起了一场运动,专注于在数据科学从业者中发展和保持势头。
在您的数据科学学术或专业旅程中,您有时可能会遇到知识积累停滞或缺乏灵感的时期。这种学习和进步停滞不前的感觉促使 Ken 重新审视数据科学的基础主题。
通过接受问责制和一致性的概念,Ken 发起了一场名为#66DaysOfData 的互联网运动。
根据 Ken 的说法,#66DaysOfData 是一项养成习惯和激发灵感的运动,参与者每天至少花五分钟学习数据科学相关主题。鼓励参与者在 LinkedIn、Twitter 等平台上分享他们的学习成果。
对于数据科学从业者来说,这是一个加入数据科学社区的机会,共同努力在社区和个人中激发灵感和推动动力。
以下链接提供了更多信息:
-
66DaysOfData 的不和谐服务器:【https://discord.gg/VXSUJYJ
- 肯的推特:https://twitter.com/KenJee_DS
- 视频版:https://www.youtube.com/watch?v=uXLnbdHMf8w
这篇文章很适合阅读:
- 数据科学从业者
- 数据科学专业的学生
介绍#66DaysOfData
towardsdatascience.com](/why-im-starting-data-science-over-21bec8036ce9)
如何联系到某方公司?由罗马 Orac
从理论上讲,在 LinkedIn 上的自我推销可以让你在 FANG 公司找到一份工作。
Roman Orac 写了一篇短文,描述了他与一位方(脸书、亚马逊、、谷歌)招聘人员就一个可能的工作机会进行对话的行为。
在媒体上写作是在特定领域建立个人品牌的一种行之有效的方式,看起来罗曼一直在媒体上写技术文章。罗曼认为,在介质上书写是他接触方招募人员的最初原因。
通过与招聘人员的直接联系,在最初的电子邮件通信后,Roman 发现一个简单的 LinkedIn 搜索已经导致他的个人资料显示在搜索结果中。
罗曼将他的崛起归功于在 LinkedIn 搜索结果页面上输入“数据科学”和“编程”等术语时的排名,这一切都归功于他之前在 LinkedIn 上发布的自我宣传文章。
通过在 LinkedIn 上的自我宣传,Roman 获得了很高的互动、联系和个人资料浏览量,这可能导致 Roman LinkedIn 个人资料在搜索“数据科学”时显示出来。
虽然 Romans 的文章是基于一种理论,但自我推销的社交媒体平台已经证明可以提供开发者和机器学习从业者获得新工作角色和机会所需的曝光率。
非常适合阅读:
- 机器学习从业者
- 数据科学家
最近一家方公司的招聘人员联系了我。为什么是现在而不是以前?关于如何提高的一些建议…
towardsdatascience.com](/how-to-get-contacted-by-a-fang-company-21711c197f80)
作为一名数据科学家,我在 6 个月里学到了什么 由 妮可·珍妮薇比尔
从作为专业数据科学家的经历中获得的经验教训。
六个月是很短的时间,但在机器学习行业,对于一个人来说,获得如何拥有成功的机器学习生涯的宝贵知识是绰绰有余的。
Nicole Janeway Bills 与 Medium 读者分享了她作为数据科学家的六个月经验。
在这篇文章中,Nicole 谈到了通过阅读研究论文、探索 Github 资源库、听播客和理解机器学习领域的硬件组件所学到的经验。
其中一个让我印象深刻的关键点是 Nicole 通过研究数据科学报告的 Github 问题产生新想法的非正统方法。
除了产生想法之外,Nicole 还分享了探索 Github 问题的额外好处,包括了解软件包的弱点,在承诺在项目中使用软件包之前评估软件包开发者社区的活动水平。
Nicole 谈到了数据科学家需要识别特定行为的社会科学线索,这些线索在探索与人类或基于人类的活动相关的数据时可能不明显。
对人类行为引起的外部因果关系和相关性的理解可以为开发机器学习解决方案的独特方法提供直觉。
强烈推荐用于:
- 数据科学家
我找到了我梦寐以求的工作。以下是一些关键要点。
towardsdatascience.com](/6-months-data-science-e875e69aab0a)
我希望这篇文章对你有用。
要联系我或找到更多类似本文的内容,请执行以下操作:
本月关于 AI/ML 的令人印象深刻的中型文章

罗马卡夫在 Unsplash 上拍摄的照片
意见
随着七月的结束,这里有一些你不应该错过的与人工智能和机器学习相关的顶级文章。
每个月底,我都会反思我读过的媒体文章,并尝试重读和保存那些提供了某种形式价值的文章。
现在,我决定分享我 7 月份在 Medium 上看到的前四篇文章。
Medium 上有大量有趣且写得很好的文章,这四篇只是我个人认为突出的,所以请考虑我的选择纯粹是主观的。
如果你遇到任何人工智能/人工智能相关的文章,希望我阅读并包含在我的每周/每月文章报道中,请随时在文章的评论部分给我加标签,我会做一个评论。或者在 LinkedIn 上连接并发送文章链接
了解雇主对 2020 年数据科学家的期望
Shareef Shaik 撰写的这篇令人印象深刻的文章以直观的视觉形式展示了印度数据科学就业市场的现状。
说从 Shareef 的文章中可以获得大量信息是一种保守的说法。本文利用搜集的数据提供以下统计信息:
- 招聘信息在印度的什么地方发布?
- 按公司分类的职位发布数量的百分比
- 需要特定的数据科学角色,以及雇主通常需要的技能。
Shareef 是一位自学成才的数据科学家,他通过一个标准的数据科学项目管道来呈现这些信息。
本文的内容对目前正在印度找工作的数据科学行业的任何人都很有用。这篇文章告诉你在哪里寻找角色,更有用的是,你应该掌握什么技能来快速找到一个职位。
除了本文的信息价值之外,Shareef 还展示了用于收集、预处理、标记和分析聚合数据的所有代码。因此,本文既是一篇关于数据科学技能利用的实用演示,也是一篇信息丰富的文章。
这篇文章非常适合阅读:
- 印度的数据科学家
- 数据科学家
整个分析是从 1000 多份最近的数据科学家工作中完成的,这些工作是使用网络搜集从工作门户中提取的。
towardsdatascience.com](/know-what-employers-are-expecting-for-a-data-scientist-role-in-2020-65ad68553cc4)
忘掉编码吧,未来的工作是哲学,作者卢卡·罗西
本周我读过的最有趣的文章之一。卢卡·罗西(Luca Rossi)写了一篇文章,这篇文章将让大多数读者走上自我和环境意识的道路。
读完这篇文章后,我发现自己在质疑我的行为和贡献的影响,这些行为和贡献会导致这篇文章中所创造的想象世界。
Luca 的文章首先陈述了农业、工业和技术革命等全球性革命周期性发生所造成的失业影响。
然后,随着自动化使传统的手工劳动过时,他描绘了引入新的角色和工作的一线希望。但这一丝希望被他的个人意见挡住了。
卢卡在他的文章中指出,自动化和人工智能不会导致大量失业,这并不能保证或确保未来所有人都有大量工作。卢卡还表达了他对未来的担忧,在未来,自动化将统治生活的所有方面,使我们变得无用;他表达了对人类幸福和满足感的关注。
Luca 列出了一些最终将被淘汰的职业,当我往下读列表时,我很欣慰没有看到任何机器学习的角色。卢卡明确指出,由于机器和自动化,没有提到的职位仍然是即将到来的就业市场末日的受害者,这种宽慰很快就消失了。他甚至提供了一个人工智能通过艺术模仿人类创造力的例子来进一步支持他的观点。
没有人是真正安全的。除了哲学家
卢卡认为人工智能不能取代哲学家,因为哲学是人类对存在和生命的本质的模糊性的表达,这与“纯智能”无关。这是一个我不完全赞同的观点。在这个问题上,我可能会和卢卡好好辩论一番。
不管我对卢卡观点的反对意见,我仍然欣赏他对四个越来越相关的哲学主题的结构化方法:道德、意识、生命的意义和对齐问题。
卢卡将每个提出的哲学主题与当前技术(如自动驾驶汽车)和假设的未来技术(如心灵传输和心灵传输)的发生结合起来。
通过创建基于简单和复杂事件的场景,Luca 展示了人类可能做出的选择之间的差异,并展示了人工智能系统做出相同决定的可能性。
Luca 的文章可能不同于许多机器学习从业者习惯阅读的更具技术性和更直接的文章。但是我推荐定期阅读探索技术进步的哲学方面的文章。我知道的一本很好的书是尼克·博斯特罗姆的超级智慧:路径、危险、策略。
在结束一篇有趣的文章时,卢卡大胆地指出,世界的命运掌握在哲学家手中,这一观点令我着迷。
这篇文章很有意思,适合:
- 工艺师
- 对与 AI 交织在一起的哲学话题感兴趣的人
人工智能在不久的将来会带来四大问题。只有哲学可以拯救我们。
medium.com](https://medium.com/i-human/forget-about-coding-the-job-of-the-future-is-philosophy-33acadcee05a)
GPT-3:第一个人工通用智能?朱利安·劳蕾特
一站式获取有关 GPT-3 的历史、发展和潜力的信息。
简短评论
Julien Lauret 的文章全面总结了 GPT 3 号的研发历程。
Julien 已经成功地将多年来对建模语言和解决自然语言处理的方法和技术的开发和介绍总结为几个小而简洁的段落。
除了向读者提供 GPT-3 的背景资料,朱利安还用外交辞令回答了 GPT-3 是否是 AGI 的问题。他的回答真实地反映了问题本身的性质,因为无论是谁提出这个问题,这个问题都要服从于智力的定义。
详细审查
朱利安关于 GPT-3 的最新文章是一篇非常需要的文章,因为我觉得人工通用智能(AGI)的话题在我们的想象中几乎已经退居二线了。
朱利安在文章的开头指出了关于 AGI 的两种观点。一种观点暗示 AGI 还有几十年的时间;另一个问题是人类是否有可能到达 AGI。
Julien 的文章中充斥着一些技术和专业术语,但每个术语都附有简短的定义,在某些情况下还有广泛的背景知识。
诸如“深度神经网络”、“机器翻译”、“Word2vec”和“少量学习”等术语的呈现和定义方式为读者提供了语言建模和 NLP 的速成课程,以及有关 GPT-3 的主要信息。
这篇文章直到文章中途才提到 GPT-3,这是因为 Julien 巧妙地带领读者经历了一次概述对语言建模和 GPT-3 本身的进步做出贡献的关键发展和研究的旅程。
关于 GPT-3 和它的前身的内在特征(重量数)的信息被提供给读者,以使读者了解 GPT 模型在每个发布版本中所取得的进步水平。
本文的后半部分展示了早期 access API 用户开发的 GPT-3 的直观应用程序示例。
但更重要的是,朱利安回答了文章题目中提出的问题。朱利安对 GPT-3 是否是 AGI 的结论是,它不是。但更重要的是,问题本身的答案并不像人们想象的那样清晰。
这种不明确性源于这样一个事实,即智力的定义是模糊的,取决于个人的解释。
朱利安指出,讨论 GPT-3 的应用是一个重要的问题。我们已经看到了它生成诗歌、游戏场景和通过语言定义的 web 组件的能力。
我们现在需要观察的是,人工智能的最新成就如何应用于涉及视频和图像的更广泛的环境中。
朱利安的文章有趣地包含了一些哲学观点和陈述。例如,朱利安指出,我们无法确定 GPT-3 拥有的智力水平,就像我们无法确定一个瘫痪的人或身体有缺陷的人的认知功能水平一样。
这篇文章深入探讨了值得思考的人工智能领域。
这篇文章非常适合:
机器学习从业者 :所使用的语言和技术术语是任何一个参与机器学习的人都非常熟悉的。所包含的定义和论文允许进一步开发与 GPT-3 相关的主题
当历史学家回顾过去时,他们会选择 2020 年作为发明 AGI 的一年吗?
towardsdatascience.com](/gpt-3-the-first-artificial-general-intelligence-b8d9b38557a1)
让你在数据科学职业生涯中不可或缺的 4 种超能力
你已经阅读了 Miguel 的文章和上面的故事,并且你已经准备好从事数据科学方面的职业(或者至少对某个领域很好奇)。你应该给自己配备超能力。
加内斯·凯萨里的文章介绍非常生动,写得很有创意。我喜欢 Ganes 用来描述数据科学家的斗争的比喻。将与项目经理打交道和互动比作拔牙是很滑稽的。
Ganes 不得不描绘一个数据科学家的可怕工作生活,以展示你在面对邪恶的逆境时需要保持的四种超能力(我坚持超能力主题)。
但严肃地说,Ganes 提出了数据科学家普遍面临的四个挑战领域,并提供了帮助您在数据科学职业生涯中导航的提示和建议。
Ganes 包括如何处理杂乱数据的技巧和掌握的重要性。但是引起我共鸣的一个关键点是强调关注技术而不是工具和应用的重要性。我将保持简单,工具和应用程序来来去去,但技术保持不变。
最重要的是,数据科学家能够理解技术的基本原理,而不是利用几年后就过时的应用程序。
Ganes 为读者提供的所有超能力都是适用的,不管你在做什么项目。
如果你目前工作停滞不前,需要一些建议,请阅读这篇文章。
这篇文章非常适合阅读
- 数据科学从业者
了解数据科学行业的这些最大挑战,以避免职业生涯停滞不前
towardsdatascience.com](/4-superpowers-that-will-make-you-indispensable-in-a-data-science-career-6571e8e7d504)
以下是我在 7 月份注意到的其他文章的链接
增强你对最新炒作的人工智能模型:GPT 3 的了解
towardsdatascience.com](/articles-that-will-help-you-understand-gpt-3-610dedc37859) [## 本周(7 月 11 日)你应该阅读的有趣的人工智能/人工智能文章
发现提供在数据科学和机器学习领域导航成功职业生涯的建议和提示的文章。
towardsdatascience.com](/interesting-ai-ml-articles-you-should-read-this-week-july-11-bac8f2a65819) [## 本周(7 月 4 日)你应该阅读的有趣的人工智能/人工智能文章
找出为什么你应该换工作,成为一名哲学家
towardsdatascience.com](/interesting-ai-ml-articles-you-should-read-this-week-july-4-cad0d162e108)
利用脑-机接口和机器学习改进青光眼评估
理解大数据
我的研究使用多任务学习来提供快速的护理点诊断,以检测周边视觉损失

人类擅长捕捉引起剧烈变化或疼痛的感官线索。但是,当变化如此轻微和缓慢,以至于人们无法注意到它时,像视力退化这样的逐渐变化又如何呢?
在许多国家,医疗保健的基础是患者在出现症状时寻求医疗护理。使用这种方法,个人需要知道他们的症状是什么。但是无症状的疾病呢?直到晚期,人们才能注意到,那时他们的生活质量由于视力丧失而受到严重影响。
这是青光眼。

正常视力与青光眼视力的比较。[按作者、原始剪辑的来源组合]
随着老龄化人口的增加,我们面临着寻找解决方案来满足老年人医疗保健需求的挑战。随着年龄的增长,失明的几率也越来越高,世界上 80%以上的盲人年龄都在 50 岁以上。总体而言,75%的各种原因导致的失明是可以预防、治疗或治愈的。
我的研究工作通过在临床筛选和诊断程序中应用脑-机接口方法来解决这个问题。这可能为无症状病例的视觉功能检测提供更准确的诊断。

随着年龄的增长,失明的几率会越来越高。[ 来源 ]
关于青光眼及其影响
青光眼被誉为“沉默的视力窃贼”。这是一种随着时间的推移逐渐发展的眼病,会夺走视力。一点一点,你在慢慢变瞎,等你意识到的时候已经太晚了。青光眼导致的视力丧失一旦发生,将是永久性的。
它没有警告标志;从这个例子中可以看出,当两只眼睛有不同的受影响区域时,患者直到晚期才会注意到。

青光眼中的不对称视野丧失可导致迟发,因为患者双眼睁开时看不到缺损。[ 来源
世界卫生组织(World Health Organization)的一份报告称,预计 2020 年(7600 万)至 2030 年(9540 万)间,青光眼患者数量将增加 1.3 倍。随着老龄化人口的增长,患有这种疾病的人数也将大幅增加。
沉默的小偷没有任何警告信号。研究表明,50%未确诊的青光眼患者在诊断时已经有明显的视野缺损。由于患者通常不会注意到视觉功能的任何变化,他们不会寻求医疗护理。
青光眼对视神经的损害是不可逆的,在大多数情况下,如果没有适当的治疗,它会发展。因此,在初始阶段进行抢先筛查以发现患者至关重要。唯一的解决办法是早期治疗。

随着老龄化人口的增长,患有这种疾病的人数也将大幅增加。【来源
现有筛选方法的局限性
青光眼的诊断包括由医生通过视野测试来评估患者的视觉功能。视野测试是一种测量个人视力的方法——中央和周边视力。视野测试可单独绘制每只眼睛的视野图,并可检测盲点(暗点),以及视力模糊的更细微区域。该测试将检查患者视野和功能的任何缺陷,如丧失周边视觉。
青光眼筛查测试的目的是检测早期疾病,以便对这些患者进行治疗,降低失明的风险。
怎样才能测量视野?
标准自动视野检查,简而言之,我们称之为 SAP。这是目前医生用来评估视野中的盲区、监测青光眼患者视觉功能的方法。
考官会一次用一只眼睛进行测试。它将提供一系列的刺激(闪烁的光点),一次一个,同时患者必须在整个过程中保持注视中心目标。如果病人看到了光,他们就按下按钮。这些反应将被记录下来,并形成患者的视野图。
SAP 的视野测试是一项主观测试。
它要求患者理解测试说明,充分合作,并完成整个视觉测试,以提供有用的测试结果。
每只眼睛的测试过程大约需要 10 分钟。10 分钟绝对集中注意力在一个中心点上。10 分钟记住当刺激物出现时按下一个按钮。
因此,当患者按下按钮时,即使没有刺激存在,也经常会遇到假阳性结果。
当患者对本应检测到的光刺激没有反应时,假阴性率也很高。当患者在测试过程中注意力不集中时尤其如此。
由于疲劳和注意力分散,患者可能会失去对中心目标的固定,从而影响测试结果的可靠性。
所有这些相互矛盾的结果阻碍了医生做出诊断的决定。单次测量的可靠性可能很低;需要几次一致的测量来确定缺陷的存在。因此,需要更多的多重测试,这反过来会导致诊断延迟。
这些因素突出了对提供客观评估以改善视野检查的技术解决方案的需求。
我们如何从当前的视野检查程序中去除主观性?
我们可以用什么来更精确地测量视野,而不是依赖患者按下按钮?
能不能缩短视野评估的时间?

我们需要一种能够提供客观评估的解决方案来改善视野检查。[ 来源
结合脑机接口和机器学习
这张图说明了我们研究的主要观点。

患者将聚焦在一个中心点上几秒钟,我们将捕捉来自视网膜中央凹和周围邻近目标的信号。我们的模型预测了整个视野中所有 SSVEP 频率的存在。也就是说,如果患者在某个区域有盲区,那么从这些刺激中提取的信号是微弱的,它会反映在视觉反应图上。[ 作者图片
我们的目标是实现一个系统,该系统产生的视野测试结果更加可靠,因为我们消除了现有视野评估中的认知方面。通过这样做,患者不必学习使用该系统,并且测试结果不会受到患者分心或感觉不舒服的影响。
当我们看到闪烁的东西时,稳态视觉诱发电位(SSVEP)会产生大脑信号,频率通常在 1 到 100 赫兹之间。在这个实验中,这些闪烁的灯在屏幕上闪烁。这些闪烁的光被称为刺激。
患者将集中注意力在一个中心点上几秒钟,我们将通过脑电图 (EEG)捕捉他们的大脑信号。脑电图是一种记录大脑电活动的电生理监测方法。
成为 X 教授,解开我们心灵的秘密
towardsdatascience.com](/decoding-brain-signals-with-machine-learning-and-neuroscience-bee288c1d585)
我们的重点是从整个视野中检测多个信号来诊断青光眼患者。在我们的工作中,我们从 EEG 信号中提取特征。通过我们的方法,我们能够生成显示患者视野中可见部分的视觉反应图。
我们的模型预测了整个视野中所有 SSVEP 频率的存在。也就是说,如果患者在某个区域有盲区,那么从这些刺激中提取的信号就很弱,并且会在视觉反应图上反映出来。
由于我们的模型可以检测多种刺激的存在,我们可以减少视野评估时间,并产生可靠的测试结果。这可能潜在地适合于为青光眼患者提供快速的即时诊断。
他们如何相互激励、共同进步、相互受益
towardsdatascience.com](/the-fascinating-relationship-between-ai-and-neuroscience-89189218bb05)
模型架构
我们的模型由 3 部分组成,1) SSVEP 特征提取,2)特征学习,3)多任务学习模块。提议的网络图示如下。

我们的神经网络由四个卷积块组成,负责学习所有目标频率的 EEG 表示。第五卷积层是一个多任务学习模块,它学习区分多个 SSVEP 目标频率。[ 作者图片
SSVEP 特征提取
该组件的目的是将原始 EEG 信号解码为我们模型的输入特征。有两个卷积块(C1 和 C2);每个卷积块由一个卷积图层、一个批量归一化和一个指数线性单元组成。
C1 块设计用于提取 EEG 输入的频谱表示,因为它在时间维度上执行卷积,从每个 EEG 通道独立于其他通道捕获特征。
C2 块被设计用于进行空间滤波,因为它在信道维度上执行卷积。这一层的目标是学习每个时间样本的所有通道的权重。
特征学习
这里,有两个卷积块(C3 和 C4),这些块的目的是捕获每个提取的特征图中的时间模式。
我们还研究了 C3 和 C4 地块上不同的膨胀构型。由于信号所需的核大小比图像大得多,膨胀卷积允许我们扩展感受野,用较小的核大小执行特征学习,产生较小的模型,并潜在地提高性能。
多任务学习模块
第五个也是最后一个卷积模块学习区分多个 SSVEP 目标频率。我们利用多任务学习的方法,设计这个模块来产生多种输出。
在经典的多任务学习架构中,每个任务被分成特定于任务的层,每层负责学习识别每个任务。但我们不是为每个输出复制一个卷积层,而是按组执行卷积。我们实际上是在单个卷积层中执行单独的卷积。这使我们能够在单个 GPU 上高效地并行训练多个任务,并且我们可以有效地动态调整我们的模型规模以适应任意数量的任务,这可能适用于其他多任务学习应用。
我们的实现建立在 PyTorch 框架之上,并在我们的伙伴网站上公开发布。
[## 用于 SSVEP 检测和视觉反应映射的深度多任务学习
使用多任务学习有效地同时捕获来自视网膜中央凹和邻近目标的信号。
jinglescode.github.io](https://jinglescode.github.io/ssvep-multi-task-learning/)
结果(多标签)—视觉反应图
我们的模型是一个统一的系统,通过学习区分 40 种频率来生成视觉反应图。我们预测所有目标频率同时出现。因此,这使我们能够用视觉响应图来可视化用户所看到的内容。

一些视觉图的例子,其中较暗的阴影表示来自 SSVEP 刺激的较强信号。[ 作者图片
这是一些视觉地图的例子,其中较暗的阴影象征着来自 SSVEP 刺激的较强信号。我们选择了位于屏幕中心周围的 6 个目标,因为这是我们未来工作中视野评估的感兴趣区域。我们已经用留一个受试者的方法评估了我们的模型,以展示我们方法的通用性,并且我们的方法需要很少或不需要对新用户进行校准。
结果(多类)—分类
我们也可以使用我们的网络作为分类器。因此,我们可以将我们的模型与 SSVEP 分类准确性的现有技术方法进行比较。

将我们的模型与其他基于 CCA 的方法以及各种模型配置进行比较。[ 作者图片
对于每次试验 1 秒钟的信号,典型相关分析 (CCA)、滤波器组典型相关分析 (FBCCA)和任务相关成分分析 (TRCA)分别产生大约 59%、72%和 88%的准确度。使用我们提出的方法,我们可以有效地识别视网膜中央凹的目标频率,在遗漏一个受试者的情况下达到 92%的准确率。
显然,这一结果表明,我们的方法可以作为识别单个闪烁目标的替代方法,其中重点是提供在视网膜中央凹视觉上检测到的可靠的 SSVEP 响应。
结论
这项研究提出了一种深度学习方法,该方法可能使我们能够同时检测多种 SSVEP 刺激,从而绘制青光眼患者的视觉地图,减少视野评估时间,并产生可靠的测试结果。
鉴于最近在疾病爆发和大流行期间发生的事件,建议将非必要的医院预约保持在最低限度,这种评估方法可以减少所需的测试次数,从而最大限度地减少任何不必要或额外的测试。本质上,这项研究使我们未来的工作能够潜在地评估青光眼患者的视野,以检测周边视力丧失。为了提高评估结果的可靠性,利用 SSVEP 可以消除患者执行程序的能力和患者精神状态的可变性。通过同时检测多个 SSVEP 目标并生成视觉反应图,可以缩短评估时间。
我们的方法可能适用于为青光眼患者提供快速的即时诊断。
[## 用于 SSVEP 检测和视觉反应映射的深度多任务学习
使用多任务学习有效地同时捕获来自视网膜中央凹和邻近目标的信号。
jinglescode.github.io](https://jinglescode.github.io/ssvep-multi-task-learning/) 


使用特征重要性提高模型性能
理解寻找特征重要性的不同方法

弗兰基·查马基在 Unsplash 上拍摄的照片
机器学习模型性能是选择特定模型的最重要因素。为了选择机器学习模型,我们可以查看某些指标,这些指标可以帮助我们选择具有最高准确性和最小误差的最佳模型。
无论是回归模型还是分类模型,特征变量在建立预测模型中起着重要的作用。拥有大量的特征并不好,因为这可能会导致过度拟合,这将使我们的模型特别适合它所训练的数据。此外,具有大量特征将导致维数灾难,即特征将增加问题的搜索空间的维数。
我们可以使用不同的技术和方法进行降维和特征选择,并且为了使这些步骤更加有效,我们可以使用特征重要性,这为我们提供了在预测目标变量时哪些特征最重要的洞察力。
特征重要性是一种为我们提供每个特征变量的相关分数的技术,我们可以用它来决定哪些特征最重要,哪些特征对预测目标变量最不重要。
在本文中,我们将探索不同的技术,我们可以使用的功能的重要性,并找出他们的相对重要性分数。
加载数据集
我们将使用包含目标变量为 0(非糖尿病)或 1(糖尿病)的糖尿病数据集进行分类问题,并使用不同的机器学习模型找出最重要的特征变量。
import pandas as pd
df = pd.read_csv('DIABETES.csv')

糖尿病数据集(来源:作者)
在找出重要的特性之前,我们需要定义特性和目标变量。
X = df[['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI','DiabetesPedigreeFunction','Age']]
y = df['Outcome']
特征重要性技术:
1.使用黄砖要素重要性
Yellowbrick 是一个可视化库,主要用于模型选择和模型性能可视化。它是使用 sklearn 构建的,基于 matplotlib 构建,用于可视化。
我们将使用 yellowbrick 的要素重要性可视化工具,它返回所有要素及其相对重要性分数。我们可以使用不同的模型来寻找特征的重要性。
#Creating SVM Model
from sklearn import svm
model = svm.SVC(kernel='linear')
#Importing Yellowbrick Feature Imporance and using it
from yellowbrick.model_selection import FeatureImportances
viz = FeatureImportances(model)
viz.fit(X, y)
viz.show()

SVM 特色重要性(来源:作者)
类似地,我们可以使用不同的模型,并找出该模型的特征重要性。让我们再看一个使用随机森林分类器的例子。
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
#Visualizing Feature Importance
viz = FeatureImportances(model)
viz.fit(X, y)
viz.show()

随机森林特征重要性(来源:作者)
2.排列重要性
置换重要性在 Sklearn 模型检验方法下定义。当数据是表格形式时,它可用于任何拟合的估计量。该函数计算给定数据集的估计量的特征重要性。n_repeats 参数设置随机洗牌的次数,并返回特征重要性的样本。
from sklearn.inspection import permutation_importance
from sklearn.naive_bayes import GaussianNB
import matplotlib.pyplot as plt#Defining the model
model = GaussianNB()
model.fit(X, y)# perform permutation importance
results = permutation_importance(model, X, y, scoring='accuracy')# get importance
importance = results.importances_mean# summarize feature importance
for i,v in enumerate(importance):
print('Feature: %0d, Score: %.5f' % (i,v))# plot feature importance
plt.bar([x for x in range(len(importance))], importance)
plt.xlabel=df.columns[:-1]
plt.show()

排列的重要性(来源:作者)
同样,我们可以使用不同的模型来找出该模型的特征的重要性。让我们使用不同的模型来找出特性的重要性。
from sklearn.linear_model import LogisticRegression#Defining the model
model = LogisticRegression()
model.fit(X, y)# perform permutation importance
results = permutation_importance(model, X, y, scoring='accuracy')# get importance
importance = results.importances_mean# summarize feature importance
for i,v in enumerate(importance):
print('Feature: %0d, Score: %.5f' % (i,v))# plot feature importance
plt.bar([x for x in range(len(importance))], importance)
plt.xlabel=df.columns[:-1]
plt.show()

物流特征的重要性(来源:作者)
我们在这篇文章中讨论的方法易于使用,因为你不必考虑不同的参数,应该有如果通过传统的。在某种程度上,这些技术自动化了特性的重要性,因此节省了时间和精力。
同样,您可以在具有不同模型的不同数据集上尝试这些技术。继续探索这些技术,并在这篇文章的回复中分享你的经验。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
通过人脸检测(人脸盒)改进人员重新识别
减少视点数量和创建高质量嵌入的简单方法

人的重新识别是一个有趣的并且没有完全解决的任务。它包括在图像中找到(定位)一个人,并为特定人的照片创建数字描述(矢量或嵌入),其方式是特定人的其他照片的矢量的距离比为其他人的照片生成的矢量的距离更近。

图片来自https://github.com/omoindrot/tensorflow-triplet-loss
人的再识别被用在许多任务中,包括购物中心的游客流分析、跨摄像机跟踪人、在大量照片中找到某个人。
近来,许多有效的模型和方法被创建来解决重新识别任务。这些型号的完整列表可以在这里找到。但是,即使是最好的模型也仍然面临许多问题,例如人的姿势和视点的变化,由于这些变化,从不同角度对一个人的照片的嵌入将彼此相距太远,并且系统可以判定这是不同人的照片。
最新的最先进的模型,如用于人员重新识别的视角感知损失和角度正则化,旨在处理上述问题,但我们在ai-labs.org提出了一种简单的方法,在某些情况下极大地简化了重新识别的任务。我将更详细地讨论这种方法。
让我们从解释大多数 re-id 框架如何检测图像中特定人的照片开始。最常用的物体检测模型,如更快的 R-CNN 或 EfficientDet ,用于创建整个人体的边界框。提取整个人体的照片后,将创建该照片的嵌入。

问题是,对象检测模型往往工作得太好了,它们从各种角度找到人们的照片,但并不总是最好的质量。基于这些照片的嵌入通常不允许正确地重新识别一个人,或者以这样一种方式生成,即从一个视点对特定人的照片的嵌入将接近于仅从相同视点对照片的嵌入,但是不接近于从不同视点和距离对同一个人的照片的嵌入。
这个问题可以通过减少我们必须处理的视点数量来解决。如果不是在整个身体图像上,而是仅在面部上进行人的重新识别,则可以实现这一点。在这种情况下,面部检测模型面部盒会有所帮助。这个模型已经在我们的工作中证明了自己,加上它可以完美地检测戴面具的人的脸,这在现在尤为重要。通过人脸检测,我们丢弃了很大一部分视点变化,如后视图,但如果我们只使用低质量图像中的人脸照片,那么我们可能没有足够的信息从特定照片中将其与成千上万的其他照片区分开来。

值得一提的是我们使用的facebox模型的实现特性。它不能检测小脸,这在我们的情况下从劣势变成了优势,因为我们会立即丢弃太小(30x30 像素或更小)的照片,这些照片上的信息不足以进行正确的重新识别。
我们还使用了一个小技巧,这将允许我们在不增加视点数量的情况下获得关于一个人的更多信息。我们将根据某种算法扩展人脸的包围盒,同时捕捉部分人体躯干。以下是该算法以函数形式实现的一个示例,该函数接收一帧作为输入,并使用来自 FaceBoxes 的 FaceDetector 对象返回检测到的人物图像列表:
import numpy as np
from PIL import Image
from face_detector import FaceDetector
MODEL_PATH = 'model/facebox.pb'
face_detector = FaceDetector(MODEL_PATH, gpu_memory_fraction=0.25, visible_device_list='0')def pad_faces(frame, tres = 0.5):
face_pad = []
width, height = frame.size
image_array = np.array(frame)
boxes, scores = face_detector(image_array, score_threshold=tres)
for b in boxes:
ymin, xmin, ymax, xmax = b.astype('int')
top_pad = int((ymax - ymin) * 0.4)
bottom_pad = int(ymax - ymin)
w_pad = int((xmax - xmin) * 0.4)
ymin = ymin - top_pad if ymin - top_pad > 0 else 0
ymax = ymax + bottom_pad if ymax + bottom_pad < height else height - 1
xmin = xmin - w_pad if xmin - w_pad > 0 else 0
xmax = xmax + w_pad if xmax + w_pad < width else width - 1
ratio = (ymax-ymin) / (xmax-xmin)
if ratio < 1.6:
xmin = xmin + w_pad
xmax = xmax - w_pad
ratio = (ymax-ymin) / (xmax-xmin)
face_pad.append(image_array[ymin:ymax, xmin:xmax])
return face_padimagex = Image.open('image1.jpg').convert('RGB')
padded_faces = pad_faces(imagex)
应用该函数后,我们得到以下格式的图像:

总的来说,我们选择了高质量的图像,并且主要是从一个角度。这将简化重新识别的任务,因为我们从一个视点接收特定人的嵌入,并且这样的嵌入将彼此接近。为了生成嵌入,我们可以使用锦囊妙计和一个强大的里德基线模型,它显示了各种数据集上的高质量嵌入。
这种方法并不适用于所有情况,但它可以在人们花费大量时间并且您从不同视角获得每个人的大量照片的区域中增加您的重新识别管道的准确性。
使用这个小 Python 语句提高您的分析质量和效率

如何使用 assert 利用 Python 和 SQL 中的测试驱动开发的实际例子
曾经写过 SQL 查询或者操作过熊猫数据帧吗?那么你就知道犯一个小错误很容易导致完全错误的结果。如果只是更新和重新运行一个旧的查询,情况会更糟。这些偏见最终会导致错误的(商业)决策,从而产生巨大的影响。
"你能快速重新运行你 6 个月前为我们做的分析吗?"-“嗯,好吧,我看看我是否能把它拼起来。”
与语法或语义错误不同,逻辑编程错误很难在分析结果中检测出来。但是幸运的是,使用 assert 语句可以大大降低产生这些错误的风险!
让我们快速看一下这个小陈述如何帮助提高你的分析质量和效率(以及对你的结果的信心)。
试驾开发快速入门
我在这篇文章中介绍的方法被广泛称为测试驱动开发 (TDD)。根据我的经验,TDD(不幸的是)在数据科学中并不常见,至少在进行探索性分析时是这样。同时,它作为一种确保高质量代码的机制,在软件工程领域被广泛使用。
这种方法背后的思想是,首先从实现您想要编写的代码的测试开始。该测试基本上定义了您想要实现的输出。然后,您开始编写和重新定义代码,直到它通过预定义的测试。
TDD 迫使程序员在编写第一行代码之前坐下来思考想要的输出。这样,一个人被迫关注实际目标,这自动有助于提高效率。

这种方法不仅有助于写作,也有助于更新你的代码。想象一下,你被要求重新进行一项半年前进行的分析。通常,您必须对您的旧代码进行一些修改。例如,可能需要更新一些参数,或者应该使用一些额外的指标来增强结果。再翻旧剧本总是一件麻烦事。所以更新脚本时很容易出错。但是您在第一次进行分析时定义的测试将帮助您快速识别那些错误,并确保您仍然产生相同的结果。
那么,在 Python 或 SQL 中进行分析时,TDD 到底可以如何使用呢?
什么是断言?
首先,Python 中有 pytest 这样的专用测试包。但是特别是当在笔记本上工作时,我认为 assert 是一种更轻量级和更直接的使用 TDD 的方法。
assert 语句测试条件是否为真。否则,它将引发 AssertionError。这使它成为调试代码的有益工具:

assert 语句引发 AssertionError。
因此,让我们看看在 Python 中处理数据时,如何将 assert 用于 TDD。
对 TDD 使用断言
为了展示如何将 assert 用于 TDD,我将使用一个实际的例子。我们有一个演员和他们出演的电影的表格(这是 Kaggle 的 2006-2016 年 IMDB 数据集)。目标是生成一个只包含每个演员的最后一部电影的表:

示例数据集的样本。
1.定义测试用例
首先要做的是定义我们想要获得的期望输出。因此,我们可以查看其中一个演员,并检查该演员制作的最后一部电影是哪部。对于布拉德·皮特来说,这个数据集中最新的电影是联盟:

布拉德·皮特的电影包含在按年份排序的数据集中。
现在我们知道我们的输出表必须包含一行,其中演员是布拉德·皮特,标题是盟军。此外,这必须是唯一一排有布拉德皮特作为演员。基于此,我们可以定义以下测试用例:

输出数据帧的测试用例。
这几行代码确保我们生成的数据帧满足定义的条件。如果没有,将引发 AssertionError 并停止笔记本的执行。
2.编写和验证代码
因此,让我们开始构建一个只包含每个演员的最后一部电影的表。为了做到这一点,我使用 Pandas 的 rank()函数按电影制作年份对每部电影进行排序,并按演员分组。然后用预定义的测试用例检查其输出:

测试函数抛出 AssertionError,因为输出表与定义的标准不匹配。
正如我们所看到的,生成的数据帧没有通过测试。布拉德·皮特似乎只有一部电影(这是第一个条件),但这部电影是巴贝尔而不是联盟。
从之前的探索性分析我们知道巴别塔实际上是布拉德·皮特在数据集中的第部电影。所以电影的排名肯定有问题。记住,rank()默认情况下按升序排列电影,我们必须更改这个参数,以便电影按年份降序排列:

输出表满足测试用例中定义的标准。
在这个小小的更新之后,表通过了测试用例!当然,我们通常会定义一个有更多条件的更复杂的测试用例,但是我认为这个小案例已经帮助传达了这个想法。
在 SQL 中测试
所提出的方法对于在 Python 中测试 SQL 查询也非常有用。如果我们连接到一个数据库,任何查询的输出都可以很容易地用完全相同的方法进行测试:

用 Python 测试 SQL 查询。
结论
我们已经看到了 TDD 如何帮助我们在处理数据时关注我们想要达到的目标,并确保我们产生正确的结果。所有这些都可以通过 Pythons 内置的 assert 语句轻松实现。
将来,这个测试用例将确保我们在更新表格后仍然获得预定义的结果。因此,尽管数据工作可能变得更加复杂,测试功能仍然有助于确保我们代码的一定质量。如果有人拿起代码并开始添加更新,这将变得更加有用:

带有更多过滤标准的最后一个电影表。
我只能鼓励每个人习惯用这种方法测试你的查询。它可以成为救命稻草!
请在 Github 上我的库中找到这个项目的代码。
喜欢这篇文章吗?那么你可能也会喜欢我的其他帖子:
脸书和他的同事如何在 AB 测试中克服互联用户的挑战。
towardsdatascience.com](/ab-testing-challenges-in-social-networks-e67611c92916) [## Jupyter 笔记本电脑的版本控制
为什么版本控制笔记本不是直截了当的,以及如何使用 nbdime 这样的工具来克服这些问题。
treatwell .工程](https://treatwell.engineering/version-control-for-jupyter-notebooks-4012646d1662)
使用配置文件改善您的数据科学管道

在过去的几个月里,我一直在用 Python 编写数据管道,为一个机器学习项目准备训练数据。为了试验不同版本的数据,有必要通过将用户定义的参数传递到管道的不同步骤来使管道尽可能灵活。在本文中,我将向您展示更好地将参数传递到数据管道所需的步骤。
一个期望的功能是能够容易地使用管道来生成数据集的不同版本。这些版本通常在以下方面有所不同:
- 用于计算特征的操作
- 要包括在特征计算中的数据子集,以及
- 将包含最终特征值的目标文件或表。
管道的早期迭代面临一些挑战:
1.我如何轻松地指定要设置哪些参数,以确保我以最小的出错几率执行正确的操作?
2.一旦管道完成执行,我如何快速返回并检查哪个数据集是使用哪个参数创建的?
我很快意识到最重要的问题是无法跟踪传递给管道组成模块的大量硬编码参数。为了改进我们繁琐而低效的方法,我从软件工程师那里得到了启示(这在处理大规模数据科学项目时非常有用),并修改了管道设计以使用配置文件。
在本文的剩余部分,我将回答以下问题:
1.什么是配置文件?
2.如何将配置文件加载到 Python 脚本中?
3.我如何利用配置的内容?
通过遵循下面的例子并利用配置文件,您将拥有更健壮、更易于维护的代码。
树立一个榜样。
在我们深入技术细节之前,让我描述一下示例场景,它将阐明我们将要讨论的要点。假设我们有一个存储为 CSV 文件的数据集(参见 Github 中的数据),它详细描述了客户执行的交易,并按项目细分。

我们示例数据的前十行。
我们希望编写代码,将原始形式的数据处理成具有客户级别功能的记录;我们称之为管道。为了达到这个目标,我们有一些中间阶段。首先,我们需要在事务级别聚合所有项目。其次,我们需要将交易记录聚合到客户级别。
除了多个阶段,我们还预计每个阶段的处理会根据业务需求而有所不同。对于事务级别的聚合,我们希望能够过滤掉某个价格范围之外的项目。我们还想以可修改的税率计算这些商品的已付税款。对于客户级别的聚合,我们需要能够根据日期过滤交易。我们还希望能够试验如何通过交易总数或每个客户购买的商品数量来标准化商品的总成本。在管道的两个阶段,我们都需要能够指定源数据以及将结果保存到文件中。

上述两个阶段是作为 Python 函数实现的。对于交易阶段:
请注意,该代码包含日期范围的筛选器,并根据 tax_rate 计算 final_price。每个客户交易记录都有日期、总价和交易中购买的商品数量。
对于客户阶段:
在这里,计算诸如 max_price、total_price 和 num_items 之类的特征。为 total_price 选择规范化的逻辑也在这里。
调用管道的代码在脚本的末尾。请注意函数的硬编码参数:
什么是配置文件?
配置文件指定应用程序的参数。这些参数通常以键值对格式编写,本质上是在参数名和该参数的关联值之间创建一个赋值。将参数值放在一个文件中可以提供一个集中的、组织良好的位置来指定应该将什么参数传递给程序。我们希望在配置中包含的数据管道参数示例包括:
- 数据源位置
- 阈值和过滤值
- 要选择的列列表
- 特殊控制标志。
让我们以 JSON 的格式描述这两个阶段,以便事务和客户级别的聚合将它们的参数指定为键值对:
我们将把这个文件保存为 config.json。
请注意,函数参数值与我们在配置中输入的值非常接近。除了 None 值变为 null 之外,其余参数保持其类型。
随着我们继续这个例子,我们将使用 JSON 格式的配置,但是您可以探索其他适合您需要的格式(例如 YAML 或 XML )。
如何将配置文件加载到 Python 脚本中?
现在我们已经在配置中为我们的步骤指定了参数,我们将使用两个模块将数据从 JSON 文件中取出并放入程序中。为此,我们将导入两个 Python 库:
当我们通过命令行界面运行 Python 脚本时,argparse 库允许我们指定配置文件的名称。
json 库用于将我们的配置内容从 JSON 格式转换成 Python 对象。
在 main 中,我们使用 argparse 来使用配置文件的绝对路径,并使用 json 来解码文件内容:
从配置中传递程序设置现在就像运行python pipeline . py-c config . py一样简单
我如何利用配置的内容?
此时,我们已经将 JSON 文件的内容作为 Python 字典加载了(在我们的代码中方便地称为“config”)。
回想一下,我们拆分了配置,这样管道的每一步都由一个字典来表示,该字典映射处理阶段的名称以及该阶段的相关参数。在管道的 Python 代码中,我们用一个函数来表示处理的每个阶段。请注意,配置中的阶段参数与函数参数名称相匹配。这很方便,因为对于配置中的每个阶段,我们可以使用**运算符提取每个处理阶段的参数:
这是一种过于简单的方法,但是您可以将这种设计扩展到更复杂的管道,这些管道可能跨越许多源文件。如果您的管道步骤需要运行多个 Python 脚本,您仍然可以使用统一的配置文件,但是只选择您在每个步骤中需要的配置部分。
在本文中,我们研究了一种利用配置文件设计 Python 管道的方法。尽管它很简单,但这一功能帮助我们更清楚地了解管道的处理过程,并让我们对训练模型所用的数据充满信心。查看本文的代码这里开始在您自己的数据科学管道中实施配置!
使用面向对象编程改善您的数据争论
按目标
munging 和 OOP 令人惊讶的成功结合

“你永远不会孤独”(摄影:Pexels)
数据科学的一个肮脏秘密如下:
“你不会花时间去发现辉煌的新算法和开发尖端的神经网络,事实上,你会把大部分时间花在清理、管理和操纵数据上”
这是一个简单而不可回避的事实的结果——现实世界中的数据通常不会被很好地包装在顶部有一个漂亮的蝴蝶结的熊猫数据帧中。由于更高质量的数据产生更高质量的模型,这是我们不能忽视的过程的一部分。
不久前,我写了一篇关于争论数据的技术的博客,尽管其中包含错误,但至少是在一个数据框架中构建的。但是如果你连那个都没有呢?回想一下我在 Target 上一篇来自 的博客——我们使用 Splinter 从英超网站上的比赛页面中收集数据。
通过自动化与网页的交互,从您的抓取中获得更好的数据
towardsdatascience.com](/elevate-your-webscraping-with-splinter-a926eee7f7d9)
这为我们提供了我们想要进行的分析/建模所需的所有数据。但这不是最友好的格式——我编写的抓取代码将所有内容放入嵌套字典中,其模式看起来有点像这样:
**MATCH_DICTIONARY
-> MatchID** (str)
**-> GameWeek** (str)
**-> Events** (long list of strings)
**-> Stats**
-> HomeStats (dictionary of team stats)
-> AwayStats (dictionary of team stats)
**-> Players**
-> HomeTeam
-> TeamName (str)
-> StartingPlayers (list of strings)
-> Subs (list of strings)
-> AwayTeam
-> TeamName (str)
-> StartingPlayers (list of strings)
-> Subs (list of strings)
值得注意的是,首先收集这些数据作为字典并不是不合理的——每场比赛中的“事件”数量因游戏而异,所以我们不能很好地将它们存储在关系表中。此外,dictionary 方法意味着比赛数据与 MatchID 相关联,match id 是每个游戏的唯一标识符,在建模过程的后期非常重要。
无论如何,我们需要以某种方式获取这些数据,并将其转换成模型友好的格式。然而,操作嵌套字典的代码很快就会变得混乱,也许更危险的是,字典是可变的数据结构——也就是说,它们的内容可以被编辑。因此,以目前的字典形式保存数据可能会有风险。
幸运的是,还有另一种方法——面向对象编程(OOP)。
对象的简要介绍
在深入我们的具体示例之前,让我们后退一步,在更概念性的层面上考虑“对象”——尤其是在 Python 的上下文中。你可能熟悉 Python 是一种“面向对象的语言”,但这实际上意味着什么呢?
非常粗略地说,一个“对象”是 Python 中的一个东西,我们可以将它存储到我们的计算机内存中。所以这可能是一个字符串,或者一个列表,或者一个字典。它也可以是更抽象的东西,比如熊猫数据帧、matplotlib 图形或 scikit 学习模型。
大多数对象的一个关键特征是我们可以对它们执行“方法”。方法是内置的函数,对于特定类型的对象来说是特有的。例如,我们可以“调用”。lower()方法使字符串中的所有字符都变成小写:
**IN:** 'MyString'.lower()
**OUT:** 'mystring'
但是,如果我们尝试调用。lower()方法,那么我们会得到一个错误——这个方法在不是字符串的对象的上下文中没有意义。
这就把我们带到了“类”的概念上。在 Python 中,类是两件事的组合:
- 一种类型的对象。
- 我们可以在该类型的对象上调用的一系列“内置”方法。
“字符串”是 Python 中一个类的例子。我们可以创建“String”类型的单个对象(例如,“Hello World”、“MyString”或“我喜欢数据科学”),并且我们有一系列可以调用它们的方法。重要的是,这些方法是“内置”在对象中的。

我们可以看到,这些方法是“内置”在对象中的——在 Jupyter notebook 的点击标签后,它会自动获取我们可以调用的可用方法。
同样值得注意的是,对象通常有属性(我们可以查找)。例如,熊猫数据帧有一个“形状”属性,它告诉我们它有多少行和列。类似地,它的列名和索引也是属性。当然,同一类的两个对象的属性可以不同(不同的数据帧可能有更多或更少的列和行),但它仍然是一个我们可以对其调用相同方法的对象。

查找数据帧的一些属性
如果类比有帮助的话,你可以把我的宠物寿司想象成一个物体。特别是,她是‘猫’类的‘对象’。因此,她与同类的其他对象(例如,其他猫)共享一些内在特征,但是她具有与其他猫不同的属性,例如“毛发长度”或“眼睛颜色”。
重要的是,她还有一些我们可以在她身上执行的“内置”方法,例如。笔画()。feed()或。playfight(),我们也可以在其他猫身上进行。当然,如果我们试图在其他类的对象上调用这些方法,比如灯、自行车或饼干,那么我们会得到一个错误。
或者至少咨询心理医生。

寿司,一个“猫”类的对象,为分散数据科学工作的注意力而高度优化…
创建自定义类
这一切都很好,尽管您可能想知道这与数据争论到底有什么关系。
好了,事情变得有趣起来——Python 允许您创建自己的类。这意味着,如果您有本质上相似但略有不同的事物的数据表示(比如我们的嵌套字典包含所有匹配数据),那么最好将它们转换成定制的 Python 对象。
假设我想创建一个新的类‘Match’。这个类的对象看起来像什么?如上所述,每个匹配对象都有一组属性:
- 每个队参加比赛的队员
- 该场比赛的统计数据(例如控球率、铲球次数等。)
- 这场比赛的解说
我们也可以定义方法(记住,这些只是特定于类的“函数”)。例如,我们可以有一个方法来输出一个数据帧,显示每个玩家的上场时间。
首先,我们必须以 Python 能够理解的方式定义所有这些。让我们一点一点地建立这个定义。
类定义总是以或多或少相同的方式开始:
**class Match(object):**
第一行告诉 Python 你正在定义一个类,就像‘def’告诉 Python 你正在定义一个独立的函数一样。给定所需的类名(标准格式指南建议您使用 Pascal Case 来实现),然后将短语“object”放在括号中。
添加到这个类中的第一个东西就是所谓的“构造函数”。请记住,这样做的目的是将一个嵌套的字典(类型为“dictionary”)转换成一个新的对象(类型为“Match”)。构造函数是 Match 类中内置的函数,它将创建新的对象。
class Match(object):
**def __init__(self, match):**
不管我们定义的是什么类,构造函数的语法都是一样的。它是用短语 init(两边有两个下划线)定义的,有两个变量:
- self’(你可以把它想成一个虚拟变量,指的是我们将要创建的对象)。
- match '(这只是一个占位符,用于创建新对象,在我们的例子中是匹配信息的嵌套字典)。
类别的建构函式会指派属性给新建立的物件。让我们开始为我们的“匹配”对象构建这些。每场比赛的两个基本属性是唯一的比赛 ID 和比赛发生在赛季的哪一周。这两个数据点都可以在我们的嵌套字典的第一层中找到:
class Match(object):
def __init__(self, match):
**self.match_id = match['MatchID']
self.game_week = match['GameWeek']**
所以上面的代码只是告诉我们的构造函数,我们的新对象的 match_id 属性应该等于在输入字典的' MatchID '键下找到的值。构造函数可以非常灵活地分配属性:
class Match(object):
def __init__(self, match):
self.match_id = match['MatchID']
self.game_week = match['GameWeek'] **self.home_team = match['Players']['HomeTeam']
self.away_team = match['Players']['AwayTeam']** **self.teams = [self.home_team, self.away_team]**
注意我们是如何通过组合上面几行中定义的两个属性来创建“teams”属性的?通过这些属性定义,我们可以得到更多的信息——定义了“events”属性(从嵌套字典中提取注释字符串的列表)之后,我们可以通过过滤包含短语“Goal!”的注释字符串的列表来定义“goals”属性
class Match(object):
def __init__(self, match):
self.match_id = match['MatchID']
self.game_week = match['GameWeek'] self.home_team = match['Players']['HomeTeam']
self.away_team = match['Players']['AwayTeam'] self.teams = [self.home_team, self.away_team] **self.events = match['Events']
self.goals = list(filter(lambda x: 'Goal!' in x, self.events))**
我们可以继续以同样的方式添加我们需要的所有不同的属性。
一旦我们完成了,我们就可以开始创建(或者用技术术语来说是“实例化”)我们实际的匹配对象。这非常简单—我们只需使用匹配字典并执行以下操作:
my_match_object = Match(my_match_dict)
完成这些后,我们可以看到我们的对象拥有我们所期望的所有内置属性和方法。

当我们第一次单独运行变量名时,我们可以看到它是一个匹配对象。然后,我们在句点后点击 Tab,以查看所有内置的属性和方法。
所以现在,我们不必通过一堆烦人的字典查找(甚至更糟)来从每个匹配字典中获取我们需要的数据,我们只需在 match 对象上调用一个简单的方法/属性查找。
管理对象
在这一点上,值得考虑我们如何存储这些对象。记住一个英超赛季有 760 场比赛,用它自己的变量存储每个比赛对象(正如我在上面的例子中所做的)是非常不切实际的。
具体采用什么样的对象管理策略取决于个人。就个人而言,将匹配对象存储在一个列表中就足够了——我能够使用简单的列表理解来创建它,因为匹配字典本身已经在一个列表中了。
match_object_list = [Match(i) for i in match_dict_list]
您还可以将它们存储在字典中,使用匹配 ID 作为关键字(使用字典理解)。
{Match(i).match_id : Match(i) for i in match_dict_list}
如果你觉得特别有趣,还可以将对象作为元素存储在熊猫数据帧中。
让事情更上一层楼
创建了我们的 Match 类之后,我们可以考虑创建另一个类——Events。请记住,我们比赛中的字符串是从英超联赛网站上的比赛评论中刮出来的。

这些事件字符串是相似的,因为它们描述了比赛中某个特定时刻发生的事情,并且描述了哪些球员/球队做了那些事情。但是同样,作为字符串,它们对数据分析不是特别有帮助。
如果有某种方法可以获取一个事件字符串,并自动查看它涉及哪个玩家,或者事件发生的时间,或者事件的结果是什么,这不是很好吗?好吧,OOP 可以做到这一点!在这种情况下,我们可以使用另一个技巧—子类。
子类是一种承认不同的类可以共享一些特征,但不能共享其他特征的方式。举个例子,让我们想想足球比赛中的不同事件——我们可能会有射门、犯规、角球、换人等等。这些事件都有一些共同的特征,例如,它们都有一个时间戳,告诉我们它们在比赛中发生的时间。因此,我们可以有一个以“时间”为属性的“事件”类。
然而,可能有一些特定于射门的特征(例如,球员从球场的哪个位置射门,或者射门是踢球还是头球)。显然,这些属性对“替代”事件没有意义。因此,我们可能需要一个“Shot”类来捕获这些附加信息。
类似地,有不同类型的射门——进球、扑救、失误等等,它们可能有特定的属性。因此,我们可能需要“目标”、“保存”和“错过”类。您会注意到,我们最终得到了一种相互关联的类树:
**-> Events**
**-> Shots**
-> Goals
-> Misses
-> Saves
**-> Corners
-> Fouls**
注意——在这个树中,虽然每个额外的“分支”增加了新的属性,但是它保持了上一层的属性。因此,“镜头”将保留我们在“事件”类中定义的属性,“目标”将保留我们在“镜头”类中定义的额外属性。
这有道理;每一个进球都是一种射门类型,每一次射门都是一种事件类型,所以合乎逻辑的是,进球至少与事件具有相同的属性。这种逻辑是“类继承”的本质,也是我们使用子类的关键动力之一。此外,我们可以很容易地实现这一点。考虑以下描述目标的事件字符串:
"64.进球!进球!利物浦 4,诺维奇城 1。提姆·普基(诺维奇)从禁区中央右脚射门,球射向左下角。埃米利亚诺·布恩迪亚传球助攻。”
我们可以像以前一样声明我们的事件类,创建属性来返回原始事件文本(即上面的字符串),以及它在匹配期间发生的时间:
class Event(object):
def __init__(self, event_string):
self.event_text = str(event_string)
self.time = event_string.split('.')[0]
然后,我们可以创建一个子类“Shot”,这是一种特定类型的事件。注意,这一次,我们没有使用短语“object”,而是传递了希望新子类继承的“超类”的名称(即“Event”)。
class Shot(Event):
def __init__(self, event_string):
super().__init__(event_string)
超级()。init 短语只是告诉 Python,每当我们实例化一个新的“Shot”对象时,查看超类的所有属性,以及我们特别在新子类中定义的属性(我们将在同一个 init 构造函数中定义这些属性)。
当然,如果我们想创建一个' Goal '子类,我们可以再次这样做,用' Event '代替' Shot '(因为' Goal '将是' Shot '的子类)。
class Goal(***Shot***): def __init__(self, event_string):
super().__init__(event_string)
注意:我在这里没有包括完整的 Event 类定义——这个单元运行了将近 200 行代码,其中的正则表达式比单个博客中通常认为的健康的要多…
将这一切结合在一起
回想一下前面的 gif,Match 类有一个属性‘goals’。这将返回一个字符串列表,每个字符串都是这场比赛中一个进球的注释。
假设我们使用 Match 对象中的一个目标来实例化一个 Goal 对象,使用我们新编码的“Goal”类—记住我们是这样做的:
my_goal = Goal(my_event_string)
然后我们看到,我们可以开始直接从目标对象中提取关于该目标的信息:

同样,这是一种比试图用特殊函数攻击数据更为简洁的处理数据的方式,特别是考虑到我们将不得不在这个项目中分析的目标数量!
这只是用 OOP 实现的数据管理的冰山一角。为了让你有个感觉,这是我为 Match 类做的一个方法。简单打电话。shots_table()在一个匹配对象上,它产生了一个详细的 pandas 数据帧,其中包含了匹配过程中拍摄的所有照片。

假设我已经有了一个匹配对象的列表,您可以看到,在用 OOP 进行了初步的调查后,我可以用几行代码创建一个记录本赛季英超联赛中每一次射门的数据帧:
df = pd.DataFrame()**for** match **in** match_object_list:
df = pd.concat([df, match.shots_table()])
我们已经从嵌套字典列表中走了很长一段路!
这是我的博客专栏“关于目标”的最新文章,在这篇文章中,我将试图建立一个“赚钱”的梦幻英超联赛的模型。我很乐意听到关于这个博客的任何评论,或者这篇文章涉及的任何概念。欢迎在下面留言,或者通过 LinkedIn 联系我。
使用 argparse 改进您的 EC2 SSH 工作流
端口转发、远程 jupyter 笔记本访问和 tmux 自动启动

动机
数据科学工作通常需要针对巨大数据集使用高级大数据分析技术,以及并行或分布式计算来进行快速模型训练和调整。虽然大多数数据科学工作流(尤其是在探索和开发阶段)都可以在个人的笔记本电脑或台式机上执行,但由于本地开发环境在处理能力、内存和存储方面的限制,完全依赖本地开发环境通常是不切实际或不可能的。
在这一点上,云计算技术的作用,如亚马逊网络服务的弹性计算云(EC2)所提供的技术,从未像现在这样重要,特别是在将大数据应用大规模部署到生产环境中的情况下。随着此类服务的可用性改变了我们设计和实施 DS 架构的方式,它也促使数据科学家在其早期开发工作流程中更加依赖云计算的处理和存储能力。
如果你还没有使用过 EC2(或任何其他类似的云服务),这个 DataCamp 教程提供了一个很好的、激励人心的介绍。我每天都使用 EC2 实例,因为我相信你们中的许多人也一样,所以我想分享一个简单的 Python 脚本,它包含了一些使用argparse模块来改进 EC2 SSH 工作流和创建最佳 EC2 实例环境的巧妙技巧。当您通过 SSH 建立连接时,该脚本将允许您:
- 每次自动启动
tmux。 - 在浏览器中本地访问远程运行的
jupyter服务器。
剧本
如果你对argparse不熟悉,可以看看这篇温和的介绍或杰夫·黑尔的学习足够有用的 Python:arg parse。
将这个脚本放在您的主目录bin中,例如/Users/jlee/bin。我将我的文件命名为ec2(为了方便起见,没有扩展名.py)。然后,通过运行以下命令将该文件标记为脚本:
chmod +x ~/bin/ec2
破解密码
1.位置参数:会话
# line 8 aboveparser.add_argument("session", nargs="?", help="tmux session name")
这一行添加了一个位置参数session,它将允许您在每次 SSH 到远程实例时启动一个新的 tmux 会话(或者附加到一个现有的会话,如果名称存在的话)。
换句话说,每次你想用一个特定的名字启动一个 tmux 会话时,不再需要键入/查找 tmux cheatsheet 来记住tmux new -s new_session。
如果您将nargs(参数数量)设置为"?",参数定义将在被解析的命令行上消耗零个或一个参数。

可变参数列表
换句话说,不为session参数传入一个字符串名称将会给你一个选项,连接到你的 EC2 实例而不用一个 tmux 会话。用以下内容扩展原始argv列表(第 16-21 行):
# lines 24-25if args.session is not None:
argv.extend(["-t", "tmux", "-2", "new-session", "-A", "-s", args.session])
2.可选参数:jupyter
# lines 9parser.add_argument('-j', '--jupyter', action='store_true', help='forward port to use remote jupyter')
jupyter是一个可选(相对于位置)参数,由前面的-- (或其简称-j)表示。对于可选参数,我们指定了一个新的关键字action。如果我们给它赋值'store_true',如果指定了选项,它将把值True设置为args.jupyter 。不指定它意味着False。
因此,在下面的代码中,传递jupyter参数将使您的localhost:8888指向远程服务器的8888端口。因此,当您在 EC2 实例上运行jupyter notebook时,它会将的端口8888转发到本地机器的8888端口,从而允许您从本地浏览器访问远程 jupyter 笔记本。
# lines 22-23if args.jupyter:
argv.extend(["-L", "8888:localhost:8888"])
现在,如果您从命令行运行jupyter notebook,它会显示如下内容:
Copy/paste this URL into your browser when you connect for the first time,
to login with a token:
[http://localhost:8888/?token=a2bc3def5g41234ed56s78zxfxc3vdfb&token=a2bc3def5g41234ed56s78zxfxc3vdfb](http://localhost:8888/?token=a7213f1213c009f4c7a6c2eddd2fded65d538e5b9ae37876&token=a7213f1213c009f4c7a6c2eddd2fded65d538e5b9ae37876)
只需将令牌 URL 复制并粘贴到您的本地浏览器中,您就可以立即访问您的远程 Jupyter 笔记本。
收尾
如果您想要定制您的 tmux,在您的主目录中创建一个名为.tmux.conf的配置文件。这是一个隐藏文件,所以你不会看到它,如果你ls ~),但tmux将选择这个文件为当前用户。
将这几行添加到文件中,看看您对 tmux 的新外观有多喜欢:
# ~/.tmux.confset-window-option -g window-status-format " [#I] #W "
set-window-option -g window-status-current-format " [#I] #W "
set-window-option -g window-status-current-style fg=colour240,bold,bg=colour247
set -g default-terminal "screen-256color"
结果是 tmux 状态栏在终端底部以灰色显示当前窗口,与会话中的其他窗口(绿色)相区别:

查看这个网站获得更多 tmux 定制选项。
最后,这里有一些有用的键盘快捷键:
- 在当前会话中创建一个新窗口:
Ctrl+b,然后是c - 转到会话中的下一个窗口:
Ctrl+b,然后是n - 转到会话中的上一个窗口:
Ctrl+b,然后是p - 从当前会话中分离:
Ctrl+b,后跟d
命令示例
综上所述,您现在可以尝试使用这些示例命令之一运行ec2脚本,每个命令都将创建一个 SSH 连接,但是结果略有不同:
(1) ec2 new_sesh -j
(2) ec2 -j
(3) ec2 new_sesh2
(1)将在 SSH 上创建(或附加到)一个名为new_sesh的 tmux 会话,结果是当您调用 jupyter notebook 时,它会将您的远程服务器的端口 8888 转发到您的本地机器的端口 8888。
(2)将使用端口转发将您 SSH 到您的 EC2 实例中,但不会启动 tmux(因为您没有为session提供名称)。
(3)将创建(或附加到)一个名为new_sesh2的 tmux 会话,但没有端口转发(即,您将无法从本地浏览器访问远程 jupyter 笔记本)。
最后,当然可以使用 bash 别名来达到(1)-(3)的效果。例如,将下面一行添加到您的.bashrc或.bash_profile脚本并运行ssh-jlee将启动一个名为default的 tmux 会话,并开始通过 SSH 连接进行8888 → 8888端口转发:
alias ssh-jlee='ssh -i ~/.ssh/mykey.pem ubuntu@10.999.9.999 -L 8888:localhost:8888 tmux new-session -A -s default'
然而,我认为使用argparse.ArgumentParse创建一个解析器对象并传递一系列字符串作为命令行参数,比使用多个硬编码(1)-(3)中所有变量行为的 bash 别名更灵活、透明、可控。
使用缺失数据改进您的模型|使用 NumPyro 进行插补
用贝叶斯方法充分利用缺失数据。使用蒙特卡罗方法提高模型性能并制定比较基准。

一个丢失的框架随时准备把你从你的模型上扔下去。维尔莫斯·海姆在 Unsplash 上拍摄的照片。
丑陋的数据
你如何处理丢失的数据、数据框中的间隙或有噪声的参数?
你花了几个小时在工作中,在实验室里或者在野外为一个有趣的研究问题或假设生成或管理一个数据集。可怕的是,您发现参数的一些测量值丢失了!
另一个可能让你困惑的情况是意外噪声 e,它是在实验中的某个时刻引入的,它注定了你的一些测量结果是极端异常值。
有时你不能仅仅因为有 25%的条目丢失就从你的分析中排除一大堆参数,你应该这样做吗?
不用担心,有一种方法可以让你充分利用你的数据集。
在本帖中,我们将使用概率编程【5】来填补你的模型可能会遇到的空白。
模拟缺失数据
让我们从头开始构建一个问题。勤奋的读者很可能熟悉鸢尾花的数据集。它在某种程度上是 ML 社区中“hello-world”的一部分;紧挨着著名的 MNIST。我们使用 sklearn.datasets 获取数据,并将其放入熊猫数据框中。:
iris_data = datasets.load_iris()
iris_df = pd.DataFrame(data=np.c_[iris_data['data'], iris_data['target']],
columns=iris_data['feature_names'] + ['target'])
为了让这个例子更加清晰易懂,我们只从给定的 3 个物种中选择 2 个。:
iris_df["target"] = iris_df.target.astype("int")
iris_df = iris_df[iris_df.target.isin([0, 1])]
现在你应该看到鸢尾花数据的 100 个测量值(行是我们的 n )。
我们现在随机取出 50%的花瓣长度条目,并赋予 NaN 值,带有一点数字和熊猫的魔力。
random_vec = np_random(iris_df["petal length (cm)"].shape)<0.5 iris_df["petal length (cm)"] = iris_df["petal length (cm)"].where(random_vec, other=np.nan)
为什么要关心所有的尺寸?
当我们绘制数据时,我们可以清楚地看到花瓣长度和花瓣宽度可以帮助我们识别我们正在观察的物种(目标列)(见图 1)。

图 1:花瓣长度和宽度与花种 aka 的关系。目标列。我们可以清楚地识别出两个集群。
我们可以通过仅使用花瓣长度参数对组进行回归来进行更清晰的区分,我们之前已经残酷地对该参数进行了删减。

图 2:已识别物种(目标)上花瓣长度参数的回归。
糟糕的是大约一半的数据丢失了。那我们现在怎么办?
不同深浅的思念
首先,至少有两种程度的缺失数据:
完全随机失踪(MCAR)和随机失踪(马尔)。
关于这方面的正式介绍,参见贝叶斯数据分析[1]第 18 章。
一个重要的区别是,MCAR 将您的缺失参数视为独立于您观察到的测量值(姑且称之为 y )。
在我们的例子中,我们相信我们的参数是随机丢失的或被标记的。这意味着我们不认为值丢失的可能性取决于参数属性,但是我们认为在我们的长度测量和目标物种之间存在潜在的某种关系。
回归模型来统治它们
首先,让我们从目前掌握的数据中提取一些基本信息:
>>> print("Petal Length μ = {}".format(iris_df["petal length (cm)"].mean()))
>>> Petal Length μ = 2.8072727272727267
>>> print("Petal Length σ^2 = {}".format(iris_df["petal length (cm)"].std()))
>>> Petal Length σ^2 = 1.4923079993698234
现在我们建立模型来做插补。为此,我们使用工具 NumPyro ,这是一个轻量级的概率库。NumPyro 为重型概率语言 Pyro 提供了一个类似 numpy 的后端。
这对于后期的模型拟合来说就派上用场了。我们将使用 MCMC 方法来执行贝叶斯推理,并在此过程中模拟缺失条目。
为了使其更适用于用例,我们将它与贝叶斯回归模型结合起来。这意味着我们想在给定所有已知参数的情况下模拟物种间的差异。因此,我们的变量是:
sepal length := s_len, sepal width := s_width, petal width := p_width and, lastly petal length := **p_len**, which includes our **missing data**.
为了简单起见,对于这些参数中的每一个,我们引入一个可学习的偏差,该偏差来自于一个规则的正态分布,即高斯分布。所以让我们开始吧。:
def model(s_len, s_width, p_len, p_width, target=None):
b_s_len = numpyro.sample("b_s_len", dist.Normal(0,1))
b_s_width = numpyro.sample("b_s_width", dist.Normal(0,1))
b_p_width = numpyro.sample("b_p_width", dist.Normal(0,1))
...
人们可以对上面的偏差参数做一点调整,但是对于我们的初始运行,正态高斯工作得相当好。现在是微妙的部分。我们引入分布,我们假设它位于我们的半破坏参数下。与许多事情一样,我们假设这是高斯分布,在我们的情况下,这是一个合理的假设。因此,我们使用之前计算的值 loc=μ (2.8 +/- 0.2)和 scale=σ (1.5+/-0.2)。****
...
len_mu = numpyro.sample("p_length_mu", dist.Normal(2.8, 0.2))
len_sigma = numpyro.sample("p_length_sigma", dist.Normal(1.5, 0.2))
...
有见识的读者清楚地看到μ和σ本身是我们在此过程中建模的概率参数。对于这两种情况,我们都假设为高斯分布,但也可以选择更严格的分布。现在让我们找到我们要建模的目标。我们用 numpy 函数定位向量中缺失的位置。
...
len_is_nan = np.isnan(p_len)
len_nan_idx = np.array(np.isnan(p_len).astype(int)).nonzero()[0]
len_impute = numpyro.sample("len_impute", dist.Normal(len_mu[len_nan_idx], len_sigma[len_nan_idx]).mask(False))
...
此外,我们告诉 NumPyro 使插补值(len _ imput)成为一个可学习的参数,并用我们丢失的值填充尽可能多的零。
简而言之——注意给面具带来一些光亮:我们的模型有一个预测模式,当没有提供目标(又名物种)时发生。当我们调用预测功能时,我们使用采样μ和采样σ从引入的分布中进行采样。
确保只在矢量中的 NaN 位置应用。
numpyro.sample("len_impute", dist.Normal(len_mu[len_nan_idx], len_sigma[len_nan_idx])
然后,我们将估算值放入正确的位置和样本,实际长度值作为我们的观察值。为此,我们使用 JAX 库和一些有效的索引更新——线性代数风格。:
...
p_len = ops.index_update(p_len, len_nan_idx, len_impute)
numpyro.sample("p_length", dist.Normal(len_mu, len_sigma), obs=p_len)
...
在我们的长度采样中,我们将实际长度测量值作为过程中的观察值包括在内。
把东西放在一起
我们继续将估算值放入回归模型。为了让贝叶斯模型起作用,我们必须符合我们的目标 y** (物种)。
因为我们有两个类,所以我们通过调用伯努利分布来实现。因此,我们在伯努利过程中问,我们看到的是 y=0 还是 y = 1——两个类别,两种可能的结果。**
贝叶斯回归代码
我们引入两个参数,其中之一是长度参数的偏差项。
...
l = numpyro.sample("l", dist.Normal(0, 1))
b_len = numpyro.sample("b_length", dist.Normal(0, 1))
logits = l + b_len * p_len
logits = logits + b_s_len*s_len + b_s_width*s_width + b_p_width*p_width
...
现在到了神奇的部分。我们将 logit 用于伯努利,它由我们放入模型的所有参数组成,与它们的偏差相互作用。这个过程中的观测值现在就是目标参数——我们的 y。
numpyro.sample("target", dist.Bernoulli(logits=logits), obs=target)
完整的 NumPyro 模型
def model(s_len, s_width, p_len, p_width, target=None):
b_s_len = numpyro.sample("b_s_len", dist.Normal(0,1))
b_s_width = numpyro.sample("b_s_width", dist.Normal(0,1))
b_p_width = numpyro.sample("b_p_width", dist.Normal(0,1))
# impute length
len_mu = numpyro.sample("p_length_mu", dist.Normal(2.8, 0.2))
len_sigma = numpyro.sample("p_length_sigma", dist.Normal(1.5, 0.2))
len_is_nan = np.isnan(p_len)
len_nan_idx = np.array(np.isnan(p_len).astype(int)).nonzero()[0]
len_impute = numpyro.sample("len_impute", dist.Normal(len_mu[len_nan_idx], len_sigma[len_nan_idx]).mask(False)) p_len = ops.index_update(p_len, len_nan_idx, len_impute)
numpyro.sample("p_length", dist.Normal(len_mu, len_sigma), obs=p_len)
l = numpyro.sample("l", dist.Normal(0, 1))
b_len = numpyro.sample("b_length", dist.Normal(0, 1))
logits = l + b_len * p_len
logits = logits + b_s_len*s_len + b_s_width*s_width + b_p_width*p_width
if target is None:
# prediction case
probs = expit(logits)
numpyro.sample("probs", dist.Delta(probs)) numpyro.sample("target", dist.Bernoulli(logits=logits), obs=target)
运行它
为了拟合该模型,我们利用 MCMC 方法使用贝叶斯推理;具体的坚果取样器。坚果采样器的美妙之处在于它是一种无需干预的方法,因为它通过问题空间步进,自己调整步长。我们让它有 5000 次预热或老化运行,在这个过程中被丢弃,让它运行 10000 次迭代,只是为了确保安全。我们的推断以 0.96 或 96%的接受概率结束——太棒了!。接下来,我们来看看发生了什么事的摘要:
mcmc = MCMC(NUTS(model=model), 5000, 10000, num_chains=1)
mcmc.run(random.PRNGKey(42), **iris_data)mcmc.print_summary()

图 3:在 MCMC 之后的模型总结表明收敛和固体 R-hat 值为度量。
输出清楚地显示了我们在推理中采样的参数的收敛性。具体来说,R-hat 值都> = 1.0。
然后,我们抽取样本并可视化后验概率——我们再次依赖 JAX 的格式化魔法:
samples = mcmc.get_samples()
posterior_mu = jnp.expand_dims(samples['l'], -1) + \
jnp.expand_dims(samples['b_length'], -1)*iris_df["petal length (cm)"].values + \
jnp.expand_dims(samples['b_s_len'], -1)*iris_df["sepal length (cm)"].values + \
jnp.expand_dims(samples['b_s_width'], -1)*iris_df["sepal width (cm)"].values + \
jnp.expand_dims(samples['b_p_width'], -1)*iris_df["petal width (cm)"].values
我们可以看到后面的图。我们找到了。我们两个阶级之间的明显区别。在界限上下有相当多的抖动,但是回归线看起来更好。
公平地说,这也是因为与我们早期的单参数模型相比,我们在回归中使用了所有可用的参数。
上面的樱桃是回归线周围的 90%置信区间,取自我们的后验线。这让事情看得更清楚。

图 4:对具有 90%置信区间的 MCMC 样本的最终贝叶斯回归。
我们已经证明,我们可以通过 MCMC 采样来填补模型中的空白。
对于精通代码、好奇的读者来说,最终的笔记本可以在我的 github 和 Google-Colab 上找到。
两个以上的类和分类数据?
这些问题也可以用 NumPyro 的工具包来回答:
- 除了在模型中进行伯努利试验,您还可以使用多项式进行贝叶斯推断。
- 我们也可以使用分类数据进行模型拟合。那看起来很不一样。我们不使用一维数组,而是依赖尽可能多的维度。
适合分类数据而不是连续数据的一个很好的例子**是关于年龄插补的优秀 Kaggle 笔记本,给出了 Titanic 数据集的其他参数:
使用 Kaggle 笔记本探索和运行机器学习代码|使用《泰坦尼克号:灾难中的机器学习》中的数据
www.kaggle.com](https://www.kaggle.com/fehiepsi/bayesian-imputation-for-age)
该做的和不该做的
请坚持你所拥有的!
不要捏造数据。我怎么强调都不为过。我们在这里走的是一条很细的线。
如果你的实验产生的数据不足,或者你不得不丢弃一些数据,那么输入数值可能不是最好的办法。即使您的数据可能以这种方式呈现。当与客户或学术期刊交谈时,你不会因为以下几点而得分:我们将参数 X 和 Y 模拟为 85.3%——无论模型看起来有多好。
请声明您使用了什么方法、分布和假设来制作模型和估算,以获得最大的透明度。
一个建议是,你可以随时取出数据,在没有遗漏测量值的情况下拟合一个模型,并将其与最终有估算值的模型进行比较。这可以成为一个引人注目的故事。
结论
我们已经走过了数据插补的过程,从最初杂乱的数据框架到最终的贝叶斯推理过程和拟合后验分布。
我们已经展示了贝叶斯回归如何受益于估算向量,以及包括置信区间在内的输出结果。
概率编程可以成为你日常工作中的一个强有力的工具。
祝您的模型和分析好运!
参考
[1] A .盖尔曼、J.B .卡林等人。艾尔。、 贝叶斯数据分析 。第三版。
[2] R .麦克勒瑞斯。统计学反思。2016.CRC 出版社。
[3]优步技术公司。使用 NumPyro 进行回归。 2019。 NumPyro 文档。
【4】m .贝当古。哈密尔顿蒙特卡罗概念介绍。 2020 年上ArXiv。
【5】CS 4110—编程语言与逻辑。概率编程。 2016 年。康奈尔大学。**
通过添加无监督的辅助损失来提高神经网络的泛化性能
作为一种正则化形式的无监督重建损失。

Sebastien Gabriel 在 Unsplash 上的照片
深度神经网络有一个很大的过拟合问题,特别是在应用于少量标记数据时。研究人员设计了多种方法来解决这个问题,如 L1/L2 权重正则化、辍学、迁移学习和多任务学习。
在这个项目中,我们将重点关注使用多任务学习作为一种提高神经网络泛化性能的方法。这里实现的想法受到了三篇非常有趣的论文的启发:
前两篇论文试图解释为什么多任务学习可以提高单个任务的表现,它们提供的一些可能的解释是:
表征偏差:

—作者图片
如果我们同时在任务 T 和 T '上训练一个网络,这个网络就会偏向服务于这两个任务的表征。这使得网络最有可能推广到新的任务。
正规化:
使用多任务学习使得网络不太可能过度适应来自训练数据的噪声,因为它减少了可能的解决方案的数量,因为 MTL 的解决方案需要同时对所有任务起作用。
注意力聚焦:
对多个相关任务的训练可以在什么是相关特征以及什么只是噪声上给模型更强的信号。
第三篇论文考虑了只有一个监督任务 T 的情况,因此作者增加了一个新的人工和非监督的重建输入的任务。他们在一个简化的设置中证明,增加重建损失提高了监督任务的泛化性能,并显示了一些支持他们假设的经验结果。
数据:
在接下来的实验中,我们使用免费音乐档案(FMA)小版本。这是一个包含 8000 首歌曲片段的数据集,分为 8 种类型:
{
"International": 0,
"Pop": 1,
"Instrumental": 2,
"Hip-Hop": 3,
"Electronic": 4,
"Experimental": 5,
"Folk": 6,
"Rock": 7
}
我们以 70%-10%-20%的比例将数据集分为 Train-Val-Test,并将原始音频波形转换为 Mel 频谱图,然后将它们馈送到网络。关于预处理的更多细节,你可以看看我以前的一个项目:

Mel 光谱图示例—作者提供的图像
型号:
我们沿着时间轴应用基于 LSTM 的神经网络来分类音乐流派。

音乐流派模型-作者图像
添加脱落图层作为额外的正则化,并使重建任务对模型来说更具挑战性。
我们使用 Pytorch Lightning 来实现这个模型,转发函数看起来是这样的:
**def** forward(self, x):
x = self.do(x)
x, _ = self.lstm1(x)
x_seq, _ = self.lstm2(x)
x, _ = torch.max(self.do(x_seq), dim=1)
x = F.relu(self.do(self.fc1(x)))
y_hat = self.fy(x)
x_reconstruction = torch.clamp(self.fc2(self.do(x_seq)), -1.0, 1.0)
**return** y_hat, x_reconstruction
现在我们将损失定义为分类损失和重建损失之间的加权和,如下所示:
损失=损失 _ 分类+ λ *损失 _ 重建
其中,λ是一个超参数,它有助于缓解两个损失的比例不同这一事实,同时还能更好地控制我们希望赋予辅助任务的重要性。损失定义如下:
**def** training_step(self, batch, batch_idx):
x, y = batch
y_hat, x_reconstruction = self(x)
loss_y = F.cross_entropy(y_hat, y)
loss_x = F.l1_loss(x, x_reconstruction)
**return** loss_y + self.reconstruction_weight * loss_x
结果:
在实验中,我们尝试了多个λ值,以查看哪一个效果更好,基线为λ= 0,这意味着辅助损耗被忽略。

我们可以看到,与基线相比,增加重建损失(λ = 10 和λ = 2)会产生更好的性能。
就分类准确度而言,我们有:

- 随机猜测: 12.5%
- 基线:准确率= 47.5%
- λ =10 :精度= 51%
当使用相同的分类体系结构时,增加重建损失给出了超过基线约 3%的精度改进。
结论:
在这个项目中,我们证明了向神经网络添加辅助的无监督任务可以通过作为正则化的附加形式来提高其泛化性能。添加重建损失的方法在 Pytorch Lightning 中很容易实现,但代价是我们需要优化新的超参数λ。
复制结果的代码在这里分享:https://github.com/CVxTz/ReconstructionAuxLoss
使用这些格式和文档模板改进您的 SQL
使用更好的 SQL 格式和文档,减少代码审查和知识转移的痛苦。

艾萨克·史密斯在 Unsplash 上拍摄的照片
介绍
您是否遇到过用于分析的复杂 SQL 查询?
你是否很难理解代码本身和其下的业务逻辑?
我做到了。而且有时候,是跟我过去的疑问!
为了节省阅读我的代码的每个人(包括我自己)的时间,我尝试将两个模板应用到我的查询中,并发现它们非常有帮助:
- 提高代码本身的质量
- 减少代码审查时间
- 并改善知识转移
你能期待什么
在本文中,我将与您分享我使用的这两个模板。
模板#1: 记录 SQL 查询中的上下文和假设
模板#2 :格式化 SQL 查询
为了演示它们的用法,我将通过一个使用 MySQL 的例子来总结新冠肺炎前后的销售情况。
希望这些模板能派上用场!尤其是在新冠肺炎启动后,远程工作成为我们的新常态,这增加了过度沟通的重要性,以确保每个人都在同一页面上。
模板# 1:SQL 查询中的文档上下文和假设
1.模板
在编写查询之前,请列出这些信息:
- 此查询的重要业务上下文
- 对查询结果的期望
- 对业务逻辑和数据的任何假设
/*
CONTEXT:
- add a brief description of why we need this queryRESULT EXPECTATION
- add a brief description of your expectations for the query resultASSUMPTION:
- add assumption about business logic
- add assumption about data
*/
2.行动中的模板
将此模板应用于我们的销售总结示例:
/*
CONTEXT:
- Our company wants to understand if COVID has any impact on sales in stores around Chicago.RESULT EXPECTATION:
- This query returns total sales (in USD) for each of our stores in Chicago every month before and after COVID, starting from 2019-03-01.ASSUMPTION:
- Dates before 2020-03-01 are considered "Before COVID"
- Each transaction has a unique id, so we do not expect duplications in our transaction table
- There are some spam transactions we have identified after COVID, so we will filter these out
*/
3.利益
在我们进行查询之前,对业务环境、结果预期和假设进行简要描述有很多好处:
- 它让我们在编写查询时专注于查询的主要目标
- 它帮助读者快速建立对我们的查询的价值和期望的高层次理解
- 它帮助代码评审员根据期望为查询创建初始测试
记住,这一步是一个迭代过程。在编写查询时,我们可能不得不反复修改文档。
模板#2:格式化 SQL 查询
1.模板规则
格式化 SQL 查询有许多规则。简单来说,这些是我遵循的主要规则:
- 使用大写字母突出显示保留的关键字(例如 SELECT,WHERE)
- 使用缩进清楚地显示查询或子查询的开始和结束位置
- 对于长而复杂的查询,在任何主要的子查询或上下文连接之前包含一个注释
- 请给出列的来源及其源表或描述性表别名
2.行动中的模板
此查询仅用于演示

3.利益
这种查询格式对可读性有很多好处。以下是一些例子:
- 理解查询的整体结构(即选择了哪些列,有多少个连接,应用了哪些过滤器)
- 节省时间来确定测试子查询的开始和结束,因为我们可以在同一条垂直线中看到子查询的开始和结束括号
- 避免迷失在复杂的查询中,在整个查询中都有注释
组合模板#1 和模板#2
在我们的例子中,结合这两个模板,我们将得到:
/*
CONTEXT:
- Our company wants to understand if COVID has any impact on sales in stores
around Chicago.RESULT EXPECTATION
- This query returns total sales (in USD) for each of our stores in Chicago
every month before and after COVID, starting from 2019-03-01.ASSUMPTION:
- Dates before 2020-03-01 are considered "Before COVID"
- Each transaction has a unique id, so we do not expect duplications
in our transaction table
- There are some spam transactions we have identified after COVID,
so we will filter these out
*/SELECT
store_info.id,
store_info.name AS store_name,
DATE_FORMAT(transactions.date, "%Y-%m") AS transaction_month,
SUM(transactions.total_amount) AS total_amount
FROM
transactions
LEFT JOIN
-- get all stores in Chicago
(
SELECT
id,
name
FROM
stores
WHERE
city = 'Chicago'
) AS store_info
ON
transactions.branch_id = store_info.id
WHERE
transactions.date >= '2019-03-01'
-- filter spam transactions
AND transactions.id NOT IN
(
SELECT
id
FROM
spam_transactions
)
GROUP BY
store_info.id,
store_info.name,
DATE_FORMAT(transactions.date, "%Y-%m")
额外小费
这些模板并不是唯一的模板。找出最适合你和你的团队的方法是一个反复试验的过程。
最终确定格式样式后,手动设置每个查询的样式可能会很累。许多 SQL IDE 都有一个选项可以自动完成这个过程。然而,如果它仍然不能满足您的需要,还有其他的工具。尝试使用这些关键字进行搜索:“SQL 格式化程序”
对于 Python 用户,我一直在摆弄 sqlparse 。你可以在这里获得更多的信息。
感谢您通读整篇文章!希望这些模板对你有帮助。我很想知道您的想法和任何其他技巧,以使 SQL 查询更具可读性。欢迎在下面留言,或者在 LinkedIn 上联系我。
改进的朴素贝叶斯分类器解决文本分类问题。
入门

斯蒂芬·菲利普斯-Hostreviews.co.uk 在 Unsplash 上的照片
本文致力于解释最经典的机器学习分类器之一——朴素贝叶斯。在这个故事中,我将解释朴素贝叶斯和背后的理论,最重要的是将呈现这个模型的一个简单的从零开始的 实现 。对于进入机器学习领域的人来说,这篇文章将会非常有用和有趣。我也相信有 ML 经验的读者也会学到新的东西。所以,事不宜迟,让我们开始吧。
正如艾萨克·纽敦曾经说过的那样:“如果我比别人看得更远,那是因为我站在巨人的肩膀上”,这是我自己相信的事情,就好像你想创造新的东西,你必须了解以前已经做过的事情。这可以让你不要在发明的东西上浪费时间,或者寻找机会来改进以前的方法和挑战现状。
因此,我想谈谈如何使用朴素贝叶斯来解决文本分类问题,但不会触及最新的深度学习方法。这将使大多数读者能够跟踪和理解这篇文章,无论其教育背景如何。
如果你是自然语言处理(NLP)领域的新手,我建议你在阅读这篇文章之前,先看看我的上一篇文章,在那里我讨论了我们如何使用简单的概率规则来执行文本生成。
在本文中,我们将从头开始使用朴素贝叶斯分类器创建一个垃圾邮件过滤器,而不使用任何外部库。首先,我想介绍一些理论,然后我们将讨论实现部分。

理论。
贝叶斯公式。
有很多文章讨论了朴素贝叶斯以及它在概念上是如何工作的,所以我不打算深入进行理论解释,而是讨论最基本和最重要的部分。
我们都知道贝叶斯公式是这样的:

在我们的 NLP 设置中,我们想要计算什么是 P(垃圾邮件|文本)和什么是 P(非垃圾邮件|文本)。
对于常用的术语,我将把“非垃圾邮件”称为“火腿”。
众所周知,任何电子邮件的文本通常由单词组成。因此,我们有兴趣计算 P(spam | word1,word2,…,wordN) 。以贝叶斯公式的形式来说:

当我们计算类似的概率时,但是对于火腿的情况,我们将得到以下公式:

如您所见,分母 P(w1,w2,…,wN) 【也称为归一化】在两种情况下是相同的,因为我们的任务是确定哪个概率更高(而不是确切的值),所以我们可以去掉归一化部分。推理如下所示:

奇怪的符号表示不确定左侧(LHS)是大于还是小于右侧(RHS)。

取消分母,因为我们知道概率是非负的。

所以最终,在贝叶斯分类中,我们得到了以下简化:

旁注:标准化部分在大多数情况下被忽略,不仅因为它是多余的,而且因为从数据中计算通常是非常复杂的,所以不必处理它简化了我们的生活!
我们为什么幼稚?
概括地说,为了判断电子邮件是否是垃圾邮件,我们需要查看哪个值更高 P(spam|w1,…,wN) 或 P(ham|w1,…,wN) 。

为了计算 P(spam|w1,…,wN) ,我们需要:
- P(垃圾邮件)–很容易找到,因为它只是我们数据集中垃圾邮件** 电子邮件与所有电子邮件的比率。**
- P(w1,…,wN | spam)–直接计算有点困难,所以让我们使用“天真”的假设,即文本中的单词是独立的,这样我们可以将这个术语简化为:

所以最后为了计算 P(spam|w1,…,wN) 我们会做:

看起来很简单,但是,让我们不要犯一个会破坏我们结果的错误。考虑一下,如果我们需要检查一个单词 w_i 但它从未出现在垃圾邮件中,会发生什么?

我们如何计算一般情况下的概率?
换句话说: P(w_i|spam) = 0。
显然,在这种情况下,由于乘法运算,我们最终会得到 P(spam|w1,…,wN) = 0 ,这可能会导致错误的结论,因为我们永远无法假设拥有包含所有单词的完美训练数据。也有可能一个单词包含了错别字,因此系统显然不知道它。(还要考虑这个词从未在垃圾邮件和火腿邮件中出现的情况,那么我们该如何对包含这个词的邮件进行分类呢?)
为了解决这个问题,使用了一种平滑方法,确保我们将非零概率分配给任何项:

这里α ( alpha )是一个平滑参数,应该是一个非负数。
提高效率——使用对数。
正如我们之前所看到的,为了计算概率,我们将不得不进行大量的乘法运算(与我们要评估的电子邮件中的单词一样多的次数)😗***

问题是所有的概率都小于 1,一般来说都很小。众所周知,2 个小值 0 < a,b < 1 的乘积会产生一个更小的数。因此,在朴素贝叶斯方法的情况下,我们将受到我们计算机的浮点精度的限制(因为在某些情况下,spam 和 ham 方程将会收敛到零,只是因为计算机在处理非常小的数字时的限制)。
我们该怎么办?我们需要把我们的计算转移到能够记录非常小的数字的超级计算机上吗?幸运的是,这是不需要的,对数来帮助!而且我们会用对数的乘积法则。

我们使用对数的另一个原因是:

这意味着如果 A > B,则 log(A) > log(B),反之亦然
**Hence, **if** *log(P(spam|text)) > log(P(ham|text))* **then** *P(spam|text) > P(ham|text)***
所以对于我们来说,用对数来计算概率会容易得多,对数的形式如下:

实施。

照片由 Alexander Sinn 在 Unsplash 拍摄
理论说够了,让我们把理论带入生活。正如我之前提到的,我将从头开始实现朴素贝叶斯分类器,并且不会使用任何 python 的外部库,因为它允许实现多种功能:
- 它帮助我们更好地理解朴素贝叶斯背后的理论。对于刚接触机器学习领域的读者来说是非常有益的。
- 它允许我们有一些灵活性并改进标准方法。在本文中,我们将同时使用单字和双字(如果你不知道什么是双字,请阅读本文)。
完整的代码和数据集可以在我的 github 库上找到。
数据集包含原始格式的电子邮件,因此为了处理电子邮件数据,我们必须使用 python 的email库。
现在,让我们看看支持功能:
第一个是记号化器,在你的修改中可以随意使用任何其他方法,但是这里这个方法记号化方法工作得足够好(你会看到我们的精度会有多好)。
下面你可以看到我们将用来计算垃圾邮件的对数概率的函数。
如前所述,我将在这里使用 unigrams 和 bigrams 来识别电子邮件是否是垃圾邮件,因此我们正在计算
P(spam|token_1,token_2,… token_n) ,其中 token_i 可以由一元或二元表示。这比只在单词(单字)层面上工作要好,因为我们变得不那么幼稚(因为我们接受文本中单词的某种依赖性)。****
除了我们在理论部分讨论的内容,我还介绍了一些特殊的标记,如<UNK>,如果我们偶然发现在训练集中没有见过的未知单词,我们将在推理部分使用这些标记。**
除此之外,我创建了一个记号<LONG_W>,它对应于大于 12 个字符的长单词和,其概率的计算与所有其他记号类似。**
垃圾邮件过滤器类别。
现在让我们转到垃圾邮件过滤器类的实现:
该类的初始化需要大约 10 秒钟,因为我们需要遍历所有垃圾邮件和业余邮件,并计算所有词类相关概率。
is_spam函数完成所有的推理工作,并负责根据文本中出现的标记判断电子邮件是否是垃圾邮件。因为这个函数确实做了我们在理论部分讨论过的事情,所以我不打算提供实现的详细解释。
现在,让我们创建主函数,并测试我们的解决方案有多好。
结果我们得到:
**done with initialization! 9.24 s
spam errors: 1
ham errors: 1
correct identified: 0.995**
99.5%的准确率,只有 1 个假阴性和 1 个假阳性,这是一个非常 骄人的成绩!
随意改变一些参数,比如平滑,或者不使用二元模型,而只使用一元模型,看看模型的准确性降低了多少。在这里,我已经提出了达到完美效果的最佳模型。
正如您从本文中看到的,朴素贝叶斯是一个非常简单且易于实现的机器学习模型,它能够在语言分类任务中实现一些令人难以置信的结果。
最不可思议的是,我们只用了 10 秒钟就训练好了模型,并且达到了非常好的精度。将其与深度学习方法进行比较,深度学习方法需要几个小时的训练,并且很可能只能达到与我们的朴素贝叶斯相似的性能。
如果你想让我在下一篇文章中涉及一些 ML 话题,请在评论中告诉我。
敬请关注更多关于人工智能和自然语言处理的文章。
洪水预报的改进

照片由 @chriswebdog
随着气候恶化,我们预测灾难性事件的责任
谷歌人工智能的研究人员写了一篇名为的文章,发表于 2020 年 9 月 3 日星期四,这是我们最近改进洪水预报背后的技术。
关于洪水,你可能不知道的几件事:
- 洪水是地球上最常见的自然灾害。
- 它影响着全球数亿人的生活。
- 每年造成约 100 亿美元的损失。
谷歌在前几年一直致力于洪水预报。
他们最近努力提高印度和孟加拉国的洪水预报。
通过这样做,他们将覆盖范围扩大到 2 . 5 亿多人,并提供了前所未有的前置时间、准确性和清晰度。

谷歌人工智能可视化
他们想出了解决这个问题的新方法。
即 形态学淹没模型 : 将基于物理的建模与机器学习(ML) 相结合,以在现实世界设置中创建更精确和可扩展的淹没模型。
他们将此与 警报定位模型相结合:“…允许使用端到端的机器学习模型和全球公开可用的数据来识别面临前所未有规模洪水风险的地区。”
他们有洪水预报系统,叫做(在今年的 ICLR 人工智能地球科学和 EGU 上展示)。
它们描述了几个重要的方面:
- ****预测水位:预计河流是否会发生洪水。
“一旦预测河流将达到洪水位,生成可操作警报的下一步是将河流水位预测转换为洪泛区将如何受到影响的预测。”
- ****形态淹没建模:在之前的工作中,我们开发了基于卫星图像的高质量高程图,并运行基于物理的模型来模拟水流穿过这些数字地形。”
根据谷歌人工智能的说法,这样做可以在数据匮乏的地区以前所未有的分辨率和准确性发出警告。
他们提到洪水建模面临三个重大挑战。
- “由于此类模型所涉及的面积和所需的分辨率较大,因此它们必然具有较高的计算复杂性。
- 此外,大多数全球高程图不包括河床水深测量,而河床水深测量对于精确建模至关重要。
- 最后,需要了解并纠正现有数据中的错误,可能包括仪表测量错误、立面图中缺失的特征等。”
他们对高程图的形态进行计算修改,允许人们使用简单的物理原理来模拟洪水,例如那些描述流体静力系统的原理。
他们训练模型使用它正在接收的数据来实时直接推断洪水地图。

谷歌人工智能可视化
“下面的动画展示了 HydroNets 中信息的结构和流动……网络迭代的输出将传递给下游模型,以此类推。”

谷歌人工智能可视化
看到谷歌人工智能取得的进步令人着迷。
这项工作肯定有助于拯救数百万人的生命。
这里是#500daysofAI,您正在阅读的是第 469 条。500 天来,我每天都在写一篇关于或与人工智能相关的新文章。
使用变换改进 CNN 深度学习模型时做什么和不做什么

迪伦·麦克劳德的图片
PyTorch 和 Torchvision 中的一个实验,用于在计算机视觉中诊断您的神经元网络性能
转换技术概述📋
根据维基百科[1]
数据转换是将数据从一种格式或结构转换成另一种格式或结构的过程。
在计算机视觉中,数据增强对于规范你的网络和增加你的训练集的规模非常重要。有许多数据转换技术(旋转、翻转、裁剪等……)可以改变图像的像素值,但仍然保留图像的几乎全部信息,因此人们很难分辨它是否被增强。这迫使模型在图像内的对象变化较大时更加灵活,较少考虑位置、方向、大小、颜色……通过数据扩充训练的模型通常概括得更好,但剩下的问题是数据转换可以在多大程度上提高 CNN 模型在图像数据集上的性能。
让我们来看看 Pytorch 在 Torchvision 中支持的一些数据转换技术,可以帮助你对ơn 图像进行增强。我还提供了一个真实图像数据集的实验,以显示应用不同方法时的性能。
- torch vision . transforms . center crop(size):类似于放大图像中心。它将给定的图像裁剪到所需的输出大小和位置(大小可以是正方形或长方形)。

- torch vision . transforms . pad(padding):相当于缩小图像。它将在给定图像的所有边上用某个值创建一个填充。

- torch vision . transforms . random crop(size,padding):这个函数将在随机位置裁剪给定的图像,以创建一组用于训练的图像。

- torch vision . transforms . randomhorizontal flip(p):该函数将按照给定的概率随机水平翻转给定的图像。

- torch vision . transforms . randomverticalflip(p):这个函数会以给定的概率随机垂直翻转给定的图像。

- torch vision . transforms . random perspective(distortion _ scale,p) :该函数将对随机给定概率的给定图像进行透视变换。它通过扭曲整个图像来降低模型学习的透视效果。

- torch vision . transforms . gray(num _ output _ channels):将图像转换为灰度。这有时有助于 CNN 模型使用单通道进行更快的训练,并且更容易地学习图像的模式。

- torch vision . transforms . color jitter(亮度、对比度、饱和度、色调):I 可以随机改变图像的亮度、对比度和饱和度

- torch vision . transforms . Normalize(mean,std): 用均值和标准差归一化张量图像。它将有助于 CNN 模型轻松转换到全局最小值或快速减少损失。如果你想知道为什么数据规范化是必不可少的,以及如何进行规范化以提高机器学习模型的性能,你可以参考下面的博客。
[## 用 Pytorch 中的数值变量转换提高机器学习模型的精度
这个故事提供了在 Pytorch 中实现转换技术和提高代码准确性的完整指南
towardsdatascience.com](/push-the-accuracy-of-machine-learning-model-with-numerical-variable-transformation-in-pytorch-9f56c56203fd) 
- torch vision . transforms . random erasing(p,scale,ratio,value)在图像中随机选择一个矩形区域并擦除其像素。该方法对 CNN 模型进行惩罚,有助于防止训练时的过拟合现象。

增强也可以应用于 NLP 以提高性能。例如:在句子中随意插入、调换、替换单词;在翻译中使用中间语言(反向翻译),打乱句子。
有几个库提供了优秀的增强模块,如白蛋白,NLPAug...下面是一篇来自 neptune.ai 的很棒的进一步探索的文章。
[## NLP 中的数据扩充:来自 Kaggle Master 的最佳实践
在自然语言处理中有许多任务,从文本分类到问题回答,但是无论你做什么,数据的数量…
海王星. ai](https://neptune.ai/blog/data-augmentation-nlp)
在 CNN 模型上评估转换技术📄
让我们讨论变换技术对 CNN 模型的影响。本实验中使用的数据集是来自 Kaggle 竞赛的犬种识别,该竞赛提供了 ImageNet 的严格犬子集,以便练习细粒度的图像分类。该数据集包括 120 个品种的狗,总共有 10,222 张图像。我们以 0.8/0.2 的比率将数据分割为训练/有效。
在本文中,预训练的 ResNet 2模型将被用作分类 CNN 模型的主干。ResNet 是 SOTA 预训练模型之一,在广泛的计算机视觉任务中显示出良好的结果。ResNet 的主要思想不是用函数 H(x)(多层感知器网络的堆叠)直接学习图像的输入特征,而是提供一个残差函数,它可以重构 H(x) = F(x)+x,其中 F(x)和 x 分别表示堆叠的非线性层和恒等函数(输入=输出)。这种思想可以解决深层神经元网络(消失梯度)的退化问题,因为它比原始映射函数更容易优化残差映射函数 F(x)。

首先,我们将加载原始数据。
# Create a custom Dataset class to read in data from dataframe
class BreedDogDataset(Dataset):
def __init__(self, dataframe, root_dir, transform=None):
self.dataframe = dataframe
self.root_dir = root_dir
self.transform = transform
def __len__(self):
return (len(self.dataframe))
def __getitem__(self, idx):
img_name = os.path.join(self.root_dir,
self.dataframe.iloc[idx, 0])
image = Image.open(img_name)
target = self.dataframe.iloc[idx, 1]
target_processed = breeds_processed_dict[target]
if self.transform:
image = self.transform(image)
sample = (image, target_processed)
return sampletransform = transforms.Compose([transforms.Resize((255, 255)),
transforms.ToTensor()])train_ds = BreedDogDataset(df_train,TRAIN_DIR, transform=transform)
val_ds = BreedDogDataset(df_val,TRAIN_DIR, transform=transform)

然后我们创建一个这样的结构模型:
# load pre-trained model
conv_base = models.resnet50(pretrained=True)# create a new model class
class Model(nn.Module):
def __init__(self, base_model, output):
super(Model, self).__init__()
self.base_model = base_model
self.output = output
self.fc1 = nn.Linear(n_outs, 512)
self.fc2 = nn.Linear(512, output)
self.dropout = nn.Dropout(0.5)
def forward(self, image):
x = self.base_model(image)
x = self.dropout(x)
x = F.relu(self.fc1(x))
x = self.dropout(x)
outs = self.fc2(x)
return outs
在深度学习模型中要调整的最重要的超参数之一是学习速率。选择正确的学习率非常重要,如果学习率太高,模型将面临发散问题,但如果学习率太低,模型将需要很长时间才能收敛。这个想法是,我们可以通过数百次迭代训练模型来找到一个好的学习率,然后基于学习曲线,我们获得一个好的学习率。学习率调度技术有很多,例如,功率调度、指数调度、1 周期调度、常数调度……在这个实验中,我们将应用1 周期调度。在 Leslie Smith 的论文中,这项技术被证明可以显著提高训练时间。你可以看看这个博客了解更多的解释。
介绍
towardsdatascience.com](/finding-good-learning-rate-and-the-one-cycle-policy-7159fe1db5d6) 
模型的学习曲线
根据上面的学习曲线结果,它显示下限是 0.9E-04,I 取整值为 1.0E-03。现在,我可以通过使用经验法则定义学习速率的范围来微调新图像数据集上的预训练 ResNet50:从比损失最小的学习速率低一个数量级的速率开始,到“安全”速率 1E-03 结束。
经过 5 个历元的训练,有效集的正确率为 83.284 %

列车损失和有效损失如下所示。可以看到两个值都降低了。从第 4 代到第 5 代,损失和准确性几乎是恒定的。这意味着模型已经从数据中学习了相对的一切,所有帮助模型区分品种狗的好信息都被捕捉到了。

然后,我们检查前 6 个损失最高的图像。我们可以看到,模型对一些图像进行错误分类的原因之一是,狗的品种预测与其他不同品种的样本相似,这甚至是人类无法区分它们。为了解决这个问题,转换技术非常有希望帮助模型深入学习每个品种的模式。另一个问题是,一些图片有 2 只不同的狗,但标签上只显示一只。错误的标签也是另一个问题。这些问题无法解决,这似乎是一个异常情况。

让我们在这个数据集中应用一些转换技术。
mean = [0.4766, 0.4527, 0.3926]
std = [0.2275, 0.2224, 0.2210]# define transform function
transforms_train = transforms.Compose([
transforms.Pad(25, padding_mode='symmetric'),
transforms.RandomHorizontalFlip(),
transforms.RandomRotation(10),
transforms.ToTensor(),
transforms.Normalize(mean, std),
transforms.RandomErasing(p=0.75,scale=(0.02, 0.1),value=1.0, inplace=False)
])transforms_val = transforms.Compose([
transforms.Resize((255, 255)),
transforms.ToTensor(),
transforms.Normalize(mean, std)
])
# load in the temporary dataset from the original dataframe with transform
train_ds = BreedDogDataset(df_train,TRAIN_DIR, transform=transforms_train)val_ds = BreedDogDataset(df_val,TRAIN_DIR, transform=transforms_val)

转换后的训练数据集

转换后的有效数据集
在变换后的数据集上用 5 个历元进行训练后,我们得到有效集的准确率达到 0.817,与原始图像相比略有下降。

新的列车损失和有效损失如下所示。与上述模型相比,列车损失和有效损失之间的距离增加,而第 4 和第 5 个时期的精度略有下降。这表明新模型面临着不匹配的问题。通常,转换确实有助于模型防止过度拟合问题。然而,在这种情况下,因为先前的模型没有过拟合问题,并且训练损失甚至高于有效损失,所以当应用变换时,没有改善。

让我们看看损失最大的前 6 张图片。我们可以看到一些混乱的图像现在可以被分类,但有些还没有。然而,这个问题无法解决,一些异常值仍然会影响模型的性能。

最后的想法📕
这个博客的主要目的是介绍一些转换图像的技术。从根本上说,这将有助于避免过拟合问题,以及增加 CNN 模型的训练数据的数量。但这并不意味着变换总是会提高模型的精度,它必须依赖于输入图像(卫星、细菌、动物、物体、..)和模型结构。许多 Deep-ML 实践者遇到了这个问题,他们通常在检查他们的模型可以从他们的原始图像学习到什么程度之前进行转换。如果模型不符合原始图像,转换数据无助于解决问题,换句话说,它会降低模型的准确性。因此,我们必须一步一步地诊断我们的模型,并通过最坏的预测来分析可视化的结果。
如果你想进一步讨论,可以联系我。这是我的 LinkedIn
尽情享受吧!!!👦🏻
参考
[1]https://en.wikipedia.org/wiki/Data_transformation
[2] 何、、、【邵青任、、,深度残差学习用于图像识别,2015。
改进 538 著名的 NFL 预测模型
深入研究 NFL 的统计数据,以改进一个有潜力与拉斯维加斯竞争的著名模型

照片由于是吊杆从的 Unsplash
NFL 赛季即将来临。球员们正在接近训练营的尾声,球迷们都渴望在周日再次观看他们最喜爱的球队比赛。退一步说,我们是如何走上这条不归路的。休赛期是我们从未见过的,今年也是如此。鉴于今年的表现,我们都应该感谢甚至会有 2020 赛季。但是足球似乎又回来了,每个人都在做准备。
有钱可赚
当我说每个人都准备好了,我指的是:教练,球员,球迷,体育出路,体育作家,体育更好,和拉斯维加斯。拉斯维加斯可能看起来很奇怪,但我向你保证,他们比任何人都更为 2020 赛季做好了准备。你可能会问为什么?因为他们从事信息产业。他们掌握的信息越多,你损失的钱就越多。
随着 2020 赛季在拉斯维加斯周围滚动,将在当前赛季发生的数百个事件中设定赔率,每年都有数百万投注者在这些赔率上下注,希望它们发生。剧透警报!许多更优秀的人将会失败。为什么?因为这些几率不会凭空出现。不,它们是由精心设计的模型生成的,当输入信息时,会输出一个事件的概率,而大多数优秀者通常会高估或低估这个概率。这就是为什么大多数优秀者会失败。他们只是没有维加斯有的信息。
有些人会战胜维加斯,并不断战胜他们。这些更好的人创造了他们自己的模型,与维加斯使用的模型竞争,这就是我们著名的模型出现的地方。
著名的模特
你可能想知道“著名模特”上的这句话是什么,它是由 Nate Silver 创作的,他是 FiveThirtyEight 的创始人兼主编和他的团队。

FiveThirtyEight 的标志
FiveThirtyEight 是一个专注于政治、经济和体育博客的网站。他们以使用统计分析和硬数字来讲述令人信服的故事和创建显示或预测结果的模型而闻名。毫无疑问,他们最著名的是他们的 NFL 预测模型。这种模式被认为可以与拉斯维加斯的模式相提并论,这也是许多职业运动员使用这种模式的原因。他们依赖预测,并根据模型的预测下注。
该模型创建于 2014 年,多年来一直在不断更新,以进一步提高预测的准确性。但在 2020 年,我找到了改进模型的方法,进一步提高了预测的准确性。稍后我会更详细地介绍,但我认为是时候让你最终了解这个著名的模型是什么以及它是如何工作的了。
电子学
如果你熟悉国际象棋中玩家的排名,那么你就熟悉 Elo 评级。Elo rating 是一个简单的系统,根据头对头的结果来判断球队或球员,是 FiveThirtyEight 创建的模型的核心。这些 Elo 评级能够预测每场比赛的结果,并为每支球队生成获胜概率。该系统的螺母和螺栓如下所述。
游戏预测
首先,Elo 模型给每个团队分配一个功率等级。这些评级用于根据两个团队的 Elo 评级之间的差异来生成游戏的获胜概率。球队通过赢得比赛来增加他们的 Elo 等级,通过输掉比赛来减少,但是增加多少取决于比赛的预期结果。
例如,让我们取两个团队,给他们每个人一个 Elo 评级。让我们说达拉斯牛仔队对纽约巨人队。达拉斯牛仔队的 Elo 评分为 1650,纽约巨人队的评分为 1400。由于达拉斯的收视率更高,我们知道他们比纽约赢得了更多的比赛,应该在这场比赛中受到青睐。事实上,我可以告诉你,Elo 模型给了他们 80%的胜算。

达拉斯牛仔队主场迎战纽约巨人队,2019 赛季第一周。照片由 Depositphotos
Elo 评分被称为一对一系统的原因是,如果达拉斯赢了这场比赛,他们将从纽约拿分,这意味着他们的 Elo 评分将增加纽约的减少量。这个数字取决于预期的结果。由于达拉斯有望以较大优势获胜,如果他们真的获胜,他们的 Elo 评分只会增加约 5 分。然而,如果纽约赢了,他们的 Elo 评分将增加约 17 个点。Elo 考虑到了对手的水平,对失败者奖励更多,对受欢迎者奖励更少。这是为了确保 Elo 评级高的团队能够战胜实力相当的团队,而不仅仅是低于平均水平的团队。
调整
从表面上看,Elo 系统非常简单。如果一个球队赢了一场比赛,他们的 Elo 评分会根据预期结果增加,反之亦然,如果他们输了这场比赛。但是足球比这更复杂。Elo 评级显示了足球队作为一个整体的整体实力,但它没有考虑影响足球比赛的外部环境。环境包括:球队是在主场还是客场比赛,他们是否会在一周内结束比赛,或者首发四分卫是否有变化。
必须针对这些情况进行调整,以确保模型尽可能准确。因此,FiveThirtyEight 的 Elo 模型还包括在每场比赛开始前进行的几项调整:
- 主场适应——NFL 的球队主场比客场打得更好。事实上,在过去的 10 年里,主场作战的球队比客场作战的球队平均多赢 2.2 分。因此,该模型通过在比赛前将主队的 Elo 评级增加 55 分来调整主场优势。
- 休息调整—NFL 中的每支球队都有 1 个轮空周(除了在季后赛开幕周不比赛的头号种子球队),研究表明,他们在那个轮空周的表现比预期的要好。为了适应这种更好的打法,一个结束轮空周的队伍会在那场比赛中获得 25 点 Elo 积分。
- 季后赛调整 —季后赛和常规赛很不一样。在季后赛中,人们发现,热门球队往往会以更大的优势击败弱队。为了调整这一点,该模型在季后赛中略微增加了热门球队的获胜概率。
- 旅行调整— 旅行会对玩家产生巨大的影响,从时差到身处不同的时区。它也显示出会影响团队作为一个整体的表现。那些不得不在全国各地旅行的球队比那些只坐一辆公交车的球队打得差一点。为了调整这一点,对手每行进 1000 英里,主队获得 4 个 Elo 点的增加。这意味着巨人队在“主办”喷气机队时获得 55 分的 Elo 奖金(没有旅行调整,因为他们在同一场地比赛,55 Elo 奖金来自主场调整),而如果西雅图来比赛,巨人队将因西雅图必须旅行的长距离获得 62 分的 Elo 奖金。
- 胜率乘数— 如果我们只根据输赢来评判球队,以上所有的调整就足够了。然而,我们希望该模型考虑到一支球队是如何获胜的——他们是统治了对手还是仅仅险胜对手。因此,有一个乘数,增加了一个团队获得的 Elo 点的数量基于他们如何获胜。这个乘数的公式如下。

如果你想知道像主场优势增加 55 个 Elo 点这样的具体数字是如何产生的,那么这是因为 NFL 比赛中的每一点都等于模型中的 25 个 Elo 点。我之前说过,主场作战的球队平均多赢 2.2 分。2.2 x 25 =55,这就是模型找出每次调整应该增加多少的方法。
季前赛收视率
关于 Elo 模型应该知道的一点是,它总是连续的。每支球队的 Elo 不会在每个赛季后重置,相反,Elo 评级会延续到下一个赛季。考虑到休赛期的变化,可能包括选秀权,自由球员,交易和教练的变化,有一个对 Elo 评级的季前赛调整。
这种调整使用两个因素。第一个是将一个球队的赛季末 Elo 恢复到平均值 1505 的三分之一。第二个是使用下个赛季拉斯维加斯的总胜率。
下赛季开始时,一个球队的 Elo 评级是三分之一的权重给回归的 Elo,三分之二的权重给拉斯维加斯的胜利。
准确(性)
回头看看达拉斯对纽约的例子,达拉斯的 Elo 评分是 1650,纽约是 1400。两者相差 250。如果我们除以 250/25,我们得到 10。这在模型中的含义是,它预测达拉斯将赢纽约 10 分。这就是如何预测每场比赛的点差。该模型将 Elo 差值除以 25,因为像我之前提到的那样,NFL 比赛中的每一分都等于模型中的 25 个 Elo 分。
通过比较每场比赛的实际得分差异,预测的点差是评估预测准确性的一个很好的方法。这正是 FiveThirtyEight 判断其模型准确性的方式。使用均方误差,该模型找出预测的点差和实际点差之间的差异,并对误差进行平方,以对不良失误给予更大的惩罚。误差越小越好。
均方差公式:
(Predicted Point Spread - Actual Score Diff)² = MSEExample: (10 - 7)² = 9
FiveThirtyEight 还使用 Brier 分数评估他们的模型。Brier 分数使用获胜概率,而不是点差。在我们达拉斯的例子中,模型给了他们 80%的获胜概率。在 80%的情况下,模型非常有信心达拉斯会赢,如果他们赢了,Brier 分数会很低(Brier 分数越低越好,因为它们意味着预测更接近正确)。然而,如果纽约仅以 20%的获胜概率获胜,这意味着我们的模型在预测这场比赛的结果方面是非常错误的,并且 Brier 得分将会相当高。
Brier 评分公式:
(Win Probability — Outcome of Game)² = Brier ScoreExample:
(0.80 — 1)² = 0.04 #If Dallas wins the game
(0.80 — 0)² = 0.64 #If Dallas loses the game
最新版本
多年来,FiveThirtyEight 的 Elo 预测模型不断更新,进行了新的调整,以进一步提高这两个指标的预测准确性。2019 年,他们的最新版本问世,表现比以前的版本好得多。下图显示了最新版本和旧版本在准确性指标上的差异。精确度的提高可以归功于他们最新模型的又一次调整,这是他们最大的调整,也可能是他们最重要的调整,我们还没有讨论过。

四分卫调整
2019 年 FiveThirtyEight 增加了游戏最重要位置的调整。它是这样工作的:
- NFL 中的每个球队和四分卫都会根据他们最近的表现获得一个价值评级。该价值等级根据四分卫在比赛中的表现而增加或减少。
- 模型如何通过这个公式评估四分卫在一场比赛中的表现: *-2.2 *传球次数+ 3.7 *完成次数+(传球码数/ 5) + 11.3 *传球次数-14.1 *拦截次数-8 次抢断次数-1.1 *抢断次数+ 0.6 *抢断码数+ 15.9 抢断次数
- 上面的公式是一个四分卫的 Game_VALUE。每场比赛后,四分卫的价值根据他们的 Game_VALUE 增加或减少。这是通过将更新后的四分卫值贡献为其旧值的 90%和其游戏值的 10%来完成的(即,值评级新值= 0.9 值评级旧值+ 0.1游戏值)
- 这个值也通过计算球队允许的 QB 值来调整对手的防守质量。这是通过从对手通常每场比赛放弃的值中减去联盟平均值来完成的,并用它来调整 QB 在所讨论的比赛中的表现。例如,如果对方球队通常放弃比平均水平高 5 分的 QB 值,我们会将其他球队个人 QB 的表现向上调整 5 分,以说明对方防守更容易。
- QB 值代表了我们期望四分卫在下一场比赛中面对一般质量的传球防守时的表现。要将这一价值评级转换为 Elo,该值可以乘以 3.3,以获得 QB 与未选秀新秀替代者相比的预期 Elo 点数。
- 为了了解四分卫可能拥有的不同价值评级,下面是 2019 赛季前 10 名四分卫的表格。

四分卫 Elo 调整在每场比赛前应用,方法是将起始 QB 的价值评级与球队的价值评级进行比较,并乘以 3.3。

德鲁·布里斯,新奥尔良圣徒队的四分卫。照片由 Depositphotos
例子:当德鲁·布里斯在 2019 赛季中途受伤时,他的价值评级为 75。新奥尔良圣徒队的球队价值得分是 78,替补球员泰迪·布里奇沃特的个人得分是 45。因此,当调整圣徒队的下一场比赛的 Elo,让布里奇沃特而不是布雷斯首发时,我们会将*3.3 (45–78)=-109的调整应用到新奥尔良在第四周对阵牛仔队的比赛中 1639 的基本 Elo 评分。这实际上会使圣徒队成为一支 1530 年的 Elo 球队,布里奇沃特在中心位置(在对主场,旅行和休息进行调整之前),尽管在主场比赛,新奥尔良队的获胜概率从 60%下降到 44%。在这种情况下,QB 调整会产生巨大的影响!
就像球队的季前赛评分是如何调整的一样,个人四分卫也是如此。当休赛期到来时,四分卫在赛季结束时的最终价值评级会在下一个赛季开始前恢复到平均 QB 值的四分之一。
对于初次登场的新秀,我们根据选秀位置给他们分配初始评分。一个未选秀的新秀在他的第一次首发总是被评为零分。相比之下,第一个整体选秀权在他第一次开始之前得到 35 的价值评级。
现在,您应该对 FiveThirtyEight 模型的工作原理有了更高质量的理解。这是一个简单而有效的模型,可以预测游戏的结果、赢的概率和他们的点数差距。
然而,这个模型还可以进一步改进,我已经改进了!我发现了 FiveThirtyEight 的人没有做的其他调整,并最终极大地改进了模型。
改进
当试图找出如何改进 FiveThirtyEight 的模型时,我不得不考虑他们没有针对游戏的哪些方面进行调整。正如我们之前讨论的,他们已经调整了:主场,再见周,季后赛的最爱,旅行距离,和首发四分卫的变化。但是深入到足球比赛中,我发现了 3 个新的调整,极大地改进了模型。
1.一个队在哪一天比赛
明尼苏达维京人队的四分卫柯克·考辛斯是这次调整的灵感来源。考辛斯因在黄金时段游戏(周一晚上)玩得很烂而出名。周四晚上和周日晚上的比赛)。事实上,他在这些比赛中的战绩是 6 胜 13 负,尽管他在一个高于平均水平的球队打球。
这让我想到,在全世界都在看的国家电视台黄金时段的比赛中,球队比在正常的周日下午打得更好还是更差。当深入研究过去 10 年的统计数据时,我发现…

从上表可以看出,在周四和周日晚上的比赛中,主队获胜的几率要高出近 5%。这些球队还在周四晚上将他们在这些比赛中的平均胜率提高了约 1 分,在周日晚上提高了约 2.5 分,从而证明了在主场,球队通常在黄金时间的比赛中打得更好。所以我们改进模型中加入的调整是周四晚比赛主队加 25 Elo 分,周日晚比赛主队加 50 Elo 分。
2.部门游戏
在 NFL 的每个部门有 4 个队。这些队在常规赛中互相打了两次。由于同一个赛区的球队比其他球队更频繁地碰面,所以他们的优势是打一次,适应一下,然后再打一次。这将导致分区赛比非分区赛更接近,因为这些球队已经看到了其他球队如何比赛,他们可以为此做准备。
下表显示了过去 10 年间分区赛和非分区赛的区别。

从上表可以看出,在分区赛中,主队的胜算比非分区赛低近 3%。他们的平均胜率也减少了一分,证明了分区比赛比非分区比赛更接近和更难预测。为了适应更接近的赛区比赛,我们的改进模型将 Elo 分数较高的球队减少 25 分,以最小化两个赛区球队之间 Elo 的总体差异。
3.维加斯点差
正如我之前所讨论的,FiveThirtyEight 的模式很有名,因为它与拉斯维加斯的模式竞争。事实上,当比较他们的模型的预测点差和拉斯维加斯的预测点差时,在大约 80%的游戏中,两者之间的差异仅仅是一个投篮得分(3 分或更少)。但是 Elo 模型的缺点是它不像 Vegas 模型那样是最新的。
当维加斯推出他们的点差时,他们在计算他们能找到的每一个因素;伤病,天气,最后一秒的首发变化等等。Elo 模型不会这样做。它的大部分调整你可以在一周前找到信息。唯一最新的调整是四分卫调整,当四分卫发生变化时应用,但对于其他每个位置,不存在调整。
如果在大约 80%的游戏中,两个点差之差大约是 3 分,那么剩下的 20%会发生什么呢?在我的结论中,我认为除了四分卫位置之外,可能还有一个伤害,或者一个 Elo 模型无法调整的未知情况,这可能会使两个点之间的差异大于 3。这是我们进行第三次调整的地方。
由于我们的模型不能适应这些情况,我决定从维加斯模型中得到一点帮助。因此,如果我们的模型的预测点差和 Vegas 的预测点差之间的差异大于 3,那么我们调整我们的预测点差以匹配 Vegas 的点差。例如,如果我们的模型预测牛仔队赢 10 分,但维加斯预测他们赢 6 分,那么我们调整两个队的 Elo,这样我们预测的点差就是 6 分。
就像上面的例子,达拉斯的 Elo 是 1650,纽约是 1400。Elo 的差别是 250 和 250/25 =10。我们的模型预测点差为 10,但我们希望它与拉斯维加斯的 6 相匹配。因此,我们将达拉斯的 Elo 从 1650 降低到 1550。
1550–1400 = 150,150/25 = 6,我们现在当前的预测点差(这也将达拉斯的预测获胜概率从 80%降至 70%)。
我们改进后的车型在这一季表现如何
2019 年是一个有点不可预测的 NFL 赛季。这是因为在 FiveThirtyEight 的最新和旧的 Elo 模型版本中,两个准确性指标(Brier 分数、均方误差)都比前几年有所下降。但是,在这个不可预测的 NFL 赛季中,我们改进的模型表现如何呢?通过在两个准确性指标上比较所有 3 个模型,我们可以确定哪个模型在 2019 年赛季中表现最好。
欧石南得分:

如果你记得 Brier 分数越低越好,我们改进的模型能够显著降低 Brier 分数。2019 年,新 Elo 的平均 Brier 分数为 0.219 ,我们改进的模型的平均分数为 0.196 ,这表明在 2019 年,我们的模型能够比两个 Elo 版本更好地预测团队的获胜概率。但不仅仅是 2019 年。如果你看上面的图表,在过去的 5 年中,我们的改进模型每年都比两个 Elo 版本表现得更好。
使用 Brier 得分,让我们看看每个模型的准确性如何在常规赛中随着时间的推移而演变。从下面的图表中可以看出,在第 3、4 和 9 周,我们的模型比 Elo 版本表现更差。但在其他方面,我们改进的模型表现更好。这意味着在 14/17 周,我们改进的模型表现最好。这导致了 2019 赛季 Brier 的整体平均得分下降。

均方差:

类似于 Brier 分数,我们改进的模型在均方误差方面每年都优于两个 Elo 版本。2019 年,新 Elo 的平均 MSE 为 183 ,而我们改进的模型的平均 MSE 为 174 ,表明 2019 年我们的模型能够比两个 Elo 版本更好地预测游戏的点差。
最大命中和未命中
你已经看到了我们的改进型号在季度和周周基础上比 Elo 版本做得更好。理论上,接下来的部分是展示我们改进的模型在哪些特定的游戏中提高了最多的准确性。
下面是两张图表。第一个显示我们的改进型号相对于最新的 Elo 版本的最佳选择,第二个显示最差的。
(老栏目指的是 FiveThirtyEight 最新的 Elo 模型预测获胜队伍的胜率。新列是我们的改进模型预测同一团队的胜率)。

2019 赛季,我们的改进模型和 FiveThirtyEight 的最新 Elo 模型之间的最高 Brier 分数差异。

2019 赛季,我们的改进模型和 FiveThirtyEight 的最新 Elo 模型之间的最低 Brier 得分差异。
FiveThirtyEight 的 NFL 预测游戏
每年 FiveThirtyEight 都会举办一场 NFL 预测比赛,看看是否有人能在预测 NFL 比赛中击败他们的 Elo 模型。每年,成千上万的人报名证明他们比 FiveThirtyEight 和其他任何人都更了解足球。
游戏通过使用 Brier 分数来工作。NFL 赛季(包括季后赛)的每一周,球员通过给球队一个胜率来决定哪支球队会赢。在每场 NFL 比赛结束后,玩家将根据他们是否选择了获胜的球队以及他们对获胜的信心程度来得分或失分。你分配给一个团队的获胜概率越高,你能赢得的分数就越多——但如果你过于自信,你失去的也就越多。

通过给匹兹堡 91%的获胜概率,如果他们赢了,这个玩家将获得 24.2 分。然而,过度自信可能是灾难性的,因为如果他们输了,这个球员将失去 57.8 分。
为了进一步证明我们改进的模型可以比 FiveThirtyEight 更好地预测 NFL 比赛,我决定参加他们的比赛,看看如果我们确实在 2019 赛季比赛,我的改进模型会积累多少分。
2019 年,超过 15,000 名球员报名参加了 FiveThirtyEight 的 NFL 预测游戏。在赛季结束时,FiveThirtyEight 的模型已经积累了 773.7 分,足以进入第 97 百分位和第 514 位。这意味着他们的模型能够比 97%的比赛更好地预测 NFL 比赛。相比之下,排名第一的格里芬·科莱齐以 1,126.2 分的成绩排名第 99 位。
问题是,我们的改进模型能够击败 FiveThirtyEight 的分数吗,它甚至接近格里芬的分数吗?
下面是我们的改进模型在 NFL 预测游戏中每周获得的净点数的每周图表。

除了 2 周之外,我们改进后的车型在净积分方面一直保持正值,并以 1,414.8 分的总成绩结束了本赛季。我们不仅将 538 分提高了近一倍,还比格里芬多得了近 300 分,彻底击败了他。这意味着,如果我们的改进模型在赛季中参加预测比赛,我们不仅会在近 15,000 名竞争对手中获得第一名,而且甚至不会接近。
季节模拟
Elo 模型如此伟大的原因是因为预测比赛所需的大部分信息可以在下赛季赛程公布前几个月找到。由于我们距离赛季开始还有几天,我们现在了解了 Elo 评级如何随着赛程的进行而更新,我们拥有了所需的信息,并可以预测整个 2020 赛季将会发生什么。
NFL 赛季并不总是确定的,通常应该击败其他球队的球队有时会输。这意味着 NFL 赛季存在随机性。为了将这种随机性整合到我们的模型中,我们使用蒙特卡罗方法模拟 2020 年 NFL 赛季 10 万次,跟踪每个模拟宇宙为每个球队产生给定结果的频率。
最后,模拟将显示一支球队的预期 Elo 积分、积分差异、整个赛季的记录以及赢得分区冠军、进入季后赛、获得第一轮比赛甚至赢得超级碗的几率。
在下面找到你最喜欢的球队,看看我们的模型预测你的球队下赛季会发生什么。


结论
FiveThirtyEight 的 Elo 模型简单但有效。通过 Elo 评级,很容易判断任何给定团队的实力,并预测赢家。随着模型而来的调整,通过处理直接游戏内外的情况,帮助这些预测变得更加准确。
我们能够通过重新创建并添加一些我们自己的调整来改进他们的 Elo 模型。但是我们能进一步改进它吗?绝对的!足球不是停滞不前的,它是不断变化的,新的模式和比赛风格将会出现,这将改变比赛的方式。这就是为什么拉斯维加斯的模式仍然是最好的,他们总是根据游戏的变化而变化。通过做同样的事情,Elo 模型可以与拉斯维加斯的一些最好的竞争,甚至有能力超越。
谢谢你
我想写一小段话来感谢五点三十八分的朋友们。他们在提供他们模型的细节方面做得很好,这让我可以重现他们。我在本文中讨论了该模型的大部分内容,但如果你想自己阅读细节,这里有一个他们网页的链接:我们的 NFL 预测如何工作。如果你也想参加他们的 NFL 预测游戏,我也会留下一个链接:如何参加我们的 NFL 预测游戏。
参考
[1] FiveThirtyEight,我们的 NFL 预测如何工作 (2019),https://FiveThirtyEight . com/methodology/How-Our-NFL-Predictions-Work/
[2] N. Paine,我们的新 NFL 模特这一季表现如何 (2020),https://fivethirtyeight . com/features/How-Our-New-NFL-Model-DOD-This-Season/
[3] J. Boice,如何玩我们的 NFL 预测游戏 (2018),https://fivethirtyeight . com/features/How-To-Play-Our-NFL-Predictions-Game/
[4]职业足球参考,https://www.pro-football-reference.com/(2020)
机器学习:使用数据扩充提高 MNIST 的分类精度
增加训练数据集的简单方法
MNIST 数据集有被称为你好世界的图像分类。每个机器学习工程师迟早都会处理这个数据集。
数据集
MNIST 是一组手写数字的小图像。请看下图,其中有一些例子。

MNIST 数据集
共有70000 张图像,每张图像有 784 个特征。这是因为每幅图像都是 28 x 28 像素,每个特征代表一个像素的强度,从 0 到 255。
有许多分类算法(SGD,SVM,RandomForest 等)可以在这个数据集上训练,包括深度学习算法(CNN)。
培训和评估
我们以 RandomForest 分类器为例,在上面的数据集上对其进行训练,并进行评估。
在测试集上评估或建模后,我们得到的准确度分数是 0.9705
我们能提高准确性吗?
我们可以通过调整算法的超参数或者尝试不同的算法来改进。但是我们能对数据集做些什么吗?
是的,我们可以!(是的,我们也会打败新冠肺炎)
有时算法需要更多的数据集来提高预测功能,我们可以使用相同的数据集本身来扩展数据集。
如何扩展数据集?
正如我们之前所讨论的,数据集的每个实例只不过是( 784 )个像素值的向量。(这实际上是一个代表 28x28 图像)
如果我们把图像向两边移动两个像素会怎么样?请看下面的例子。

增强图像
这些图像会聚在一起,对吗?如果我们生成这样的图像,并将其添加到我们的训练集中,然后再次训练模型,会怎么样呢?我们可能会得到更准确的预测。
履行
我们可以编写一个方法,按照给定的顺序在四个方向上移动图像。
我们将把图像向四个方向移动一个像素,并从一幅图像中再生成四幅图像。结果数据集现在将包含 3,00,000 张 图像( 60000 x 5 )。
我们可以为每一次移位增加 60,000 个实例。
让我们在这个新数据集上训练模型并进行评估。
瞧啊。!!精度得分现在是 0.9803 。
我们将精度提高了 ~0.01% 。这太棒了。
结论
- 我们已经从现有的数据集扩展了我们的数据集,使用“数据扩充”技术,通过简单地改变像素顺序。
- 在这个更大的数据集上进行训练,我们的准确率提高了 0.01%
请在下面的 GitHub 位置找到完整的代码
机器学习的注释和代码:https://akashp1712.github.io/ml-akash-阿卡什 1712/ml-阿卡什
github.com](https://github.com/akashp1712/ml-akash/tree/master/Articles/data-augmentation)
更多想法?
- 你能增加更多的数据集吗?(提示:对角移动图像)
- 尝试其他算法,而不是随机森林,比如 KNeighborsClassifier 或 SVM
当你纠结于一个问题的时候,就是你理解它的时候——埃隆·马斯克
通过改变图像的难度来提高分类器性能
我们提出了一个难度转换模型,该模型修改了结肠直肠组织病理学图像,使分类变得更具挑战性,发现用生成的图像作为增强数据训练的图像分类器表现更好。
概述。在这项研究中,我与一组研究人员合作,为组织病理学图像创建了一个难度翻译模型。换句话说,给定一些癌症的图像,我们将其修改成一个更难分类的图像。这是基于这样的动机,即这些图像具有一系列决定它们将如何被分类的特征,这不同于像 ImageNet 这样的一般计算机视觉数据集(例如,没有猫和狗的范围)。
如果你想更详细地了解我们的工作,可以在这里找到全文。

病理学家对生成的图像的认同度较低。左边的一组图片显示的是更难分类的翻译图片。右边的一组图像显示了图像翻译,并没有变得更难分类。
数据集。数据集由来自达特茅斯-希区柯克医疗中心的结肠直肠癌图像组成,它已被分为 2,051 个图像的训练集和 1,101 个图像的测试集。这些图像中的每一个都被标记为过度增生性息肉(HP)或无柄锯齿状腺瘤(SSA)。
模型。我们的模块由一个评分器和一个循环一致的生成对抗网络(CycleGAN)图像翻译器组成,前者预测给定图像的难度,后者将容易分类的图像翻译成较难分类的图像。通过这种配置,该模块能够将给定的图像翻译成类似的示例,该示例将被分类为具有相同的标签,但是将更加难以分类。
生成更难的训练数据。在本模块中,我们将 image translator 的源域设置为简单惠普映像,并将目标域设置为硬惠普映像。通过这样做,图像翻译器学会了将简单的 HP 图像转换成硬的 HP 图像。
为了评估翻译图像的难度,我们与三位病理学家一起进行了图灵测试。每个病理学家被给予 75 个随机采样的真实简易 HP 图像、75 个随机采样的真实硬 HP 图像、75 个从选择的简易 HP 图像翻译的生成的 HP 图像和 75 个 SSA 图像。病理学家被要求将每个图像分类为 HP 或 SSA。我们发现病理学家在生成的图像上比他们真正的对手有更多的分歧,这意味着生成的图像确实更难分类。完整的结果可以在下面看到。

与真实图像相比,病理学家对生成的 HP 图像的真实标签认同较少。大多数生成的图像保留了它们的 HP 标签,因为源图像和它们相应的生成图像都被大多数病理学家分类为 HP。
提高分类器的性能。生成的图像也可以作为附加数据,更好地训练深度学习分类器。为了测试这一点,我们首先将生成的 HP 图像添加回原始训练数据集中。然后,我们在这个新的训练数据集上训练了一个新的分类器,并将其性能与我们以前的分类器进行了比较。我们将我们的方法与一种更简单的数据增强方法进行了比较,在该方法中,简单图像和困难图像被拼接在一起,发现我们优于基线增强,并且使用生成的图像作为增强数据始终提高了性能。完整的结果可以在下面看到。

图像分类器的性能(% AUC)使用生成的图像作为具有高注释者一致性(即,容易图像)、低注释者一致性(即,困难图像)和所有测试集图像的增强数据进行训练。
总结。在我们的研究中,我们证明了改变图像的难度并使用困难的例子作为附加数据是一种改善深度学习分类器性能的有前途的方法。在我们的数据集上,我们的方法能够将性能提高大约 2%,这是一个显著的改进。我们希望这些结果鼓励其他人探索在其他环境中使用改变图像难度,如课程学习或对抗性攻击。
如果你想阅读我们的全文,可以在这里找到。
我们如何使用类平衡方法改进用于文本一致性建模的卷积神经网络
最近,深度学习由于在处理非常复杂的问题时在准确性方面的优势而越来越受欢迎。它在 NLP 中被证明是有效的,并被许多问题广泛采用,为更有意义和更准确的建模方法打开了新的大门。
虽然自然语言处理中的许多问题涉及文本合成,如文本生成和多文档摘要,但文本质量度量成为一个核心需求,并且对它们进行建模是一个活跃的问题。在这些措施中,语篇连贯是关键,需要特别处理。
语篇连贯(Text coherence)是指语篇逻辑一致性的程度,这个问题可以追溯到 20 世纪 80 年代,当时提出了几个模型。但是由于连贯性的概念过于抽象,因此制定一个衡量标准相当困难。我们讨论了使用最先进的方法对文本连贯性建模,以及我们为获得更准确的结果而对其进行的改进。图 1 显示了两段文本:文本 1 是连贯的,其中句子是逻辑有序的,而文本 2 具有不连贯的句子顺序。

图一。连贯和不连贯的文本样本
相干建模
统计方法
在深度学习兴起之前,有人建议用统计方法来模拟连贯性的意义;隐马尔可夫模型(HMM)被建议通过将文本视为主题序列来捕获全局连贯,连贯通过主题转移来捕获,其他方法使用词汇和句法特征。这些方法显示了良好但不是最好的结果。后来,提出了一种更有前途的基于深度学习的方法,使用递归神经网络(RNNs)⁵.然而,这种方法很少注意句子之间的语义关系。由于消失梯度问题,它也受到了 RNNs 处理长句的限制。
CNN 模型
2017 年,Yingming Li 等人提出了一种基于深度学习的文本连贯性分析,该分析利用卷积神经网络(CNN)的能力,将输入句子映射到专注于低级特征的高级表示中,并利用这些特征来捕捉更准确的句子语义交互,从而克服了以前模型的局限性。该模式建议同时学习句子分布表征和连贯;通过映射句子和学习句子级别的交互,如相似性,可以实现对文本连贯性的有意义的评分。然后在句子排序任务上对该模型进行评估。
了解模型
该模型将文档分成被称为 n 个句子的集团的段落。原始文档的派系是一致的;标记为 1。然后,它生成文档的 20 个排列,其中形成排列文档的集团被认为是不一致的;标记为 0。因此,文档的一致性分数是其所有派系的产物。
一个 3 人集团模型应该是这样的:

图二。文本连贯性测量的 CNN 模型
卷积层将句子映射到高级表示中,在该表示中捕获细粒度特征,然后根据图 3 中的等式计算相似性,在图 3 中还学习了相似性矩阵。
相似性方程使用训练的相似性矩阵 M1 来测量团体的第一个句子 Xf 和第二个句子 Xs 之间的相似性。同样的等式适用于第二句和第三句;Xs 和 Xt。第一句和第三句的相似度既然是传递关系,那就从前两个分数推断出来,不需要计算。
最后,致密层负责决定句子是否连贯。

图 3。相似方程
该模型的结果得到了认可,并且优于其他方法。正如该报所报道的:在由美国国家运输安全委员会官员撰写的航空事故报告集上测试该模型的结果是 95.0% 的准确率。
模型实现和分析
我和我的团队在“单文档摘要和评估”中实现了这篇论文,作为我们毕业论文的一部分,其中我们给生成的摘要一个一致性分数(代码可在 GitHub 这里获得),据我们搜索,这是这篇论文唯一可用的开源实现(有另一个资源库的作者宣布它是一个不正确的实现)。
我们首先按照论文的建议,使用相同的事故数据集训练模型。我们使用分层 k 折叠交叉验证进行 10 个折叠的模型训练,结果与论文报道的几乎相同;平均模型准确率为 95.38%
然后,我们开始解决模型的弱点。主要地,为训练数据中的每个文档创建 20 个排列,然后将其分成单独的集团的建议产生了不平衡的数据集。如 Buda 等人(⁴)所讨论的,具有类别不平衡数据会导致模型表现显著不佳。这可以通过调查下图 4 中测试数据的建议模型的 ROC 曲线来显示,其中模型的 AUC 为 0.77

图 4。基于测试数据的不平衡基本模型 ROC 曲线
尽管由于 CNN 使用共享参数并且该架构所建议的密集层较浅,所以该模型不会遭受过拟合,但是所建议的模型允许进一步改进。
改进模型
为了解决阶级不平衡的问题,我们采用了两种方法来比较它们是如何工作的:获取更多的数据,并试图克服阶级不平衡的问题。
1.访问更大的数据集:
首先,我们试图获得更多的数据。由于模型没有对文档进行限制,我们可以使用由数百万篇文章组成的 CNN/Daily Mail 数据集来增加数据集的大小。这种方法仅将精度提高到了 ~98% ,并允许架构有更深的密集层。但是 ROC 曲线几乎保持不变。
2.使用过采样平衡等级:
改进模型的第二种方法是使用布达和 al.⁴建议的过采样,通过随机重复数据中的少数类观察值来平衡类,直到它们几乎平衡。这种技术非常有效,并允许更深层次的网络架构,导致分层 10 倍验证准确性的平均 ~99% 和测试数据的 98.3% 准确性。
如图 5 所示,不仅提高了模型准确性,而且测试 ROC 曲线也接近最优,AUC 等于 0.993 。

图 5。基于测试数据的平衡基础模型 ROC 曲线
参考
[1] Pascale Fung 和 Grace Ngai。2006.一个故事,一个流程:用于多语言多文档摘要的隐马尔可夫故事模型。TSLP 3,2 (2006),1–16。
[2]安妮·路易斯和阿尼·年科娃。2012.基于句法模式的连贯模型。在 EMNLP-CoNLL。1157–1168.
[3]崔,b,李,y,张,y,张,z:基于深度神经网络的语篇连贯分析。载于:CIKM 2017,第 2027–2030 页。美国计算机学会(2017 年)
[4] Mateusz Buda、Atsuto Maki 和 Maciej A Mazurowski。卷积神经网络中类不平衡问题的系统研究。神经网络,2018。
[5]李继伟和爱德华·h·霍维。2014.基于分布式句子表示的连贯模型。在 EMNLP。2039–2048.
改进深度神经网络
吴恩达在深度学习专业课程中对超参数调整和正则化的建议。

帕维尔·卡迪什
我最近一直在学习 Coursera 的深度学习专业课程,该课程由吴恩达设计和教授。第二个子课程是改进深度神经网络:超参数调整、正则化和优化。在我开始这个子课程之前,我已经在我以前的项目中完成了传统机器学习算法的所有步骤。我调优了决策树的超参数,比如 max_depth 和 min_samples_leaf,还调优了 SVM 的 C、kernel 和 gamma。为了正则化,我将 Ridge (L2 惩罚)、Lasso (L1 惩罚)和 ElasticNet (L1 和 L2)应用于回归模型。所以我想这不会比把这些概念翻译到神经网络上多多少。好吧,我在某种程度上是对的,但是考虑到吴恩达是如何解释数学和直观地展示这些优化方法的内部运作的,我从基础层面上有了更好的理解。
在这篇文章中,我想回顾一下 Andrew 对这些技术的一些解释,并附有一些数学和图表。
超参数调谐
以下是一些针对深度网络调整的流行超参数:
- α(阿尔法):学习率
- β(β):动量
- 层数
- 隐藏单元的数量
- 学习率衰减
- 小批量
还有其他特定于优化技术的,例如,对于 Adam 优化,有β1、β2 和ε。
网格搜索 vs 随机搜索
假设对于一个模型,我们有一个以上的超参数正在调整,一个超参数可能会比另一个超参数对训练/验证精度有更大的影响。在这种情况下,我们可能希望为更有影响力的超参数尝试更广泛的值,但同时,我们也不想运行太多模型,因为这很耗时。
对于这个例子,假设我们正在优化两个不同的超参数,α和ε。我们知道α更重要,需要通过尝试尽可能多的不同值来调整。然后你仍然想尝试 5 个不同的ε值。所以,如果我选择尝试 5 个不同的α值,那么就有 25 个不同的模型。我们已经用 5 α和 5 ε的不同组合运行了 25 个模型。
但是我们想在不增加模型数量的情况下尝试更多的α值。以下是安德鲁的解决方案:
为此,我们使用随机搜索,其中我们为每个α和ε选择 25 个不同的随机值,每对值用于每个模型。现在我们只需要运行 25 个模型,但是我们可以尝试 25 个不同的α值,而不是网格搜索中的 5 个。

左:网格搜索,右:随机搜索
额外收获:使用由粗到细的方法有助于进一步提高调音效果。这包括放大表现最佳的超参数的较小区域,然后在该区域内创建更多模型,以更精确地调整这些超参数。
选择音阶
当尝试不同的超参数值时,选择正确的比例可能会很困难,尤其是要确保在一个非常大的数字范围和一个非常小的数字范围内进行彻底的搜索。
学习率是一个超参数,可以根据模型的不同而有很大的变化,它可以在 0.000001 和 0.000002 之间,或者在 0.8 和 0.9 之间。当查看线性标尺时,很难同时在这两个不同的范围之间进行公平的搜索,但是我们可以使用对数标尺来解决这个问题。
假设α的值在 0.0001 到 1 之间。使用线性标度意味着 10%的尝试α值在 0.0001 和 0.1 之间,90%在 0.1 和 1 之间。这很糟糕,因为我们没有对如此广泛的值进行彻底的搜索。通过使用 10 标度的对数,25%的α值在 0.0001 和 0.001 之间,25%在 0.001 和 0.01 之间,25%在 0.01 和 0.1 之间,最后 25%在 0.1 和 1 之间。这样我们对α进行了彻底的搜索。0.0001 到 0.1 的范围对于线性标度是 10%,而对于对数标度是 75%。

左:线性标度,右:对数标度
这里有一点数学知识,用一个 numpy 函数来演示它如何对α的随机值起作用。

规范化
由于高方差,过度拟合可能是模型的一个巨大问题,这可以通过获得更多的训练数据来解决,但这并不总是可能的,所以一个很好的替代方法是正则化。
L2 正规化(‘重量衰减’)
正则化利用 L1 和 L2 两种惩罚技术中的一种,主要使用神经网络 L2。
我们必须首先看一下神经网络的成本函数:

价值函数
然后加上 L2 罚项,其中包含了弗罗贝纽斯范数:

L2 刑罚术语,包括弗罗贝纽斯规范
通过 L2 正则化,权重不仅通过学习速率和反向传播降低,而且通过包括正则化超参数λ (lambda)的中间项降低。λ越大,w 越小。

重量衰减
规范化如何防止过度拟合?
我们看到 L2 正则化使用λ惩罚来减少权重 w,但是这如何减少方差并防止模型的过度拟合呢?

λ上升,w 下降,改变 z 的幅度
如果 w 很小,z 的大小也会下降,如果 z 是一个大的正数,它会变小,如果是一个大的负数,它会变大,接近 0。当通过激活函数传递 z 时,我们有一个更线性的效果(如下图所示,tanh 曲线在 0 附近更线性)。

双曲正切激活函数的图形,显示了 z 值的减小如何使函数更加线性
这里 g(z)对于 tanh 激活函数大致是线性的。“最佳拟合线”的决策边界将更简单,更接近线性,这将消除训练数据中的过度拟合。
这是吴恩达深度学习专业化课程的一小部分,我觉得非常有用,并想写下来,但课程提供了更多。如果你对学习深度神经网络感兴趣,并希望从基础水平理解所有事情,对所有过程进行彻底的数学论证,并进行编码练习,我强烈建议你完成本课程。
用合成数据改进机器学习中的大规模不平衡数据集
我们将使用合成数据和 SMOTE 中的一些概念来提高欺诈、网络安全或任何极少数类别分类的模型准确性
在机器学习中处理不平衡的数据集是一项艰巨的挑战,可能包括支付欺诈、诊断癌症或疾病,甚至网络安全攻击等主题。所有这些交易的共同点是,在所有交易中,只有很小一部分是真正的欺诈,而这些交易才是我们真正关心的。在本帖中,我们将通过训练一个生成合成数据模型来创建额外的欺诈记录,从而提高流行的 Kaggle 欺诈数据集的准确性。独特的是,该模型将结合来自欺诈性记录及其最近邻居的特征,这些特征被标记为非欺诈性的,但与欺诈性记录足够接近,以至于有点“可疑”。

特征图像 Gretel.ai
我们不平衡的数据集
在这篇文章中,我们选择了 Kaggle 上流行的“信用卡欺诈检测”数据集。该数据集包含 2013 年 9 月欧洲信用卡持有者的标记交易。为了保护用户身份,数据集将敏感特征降维为 27 个浮点列(V1–27)和一个时间列(数据集中此事务和第一个事务之间经过的秒数)。在这篇文章中,我们将使用信用卡欺诈数据集中的前 10k 条记录——点击下面的链接,在 Google 联合实验室中生成下面的图表。
colab.research.google.com](https://colab.research.google.com/github/gretelai/gretel-synthetics/blob/master/examples/research/synthetics_knn_classify_and_visualize.ipynb) 
一个极度不平衡的数据集
度量陷阱
让我们看看使用最先进的 ML 分类器检测欺诈记录可以获得什么样的性能。我们首先将数据集分为训练集和测试集。

对我们的默认欺诈数据集进行分类的结果
哇,99.75%的检出率。太棒了,对吧?!也许——查看整体模型准确性只是显示模型在整个集合中的表现有多好,而不是我们在检测欺诈记录方面做得有多好。要了解我们的实际表现,请打印一份混淆矩阵和准确性报告。

从上面我们可以看到,尽管我们的总体准确率为 99.75%,但在我们的测试集中,我们对 43%的欺诈示例进行了错误分类!
用合成数据增加欺诈案例
在本节中,我们将重点关注如何通过使用 gretel-synthetics 生成欺诈记录的更多示例,来提高欺诈记录的模型性能和泛化能力。让我们从我们想要完成的事情开始——我们的目标是生成额外的欺诈记录样本,这将帮助我们的分类器进行归纳,并更好地检测我们测试集中的欺诈记录。
合成少数过采样技术
数据科学社区中实现这一点的一种流行技术被称为 SMOTE(Syn intesticMinorityOversamplingTetechnique),由 Nitesh Chawla 等人在他们 2002 年的论文中描述。SMOTE 的工作方式是从少数类中选择样本,在少数类中找到它们最近的邻居,并在它们之间有效地插入新点。SMOTE 不能合并来自少数类之外的记录的数据,在我们的示例中,这些记录可能包含有用的信息——包括欺诈性的或贴错标签的记录。
Gretel 合成了 SMOTE 的概念
我们的训练集中只有 31 个欺诈数据的例子,这给泛化带来了独特的挑战,因为 gretel-synthetics 利用深度学习技术来学习和生成新的样本,这在传统上需要大量数据才能收敛。打开下面的笔记本,使用 Google Colab 免费生成您自己的合成欺诈数据集。
colab.research.google.com](https://colab.research.google.com/github/gretelai/gretel-synthetics/blob/master/examples/research/synthetics_knn_generate.ipynb)
通过借用 SMOTE 找到欺诈集的最近邻居的方法,并结合来自多数类的几个最近邻居,我们有机会扩展我们的训练集示例,并结合从我们的欺诈类(姑且称之为可疑)记录中获得的一些知识。这种方法不需要对 Gretel Synthetics 做任何更改,我们只是智能地从欺诈+最近正邻居(shady)记录中挑选数据集。我们开始吧!
为了构建我们的合成模型,将使用 Gretel 的新数据框架训练模式默认值和以下几个参数集来优化结果:
epochs: 7。将 epochs 设置为尽可能低的设置,以平衡创建有效记录,而不会过度适应我们有限的训练集。dp: False。在这种情况下,不需要考虑运行差分隐私对准确性的影响。gen_lines: 1000。我们将生成 1000 条记录,以增强我们现有的 31 个正面示例。注意,并不是所有从我们的模型生成的记录都是正面的,因为我们合并了一些负面的例子——但是我们至少应该有几百个新的正面例子。batch_size=32。将所有 30 行放入单个神经网络模型中,以保留所有字段-字段相关性,代价是更多记录未通过验证。- 训练模型,生成行,并且只保留由合成数据模型创建的“欺诈性”记录
检查我们的合成数据集
现在,让我们来看看我们的合成数据,看看我们是否可以直观地确认我们的合成记录是他们接受培训的欺诈记录的代表。我们的数据集有 30 个维度,因此我们将使用数据科学中的一种称为主成分分析(PCA)的降维技术来以 2D 和 3D 方式可视化数据。
下面我们可以看到我们的训练、合成和测试数据集被压缩成二维。从视觉上看,除了 31 个原始训练示例之外,883 个新的欺诈性合成记录可能对分类器非常有帮助。我们添加了 7 个测试集正面例子(其中我们的默认模型误分类了 3/7,我们希望增强的合成数据将有助于提高检测。

从我们的图表中可以看出,我们合成生成的欺诈示例可能真的很有用!注意在训练负集附近出现的假阳性例子。如果你看到很多这样的例子,试着将NEAREST_NEIGHBOR_COUNT从 5 减少到 3 以获得更好的结果。让我们把同样的 PCA 可视化 3 维。

查看上面的数据集,似乎用合成数据增强我们的少数欺诈记录集可能对模型性能有很大帮助。我们试试吧!
用合成数据增强我们的训练数据集
现在,我们重新加载训练和测试数据集,但这一次用新生成的合成记录增加了现有的训练数据。

增加 852 个合成例子,使我们的负/正比从 257 降低到 9 倍!
在扩充数据集上训练 XGBoost,针对测试数据集运行模型,并检查混淆矩阵。

借助额外的欺诈示例检测,欺诈检测率提高了 14%!
正如我们所见,训练机器学习模型来准确检测极端少数类是一个严峻的挑战。但是,合成数据创造了一种提高准确性的方法,并有可能提高模型归纳到新数据集的能力,并且可以独特地将整个数据集的特征和相关性合并到合成欺诈示例中。
接下来,试着用你自己的数据运行上面的笔记本。想了解更多关于合成数据的信息吗?点击这里的和这里的查看关于数据科学的文章。
结束语
在 Gretel.ai ,我们对使用合成数据来增强训练集以创建 ML 和 ai 模型的可能性感到非常兴奋,这些模型可以更好地概括未知数据,并减少算法偏差。我们很乐意听到您的使用案例——欢迎在评论、 twitter 或 hi@gretel.ai 中联系我们进行更深入的讨论。关注我们,用合成数据跟上最新趋势!
有兴趣在自己的数据集上进行训练吗? Gretel-synthetics 是免费开源的,你可以通过联合实验室在几秒钟内开始实验。如果你喜欢 gretel-synthetics,请在 GitHub 上给我们一个⭐!
磨练熊猫的知识
三个有用的熊猫方法

Pandas 是 python 中的一个库,通常用于统计分析、数据聚合等等。在这篇文章中,我将讨论熊猫中非常有用的三种方法。我将讨论“read_clipboard()”方法、“query()”方法和“apply()”方法。
我们开始吧!
读取剪贴板的方法
“read_clipboard()”方法提供了一种在数据框中存储复制到剪贴板的文本的简单方法。首先,去雅虎财经搜索道琼斯工业平均指数。接下来,单击历史数据并突出显示前几行,如下所示:

并按“CTRL + c”。最后,我们可以通过执行以下命令将复制的文本存储在数据框中:
import pandas as pd
df = pd.read_clipboard()
print(df.head())

让我们将此数据帧写入“csv ”,因为我们将在后续示例中继续使用此数据。
df.to_csv("dow_jones.csv")
接下来,让我们继续讨论“query()”方法。
查询方法
“query()”方法提供了一种使用字符串表达式选择数据的简单方法。让我们使用上面的相同数据来演示这种方法的使用。
让我们将 csv 文件读入数据帧:
df = pd.read_csv("dow_jones.csv")
让我们将日期列转换成日期时间对象:
df['Date'] = pd.to_datetime(df['Date'])
接下来,让我们创建月和周列:
df['Month'] = df['Date'].dt.month
df['Week'] = df['Date'].dt.week
让我们也放宽对行和列的显示限制:
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)print(df.head())

最后,让我们使用“query()”方法来选择基于周的数据:
df = df.query('Week < 10')
print(df.head())

我们也可以按月份过滤:
df = df.query('Month == 3')
print(df.head())

就此而言,我们也可以基于任何其他列进行筛选。
现在让我们继续讨论“apply()”方法。
该应用方法
我们将讨论的下一个方法是“apply()”方法。假设我们想取“开放”列的平方。要使用“apply()演示这一点,让我们首先从“Open”列中的字符串值中删除逗号,并将字符串值转换为浮点型:
df['Open'] = df['Open'].str.replace(',', '')
df['Open'] = df['Open'].astype(float)
然后,我们可以使用“apply()”方法对列中的值求平方:
df['Open^2'] = df['Open'].apply(lambda x:x**2)
print(df.head())

一个更实际的用例是使用带有自定义函数的 apply 方法。假设我们想从“Open”和“Close”值计算回报。让我们从“Close”列的字符串值中删除逗号,并将字符串值转换为浮点数:
df['Close*'] = df['Close*'].str.replace(',', '')
df['Close*'] = df['Close*'].astype(float)
接下来,让我们定义一个用于计算回报的函数:
def calculate_returns(df_in):
returns = (df_in[1] — df_in[0])/(df_in[0])*100
return returns
回报的公式是:
(df['Close*'] — df['Open'])/(df['Open'])*100
现在,让我们使用“apply()”方法和我们的自定义函数来计算将存储在新列中的回报:
df['returns'] = df[['Open', 'Close*']].apply(calculate_returns, axis = 1)
让我们打印前五行:
print(df.head())

结论
总之,在这篇文章中,我们讨论了熊猫的三种方法。我们讨论了“read_clipboard()”方法,该方法允许我们将复制到剪贴板的文本读入数据框。我们还讨论了“query()”方法,它允许我们用字符串表达式选择和过滤数据。最后,我们讨论了“apply()”方法,该方法允许我们用相对简单的代码转换和创建新列。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
改进 Plotly 的极坐标条形图
超越默认设置,创建漂亮且可复制的图表

如果您想将更多的注意力吸引到具有更高值的类别上,极坐标条形图是显示分类信息的好方法。它们在《华尔街日报》关于亚马逊 HQ2 候选名单的文章中发挥了巨大作用。但是,即使有了强大的可视化工具,制作这样的图表也需要一些跑腿的工作。
今天我在这里向你们提供将 Plotly 的极坐标条形图转化为视觉上可接受的东西所需的几何图形。到最后,你可以把这些烦人的内务代码扔进一个函数里,再也不去想它了。

这是 Plotly 的教程代码产生的情节。
虽然我知道他们在演示如何用更少的代码行创建 Matplotlib 徽标,但是这个例子对于实际应用程序并没有什么用处。
下面,我将以一种可重现的方式解决我在这个例子中遇到的主要问题。这些问题是:
- 图和背景的切片在数量上是不同的,并且没有对齐。
- 图切片之间的间隙不一致。
- 从例子看不清楚怎么做传奇。
像往常一样,您可以跳到最后查看完整的代码片段。
切片对齐又称角度窗格条
让我们从框定我们的问题开始。我们有一组值,我们希望将每个值映射到一个圆形切片的半径。也许我们也有每个值的标签。
vals = [3, 2, 5, 1, 2]
labels = ["Strength", "Intelligence", "Dexterity", "Wisdom", "Stealth"]
仅从这些值,我们想要确定切片和背景的定位和对齐。
每个切片的半径、位置和宽度分别由 Plotly barpolar 函数的r、theta和width参数决定。注意theta对应每个切片的中心的角度。
如果我们希望切片之间没有间隔,并且宽度相等,我们可以从原始值的长度推断出这些参数。
num_slices = len(vals)
theta = [(i + 1.5) * 360 / num_slices for i in range(num_slices)]
width = [360 / num_slices for _ in range(num_slices)]
这里“+ 1.5”将确保我们的第一个切片的右边缘在零度。
我喜欢做的另一件事是通过调色板(如粉彩)为我的切片产生一个颜色序列:
color_seq = px.colors.qualitative.Pastel
color_indices = range(0, len(color_seq), len(color_seq) // num_slices)
colors = [color_seq[i] for i in color_indices]
让我们来看看我们的进展:
fig = go.Figure(go.Barpolar(r=vals, theta=theta, width=width, marker_color=colors))
fig.show()

越来越好了!如您所见,切片从零度开始,间隔均匀。但是背景还是完全不对齐。
角窗格条第 2 部分:背景对齐
对齐背景就是调整图形的polar_angularaxis_tickvals布局选项。我们将推断角度的顺序,类似于我们对切片所做的那样。
angular_tickvals = [(i + 1) * 360 / num_slices for i in range(num_slices)]
fig.update_layout(polar_angularaxis_tickvals=angular_tickvals)fig.show()

很好,现在背景和切片对齐了。你可以用update_layout调整更多的选项,让剧情更有美感。最后我会给你们留下一些。
痕迹和传说带来的麻烦
现在,如何添加将标签与每个切片相关联的图例?如果你只是使用name参数,你会遇到一个问题:Plotly 将我们所有的切片视为一个单独的轨迹,它只能与一个单独的名字相关联。
我们如何将每个单独的切片与其自己的名称关联起来?
这并不理想,但目前我发现为每个切片制作一个单独的条形图是最好的方法。我希望存在一种更好的方法,或者至少一种方法将很快被开发出来。
barpolar_plots = [go.Barpolar(r=[r], theta=[t], width=[w], name=n, marker_color=[c])
for r, t, w, n, c in zip(vals, theta, width, labels, colors)]fig = go.Figure(barpolar_plots)angular_tickvals = [(i + 1) * 360 / num_slices for i in range(num_slices)]
fig.update_layout(polar_angularaxis_tickvals=angular_tickvals)fig.show()

将所有东西打包在一起
因为我们只是从原始值中推断出所有的角度参数,所以将所有的工作打包到一个函数中是有意义的。我已经用一些额外的布局选项演示了它的用法。您可以在 Plotly 图参考中找到更多信息。

目前,从 Plotly 的教程极坐标条形图到一些可用的东西需要一点工作。特别是,需要一些角度格来对齐切片和背景。此外,添加图例并没有想象中那么简单。
在这里,我已经完成了进行这种调整所需的步骤,并将它们打包到一个可重用的函数中。希望对你有帮助。
用数据科学改善 SaaS
我们的实习团队如何利用数据帮助一家 SaaS 公司改善其客户拓展和维系战略

作为一名加州大学戴维斯分校 MSBA 分校的学生,我是实习团队的一员,为一家 SaaS 公司从事数据科学项目。这个为期 10 个月的项目致力于帮助他们的销售团队改进客户拓展和保留策略。在我开始深入细节之前,先来看看我将在这个博客上涵盖的内容:
- 什么?那么,SaaS 到底是什么?
- 为什么 —为什么订阅很重要?
- 谁—SaaS 公司和我们加州大学戴维斯分校 MSBA 团队
- 如何 —我们利用他们的数据改善业务的计划
什么是 SaaS?

SaaS 代表软件即服务。这意味着供应商通过互联网向客户提供基于云的服务(即托管/维护组成应用程序的服务器、数据库和代码)。软件咨询,一家 Gartner 公司,软件服务的领导者之一,解释说SaaS 的最大优势之一是它允许客户消费软件而不必担心硬件和基础设施成本。它在数据方面也更加安全,并且允许定制。
使用 SaaS 的另一个重要优势是定价模型。选择 SaaS 的客户通常会支付满足他们所有需求的年费或月费,而不是购买软件许可证、维护和支持费用。
为什么订阅很重要?
客户按月或按年向 SaaS 供应商付款。对于这样的 SaaS 公司来说,获得客户是昂贵的,所以他们必须投资于他们的客户,并等待一段时间才能从最初的成本中收回任何利润。连续创业者和《福布斯 2 号最佳创业者网站》的作者 David Skok,用一个简单的客户现金流的例子说明了这个概念。想象一下,你花了 6000 美元获得了一个每月支付你 500 美元的新客户。您需要两年时间才能从该客户身上看到任何利润:

SaaS 企业最终从他们在获取新客户的初始投资中看到利润
正如我们从上面的图表中所看到的,初始投资在一段时间后显示出积极的结果。换句话说,企业在某个时间点后开始创造正现金流。人越多越好!如果一个客户获得成功,那么获得更多的客户并提高获得率将导致更深的正现金流曲线:

更深的曲线意味着更高的短期支出,但也会导致更高的长期收益
我们已经看到,获得客户是昂贵的,但最终这种投资是值得的。也就是说,在 SaaS 业务中,收入是在很长一段时间内产生的,也就是客户的一生:
“如果客户对服务满意,他们就会长期,从该客户身上获得的利润就会大大增加。另一方面,如果客户对不满意,他们会很快流失,企业很可能会在获得该客户的投资上赔钱。”—大卫·斯科克****
这都与订阅相关,因为:
- 获得客户是昂贵的
- 让他们开心,让他们的人生价值最大化,将有助于公司收入最大化
我们今天不会关注客户获取部分,而是在 让客户开心 。
谁参与了这个项目?
你已经知道我们是加州大学戴维斯分校 MSBA 实习团队,与 SaaS 的一家公司合作,但是我们与他们公司的谁合作呢?
既然我们关心创造更多的收入,我们与他们的销售&运营团队合作也就不足为奇了。然而,我们也关心如何让客户满意,幸运的是,这家公司有一整个团队致力于这一目标,即客户成功团队。他们在提供大量有趣的数据方面非常有帮助,这些数据结合了客户使用数据(来自公司的平台)以及客户关系管理(CRM)信息。
我们将如何利用他们的数据创造商业价值?
好了,现在进入有趣的部分!
我们的实习项目旨在发现客户的关键特征,这些特征表明客户是否准备增加与 SaaS 公司的业务,或者客户是否即将流失。我们将执行客户细分分析和客户流失分析来确定 SaaS 公司扩大收入的方法。这些模型将帮助该公司从传统的基于直觉的决策过渡到基于数据的决策,并重新定义客户健康指标,从而在未来几年改善他们的客户战略。
客户细分分析

我们细分分析的目标是扩大现有客户的业务。为了做到这一点,我们将看看:
- ****客户关系管理(CRM)数据:他们成为客户多久了,他们在公司消费了多少,等等。
- ****客户使用数据:他们使用产品的频率如何,他们使用最多的是什么样的产品功能,他们的问题(如果有的话)得到解决的速度有多快,等等。
这个想法是要看看不同类型的客户(大鱼,休闲客户,非常活跃的客户等)的典型行为是什么。)为了根据这些指标对客户进行分类,我们计划执行 K 均值聚类。这是一种无监督的学习算法,我们将试图在观察值中找到同质的子群。机器学习专家和 StatQuest 创始人 Josh Starmer ( 他也是一位相当不错的歌手!)在这段视频中非常好地解释了 K-means 聚类。
我们还将利用至关重要的 SaaS 指标,如下所示,这些指标在由 B2B 软件领导者 Joel York 创建的这份有用的备忘单中有详细说明:
- ****经常性收入:由于客户是基于订阅的,他们的经常性收入是他们在一段固定时间内支付的费用,通常按月(MRR)、按季度(QRR)或按年(ARR)计算。
- ****客户获取成本(每个客户):我们之前讨论过这个问题。这是(在营销和销售活动中)激励某人成为实际付费客户的成本。
- ****客户终身价值:客户一生能为公司带来多少价值。这通常是一个固定的时间量,不幸的是,它用一条曲线来表示,最终总是随着时间的推移而减少。不过,这是意料之中的。举例来说,谁会在一生中真正成为 Prime 会员?
- 流失率(或损耗)**:客户在特定时间段内取消订阅的概率。该指标也将用于流失分析。
- ****留存率:客户在同一时期停留的概率。因此,它是 1-流失率。
通过使用这些指标以及来自约克的小抄的更多信息,我们希望这些数据能告诉我们 T21 一个故事。
流失分析

流失分析似乎很有前景,我们非常兴奋能够开始这部分的分析!关于这个话题已经做了很多研究,所以有很多资料。一个很酷的例子是 Zuora 的首席数据科学家 Carl Gold 关于用数据对抗流失的博客。我们了解到的一个令人放心的概念是,防止客户流失的方法之一是建立客户成功团队。戈尔德解释说,“客户成功和支持代表通过确保客户采用某个产品来防止客户流失,并在他们不能接受时给予帮助。”如果您还记得“谁参与了这个项目?”上一节,我们很幸运能与一个客户成功团队合作,该团队正引导我们更好地理解客户行为和业务洞察力。他们不只是向我们扔数据,而是在整个项目中努力与我们合作。
这些是我们准备尝试的一些方法,目的是提高客户保持率:
- 由于客户的异质性,确定动态保留率
- 实施人工神经网络来模拟流失
- 运行 XGBoost 和/或逻辑回归来预测流失
- 查看生存分析,估计客户在特定时间段内流失的可能性
有这么多的工具和方法,我们可以为这个部分,它可以是自己的博客!好消息是我们已经准备好了数据,像这个教程这样的好例子,还有很多时间(期中考试后)来应对这个挑战。
下一步是什么?
按照我们项目中的数据科学工作流程的步骤,我们已经对业务问题有了充分的了解,我们已经修改了数据并准备好进行分析,我们即将开始建模阶段。在整个过程中,我们将与销售&运营和客户成功团队一起检查,以确保我们的分析朝着正确的方向发展。
敬请关注,看看我们发现了哪些有趣的见解!
用 BERT 和表征学习改进句子嵌入
在这个实验中,我们对 BERT 模型进行了微调,以提高它对短文本进行编码的能力。这为下游 NLP 任务产生了更有用的句子嵌入。
虽然一个普通的 BERT 可以用来编码句子,但是用它生成的嵌入并不健壮。正如我们在下面看到的,被模型认为相似的样本通常在词汇上比语义上更相关。输入样本中的小扰动会导致预测相似性的大变化。

平均池 BERT-base 模型编码的句子对之间的相似性
为了改进,我们使用斯坦福自然语言推理数据集,该数据集包含手动标记有蕴涵、矛盾和中性标签的句子对。对于这些句子,我们将学习这样一种表述,即蕴涵对之间的相似性大于矛盾对之间的相似性。
为了评估学习嵌入的质量,我们在 STS 和 SICK-R 数据集上测量 Spearman 等级相关性。
这个实验的计划是:
- 准备 SNLI 和 MNLI 数据集
- 实现数据生成器
- 定义损失
- 构建模型
- 准备评估管道
- 训练模型
这本指南里有什么?
本指南包含在标记数据上构建和训练句子编码器的代码。
需要什么?
对于一个熟悉的读者来说,完成这个指南和训练句子编码器需要大约 90 分钟。代码用 tensorflow==1.15 测试。
好吧,给我看看代码。
这个实验的代码可以在这里获得。这一次,来自先前实验的大部分代码被重用。我建议先去看看。
独立版本可以在库中找到。
步骤 1:设置
我们从下载 SNLI 、 MNLI 、 STS 和 SICK 数据集以及预训练的英语 BERT 模型开始。
为 SNLI jsonl 格式定义一个 loader 函数。
为了更方便地处理数据集,我们稍微重新安排了一下。对于每个唯一的锚,我们创建一个 ID 和一个包含锚、蕴涵和矛盾样本的条目。每类缺少至少一个样本的锚被过滤掉。
单个条目如下所示
{
'anchor': ["No, don't answer."],
'contradiction': ['Please respond.'],
'entailment': ["Don't respond. ", "Don't say a word. "]
}
最后,加载 SNLI 和 MNLI 数据集。
步骤 2:数据生成器
为了训练模型,我们将对三元组进行采样,由锚、正样本和负样本组成。为了处理复杂的批处理生成逻辑,我们使用以下代码:
高层逻辑包含在 generate_batch 方法中。
- 批量锚点 id 是从所有可用 id 中随机选择的。
- 锚样本从其 id 的锚样本中检索。
- 阳性样本从其 id 的蕴涵样本中检索。
- 阴性样本是从矛盾样本中检索出它们的 id。
这些可以被认为是硬否定样本,因为它们通常在语义上与它们的锚相似。为了减少过度拟合,我们将它们与从其他随机 ID 检索的随机阴性样本混合。
第三步:损失函数
我们可以将学习句子相似性度量的问题框架化为排序问题。假设我们有一个由 kk转述的句子对 x 和 y 组成的语料库,并且想要学习一个函数来估计 y 是否是 x 的转述。对于某些 x 我们有单个阳性样本 y 和 k-1 阴性样本 y_k 。这个概率分布可以写成:

使用评分函数估计 P(x,y) 的联合概率,S:

在训练期间,对数据集中的所有 k-1 阴性样本求和是不可行的。相反,我们通过从我们的语料库中为每一批抽取 K 个响应并使用它们作为负样本来近似 P(x) 。我们得到:

我们将最小化数据的负对数概率。所以,对于一批 K 个三胞胎的损失我们可以写下:

注 :以上表达式称为 Softmax-Loss。
在本实验中,内积用作相似性函数 S 。计算最后括号中表达式的代码如下
第四步:模型
首先,我们导入之前实验中的微调代码,并构建 BERT 模块。
该模型对于锚、阳性和阴性样本有三个输入。具有平均池操作的 BERT 层被用作共享文本编码器。文本预处理由编码器层处理。对编码的句子计算 Softmax 损失。
为了方便起见,创建了 3 个模型: enc_model 用于编码句子, sim_model 用于计算句子对之间的相似度, trn_model 用于训练。所有型号都使用共享重量。
步骤 5:评估渠道
自然语言编码器通常通过嵌入标记的句子对,测量它们之间的某种相似性,然后计算相似性与人类判断的相关性来评估。
我们使用 STS 2012–2016 和 SICK 2014 数据集来评估我们的模型。对于测试集中的所有句子对,我们计算余弦相似度。我们报告了带有人工标注标签的 Pearson 等级相关性。
下面的回调处理评估过程,并在每次达到新的最佳结果时将提供的保存模型保存到保存路径。
第六步:培训
我们训练 10 个时期的模型,每个时期有 256 个批次。每批由 256 个三胞胎组成。我们在每个时期的开始执行评估。
trn_model.fit_generator(tr_gen._generator, validation_data=ts_gen._generator, steps_per_epoch=256, validation_steps=32, epochs=5, callbacks=callbacks)*** New best: STS_spearman_r = 0.5426
*** New best: STS_pearson_r = 0.5481
*** New best: SICK_spearman_r = 0.5799
*** New best: SICK_pearson_r = 0.6069
Epoch 1/10
255/256 [============================>.] - ETA: 1s - loss: 0.6858
256/256 [==============================] - 535s 2s/step - loss: 0.6844 - val_loss: 0.4366
*** New best: STS_spearman_r = 0.7186
*** New best: STS_pearson_r = 0.7367
*** New best: SICK_spearman_r = 0.7258
*** New best: SICK_pearson_r = 0.8098
Epoch 2/10
255/256 [============================>.] - ETA: 1s - loss: 0.3950
256/256 [==============================] - 524s 2s/step - loss: 0.3950 - val_loss: 0.3700
*** New best: STS_spearman_r = 0.7337
*** New best: STS_pearson_r = 0.7495
*** New best: SICK_spearman_r = 0.7444
*** New best: SICK_pearson_r = 0.8216
...
Epoch 9/10
255/256 [============================>.] - ETA: 1s - loss: 0.2481
256/256 [==============================] - 524s 2s/step - loss: 0.2481 - val_loss: 0.2631
*** New best: STS_spearman_r = 0.7536
*** New best: STS_pearson_r = 0.7638
*** New best: SICK_spearman_r = 0.7623
*** New best: SICK_pearson_r = 0.8316
Epoch 10/10
255/256 [============================>.] - ETA: 1s - loss: 0.2381
256/256 [==============================] - 525s 2s/step - loss: 0.2383 - val_loss: 0.2492
*** New best: STS_spearman_r = 0.7547
*** New best: STS_pearson_r = 0.7648
*** New best: SICK_spearman_r = 0.7628
*** New best: SICK_pearson_r = 0.8325
作为参考,我们可以查看来自 Sentence-BERT 论文的评估结果,在该论文中,作者对 STS 和 SICK 任务上的几个预训练句子嵌入系统进行了评估。
我们使用普通平均池 BERT 模型的结果与公布的指标一致,在 SICK-R.
上获得 57.99 Spearman 等级相关分数,在 10 个时期后,最佳 Colab 模型获得 76.94 ,与通用句子编码器的最佳结果 76.69 相当。

Spearman 对句子表述的余弦相似性和各种文本相似性任务的黄金标签之间的相关性进行排序。(摘自句子-伯特:使用暹罗伯特网络的句子嵌入)
由于在一个批次中的所有样本之间共享负面示例,因此使用较大的 batch_size 进行微调往往会将指标提高到某个程度。如果你的 GPU 能够处理的话,解冻更多的编码器层也会有所帮助。
一旦训练完成,我们就可以通过编码测试三元组并并排检查预测的相似性来比较基础模型和训练模型。一些例子:


结论
上面我们提出了一种使用标记句子对来改进句子嵌入的方法。
通过显式地训练该模型来根据它们的语义关系对句子对进行编码,我们能够学习更有效和更健壮的句子表示。
自动和人工评估都证明了相对于基线句子表示模型的实质性改进。
本系列中的其他指南
利用仪表板提高利益相关者的认同度
数据仪表板是向利益相关者传达分析故事的一个宝贵工具
在 Manufacturing Analytic,我们发现使用交互式仪表板共享我们的运营评估使客户成为发现过程的一部分。仪表板成为持续讨论的推动者——客户可以提问,我们可以即时提供答案。

仪表板原型将高利润和低利润产品与过程变量相关联
我们的方法从我们如何看待生产过程开始:业务不是销售产品;在线出售时间,就好像该公司出租其生产资产一样。
企业应该问的是:
我应该优先考虑我生产线上的什么产品,以提高生产线的每小时盈利能力?
我生产的每件产品的利润率或 EBITDA 率是多少,我如何将其与关键流程变量联系起来?
我们通常发现,误导的先入之见决定了公司优先考虑哪些产品。这些假设是由于将业务团队和工厂运营者分开的组织筒仓。虽然业务团队可能知道与浪费材料、在制品和转换损失相关的实际成本,但他们不关心产品线面临的问题以及这些问题如何扰乱周期时间。将来自工厂车间的知识与业务部门的知识相结合,以提供准确的分析来提高生产率和优先级,这一点至关重要。
这种筒仓效应的一个原因是,制造业中的许多人对最新数据方法的吸收一直很慢。由于缺乏数字基础设施,他们无法贯穿整个流程。一旦渗透到组织中的零散数据集被组合起来,资金模式就变得清晰了。(即带有流程或周期时间数据的产品利润)。
举一个简单的例子,按照 EBITDA 对每种产品进行排序,然后绘制一个 EBITDA/hr 的气泡图,气泡大小与体积成比例,通常会得到以下结果:高和低 EBITDA 尾部以高体积产品为标志,而净零产品的长平台以低体积产品为标志。不足为奇的是,新产品或实验性产品的产量不足以推动利润增长。然而,在某些情况下,低产量产品具有非常高的 EBITDA/hr。如果这些产品具有适当的产量,它们可能会为组织实现更高的回报。如果我们只考虑息税折旧及摊销前利润(EBITDA ),我们会失去这样的洞察力,即我们应该扩展到几个关键的、低产量的产品,因为它们的生产速度更快。

气泡代表一种独特产品的许多生产周期。泡沫从左到右按平均 EBITDA 递减的顺序排列。气泡尺寸与体积成比例,y 轴值为 EBITDA/hr。几种关键的低体积产品比高体积产品提供更高的 EBITDA/hr 比率。
在我们的一次客户分析中,我们发现了他们流程的关键组成部分和产品利润率之间的相关性。在化学组成、颜色、形状、处理和其他因素的数百种组合中,我们能够确定哪些是赢家,哪些是输家。通过将这些分组合并到一个控制面板中,我们能够即时提出问题:如果我们用这个组合替换这个组合,可能会对我们的利润产生影响,但它是否仍然符合最终客户的需求——不会吗?—嗯,这个组合怎么样?诸如此类。它简化了客户会议,使我们能够围绕他们流程中的哪些部分快速制定可行的计划,从而大幅提高他们的盈利能力。

Violin 在左侧绘制了特定产品的等级——逐行排序,即递减的平均 EBITDA。右侧的旭日图显示,对于 E28 系列,该产品的最低 EBITDA 版本与 TR 颜色组中的产品隔离。
智能分析仪表盘是讲述分析故事不可或缺的工具。当组织内的涉众试图向其他业务部门阐明计划的优先级时,他们可以很容易地返回到数据。让算法挑选出哪些过程变量是重要的是一回事。如果它随后将这种洞察力转化为能够以直观的方式深入和总结主题的指标和图表,那就是另一回事了。创建一条所有组织部门都能使用同一种语言的道路是不可或缺的。
概括地说,我们从制造业在数字化和数据科学吸收方面进展缓慢这一事实开始,但他们正开始快速加快步伐。在 MFG Analytic,我们希望我们的客户处于这一潮流的最前沿。您的数字化之旅始于分析,始于充分利用当今组织中现有的数据集。在花大价钱“感知”工厂里的每一个泵、水箱和热交换器之前,使用已经有的东西。找出您所知道的,并让您的下一个数字化步骤成为一个明智的步骤—一个由数据支持的步骤。
提高循环一致对抗网络中损失函数的效率
CycleGAN 是一种涉及图像到图像翻译模型的自动训练的技术,不需要成对的例子。我们先来看结果。

基于循环一致对抗网络的马到斑马翻译
在这篇文章中,你会发现一些关于生成对抗网络、CNN、CycleGAN 技术的小知识。现在让我们从这个概念背后的一些基本信息开始:生成性对抗网络。生成对抗网络(GANs)是一类用于无监督机器学习的神经网络。发生器和鉴别器分开工作,互为对手
生成对抗网络
生成对抗网络(GAN)是神经网络中的一种模型,它在机器学习领域提供了很多潜力。在 GAN 中有两个神经网络:第一个是生成网络,第二个是鉴别网络。所以这个项目背后的主要概念是生成性对抗网络。甘是关于创造的东西,这是很难比较的另一个深度学习领域。GAN 的主要重点是从零开始生成数据。GAN 的一个例子是,从马生成斑马。正如我们所见,早期的 GAN 由两个网络组成,即发生器和鉴别器。我们来看图像。

了解 GAN(资料来源:Suransh Chopra 著《CycleGANs 简介》)
CycleGAN 是一种使用生成对抗网络或 GAN 模型架构来处理准备图像到图像翻译模型的方法。
现在,在我们跳到 CycleGAN 之前,我们需要了解 CNN。
卷积神经网络


CNN 如何识别图像(来源:Jason Brownlee,“深度学习的 Adam 优化算法的温和介绍”)
CNN 主要用于图像分类或识别。CNN 使功能更加高效,减少了参数。CNN 接受像素值作为网络的输入。用于特征提取的隐藏层和最后完全连接的层识别图像属于哪一类?CNN 有 4 层。卷积层、ReLu 层(激活函数)、池层和全连接层。
卷积层使用图像上的滤波器矩阵或图像上的移位滤波器矩阵,并获得卷积的特征图。
下一层是 ReLu 层。它将所有负像素转换为零并运行,但在 CycleGAN 中,由于负值,我们使用了 LeakyReLu。输出被称为校正特征图。下一层是池层。合并层降低了校正后的特征图的维度,这意味着我们必须从图像中选择最大像素。然后将汇集的特征图转换成长的连续 LV。这整个过程叫拍马屁。谄媚地连接着一个完全连接的图层来对图像进行分类。
循环 GAN

该模型包含两个函数 G: X -> Y 和 F: Y -> X,其中 X 是源域,Y 是目标域。生成器 X2Y 将马转换为斑马,Y2X 将斑马转换为马。CycleGAN 背后的关键思想是,它们允许你将模型指向两个不成对的图像集合。例如,一个图像集合,组 A 是未来的斑马,而另一个集合 B 是马。所以 Cycle-GAN 模型可以计算出如何解释不成对的图片。
这里的主要部分是循环一致性损失,例如,如果我们的输入图像 A 来自域 X,通过生成器 G 转换为目标图像或域 Y 的输出图像 B,然后域 Y 的图像 B 通过生成器 f 转换回域 X,因此这两个图像之间的差异称为循环一致性损失。

循环损耗(资料来源:Mohan Nikam“改善循环-GAN”)
发电机有三个部分:
I .编码器(提取特征):作为输入,卷积网络拍摄一张图片,我们在输入图片上移动以提取特征的滤波器窗口的大小,以及选择每次前进后我们将移动滤波器窗口的量的步长。
二。Transformer(添加先前结果的余数):因此,为此,我们利用了 9 层 resnet 块来如下改进结果:Resnet 块是包括两个卷积层的神经网络层,其中信息的累积被添加到产出。
三。解码器(解码结果):解码步骤是步骤 1 的特定逆步骤,我们将从元素向量再次返回低级特征。

CycleGAN 实施的步骤
周期目标函数、对抗性损失和周期一致性损失。



对抗性损失
现在,我们可以通过将这些损失项放在一起,并用超参数λ对循环一致性损失进行加权,来创建完整的目标函数。我们建议设置λ = 10

为了测量损失,我们像在大多数深度学习中一样使用交叉熵:p log (q)。
对于生成的图像,我们反转标签(即一减一标签)。所以目标变成了:

识别真实图像和生成的图像
另一方面,基于等式 1,优化检查发生器图像的 D,目标函数希望模型以最高可能的方式生成图像来欺骗鉴别器。

愚弄鉴别者
g 想最小化 V,而 D 想最大化 V。
通过提升其随机梯度来更新鉴别器:

通过降低其随机梯度来更新生成器:

这些算法实际上是由 Ian Goodfellow 使用的,但大多数深度学习研究人员使用 adam optimizer 来获得更好、更高效的结果,因为这种算法的结果与最佳结果相差很远。我使用了亚当优化的最佳效果。
发电机损耗:
发电机损耗是这两项之和:
G _ loss _ G = G _ loss _ G _ disc+G _ loss _ G _ cycle
因为循环损耗非常重要,所以我们想增加它的影响。
我们为这个乘数使用了一个 L1λ常数(在论文中使用了值 10)。
现在发电机损耗看起来像:
G _ loss _ G = G _ loss _ G _ disc+L1 _λ G _ loss _ G _ cycle*
g _ loss _ F = g _ loss _ F _ disc+L1 _λ g _ loss _ F _ cycle*
鉴频器损耗:
鉴别器需要做出两个决定:
1.真实图像应标记为真实(推荐值应尽可能接近 1)
2.鉴别器应该能够识别生成的图像,从而预测假图像为 0。
减少模型振荡
- 为了防止模型从一次迭代到另一次迭代发生剧烈变化,鉴别器被输入生成图像的历史,而不仅仅是由最新版本的生成器生成的图像。
- 此外,我们包含了过去 100 张图像的历史来训练鉴别器,为什么我们要做这些事情,因为生成器和鉴别器都可能过度拟合,导致模式崩溃
- 为此,我们保存了 100 张最近生成的图像。基于这种技术,我们减少了模型振荡以及模型过拟合。
亚当优化器
Adam 代表自适应矩估计。在训练的前半部分,学习率被设置为 0.0002,然后在剩余的迭代中线性降低到零。
就像最初的 GAN 实现一样,我们将创建单独的优化器,这些优化器只能更新网络的某些部分。我们希望两个网络都变得更好。
优化器是最重要的,因为在每个时期后,学习率会改变,偏差和权重也会改变,我们会获得最佳结果。大多数研究人员使用随机梯度,但随机是恒定的学习率算法,这就是为什么学习率在每个时期后不会改变。利用亚当优化函数和 L1 损失函数达到了较好的效果。 批量大小被设置为 1,这就是为什么我们称之为实例规范化,而不是批量规范化。
我们将在这里做同样的事情,只是现在我们有 3 个网络要优化,因此我们需要 3 个优化器:
- G_xy 和 G_yx 变量将作为生成器进行优化,而 D_x 和 D_y 应该更新两个不同的鉴别器。

FCN-不同方法的得分,在城市景观标签上进行评估
这是我在表 1 和表 2 中实现的结果,我们考虑的是完全损失的清除。消除 GAN 损失会极大地破坏结果,消除循环一致性损失也是如此。我们沿着这些思路假设这两个术语是我们结果的基础。
我们同样评估我们的策略,仅在一个方向上的周期损失:GAN +正向周期损失或 GAN +反向周期损失。

消融研究:FCN——我们方法的不同变体的得分,在城市风景照片→标签上评估
此外,我们包含了最近 100 张图像的历史记录来训练鉴别器,为什么我们要做这些事情,因为生成器和鉴别器都可能过度拟合自己(例如:普京骑在马上),导致模式崩溃。使用这种鉴别器不会有助于击败发生器。它需要击败最后的 100 个生成器,才能得到最优解。
结果(Pytorch)


故障案例(Pytorch)

有时生成器崩溃,这就是为什么产生有限的样本数据
摘要
在本文中,你发现了在循环一致的敌对网络中提高损失函数的效率。具体来说,您学到了:
执行 CycleGAN 的确切方法,GAN、CNN、随机和 Adma 优化器、发电机损耗、鉴别器损耗的知识,减少模型振荡。
如果您想了解更多的实现细节,可以参考一些非常开放的用法。
感谢阅读!
随时给我发信息。
Twitter:aamirjarda
LinkedIn:aamirjarda
insta gram:aamirjarda
你有什么问题吗?在下面的评论中提出你的问题,我会尽力回答。
提高机器学习模型的性能
模拟性能的不同方法

克里斯·利维拉尼在 Unsplash 上的照片
在之前的帖子中,我们探索并分析了一个客户流失数据集。然后,我们建立了一个机器学习模型来预测客户流失,在训练集和测试集上的准确率分别达到了%91.7 和%90.7。
在本帖中,我们将致力于:
- 如何提高准确率(正负类都有)
- 如何将模型的焦点更多地向正面类倾斜
值得注意的是,提高模型性能的最佳方法通常是收集更多的数据。然而,这并不总是一个可行的选择。
让我们回到我们的话题。
我们构建的模型是一个带有超参数的随机森林分类器:
- max_depth = 10(森林中一棵树的最大深度)
- n_estimators = 200(森林中的树木数量)
该模型的性能如下:

第一和第二矩阵分别是训练集和测试集上的混淆矩阵。混淆矩阵通过显示每个类别的正确和不正确(即真或假)预测,比分类准确性更深入。
让我们首先关注准确性,然后深入研究混淆矩阵和相关指标。
提高模型性能的一种方法是搜索最佳超参数。调整超参数就像调整模型一样。随机森林有许多超参数,但最重要的是树的数量(n_estimators)和单棵树的最大深度(max_depth)。
我们将使用 scikit-learn 的 GridSearchCV 类。它允许从一系列值中选择最佳参数。让我们首先创建一个字典,其中包含一组 n_estimators 和 max_depth 的值。我将选择我们之前使用的值。
parameters = {'max_depth':[8,10,12,14],
'n_estimators':[175,200,225,250]}
可以尝试更多的值或者超参数。没有一个正确的答案。我们现在可以将这个字典和一个估计器一起传递给 GridSearchCV 对象。
rf = RandomForestClassifier()gridsearch = GridSearchCV(rf, param_grid=parameters, cv=5)gridsearch.fit(X_train_selected, y_train)
cv 参数正在进行交叉验证。
我们已经训练了 GridSearchCV 对象。让我们看看最佳参数是什么:
gridsearch.best_params_
{'max_depth': 12, 'n_estimators': 225}
我用大约 12 和 225 的值再次运行了 GridSearchCV。最好的参数是 13 和 235。
让我们看看这些新的超参数值的混淆矩阵和准确性。
rf = RandomForestClassifier(max_depth=13, n_estimators=235)
rf.fit(X_train_selected, y_train)y_pred = rf.predict(X_train_selected)
cm_train = confusion_matrix(y_train, y_pred)
print(cm_train)y_test_pred = rf.predict(X_test_selected)
cm_test = confusion_matrix(y_test, y_test_pred)
print(cm_test)train_acc = (cm_train[0][0] + cm_train[1][1]) / cm_train.sum()
test_acc = (cm_test[0][0] + cm_test[1][1]) / cm_test.sum()print(f'Train accuracy is {train_acc}. Test accuracy is {test_acc}')

训练集的准确率提高了,但我们在测试集上没有取得任何成绩。如果我们可以收集更多的数据,这通常是提高准确性的最佳方式,测试准确性也可能随着这些新参数而提高。
如果你还记得之前的帖子,我们已经删除了 4 个与其他相比信息量较少的特性。在某些情况下,消除信息量较少或不相关的要素是一种很好的做法,这样可以避免给模型带来不必要的计算负担。然而,这些被消除的特征可能会稍微提高精度,所以这归结为性能增强和计算负担之间的决定。
我摆弄了一下超参数值,并用所有的特性进行了训练。结果如下:

我们已经实现了大约%1 的测试精度增加,这也是在过度拟合方面的改进。
我们的任务是预测客户是否会流失(即不再是客户)。因此,重点应该放在积极的一类(1)上。我们必须正确预测所有的正类(Exited=1)。对于负类(Exited = 0),我们可以承受一些错误的预测。
我们需要进一步提高精确度。先说混淆矩阵。

(图片由作者提供)
- 真阳性(TP) :预测阳性类别为阳性(ok)
- 假阳性(FP) :将阴性类别预测为阳性(不正常)
- 假阴性(FN) :将阳性类别预测为阴性(不正常)
- 真阴性(TN) :预测阴性类为阴性(ok)
因为我们希望尽可能预测客户流失,所以我们的目标是最大化 TP,最小化 FN。
当我们预测“客户不会流失(0)”但在实际情况下,客户会流失时,就会发生 FN。
是时候引入两个指标了,即精度和召回。
Precision 衡量当预测为正时,我们的模型有多好。

精度的焦点是正面预测。它表明有多少积极的预测是正确的。
回忆测量我们的模型在正确预测正类方面有多好。

召回的重点是实际正班。它表示模型能够正确预测的阳性类别的数量。
我们希望预测所有积极的类,因此 recall 是我们任务的合适度量。最大化 TP 和/或最小化 FN 将增加召回值。
以下是训练集和测试集的混淆矩阵:

我们需要最小化标有黄色的值,这些值是假阴性(FN)。
实现这一点的一个方法是告诉模型“正类(1)比负类(0)更重要”。使用我们的随机森林分类器,可以通过 class_weight 参数来实现。
rf = RandomForestClassifier(max_depth=12, n_estimators=245,
class_weight={0:1, 1:3})rf.fit(X_train_transformed, y_train)
我们传递了一个包含每个类的权重的字典。我设定为 3 比 1 作为例子。
以下是新的混淆矩阵:

假阳性的数量大大减少。积极类上的错误预测比消极类上的错误预测受到更多惩罚。因此,该模型倾向于在尽可能低的正类上犯错误。
这种方法有一个缺点。虽然在预测正类方面越来越好,但整体准确性可能会变得更差。让我们检查一下。

测试集的准确率从%91.21 下降到%89.57。因此,这归结为一个商业决策。如果我们只想预测所有的正类,不关心整体的准确率,可以进一步增加正类的权重。
例如,当我们将权重指定为 10 比 1 时,这是混淆矩阵和准确度:

我们还可以尝试不同的算法,看看性能是否会变得更好。然而,更复杂的模型需要更多的数据。他们渴望数据。梯度增强决策树(GBDT)及其变体(如 XGBOOST、LightGBM)也可以尝试,但我认为性能只会略有提高。
当考虑到任务的复杂性和数据量时,我认为随机森林会做得很好。
感谢您的阅读。如果您有任何反馈,请告诉我。
使用 Bagging 提高机器学习模型的性能
理解 Bootstrap Aggregation (Bagging)集成学习的工作原理,并使用 sklearn 库实现一个随机森林 Bagging 模型。

在 Unsplash 上由 Carlos Muza 拍摄的照片
机器学习模型的性能告诉我们,对于看不见的数据点,模型的表现如何。有各种各样的策略和技巧来提高 ML 模型的性能,其中一些是:
- ML 模型的微调超参数
- 使用集成学习。
什么是集成学习?
集成学习是一种组合多个 ML 模型以形成单个模型的技术。也被称为基础模型或弱学习器的多个 ML 模型可以是不同的算法,也可以是超参数有变化的相同算法。
像分类任务一样,多个 ML 模型可以是逻辑回归、朴素贝叶斯、决策树、SVM 等。对于回归任务,多个 ML 模型可以是线性回归、Lasso 回归、决策树回归等。
集成学习结合了基本模型的优点,以形成具有改进性能的单个鲁棒模型。各种类型的集成学习技术有:
- 引导聚集
- 助推
- 投票
- 级联
- 堆垛
还有很多。本文将介绍 Bagging 集成技术的工作和实现。
Bagging(引导聚合)概述:
Bagging ensemble 技术也称为 Bootstrap Aggregation,它使用随机化来提高性能。在 bagging 中,我们使用在部分数据集上训练的基础模型。在 bagging 中,我们使用弱学习者(或基础模型)模型作为积木,通过组合其中的几个来设计复杂的模型。
大多数时候,这些基本模型表现不佳,因为它们要么过拟合,要么过拟合。模型的过拟合或欠拟合是由偏差-方差权衡决定的。
什么是偏差-方差权衡?[1]
模型的总体误差取决于模型的偏差和方差,遵循以下等式:

对于一个好的稳健模型,模型的误差尽可能小。为了最小化误差,偏差和方差需要最小,并且不可约误差保持恒定。下面的误差与模型灵活性(自由度)图描述了偏差和方差以及测试和训练误差的变化:

来源,偏差-方差权衡误差图
从上图分析:
- 当模型处于训练的初始阶段时,训练和测试误差都非常高。
- 当模型训练足够的时候,训练误差很低,测试误差很高。
- 训练和测试误差高的阶段是欠拟合阶段。
- 训练误差低而测试误差高的阶段是过拟合阶段。
- 在训练和测试误差之间存在平衡的阶段是最合适的。
- 欠拟合模型具有低方差和高偏差。
- 过度拟合模型具有高方差和低偏差。
Bagging Ensemble 技术可用于具有低偏差和高方差的基础模型。Bagging ensemble 使用数据集的随机化(将在本文稍后讨论)来减少基础模型的方差,从而保持较低的偏差。
装袋工作[1]:
现在很清楚,装袋减少了基础模型的方差,保持了较低的偏差。通过结合 bootstrap 抽样和聚集策略来减少基本模型的方差。装袋的整个工作分为三个阶段:
- 自助抽样
- 基础建模
- 聚合
下图描述了具有 n 行的样本数据集 D 的所有三个步骤:

(图片由作者提供),打包的 3 个步骤——引导取样、建模、汇总
自举采样:
引导样本是一个较小的样本,是初始数据集的子集。引导样本是通过替换采样从初始数据集创建的。
假设一个数据集有 n 行和 f 个特征,我们做一个引导取样,它指的是取样替换成 k 个不同的较小数据集,每个数据集大小为 m,具有相同的 f 个特征。D_i 形成的每个更小的数据集看到数据集的子集。在下图中,形状为(n,f)的初始数据集 D 被采样为形状为(m,f)的 k 个数据集,其中 m < n

(图片由作者提供),数据集的自助抽样
下图描述了如何引导样本。具有 10 行的数据集 D 被采样并替换成 k 个更小的数据集,每个数据集具有 5 行。上图中 n=10,m=5。
观察到通过自举形成的每个数据集仅看到原始数据集的一部分,并且所有数据集彼此独立。

(图片由作者提供),10 行样本数据集的 Bootstrap 采样。
这是 bagging 集成技术的第一步,其中 k 个较小的数据集通过彼此独立的引导来创建。
建模:
建模是装袋的第二步。在通过自举创建了 k 个较小的数据集之后,使用 ML 算法来训练 k 个数据集中的每一个。用于训练 k 数据集的算法在超参数改变或不改变的情况下可以是相同的,或者可以使用不同的算法。
举个例子,
- 决策树算法可以用作基础模型,并改变超参数,如“深度”。
- 可以使用不同算法的组合,例如 SVM、朴素贝叶斯、逻辑回归。
在每个引导数据集上训练的模型被称为基础模型或弱学习器。下图描述了独立模型的每个数据集的训练:

(图片由作者提供),引导数据集的建模
聚合:
通过组合 k 个不同的基础模型来创建最终强大的健壮模型。因为基本模型是在引导样本上训练的,所以每个模型可能有不同的预测。根据问题陈述的不同,聚合技术也不同。
- 对于回归问题:聚合可以取每个基础模型预测的平均值。

Notation,
**prediction:** Final Output of bagging ensemble
**k:** number of base models
**pred_i:** prediction of ith base model
- 对于一个分类问题:聚集可以使用多数投票,具有最多投票的类可以被声明为最终预测。

Notation,
**prediction:** Final Output of bagging ensemble
**pred_i:** prediction target class of ith base model
**1,2,3...,c:** c different target class
**C:** Target Class having maximum vote

(图片由作者提供),k 基础模型的聚合
随机森林:
随机森林是 bagging 集成学习的一个例子。在随机森林算法中,基学习器只是决策树。随机森林使用装袋和列抽样形成稳健模型。
换句话说,RF 使用 bagging 集成学习的实现,除此之外,它在自举步骤期间使用替换进行列采样。引导第一步的变化如下所示:

(图片由作者提供),自举采样和列采样
初始数据集 D 的形状是( n 行, f 特征),在 bootstrap 采样+ column 采样的情况下,形成的 k 基数据集是行采样和列采样。基础数据集 D_i 的形状是( m 行, d 特征)其中 n > m 和 f > d 。
随机森林的实现:
为来自 Kaggle 的 Pima Indians 糖尿病数据集实施决策树和随机森林分类器。
(作者代码),决策树和随机森林分类器的实现
决策树分类器的观察:
决策树分类器针对 X_train 进行训练(第 16–19 行),DT 分类器模型的性能(第 21–23 行)在 X_test 数据上进行测试。对 DT 模型性能的观察是:

随机森林分类器的观察:
k=50 的随机森林分类器针对 X_train 进行训练(第 25–28 行),RF 分类器模型的性能(第 30–32 行)在 X_test 数据上进行测试。对 RF 模型性能的观察是:

性能改善观察:
- 模型的准确率从 71%(对于 DT 分类器)提高到 75%(对于 RF 分类器)。
- 从两个混淆矩阵中可以观察到 FN 和 FP 值减少以及 TP 和 FN 值增加的变化。
参考文献:
[1](2019 . 4 . 23),系综方法:装袋、升压、堆叠:https://towardsdatascience . com/Ensemble-methods-bagging-boosting-and-stacking-c 9214 a 10 a 205
感谢您的阅读!
利用 Keras 中超参数调整提高 ResNet50 涂鸦图像分类器的性能

来自数据集的涂鸦图像
介绍
在世界各地的绝大多数城市地区,街道周围都有故意破坏的迹象。最常见的破坏形式之一是涂鸦或标记,这也是众所周知的。在世界上任何一个城市的墙上、高速公路上、火车上,都可以发现涂鸦。它们可以是在公共表面上绘制或刮擦的不适当的图像、颜色、字母,这是所有执法机构共有的问题。
涂鸦破坏行为会影响社区,对旅游业和财产价值造成负面影响。它还会导致零售额下降,并加剧公民的恐惧;这最终耗尽了用于预防措施的税收。为了更好地协助执法部门减少破坏行为,涂鸦图像分类器可以帮助他们完美地识别街道上的涂鸦图像。
本文的重点是通过调整参数,如学习速率、批量大小和识别最佳冻结层,使用 ResNet50 神经网络来提高 Graffiti 分类器的性能。
为什么要调学习率、批量、冻层?
学习率是随机梯度下降反向传播中的步长。学习率将告诉我们在反向传播中需要改变多少权重,以便我们的模型预测得更好。对于较大的学习率,训练将是多样化的,并且模型可能表现得更差。因此,选择最佳的学习率对于模型的更好性能至关重要。
批次大小是用于训练模型以更新模型参数的样本数。也可以用单幅图像更新参数,但是这个过程噪声很大,而且损耗会很高。所以我们选择批量。一次用一批图像训练网络,可以更准确地估计误差梯度。
对于神经网络的前几层,网络学习图像的边缘(水平线和垂直线)和形状。在特定层,网络能够区分图像是否是涂鸦。因此,如果我们能够冻结该层并训练其余层,将会提高模型的性能。
用于训练/测试模型的图像总数
共有 2256 张图片;1127 个涂鸦,1129 个无涂鸦图片。总图像被分成 0.8:0.1:0.1 的比例作为训练、测试和验证集。要将图像分割成训练、测试和验证文件夹,可以使用“split _ folders”python 包。
注意:所有模型都是使用 Keras functional API 在 Google Colab (GPU)中运行的。
数据集和代码文件的链接:【https://github.com/ShailuSurya/GraffitiImageClassifier
迁移学习模型
ResNet50 针对 Imagenet 类的一百多万张图像进行了训练。因此,用超过 2000 张图像训练整个网络,对于一台带 CPU 的普通计算机来说是不可能的。因此,通过迁移学习,可以使用预先训练好的网络权重来训练顶层。

通过迁移学习的神经网络(使用 draw.io 创建)
我在输出中添加的图层是一个全局平均池图层、一个完全连接图层、一个下降图层和一个用于输出图层的 sigmoid 函数。如果对输出不满意,可以使用正则化或超参数技术来提高模型的性能。
我使用数据扩充(shear_range=0.2,horizontal flip=True,zoom_range=0.2)和丢失(rate=0.3)以及早期停止(耐心=10)作为正则化技术来提高模型的性能。
注意:在这里,我着重于涂鸦图像比无涂鸦图像更完美的预测。因此,我将检查所有模型的假阴性率;最终优选的模型将是具有高测试准确度和低假阴性率的模型。
超参数调整以提高性能
- 学习率
该网络以各种学习率进行调整,例如 0.1、0.01、0.001、0.0001、0.00001。选择一个最佳的学习速度非常重要。如果我们选择一个更高的学习率,通过选择最大损失函数,模型可以表现得更差。
- 对于学习率 0.1 和 0.01,训练准确率达到 80%,而验证和测试准确率为 50%,这是一个直线趋势。这意味着,对于较高的学习率,模型学习不多。
- 对于学习率 0.001,测试准确率为 82%。该模型错误地将 27 个图像预测为没有涂鸦,即使它们是涂鸦图像。总体而言,该模型正确预测了 89%的涂鸦图像。
- 对于学习率 0.0001,测试准确度为 84%。这个模型错误地将 26 个图像预测为涂鸦。该模型的召回率为 77%,准确率为 89%,假阴性率为 8%。
- 对于学习率 0.00001,测试精度为 86%,尽管在训练和验证精度之间存在较小的差异,但这存在欠拟合问题。该模型正确预测 83%的无涂鸦图像和 90%的涂鸦图像,假阴性率为 8%。
总的来说,0.0001 的学习率比其余的学习率表现得更好。因此,有了这个学习率,批量大小和冷冻层数被调整。




调整不同的学习率 0.01、0.001、0.0001、0.00001

不同学习速率下涂鸦图像预测混淆矩阵的度量
2。批量大小
根据 Jason Brownlee 博士关于调整超参数的文章,ResNet50 使用 16、32、64、100 个批量进行了调整,学习率为 0.0001。
- 对于批量 16,测试准确度为 82%。训练和验证准确度之间的波动很大(见下图)。该模型以 88%的精度正确预测了 75%的涂鸦图像。
- 对于批量 32,测试准确度为 84%。该模型以 90%的精度正确预测了 77%的涂鸦图像。
- 对于批量大小 64,测试精度为 85%,该模型以 88%的精度正确预测 81%的图像为涂鸦。该模型的假阴性率为 10.5%,这意味着该模型有 10.5%的可能性预测错误。
- 对于批量大小为 100,测试准确率为 85%,该模型正确预测 86%的图像为涂鸦,82%的图像为无涂鸦,假阴性率为 13.1%。
总的来说,根据需求的优先级,可以在 32、64、100 之间选择任何批量。如果优先考虑的是完美地预测涂鸦图像,那么可以选择批量 64。然而,我们也应该考虑假阴性率。批次大小为 64 时,假阴性率较低。所以,我要 64 号的。




调整批量大小 16、32、64、100

不同批量的涂鸦图像预测混淆矩阵的度量
3。寻找最佳冷冻层
根据下面的大小-相似性矩阵,在象限 3 中,如果数据集大小很小,那么我们必须冻结前几层并训练剩余的层。通过这样做,我们的模型可以更多地了解我们的数据集。

尺寸相似矩阵
基于大小-相似性矩阵,也基于 加布里埃尔·林斯·特诺里奥的一篇关于提高迁移学习性能的文章,我已经冻结了前几层,并训练了剩余的几层。为了让模型更好地学习涂鸦数据集,我已经冻结了除最后 15 层、25 层、32 层、40 层、100 层、150 层以外的所有层。
- 训练最后 15 层,测试准确率 86%。该模型能够正确预测 86%的涂鸦图像。尽管该模型将图像分类为涂鸦,但该图像不是涂鸦的可能性为 19%(假阴性率)。
- 训练最后 25 层,训练准确率为 81%,训练和验证数据集之间的方差较高。这个模型只正确预测了 73%的涂鸦图像。
- 训练最后 32 层,测试准确率 81%。与其他模型相比,该模型在预测涂鸦图像方面表现更好,准确率为 90%。
- 训练最后 40 层,测试准确率 86%。该模型仅能够正确预测 88%的涂鸦图像,但是假阴性率高达 14%。这意味着,有 14%的几率图像不是涂鸦,即使模型预测它是涂鸦。






训练最后几层并冻结剩余层

用于训练不同层的来自涂鸦图像预测混淆矩阵的度量
训练最后 100 层,测试准确率 87%。该模型可以正确预测 85%的涂鸦图像。假阴性率为 11.4%,低于“训练最后 40 层”。所以,我要进行最后 100 层的训练。
什么样的学习速率、批量大小和冻结层数提高了性能?
总体而言,在学习率为 0.0001 的情况下,测试准确率为 84%,假阴性率为 8%。以这个学习率和批量 64 ,测试准确率为 85%,假阴性率为 10.5%。最终在学习率为 0.0001,批量为 64 的情况下,训练最后 100 层,测试准确率提高到 87%。
结论
最佳学习速率、批量大小和识别最佳冻结层的选择取决于我们的要求。一些模型完美地预测无涂鸦图像,一些模型更正确地预测涂鸦图像。对于所有的模型,我考虑了假阴性率来决定最佳的参数值。最后,决策取决于需求的优先级。
参考
电通外部服务管理 ,(2017)。涂鸦:墙上的文字
加布里埃尔·林斯·特诺里奥、克里斯蒂安·穆尼奥斯·比利亚洛沃斯、莱昂纳多·福雷罗·门多萨、爱德华多·科斯塔·达席尔瓦和沃特·卡尔。提高迁移学习性能:在遥感数据分类中的应用
莱斯利·史密斯,美国海军研究实验室高级研究科学家。竞赛获奖学习率。
罗森布拉特感知机的改进
自适应线性神经元和 Delta 规则

机器学习和人工智能已经在许多领域产生了变革性的影响,从医学科学(例如成像和 MRI )到实时战略视频游戏(例如星际争霸 2 )。这些成功的关键促成因素是深度神经网络,其特点是所谓的隐藏层和人工神经元的数量不断增加。然而,必须强调的是,神经网络最初有着卑微的开端:当弗兰克·罗森布拉特(1928–1971)在 1957 年介绍他的感知机时,它只有一层由单个计算神经元组成,与今天可能有数百层和数千个神经元的神经网络相去甚远。尽管自 20 世纪 50 年代末以来发生了很多变化,但这些系列旨在引导学生了解神经网络的起源。这样做将更容易最终掌握深度学习所依赖的数学,以及现代神经网络是如何成为今天的样子的。为此,今天的主题是自适应线性神经元和 Delta 规则,这是由 Bernard Widrow 和他的学生 Ted Hoff 于 1960 年提出的。在开始之前,让我们快速回顾一下罗森布拉特的感知机。

左图:伯纳德·维德罗。右:马尔西安“特德”霍夫。
快速回顾罗森布拉特的感知机(1957)
深度学习快速入门。
towardsdatascience.com](/rosenblatts-perceptron-the-very-first-neural-network-37a3ec09038a)
当 Rosenblatt 在 1957 年首次为二进制分类问题引入感知器时,他的机器使用了一个单一的计算神经元,如下图所示。

罗森布拉特感知机
给定输入向量

感知器首先计算加权和

然后将其传递给 Heaviside 函数以生成其输出

最终输出是 x 所属的预测类(0 或 1)。尽管这种人工神经元的数学简单,罗森布拉特的主要成就是设计了一种算法,使它能够直接从训练数据中实际学习一组权重和偏差 b 。今天,这种监督学习算法被称为感知器学习算法。

感知器训练程序的局限性
罗森布拉特的感知机并非没有局限性。其中一些根源于数学模型本身,已经在明斯基于 1969 年出版的一本臭名昭著的书中指出。

图 1: 玩具问题考虑。
为了说明我们的观点,让我们考虑图 1 中的二元分类玩具问题。这和介绍罗森布拉特的感知机时考虑的是一样的。然而,一个单独的训练示例被故意贴错了标签。使用标准的机器学习工具,人们会期望这一个错误标记的训练示例不会显著恶化分类模型的性能。虽然这种直觉对最近的模型可能是正确的,但我们会看到它不适用于罗森布拉特的感知机。

图 2: 罗森布拉特感知器的决策边界在 100 个历元上的演变。学习率设置为 1。
图 2 描绘了当历元的数量从 1 到 100 变化时,感知机的决策边界的演变(即,我们循环通过整个训练数据集以学习权重 w 和偏差 b 的次数)。很明显,决策边界到处都是。巧合的是,错误分类点的数量从 1 一直到 100 个数据点中的 69。这种不稳定的行为不能通过降低学习速率(默认设置为 1)来缓解,这是一种经典的建议。事实上,回头看看感知器学习算法(见算法 1),只要感知器误分类哪怕是一个点,权重 w 和偏差 b 就会不断更新。然而,给定我们的训练数据集,感知器实际上不可能正确地分类所有的点,因此学习过程永远继续下去,永远不会收敛!然而,感知器学习算法的这种基本限制和缺乏鲁棒性可以通过稍微修改学习过程来消除。我们将在下文讨论的小修改产生了现在被称为 ADALINE 的单层感知器。
适应性线性神经元(1960 年)
像罗森布拉特的感知器一样,ADALINE(又名自适应线性元素或 Widrow-Hoff 规则)是一个单层感知器。然而,它与它的不同之处在于它如何从数据中学习权重 w 和偏差 b 。

阿达林。与罗森布拉特感知器的图表进行比较。
主要区别来自用于调整两个感知器的权重和偏差的反馈误差。Rosenblatt 使用分类误差(即二进制值),ADALINE 引入了所谓的损失函数(有时也称为成本函数或目标函数)的概念,它依赖于量化前人工神经元的输出(即连续值)。虽然这可能看起来是一个很小的区别,但我们很快就会看到,当涉及到最终的模型时,这实际上是一个很大的区别!
损失函数的引入使得 ADALINE 比 Rosenblatt 的感知器更接近现代机器学习方法。给定我们的集合 m 例(x【yₘ】用 yₘ ∈ {0,1}表示类**x所属,ADALINE 的损失函数定义为**

其中 φ(z) 为激活函数(即这里的恒等函数)。基于该定义,获得权重 w 和偏差 b 作为最小化问题的解

即,它们被选择为使得我们的示例集上的误差平方和尽可能小。
损失函数如何最小化?
让我们看看如何找到最小化损失函数的权重和偏差集。为此,我们将依赖于损失函数是二次的以及相关的最小化问题是凸的事实。如果你不知道什么是凸优化问题,简单来说就是我们知道如何高效求解的优化问题。我们还需要一些基本的高中微积分。
一个凸函数ℒ (z) 只有一个最小值。它位于ℒ (z) 的斜率为零的点 z ,即

我们的目标是找到满足这个条件的一组权重 w 和偏差 b 。这些是导致误差平方和尽可能小的权重和偏差(给定我们的数据)。
****德尔塔法则:记住一个函数的梯度表示正斜率最大的方向。因此,寻找函数最小值点的一个简单的启发式方法是向与梯度相反的方向移动。因此,让我们首先计算损失函数的梯度。对于一般激活函数 φ(z) ,它由下式给出

和

用φ’(z)激活函数相对于 z 的导数。注意 ADALINE 代表 ADA 感受性线性神经元。它的激活是恒等式,即 φ(z) = z 从而 φ'(z) = 1 。因此,损失函数的梯度简化为

和

从给定的一组权重 w 和偏差 b 开始,delta 规则规定,为了减少误差平方和,这些权重和偏差需要更新如下

其中更新∈w和∈b由下式给出**

和

这里,α是一个标量,通常称为学习率或步长。最简单的形式是,德尔塔法则假设α常数。变量 w 和 b 持续更新,直到执行了规定的迭代次数,或者更新的范数小于用户定义的容差。这就是事情的全部。
如你所见,德尔塔法则背后的数学和哲学都很简单。尽管如此,它仍然是用于训练更深层次神经网络的更一般的反向传播算法的一个特例,因此它在本系列中很重要。不要犹豫重新推导所有的数学作为练习。同时,现在让我们转移到有趣的东西,用 Python 实现 ADALINE。假设您已经熟悉 Python,下面的代码应该是不言自明的。
为了清晰和易用,我们将在整个系列中坚持使用 scikit-learn API。这段代码的扩展版本也可以在我的 TowardsDataScience Github repo 上获得(此处)。
ADALINE vs. Rosenblatt 的感知器

图 4: 随着训练的进行,训练数据集中误分类点的数量。

图 5: 罗森布拉特感知器(浅灰色)和 ADALINE(黑色)的决策边界在 100 个历元上的演变。在这两种情况下,学习率都设置为 0.1。
图 4 显示了 Rosenblatt 的感知器和 ADALINE 在训练过程中错误分类点的数量,而图 5 描述了两个模型的决策界限的演变。罗森布拉特的感知器无处不在,在某个特定时期的准确率接近 99%,而在下一个时期的准确率不到 50%。这种鲁棒性的缺乏来自于一个错误标记的数据点阻止罗森布拉特的感知机学习任何东西。
相比之下,随着训练的进行,ADALINE 的误分类点的数量单调减少。看 ADALINE 的决策边界的演化,可以看出它比 Rosenblatt 的感知器要平滑得多。这种更平滑的演变来自于成本函数的定义,使得训练过程能够基于对当前预测的错误程度的一些评估,而不是简单地基于它是否错误(如罗森布拉特的感知器的情况),在每一步对权重【w】和偏差 b 执行小的调整。由损失函数编码的信息因此使得 ADALINE 的训练更加健壮和良好。最后要注意的是,即使这两个类不是线性可分的(由于一个错误标记的数据点),ADALINE 的最终线性决策边界仍然是基于最小化问题的公式以有原则的方式选择的,从而确保它在某种意义上是最优的。关于 Rosenblatt 的感知器的决策边界,没有这样的事情可以说,因为对于这里考虑的问题,它根本不存在,感知器学习算法不能收敛。这是这两个单层感知器的主要区别…
ADALINE 普通最小二乘法是变相的吗?
在结束之前,让我们试着更好地理解 ADALINE 实际上在学习什么。虽然它用于分类目的,但它与最简单的回归模型之一的普通最小二乘法 (OLS)密切相关。当观察损失函数时,这种紧密的联系清晰可见

使用简单的变量变化,

和

这个损失函数可以重写为

其中 X 的每一行都是给定的训练示例。这个损失函数不过是普通最小二乘最小化的二次损失函数。最优解的封闭形式是

因此,两个模型之间的这种等价允许我们将 ADALINE 的权重 w 和偏差 b 理解为出现在超平面的方程中的系数,该方程在最小二乘意义上最好地分离了两个类别。
尽管 ADALINE 改进了 Rosenblatt 的感知器,但我们将在接下来的帖子中看到在最小二乘意义上解决问题并不是一个人可以为分类问题做的最合适的事情…
结论
这篇文章是我的深度学习初学者系列的第二篇。这本书应该更早出版,但生活另有决定(新生儿、新房子、工作等)。至于罗森布拉特的感知机的第一篇文章,我知道将自适应线性神经元的文章标记为深度学习可能有些牵强,但相信我,我们会实现的。与此同时,不要犹豫地玩代码(见 GitHub repo ),如果有兴趣,自己重新推导所有的数学。没那么复杂。如前所述,ADALINE 比 Rosenblatt 的感知器更接近现代机器学习方法。因此,当我们转向现代神经网络时,很好地理解它所依赖的数学将是非常有价值的!
在接下来的几篇文章中,我们将讨论以下主题:
- 感知器收敛定理。
- XOR:深度学习的卑微开端。
最后,您会在下面找到一个与 ADALINE 相关主题的附加在线资源列表。不要犹豫,看看这些,因为它们可能会处理一些我们可能会忽略的方面!
PS:如果你知道任何其他相关链接,不要犹豫给我发消息,我会编辑帖子来添加它:]
其他在线资源
- Sebastian Raschka 关于单层神经网络和梯度下降的博客文章以及他的机器学习常见问题。
- 如果你想更多地了解泰德霍夫:https://computerhistory.org/profile/ted-hoff/
想要阅读更多此类内容?查看我其他关于低秩结构和数据驱动建模 的文章或者干脆我的 机器学习基础知识 !
有没有想过我们为什么使用它,它来自哪里,如何有效地优化它?这里有一个解释(代码…
towardsdatascience.com](/binary-cross-entropy-and-logistic-regression-bf7098e75559)**
杂质和判断分裂——决策树如何工作

罗马卡夫在 Unsplash 上拍摄的照片
如果你想了解机器学习算法是如何工作的,那么从不起眼的决策树开始是不会错的。本质上,决策树是一个流程图,它询问一系列关于数据点的问题(数据点被赋予一组特征/值)以便对其进行分类(见下文,决策将是绿框中的多数组)。

注意:绿框代表叶节点,在这些叶节点上,将组进一步分成“赢”和“输”是没有改进的
为了训练一个决策树,你需要一组训练数据,然后通过在每个点为每个结果组提出最佳问题,找到将它分成越来越相似的组的最佳方法。
例如,在上面的图表中,我们想要分类一支球队是否会赢得比赛(训练集为 9 胜 5 负),它查询的第一个问题是数据中的列,该列详细说明了他们是与 A 队、B 队还是 C 队比赛,然后将它分成三组。如果你玩的是 B 队,那么它不会再进行分裂,因为最终的小组是你能做到的最纯粹的小组(4 胜 0 负),所以预测你会赢得任何新的数据点。其他组仍然是“不纯的”(有混合数量的赢和输),将需要进一步的问题来进一步分裂他们。有趣的是,对于每个组,他们可能不会被问到相同的问题(例如,“主场优势?”或者“以前赢过?”).
决策树的工作方式是一种非常有趣的预测方式,因为:
- 它们很直观——你可以阅读这些问题集,很快就能知道它是如何做出决定的
- 您可以按类别或数量分割数据——如果数据大于某个数量(即一组小于 3,另一组大于或等于 3),您可以按类别分割数据(一组中的所有“狗”,另一组中的所有其他动物)
- 这是一种你可以硬编码的东西——你可以将问题物理编码到简单的电子设备中,这比神经网络等更复杂的算法更容易,甚至在某些情况下可以打印出来
- 它是更复杂算法的构建模块(最流行的机器学习算法之一,随机森林,本质上是一组专门构建的决策树)
- 他们可以做出非常复杂的决定——他们处理高维和低维数据,他们甚至可以预测一个数字以及预测一个类别(他们可以进行分类和回归预测)
- 可以计算特征重要性 —这个我以后再回答。
你说很好。让我们开始编写代码吧!等等,等等,等等……在我们开始构建一棵树并测试它之前,我们需要回答一个重要的问题。
它如何决定要问的最佳问题?

埃文·丹尼斯在 Unsplash 上拍摄的照片
如果你想到了关于球队获胜的例子,那么算法是如何知道问你在和哪个队比赛是最先问的问题的呢?我们可能会争论“最佳”在这里意味着什么,但我的意思是,对于我们从可用问题列表中提出的每个问题,它应该是将数据分成彼此更相似的组的问题(因此,对于我们之前的示例,我们希望组只包含赢或输)。那么它是如何决定的呢?

照片由 Justus Menke 在 Unsplash 上拍摄
为了观察这一点,我将制作一组虚假的数据,根据你鞋子的抓地力有多滑(4 表示非常滑,0 表示不滑)以及地板表面有多滑,涵盖你是否可能摔倒(“摔倒”)或不摔倒(“没有摔倒”)。想象它,我们有:

假的秋天数据。蓝色不太可能掉(“不掉”),绿色很可能掉(“掉”)
我们凭直觉知道,如果你有更多防滑鞋,你可以在更滑的地板上保持抓地力,反之亦然。因此,如果您可以将一个轴(地板或鞋子光滑度)上某个值的数据分成两组,这样得到的组会“更纯”,那么您会怎么做呢?更重要的是,算法是如何做到的?是否要在地板光滑度为 2.5 的情况下将数据分成两组?或者是 1.5 的鞋滑度?
这就是我们进入测量分割数据质量的数学的地方。对于每一个问题,我们都希望将一组数据放入问题中,最终得到两组数据,一组包含问题上方的所有数据,另一组包含问题下方的所有数据。我们不会问没有出现分裂的问题(比如将鞋子光滑度 5 分或以上的所有分数放入一个新组,而将其余分数放入另一个新组),因为我们根本没有改进这些组(没有任何变化)。
分裂的纯粹性

汤姆·巴瑞特在 Unsplash 上的照片
已经存在几种“纯度”或“最佳”分离的数学方法,您可能遇到的主要方法有:
- Gini 杂质(主要用于正在进行分类的树)
- 熵(同样主要是分类)
- 方差减少(用于正在进行回归的树)
*如果你在 pythons 的 SKLearn 模块中寻找决策树分类器或回归器,你会看到它们列在“标准”选项下。
本周,我将重点讨论基尼系数不纯度,因为一旦你理解了它的数学原理,你就可以很直观地计算出来(而熵可能会有点困难)。在我们的决策树在未来的版本中工作之后,我们总是可以看看其他的。
基尼杂质
(我打赌你能看出为什么我之前一直用“纯”这个词来让你做好准备!)
基尼系数所做的是计算出你从一组数据中选择一个项目的概率,然后计算出你错误分类的概率。
例如,如果我有一袋 6 个蓝色和 4 个黑色的球(上面都有一个说明颜色的小标签),那么纯度测量就是如果我去掉所有的标签,随机选取一个标签放在我也从袋子中随机抽取的一个球上,我对它们进行错误分类的可能性有多大。
基尼系数的实际等式如下:

其中 I(i)是一组数据的杂质,I。j 和 k 是该组中不同的类别/标签,f(i,j)和 f(i,k)是 I 被分类为 j 组或 k 组的概率。
求和项是因为我们对没有正确分类的每个可能的组合都这样做。我不会深入这个等式,因为我会把它作为一个练习留给着迷的读者去查看链接,我发邮件去了解更多。
因此,做一个工作示例,对于袋子,我们选择蓝色球的概率是 6/10(10 个袋子中只有 6 个蓝色球),我们在袋子上贴黑色标签的可能性是 4/10(总共 10 个标签中只有 4 个黑色标签)。我们将这两者相乘,得到 24/100。如果我们对黑球这样做,我们得到 4/10 乘以 6/10,得到 24/100。将它们相加,我们得到 48/100 或 0.48。这袋球的纯度是 0.48。
现在我们有了一种计算一组数据的杂质的方法,我们要问的问题应该是,分裂组合并杂质(这通常由分裂组的大小加权,因此较大的组具有较大的权重)较低,我们对此进行了最大化。
对于我们跌倒的例子,我们只需要检查鞋子打滑和地板打滑的所有可能值,看看哪一个分裂给出最大的基尼不洁分数减少。
注意:有些人可能会说,如果你同时兼顾鞋子和地板的光滑度,这两组人会更好。
然而,虽然这是真的,但将它编码到算法中在计算上是非常昂贵的。这是因为要问的问题数量会成倍增加。
例如,对于我们来说,我们问了 4 个关于鞋子特征的问题和 4 个关于地板特征的问题(之所以是 4 个,是因为我们没有问一个所有数据都在一个组中结束而不是在另一个组中结束的问题,就像在 4.5 的光滑度上分裂一样),总共有 8 个可能的分裂问题。
如果我们使用上述方法,我们将有 4*4=16 个问题,这是一个很大的数字。一次只执行一次分割的结果是训练算法更快,只是树中的问题稍微多一些。合理的交易。
应用拆分
因此,查看我们的秋季数据,我们发现初始杂质分数为 0.3648,如果我们以 1.5 的鞋滑度进行分割,那么我们得到的分数为 0.2747(减少 0.0901),如果我们以 2.5 的地板滑度进行分割,那么我们得到的分数为 0.288 (0.0768),这使得鞋子切割效果最佳。我制作了一个 python Jupyter 笔记本和一个 Excel 电子表格(可以在我的 GitHub 上找到,还有一个处理 100 个数据点的脚本)来显示所有决策的计算,并在下面制作了这些漂亮的视觉效果来展示如何将数据分成更好的组。


左: Excel 模型,右: Python Jupyter 笔记本模型
对于获胜的问题,我们可以计算分数:
- 首发组:总分 25 分有 6 个“摔倒”,19 个“没有摔倒”。由于篇幅原因,我不会在这里计算它,但在阅读了下面几点后,可以随意尝试一下。总数是 0.3648。
- 高于 1.5 的组:我们有 1/15 的机会选择一个“无落差”数据点,14/15 的机会给它一个错误的 14/225 倍数值的标签。对于 14 个“下降”数据点,我们有相反的结果,但是 14/225 的结果是相同的。求和后我们得到的值是 28/225。
- 低于 1.5 的组:我们有 5/10 的几率选择“不坠落”,有 5/10 的几率误分类为 25/100 的值。对于“下降”数据,我们有相反但相同的最终值 25/100。总数是 50/100
- 总计:高于 1.5 的组有 15 个数据点,因此其值被加权为 15/25(起始组中有 25 个数据点)。对于低于 1.5 的组,我们有 10/25。这给了我们:
28/22515/25 + 50/10010/25 = 0.0747 + 0.2000 = 0.2747
- 杂质的减少是起始组 Gini 杂质减去来自所得分裂组的杂质的加权和。这是 0.3648–0.2747 = 0.0901(与代码相同!)
我之前说过,您可以询问决策树数据中的哪些特征是最重要的,您可以通过对针对该特征提出的每个问题的纯度减少量进行求和来实现这一点(例如,我在前面的问题中根据身高分割数据,然后在后面的问题中再次分割数据)。把这些加起来,你就能清楚地看到哪些决定是最重要的。这对于修剪和简化你的树是有用的,但是也给出了最有价值的决策信息来自哪里的很好的指示。
我们完了。我们可以判断劈叉的质量
恭喜你!现在,您了解了决策树判断最佳问题的一种方式。我计划在以后的文章中添加到 jupyter 笔记本中,这样我们就可以使用这种方法从头开始构建一棵树。
对于那些认为我们的数据太容易分割的人来说,嗯…你是对的。虽然我的测试例子很简单,你可以通过眼睛很容易地判断它,但请记住,这些算法经常查看超过 2 维的数据,一旦你到达 3 或 4 维,人脑真的很难想象它。这真的显示了这些算法的关键力量,它总是能够对我们自己难以做到的数据进行最好的分割。
参考资料:从零开始构建算法的一个很好的参考资料是 Toby Segaran 的《编程集体智慧:构建智能 Web 2.0 应用程序》。它很老了,是用 Python 2 编写的,期望数据在列表中,但这是一个很好的介绍,你可以挑战自己,将它转换成最新 Python 中的 pandas 数据帧。如果你想先看看机器学习算法,我也推荐维基百科。
IMS 超细与 VST:一个小样本浓缩咖啡过滤器的比较
利用数据找到一种比较和对比的方法
当我第一次得到 VST 过滤篮时,它极大地改变了我的浓缩咖啡。一旦我开始制作不连续浓缩咖啡,过滤的想法就更加强烈了。我对我的 VST 过滤器和其他过滤篮进行了分析,在某个时候,我偶然发现了 IMS 超细过滤器。有人在网上询问过滤器,当我提到我使用过它们时,我想到了数据。
我有足够的数据来更好地比较 IMS Superfine 和 VST 吗?我有足够的数据来比较我的 VST 7g 过滤器和 VST 20g 过滤器吗?所以我挖掘了 6 个月的数据,看看我是否能控制足够的变量来发现一些有趣的东西。
请记住,就使用的过滤器数量而言,这是一个超小型采样。这种分析应该从“这些特定过滤器中哪一个更好”的角度来看,而不是 IMS 或 VST 总体上更好。对于这项测试,需要进行更大规模的研究。




顶部图片:7g VST,20g VST,IMS 超细。左下:VST 20g,IMS 超细。右下:IMS 超细
极其简短的历史
VST 过滤器是经过大量研究后制成的,这些研究确定了改善浓缩咖啡所需的孔公差。他们提供了一份购买规格表,我已经独立核实了他们的说法。
IMS 超细过滤器使用筛网过滤掉 170 微米以上的颗粒,而不是典型的 250 微米及以上。该过滤器也被视为精密过滤器。
之前,我已经使用图像处理来分析过滤器上的孔尺寸变化。我将对这些过滤器进行分析,以便进行比较。每一个都有一些热点,那里的孔比较大,会影响流动。我注意到这些整体流动模式,而拉镜头。很难看出特定的孔值有很大的影响,但这是需要注意的。他们都有一些偏见,但没有一个主要的偏见会表明他们的表现会很糟糕。对于超细过滤器,分析包括顶部的金属筛网,使每个孔具有 4 至 10 个更小的孔。然而,我不确定这是否是过滤器的实际作用,因为金属网只是附着在边缘,而不是焊接在过滤器上。

绩效指标
我使用了两个指标来评估过滤器之间的差异:最终得分和咖啡萃取。
最终得分是 7 个指标(强烈、浓郁、糖浆、甜味、酸味、苦味和余味)记分卡的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。
使用折射仪测量总溶解固体量(TDS ),该数值与咖啡的输出重量和输入重量相结合,用于确定提取到杯中的咖啡的百分比。
浓缩咖啡数据随着时间的推移慢慢收集
我用六个月的时间拍摄了我的 VST 单曲(7g)、VST 双曲(20g)和 IMS superficial(18g),我开始寻找模式。最终,我没有一个公平的比较,因为我没有一个相同的重量,但我有很多数据,也许我们可以看到一个故事。
首先,将所有跨最终得分和提取的数据与产出投入比进行比较。除了看起来他们有相似的表现之外,在这些数据中没有出现一个模式。

然后,让我们比较一下在过滤(PFF)篮中有无纸质过滤器的情况。尽管如此,除了超细提取似乎与味道不太相关(最终得分)之外,模式还不太清楚。

为了改进这种比较,我们来做一些配对数据。我们将为每种烤肉搭配最佳口味,并将 VST 的最佳口味与 IMS 进行比较。同样,也缺乏数据,但即使是这么少的数据,也没有明确的令人信服的模式。

因此,让我们为每一次烧烤拍摄所有照片,按口味排序,并对 VST 和 IMS 拍摄进行配对,以比较 VST 的最佳照片和 IMS 的最佳照片,第二好的照片和第二好的照片,等等。这就给出了更多的数据,从口味上来说,它们似乎没有太大的区别。从提取方面来说,VST 要么与 IMS 相同,要么比 IMS 好得多。

VST 7 克对 VST 20 克
因为我们在比较数据,所以让我们用同样的方法来比较 VST 7g 和 VST 20g。让我们开始直接把每一次烘烤的最佳镜头配对在一起。一般来说,问题是一次烘烤有 20 次左右,我没有刻意对每次烘烤使用所有三种过滤器。所以在数据上有点欠缺。

让我们扩展数据,包括过去一年的数据,即使我没有提取测量。有些镜头是实验性的,有些是用来拨入研磨。总的来说,我在性能方面没有看到太多的偏好。当我有时间的时候,我喜欢更频繁的投篮,所以一个更小的篮子,但是这些天我在原地躲避的时间更少了。

这两个 VST 过滤器有差异,但最终在过去的一年里,他们最好的镜头对彼此几乎相等。
末端的精密过滤器
关于哪一个更好还存在一些争论。最终,在这篇文章中,我只有 2 个 VST 滤波器和 1 个 IMS 滤波器。为了获得更好的过滤器性能总体样本,需要大约 30 个过滤器,每个过滤器上有多个镜头。如果我有时间和钱,我会尝试这个实验。
我很失望,因为我以为 IMS 超细将是下一个增量改进,但它是相同的另一个 VST 过滤器。然而,令人欣慰的是,IMS 滤波器比 VST 滤波器差。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。
我的进一步阅读:
买得起的咖啡研磨机:比较
克鲁夫筛:一项分析
AI 中的“地面真实”是什么?(一个警告。)
一个演示,展示了为什么你不应该把人工智能当成一个神奇的魔法盒
注意:下面所有的链接都会带你去同一作者的其他文章。
随着所有的无端拟人化感染机器学习( ML )和人工智能( AI )空间,许多商人被骗去认为 AI 是一个客观、公正的同事,知道所有正确的答案。这里有一个快速演示,告诉你为什么这是一个可怕的误解。

图片:来源。
几乎每个人工智能学生都必须经历的一项任务是建立一个系统,将图像分类为“猫”(照片包含一只猫)或“非猫”(看不到猫)。这是一项经典人工智能任务的原因是,识别物体对人类来说是一项相对容易完成的任务,但我们真的很难说出我们是如何做到的(所以很难编写描述“猫性”的明确规则(T21)。这些任务对人工智能来说是完美的。
演示
我听到你们中那些已经和 AI 相处了一段时间的人的抱怨——你们已经厌倦了猫/非猫的任务。很公平,但就这一次。对于这个练习,你将是我的 AI 系统。你的任务是将下面的六幅图片分类。您只能从两个允许的标签/输出中选择:
- 猫
- 非猫
我们开始吧!给 6 幅图像中的每一幅分配一个允许的标签,就像人工智能系统会做的那样:

花点时间将每张图片标记为“猫”或“非猫”。
啊哈!图片 1-5 很简单,但是我听到你对图片 6 喃喃自语。《大猫》?《猫的种类》?《也许猫》?这些是不允许的选项!你是一个被编程为只输出【猫】或【非猫】的系统。那到底是哪一个?
转到此视频的 0:20,与现场观众一起观看本文的演示。
因此,我们开始看到项目的决策者是多么重要。正确的答案不是柏拉图式的,当然也不是来自人工智能系统……事实上,没有【正确】的答案。【正确】答案取决于系统的所有者希望系统做什么。
人工智能不能为你设定目标——那是人类的工作。
如果我试图建立一个宠物推荐系统,它只推荐那些在典型的成年形态下可以安全拥抱的动物,那么答案就很明显了。我对该系统的预期目的是指您的正确行动是将图像 6 标记为“非猫”。如果在这一点上你仍然把它贴上“猫”的标签,那么…我建议你购买更多的人寿保险。
机器学习的“正确”答案通常是在旁观者的眼中,因此为一个目的而设计的系统可能不会为不同的目的而工作。
如果你打算出于其他目的给猫分类,那么也许【正确】答案会有所不同。目的或目标来自人类决策者!靠边站柏拉图;不同的答案将适用于不同的项目。在人工智能中,客观总是主观的。由项目的所有者来决定那些主观的提议。(其他每个人都应该明白,人工智能系统有很多主观性。)
在人工智能中,客观总是主观的!人工智能系统有很多主观性。
决策者必须充当负责任的家长挑选他们希望他们的系统复制的行为……几乎从来没有一个“正确的”方法来定义类别并设定每个决策者都会同意的目标。那些事情取决于个人。不同的人会发现不同的行为适合复制。
如果你继承了我的系统,并且你的意图与我的不同,或者如果你计划将它用于不同于我设计它的目的——例如,如果你在什么应该被称为猫的问题上与我的观点不同——你可能会发现我的系统不适合你。它甚至可能伤害你,尽管它让我非常开心。
如果发生这种情况,那就是你的错,而不是我的。你太蠢了,以为只有一种方法来定义事物。你认为一个有数学成分的系统不可能有歧义和人类的弱点,所以你最终找到了一个解决错误问题的好方法,因为这不是你的问题(是我的问题),而是 T2 的问题。
你应该总是测试别人开发的人工智能系统,尤其是当你不知道他们是如何定义他们的目标的时候。
我是不是在说,你不能使用其他 AI 工程团队开发的系统,每次都必须从头开始构建自己的系统?一点也不。然而,你确实需要对正确执行你的任务意味着什么形成你自己的清晰想法(例如,如果有一只老虎该怎么做),你需要仔细测试你正在考虑继承的一系列你自己的例子的系统(例如你手工标记的照片)。
什么是地面真相?
你可能听说过术语“地面真相”在 ML/AI 领域流传,但是它是什么意思呢?新闻快讯:地面真相不是真的。这是一个理想的预期结果(据负责人说)。换句话说,这是一种通过创建一组带有输出标签的例子来总结项目所有者意见的方法,这些标签是那些所有者觉得合意的。它可能涉及手工标记示例数据点或将传感器“放在地上”(在一个精心策划的真实世界位置),以收集所需的答案数据,用于训练您的系统。
新闻快讯:地面真相不是真的。
例如,根据项目负责人的意见,一组图像可能被煞费苦心地手工标记为猫或非猫,这些猫/非猫标签将被称为该项目的“真相”。

这到底是什么?!猫还是不猫?看电影猫的预告片诱惑我漂白眼睛。
当这样一个数据集被用来训练 ML/AI 系统时,基于它的系统将继承并放大那些决定理想系统行为对他们来说是什么样子的人的隐含值。
当我们创造基于数据的机器系统时,我们教给他们我们的价值观。
当我们谈到这个话题时,请注意,通过让可信任的人执行您的任务来创建“地面真相”会出现各种错误,包括人为错误。尝试通过基于共识的数据收集工作流、反应时间监控和减少数据输入错误可能性的巧妙用户体验(UX)技巧等方法来最小化这种错误的可能性是一个好主意。(在以后的文章中会有更多的介绍。)
让你的项目决策者审查一个随机的样本来检查质量是否足够高总是一个好主意。
如果你在网上找到一个数据集并使用它而不是收集你自己的呢?那么你的项目就继承了创建你的数据集的人的隐含价值和偏见。在这个过程中总会有主观的判断,无论是谁做出这些判断,都会为你的项目确定“对”和“错”。小心你信任的人!决策者花时间亲自执行任务,以更好地理解他们试图解决的问题,以及数据、目标和边缘案例,这有很多值得说的。

警告(如何做一个好公民)
我写了很多赞扬仔细测试 ML/AI 系统的文章,但是要小心!由于整个过程从根本上邀请定义和目标的主观性,所有的测试将根据你的团队的决策者喜欢的答案来完成。不幸的是,首先没有测试这些主观想法的愚蠢程度。除了其他决策者审查他们在项目第阶段所做选择的理由之外,对决策者没有制衡。
没有测试来检查主观定义和目标的愚蠢,所以明智地选择你的项目负责人。
现在你知道了所有人工智能/人工智能项目的第一部分是多么主观,你可以在一个日益人工智能泛滥的社会中成为一个更好的公民。不要轻信人工智能解决方案,而要经常问自己:
- 这个系统是谁建的?
- 他们的(主观)目标是什么?
- 他们是如何定义正确答案的?
- 大多数人会有相似的定义吗?
- 地面真实数据集是如何创建的?
- 这个系统打算让哪些人受益?
- 犯错会有多痛苦?
- 是否有合适的 安全网 内置?(系统的创建者是否谦逊地预见到他们的选择可能是不明智的,并据此制定计划?)
在许多情况下,你对这些问题的回答不会暴露任何可怕的东西。人工智能已经围绕在你的周围,在很大程度上,它设计得很好,很有营养。唉,偶尔你会发现自己身处困境。例如,你不会想成为短视的欺诈检测系统的受害者,该系统对金融欺诈的定义很草率,特别是如果这样的系统被允许错误地指控人们,而不给他们一个简单的方法来证明自己的清白。那种事情是自找麻烦的火药桶。作为一个负责任的公民,你应该注意到易燃的情况,并大声说出来。一旦你开始看到人工智能游戏中固有的主观性,你将更好地武装自己,召唤出丑陋的人类元素,如果没有人观看,这些元素可能会被放大。
关于如何明智地处理这些模糊的主观想法,请看我的《终极决策者 AI 入门指南》。
感谢阅读!人工智能课程怎么样?
如果你在这里玩得开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的娱乐课程:
在这里欣赏整个课程播放列表:bit.ly/machinefriend
喜欢作者?与凯西·科兹尔科夫联系
让我们做朋友吧!你可以在 Twitter 、 YouTube 、 Substack 和 LinkedIn 上找到我。有兴趣让我在你的活动上发言吗?用这个表格联系。
在对话式人工智能中,精确和回忆(嗯)不是你最好的朋友
这些指标实际上是不相关的对话情况下,导致误解和过度自信
为了让对话助手自动响应用户的请求,有必要训练用户正确识别问题,从而触发正确的场景。为此,工业解决方案(即聊天机器人解决方案)大多使用机器学习来执行这种检测,方法是创建一个模型(学习过程的结果)来按意图对请求进行分类。学习方面的文献建议我们通过精度和召回指标来检查模型的性能。从经验来看,我发现这些指标实际上在对话情况下是不相关的,会导致误解、过度自信,并最终成为分析师的诱饵。我建议使用关键成功指数(CSI ),但由于它仍然不够,通过分析我们的老朋友和新朋友的无偏变异系数来完成这一指标。

插图照片。照片由 gratisograph-Pexels 提供
介绍
在对话式人工智能中,系统必须“理解”用户的请求,然后才能执行所请求的操作(例如,“开灯”、“给我点一份披萨”、“我如何才能关掉电视”等)。).为了做到这一点,这些系统使用了一种机器学习技术,其中包括从具有相同含义的句子分组中自动创建分类模型,这些句子隐含着相同的意思。为此,对话人(即编写对话助手的对话的人)必须监督检测器(分类器)的训练,向其提供一组例句,并按意图(按请求类型)对其进行分组。

天气预报助手的例句
在学习之后,必须对系统进行测试,以确保它足够“聪明”来理解所有的请求。尤其是因为这些系统被用于检测需求的能力,即使需求与预期不同。关于用户请求处理的描述,你可以参考我以前的文章《对话人的对话式人工智能:4 个复杂等级》。
为了测试他的助手,对话人必须问一些不在训练中的问题,并检查系统是否检测到意图,尽管他会引入一些变化,以验证系统能够提取不同的句子。例如由于训练不足而导致的训练缺陷会给用户带来负面影响,因为系统会触发与其初始请求不对应的动作。

不良检测示例
该理论
在自动分类中,精度(也称为正面预测值)是所有建议项目中相关信息的比例。召回率(敏感度)是所有相关项目中建议的相关项目的比例[1]。
当对话助手正确回答了 20 次(也称为真肯定或 TP),执行了 10 次不是请求的动作(称为假肯定或 FP),没有执行预期动作 40 次(称为假否定或 FN),则其精度则为 20/(20+10) = 0.667 (66.7%),其召回率等于 20/(20+40) = 0.334 (33.4%)。能够无错误检测的系统具有等于 1 (100%)的精确度和等于 1 (100%)的召回率。

在训练阶段之后,用一个意图的不同测试短语来测试分类器(然后是下一个)。每个测试的结果根据识别的意图进行排序。

计算二进制系统的精度和召回值(检测到或未检测到)
在多类系统中(在我们的例子中,是多意图系统,因此它涉及所有会话助手),整体系统精度是所有意图精度的平均值,召回率是所有意图召回率的平均值。这些值被称为精度的宏观平均值和召回的宏观平均值。

多类系统中查准率和查全率的计算
计算每个意向的精确度和召回率,并对总体结果进行平均。真正的肯定结果对应于对意图的正确检测。假阴性对应于我们的意图测试句子给出另一个意图作为结果(其他意图之一)的情况。假阳性对应于给出那个意图的其他意图的句子。真正的否定对应于所有其他没有给出我们想要的结果的测试。
还有另一个指标是精度的微平均值,它对应于不同类别的 TPs 之和除以 TPs 和 FPs 之和。该计算包括对分母中的所有值求和,这导致最终成功率的计算。
为了测试该系统,对话方准备一组测试短语(称为验证数据集),该组测试短语由不属于训练(称为训练数据集)的短语组成。每个句子都与其中一个意图相关联。
还可以使用自动测试技术,根据取决于所选交叉验证类型的规则,将可用数据分成训练数据和测试数据。在非交叉分离中,选择一个比率将数据分成两组。通常使用 50/50、66/33 或 80/20 的比率。然而,如果数据数量较少,将可用数据分成两个不相交的子集会产生检测偏差。这些偏差可能是拟合不足或误差过大。

将数据分为训练和验证数据的示例
这个问题的一个解决方案是使用交叉验证技术,通过称为 k 折叠的折叠来分离集合。k 折叠建议将数据分离成 k 个折叠。保留一个折叠用于测试,剩余的折叠(k-1)用于训练[2]。在对话人可以直接干预模型的系统中,该测试模式允许调整模型的超参数并在适当的时间(即在过度拟合之前)停止训练。

将数据分成多个文件夹的示例(k = 4)
在具有不平衡意图的系统中(即,每个意图具有不同数量的句子,这在对话解决方案中也是常见的情况),保持意图中的块比率是很重要的。这种技术被称为分层交叉验证。
在“现成的”对话式人工智能解决方案(即几乎所有的商业聊天机器人解决方案)中,不可能选择这些超参数,系统“自行”设置自己。这种黑盒侧使得很难知道系统是否是工厂预设的,或者它是否使用内部交叉验证和早期关闭功能自动适应。
实践
让我们以一个四意图系统为例,它由一个专门为验证而创建的测试集构成。假设它在第一次业务迭代之后被训练,即主题专家已经给出了一组句子,根据他们,这些句子对应于需要自动化的领域的最常见的用户请求。让我们假设测试的第一阶段给出了以下结果:

TEST_1:第一次测试活动的结果
使用测试句子(每个意图 20 个句子)来测试分类器,并且在称为混淆矩阵的表格中记录检测的结果,该表格被分成用于要被测试的意图的行和用于被检测的意图的列。交叉点处的数字对应于测试意图的检测出现次数。
在示例 TEST_1 中,第一意图的 20 个测试短语被正确分类了 16 次,并且发现了 4 个错误。在 80 个测试短语中,59 个短语被全局正确地检测到,21 个导致分类错误。该分类器的平均准确率为 74%,召回率也为 74%。成功率(正确识别的句子/句子总数)给出了 74% (59/80)的结果,这对于第一次迭代来说是相对正确的。
在完成整体训练的第二次迭代之后,用初始测试句子再次测试系统。这一新测试给出了以下结果:

TEST_2:第二次测试活动的结果
新的成功率与之前的培训相同,即 59/80 = 74%。Intent 3 测试的准确率是 100%,召回率是 5%。这组平均值意味着该训练的总体精度为 80%,召回率为 74%,即精度提高了 6%,召回率相同,而结果在 intent 3 测试中急剧恶化,实际上不再被识别。因此,对整体精度的分析给出了肯定的结果,然而由于系统实际上将不再能够回答一类问题,因此用户体验严重下降。只有对每个意图的精细分析才允许在新的训练之后检查系统的发展。
假设分析师在意图 3 上执行了额外的工作来纠正已识别的问题,增加了对这个意图的了解,并执行了一组新的测试。

TEST_3:第三次测试活动的结果
新的成功率为 74%,与其他 2 次试验相同。准确率为 87%,与之前的测试相比提高了 7%,召回率为 74%,这个值在所有测试中都保持不变。对于分析师来说,系统显示了精度的整体进展,这表明系统的改进!通过更详细地分析结果,我们可以看到,意图 3 现在被过度检测,该意图的精度几乎为 20/41 = 49%,低于之前的测试。从用户的角度来看,这最终是最重要的,系统给人的印象是系统地触发相同的动作(50%的请求和 25%的请求是合理的)。
因此,对精确度总体变化的分析不会发现任何分类错误。在这些病例中,对召回的分析也是不确定的,因为它在 3 次测试中没有变化。从测试者的角度来看,未检测或错误检测之间的区别对于分析结果和确定要对培训执行的操作(创建新的意图、将它们组合在一起、向意图添加句子……)非常重要。
然而,从最终用户的角度来看,重要的是系统在大多数情况下都能正确响应,并且对这些值的整体分析会遗漏那些会影响用户体验的错误。当然,分类器的性能必须是全局平衡的。然而,对于不太频繁的请求,可以设想不太好的检测。然后有必要将结果与请求的频率相关联,但这是另一个主题。
关注不平衡的系统
测试分类器的性能时,考虑测试集的平衡并尽可能在每个意图中使用相同数量的测试值是很重要的。
为了突出这一点,让我们尝试另一个例子。我们正在执行检测测试,但我们没有一个平衡的系统,因为测试句子的数量根据意图而变化:意图 1 只有 10 个测试句子,意图 2 有 20 个,意图 3 最完整,有 45 个句子,而意图 4 只有 5 个句子。
该测试给出了以下结果:

第一次测试的结果
我们有以下指标:准确率= 86%,召回率= 84%,成功率= 86%。为了平衡结果,有必要引入加权指标的概念。不同类别的各个指标的值必须乘以用于测试的句子的比率。意向 1 的比例是 10/80 = 0.125。加权后的指标是加权精度= 87%,加权召回率= 86%。
我们修改培训,试图改善我们的系统。

第二次测试的结果
这些指标具有以下值:对于 90%的成功率,精确度= 80%,召回率= 89%。加权准确率为 93%,加权召回率为 90%。在没有加权的计算中,我们会看到精度下降了 6%,而系统总体上有所改善,这由加权值显示,因为我们看到精度提高了 7%。这个非常重要的区别来自于实例 4 的权重与其他类相同,而这个实例的测试数量很少。实例 4 的测试数量少意味着一个坏结果的影响给了这个实例的测试结果很大的权重,这里突出显示了这一点。
那么选择哪个(些)指标呢?
我们已经看到,精度和召回指标没有突出局部分类错误,这可能会对整个系统不利。在 TEST_3 的情况下,系统在四分之一的请求中检测到不良意图,这将最有可能导致对话助手的拒绝。此外,精确度和召回率集中在 2 个不同的轴上:第一个轴强调假阳性问题,而第二个轴强调假阴性问题。对于用户来说,这仍然是一个错误的答案,因此我们需要一个新的指标来将这两个轴组合在一起。
这个指标是存在的(尽管它不太明显),而且它是关键成功指数(CSI ),在其他地方的天气预报中被广泛使用。它也被称为威胁分值 TS。CSI 是用于分类检测的性能验证措施。它等于正确事件预测的总数(TP)除以错误检测的总数(FN + FP ),再加上 TP 就得到一个性能比。
为了在上线前完成我们的测试,我们正在进行一项新的培训,在全球范围内改进我们的模型,将其置于完全可操作的水平,准确率为 90%,召回率为 89%,成功率为 89%。

TEST_4:第四次测试活动的结果
然后我们计算几个指标,你会发现这些指标列在这个维基百科页面上。

不同测试的性能指标值
对该表的研究表明,没有指标真正突出了 TEST_2 和 TEST_3 分类器的问题。只有指标 CSI、F1-score、Matthews 相关系数(MCC)和 Fowlkes-Mallows 指数突出了 TEST_2 分类器的质量下降。没有检测 TEST_3 问题的指标。CSI 指标最接近整体系统性能的预期,这使得它比精确度、召回率甚至准确度更相关。
由于指标没有给出任何指示,我们不得不查看每个意图的价值测试的细节,以确定哪些意图是有问题的。

按意图的分类器得分
由于这项工作在大量的测试和许多目的上是单调乏味的,我建议使用一个叫做变异系数(或相对标准偏差)的离差指标。该指标定义为标准偏差与平均值的比率[3]。这个没有单位的数字允许在几个系列之间进行比较,这对于自动化测试来说很有趣。然而,考虑到样本数量较少,必须调整该值。这一指标的公式如下:

无偏变异系数
在我们的 4 次测试中,该指标的计算给出了精度、召回率和 CSI 的以下结果:

精确度、召回率和 CSI 指标的调整变异系数的计算结果,并突出显示最大值
因此,超过这 3 个值之一的阈值(例如 20%)可以用于通知分析师培训质量问题。这一指标补充了业绩指标的经典分析,例如整体精确度低。当达到阈值时,建议更仔细地分析结果,以便确定有问题的意图,从而了解如何修改训练,或者甚至拒绝新的训练。
结论
在会话助手领域,系统拒绝的原因之一是它们不能正确识别请求。因此,在发布助手并提供给用户之前,测试助手的性能非常重要。我们已经看到了如何计算多类系统的精度和召回值,以及当测试句子的数量不平衡时,对这些值进行加权是多么重要。然而,机器学习中最常用的精度和召回指标不允许我们得出一个系统是否在一个或多个意图上不包含错误的结论,因为我们只是在研究一个全局值。
因此,我邀请您通过添加 CSI 指标来完成您的计算,CSI 指标与用户期望更相关,即尽可能经常正确响应的助手(无论 I 型或 II 型错误)。通过计算精确度、召回率和顾客满意度指数的调整变异系数(无偏)来完成本指标。将警报阈值设置为这三个值中的最大值,可以让您突出显示学习问题,而不必逐个检查指标,从而节省分析训练迭代的时间。
参考
[1].精确和召回—维基百科—https://en.wikipedia.org/wiki/Precision_and_recall
【2】。交叉验证—维基百科—https://en . Wikipedia . org/wiki/Cross-validation _(统计)
【3】。变异系数—维基百科—https://en.wikipedia.org/wiki/Coefficient_of_variation
数据库中的机器学习:我们就不能好好相处吗?

意见/供应商观点
简单看看 Splice Machine 最近融合 ML 和关系世界观的努力
如果数据在企业内部驱动机器学习(ML),如果企业数据存在于数据库中,那么为什么两者不能和睦相处?为什么数据科学家用来构建 ML 结果的 ML 算法、模型和其他工件在物理上距离它们所依赖的数据如此之远?
简单的回答是,数据科学的工作方式不同于数据库,尤其是传统的关系数据库管理系统(RDMSes ),它强调定向事务,新数据随着时间的推移不断增加。相反,ML 项目是高度迭代的,探索性的,完全实验性的。
即使是最直接的企业 ML 项目,如预测客户流失,数据科学家也必须安排一个极其复杂和高度迭代的工作流程。这些工作通常在像 Project Jupyter 这样的基于 web 的笔记本环境中进行,需要不断地与支持性数据库资产进行交换。随着 ML 项目的临近和进入生产,这种来回变得更加困难和关键。这是 ML 的“最后一英里”问题:企业如何更快地将 ML 项目投入生产,然后随着时间的推移成功地将它们保持在那里。
作为回应,技术提供商开始推出更多生命周期完整的人工智能开发工具,如 AWS Sagemaker 套件。有趣的是,除了 AWS 广泛的数据库组合之外,这个神奇的工具独立存在,从任何和所有可用的数据存储中提取数据。但这并不意味着两者合不来。许多数据库供应商希望通过将 Sagemaker 所做的一些事情转移到数据库本身来参与其中。
表格功能:旧思想的新生命
一个恰当的例子是,数据库供应商 Splice Machine 在其最近的版本( version 3.0 )中引入了一种有趣的方法,使用一种古老的数据库技术来解决 ML“最后一英里问题”。供应商已经嵌入了自己的 Jupyter 笔记本环境实现,该环境可以支持 Python 和 r 之外的多种语言。该环境利用了流行的 ML 生命周期管理平台 MLflow 的产品内实现。或者,模型可以部署到 AWS SageMaker 或微软 Azure ML 。
使用这些工具,开发人员可以调用一个“deploy()”函数来将他们的最终模型推向生产。该函数采用最终的 ML 模型加上支持的数据库表,并在数据库中自动生成代码作为表函数(类似于存储过程)。每当新记录进入数据库时,这个原生表资源就会执行,生成新的输出预测。
这种方法的固有优势包括大大简化了模型部署例程,更好地了解关键的部署后问题(如模型漂移),由于数据不必离开数据库而提高了性能,以及由于解决方案包含自己的容器管理平台而减轻了管理负担。转化为业务成果,这意味着交付 ML 解决方案所需时间的显著减少,以及长期维护该解决方案的成本的降低。
这是在企业中实施 ML 问题的唯一解决方案吗?当然不是。与任何现实世界的 ML 实现一样,期望的结果取决于所选工具和可用资源(技术和专业知识)之间的完美结合。幸运的是,由于 ML 市场严重依赖开源软件,企业购买者可以混合搭配语言、库、编排器等。
这也意味着买家可以投资像 Splice Machine 这样的基于数据库的解决方案,并且仍然可以利用熟悉的资源。目前 3.0 版本可以把模型推送到比如 AWS SageMaker 和微软 Azure ML。在未来,Splice Machine 很可能允许用户运行其他 ML 编排工具,如 Kubeflow 与 MLflow 并行或代替 ML flow。
我们应该会看到更广泛的数据库社区使用这种方法进行更多的投资。Oracle 最近已经开始将许多 ML 特性推送到 Oracle 自治数据库中;微软也这么做了。接下来还会有更多,尤其是随着行业开始处理更多极端环境下的 ML 用例(制造业、医药、石油和天然气等)。),其中时间和性能是最重要的。
数据库机器学习—变得简单
包含代码的端到端指南

照片由皮卡在土坯库存上根据许可从 Zer0 到 5ive 拍摄
**免责声明:我是拼接机*的机器学习负责人
如果你点击了这篇文章,我不需要说服你,机器学习是一个改变游戏规则的工具。构建 ML 模型现在是可访问的、容易的、初学者友好的(大部分时间)。然而,部署这些模型是另一回事。简单性、可伸缩性和推理速度只是您必须克服的一些障碍。
创建 ML 模型的最大问题之一是,模型是在对部署无用的环境中构建的。也许你已经用 Python 启动了单实例 Jupyter 笔记本。您可以集成 Spark 进行大数据处理,这很好,但由此产生的推理速度非常慢。也许您已经用 Flask 创建了一个将您的单个模型投入生产的管道,这是可行的,但是它缺少可再现性(和潜在的可伸缩性)。也许 Python 对于您的实时用例来说太慢了。
根本的问题是,机器学习部署是一个年轻和不成熟的领域,它还没有开发出数据库或软件开发所拥有的工具包。例如,数据库广泛可用,稳定,(有时)可扩展,速度极快。正因为如此,我们将借鉴数据库工程师已经完成的工作,并利用他们的工具为我们服务。这里,我们将重点关注使用横向扩展 RDBMS 进行模型部署。
在本文中,我将带您使用熟悉的工具构建一个机器学习模型,并将其部署到数据库中。为了获得完整的体验,你可以在这里创建一个免费的沙盒环境,和我一起浏览这些例子。
TL;博士笔记本位于这里,有输出的笔记本的要点是这里。要直接跳到本文的模型部署部分,请单击这里的按钮
获取环境
首先,在这里创建一个免费的沙盒环境。准备好数据库后,单击数据库名称进入仪表板。

数据库名称
在那里,您可以单击“检索数据库密码”来获得您的登录。

获取数据库用户名和口令
一旦你有了,点击“笔记本”来启动你的 Jupyter 笔记本实例。

启动您的 Jupyter 笔记本
您将被提示输入您的用户名和密码,这是您刚刚在仪表板上看到的。这需要一分钟左右的时间。
现在您已经进入了笔记本环境,您将创建一个新的笔记本,选择 Python 3 作为您的内核。使用的整个笔记本将在这里可用
您将构建一个 Spark 模型来预测虹膜数据集,以保持演示简短,但这可以扩展到任何数据集(任何大小)。

选择你的环境
首先,您将创建您的 Spark 会话。配置设置是在幕后为您处理的,所以只需运行下面几行就可以开始了。
创建 Spark 会话
在任何时候,您都可以通过运行以下代码来检查您的 Spark 控制台
获取 Spark UI
这将返回一个交互式窗口,您可以在其中观察您的 Spark 作业,并在它们运行时深入研究它们。
既然已经有了 Spark 会话,就可以获得 MLFlow 会话和本机数据库连接了。你可以在这里了解更多关于 MLflow 的信息,在这里了解更多关于原生 Spark 数据源的信息。
MLFlow 和 NSDS 的设置
这些行将自动配置您的 MLflow 会话并将其连接到数据库。
最后,您将开始您的 MLflow 实验,并运行以表明您即将构建您的第一个模型。就像使用 Spark 一样,您可以使用类似的命令查看 MLflow UI。
MLFlow 开始实验并运行
建立模型
现在您已经连接了,您将加载数据并构建您的第一个模型。这一部分将会更短,因为它侧重于部署,但是您可以通过单击“拼接笔记本”文件夹,然后单击“7”来访问您的试用集群的 Jupyter 笔记本中更长、更深入的示例。MLManager "

访问拼接笔记本文件夹

访问更多 MLManager 示例
现在,您将加载 iris 数据集,并将其转换为用于训练的 Spark 数据帧。
您将在这里为分类构建一个简单的决策树模型。
建立火花模型
如果你愿意,你可以在 MLflow 中记录一些信息来跟踪你做了什么。至关重要的是,您将把您的模型记录到 MLflow 中,以便您可以部署它。
将参数、度量和模型记录到 MLFlow
部署您的模型
就是这样!您已经创建了一个简单的 Spark 模型。现在是时候将它部署到数据库中,并利用 SQL 与它进行交互。您将使用 deploy_db 函数来实现这一点。这个函数有许多可选参数,您可以在这里深入研究,但是现在,简单地说:
- 方案名:要部署到的表的方案
- 表名:要部署到的表
- 运行 ID:存储模型的运行 ID
- 创建模型表:是否为我们创建表
- Df:作为表格基础的数据帧
- 主键:表的唯一标识符列
- 类别:类别标签名称(鸢尾属、弗吉尼亚属、刚毛属)
部署 ML 模型
就这么简单。幕后发生的事情是,作业被提交给代表您处理请求的服务器。最后一行调用 watch_job 获取从服务器自动传入的日志,这样您就可以实时看到发生了什么,并在出现问题时进行调试。
现在您已经部署了您的模型,您将进行一些预测。通过用%%sql 启动单元格,您可以在笔记本中运行 SQL。这是一个定制的魔术,允许你直接对你正在工作的拼接机器数据库运行 SQL。
使用 SQL 调用模型
最后,你可以停止你的火花会议,结束你的跑步。这不会影响 SQL,并且您可以通过插入新行来继续与部署的模型进行交互。
结束我们的会话
包扎
就是这样!您已经创建了您的机器学习模型,对其进行了跟踪,并将其部署到数据库中,以提高可扩展性、可用性和速度。这个简单的例子可以扩展到 Scikit-learn(可以在文件夹“7。MLManager”)或大规模数据集和复杂管道的困难问题。您甚至可以用触发器将模型(表)链接在一起。要查看其他一些示例,请参见 7 中的笔记本实例附带的 splice_notebooks 文件夹。MLManager 文件夹。
感谢您坚持使用我的例子!如果你有任何问题,请在文章中发表,我一定会回复。
为 DIY 数据科学家辩护

西蒙·艾布拉姆斯在 Unsplash 上拍摄的照片
教会自己如何解决问题很酷
有些人从正规教育开始他们的数据科学之旅。他们在大学里学习基本的数学、编程和统计学。他们带着熟练的学位进入数据科学领域。
但是许多其他人没有。相反,他们自己拼凑知识。他们在需要的时候会把需要的东西挖出来。他们是自学的;DIY。
虽然每个人的旅程都有点不同,但如果你是一名 DIY 数据科学家,你的机会可能包括以下一项或多项:成为 excel 的专家用户,被迫学习一些编程,解决工作中与数据相关的问题,由同事或朋友介绍机器学习,学习一些算法的功能,使用 scikit-learn 建立模型,参加 Kaggle 竞赛。
这些活动中的许多都属于“应用数据科学”的范畴——使用已经整齐地打包在一起的代码来实现复杂想法的快速应用。
这些资源的可用性存在一些问题。知识有限的人会犯错。他们应用事物不正确。他们愚弄自己。
关于让错误的人或错误的情况与数据和数据科学工具一起失控所导致的问题,有大量的警告。
但是也需要用乐观和前瞻来平衡围绕民主化的怀疑。
事实上,我认为“应用”是未来的方向,正如它塑造了过去一样。
作为一个社会,我们学习一些东西,我们把它打包在一起,让它更容易使用和建立。所有的建设者也是用户——利用跨越时间和人类进步的长桥的工具和结构。
几乎每个人都会使用电脑,但只有少数人能详细解释晶体管的物理原理和将互联网浏览降低到 1 和 0 的代码。
当然,拥有这些知识的人可能是世界上“最好的”计算机用户。但是一般人用电脑能不完成很多令人印象深刻的事情吗?
许多 DIY 数据科学家的旅程将只在这个应用世界中进行。他们将用必要的工具和知识来武装自己,以解决越来越多的问题。当然,他们应该被教导要小心谨慎,但是怀疑他们创造价值的能力是愚蠢的——尤其是当 T2 工具变得更好的时候。正如数据问题存在于光谱中一样,解决这些问题所需的技能也存在于光谱中。
一些 DIY 数据科学家的旅程不会停留在基础应用上。他们将继续攻读本科和硕士学位,以补充他们的知识。或者他们会找一个小众,深入学习。或者他们会如此深入地自学以至于他们的知识达到或超过那些受过正规教育的人。
其他人,特别是那些拥有多种技能的人,将继续建立和领导公司——利用他们的数据素养在日益数据驱动的世界中创造价值。
最后,让我们面对现实吧。自学的人有令人钦佩的地方。
通过在线课程奋力拼搏的人们。那些晚上和周末都在调试代码和学习新工具的人。那些充满动力和激情,克服无数挑战来解决问题的人。至少,这种程度的坚韧说明了职业道德和内在动力。
自学如何解决问题很酷。
为神经结构搜索的权重共享辩护:一个优化的观点
如何优化正确的几何形状,以实现更好、更快的神经结构搜索。
CMU 和决心艾的合作作品由米沙·克达克和利亚姆·李共同创作。

图 1: 动画演示飞镖和其他权重分配方法如何用其输出的 θ 加权组合来替换四个运算 o ∈ O 之一到边 e 的离散分配。在网络的每个边 e 处,输入节点 eᵢₙ 处的值传递给 O 中的每个操作={Conv 3x3,Conv 5x5,池 3x3,跳过连接};输出节点 eₒᵤₜ处的值将是由满足σₒθₑₒ= 1 的参数θₑₒ∈【0,1】加权的运算输出的总和。
神经架构搜索(NAS)——选择哪种神经模型用于你的学习问题——是一个有前途但计算昂贵的机器学习自动化和民主化的方向。权重分配方法最初在大幅加速 NAS 方面的成功让该领域的许多人感到惊讶,但由于其作为完整模型训练的替代品的糟糕表现(一种被称为等级混乱的错误关联问题)以及最近基准测试的不一致结果,它已经受到了审查。在本帖中,我们简要介绍了重量共享,并支持在 NAS 中继续使用它。为此,我们将考虑一个简单的优化公式,它揭示了以下关键要点:
- 对于一个支持过参数化模型的非凸优化的社区来说,权重共享工作的事实不应该太令人惊讶。
- 对于大多数权重分配方法来说,等级无序并不重要,因为我们关心的是获得高质量的架构,而不是它们的等级。
- 重量共享的性能有时很差,这是优化问题的结果,可以在仍然使用重量共享的情况下修复这些问题。我们提出了这样一种修复方法——几何感知指数算法(GAEA ),它适用于许多流行的 NAS 方法,并在多种设置下实现了最先进的结果。
具有重量共享的 NAS 简史
NAS 通常被公式化为一个双层优化问题,其中我们在某个体系结构域 A 中搜索实现最低验证损失的体系结构a∈a**ℓⱽ(wₐ,a) 在训练最小化训练损失的权重 wₐ 之后:

第一代 NAS 方法非常昂贵,因为搜索空间非常大,需要训练数千个神经网络才能完成。然后,在他们的 2018 ENAS(针对高效 NAS) 论文中,Pham 等人引入了权重共享的思想,其中只有一个共享组模型参数 w ∈ ℝᵈ 被训练用于所有架构。使用这些共享权重计算的不同架构的验证损失 ℓⱽ(w,a)**a∈a然后被用作使用独立权重 wₐ (即通过解决上述内部优化问题为每个架构单独训练的权重)的验证损失 ℓⱽ(wₐ,a) 的估计值。因为只需要训练一组参数,重量共享导致了比早期方法大幅度的加速,将 CIFAR-10 上的搜索时间从2000-20000GPU 小时减少到仅 16 小时。令许多人惊讶的是,使用共享权重计算的验证精度 ℓⱽ(w,a)w足以替代 ℓⱽ(wₐ,a) ,这意味着 ENAS 能够廉价地找到好的模型。我们将会看到,这种相关性实际上是重量共享做得好的一个充分条件,但不是必要条件,重量共享的整体成功并不像最初想象的那么令人惊讶。
继 ENAS 突破之后,提出了几个更简单的方法,例如飞镖和 GDAS ,其中分类架构决策(例如,对于每个网络边 e ∈ E ,在 e 处使用的某个固定操作集合 O 中的哪些操作被放宽到连续参数θ∈θ(例如,因此θ是|的乘积如图 1 中的动画所示,这些架构参数控制用于使用训练损失的梯度来更新共享权重的架构;例如,在飞镖游戏中, θₑₒ 决定了网络中边 e 输出的操作的加权和中的权重。总的来说,这种参数化导致了早期双层问题的连续松弛:

由于θ是 ℝᴱᴼ 的约束子集,DARTS 和 gda 通过重新参数化“logit”参数 α ∈ ℝᴱᴼ 来避免单纯形投影,其中 θ = Softmax (α) 定义为

然后,可以通过下面的交替梯度更新方案(这里η > 0 是步长)来近似松弛的优化问题:

注意,在搜索的最后,我们需要从架构权重 θ 中恢复出一个离散架构A∈A;在 DARTS 中,这是在修剪步骤中完成的,该步骤简单地选择最高权重的操作。这种事后修剪是我们的方法 GAEA 可以改善的误差源,我们将在后面讨论。
进一步的简化,也许是使用共享权重作为独立权重替代的最显著的例子,是权重共享随机搜索 (RS-WS)方法,其中共享参数通过使用从搜索空间均匀随机采样的架构采取梯度步骤进行优化。尽管没有更新架构参数,RS-WS 还是取得了有竞争力的,在某些情况下,是最先进的结果。
我们应该使用重量共享吗?
最近,体重分担受到了越来越多的关注:在模特之间分担体重真的能加速 NAS 吗?它会阻碍最佳架构的恢复吗?特别是,几篇 论文已经观察到出现了排名混乱的问题,即当架构的共享权重性能与其独立性能没有很好的关联时;下图说明了这个问题。对于诸如 RS-WS 之类的依赖于共享权重性能来对架构进行排名以进行评估的方法来说,排名无序是一个问题,因为当其参数在没有共享的情况下被训练时,这将导致它们忽略实现高准确度的网络。

图 2:Yu et al .2020排名混乱问题的图示当使用共享权重评估的架构的性能排序(右)与从零开始训练单个权重时的真实架构性能(左)不匹配时,就会出现这种情况。
最近一些著名的减肥方法表现不佳的案例强化了这种怀疑;特别是,在最近的鲁棒性评估中,发现 DARTS 过度适合上层验证集,并且在 NAS-Bench-201 上,给定类似的时间预算,GDAS 和 DARTS 都优于标准超参数优化方法。这里 DARTS 的性能特别差,收敛到只包含身份映射(跳过连接)的架构。
考虑到体重共享引发的问题和最近糟糕的结果,是时候重新考虑它的使用了吗?在下一节中,我们给出了否定的答案,表明(a)权重共享“超网”的性能与完全训练的模型的性能之间的相关性是权重共享起作用的充分但非必要条件,即我们不需要害怕排序无序;以及(b)使用权重共享获得高质量的架构解决方案主要归结为正则化和优化,这是机器学习的两个众所周知的方面。在最后一节中,我们快速强调了 NAS 中最近在正则化方面的一些工作,然后介绍了我们自己在优化方面的工作。
普通的重量分担只是经验风险最小化
权重共享之所以成为可能,是因为与正则化和步长等超参数不同,架构参数直接影响损失函数,因为从一种架构 a ∈ A 改变到不同的架构a’∈a导致损失从 ℓ(w,a) 改变到 ℓ(w,a') ,因为在后一种情况下,不同的函数被用于预测。另一方面,改变步长设置不会改变损失,除非通过使用新的步长训练 w 来改变权重;这意味着不同的超参数设置不再共享权重。
事实上,我们可以利用架构参数可以被归入超网的参数这一事实,在由权重 w ∈ ℝᵈ 和架构参数θ∈θ编码的一类扩展函数上,将具有权重共享的 NAS 作为经验风险最小化(ERM):

大多数(但不是所有的)关于 NAS 的经验工作都使用前面描述的两层公式,而不是解决这个单层 ERM 问题。然而,我们认为 ERM 应该是 NAS 研究的基线对象,因为它在统计和算法上更容易理解;更常见的双层优化可以被视为一种(可能是关键的)通过分割数据进行正则化的方法。
单级公式清楚地表明,NAS 可能会因为 ERM 失败的两个常见原因之一而失败,而不是等级无序:优化失败或泛化能力差。例如,这些各自的故障可以在很大程度上解释前面讨论的 NAS-Bench-201 和 NAS-Bench-1Shot1 上的 DARTS 所面临的问题。当然,超网可能面临优化和泛化问题并不奇怪,因为它们是非凸和过度参数化的模型;但是 NAS 从业者通常很舒服的训练正则深网,它也是非凸的,参数几乎一样多。一个主要的区别是,在后一种情况下,我们已经进行了多年的密集努力来设计正则化 方案和优化 算法;如果我们在这两个问题上投入类似数量的 NAS 研究,那么我们可能不会比训练标准深网更害怕重量共享。
此讨论的一个注意事项是,NAS 面临着从不断放松的体系结构权重中恢复离散体系结构的额外挑战。我们接下来提出的优化方案通过首先提升稀疏架构参数来改善这个问题。
通过权重共享固定可区分 NAS:一种几何感知方法
我们上面的讨论将设计 NAS 方法的问题简化为为超网设计良好的正则化和优化方案的问题。关于超网的更好的正则化方案,最近有大量的工作,包括部分信道连接,惩罚确认损失的海森,以及双层公式本身;因此,我们转而专注于改进优化方案,这是通过我们的几何感知指数算法(GAEA)来实现的。
像往常一样,我们希望有一个优化方法,能够更快地收敛到更好的解决方案。在权重共享 NAS 的情况下,高质量的解决方案不仅具有良好的泛化能力,还会导致稀疏的架构权重θ∈θ,其召回与通过 softmax 优化的参数 α ∈ ℝᴱᴼ 有关。我们期望稀疏架构参数更好,因为如前所述,架构参数在后处理步骤中被舍入,以导出最终的分立架构。

图 3: 我们希望最终的架构权重 θ 是稀疏的,以便在舍入时,得到的离散架构 a ∈ A 接近由 θ 编码的超网。否则,分立架构的确认损失与超网的确认损失之间的差异可能非常不同。由于θ的元素位于单形的乘积中,稀疏性意味着,在每个单形中,单个元素为 1,其余元素为 0。
为了实现这一点,我们使用指数梯度下降来直接优化元素θ∈θ而不是无约束值 α ∈ ℝᴱᴼ 。更新方案用逐元素乘以负指数梯度 w.r.t. θ (4.a)来代替减去梯度 w.r.t. α (伪代码中的第 4 行),然后投影到包含 θ (4.b)的单纯形:

请注意,每次迭代的开销大致与 SGD 中的一样。
对于凸问题,已知指数梯度非常适合单纯形几何,其中迭代复杂度仅对数地取决于单纯形的大小 k ,而不是梯度下降的 O (k) 依赖性。在线性预测结果的镜像下降视图(视频链接)下,这种改进源于隐式正则化器在远离稀疏目标解时鼓励更大的更新。对于我们的非凸问题,我们通过扩展张&何最近的镜像下降结果来获得类似的保证,以表明将对架构参数的指数更新与对共享权重的 SGD 更新交替进行会在 O(log k / ε 次迭代中产生ε-驻点。我们还在图 4 中实验性地展示了这种方法比 DARTS 和 PC-DARTS 更鼓励稀疏的解决方案。


图 4:GAEA 获得的架构权重的稀疏性与它在两个不同的搜索空间上修改的方法相比较。稀疏性是使用跨架构决策简化的平均熵来度量的。
我们的 GAEA 方法适用于前面描述的使用 softmax 公式的任何方法(包括 DARTS、GDAS、PC-DARTS 等),可以总结为两个简单的步骤:
- 将传递给 softmax 的架构权重 α 替换为直接位于架构决策简化上的权重 θ 。
- 使用指数梯度方案(4.a & 4.b)来更新这些架构权重 θ 。
GAEA 的实证评估



图 5: 在 NAS-Bench-201 上对 GAEA 的评估。标准超参数优化方法用蓝色表示,而权重分配方案用紫色表示。搜索空间中的最优是黑色的。GAEA 是第一个在该搜索空间上优于标准超参数优化的权重共享方案,也是唯一一个在三个数据集(CIFAR-10 和 CIFAR-100)中的两个数据集上获得最优值的标准差以内的方案。
那么,从经验上看,GAEA 的稀疏性和更快的收敛速度会带来更好的性能吗?为了测试这一点,我们简单地应用上面的两个步骤来修改现有的最先进的 NAS 方法。首先,我们评估了 Dong 等人在 NAS-Bench-201 搜索空间上应用于 DARTS 的 GAEA。在 Dong 等人评估的方法中,非权重共享方法在所有三个数据集上都优于权重共享方法。但是,应用于单级 ERM 目标的 GAEA DARTS 在所有三个数据集上实现了最佳准确性,在其中两个数据集上达到了接近 oracle 的最佳性能。值得注意的是,它修复了飞镖在这个空间的灾难性的糟糕表现,并且是唯一击败标准超参数优化的重量共享方法。


图 6:GAEA 对飞镖搜索空间的评价。重量分担方法用紫色表示,而非重量分担方法用蓝色表示。请注意,非权重共享方法搜索所需的 GPU 时数是 GAEA 的 10,000 多倍。
我们还在原来的 DARTS CNN 搜索空间上评估了应用于 PC-DARTS 的 GAEA。通过改进权重共享优化问题的正则化,PC-DARTS 最近能够在 CIFAR-10 和 ImageNet 上匹配计算昂贵的非权重共享方法的性能。我们能够通过 GAEA 进一步提高 PC-DARTS 的性能,并在这个搜索空间上实现最先进的性能,这证明了在正确的几何结构中高效优化的重要性。
有兴趣了解更多信息吗?
要了解更多有关我们的结果、体重分担和 NAS 的信息,您可以
- 更多细节见我们的论文,与尼娜·巴尔坎和阿梅特·塔尔沃卡联合。
- 下载我们的代码以获得 GAEA 的完整实现。
- 阅读最初的重量分配方法 ENAS ,以及基线重量分配方法 RS-WS 。
- 阅读该领域的调查(埃尔斯肯、梅岑、&赫特、JMLR,2019)。
原载于 2020 年 7 月 17 日https://determined . ai。
基于经验风险最小化的正则化最小二乘算法的深入分析

作者图片—加拿大桑德湾
本文将介绍正则化损失最小化(RLM)和经验风险最小化(ERM)的关键概念,并通过 MATLAB 实现最小二乘算法。然后将使用 RLM 和机构风险管理获得的模型进行相互比较和讨论。
我们将使用多项式曲线拟合问题来预测该数据的最佳多项式。最小二乘算法将使用 MATLAB 逐步实现。
在这篇文章结束时,你会理解最小二乘算法,并意识到 RLM 和 ERM 的优点和缺点。此外,我们将讨论一些关于过拟合和欠拟合的重要概念。
资料组
我们将使用一个简单的具有 N = 100 个数据点的输入数据集。这个数据集最初是由 Ruth Urner 博士在她的一次机器学习课程作业中提出的。在下面的存储库中,你会发现两个 TXT 文件: dataset1_inputs.txt 和 dataset1_outputs.txt 。
正则化最小二乘算法用于回归以寻找机器学习模型。这个实现…
github.com](https://github.com/jaimedantas/least-squares-regression)
这些文件包含输入和输出向量。使用 MATLAB,我们将这些数据点绘制成图表。在 MATLAB 上,我在主页>导入数据中导入它们。然后,我创建了绘制数据点的流程脚本。
您应该会看到如下所示的图表。

资料组
最小平方
最小二乘法用于解决使用平方损失法的线性回归中的 ERM 问题。在继续讨论实现本身之前,我推荐这篇快速文章。
经验风险最小化(ERM)
ERM 是机器学习中一个广为人知的概念,我建议在开始实际实施之前,先看一下关于 ERM 的解释。ERM 用于对学习算法的性能进行分类,我们可以通过找到一个向量 w 来解决 ERM 优化问题,该向量最小化下面的公式【1】。

上式中, X 为设计矩阵, t 为输出向量。我们想找到多项式拟合问题的最佳拟合。为此,我们将计算 W = 1、2、…、30 阶多项式,并分析经验平方损耗,以了解哪种多项式阶最适合我们的数据。我们问题的设计矩阵 X 由下式给出:

我们可以通过求解下面的线性方程来找到多项式 w 。

如果我们认为X’X是可逆的【1】,上面的方程总是有解的。同样,如果你想知道为什么会这样,你可以阅读这篇关于最小二乘法的解释。解决方案由下面的等式给出。

这就是 MATLAB 派上用场的地方。我们需要求解上面的线性方程来找到并测试我们的模型。
为了在 MATLAB 上求解这个方程,我们将通过矩阵相乘和求逆来手动实现运算,而不是使用有效的算法来求解线性方程。需要指出的是,这可能不是理想的方法,因为效率较低。为了计算解决方案,我首先计算 W = 1 的设计矩阵,并计算第一个多项式。
然后,我创建了一个循环来计算剩余的 Wᵢ ,并将它们存储在名为多项式 _wi 的单元数组中。30 个设计矩阵也存储在单元阵列设计矩阵中。
现在,我们需要计算多项式 _wi 上所有 wᵢ 多项式的经验平方损耗。我们的问题的数据点数是 N= 100。按照这个脚本,我创建了一个循环来计算每个多项式 wᵢ 的 ERM。我还打印了使我们的经验平方损失最小的多项式的阶。
我们算法的输出如下图所示。

ERM.m 脚本的输出
因此,21 阶多项式的经验平方损失最小。现在,让我们分析下图中所有多项式的经验平方损耗图。对于这个分析,我绘制了从 W = 1 到 W = 30 的经验平方损失向量 E 。

缩小比例下的经验平方损失
查看 ERM 的经验平方损失,我们可以看到,多项式 W= 21 确实是数据集的最佳拟合。我们还可以看到,在 W = 6 之后,经验损失几乎变得稳定,直到 W = 21 时略有下降,而在 W = 23 之后,我们的模型开始过度拟合,以至于经验损失飙升。当我们在如下图所示的 MATLAB 命令窗口中执行命令【ERM,W】= max(E)时,我们看到对于订单 27,平方损失超过 395。

最大经验平方损失
下图显示了 W = 21 阶多项式相对于数据集的曲线。

21 阶多项式与数据集
分析上图中的曲线本身后,我们可以看到,尽管 W= 21 阶的多项式的经验损失最小,但它过度拟合了数据。因此,仅将经验损失作为选择最佳拟合的唯一指标可能不是最佳方法,因为它会导致我们选择过度拟合模型。
正则化损失最小化(RLM)
现在,让我们使用正则化最小二乘多项式回归重复上一步。我建议在阅读这部分之前先看一下关于 RLM 的解释。对于 RLM,我们使用正则化子λ来计算向量 w 。对于正则化最小二乘回归,我们可以使用下面的等式[1]来计算 w 。

注意,我们使用正则化子λ乘以 X. 阶的单位矩阵

如果我们将 w 分离出来,我们可以得到下面的线性方程:

同样,我将在 MATLAB 上手动实现这些操作来求解这个线性方程。这种情况下的设计矩阵与为 ERM 定义的相同。
正则化子λ的重要性
让我们首先分析在我们的机器学习模型的计算中有一个正则化子的后果。为了做到这一点,让我们分析 W = 30 阶的多项式,看看它在使用不同的λ值时的表现。
我们将对区间λ进行这种分析,其中 ln(λ) = -1,-2,…,-30。因此,λ的值将由下式给出

首先,我计算了 30 阶多项式的设计矩阵的值。
与我在 ERM 上所做的类似,我创建了一个循环来计算λ的所有值的 wᵢ 。我还计算了 RLM 的经验平方损失,这与 ERM 相同。
对于每次迭代,λ的值被更新。

带正则项的 30 阶多项式
我们算法的输出如下图所示。

RLM.m 脚本的输出
因此,30 阶多项式(其中 ln(λ)= 30,即 i = 30)最适合此数据。下图显示了带有 i = 30 的 W = 30 阶多项式对数据集的绘图。

i = 30 的 30 阶多项式和数据集
正如在 ERM 上看到的,我们的 30 阶 RLM 模型和 i = 30 也过度拟合了数据。
ERM vs RLM
现在,让我们比较一下 ERM 和 RLM 的结果。当我们分析 RLM 的等式时,我们可以得出结论,对于λ的大值,即 i 的小值,我们具有较大的经验平方损耗。这意味着对于小值的 i ,我们得到一个欠拟合模型。另一方面,对于λ的小值,即 i 的大值,我们得到较小的经验平方损耗。然而,这种行为会导致过度拟合模型。我们可以在下图的右图中注意到这一点。此外,λ的大值也有助于减少高阶多项式的过拟合问题。这可以从下图的右图中看出。

左边是 W = 2(欠拟合)和 W = 27(过拟合)阶多项式的 ERM,以及 i = 2 和 i = 26 的 30 阶 RLM 多项式。(剧情来自 RLM_ERM.m 剧本)
谈到 EMR 曲线(在经验平方损失图中用橙色表示),我们也有类似的结果。然而,在这种情况下,我们改变多项式的阶数,直到 W = 30。对于阶数较小的多项式,我们得到一个具有较大经验平方损失的欠拟合模型,而对于阶数较大的多项式(本例中为 W > 23 ),我们可以过拟合我们的数据,即使我们得到一个较小的经验平方损失。这可以在上图的左图中看到。注意,RLM 中的正则化有助于减少较高阶多项式的过度拟合。因此,分析两种解决方案的经验平方损失图对于选择最适合我们数据集的模型至关重要。
此外,如果我们分析极限λ→0 的正则化最小二乘,即极限 i→∞,我们看到 RLM 方程的正则化项消失,使得 RLM 与 erm 相同。当我们分析 i= 12 的 10 阶 RLM 多项式时,这一点得到了证明。由于这种情况下λ值非常小(0.000006144),我们可以注意到,该多项式的曲线与 10 阶 ERM 多项式大致相同。

10 阶 ERM 多项式和 10 阶 RLM 多项式,i = 12。请注意,这些曲线相互重叠。(剧情来自 RLM_ERM.m 脚本)
最后,与 W = 30 阶的 ERM 相比,RLM 的 W = 30 阶和 i = 30 阶的模型具有明显更小的经验平方损失(分别为 0.0453 和 4.7873)。这支持了正则化有助于减少过拟合的结论。此外,RLM 的 W = 30 次和 i = 30 次多项式对于 ERM 具有大约相同的 W = 21 次经验平方损失。
毕竟哪种模式最好?
现在我们有了所有这些数据,我们可以为我们的问题选择最好的模型。目标总是找到一个小阶多项式,这样我们就不会过度拟合我们的数据。此外,订单必须足够大,这样我们就不会吃不饱。
让我们绘制并查看订单 W= 1、5、10、20、30 时的 ERM 和 RLM 曲线。这一次,我们将固定正则化因子λ = 0.0025。脚本 Visualization.m 用于绘制两条曲线。

左边是 RLM 和数据集的 1、5、10、20 和 30 阶多项式,右边是 RLM 和数据集的 1、5、10、20 和 30 阶多项式
当我们分析 EMR 和 RLM 的图表时,我们肯定能注意到它们之间的差异。较大订单的 ERM 模型具有很大的变化,并且使它们自己过多地适应训练数据。这意味着,随着模型阶数的增加,过度拟合的风险也会增加。当我们研究 W = 10 阶的多项式时,尤其如此。虽然 RLM 多项式没有很大的变化和差异,但 ERM 多项式以一种导致过度拟合的方式适应数据。因此,与 RLM 相比,欧洲汇率机制的实际损失看起来较小。当我们比较这两个经验损失时,很容易观察到这一点。
为了更好地形象化这种行为,我们可以分析下面的条形图,其中显示了 W= 1、5、10、20 和 30 阶多项式的 ERM 和 RLM 的经验损耗。当我们查看它时,我们可以证明,除了 W= 30 多项式,ERM 的经验平方损失小于 RLM。

正则项λ = 0.0025 的 RLM 的经验平方损失和 W = 1、5、10、20 和 30 的 ERM
在表示数据时,RML 模型中的正则化因子起着重要的作用。正则化模型对数据集更精确,因为它们不会像 ERM 那样过度拟合数据。当我们看到下图时尤其如此。在左侧,我们有不同λ值的 RLM 的经验平方损耗。注意,当我们降低λ的值时,我们也降低了 W > 6 的经验损耗。

在缩小的比例中,左边是具有不同正则化子的 RLM 的经验平方损失,右边是具有不同正则化子的 RLM 的 10 阶多项式。(剧情来自与 RML_For_W_Risk.m 和 RML_For_W_Poly.m 剧本)
在上图的右侧,我们可以看到不同λ值的 W= 10 阶多项式。随着λ值的减小,我们增加了模型的适应性。因此,非常小的λ值可能导致过拟合,而大的λ值可能导致欠拟合。
鉴于这些事实,最适合该数据集的模型是 W= 5 阶的 RML 多项式。多项式如下所示。
0.6721-0.5555 x-6.5428 x-0.9711 x+6.5883x⁴+0.7647x⁵
这是因为这个多项式阶次小,经验损失小。此外,当我们分析 ERM 和 EML 的曲线图时,我们可以看到这个模型没有过度拟合数据。此外,W= 5 阶的 ERM 多项式似乎也符合数据而没有过度拟合。

λ = 0.0025 的 W = 5 阶多项式
结论
我们看到,使用 RML 可以降低我们的模型的整体复杂性,并避免过度拟合。然而,由于我们现在有一个新的参数λ要确定,RML 模型计算起来更加复杂。
在选择模型时,我们应该在分析中使用的另一个重要特征是经验平方损失曲线。我们还可以得出结论,经验平方损失最小的模型并不总是我们数据的最佳解决方案。此外,在参数λ和我们预测的多项式的阶数之间找到一个平衡在这个分析中是至关重要的。
数据欠拟合和过拟合是当今数据科学家面临的一个极其常见的问题,为给定问题找到理想的解决方案需要对可能的模型进行详细分析。
感谢阅读!
关于我
我是约克大学的一名硕士研究生,骨子里是一名软件工程师。在过去的十年里,我一直在软件开发、云计算和系统工程等领域的几个行业工作。目前,我正在研究云计算和分布式系统。
如果你愿意,你可以在我的网站上查看我的作品。
参考
[1] Shai Shalev-Shwartz 和 Ben-David。理解机器学习:从理论到算法。剑桥大学出版社,2014 年。DOI:10.1017/CBO9781107298019。网址:https://www . cs . huji . AC . il/~ shais/understanding machine learning/understanding-machine-learning-theory-algorithms . pdf
利用数据科学深入分析联合国可持续发展目标的进展

照片由 Unsplash 上的 Mat Reding 拍摄
数据新闻
使用网络搜集、探索性数据分析、时间序列分析和自然语言处理/软余弦矩阵深入探究 17 个可持续发展目标的合作关系。
2030 年议程主张通过加强全球伙伴关系,重新致力于人类、繁荣、地球与和平。可持续发展目标是 2015 年在该议程中设定的,此前十年的千年目标以发展中国家为目标。这一宣布已经过去五年了,所以我认为这是对合作关系(这是这一变化的最大驱动力)做一些初步分析的好时机。对于那些不熟悉这些目标的人,你可以在这里找到他们的陈述、目标和指标的摘要。
虽然有 17 个目标,但每个目标都可以分为三大类(引自来源):
1)它应支持各国投资于附加值更高的产品和部门、技术、多元化经济和更高的生产率,所有这些都应创造高质量的就业和生计(可持续发展目标 7 至 15 强调了与这种转型相关的关键问题)。
2)只有这样,各国才能满足其社会最紧迫的需求,包括消除极端贫困(可持续发展目标 1 至 6 反映了这一社会议程和以人为本的发展方式,是巩固和加快可持续经济增长所必需的)。
3)最后,2030 年议程首次承认,要实现这一转变,在能力、合作和资源方面需要实现巨大飞跃(可持续发展目标 16 和 17 谈到了在国家内部和国家之间加强社会契约的手段)。
基于以上所述,我认为应该有跨越类似目标的合作伙伴,以及在援助类型/这些目标的地理覆盖范围方面的相似性。我收集的数据可以在联合国可持续发展目标伙伴关系平台上找到。它显示了 4585 个独特的合作伙伴,总共约有 14249 个合作伙伴。我使用的栏目如下所示(合作关系示例此处):


所有数据、交互式图表和脚本都可以在我的 GitHub repo 中找到。
本文将探讨以下问题:
- 提供者/受益者的地理覆盖和交叉覆盖是什么?
- 谁是顶级实体和次级合作伙伴?
- 这些年来,伙伴关系的势头发生了怎样的变化?
- 每个目标的伙伴关系之间的关系是什么?重叠是我们所期望的吗?
- 每个目标的资源援助有多不同?
地理覆盖:
让我们先来看看哪些国家是每个目标的最大受益者。受益者的数据有以下几种形式:
ChinaItalyMexicoMoroccoSouth AfricaSpainUruguay
我在大写字母上使用了re.findall,然后创建了一组扩展列表来查找唯一的国家。由于一些国家有多个单词(如“南非”),它们将显示为两个不同的国家,考虑到这一点,有 234 个不同的受益人。大约 7000 个伙伴关系没有在他们的网页上列出受益人,所以这个数据可能略有偏差。

为了获得跨国报道,我使用了based栏。只有 2000 个伙伴关系列出了它们的所在地,所以这只是整个数据集的一小部分。

我真希望我能为所有 14249 合作伙伴完成[总部,受益人]配对,因为这将让我们非常清楚地了解谁在帮助谁。
目标、实体和合作伙伴之间的关系:
大多数合伙企业列出了主要实体关系,大多数列出了额外的次级合伙人。合伙企业中有 607 个独立实体和 13165 个独立子合伙人。

你可以从上面看到欧盟委员会的推动,尽管 120 是 14249 的一小部分。大多数实体都与联合国有某种联系。

有些名字只是为了更好看而缩短了
IUCN 是国际自然保护联盟(T2),这是有道理的。我找不到资助者,我能找到的最接近这个名字的组织来自印度,专注于印度女性创业。上图中有不少来自印度的子合作伙伴,这让我相信印度是推动组织合作的领导者。
过去五年的目标发展势头:
在进入时间序列分析之前,我在清理时发现,大约 400 个合作伙伴有某种日期输入错误,我无法轻易修复,但是,它们平均分布在每个目标的 30-50 个左右。总共有 712 个正在进行的项目,我用结束日期12–31–2030来代替,作为这个分析的占位符。

每年都开始合作
从这张图表中我们可以看出,一些伙伴关系早在 2030 年议程制定之前就已经存在。我的猜测是,一些合作伙伴是在该计划宣布后加入的,并且已经存在/持续了很长时间。

合作伙伴关系每年都以目标开始。颜色重复,但在图例中是从下到上绘制的。
伙伴关系的势头显然有点停滞,大多数都是在 2017 年开始的。这是概念上的,如果我们把它看做总合伙企业的百分比:

每年开始的项目占目标的百分比。颜色重复,但在图例中是从下到上绘制的。
在试图断定势头已经下降之前,我们还应该研究一下合作关系的结束日期。一些伙伴关系可能会比其他伙伴关系产生更大的影响,我会把钱投在那些持续时间最长的伙伴关系上。
按类别分列的每年结束的项目:

712 个正在进行的项目被归类为 2030 年底,其中一些可能会延长更长时间。尽管如此,仍有超过 1500 个项目将在 2030 年结束。

大多数项目持续时间在 1-5 年之间,从条形图中我们可以看到,到 2021 年,几乎三分之一的现有项目将会结束,到 2025 年将会增加到一半。为了保持目前的势头,我们需要每年看到至少 1000 个新的合作伙伴。我确信新冠肺炎对 2020 年的注册产生了影响,事实上,今年大多数合作伙伴在描述中都提到了新冠肺炎。
研究各目标之间的关系:
首先,让我们看看哪些目标通常由合作伙伴关系共同涵盖:

此处显示的前 30 名
许多伙伴关系试图同时解决所有的可持续发展目标(尽管出于某种原因,可持续发展目标 12:“可持续消费。”被跳过很多次)。除此之外,可持续发展目标 3:“良好的健康和福祉”和可持续发展目标 16/17(机构力量和全球伙伴关系)似乎最常与其他目标配对。可持续发展目标 13/14(气候行动和海洋保护)也经常与其他目标一起出现。这种模式似乎是要解决前面列出的三个类别的目标,而不仅仅是其中的目标。这告诉我,也许有一种方法可以在不同的目标之间划分等级和联系。
为了更深入地了解为什么某些目标可能会包含在一起,让我们分析一下它们描述中的文字。这些描述涵盖了合作伙伴的概要,以及合作关系结束时的预期影响。为了找到伙伴关系之间的关系,我在描述中使用了自然语言处理(NLP)。
包括四个主要步骤:
- 使用
googletrans将所有描述翻译成英语,其中大约 5000 个是西班牙语、法语和其他语言。 - 对描述进行单词标记,删除停用词,然后使用
nltk进行词汇化。 - 使用来自
scikit-learn的计数矢量器和 TF-IDF 转换器为描述中使用的所有单词创建一个一次性编码的备用矩阵。 - 最后,运行主成分分析(PCA)来寻找描述之间的关系。
(如果这些听起来都很拗口, 查看本文 我在另一个示例中详细介绍了这个代码过程。但是,理解它并不一定要继续跟着读下去)。
在密度图中绘制 PCA 的前两个组成部分给出:

使用目标散点图显示 PCA:

如果你仔细观察,你会发现有相当多的点是完全重叠的。请记住,许多伙伴关系同时处理多个目标——所以我删除了那些重复的,只绘制了独特的伙伴关系。作为参考,4585 个唯一合作伙伴中的 2232 个只处理一个 SDG 。

过滤主成分分析
虽然这确实开始揭示一些清晰的目标群,但在不同目标的描述中仍有许多相似之处。大多数目标要么聚集在 y 轴上 0 的左边,少数在 0 的右边。我注意到,在整个范围内,这些目标都是以气候和环境为重点的。这并不令人惊讶,因为我预计气候将处理最多样化的问题、资源和伙伴关系。

选自原始 PCA
这更好地从时间的角度来看,所以我用 plotly Dash 应用程序创建了一个 GIF,展示了在未经过滤的 PCA 中,合作关系是如何随着时间的推移而出现的。我们可以看到不同的目标在不同的时间获得了动力,集群确实是在 2017 年和 2018 年形成的。“包容性和公平的优质教育”和“保护……海洋”分别在 2012 年和 2016 年获得强劲势头。

虽然这些图表给了我一些关于每个目标特有的集群的信息,但并没有告诉我我想要的那么多。这些目标似乎都在某种程度上重叠,而不是独特的成对/三对。为了扩展这一分析,我们将看看如何使用余弦相似度,而不仅仅是欧几里德距离比较。有两种方法可以做到这一点,要么在应用 TF-IDF 后对单词向量使用余弦相似性,要么更进一步,在先前的单词嵌入模型相似性矩阵和文档相似性矩阵之间进行额外的内点积(具有 L2 范数),以获得软余弦矩阵(本质上更好地捕捉描述中单词的语义)。我们可以使用 gensim word2vec 或FastTex预训练的单词嵌入模型轻松做到这一点。
矩阵看起来像这样:

越接近 1,文档之间的相似度越接近。从概念上讲,你可以把它想象成 Seaborn 的 pairplot 或者 correlogram。
创建余弦矩阵后,我们可以再次进行主成分分析,看看我们的聚类是否发生了变化:

分布发生了很大的变化,尽管集群并没有真正发生很大的变化。平均软余弦相似性是 0.779,这是相当高的,所以没有明确的独立聚类是有道理的(即使我们运行 t-SNE)。我尝试查看某个领域的关键词(即 x(-10,10)和 y(-2,2)),并获取某个领域的 gensim 摘要,但这些都返回了目标中广泛涉及的问题。下一节将帮助解释一个可能的原因。
每个目标的资源覆盖范围:
每个合作伙伴提供的资源可以不同,从财政援助到农业或技术。大多数描述实际上是关于为什么某个资源是必要的,它将如何实现,以及最终的影响。困难的任务是弄清楚如何根据描述识别提供了什么资源。
在通读了一千个合作伙伴之后,我决定使用以下资源/搜索词:
- 技术(科技、IT、数字、数据)
- 培训(教学、培训、技能、课程、班级)
- 粮食(种子、农业、灌溉)
- 财政/经济(补贴、资金、贸易、金融、投资)
- 研究(研究、框架、评估、监测)
- 保护(保护、土木工程、生物多样性)
- 法律/政治(民主、权利、政策、法律)
- 其他(不属于上述类别的所有伙伴关系)
这是一种简单的方法,目的是给我们一个大概的了解,并不意味着面面俱到。产出如下,其中每个伙伴关系可被视为提供了一种以上的资源。

14249 个合伙企业中有 1500 个不符合我的分类
研究、技术、培训和财政看起来像是伙伴关系提供的共同资源。将它分解成每个目标看起来像这样:

概念视图
这比我预期的要均匀得多,尤其是当您将视图转换成百分比形式时:

百分比视图
唯一让我印象深刻的一点是 SDG 14,与其他目标相比,它对训练的依赖要少得多。这也与我们的主成分分析结果相符,该结果显示所有目标的分布存在一致的重叠。很高兴看到资源在各个目标之间的平均分配,因为这意味着每个部门/行业都有能力为每一个可持续发展目标做出贡献。
后续步骤
这篇文章是理解可持续发展目标如何在许多方面取得进展的良好开端,也揭示了伙伴关系和 17 个可持续发展目标之间的许多关系。 我想重申,这是一篇关于前进的文章,不是进步。 如果您想了解不同目标的实际进展,请深入研究列出的目标和指标,以及每个国家如何报告这些目标和指标。
我认为下一步可能是使用所有这些数据,并生成一个分类机器学习模型。该模型将接受任何组织的名称、居住国和描述,并建议哪些目标、资源和合作伙伴是合适的。如果这听起来像是你想要合作的事情,请随时通过 LinkedIn 联系我。
(我仍然在清理、重构和注释掉代码——清理、清理和分析超过 1000 行代码——但如果你现在想自己破译它,请查看GitHub Repo。所有的绘图文件和数据都在那里)
深入了解 Julia 中的数据结构
朱莉娅综合教程
Julia 编程语言中数据结构的快速介绍。
本文视频:

(图片由作者提供)
介绍
在之前的 Julia 教程中,我们讨论了如何对类型和函数使用 Julia 的多重分派。多重分派是一个简单的系统,用于在相同的方法参数下对不同的函数调用应用不同的类型。该结构中的关键组件是类型,更具体地说,是数据类型。
数据类型是计算机编程的基础。任何编程工作都将涉及操纵、移动和使用基本数据类型。在语言中创建的类型本身只是其他类型(通常是数据类型)的容器。
基本数据类型
我们可以在 Julia 编程语言中存储的第一种数据是基本数据类型。基本数据类型包括数字、文本、字符和布尔值等数据。
布尔代数学体系的
布尔类型是一种指示条件是否为真的类型。布尔值可以用最终压缩为 1 或 0 的真/假值来表示,也可以用表示类型条件的整数(1 或 0)来表示。
typeof(true)Bool
同样,在 Julia 语言中,我们也可以将布尔值断言为表示真或假的整数:
Bool(1)true
整数
编程中的整数数据类型类似于数学中的整数数据类型。整数是没有小数值的整数。通常,每当我们在 Julia 中处理整数时,我们都会处理 Int64 数据类型。这意味着该整数有 64 位。或者,也有 Int32s 和 BigInts。
typeof(5)Int64
漂浮物
浮点数是小数点后有第二个数字的整数,或者是一个小数值。浮点可以被认为是两个独立的数据片段,小数值之前的整数和整数之后的小数值。
typeof(5.5)
Float64
复杂而庞大
复杂的浮点数在 Julia 语言中经常出现。复浮点数就是既有虚值又有实值的浮点数。需要注意的是,这意味着这些类型不是真正的。通常科学计算需要一个真实的数据类型,因此你可能需要断言一些复杂的浮点数。
typeof(5.5 + 5.5im)Complex(Float64)
该数据类型第二部分中的“im”表示前面的数字是虚数。
另一方面,大数据类型是实数,但超出了大多数 64 位整数和浮点数应用程序的能力,并且是精确的。这是 Julia 语言的一个显著特点,因为它允许巨大的整数和浮点数据类型毫无问题地通过多个函数传递——这是很少有语言能够做到的。
# Big Int
big(51515235151351335)# Big Float
big(5.4172473471347374147)
标志
符号数据类型是 Julia 语言从函数范式中获得的另一个伟大的东西。符号可以用来表示从参数到字典键的任何东西——它们在这方面做得相当好。一般来说,符号数据类型在编程语言中是一个很好的东西,因为它可以用来表示基本上任何东西,因此得名:符号。在 Julia 中,只需在关键字前加一个冒号就可以写出符号,例如:
typeof(:Symbol)Symbol
字符串和字符
字符串是一个非常简单的概念,它是由一组连续的 unicode/ascii 字符组成的字符组合。正如第 3 部分——循环中所演示的,字符串可以循环显示下一个数据类型,chars。如果您还没有阅读第 3 部分,您可以在这里查看:
Julia 编程语言中循环和条件一起使用的介绍。
towardsdatascience.com](/getting-familiar-with-loops-in-julia-cfbcc344728c)
字符串用引号分隔。另一方面,字符用撇号分隔。
typeof("Hello")Stringtypeof('h')char
浮点数用于表示 ASCII 中的字符。因此,我们总是可以将 asset chars 转换成 floats:
float('5')
有趣的事实:这就是标签编码的工作原理
数据结构
所有的分类数据、向量数据和矩阵数据都将充当其他类型数据的容器。考虑由多种数据类型组成的数组的例子,如整数、浮点、布尔或字符串。
数组
element_wise = [5, 10, 15, 15]
这个新数组是包含 4 个 Int64s 的数组。我们可以根据它们在数组中的位置用数字对它们进行索引:
element_wise[1] == 5trueelement_wise[2] == 10true
我们还可以在类型中看到这一点:
typeof(element_wise)
Array{Int64, 1}
为什么括号很重要:
您可能已经注意到,无论何时创建数组,它通常都在方括号的范围内。如果没有这些括号,这个数据集合的类型将是一个元组。虽然我没有深入研究元组,但它们是一种非常有效的数据类型——但如果您需要数组,这肯定不是您想要的。
h = 5,10,15,20
typeof(h)NTuple{4, Int64}
此外,不使用括号会使函数无法理解哪个参数对应于哪个变量。考虑追加!()方法。追加!方法有两个参数,第一个是您想要追加的数据,第二个是您想要追加的数据。如果我们使用括号,这是可行的,因为数组被视为一个参数。但是,使用逗号会出现 ArgumentError。
parameters
v v
append!([5,10], 15) parameters
v v vappend!(5,10,15)
字典
在 Julia 中,字典需要被明确定义,否则它将返回一个元组。这是一种非常有价值的动态类型,在处理数据集或 JSON 数据时会进一步体现这一点。
data = Dict(:A => [5,10,15], :B => [11, 12, 13)
使用字典,我们可以通过调用相应的符号键来调用数据,在本例中:
data[:A][5, 10, 15]
双;对;副
对实际上是元组类型,但重要的是要认识到对是元组,但元组不是对。pair 与我们一秒钟前用来访问字典的部分内容完全相同,并且可以用相同的方式创建:
key = :A => [5,10,15]
一组
集合只是从一个类型中提取的唯一值。例如,如果我们断言一个数组的集合类型,我们将获得该数组中的每个唯一值:
arr = [5, 5, 7, 7, 6, 4, 5]set = Set(arr)println(set)[5, 7, 6, 4]
元组
元组是数据类型的一般化结构,不一定具有已定义的结构。元组可以被认为是一个组织性较差的数组。
h = 5, 10, 15
创建类型
有时,处理原始数据类型可能是乏味和令人疲惫的,尤其是当一个函数需要处理许多参数时。这就是结构的用武之地。创建一个结构将产生一个新的类型,它可以保存任意的和预定义的数据结构。我们可以通过使用 struct 关键字,后跟定义和数据来创建结构。
struct typer
h
v
end
有了这个类型,我们现在可以给它分配一个新变量,提供必要的数据作为构造函数的参数:
w = typer(5, 10)
在这个实例中,struct typer 是我们保存数据 h 和 v 的新类型,我们可以通过调用 struct.data 来访问这些数据:
typer.h5typer.v10
我们还可以通过函数传递这个新类型,例如从我们的 typer 结构中添加我们的 h 和 v 数据:
function addtyper(typer)
return(typer.h + typer.v)
end
值得注意的是,在 Julia 语言中,构造类型中的数据是不可变的。这可以通过在类型前放置关键字 mutable 来改变:
mutable struct typer
h
v
end
结论
数据类型一直是编程中非常重要的事情,这个问题在数据科学的世界中更为明显。大多数编程只是简单地使用数据结构和构造类型来处理数据类型。也就是说,理解数据类型对程序员来说非常重要。在 Julia 中有许多类型,有些你可以自己构造,但是学习如何利用和操作这些类型将是成为一个伟大的程序员的关键。**
使用张量流的(深入)机器学习图像分类
理解实现用于图像分类的神经网络的过程。

Arif Riyanto 在 Unsplash 上拍摄的照片
介绍
T 这将是一篇很长的文章,因为我将详细讨论实现图像分类神经网络所必需的组件和过程。
随意休息一下,甚至直接跳到有代码的部分。
本文旨在介绍实际的实现技巧,并解释机器学习开发中涉及的术语和术语。
本文内容面向初学者和中级机器学习从业者。
在页面底部有一个链接,指向本文中介绍的代码的笔记本。
享受吧。
目标
神经网络解决各种各样的任务,例如分类、回归等等。
本文研究了开发一个简单的用于图像分类的神经网络的过程。
将对以下内容进行探讨:
- 图像分类和其他术语的定义
- 机器学习中的理论和概念(多层感知器)
- 如何利用 TensorFlow、Keras 等工具和库
- 如何建立、训练和评估神经网络
图像分类
图像分类是与多标签分配相关联的任务。
它包括从图像中提取信息,然后将提取的信息与一个或多个类别标签相关联。机器学习领域中的图像分类可以作为监督学习任务来处理。
但在我们进一步深入之前,需要理解一些基本术语以及所使用的工具和库,以正确理解实施细节
感知器
感知器是人工神经网络的基本组成部分,由弗兰克·罗森布拉特于 1958 年发明。感知器利用基于阈值逻辑单元的操作。
感知器可以以单层格式堆叠,这能够解决线性函数。多层感知器能够解决更复杂的功能,并具有更大的处理能力。

MLP
多层感知器(MLP)是几层感知器一个接一个地连续堆叠。MLP 由一个输入层、一个或多个称为隐藏层的 TLU 层以及一个称为输出层的最终层组成。
工具和库
- TensorFlow :机器学习模型实现、训练、部署的开源平台。
- Keras :一个开源库,用于实现运行在 CPU 和 GPU 上的神经网络架构。
- 熊猫 :数据分析修改库。
- Matplotlib :用于在 Python 中创建可视化绘图的工具,如图表、图形等
- Numpy :实现数组数据结构的多种数学计算和运算。
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import os
import time
资料组
时尚-MNIST 数据集由源自 Zalando 图像目录的服装图像(t 恤、裤子、连衣裙等)组成。Zalando 是一家成立于 2008 年的欧洲电子商务公司。

时尚-MNIST 类和相关图像的例子
Zalando 的研究人员创建了包含 70,000 幅服装图像的时尚 MNIST 数据集。更具体地说,它包含 60,000 个训练样本和 10,000 个测试样本,这些样本都是尺寸为 28×28 的灰度图像,分为 10 类。
这些类别对应于图像中出现的服装项目。例如,一个踝靴的图像对应于数字标签“9”。

时尚 MNIST 数据集分布的可视化
数据集分区
对于这个特定的分类任务,使用了 55,000 幅训练图像、10,000 幅测试图像和 5,000 幅验证图像。
- 训练数据集:这是我们用来直接训练神经网络的数据集组。训练数据是指在训练期间暴露给神经网络的数据集分区。
- 验证数据集:这组数据集在训练期间被用来评估网络在各种迭代中的性能。
- 测试数据集:数据集的这一部分在训练阶段完成后评估我们网络的性能。

数据集分区的图示
Keras 图书馆有一套易于使用的数据集。
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
60,000 张 28x28 尺寸的训练图像
train_images.shape
>> (60000, 28, 28)
60,000 个训练标签,每个标签对应于一件衣服,例如,标签 9 对应于踝靴
train_labels.shape
>> (60000,)train_labels[0]
>> 9
可视化和预处理数据
在我们继续之前,我们必须将训练图像像素值标准化为范围 0 和 1 内的值。这是通过将训练和测试图像中的每个像素值除以 255 来实现的。
train_images = train_images / 255.0
test_images = test_images / 255.0
以下是 fashionMNIST 数据集中的图像对应的类名。
class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]

时尚-MNIST 类和相关图像的例子
可视化数据集
plt.figure(figsize=(10,10))
for i in range(20):
plt.subplot(5,4, i+1)
plt.xticks([])
plt.imshow(train_images[i])
plt.xlabel(class_names[train_labels[i]])
plt.show()

数据集的验证分区是从训练数据集导出的。5000 张图像和标签将用于验证目的。
validation_images = train_images[:5000]
validation_labels = train_labels[:5000]
以下是用特定索引位置标识的相应服装名称的示例。
class_names[train_labels[2]]
>> 'T-shirt/top'
构建模型
Keras 提供了实现分类模型所需的工具。Keras 提出了一种顺序 API,用于将神经网络的层堆叠在彼此之上。
分类网络是一个浅网络,具有 3 个隐藏层、一个输入层和一个输出层。使用“Flatten”构造函数构建输入层,该构造函数将输入形状作为其参数,在本例中为[28,28]。
每个图像输入数据被转换或展平成 1D 阵列。密集层有确定数量的神经元/单元,单元的数量作为第一个参数传入。每个密集层还具有第二个自变量,该自变量接受要在每个层中使用的激活函数。
前三层使用 ReLU 激活功能,而最后一层使用 softmax 激活。
定义
- 激活函数:将神经元的结果或信号转化为归一化输出的数学运算。激活函数是在网络中引入非线性的神经网络的组成部分。激活函数的引入使得神经网络具有更强的表达能力和解决复杂的函数。
- ReLU 激活:代表‘整流线性单元’(y = max(0,x)) 。这是一种激活函数,可以转换神经元的值结果。ReLU 对来自神经元的值施加的变换由公式 y=max(0,x)表示。ReLU 激活函数将来自神经元的任何负值钳制为 0,而正值保持不变。这种数学变换的结果被用作当前层的输出,并作为下一层的输入。
- Softmax :激活函数,用于导出输入向量中一组数字的概率分布。softmax 激活函数的输出是一个向量,其中它的一组值表示一个类/事件发生的概率。向量中的值加起来都是 1。
# Classification MLP(Multilayer perceptron) with two hidden layers
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28,28]),
keras.layers.Dense(500, activation=keras.activations.relu),
keras.layers.Dense(250, activation=keras.activations.relu),
keras.layers.Dense(100, activation=keras.activations.relu),
keras.layers.Dense(10, activation=keras.activations.softmax)
])
通过调用我们的模型上可用的' summary '方法,可以获得上面实现的模型的可视化统计摘要。通过调用 summary 方法,我们获得了关于模型属性的信息,例如层、层类型、形状、模型中的权重数以及层。
model.summary()
提供了以下输出
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
_________________________________________________________________
dense (Dense) (None, 500) 392500
_________________________________________________________________
dense_1 (Dense) (None, 250) 125250
_________________________________________________________________
dense_2 (Dense) (None, 100) 25100
_________________________________________________________________
dense_3 (Dense) (None, 10) 1010
=================================================================
Total params: 543,860
Trainable params: 543,860
Non-trainable params: 0
模型中的每一层都是一些感知器,每一层都有一组属性权重和偏差。
模型的权重随机初始化。使用 glorot 统一初始化器初始化网络中的权重值,该初始化器被证明是 Keras 中密集层的默认初始化器。
- Glorot uniform initializer :一种神经网络的权重初始化方法,用作解决神经网络内不稳定梯度的解决方案。网络中的权重由某个范围内的值分布初始化,这些值的平均值等于零且方差恒定。分布的最大值是范围的正值,最小值是范围的负值。范围=[值,-值]
用于确定分布范围的值来自以下公式:
值= sqrt(6 /扇入+扇出)
‘fan _ in’是输入到层的数字。
“扇出”是层内神经元的数量。
官方研究论文中提供了更多信息。
first_hidden_layer = model.layers[1]
weights, biases = first_hidden_layer.weights
print(weights)
print('_____________')
print('_____________')
print(biases)
训练模型
汇编
Keras 通过我们之前实例化的模型对象提供了' compile' 方法。compile 函数支持我们在幕后实现的模型的实际构建,该模型具有一些额外的特征,如损失函数、优化器和指标。
为了训练网络,我们利用损失函数来计算网络提供的预测值和训练数据的实际值之间的差异。
伴随着优化算法的损失值促进了对网络内的权重进行的改变的数量。支持因素,如动量和学习率时间表,通过使损失值尽可能接近零,提供了使网络训练收敛的理想环境。
定义
- 学习率是神经网络不可或缺的组成部分,因为它是一个因子值,决定了网络权重值的更新水平。
在可视化练习中,要求解的函数可以描述为 n 维参数空间中的双曲线。
学习率是影响当前参数值朝向局部/全局最小值的步长的分量;因此,学习速率直接影响训练期间网络的收敛速率。如果学习率太小,网络可能需要几次迭代和历元才能收敛。另一方面,如果学习率太高,就有超过最小值的风险,因此我们的训练不会收敛。选择合适的学习速度可能是一项耗时的工作。
- 学习率时间表:在神经网络的训练过程中可以使用恒定的学习率,但这会增加达到最佳神经网络性能所需的训练量。通过利用学习速率表,我们在训练期间引入学习速率的适时减少或增加,以达到神经网络的最佳训练结果。
- 学习率衰减:学习率衰减减少了梯度下降过程中向局部最小值移动的步长的振荡。通过将学习率降低到与训练开始时使用的学习率值相比更小的值,我们可以将网络导向在最小值附近的更小范围内振荡的解。
- 损失函数:这是一种量化机器学习模型表现“有多好”的方法。量化是基于一组输入的输出(成本),这些输入被称为参数值。参数值用于估计预测,而“损失”是预测值和实际值之间的差异。
- 优化器:神经网络中的优化器是一种算法实现,它通过最小化损失函数提供的损失值来促进神经网络中的梯度下降过程。为了最小化损耗,适当地选择网络内的权重值是至关重要的。
优化算法示例:
- 随机梯度下降
- 小批量梯度下降
- 内斯特罗夫加速梯度
有关梯度下降的详情,请参阅以下文章:
简要了解机器学习模型中的学习过程是如何得到优化支持的…
towardsdatascience.com](/understanding-gradient-descent-and-its-variants-cf0df5c45478)
sgd = keras.optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss="sparse_categorical_crossentropy", optimizer=sgd, metrics=["accuracy"])
TensorBoard 提供对每个时期训练中发生的事件的可视化洞察。
TensorBoard 提供的训练可视化存储在“runs”文件夹目录中。我们创建一个函数来生成一个文件夹目录,并通过时间戳来标识每个日志。
root_logdir = os.path.join(os.curdir, "runs")def get_run_logdir():
run_id = time.strftime("run_%Y_%m_%d-%H_%M_%S")
return os.path.join(root_logdir, run_id)run_logdir = get_run_logdir()
tensorboard_cb = keras.callbacks.TensorBoard(run_logdir)
模型的功能 API ' fit '方法提供了训练实现的网络的工具。
将特定参数传递给 fit 函数:
- 我们可以指定用于训练的训练数据
- 我们要训练网络的纪元数
- 以及用于在对看不见的数据进行训练期间验证网络性能的验证数据集。
我们还将利用“回调”参数,在本例中,它调用创建的 TensorBoard 回调。
训练类神经网路时,Keras 中的预设批次大小是 32。该网络总共被训练 60 个时期。利用提前停止,一旦在 3 个时期后记录到验证损失没有改善,则停止训练。尽早停止可以节省您的时间,尤其是在您的网络开始超载并停止收敛的情况下。
总之,我们最多训练 60 个时期的模型,其中我们在每个时期通过网络以 32(批次大小)的批次前馈我们的所有训练数据。
在看到 32 个训练图像和标签后,我们的网络的权重参数进行了更新。
“fit”方法采用官方 Keras 文档中的附加参数。
early_stopping_cb = keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=3, verbose=0, mode='auto')
model.fit(train_images, train_labels, epochs=60, validation_data=(validation_images, validation_labels), callbacks=[tensorboard_cb, early_stopping_cb])
要运行 TensorBoard,请在您的终端中输入下面的命令,然后导航到 localhost:6006。
tensorboard --logdir=runs

来自 TensorBoard 的训练快照
估价
评估一个模型需要通过网络数据进行前馈,这些数据在训练期间还没有暴露给网络。
在实际使用之前对模型进行评估是一个很好的指标,可以观察模型对未知数据的概括能力。
有了评估结果,您可以决定微调网络超参数,或者在观察测试数据集评估的准确性后进入生产阶段。
model.evaluate(test_images, test_labels)
>> 10000/10000 [==============================] - 1s 74us/sample - loss: 0.3942 - accuracy: 0.8934
[0.3942159619651735, 0.8934]
预言
为了用训练好的模型进行预测,来自我们的测试数据集的 5 幅图像被用来模拟基于真实生活场景的测试。
通过使用通过我们的训练模型可用的“预测”方法,我们可以将一批实际测试图像传递给我们的模型,并提取每个图像的概率向量。
概率向量包含 10 个元素,并且向量中的每个元素对应于来自先前定义的 10 件服装类别的类别出现的可能性。
practical_test_images = test_images[:10]
prediction_probabilites = model.predict(practical_test_images)
prediction_probabilites
我们可以创建一个函数来循环遍历每个向量,并获得最高的置信度得分,这对应于我们的模型预测图像所属的类别。
def derive_predicted_classes(prediction_probabilites):
batch_prediction = []
for vector in prediction_probabilites:
batch_prediction.append(np.argmax(vector))
return batch_predictionmodel_prediction = derive_predicted_classes(prediction_probabilites)
model_prediction
>> [9, 2, 1, 1, 6, 1, 4, 6, 5, 7]
我们可以利用的另一种方法是利用' predit_classes '方法来获得每个图像对应的类。
model_prediction = model.predict_classes(practical_test_images)
model_prediction
' predict_classes '方法提供了一个一维向量或一个包含每个图像对应的类的数组。
np.array(class_names)[model_prediction]
>>array(['Ankle boot', 'Pullover', 'Trouser', 'Trouser', 'Shirt', 'Trouser',
'Coat', 'Shirt', 'Sandal', 'Sneaker'], dtype='<U11')
让我们将 practical_test_images 中的图像和模型中的预测类可视化。
# Visualise the prediction result
plt.figure(figsize=(10,10))
for i in range(len(practical_test_images)):
plt.subplot(5,5, i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(practical_test_images[i])
plt.xlabel(class_names[model_prediction[i]])
plt.show()

保存模型
最后一步是保存我们的模型以备将来使用。
保存一个经过训练的张量流模型包括调用模型本身的“保存”功能。
model.save("image_classification_model.h5")
通过调用 Keras.models API 提供的“load_model”函数,可以使用保存的模型。
loaded_model = keras.models.load_model("image_classification_model.h5")
predictions = loaded_model.predict_classes(practical_test_images)
print(predictions)
print(np.array(class_names)[predictions])>>[9 2 1 1 6 1 4 6 5 7]
['Ankle boot' 'Pullover' 'Trouser' 'Trouser' 'Shirt' 'Trouser' 'Coat'
'Shirt' 'Sandal' 'Sneaker']
结论
本部分包含会员链接。
通过这篇文章,我们做到了以下几点:
- 实现了一个模型
- 训练了一个模特
- 评估模型
- 保存了一个模型
从这里开始,您可以探索更多可以实现的神经网络架构,或者深入 TensorFlow 和 Keras 库。
下面是一个 GitHub 知识库的链接,其中包含了本文中的所有代码。
[## Richmond alake/tensor flow _ 2 _ 教程
permalink dissolve GitHub 是 4000 多万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/RichmondAlake/tensorflow_2_tutorials/blob/master/02_image_classification_fashionmnist.ipynb)
为了更好地理解实用的机器学习,下面还有一本我极力推荐的书。许多读者可能会熟悉这本书或它以前的版本
用 Scikit-Learn、Keras & TensorFlow 进行动手机器学习

动手机器学习
希望这篇文章对你有用。
要联系我或找到更多类似本文的内容,请执行以下操作:
- 订阅我的 YouTube 频道 即将发布的视频内容 这里
- 跟我上 中
- 通过 LinkedIn 联系我
谁认为你的测试和测试本身一样重要
A/B 测试需要对测试组和对照组进行深思熟虑的设计,而不仅仅是简单的随机分组
当尼克·卡拉斯和我写了《测试是不确定性的疫苗》一书,解释为什么测试对现代商业战略至关重要时,我们意识到这个话题会引起商业领袖、数据科学家和分析师的共鸣。我在那篇文章中提到,选择正确的测试和控制组是成功的关键。鉴于它的重要性,这个主题值得更详细地研究一下最佳实践和缺陷,这将帮助您实现最佳的测试设计。
所以,你已经为你的公司想出了下一个好主意,你有常识不只是把谨慎抛到九霄云外,而是,你想测试和学习。谁将成为测试的一部分?这是你需要回答的关键问题。如果你在测试中有错误的个体样本,这充其量是不确定的,最糟糕的是误导。值得庆幸的是,这并不是一个未知的领域,你可以遵循一些原则,并考虑一些方面来确保你的成功!

选择测试对象和测试本身的想法和假设一样重要
瞄准正确类型的测试对象
当然,第一部分是确定要测试的个人类型。这是一个你会对所有顾客进行的测试吗(例如,登陆你的网站或访问你的商店的每个人?),还是只针对变革最相关或被认为最有效的特定群体?例如,测试一个新的移动应用的横幅广告对于那些从电脑上访问你的网站的用户来说意义不大。你可以考虑通过人口统计(年龄、地点、收入、等)来细分你的客户群。)或通过行为(频繁访问者、高级用户、移动用户)。
还要考虑到你想要测试的想法可能会影响到多方,你会想要对所有参与方进行控制。例如,市场上的测试可能会影响生产者和消费者、销售者和购买者、司机和乘客,广告生产者和观众,他们的互动最终可能会掩盖测试的真正影响。例如,考虑测试一个新的推荐系统,这个系统将会从你的测试组中为赞助内容带来更多的流量。受影响的内容制作者注意到了这一点,并开始制作更好的内容。现在控制组看到了测试的溢出效应,他们的参与度也提高了。选择正确的随机化单位(买家?卖家?会话?)在这种情况下尤其棘手。
你永远也不想结束这样一种情况:你从测试中取出不干净的个体。帮自己一个忙:要么从一开始就计划一个干净的测试,要么计划需要度量的交互。
另一个重要的考虑是重叠测试。这就是为什么建议保持干净的测试池的原因,并且应该努力维护和更新。如果您最终用重叠的测试对个体进行抽样,这将会产生一种危险的诱惑,即挑出表现差的测试组成员并合理化一个理由。是通往 p 的阶梯——黑客、厨房水槽统计测试等数据科学地狱的圈子。然而,你可以在一个多因素分析中考虑多个测试,并预先设计你的分析来研究测试的相互作用。
现在你知道了运行测试的客户类型,但是你如何选择特定的个人作为测试和控制组的一部分呢?A/B 测试的黄金方法一直是随机抽样。然而,在某些情况下,随机抽样是不够的。以社交网络上的测试为例,测试组中的个体与控制组中的个体互动,从而影响控制组的行为。在这里,您会希望将测试和控制划分到比个体更粗糙的分组中,例如地理或社会集群。这里图划分方法,例如通过使用交互频率的阈值,可能会有所帮助。此外,如果您的样本量很小,您可能还需要根据一些关键标准对样本进行分层,以确保您在细分时没有偏见。
瞄准正确数量的测试对象
现在你知道你需要什么样的考试科目了,但是需要多少呢?这里既有战略上的考虑,也有统计上的考虑。
从战略的角度来看,你不应该把测试做得太大。您希望为其他测试维护干净的测试主题的共享池,所以使用比需要更多的主题会更快地耗尽这个资源,然后需要等待它补充。当然,第二个因素也是成本:许多想法都失败了,在更大的样本上运行昂贵的测试增加了对业务的负面影响。
统计学的观点是,你要确保你的测试不会太小。任何称职的数据科学家都知道功效分析,以及可靠地测量 x 的效应大小的基本规则,你将需要至少 N 个人,并且 N 随着 x 变小而变大。如果你的测试有望使销售额翻倍,你可能不需要那么多人。但是统计能力只会告诉你所需的最少和,而你想要的往往不止这些。例如,如果您计划在之后的分析中进行细分,尤其是如果您希望通过回归和机器学习模型将数据用于目标定位,您将需要更多数据。有好工具和好文章更详细地涵盖了这个主题。
这取决于人们
在统计计算时代,一台计算机可以在几个小时内运行数百个测试和模型,将批判性思维从测试过程中剔除,让机器清理人们造成的混乱已经成为一种时尚。这是导致灾难的一个因素:这实际上是垃圾进垃圾出。
一台机器无法单独从结果中判断测试是否有偏差,它无法判断市场中的多方之间是否存在交互影响,它也无法判断一个无关紧要的结果是因为样本量少还是因为这种影响不存在。
当运行统计测试是 Python 或 R 中的一个帮助命令,并且模型交叉验证被简化为一个函数时,数据科学家的关键知识将不是技术细节,而是概念思维。高影响力数据科学家甚至在数据进入之前就开始为业务增加价值。因此,通过选择正确的测试对象来设计正确的测试,对于成为一名高效的数据科学家至关重要。
深入的熊猫教程
数据科学速成班
处理关系数据的终极 Python 库

本月早些时候, Edward Qian 和我开始为有抱负的数据科学家编写一套综合课程,这些课程可以在我们的网站www.dscrashcourse.com上找到
我将把稍加修改的课程交叉发布到 Medium 上,让更多的观众可以看到。如果你觉得这些文章很有帮助,请到网站上查看更多的课程和练习题!
pandas是一个 Python 库,可以轻松读取、导出和处理关系数据。本课将详细介绍其功能和用法。我们通常使用缩写形式来引用库。下面分享的所有代码都是用 Python 3 和pandas==0.24.2编写的。
熊猫系列
从官方文档来看,Series 是带有轴标签的一维 ndarray。ndarray 是在numpy 库中找到的一种特殊数据类型,它定义了一个固定大小元素的数组。简单来说,系列是表格或电子表格中具有相同数据类型的列。每个系列都有一个用于指示轴标签的索引。
我们可以使用pd.Series(['some', 'array', 'object'])创建一个系列

索引系列
我们可以使用轴标签或它们的位置标签来查找系列值。如果未指定,系列轴标签(也称为系列索引)将默认为整数。我们也可以将索引设置为字符串。
sample_series = pd.Series(['some', 'array', 'object'], index=list('abc'))
# positional indexing: this returns the first value, which is 'some'
sample_series[0]
# label indexing: this also returns the first value 'some'
sample_series['a']
这就是sample_series的样子。

我们可以对一个系列进行切片以获取一系列值。使用轴标签时切片行为是不同的——与通常的 Python 切片相反,起点和终点都包括在内!
# positional slicing: this returns the first two values sample_series[:2] # label slicing: this also returns the first two values
sample_series[:'b']
熊猫数据框
数据帧用于定义二维数据。使用索引标记行,使用列标题标记列。每一列都可以解释为一个系列。我们可以使用pd.DataFrame({'column 1': [1, 1], 'column 2': [2, 2]}).创建一个数据帧

或者,我们也可以将表格数据读入数据帧。
# Read in a CSV file
csv_dataframe = pd.read_csv('my_csv_file.csv')
# Read in an Excel file
xls_dataframe = pd.read_excel('my_xls_file.xls')
索引数据帧
我们可以使用方括号来索引数据帧列。让我们以我们创建的非常简单的数据帧为例。
sample_dataframe = pd.DataFrame({'column 1': [1, 1], 'column 2': [2, 2]})
# get the column 'column 1'
sample_dataframe['column 1']
对于更复杂的索引,我们可以使用。iloc 或. loc。
- loc 是一种基于标签的索引方法,它需要行和列的名称
- iloc 是一种基于位置的索引方法,它需要值的位置
因为我们没有为行指定轴标签,所以它们采用了默认的整数值。因此,该数据帧的位置标签和轴标签是相同的。
我们可以使用以下两种方法之一检索第一行:
sample_dataframe.iloc[0, :]
sample_dataframe.loc[0, :]
探索熊猫的合成数据集
让我们创建另一个数据框架来说明一些功能。我们可以假装这些数据是从一家发行教育资料的公司获得的。
data = pd.DataFrame({'customer_id': [1,2,3,4,5,6,7,8],
'age': [29,43,22,82,41,33,63,57],
'email_linked': [True,True,False,True,False,False,True,True],
'occupation': ['teacher','highschool teacher','student','retired',
'tutor','unemployed','entrepreneur','professor']})
对于更大的数据帧,我们可以使用.head(n)来查看前 n 行。要查看最后几行,我们可以使用.tail(n).执行类似的操作,这对我们的小数据集来说都不是必需的,但是我们仍然可以使用data.head(3)进行演示。

过滤和索引数据帧
假设我们想要运行一个电子邮件活动。我们首先提取相关的专栏来开展我们的活动。
# use double brackets to index multiple columns, single brackets for one column
email_data = data[['customer_id', 'email_linked']]
并非所有的客户都有电子邮件链接,所以我们肯定要排除那些没有。
# the condition goes inside the square brackets email_data = email_data[email_data['email_linked']]
应用列式函数
让我们写一个非常简单的函数来判断一个客户是否是教育者。这就是我们如何定义一个教育家。
def is_educator(occupation):
return 'teacher' in occupation.lower() or occupation.lower() in ['tutor', 'professor', 'lecturer']
我们可以将这个函数应用到职业列来创建一个新列。
data['is_educator'] = data['occupation'].apply(is_educator)

我们还可以转换数据帧中每一列的所有行。这就需要我们设置axis=0(也是默认设置)。我们可以编写一个列式函数来删除任何包含缺失值的列。这只是为了演示——有更好的方法来处理缺失值(参见官方熊猫文档)。
def remove_missing_columns(col):
if col.isnull().values.any():
return col
data.apply(remove_missing_columns, axis=0)
应用逐行函数
我们还可以应用一个函数来转换一行中的每一列。这就要求我们设定axis=1.
def is_educator_above_50(row):
return row['age'] > 50 and is_educator(row['occupation'])
data['is_educator_above_50'] = data.apply(is_educator_above_50, axis=1)

Groupby 操作
Groupby 操作对于分析 Pandas 对象和从大量数据中设计新功能非常有用。所有 groupby 操作都可以分解为以下步骤:
- 将对象分成组
- 对每组应用一个函数
- 结合结果
通常,对象会根据某些标准进行拆分,为每个组计算一个汇总统计数据,并组合成一个更大的对象。我们可以使用 groupby 运算来计算每种职业的平均年龄。
- 按职业分割数据帧
- 将一个均值函数应用于每个职业
- 把平均年龄结合成它自己的对象
这个操作的代码非常简单:data.groupby(by=['occupation']).mean()['age']
by 参数表示如何确定组, mean() 是兴趣的统计量,按年龄索引获取年龄的组统计量。输出是一个系列,其中职业是轴标签。

我们可以使用多个参数来划分群组,例如,职业和他们的电子邮件是否链接的组合:data.groupby(by=['email_linked', 'occupation']).mean()['age']

除了意味着,还有其他内置函数可以应用于每个组: min,max,count,sum 等等。我们也可以使用agg() 来应用任何自定义功能。聚合方法对于返回多个汇总统计信息也很有用。
例如,data.groupby(by=['occupation']).agg(['mean', 'sum'])['age']将返回每个组的平均年龄以及年龄总和。
数据帧属性
这些属性帮助我们探索和熟悉新的数据框架。
data.columns返回所有列的列表data.shape以(行数,列数)的形式返回维度data.dtypes返回每列的数据类型data.index返回索引值的范围
以下是一些可能有帮助的额外阅读材料:
- 参考熊猫官方文档了解语法、用法和更多例子。
- 书籍:用于数据分析的 Python:与 Pandas、NumPy 和 IPython 的数据角力
感谢您的阅读!
如果你喜欢这篇文章,你可能想看看我关于数据科学、数学和编程的其他文章。请在 Medium 上关注我的最新更新!
为了赞美抛硬币
统计数字
不起眼的抛硬币如何帮助解决数据科学中的问题

来源:像素
1953 年,卡尔·巴克斯创作的一部名为《翻转决定》的唐老鸭漫画,提出了一种伪哲学,叫做翻转主义。前提很简单:对于人生中每个需要做出决定的十字路口,选择一张硬币的正面(正面或反面),投掷硬币,然后根据掷硬币的结果做出决定。作为哲学的发明者,巴蒂教授宣称:
“人生不过是一场赌博!让 flipism 图表你的漫谈!”
现在,不幸的是,在漫画中,对唐纳德来说,flipism 并不奏效。每个决定都要掷硬币,这给可怜的唐纳德带来了一连串的不幸。然而具有讽刺意味的是,为了得到应有的惩罚,唐纳德通过抛硬币找到了正确的门背后的欺诈行为,成功地追捕到了骗子教授巴蒂,所以也许这种哲学确实有一些价值(或者更有可能,只是证明了作者的力量)。
虽然我不一定主张过基于抛硬币的生活,但事实证明,抛硬币和管理抛硬币的基本统计原则在应用于数据中经常面临的一些问题时特别有效。
我们来看三个例子。
基准模型
想象一下,现在你已经训练了你的机器学习模型,比方说,在给定一些用户上下文信息的情况下,预测网页上广告的点击率。你使用一些关于你的用户的信息,例如,他们来自哪个国家,他们的人口统计信息,他们来自的登陆页面和一系列其他功能。如果他们在你的平台上工作,你可以使用基于他们在使用平台时所做的特性来提高你的模型的性能。
然后你训练你的模型。现在,
您可以使用什么样的最简单的基准来了解您的模型是否是高性能的?
值得注意的是,在这种情况下,任何训练有素的模型都必须以简单的抛硬币为基准。
如果我们以 50%的概率为广告的点击和非点击分别指定正面和反面,然后通过投掷硬币随机指定正面和反面来预测广告点击,我们得到一个随机分类器。现在,任何经过训练的模型的目标都很简单:它必须至少击败随机预测器。这就是为什么测量模型的准确性很重要,然后将其与随机预测值的准确性进行比较(平均而言,准确性为 50%)。
我们甚至可以更进一步:假设我们知道广告的历史基础点击率是 30%。然后,使用上面的硬币方法,我们现在模拟一个有偏向的硬币,正面有 30%的概率,反面没有。任何预测模型都必须击败这个新的随机预测基准。请注意,准确性不是衡量性能的唯一标准;其他如假阳性率,以及精度和召回率也可以使用。
我们可以看到这如何应用于任何类型的二元类预测场景,随机预测器作为一个简单的健全性检查:如果一个模型不能击败基准,那么是时候回到绘图板。相反,如果它确实超过了基准,那么我们想量化多少。通过这个简单的比较,我们可以很容易地做到这一点,确信我们的模型不是出于随机的机会,而是比那更好。
计算大数
自计算的早期以来,计数一直是计算机科学的一个标准焦点。一个值得注意且重要的问题是大数的计数,以及确定大量项目的大小(基数)的相关问题,这是每个现代数据库系统都面临的问题。
假设你有一个有限的内存空间,但是必须计算非常大的数字。更具体地说,考虑这样一个场景,您受限于一个 32 位寄存器,并且需要计数到大于 2 -1= 65,535 的数。这种情况在高速网络路由器中很普遍,其中计数需要在非常短的时间窗口内在快速但昂贵的静态随机存取存储器上执行。
一个技巧是近似地计数,即放松必须精确计数的要求,而不是以一些小的误差幅度计数。这里的基本原理是,一旦您处理大数字,与 1 亿的值相比,相差几百的小误差对某些应用程序来说并不是什么大问题,尤其是那些大致的数字已经足够可行的应用程序。
计算大数的简单算法如下:
要增加计数器,掷一枚等于计数器当前值乘以数字的公平硬币。如果硬币每次都正面朝上,计数器加 1,否则什么都不做。
这就是众所周知的莫里斯算法,它是由贝尔实验室的罗伯特·莫里斯于 1977 年发明的。
看起来很简单,但是它是如何工作的呢?
假设计数器当前处于数字 2。现在,为了增加,我们连续两次投掷一枚公平的、无偏见的硬币,所以我们可以得到的排列是
HH,HT,TH,TT
其中 H 代表正面, T 代表反面。按照上面的说明,我们只在 HH 上递增,实际上只以 0.25 的概率递增。因为下一个计数器状态将是 3,所以由计数器表示的数字范围在 4 和 8 之间(包括 8)。
随着计数器值变大,我们可以看到算法只是存储数字范围的以 2 为底的对数,即* 1,2,4,8,…无限。由于任何数字 N 都可以用对数来表示,即 log ₂ N,那么莫里斯计数器所做的就是只保留 log ₂ N, 的第一个数字,换句话说就是数字 N 的指数。*
Phillipe Flajolet 对 Morris 算法进行了更彻底的分析,通过将其增量建模为离散时间生灭过程(他还在论文中创造了术语近似计数)。我们可以进一步扩展 Morris 算法(如果我们愿意的话),为更大的数字保留指数的指数!
另一个有趣的花絮来自信息论分析。如果我们想要一个数字 N 的精确计数,我们将需要对数* ₂ N 位。莫里斯提出了一种计数器,它使用对数 ₂ 对数 ₂ N 位,因此只保留数字的指数。我们现在可以看到,内存增长的规模将比我们想要一个确切的数字要慢得多。*
如今,Morris 算法已经被改进的算法所取代,例如现代数据库系统中使用的hyperlog log算法,以及 SQL 方言中的近似不同计数函数,例如 Presto 和雪花。然而,Morris 算法仍然是现代概率计数算法的先驱,并且是最容易实际实现的算法之一。**
伯努利多臂强盗
多臂土匪问题涉及在一组竞争选项中最大化期望回报的问题,其中每个选项的回报最初是未知的,但随着时间的推移是可发现的。这个术语暗指赌场中的一排排老丨虎丨机,也称为独臂强盗。

一排独臂土匪。(来源:派克斯)
在多臂土匪的情况下,一个赌徒必须玩一套吃角子老丨虎丨机,以找出随着时间的推移哪台机器将提供最高的预期奖励。当游戏者第一次开始时,游戏者不知道随着时间的推移哪台机器将提供最高的预期回报;如果游戏者这么做了,那么问题就变成了通过独自在上面玩来利用正确的吃角子老丨虎丨机。由于游戏者没有预先的知识,那么游戏者将不得不探索一组机器,随着时间的推移,确定产生最高预期回报的机器。
因此,在回报最初未知的环境中,我们有一个探索对开发的常见案例。你应该采取什么样的策略,你需要做多少探索和开发?开发得太快,你就有陷入局部最大值的风险;探索太多,你将永远无法最大化你的预期回报,因为你会从一个选项跳到另一个选项。
现实世界中的许多问题都会出现这种情况:投资组合分配、推荐系统、优化显示给用户的广告、搜索结果排名和约会。虽然有人可能会在最后一次申请时生气。
有趣的是,许多这样的问题都符合抛硬币的框架。让我们考虑我们想要向用户展示的广告的两种变体,目标是最大化点击率。我们在我们的平台上部署广告的两种变体,50%的用户群看到变体 A,而其余的看到变体 b。然后,随着时间的推移,我们希望分配更多比例的用户来查看表现最佳的变体。
我们可以对这个场景建模如下:当每个用户看到一个广告时,一次点击,比如说头头,就是一个奖励。广告 A 和 B 都可以被建模为具有不同翻转概率的硬币。然后,我们的任务是推断每个广告的点击率,这实质上是推断广告 A 和 B 的掷硬币概率。我们还想知道基于这些概率哪个是表现最好的变体(这可以用作贝叶斯 A/B 测试的基础)。
一旦我们做到了这一点,我们就可以计算出如何将用户比例分配给表现最好的广告。分配策略的主题仍然是一个活跃的研究领域,有一些著名的解决方案,如置信上限算法和 Thompson 抽样。点击这里,查看 Lilian Weng 对这些算法的实现。
我们可以将这个框架扩展到多种广告。多臂 bandit 公式已被各公司用作经典 A/B 测试的替代品,如网飞。
最好的部分是,它可以应用于广告以外的其他东西!您当然可以将它扩展到推荐商品和对一组搜索结果进行排名;对这两种情况的警告是,在 UI 中向用户显示项目时,您必须考虑位置偏差。其中一个版本用于在 Canva 对图片搜索结果进行排名,它已经投入生产有一段时间了。此后,它被更强大的算法所取代,但却是一个令人惊讶的难以推翻的基准!
虽然唐老鸭可能在抛硬币决定其人生道路方面运气不佳,但抛硬币解决数据科学中的问题确实非常有用。
不起眼的抛硬币是这样一个通用的框架,它可以作为二元选择情况下的一个有用的心理模型。下次你遇到问题的时候,想想你可以如何使用抛硬币!只是…不要做唐纳德做过的事。
参考
[1]菲利普·弗莱约莱。“近似计数:详细分析”。http://algo.inria.fr/flajolet/Publications/Flajolet85c.pdf
[2]彼得·奥尔。“使用置信界限进行开发-探索权衡”,《机器学习研究杂志》第 3 期,2002 年,第 397–422 页。http://www.jmlr.org/papers/volume3/auer02a/auer02a.pdf
[3]威廉·r·汤普森。“根据两个样本的证据,一个未知概率超过另一个未知概率的可能性”。《生物计量学》, 25(3–4),1933 年,第 285–294 页。https://www.dropbox.com/s/yhn9prnr5bz0156/1933-thompson.pdf
一开始,有模拟
一本新书调查了数据科学的起源

数据科学早期的主力 IBM 704(来源:计算机历史博物馆)
还记得第一次听到“数据科学”这个名词的时候。它被我的雇主非常喜欢的一家昂贵的 It 咨询公司的客户经理抛弃了。“数据科学?”我的老板说,他是一位身经百战的 IT 老兵。"那听起来像是一群刚刚加薪的统计学家."
在她的新书“If Then:the simulatics Corporation How Invented the Future”中,吉尔·莱波雷(Jill Lepore)为数据科学提供了一个起源故事,或者如当时所知的那样:“海量数据”。
生命周期很短的小公司 Simulmatics 是否真的发明了数据科学的未来,这是一个疑问。《纽约时报》在评论 Lepore 的书时,用了一个更加怀疑的标题:“笨手笨脚的 20 世纪 60 年代数据科学家,他们预见了脸书和谷歌。”
我更倾向于时代的解释;仿真预测了未来,但实际上它创造的很少。
这并没有从 Lepore 的书中带走任何东西,这是该国最着名的历史学家之一对数据科学早期的深入研究和精心撰写的旅程。Lepore 是哈佛大学的历史学教授,也是《纽约客》的作者,他的上一本书【这些真相】:是一部美国历史。

《如果那么》作者吉尔·莱波雷(来源:Liveright/W.W .诺顿)
这是 Simulink 故事中的三位明星,Lepore 将其描述为“马克·扎克伯格、谢尔盖·布林、杰夫·贝索斯、彼得·泰尔、马克·安德森和埃隆·马斯克的去世已久的白胡子祖父。”:
埃德·格林菲尔德(Ed Greenfield),一个麦迪逊大街的广告人,谎称自己曾就读于耶鲁大学法学院和芝加哥大学(事实上,他在印第安纳州的沃巴什学院(Wabash College)就读一年后就辍学了)。
比尔·麦克菲,一个才华横溢但显然相当疯狂的 FORTRAN 程序员,有一次被他的妻子不由自主地送进了精神病院。
伊希尔·德·索拉·普尔是定量社会科学的专家,被怀疑是共产主义者,在一位名叫理查德·尼克松的年轻加州众议员的干预下,他才获得了从事政府工作所需的安全许可。
格林菲尔德的伟大想法是将定量社会科学和计算的力量带入他的广告公司,在那里它将被用来兜售消费品和让政治家当选。人类行为,无论是投票还是决定购买哪个品牌的肥皂,都将被建模、模拟,并最终被应用于海量数据的复杂算法所操纵。
听起来熟悉吗?这一切实际上开始于 1952 年。
格林菲尔德是一位热情的自由主义者和民权活动家。他希望利用分析和技术来帮助 20 世纪 50 年代和 60 年代的民主党人消除共和党人当时享有的技术优势。
他的公司爱德华·l·格林菲尔德公司建立了自己的“社会科学部门”。这成为了 1959 年由格林菲尔德和普尔创建的 Simulmatics 的前身。“他们很自信,也很自大,”Lepore 写道。"但他们有时怀疑这一切是否都是胡说八道."
最终,格林菲尔德以及他的同伴普尔和麦克菲的雄心,远远超出了当时的技术支持。当时最先进的是 IBM 704 大型机。为了在大型机上运行程序,IBM 开发了 FORTRAN(代表“公式翻译”)。
这就是问题所在。Lepore 引用了 IBM 的 FORTRAN 文档:
“FORTRAN 语言旨在能够表达任何数值计算问题……然而,对于机器语言具有逻辑意义而非数值意义的问题,它就不那么令人满意了, 它可能完全无法表达某些问题 。”(重点后加)。
你可能已经注意到,人类通常不会根据数字计算来做决定。就此而言,许多都不太符合逻辑。Simulink 用不太理想的工具集解决了一个大问题。
另一个问题是数据很难获得。营销和研究公司倾向于将其视为专有资产。开始开放联邦数据存储的第一版《信息自由法案》直到 1967 年才颁布。当数据可用时,通常必须从穿孔卡片和磁带盘等媒介输入。
在 1960 年的总统选举中,Simulmatics 一跃成为知名企业,并将其服务卖给了约翰·肯尼迪竞选团队。它是基于麦克菲的 FORTRAN 编程,麦克菲在他的哥伦比亚大学博士论文中将其描述为“完全可观察的选民”。
Lepore 指出,“在初级水平上,它与剑桥分析公司(Cambridge Analytica)在 2015 年和 2016 年向川普和英国退出欧盟“脱欧”运动出售的服务没有任何不同。”
大多数创新都有很多发源地。在 Simulmatics 的例子中,一个诞生地是纽约市贝尔维尤医院的精神病病房。在妻子把他送进病房后,麦克菲继续在病房里进行新的项目。
对于肯尼迪的竞选活动,Simulmatics 基于 460 个不同选民群体的历史投票模式进行了分析。一个示例组:“中西部,农村,新教徒,低收入,女性。”
关键建议是:肯尼迪不要试图回避他的天主教问题(这在 1960 年是一个很大的问题),而是作为反对偏见的整体立场的一部分,直面这个问题。这将吸引肯尼迪弱势的两个群体:黑人和犹太人。这也有助于进一步激励天主教徒。
仿真技术在肯尼迪的选举中发挥了多大的作用还有待商榷。但毫无疑问的是,北方的黑人选民是他险胜的主要因素。Simulmatics 立即开始了自己的活动,宣传其在肯尼迪竞选中的作用。这引发了一场关于肯尼迪实际上在多大程度上是一位电脑控制的总统的争论。
这也是这本书最精彩的部分之一。今天,这样的发现不会引起任何反响。大多数选民会简单地认为,所有的政治家都使用技术来分割选民,并为不同的群体量身定制信息。
然而,在 1960 年,这是一桩丑闻。它有效地结束了政治运动的模拟工作。
但是其他的机会出现了。1962 年,Simulmatics 受雇为《纽约时报》对选举结果进行实时分析。但事实证明,实时意味着尽快通过电话和电传接收到反馈,然后编码到穿孔卡上,通过调制解调器提交到 IBM 数据中心。《泰晤士报》很快失去了兴趣。
政治运动的合理后续是帮助五角大楼发动心理战。越南提供了机会。“越南,”Pool 在 1966 年说道,“是我们有过的最伟大的社会科学实验室。”
许多社会科学家已经在越南问题上与五角大楼分道扬镳,并停止争夺五角大楼的合同和拨款。对于不隶属于大学的 Simulmatics 来说,这不是问题。它有自己的团队,包括一些当地人,在南越的土地上对全国各地的村庄进行调查。
资助南越仿真工作的五角大楼高级研究计划局(ARPA)很快对结果感到不满,认为它们“不是负责任的研究人员的工作”。当 ARPA 终止合同时,它甚至更为关键:“仿真不仅反映了作为一个组织自身的信誉——它看起来更像是一个骗局——而且反映了一般行为研究的信誉。”
随着五角大楼的工作被关闭,Simulmatics 转移到了 20 世纪 60 年代末困扰美国的城市动荡,当时越南和民权运动正在酝酿。它被雇来协助肯纳委员会,该委员会是政府为研究暴乱的原因和影响而成立的。它模拟了市中心贫困的原因和解决方案。不出所料,报告得出的结论是,解决办法是摆脱贫困。
然后生意开始枯竭。到 1969 年,Simulmatics 已经是一家名存实亡的公司。1970 年,它申请破产。到 1974 年,随着 simulation 成为模糊的记忆,计算机模拟人类行为的整个概念受到质疑。水门事件和越南事件增加了人们对政府数据收集的怀疑。1974 年的隐私法使得政府收集和汇总个人数据更加困难。
格林菲尔德于 1983 年去世,一年后去世。仿真故事最后悲伤的一章写于 1998 年。比尔·麦克菲(Bill McPhee)是一名程序员,他在精神病病房里编写了最初的 Simulink 代码,坐在电脑前开枪自杀。他 77 岁了。
每一波创新都是从一长串行不通的事情开始的。
Simulmatics 是一家失败的公司,它建立在冷战思想的基础上,即人类行为可以被操纵以达到政府、政治家和公司的目的。但是这个想法仍然存在,即使 20 世纪 50 年代和 60 年代的技术不支持它。毕竟,在今天的社交媒体平台上运行的算法比 21 世纪版本的仿真思想更好吗?
开始时,有一片空白*
一个进化代码和意想不到的后果的故事

信用: RawPixel
为了纪念即将在谷歌发布的“软件工程”,我强烈推荐它,我想我会讲述一个软件进化和功能蔓延如何出错的故事,虽然在旅程的每一步都感觉很好,但十年后的最终结果是一场具有惊人大爆炸半径的灾难。这是我与东尼·霍尔的十亿美元错误或者丹尼斯里奇的最昂贵的单字节错误的适度类比,而且,巧合的是,它同时涉及指针和以零结尾的数据结构。
这一切开始时都很天真。今年是 2009 年。我的一个同事有大量的点积需要加速,以提高一个大规模优化问题的可扩展性。当时,浮点计算并不是我们工作负载的常见瓶颈,我们也没有现成的解决方案可用:引入 BLAS 库是多余的,对于像我这样喜欢编写复杂的数学代码和摆弄矢量化英特尔指令的人来说,还有更简单、更有趣的事情可以做。
没问题,我将使用 SSE 内部函数和一些手动调整的展开来快速实现点积。有一个非常聪明的方法来利用可怕的美丽的达夫的设备,并在不滥用预处理器的情况下快速展开,代价是同样可耻的滥用 C 语法。我喜欢它。一个窍门是:SSE 指令喜欢对 16 字节对齐的数据进行操作。我们的工具链并不总是提供这种保证,编译器提示仍然是特定于编译器的。没问题:我将分配一个更大的缓冲区,并添加一个指向最近的 16 字节边界的数据指针来强制对齐。
但是,等等,如果我要对数据的分配方式加以限制,现在很容易通过正确的输入来确保契约得到执行。因此,让我们将这个裸指针包装成一个新的数据结构: float ** 变成类似于aligned _ scoped _ array
等等。有人说线性代数吗?我们可以批量处理那些点产品吗?到那时,我们真的进入了 BLAS 的领域,但是让我们不要仅仅为了一个基本的矩阵乘法而重写一切:只需要给数组添加另一个维度,一个执行 2D 乘法的函数,我们就可以开始了。对齐和填充数据也意味着我们可以遍历它,而无需任何进一步的指针间接寻址,这使得代码简短而优雅。当然,任何阅读过 BLAS 相关文献的人,特别是关于该主题的开创性的 Goto 论文,都知道短小精悍可能会带来大量的性能问题,因为关于缓存性能的考虑可能会变得非常复杂。正确的答案可能是不要尝试推出你自己的实现,但是…这很有趣,感觉像是进步,对吗?
坚持住。你能对量子化的表示做同样的事情吗?哦,但是是的!事实上,我写了这篇漂亮的论文关于混合无符号和有符号定点表示对于神经网络来说是如何令人惊讶地工作的。BLAS 在定点数学领域没有提供任何东西,但所有对齐和填充方面的考虑仍然适用。所以我将为 int8uint8* 产品添加一个专门化,我们就完成了。魔法。
现在,你可能开始看到一个模式。特性蔓延,每一步都有略微次优的决策,进展的幻觉和越来越难回头的决策。几年后,我的裸指针一次性包装器已经变成了一个成熟的触须矩阵库,学究式地称为 FastMatrix。它支持 x86、ARM 和 CUDA。处理浮动、双、 int8 、 uint8 、 int16 和 int32 。它可以为 Android 和 iOS 编译。它已经移动到我们共享代码库中的一个常规的' util' 目录中。它正被深度学习代码库以及越来越多的项目使用,其中大多数我从未听说过。在我们的谷歌范围分析仪表板上,它在 CPU 周期最大消耗者的名单上也占据着一个令人尊敬的位置。有什么不喜欢的?
好吧。它还有一个糟糕的、令人抓狂的不一致的 API,部分原因是不同的硬件供应商针对不同的数据类型和布局进行了优化,而我没能抽象出那些实现细节。它还陷入了一个进化的死胡同:仅仅为了节省几个 CPU 周期和代码行而强制控制数据布局被证明是一个糟糕的想法,因为在它通常强制用户经历的所有数据移动中,大部分好处都消失了。它的存在阻碍了更好支持、更全面、BLAS 感知的解决方案的进展,例如令人敬畏的 Eigen 库,它同时获得了对定点操作的支持。它的 CUDA 端口充满了反模式,当我看到在代码库中的其他地方进行剪切和粘贴时,我很害怕。我们还错误地尝试支持跨指令集的一些算法的动态调度,如果调用者不小心,可能会导致错误平台的编译单元泄漏到一个人的二进制文件中,并导致难以理解的崩溃,这几乎不可能追溯到最初的根本原因,因为二进制文件甚至不必调用被感染的违规代码。哎呀。在广告 SRE 来敲门之前,一切都是娱乐和游戏。
我有没有提到过谷歌在我第一次申请软件工程师时拒绝了我?他们可能说得有道理。那个图书馆需要消亡。
但到那时,所有这些主要的设计缺陷也带来了短期回报:速度相当快。它在那里。由于有点松散,类似 C 的 API,很容易添加功能,或复制粘贴它。消除一些最糟糕的维护噩梦可能会花费数千个 CPU 内核,或者数百个软件工程师小时:对性能敏感的代码极难推理,因为尽管可以安全地假设它具有不错的正确性覆盖率,但性能覆盖率很难实现:10%的速度回归可能只花费一微秒或使数据中心过载,并且您可能无法分辨出差异,直到有人在提交更改几个月后部署了包含您的更改的二进制文件。那时,我看不到的其他库已经开始依赖它,包括它最粗糙的实现细节,我已经达到了疫情级别的感染。
现在是 2020 年。已经十年了。这个怪物还没有完全死去,尽管我已经砍下了它的许多头。最近,该图书馆的死忠粉丝极大地推动了它的消亡,这位死忠粉丝已经决定离开该公司。不要告诉他们:我很高兴地在同一天删除了他们所有的代码。在我在这里的 12 年里,我已经自豪地从我们的库中删除了超过 150 万行代码,然而这些卷须顽固地保留了下来。回想起来,我最近几年做的最好的决定是坚持让 TensorFlow 不依赖于任何一个。
Donald Knuth 有一句名言:直到最后一个用户死去,代码才会被完全调试。显然,Knuth 不在谷歌工作,否则他可能会说“……它的最后一个用户和他们所有的同事……”。即使代码死了,它的一些反模式仍然存在,或者在人们的头脑中,或者通过传统的复制方式。前述书的合著者 Titus Winters 喜欢说“软件工程是随着时间的推移而集成的编程”一个问题是,所涉及的时间常数可以用几十年来衡量,很少有人在任何工作岗位上呆得足够长,以至于看到自己的错误暴露出来。局部地、渐进地做出的决策会很快毒害整个代码库,并且变得难以回头,特别是当人们转向其他更重要的问题时。
乐章结尾部
几年后,当我开始研究dist faith代码库时,我立即注意到一些令人惊讶的事情:保存神经网络的最内部结构是一个裸露的“*空洞** ,仅此而已。我查了一下是谁写了那篇异端邪说,当然,结果是杰夫·迪恩。哦。我胆怯地问:“杰夫……但是为什么呢?”???'他的回答很简单:“嗯,我们还不知道我们在做什么,所以我们不要在数据结构中加入任何我们无法回避的假设。果然,在这种情况下使用正确的数据布局是非常不明显的:您可以使用它来优化 CPU 上的正向推理,但它会影响训练期间反向传递的速度,并且反向传递的成本大约是正向传递的两倍。但在生产中,你大多只是运行推理,所以这可能是正确的权衡?这要看情况,因为在 GPU 上几乎正好相反。这些权衡需要一些时间来解决,最终我们编写了一个类型系统,一个布局,并删除了裸露的指针。教训?有时候,让 Hyrum 定律(即将出版的书的另一位著名合著者)对你有利会更好,推迟 API 合同,直到你理解你的用户将如何(ab)使用它们,而不是过早地承诺一个 API 并成为它的受害者。
在数据时代,IT 和数据团队 2.0 和数据公民
上的数据值
IT、数据和业务团队不断变化的角色
在 本系列的第一篇文章中,我们看到了数据的价值在于什么,数据如何被使用,以及它如何影响价值创造。第二个是关于实现价值创造最大化的方法,特别是通过数据质量、完整性和可利用性。
这第三篇也是最后一篇文章讨论了 IT、数据和业务团队的角色和职责,以及它们在数据时代的演变。事实上,在当前所有领域“数字化”的背景下,许多企业正在转型。数据是服务质量、卓越运营和决策制定的日益重要的驱动因素,通常是这种转变的核心。
我们正在经历一场革命,这场革命带来了新的工作方式、新的工具和新的实践,以更好地生产、管理和使用数据。因此,直接或间接负责从数据中创造价值的团队的角色正在发生变化。
在本文中,我将展示我自己对这些团队在从数据中创造价值方面的角色和职责的看法,特别是就保证数据质量、完整性和可利用性的方法而言。
我不会冒险尝试定义 CDO(首席数据官)的角色,因为我不认为它有一个通用的定义,并且说他“负责数据”远远不足以获得一个概念,特别是考虑到该领域的规模。不同领域的许多公司对于其数据战略的不同组成部分的 CDO 都有自己的概念。然而,在我看来,从数据中创造价值显然应该是这一数据战略的核心,是 it、数据和业务完美结合的结果。

数据质量是业务团队的责任
在我看来,数据质量,即“在正确的时间、正确的地点提供的好数据”,必然是负责生产和使用数据的人的责任,但也是定义数据应该用于什么、为什么和如何使用数据,以及确定数据是否符合公司质量要求的标准的责任。
因此,业务团队的职责是:
- 实施流程以加强、衡量和控制数据质量及其对服务质量、运营卓越性和决策制定的影响
- 将数据视为他们所拥有的业务应用程序的关键元素,这些应用程序是由 IT 团队根据他们的(业务)需求开发和/或配置的
- 确保(主要通过管理)生成数据的运营团队意识到数据质量作为关键驱动因素(服务质量、卓越运营和决策制定)的重要性
显然,IT 团队也参与其中,通过开发和配置允许生成或传输数据的操作和分析应用程序,来衡量数据的质量等。然而,他们的角色只是解决业务团队表达的需求,在这种情况下,业务团队就是他们的客户。
数据完整性,IT 对数据的首要责任?
另一方面,数据完整性是负责存储和复制数据的人的责任。在我看来,完整性的保证可能是 IT 团队对公司数据的首要责任。
正如我在上一篇文章中解释的那样,数据完整性主要是一个技术问题,完整性的保证依赖于基础设施和工具,以及与存储和复制数据相关的过程和良好实践,所有这些都是 it 的领域。
因此,他们必须保证数据(根据业务定义的规则生成)保持不变,拷贝或传输的数据完整地到达目的地,并与源保持完全一致。
此外,当本应传输的部分数据丢失时,我认为这是一个完整性问题。因为事实上,作为整体一部分的缺失数据会导致整体完整性的丧失。因此,不同系统之间的数据传输问题尤其关键,并且今天可能代表公司数据完整性问题的重要部分,如果不是最大部分的话。
最后,所有转换数据的过程(计算作业),从而通过合并、聚合、重新格式化等来修改数据。必须始终允许轻松追溯到“原始”的未转换数据,特别是为了验证输入数据是完整且未被更改的(并且输出数据与指定的转换规则一致)。
因此,这种完整性保证还“包括”保证从一个业务应用程序到另一个业务应用程序,或者从应用程序到用于报告和商业智能的平台和分析模型,提取、传输、接收和转换数据的所有过程的可追溯性和监控。这也是 IT 部门职责的一部分,即使在规范中没有来自业务部门的具体要求(在这种情况下,IT 部门还将起到咨询的作用,并有责任让业务部门相信这些关键特性的必要性)。
新工具和新实践正在改变 IT 的角色
如果关于数据质量和完整性的责任看起来很清楚,数据可利用性是另一个主题,尤其是关于分析。
事实上,在商业应用和数据的操作使用中,可利用性主要取决于质量和完整性。这些应用程序通常旨在满足特定的业务需求,从而允许相应地使用数据。
另一方面,对于分析来说,这要复杂得多。传统上,IT 和数据团队是公司的“报告工厂”。业务团队根据数据、指标、它们的定义和目标(什么、为什么和谁)、将允许分解这些指标的维度(每个客户、每月等)精确地指定他们的需求。),以及报告的设计。然后 IT 和数据团队构建报告。
然而,这种情况正在改变,原因和方式如下。
数据公民的崛起
一方面,需求急剧增加,用户希望分析和展示越来越多的数据,缩短“项目时间”和“上市时间”,并且他们的需求不断变化。因此,“传统的”构建周期(规格说明>开发>测试>部署)变得越来越不适合,因为它不能在如此短的时间跨度内对持续敏捷性的需求提供令人满意的响应
另一方面,工具在快速发展,特别是为了适应这些新的需求和这些新的“数据公民”,他们已经习惯于一直使用数据,并且越来越有能力分析和显示数据。他们还寻求更加独立,不再依赖 IT 和数据团队,摆脱传统构建周期固有的惰性。
数据可视化实践就是一个很好的例子。Tableau Software 或 Power BI 等工具极大地推广了报告和数据分析工具的使用。如今,他们倾向于将更多的数据公民作为业务团队、分析师、经理等的目标。比 IT 和数据团队的开发人员更多。构建报表不再需要成为专业开发人员,您所需要的只是了解您的数据,熟悉 IT 系统和使用数据库的基本原则(我这里所说的复杂程度或多或少与数据透视表有关)。这些工具允许任何数据公民构建他们自己的商业智能报告和仪表板。
从报告工厂到数据提供者
因此,在短短几年内,数据可视化这一特定领域中的“谁做什么”已经从 IT 显著转移到业务用户。但这并不意味着负责报告和商业智能的 IT 和数据团队面临失业的风险(根本没有)。
首先,人工智能和高级分析也在兴起。使用机器学习等先进技术构建和工业化复杂模型或算法需要大量的 IT 专业知识和高技能人才,如数据科学家、工程师或建筑师,他们将通过新的和更专业的数据专业人员扩大 IT 和数据团队的队伍。
然后,虽然数据公民不再依赖商业智能团队代表他们并根据他们的规范来生成简单的报告和仪表板,但他们仍然希望向他们提供数据,并保证数据的完整性和可利用性以进行分析(如果可能,还需要实时提供)。
数据可视化工具的大规模实现也需要对这些工具进行配置和适当的管理(在许可等方面)。).他们还需要依赖可靠、高性能和可扩展的基础架构,所有这些都仍在 IT 的范围内,并且在规模上可能相当具有挑战性。
最后,IT 和数据团队可以成为部署这些工具和相关实践的关键合作伙伴。如果 Tableau 软件或 Power BI 比其他一些不太“用户友好”的工具更容易使用,它们仍然需要足够的培训和支持。它不仅仅是关于使用工具,数据可视化有它的理论(和理论家),公认的良好实践,以及可以达到数十万成员的用户社区(例如,参见 Tableau Software)。
IT 和数据团队 2.0 和数据公民
IT 和数据团队受益于使用这些工具的丰富经验,他们可以在部署和开发数据公民的相关实践中发挥关键作用,为他们提供培训和支持,以帮助他们更好地使用工具和数据,甚至在公司内部创建用户社区并为其注入活力。
还有更多。现在,业务团队拥有了数据,他们希望能够在将数据放入仪表板之前对其进行处理、清理、重新格式化,甚至应用更复杂的转换,所有这一切除了他们自己,不需要依赖任何其他人。事实上,即使有世界上所有的善意来保证数据的质量和完整性,在它可以被正确地分析和显示之前,它通常仍然需要被“修复”。如果良好的实践表明数据应该只在源位置固定,那么在您真正需要它的时候并不总是可能的。这被称为“数据准备”或“数据准备”,今天它占数据分析师工作的 80%左右。
因此,已经发生在数据可视化上的同样的事情现在正在发生在数据准备上。用户希望能够在没有开发人员帮助的情况下,更容易、更快速地处理他们的数据。这并不意味着 ELT/ETL(提取、转换和加载数据的工具)将会消失(远非如此),但同样,在应用于数据的转换方面,“谁做什么”正在发生转变,数据准备很可能是数据公民时代的下一场小革命。
IT 和数据团队将继续提供数据,并通过优化的工业化流程对数据进行“上游”转换,但这些可能只有在数据公民直接使用数据准备工具执行“试错”流程后才能实施,因此数据公民将越来越多地参与这些流程设计。同样,这些数据公民在使用这些数据准备工具和学习相关的良好实践方面需要支持。
总之,IT、数据和业务团队的角色正在发生变化。业务用户正在成为数据公民,并从简单的报告消费者转变为创造者、数据专家甚至影响者。他们那边的 IT 和数据团队正在从报告工厂转变为数据提供商,从开发人员转变为教练,从分包商转变为顾问、培训师甚至社区经理。
在我看来,IT 和数据团队还必须作为业务合作伙伴在发展数据素养(读取、分析和解释数据的能力)和数据驱动文化(基本上包括尽可能多地使用数据来行动和/或决策)方面发挥关键作用,因为他们负责部署的新工具和实践是关键驱动因素,可以更好地理解和满足我们客户的需求,更快更好地工作和决策。
感谢您的阅读,请让我知道您的想法,并毫不犹豫地分享。
用他们自己的话说:60 年的总统辩论
从肯尼迪-尼克松到拜登-特朗普总统辩论的 NLP 分析

希拉·墨菲在 Unsplash 上拍摄的照片
由于我们中的许多人(希望)已经通过邮件或提前投票的方式投了票,可能仍有一些人在 11 月 3 日之前没有做出决定。本着民主的精神,我希望这篇文章能在你投票之前送到你手中。受到即将到来的选举日的鼓舞,我决定翻阅一些旧的总统辩论。怀旧可能是 2020 年的一个关键话题,因为人们开始意识到所有在前疫情时代不受重视的事情。选举日是一个重要的十字路口,在选择道路之前,回顾一下我们在不断发展的民主中所处的位置可能是有益的。
这个项目最初的灵感来自于 NLP 的一篇关于散点文本可视化的帖子。《华盛顿邮报》分析了 2012 年总统大会的演讲(奥巴马诉罗姆尼),并按政党进行了分类。这是一个伟大的阴谋,看到一个用文字说明的党派分歧的快照。词频和排名还显示了党纲中关键主题的快照(在上对角线和下对角线)以及对角线上的常见问题。大会演讲中充满了关键的政党纲领短语。
- 共和党:失业、商业、自由
- 民主党:女性,中产阶级,医疗保险
下面,我用散文本来探索 1960-2020 年总统辩论的主题特征。辩论也是一个有趣的案例,原因有很多。主持人或小组成员选择当前问题或更多关于领导力的自由话题。候选人并不为自己的支持者感到舒服,但是经常会面临犹豫不决的选民提出的棘手问题。此外,时间限制要求他们简明扼要,候选人必须衡量他们选择的词来解决这个问题。通过每个候选人,人们可以看到一个选举周期中政党意识形态的快照。
下面是一个用 PyTextRank 给突出短语打分的散点图截图。这些短语然后通过它们的密集等级频率和两个当事人类别之间的密集等级频率的差异关联到一个点(这里是一个很好的例子!)。在标题中,有一个互动情节的链接,你可以点击一个点,看看谁说了什么!

散点图快照,显示民主党人(垂直)和共和党人(水平)在坐标轴上的排名频率。民主党人经常使用的短语更靠近左上角,共和党人在左下角。黄色对角线代表双方共有的更中性的词语或问题(如贸易、民主、政治、犯罪)。情节是互动的,允许点击单词,并看到所有发言者包含该词的辩论响应。互动图可以在这里访问:(散点图总统辩论带有搜索栏)
窥探图中的特征:
基于一个词,我们可以使用散点文本可视化的直观特性来深入研究思想分歧。沿着关键短语的对角线看,得分接近零,代表双方需要解决的关键问题或挑战。就像站在一个山谷里,仰望两座大山。:
- 摇摆州俄亥俄州被列在对角线上,而密歇根州的得分更低,因为它被共和党人更频繁地提到。
- 像“预算”和“贸易”这样的关键问题被双方以平均频率提及,因此这些点显示在图表的中心。
- 在黄点的右上方区域,最常讨论的话题是“税收”和“就业”,两党得分几乎相等。
表示意识形态的词离这个山谷最远。例如,“美国工人”这个短语是民主党候选人专用的。乔治·w·布什在描述他的社会保障计划时经常使用类似的短语“年轻工人”。具有相等和相反符号分数的单词对于比较政党纲领的焦点是有趣的。例如,共和党人对北美自由贸易协定的得分与民主党人对“收入”的得分一样多,这表明共和党人对北美自由贸易协定的讨论和批评与民主党候选人对家庭收入的关注一样多。更多实例表明了各方的关键谈话要点:
- d:“人权”,R:“我们的部队”
- d:“减税”,R:“失业”
- d:“住房”,R:“债务”

看看左上角和右下角,你可以看到每个候选人对他或她的对手说了什么。一个有趣的特点是在让步协议中,例如巴拉克·奥巴马几次承认参议员麦凯恩(或“约翰”)是“绝对正确的”,约翰·麦凯恩也至少承认过一次这一点(当提到在阿富汗的战术和战略时)。从图的底部看,辩论变得更加个人化,因为对手主要被称为他们的名字(左下角),共和党人而不是民主党人经常使用的许多术语被唐纳德·特朗普的关键短语所主导:
- “是的,是的,我们听说过——我们以前听说过,希拉里。”
- “因为你知道什么,你一点也不聪明,乔。47 年了,你什么都没做。
- “打扰了。因为作为参议员,她在 T4 遭遇了一场灾难。灾难。”
- “她的判断力很差,老实说,差到她永远都不应该成为美国总统。这我可以告诉你。”
- “我不认识宝儿。我知道猎人。亨特被军队开除了。他被开除了,因为吸食可卡因而被开除军籍。”

由 Maria Oswalt 在 Unsplash 上拍摄的照片
随着候选人的立场随着时间的推移而演变,关注更实质性的话题会更有意思。堕胎一直是共和党和民主党之间党派分歧的一个关键问题,特别是在最近确认艾米·科尼·巴雷特的情况下。在卡特-福特辩论和蒙代尔-里根辩论中都有提及。里根和卡特给出了截然相反的声明,尽管他们当时并没有展开辩论:
“我认为堕胎是不对的。我认为政府不应该做任何事情来鼓励堕胎。但是我不赞成在这个问题上的宪法修正案……我个人不认为联邦政府应该资助堕胎,但是我——我划清界限,不支持宪法修正案。”- 吉米·卡特
“但是关于堕胎问题,我有一种感觉,在蒙代尔先生的言论中,有一些地方提到了将宗教注入政府,但没有提到。跟我,堕胎不是宗教的问题,是宪法的问题。”- 罗纳德·里根
里根表示,这个问题是关于宪法,而不是宗教。卡特的回应有点混乱。他明确指出不应该有禁止堕胎的修正案,但是政府不应该有资助堕胎的项目。乔治·w·布什的回应暗示这个问题是一个社会建设的问题,这与里根关于宪法的回应是矛盾的。希拉里和迈克尔·杜卡基斯明确表示,这是一个关于女性选择权的问题。戈尔和麦凯恩在最高法院大法官的试金石背景下谈论罗伊诉韦德案,并一致认为支持罗伊诉韦德案是任命甚至提名的关键指标。
“我认为推广生活文化很重要。我认为一个好客的社会是一个每个人都很重要的社会。我相信理想的世界是这样的:每个孩子都受到法律的保护,都受到生活的欢迎。”——小布什
“当使用严格的构造论者这个短语时,当斯卡利亚和托马斯的名字被用作谁将被任命的基准时,这些都是暗语,任何人都不应该误认为州长会任命推翻罗伊诉韦德案的人。我很清楚。我会任命持有我认为很可能会支持罗伊诉韦德案的理念的人。”——阿尔·戈尔
“我会考虑任何人的资格。我不认为支持罗伊诉韦德案的人会被列入这些资格。”约翰·麦凯恩
巴拉克·奥巴马承认存在分歧,双方在防止意外怀孕方面可能有共同点:
“这是一个让我们产生分歧的问题。在某些方面,可能很难调和这两种观点……“我们应该努力防止意外怀孕,为我们的年轻人提供适当的教育,宣传性是神圣的,他们不应该参与无拘无束的活动,提供收养的选择,并帮助那些希望选择留下孩子的单身母亲。”这些都是我们今年第一次在民主党政纲中提出的,我认为这是我们可以找到一些共同点的地方,...”——巴拉克·奥巴马
透过零散文本的镜头来研究总统辩论,突显了永恒的政治话题,这些话题会随着时间的推移而改变和演变政党纲领。上述情节启发我观察总统辩论中的主题特征,分析辩论主题如何随时间变化,并使用为文本分类训练的 BERT 模型,根据候选人的回答,按意识形态排列候选人。
分析工具包
- 获取数据的第一步是抓取一个包含辩论记录的网页。我使用了总统辩论委员会,它有一个非常简单的格式。这个网站错过了唐纳德·特朗普和乔·拜登之间的最新一轮辩论,我是从《今日美国》上看到的。我使用 Beautiful Soup 4 从这些网页中获取文本(链接见下面的参考资料)。我在这里链接我的代码。
- 来自 Scikit learn 的非负矩阵因子分解用于从主持人/小组成员文本中提取关键词。 PyTextRank 用于给最突出的主题短语打分。
- 我使用 SpaCy 为给定的主题分配关键字,并匹配候选人的回答。我在这里确定了关键字和主题
- BERT 文本分类模型是在 Google CoLab GPU 上用张量流分类层训练的,下面链接了我的一个笔记本。
- 可视化和输出图表由表格制作。
提取永恒的话题
小组成员和主持人的角色使得每次辩论都很容易找到辩论提示。分析提示的困难在于术语会随着时间而变化。例如,“气候变化”现在是一个常见的术语,但在 2000 年的辩论中,它被阿尔·戈尔称为“全球变暖”,所以我依赖于在每次辩论中挑选出主题词,然后将它们分组到主题中。在辩论中,有几十年来反复出现的主题:税收、环境和气候变化、经济、联邦支出、医疗保健、枪支管制、移民、国防、石油和石油工业、公共教育、种族和歧视以及社会福利。
我通过为每场辩论的主持人和小组成员文本建立一个主题模型,并将关键词分组到主题中,找到了这些主题。下面是奥巴马和罗姆尼辩论中主题词的一个例子:
**gas prices**, specific examples, **financial problems**, the difference, **american jobs**, **productive members**, vast array, clear choice, quick response, red lines, other things, everyday living, **your energy secretary**, your energy, tax revenue, the biggest, the biggest misperception, own plan, his own plan, **lower gas prices**
使用 PyTextRank 并仅保留得分大于 0.1 的短语来缩减全文。题目建模很乱,因为文字很稀疏,辩论题目设计的面很广。下面这个话题的内聚力较低,但突出显示的文字显示了经济和油价的广泛主题。我使用空间匹配模式将这些单词编码为主题。对于话题“社会福利”,下面根据版主使用的词语列出了匹配模式。
matcher.add(“Social Welfare”,None,[{“LOWER”:”social”},{“LOWER”:”security”}])
matcher.add(“Social Welfare”,None,[{“LOWER”:”housing”},{“LOWER”:”subsidies”}])
matcher.add(“Social Welfare”,None,[{“LOWER”:”minimum”},{“LOWER”:”wage”}])
matcher.add(“Social Welfare”,None,[{“LOWER”:”prevailing”},{“LOWER”:”wages”}])
matcher.add(“Social Welfare”,None,[{“LOWER”:”abnormal”},{“LOWER”:”poverty”}])

所有总统辩论中的话题按匹配的候选人回答总数的百分比划分
给定主题关键词,我浏览所有候选人在辩论中的回答,并计算每个主题中匹配的频率。从上面的图表可以清楚地看出,经济、税收和联邦支出等广泛的国内话题在这些年来几乎占了候选人回答的 50%。这些话题引发了很多关于国内政策的辩论。第二大主题是绿色显示的医疗保健,占 13.8%。公共教育是讨论最少的话题,不到 1%(0.86%)。
为了衡量每场辩论与其他文本(如人身攻击或相声)相比的实质内容,我查看了候选人回应文本的主题匹配频率。我不期望有 100%的匹配效率,因为所选择的关键词没有涵盖所有可能的辩论问题和提示。然而,观察比赛效率有多平坦对于衡量一段时间内辩论的质量是有用的。

主题关键字匹配候选人回答的效率,用作查看辩论中有多少实质性讨论的指标
早期的总统辩论比后来的辩论包含更多的话题词。1980 年卡特和里根之间的辩论有最大比例的匹配回答(66%)。1980 年到 2012 年之后的辩论,接近平均值 40%的有 33%到 46%不等。匹配度最低的是 2016 年克林顿-特朗普和 2020 年特朗普-拜登的辩论。


1980 年卡特-里根辩论和 2020 年拜登-特朗普辩论的辩论主题细分
比较最高和最低匹配效率辩论指出了辩论的焦点有多宽或多窄。1980 年的辩论在对石油工业、整体经济、社会福利、气候变化和种族/歧视的讨论之间很好地划分开来。医疗保健(4%)和国防(7.2%)的覆盖范围较小。在最近的辩论中,经济和医疗保健(可能是新冠肺炎强调的)是讨论的主要部分。1980 年,在匹配的关键词:种族歧视和黑人失业的匹配候选人回答中,种族只占 8%。而 2020 年是 14%(所有辩论中最大的比例),匹配的关键词列表是:白人至上主义者、民权、黑人社区、西班牙裔和种族主义者。
意识形态的伯特文本分类
BERT(来自变压器的双向编码器表示)是一种用于自然语言处理的预训练机器学习技术。BERT 预训练模型可以与用于文本分类的分类层相结合。BERT 模型的关键创新是它们能够通过双向编码器识别上下文,而不仅仅是左-右/右-左符号序列。这使得训练能够根据单词的环境来识别单词的上下文,而不是仅仅根据单词串在一起的顺序。
BERT 是对几百个标记的短句进行文本分类的强大工具。句子的标记大小越大,用于训练模型的资源就越多。我将总统候选人的回答解析成 192 个令牌长度的片段。下面列出了预训练的 BERT 模型,可从 TensorFlowHub 下载:
# More details here: [https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/2](https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/2)bert_layer=hub.KerasLayer(‘https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/2',trainable=True)vocab_file=bert_layer.resolved_object.vocab_file.asset_path.numpy()do_lower_case=bert_layer.resolved_object.do_lower_case.numpy()#### is the Bert layer case sensitive?tokenizer=tokenization.FullTokenizer(vocab_file,do_lower_case)
TensorFlow 输入管道将输入文本转换为一批输入,用于多线程训练和测试。最后一个阶段是在 BERT 层之后添加分类器模型:
def create_model():input_word_ids = tf.keras.layers.Input(shape=(max_tok_sequence,), dtype=tf.int32,name=”input_word_ids”)input_mask = tf.keras.layers.Input(shape=(max_tok_sequence,), dtype=tf.int32,name=”input_mask”)input_type_ids = tf.keras.layers.Input(shape=(max_tok_sequence,), dtype=tf.int32,name=”input_type_ids”)pooled_output, sequence_output = bert_layer([input_word_ids, input_mask, input_type_ids])#### Hard code initialization seeds for reproducibilitydrop=tf.keras.layers.Dropout(0.2,seed=9)(pooled_output)#### tuned the hyperparameter for regularization termoutput=tf.keras.layers.Dense(1,activation=’sigmoid’,name=’output’,kernel_initializer=tf.keras.initializers.glorot_uniform(seed=9))(drop)#### classifier values between 0,1model=tf.keras.Model(inputs={‘input_word_ids’:input_word_ids,’input_masks’:input_mask,’input_type_ids’:input_type_ids},outputs=output)#### keras modelformattedreturn model
model=create_model()model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=2e-5),loss=tf.keras.losses.BinaryCrossentropy(),metrics=tf.keras.metrics.BinaryAccuracy())
给定 19 名候选人,我把他们分别标为共和党(1)和民主党(0)。该模型被训练为给每个辩论响应一个分类器分数。只有与关键字匹配的数据用于训练/验证。我会查看与关键词不匹配的回复,并对其意识形态进行评分:

分类分数范围从 0 到 1,将文本分类为民主党或共和党的意识形态
每个候选人的每个辩论回答都有一个分类器得分(被解析为 192 个标记段)。中值分数显示了他们对自己党派的支持程度。

中值分数可以根据每位候选人的辩论回答,对他们与其政党的关系进行排名(色标)
得分显示,迈克尔·杜卡基斯、吉米·卡特、比尔·柯林顿和约翰·f·甘乃迪是最民主的,平均得分接近于零。尼克松、里根和麦凯恩的平均得分都在 0.95 分以上,与共和党最接近。杰拉尔德·福特有点反常,因为根据他的辩论回答,他比共和党人更接近民主党的平台,所以我看了归类为大多数民主党支持者的回答。这些对杰拉尔德·福特的回应包括对逃避兵役者和逃兵的大赦,解决世界饥饿问题,以及几次提到适用于中东和平努力的“道德原则”和“道德标准”。
最党派一致声明的获胜者是巴拉克·奥巴马,他在与约翰·麦凯恩的第三次辩论中对公共教育和大学入学问题的回应。共和党一致声明的最高分来自唐纳德·特朗普在与希拉里·克林顿的第三场辩论中。他谈到他计划如何重新谈判贸易协议,北约如何“付钱”,以及他将如何终止北美自由贸易协定。一般来说,与团体一致的响应往往出现在长响应中,因此很可能包含大量的团体关键短语。巴拉克·奥巴马的回答包括“地方学区”、“公立学校”和“大学的可及性和可负担性”。这与之前在散点剧情中看到的特征相吻合,“教育”是给民主党打了高分的一个词。在唐纳德·特朗普的声明中,几个得分很高的共和党词汇得到了强调:“北美自由贸易协定”、“北约”、“国债”、“贸易协议”和减税。
当然…讽刺和预示:
你可以把这一部分看作是总统辩论的一盘闹剧。但仔细想想,这并不轻松。我发现向杰拉尔德·福特提出的这个问题非常尖锐:
梅纳德先生,“总统先生,你已经两次成为使用手枪的潜在刺客的目标受害者。然而,你仍然是实质性手枪控制的坚定反对者。这个国家现在大约有 4000 万支手枪,并以每年 250 万支的速度增长。可悲的是,这些手枪经常是为了自我保护而购买的,最后却被用来对付亲戚或朋友。有鉴于此,你为什么如此坚决地反对在这个国家实施实质性的枪支管制?”
乔·拜登(Joe Biden)和唐纳德·特朗普(Donald Trump)最近一场辩论中的一句极具挑衅性的评论让许多人震惊不已。特朗普会接受选举结果(如果他可能会输)并鼓励和平过渡吗?在与希拉里·克林顿的第一场总统辩论中,他的回答很简单:
“答案是,如果她赢了,我绝对支持她。”唐纳德·特朗普
在与希拉里·克林顿的第三场总统辩论中,克里斯·华莱士再次提出了这个问题,并引用了他的竞选伙伴和他的女儿仍然同意的话:
“你最近在集会上警告说,这次选举受到操纵,希拉里·克林顿正在试图从你那里偷走它。你的竞选搭档、州长彭斯(Pence)周日承诺,他和你——用他的话说——“将绝对接受这次选举的结果。”今天你的女儿伊万卡也说了同样的话。我想在今晚的舞台上问你:你是否承诺你将绝对——先生,你将绝对接受这次选举的结果?“主持人克里斯·华莱士
特朗普回答道,这几乎是 2020 年的可怕预兆
“我说的是,我会在那时告诉你。我会吊你胃口的。好吗?”唐纳德·特朗普
这看起来更像是一个“万圣节快乐”的结尾,而不是一个“选举快乐”日的结尾,所以我将以这段代码的一些未来方向来结束:
- 二元文本分类可以扩展到多分类,以将辩论响应映射到一组主题上。
- 类似的方法可以应用到最高法院的确认听证会上吗?
- 如果他们说到做到,他们会说到做到吗?将辩论和演讲中确定的主题与选举后的投票和政策记录进行比较。
密码
总统辩论委员会的辩论记录
链接到图表
参考
Jason s . Kessler“Scattertext:一个基于浏览器的工具,用于可视化语料库如何不同” arXiv:1703.00565
Jason S. Kessler“使用 Scattertext、PyTextRank 和 Phrasemachine 可视化数千个短语”中型文章
Jacob Devlin,Chang Ming-Wei,Kenton Lee,Kristina Toutanova“BERT:用于语言理解的深度双向转换器的预训练” arXiv:1810.04805
在您的数据科学工作流中包含这些 Spark 窗口函数

来源: Pixabay
使用 pySpark 创建等级、滞后和滚动特征
在我关于 Spark 的最后几篇文章中,我解释了如何使用 PySpark RDDs 和 Dataframes。
虽然这些帖子解释了很多关于如何使用 rdd 和数据帧操作的内容,如果读者想学习 Spark 基础知识,我会要求他们通读这些帖子,但我仍然没有提到很多关于使用 PySpark 数据帧的内容。
其中一个就是火花窗函数。
最近,当我在做我的一个项目时,我意识到了它们的力量,所以这篇文章将是关于 Spark 中一些最重要的窗口功能。
数据
我将与南韩的新冠肺炎数据科学合作,这是 COVID 在互联网上最详细的数据集之一。
请注意,我将使用这个数据集来展示窗口函数,但这不应该以任何方式被视为对这个奇妙数据集的数据探索练习。
对于本文,我将使用 TimeProvince 数据框架,它包含每个省的每日病例信息。

等级
使用此功能,您可以在一个组上获得rank和dense_rank。例如,您可能希望 timeprovince 表中有一列提供某个省中每天的排名。我们可以通过以下方式做到这一点:
from pyspark.sql.window import Window
from pyspark.sql import functions as FwindowSpec = Window().partitionBy(['province']).orderBy(F.desc('confirmed'))
timeprovince.withColumn("rank",F.rank().over(windowSpec)).show()

这里,我们首先创建一个由province划分的window,并按照confirmed案例的降序排列。人们可以把window看作是按照用户提供的顺序排列的一组特定省份的行。然后,我们可以通过在这个窗口上使用 rank 函数轻松地添加等级,如上所示。
滞后变量
有时,我们的数据科学模型可能需要基于滞后的功能。例如,一个模型可能有像price_last_week或sales_ quantity_previous_day这样的变量。我们可以使用窗口函数的滞后函数来创建这样的特征。在这里,我试图得到 7 天前确诊的病例。我正在过滤以显示结果,因为头几天的电晕案例为零。您可以在这里看到 lag_7 day 特性移动了 7 天。
from pyspark.sql.window import Window
windowSpec = Window().partitionBy(['province']).orderBy('date')
timeprovinceWithLag = timeprovince.withColumn("lag_7",F.lag("confirmed", 7).over(windowSpec))timeprovinceWithLag.filter(timeprovinceWithLag.date>'2020-03-10').show()

滚动聚合
有时,为我们的模型提供滚动平均值会有所帮助。例如,我们可能希望将连续 7 天的销售额总和/平均值作为销售回归模型的一个特性。让我们计算一下过去 7 天确诊病例的移动平均数。这是很多人已经在用这个数据集做的事情,来看真实的趋势。
from pyspark.sql.window import WindowwindowSpec = Window().partitionBy(['province']).orderBy('date')**.rowsBetween(-6,0)**timeprovinceWithRoll = timeprovince.withColumn("roll_7_confirmed",F.mean("confirmed").over(windowSpec))timeprovinceWithRoll.filter(timeprovinceWithLag.date>'2020-03-10').show()

这里有几件事需要了解。首先是我们在这里使用的 **rowsBetween(-6,0)** 函数。该函数有一个包含开始和结束的rowsBetween(start,end)形式。使用此功能,我们只查看特定窗口中过去七天的情况,包括当前日期。这里 0 指定当前行,而-6 指定当前行之前的第七行。记住,我们从 0 开始计数。
因此,为了得到日期为2020–03–22的roll_7_confirmed,我们查看日期为2020–03–22 to 2020–03–16的确诊病例,并取其平均值。
如果我们使用了**rowsBetween(-7,-1)** ,我们将只查看过去七天的数据,而不是当前日期。
我们还可以找到rowsBetween(Window.unboundedPreceding, Window.currentRow)的一种用法,我们从窗口的第一行和 current_row 之间的行中获取运行总数。我在这里计算累计 _ 确认。
from pyspark.sql.window import WindowwindowSpec = Window().partitionBy(['province']).orderBy('date').rowsBetween(Window.unboundedPreceding,Window.currentRow)
timeprovinceWithRoll = timeprovince.withColumn("cumulative_confirmed",F.sum("confirmed").over(windowSpec))
timeprovinceWithRoll.filter(timeprovinceWithLag.date>'2020-03-10').show()

结论
在这里,我尝试总结了一些我在使用 Spark 时使用的窗口函数。你可能会想到使用这些窗口函数的许多其他方式,但是我希望这篇文章能让你清楚地知道如何使用它们而不会太混乱。
你可以在 GitHub 库找到这篇文章的所有代码。
此外,如果您需要学习 Spark 基础知识,可以看看我之前的帖子:
不仅仅是介绍
towardsdatascience.com](/the-hitchhikers-guide-to-handle-big-data-using-spark-90b9be0fe89a)
还有,如果你想了解更多关于 Spark 和 Spark DataFrames 的知识,我想调出这些关于 大数据基础知识的优秀课程:HDFS、MapReduce 和 Spark RDD 和 大数据分析:Hive、Spark SQL、DataFrames 和 GraphFrames 由 Yandex 在 Coursera 上提供。
谢谢你的阅读。将来我也会写更多初学者友好的帖子。在 媒体 关注我,或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter@ mlwhiz联系
此外,一个小小的免责声明——这篇文章中可能会有一些相关资源的附属链接,因为分享知识从来都不是一个坏主意。
使用 Tensorflow 2 在保存的模型中包含训练操作
向以 SavedModel 格式导出的模型中的推理操作添加训练操作,以及如何用低级操作调用它们。

大多数 Tensorflow 文档和教程都展示了如何用 python 训练一个模型,并将其保存为 SavedModel 格式,以便在另一个环境中进行预测。但是为培训保存一个模型需要更多的工作。本文介绍了一种方法。所有的代码都在这个 jupyter 笔记本里(用 tensorflow 2.3 测试)
高级 API 的一些限制
通常的场景是构建一个 Keras 模型并用model.save()导出它。然而,这仅保存了预测图,并且以后不可能在另一个环境中加载该模型。
此外,虽然简单的model.compile() + model.fit()场景可以涵盖许多场景,但它不允许设计复杂的损失函数,这些函数组合了对应于几个输出的标签,如下所示:

不能让一个函数使用多个标签来计算损失
复杂的情况通常用定制的训练循环来解决。节选自优秀 Keras 教程:
在这里,损失函数loss_fn可以做任何事情,并且在多输出模型的情况下可以访问所有标签。但问题是,我们仍然只剩下一个只能导出服务图的模型。所有的训练循环都不会被导出。
解决方案是在tf.Module中使用tf.function来导出几乎任何可以用张量流图运算表达的代码。
tf.function 中的自定义训练步骤
在下面的代码中,我们用函数式 API 定义了一个 Keras 模型。它包括一个定制层,不是完全无关紧要,但它可以是任何复杂性。我们还在包含在自定义tf.Module中的tf.function中定义了一个自定义训练步骤。
tf.function 中的自定义训练步骤。组件
sample prediction: [[0.20642705]]
让我们反复调用my_train函数来训练模型
Mean squared error: step 100: 1.3914144039154053
Mean squared error: step 200: 1.3325191736221313
Mean squared error: step 300: 1.321561574935913
Mean squared error: step 400: 1.3107181787490845
Mean squared error: step 500: 1.3031591176986694

让我们检查一下我们使用的ADAM优化器的状态。亚当学习与每个重量相关的两个变量m和v。
m和v分别是梯度的一阶矩(均值)和二阶矩(无中心方差)的估计。
了解更多信息:https://ruder . io/optimizing-gradient-descent/index . html # Adam
在张量流术语中,它们被称为slots。有关如何跟踪它们的更多信息,请参见https://www . tensor flow . org/guide/check point # loading _ mechanics
让我们检查 ADAM 的m槽的内容,看第一个密集层的偏差。
让我们再训练一会儿。正如预期的那样,损失仍然很低(注意该图的比例)

然后,我们可以检查 ADAM 优化器的变量是否也发生了变化:
坚持模型,继续训练
以上都是在记忆中完成的。同样,当我们保存一个模型时,不仅保存了层的权重,还保存了优化器的状态,这很好。然后,当我们继续训练一个重新加载的模型时,优化器不需要重新学习它的变量(ADAM 的m和v时刻)。
让我们以 SavedModel 格式保存模块。SavedModel 格式包含描述导出函数及其输入和输出的签名,这些签名在我们加载模型时可用。更多信息见https://www.tensorflow.org/guide/saved_model
然后我们将检查与模型一起保存的检查点的内容。
我们不仅可以看到层的权重,还可以看到前面讨论过的亚当槽变量(m和v)。
节选自https://www . tensor flow . org/guide/saved _ model # saving _ a _ custom _ model
保存一个
*tf.Module*时,任何*tf.Variable*属性、*tf.function*-修饰方法,以及通过递归遍历找到的*tf.Modules*都被保存。(参见 检查点教程 了解更多关于递归遍历的信息。)
这在https://www . tensor flow . org/guide/check point # loading _ mechanics中有详细介绍
让我们检查一下亚当的m槽的内容,看看第一个密集层的偏差
我们可以看到,这正是上面用module.opt.weights[2]检查的那个槽的内存内容
这表明 ADAM 的状态确实保存在检查点中。让我们用 Tensorflow 捆绑的saved_model_cli工具来看看导出的签名。
!saved_model_cli show --all --dir $model_dir
我们看到预测(my_serve)和训练(my_training)输出函数的预期签名。稍后将详细介绍。
让我们创建一个模块的新实例,不经训练保存它并重新加载它。
这里值得注意的是,加载的new_module对象不是一个tf.Module实例,而是另一种仍然提供我们导出的my_train和__call__函数的对象。让我们调用__call__()方法来看看它是否工作(将产生任何东西,因为模型还没有被训练)
因此,我们仍然可以将my_train函数与train_module函数一起使用。让我们训练重新加载的模块,然后保存它

上面显示了我们可以加载一个模块并训练它,就像我们用CustomModule()实例化它一样。让我们像上面一样检查一些优化器状态。
重新加载模块,继续培训并保存

就像我们在内存中所做的一样——只是前面显示了重量已经被正确地重新加载,并且我们没有从头开始训练。亚当的变量呢?
亚当的变量也发生了变化。随着训练的继续,它们的变化越来越小,这可以通过取训练前后那些槽的差的范数来显示,并且看到该范数随着时间而减小。
这表明优化器状态也在保存的模型中被捕获,并且我们可以停止和恢复训练而不会丢失任何东西。
低级操作
以上所有工作都是在重载模块时使用 python 对象和方法完成的。但是在只有图形和操作的情况下,我们如何用另一种语言来做呢?
我们先来看看用 python 怎么做。这是my_train签名的saved_model_cli输出:
signature_def['my_train']:
The given SavedModel SignatureDef contains the following input(s):
inputs['X'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 8)
name: my_train_X:0
inputs['y'] tensor_info:
dtype: DT_FLOAT
shape: (-1)
name: my_train_y:0
The given SavedModel SignatureDef contains the following output(s):
outputs['output_0'] tensor_info:
dtype: DT_FLOAT
shape: ()
name: StatefulPartitionedCall_1:0
Method name is: tensorflow/serving/predict
事实证明,我们可以通过这里显示的名字来访问输入和输出张量。例如:
inputs['X']有名字my_train_x:0output['output_0'](损失)有名称StatefulPartitionedCall_1:0
隐藏的是用于保存模型的操作和张量
- 检查点名称:
saver_filename:0:必须指向model_dir + '/variables/variables' - 保存操作:
StatefulPartitionedCall_2:0:本模块导出后的下一个StatefulPartitionedCall
关于保存操作的信息当然没有被记录,这可能是有意的,因此这可能在未来的 tensorflow 版本中不起作用。
用低级操作训练和预测加载模型
loss: 1.2404047
prediction: [[1.9881454]]
checkpoint saved
如果你不止一次执行train_predict_serve(),你会得到不同的结果,因为模型的权重会随着训练和预测的变化而变化。
以上表明,我们可以仅通过低级操作来训练、保存模块并进行预测。
这允许导出空白模型及其训练和服务图表,并让第三方组织对其进行训练和预测。导出的操作足以让该组织训练和监控损失减少,报告验证数据集的准确性并做出推断。
边注:如果模块函数返回两个输出,saved_model_cli会这样报告它们:
The given SavedModel SignatureDef contains the following output(s):
outputs['output_0'] tensor_info:
dtype: DT_FLOAT
shape: ()
name: StatefulPartitionedCall_1:0
outputs['output_1'] tensor_info:
dtype: DT_FLOAT
shape: ()
name: StatefulPartitionedCall_1:1
他们可以这样理解:
相同的导出模型可用于 java 中的训练和预测,代码如下:
打印这个:
loss after training: 1.2554951
prediction: 2.1101139
这个 java 代码是用 tensorflow 2.3.0 测试的。更多信息:
https://github.com/tensorflow/java
https://www . tensor flow . org/API _ docs/Java/reference/org/tensor flow/package-summary
为了完整性,请注意,也可以通过使用experimental _ export _ all _ saved _ models方法,将预测图和训练图导出到带有tf.Estimator的单个 SavedModel 中。我们也可以用低级图形操作来调用它。这是一种不同的方法,需要函数来构建模型,并以明确定义的格式返回数据集。欲了解更多信息,请参见估算师指南。
结论
在本文中,我们展示了一种将训练步骤导出为 SavedModel 格式的方法,以及如何在 python 中的重载模型上调用它,以及在 python 或另一种语言(如 java)中使用低级操作调用它。
关于 SavedModel 操作的其他有用链接(感谢 Drew Hodun!)
https://towards data science . com/how-to-extend-a-keras-model-5 effc 083265 c
包容性机器学习:解决模型公平性问题
AI 中的公平是什么?我们如何解决这个问题?实现模型公平性用例。
人工智能(AI)和机器学习(ML)系统正越来越多地用于所有部门和社会。
伴随着这种增长,模型公平性在过去几年里已经获得了关注。该领域旨在评估该模型在处理数据中预先存在的偏见时的公平性: 职位匹配系统因为与历史数据相匹配而倾向于男性候选人参加 CEO 面试,这公平吗?

图 1:2011 年至 2017 年发表的论文数量(图片由 Moritz Hardt 提供)
在我之前的文章中,我提到了 ML 模型的可解释性。这一次,我们将更进一步,评估我们训练的模型如何处理潜在的敏感(有偏见)特征。
审计一个模型并不总是黑白分明的——在一个上下文中可能敏感的特性在另一个上下文中可能不那么敏感。很少有人会认为性别不应该决定一个人是否能找到工作。但是,某保险公司定价模型因为历史数据显示男性比女性理赔多而向男性收取更多费用,这是否不公平?或者这是他们更鲁莽驾驶的正确原因吗?当然,这至少是有争议的。
在许多用例中,公平性的定义并不是绝对清晰的。为系统确定适当的公平标准需要考虑用户体验、文化、社会、历史、政治、法律和伦理因素,其中一些因素可能需要权衡。
在本文中,我们将使用由 Julius Adebayo 开发的 FairML 库来解决模型公平性问题。使用的完整代码可以在我的 GitHub 中找到
内容
- 数据集和模型培训
- 公平的直觉
- 评估模型公平性
- 推荐做法
1.数据集和模型培训
本文使用的数据集是来自 UCI 机器学习知识库的 成人人口普查收入 。预测任务是确定一个人的年收入是否超过 5 万美元。
由于本文的重点不在 ML 管道的建模阶段,所以执行了最小特征工程,以便用 XGBoost 对数据进行建模。
为该模型获得的性能指标如下:

图 2:训练和测试集的接收操作特性(ROC)曲线。

图 3: XGBoost 性能指标
这个模型的性能似乎还可以接受。
在我之前的文章中,我们讨论了几种解决模型可解释性的技术。在其他库中,我们使用 SHAP 来获得模型输出中的特性重要性:

图 4: SHAP 特征重要性
数据集中有几个特征可以被认为是包含在模型中的【敏感性】,其中一些比另一些更有争议。例如,像国籍、种族和性别这样的特征可能是决定一个人收入的最敏感的特征。
此外,尽管像年龄和婚姻状况这样的特征可能通过掩盖个人的某些方面(如工作经验或教育程度)而具有良好的预测能力,但它们也可能被视为敏感信息。
那么,我们如何评估模型在多大程度上依赖这些敏感特征来进行预测呢?
2.公平的直觉
像大多数解释算法一样,FairML 背后的基本思想是测量模型的预测如何随着输入的扰动而变化。如果一个特征的微小变化显著地修改了输出,那么模型对该特征是敏感的。
然而,如果特征是相关的,它们之间的间接影响可能仍然没有在解释模型中被考虑。 FairML 使用正交投影解决了多重共线性问题。
正交投影

图 5:矢量 a 在矢量 b 上的正交投影
正交投影是一种矢量投影,它将一个矢量映射到另一个矢量的正交方向上。如果将一个矢量 a 投影到一个矢量 b (在欧氏空间)上,则得到 a 位于 b 方向的分量。
这个概念在 FairML 中非常重要,因为它允许完全消除特征之间的线性依赖。如果两个向量相互正交,那么没有一个向量可以产生另一个向量的线性组合。 a 正交于b的分量,可计算为【a2】=a-a1**
正交投影保证不会有隐藏的共线性效应。值得注意的是,这是一个线性变换,因此它不考虑特征之间的非线性依赖关系。为了解决这个问题,FairML 使用了基展开和对这种展开的贪婪搜索。
FairML 过程

图 6:解决模型公平性的 FairML 方法(图片由 Julius Adebayo 提供)
如果 F 是训练有两个特征和 x2 的模型,为了计算 F 对 x1 的依赖性,首先使 x2 与 x1 正交其次,使用 x2 的正交分量并在×1中进行扰动来分析模型输出的变化。扰动输入和原始输入之间的输出变化表明模型对 x1 的依赖性。 F 对 x2 的依赖关系可以用同样的方法估算。
3.评估模型公平性
现在我们知道了 FairML 是如何工作的,让我们用它来评估我们的模型。首先,我们将安装 Python 包并导入所需的模块。
*# FairML install
pip install [https://github.com/adebayoj/fairml/archive/master.zip](https://github.com/adebayoj/fairml/archive/master.zip)# Import modules
from fairml import audit_model
from fairml import plot_dependencies*
其次,我们将对模型进行审计。 audit_model 方法接收 2 个必需输入和 5 个可选输入:
必需的
- predict _ function:有预测方法的黑盒模型函数。
- 输入 _ 数据帧 :带形状的数据帧(n _ 样本,n _ 特征)
可选
- distance _ metric:[‘MSE’,‘accuracy’](default =‘MSE’)之一
- 直接 _ 输入 _ 扰动 _ 策略 :指如何将单个变量归零。选项= [' 常数-零'(替换为随机常数值),'常数-中值'(替换为中值常数值),'全局-排列'(替换为列的随机排列的所有值)]。
- 运行次数 :要执行的运行次数(默认=10* )。*
- include _ interactions:启用检查模型对交互依赖的标志( default=False )。
- external _ data _ set:没有用于训练模型的数据,但是您想要查看该数据对黑盒模型有什么影响( default=None )。
*# Model Audit
importances, _ = audit_model(clf_xgb_array.predict, X_train)*
audit_model 方法返回一个字典,其中键是输入数据帧 (X_train) 的列名,值是包含特定特性的模型依赖关系的列表。这些列表的大小为 运行次数 。
针对每个功能执行的过程如前一节所述。 这种方法的一个缺点是,当特征数量很大时,运行起来计算量很大。
FairML 允许绘制输出对每个特征的依赖性(排除与其他预测器的相关性的影响):
*# Plot Feature Dependencies
plot_dependencies(importances.median(),
reverse_values=False,
title="FairML Feature Dependence",
fig_size=(6,12))*

图 7: FairML 特征依赖
红色条表示该特征有助于输出 1(收入> 50K),而浅蓝色条表示它有助于输出 0(收入<= 50k).
It is observed that this algorithm, by removing the dependence between features through orthogonal projection, identifies that the model has a high dependence on sensitive features such as 种族 _ 白人、NAC _ 美国和性别 _ 男性)。换句话说,根据训练好的模型,一个出生在美国的白人将有更高的概率拥有大于 50k 美元的收入,这构成了一个非常强的偏见。
注意算法中正交投影的相关性非常重要,因为像种族 _ 白人和NAC _ 美国这样的特征在 SHAP 的特征重要性或其他解释算法中似乎不那么相关。这可能是因为这些的效果隐藏在其他功能中。通过移除多重共线性并评估每个特征的个体依赖性,可以识别每个特征的内在影响。
4.推荐做法
人工智能和人工智能中的公平性是一个开放的研究领域。作为该领域的主要贡献者, GoogleAI 推荐了一些最佳实践来解决这个问题:
- 使用公平和包容的具体目标来设计你的模型 :与社会科学家、人文主义者和其他与你的产品相关的专家合作,理解和考虑各种观点。
- 使用代表性数据集来训练和测试你的模型 :识别特征、标签和群组之间的偏见或歧视性关联。
- 检查系统中不公平的偏见 :在设计度量标准来训练和评估你的系统时,也包括度量标准来检查不同小组的表现(使用不同的测试人员,并在困难的情况下对系统进行压力测试)。
- 分析性能 :即使系统中的一切都经过精心制作以解决公平性问题,基于 ML 的模型在应用于真实的实时数据时也很少能达到 100%的完美。当一个问题出现在一个活的产品中时,考虑它是否与任何现存的社会弊端一致,以及它将如何受到短期和长期解决方案的影响。
结论
这篇文章旨在帮助数据科学家更好地了解他们的机器学习模型如何处理数据中预先存在的偏见。
我们介绍了 FairML 如何解决这个问题的直觉,并对在 成人人口普查收入 数据集中训练的 XGBoost 模型进行了公平性评估。最后,我们总结了 GoogleAI 在这个不断发展的领域推荐的一些最佳实践。
作为结束语,我想引用谷歌负责任的人工智能实践中的一句话:
人工智能系统正在为全球各地的人们带来新的体验和能力。除了推荐书籍和电视节目,人工智能系统还可以用于更重要的任务,例如预测医疗状况的存在和严重程度,将人与工作和伴侣进行匹配,或者识别一个人是否正在过马路。与基于特别规则或人类判断的决策过程相比,这种计算机化的辅助或决策系统有可能在更大范围内更加公平和包容。风险在于,这种体系中的任何不公平也会产生大范围的影响。因此,随着人工智能对各个部门和社会的影响越来越大,努力建立对所有人都公平和包容的系统至关重要。
我希望这篇文章能够作为解决黑盒模型中的公平性的一般指南,并为人工智能的更公平和更包容的使用提供一粒沙子。完整代码可以在我的 GitHub 中找到
将 Python 的最佳实践与这 4 个顶级 VSCode 扩展相结合
为什么不让 Python 的最佳实践更容易被采用呢?

动机
作为一名数据科学家,拥有良好的编码实践是至关重要的,因为同事更容易查看您的代码,并且您在将来重新访问您的代码时也可以避免混淆。你希望你的代码既干净又容易理解。
因此,必须:
- 包含类型提示
- 编写好的文档
- 保留相关变量和函数,并导入相关包
- 突出显示需要注意或改进的代码
- 避免其他琐碎的错误,比如忘记声明变量
与其试图一次注意代码中的几个小细节,为什么不使用扩展来帮助和提醒你呢?这将有助于培养良好的编码实践。
VSCode 是我最喜欢的 IDE,因为它有用的键盘快捷键和扩展。我写了关于我最喜欢的键盘快捷键和vs code 中的这 4 个顶级代码查看器如何让我更容易地查看我的数据。在本文中,我将介绍 4 个我最喜欢的 VSCode 扩展,以便进行良好的编码实践。
Python 类型提示
类型提示表示 Python 代码中值的类型,让使用函数或类的人更容易知道在函数或类中为特定参数插入哪种数据类型。
例如,通过向函数添加类型信息,它会提醒那些使用您的代码的人插入 datetime 类型的参数。

类型提示是有帮助的,但是对于初学者来说,记住类型提示的所有语法可能是困难的。这时 Python 类型提示就派上用场了。

如果您没有使用 Python 3.9,请确保从typing导入List, Set, Dict,以指定 Python 列表、集合或字典中的数据类型
挂架
如果你用 Python 编码并使用 VSCode,你肯定应该安装 Pylance。 Pylance 为 Python 3 提供了许多令人敬畏的特性。这些功能包括:
显示文档字符串并建议参数
你是否曾经使用过你的类或函数,却忘记了输入哪些参数?Pylance 通过显示正在使用的类或函数的文档字符串,使您更容易输入正确的参数和数据类型。

显示未使用的库、变量或函数
导入大量的库或者声明一个在脚本中的其余代码中不会用到的变量或函数是很常见的。拥有不必要的代码会使你的代码变得混乱,让其他人阅读你的代码时更加困惑。
但是,查看每一行代码以确保只导入库或声明将要使用的变量或函数是非常耗时的。幸运的是,Pylance 通过不突出显示不使用的库、变量或函数使它变得更容易!

导入不必要的库

在函数中包含未使用参数
现在你可以删除那些没有高亮显示的!现在看起来应该没那么乱了。
报告代码中的错误
使用尚未在函数中声明或尚未包含在函数参数中的变量也很常见。Pylance 会检测到这一点,并给未定义的变量加下划线。

而且还有更多功能我这里不提!我鼓励您自己使用 Pylance 来发现这个扩展还能做些什么来帮助您更快地编码。
Python 文档字符串生成器
对于您编写的函数或类,有一个好的 docstring 是很重要的,这样其他人就更容易理解和使用您的代码。但是您可能懒得编写合适的 docstring,因为这可能会花费您相当多的时间。
如果 docstring 是自动为您创建的呢?您可以使用 Python Docstring Generator 扩展,通过简单地使用Ctrl + Shift + 2为您的函数或类创建一个 Docstring。

现在你需要做的就是用你的描述替换括号里面的文字!将来你的同事和你自己都会很高兴看到写得很好的 docstrings。
如果您喜欢其他 docstring 格式,可以切换到这些格式中的一种
- 谷歌(默认)
- docBlockr
- Numpy
- 狮身人面像
查看文档了解如何切换格式。
更好的评论
不错!现在,您已经有了一个好的 docstring、类型提示,并组织了您杂乱的代码。但是你遗漏了一些东西。如果你想强调代码中重要的或者需要改进的部分怎么办?
例如,您使用 0.5 作为阈值将概率列表转换为二进制值,但您认为如果更改阈值,结果会有所改善。
但是,您希望在返回这段代码之前完成剩余的代码。如果你有不止一行,而是十行代码需要改进,你如何记住它们?

这时,带有单词 TODO 的代码注释就派上了用场。但是即使注释 TODO 在数百行代码中也是不可见的。幸运的是,更好的注释扩展让你更容易注意到这些重要的注释。
有了这个扩展,您将能够将您的注释分类为:
- 突出
- 警报
- 问题
- 托多斯

现在您可以突出显示重要的注释,而不必担心您可能会忘记需要改进或需要小心处理的代码。
结论
恭喜你!您刚刚学习了 4 种不同的 VSCode 扩展,以便更快、更容易地采用良好的编码实践。编写好的文档,包括类型提示,突出重要的注释,并拥有干净的代码,将节省您调试的时间。良好的编码实践也将为你的同事节省几个小时甚至几天去解释和使用你的代码。结果,大家都很开心!
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以通过 LinkedIn 和 Twitter 与我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
就像 Git 一样,但是有数据!
towardsdatascience.com](/introduction-to-dvc-data-version-control-tool-for-machine-learning-projects-7cb49c229fe0) [## 数据科学家 Pytest
适用于您的数据科学项目的 Pytest 综合指南
towardsdatascience.com](/pytest-for-data-scientists-2990319e55e6) [## 使用 Python 和情感分析探索和可视化您的 LinkedIn 网络
希望优化您的 LinkedIn 个人资料?为什么不让数据为你服务呢?
towardsdatascience.com](/sentiment-analysis-of-linkedin-messages-3bb152307f84) [## 超调 ML 模型时提高效率的 3 个步骤
毫不费力地在不同型号之间切换,不会弄乱代码
towardsdatascience.com](/3-steps-to-improve-your-efficiency-when-hypertuning-ml-models-5a579d57065e) [## Datapane 简介:构建交互式报表的 Python 库
创建精美报告并与您的团队分享分析结果的简单框架
towardsdatascience.com](/introduction-to-datapane-a-python-library-to-build-interactive-reports-4593fd3cb9c8)
通过提高面部对比度来提高面部识别模型的准确性
预处理图像以获得更好的结果

在 Unsplash 上由Tiko giorgaze拍摄的照片
对比度提高图像预处理步骤
我给你介绍一下我前阵子遇到的一个问题。我正在试验面部检测和 OpenCV ,以探索最新的机器和深度学习模型。
我注意到,对于有明显对比的人脸,检测和识别率明显更高。这让我开始思考,如何自动提高图像的对比度?
我给你看看什么是直方图均衡 。在这篇博文的最后,你将学会一个可以提高识别率的预处理步骤。首先,我将解释对比度在图像处理中的意义,然后我们将从这里开始。
最后,我将向您展示如何在彩色图像上应用一种非常先进的直方图均衡化方法,即所谓的对比度受限的自适应直方图均衡化算法(CLAHE)。
什么是图像中的对比度?
“颜色或亮度的差异使一个物体与同一视野内的其他物体区分开来。”— 维基百科
这个定义对每个熟悉摄影的人都有意义。它直接告诉我们需要什么来将物体从背景中分离出来。
我们不需要低对比度或高对比度,而是介于两者之间。它需要是最优的。

高对比度和低对比度图像之间的差异(来源:filmschoolonline.com)。
左边的图像比右边的图像对比度低。更难看清左脸的轮廓。
虽然后者具有更好的轮廓,但对比度太大的图像会丢失微妙的信息。这最后一部分可能是我内心的数据科学家会担心的事情。
当你在对一个对象进行分类之前提高对比度时,你就去除了一点噪声,这有助于改善模型。大轮廓是最重要的。
因此,当你应用对比度提高算法时,你必须记住一件事——不要过度。
直方图均衡
直方图均衡化是一种用于调整图像强度的图像处理技术。这增强了图像的对比度。
在幕后,可以用一个直方图来解释。均衡直方图意味着图像以相等的比例使用所有灰度级。然后,强度更好地分布在直方图上。
下图直观地展示了这一点,其中 T 是转换函数。我认为这对任何有统计学背景的人来说都是有意义的,你同意吗?

直方图均衡化(OpenCV 文档
OpenCV 有一个cv2.equalizeHist()方法,在灰度输入图像上执行直方图。它具有作为输出的直方图均衡图像。这种方法对于具有亮/暗背景和前景的图像都很有用。
但是,直方图均衡化有一个重要的限制,它只有在整个图像中像素值的分布相似时才能正常工作。
当某些区域与图像的其他部分明显不同时(例如,更亮或更暗),某些区域的对比度可能无法正确增强。
这种图像的一个例子是,从窗口进入的光使图像的一些区域明显变亮。
自适应直方图均衡
要解决直方图均衡算法的缺点,您可以为一幅图像计算多个直方图。
然后,每个直方图对应于图像的一个特定区域。这使得图像的每个区域被单独增强,从而解决了原来的问题。
然而,自适应直方图均衡算法产生了新的问题。AHE 会过度放大图像中接近恒定区域的对比度。
由于这种过度放大导致噪声在图像的特定区域被放大,我们需要一种替代方法。我在下一节提出了一个替代方案,所以坚持住。

照片由马克西姆·梅德维杰夫在 Unsplash 上拍摄
对比度有限的 AHE
如前所述,自适应直方图均衡会导致噪声在近常数区域被放大。
对比度受限 AHE 限制对比度放大,以降低放大噪声。这是通过在所有直方图中平均分布超出限幅的直方图部分来实现的。
但是你现在想看到一些结果,不是吗?我准备了一些东西,所以不要让你再等了。


适用 CLAHE 前后的美国现任总统。
请注意,脸部轮廓更加直观。这个预处理步骤你不用跟着我做,但是我觉得这是一个视觉上的提升。最重要的区域被稍微放大了。但是你是怎么做到的呢?
用 OpenCV 实现
我发现大多数实现只适用于灰度图像。所以,我认为,如果我能在这里做出改变,提供一个彩色图像的例子,将会非常有用。实现如下:
BRG 图像的 CLAHE 方法。
我只粘贴了最重要的部分,我认为每个经验丰富的数据科学家/工程师都应该能够解决剩下的部分。然而,我将详细解释这个方法。
首先,我将 BGR 图像(蓝色、绿色和红色通道)转换为 HSV 格式(色调、饱和度和值通道)。这允许我们只在价值通道上执行 CLAHE 算法。我们不想弄乱图像的色调或饱和度。
在我继续之前,让我解释一下 HSV:
- 色相:纯光谱颜色的术语,通常被称为“颜色名称”——红色、橙色、黄色、蓝色、绿色和紫色——出现在色相圈中。
- 饱和度:指图像中颜色的强度。原色——红色、蓝色和黄色被认为是最纯净的,因为它们完全饱和。当饱和度增加时,颜色会感觉更纯。
- 值:指颜色的明度或暗度。没有色调或饱和度的图像是灰度图像。
接下来,我在图像的价值通道上应用 CLAHE。我也将解释我使用的参数。我发现默认的 40 的限制过于激进,当使用 2 时,结果通常会有所改善。
第二个参数——瓦片栅格大小——将一幅图像分割成 8 列 8 行的 64 个瓦片。假设您的输入图像是 160x160 像素宽。在这种情况下,我将图像分割成 20x20 像素的区域。
这两个参数经常被用作缺省值,所以我没有费事去改变它们。请记住,如果你想要一致的行为,每张图片都应该使用相同的比例。
在最后的步骤中,在我将图像恢复为原始的 BGR 格式之前,我简单地将改变后的色值通道与色调和饱和度通道合并。
什么时候用?

我把这留给读者去发现。对我来说,这在两个阶段是有用的。在检测阶段或识别阶段。我会解释这两者,如果可能的话,我会讨论替代方案。
探测阶段
在这个阶段,它当然可以帮助找到更多的对象。我做了测试,使用 CLAHE 后,该模型可以检测更多的对象。例如,它还可以应用于 MRI 扫描。
然而,对于对象检测,有时对图像进行上采样会更有用。这比在整个图像上使用 CLAHE 效果更好。
识别期
正如我所展示的,在识别阶段使用 CLAHE 肯定是有帮助的。例如,当人们需要对图像进行分类来训练模型时,它可以在视觉上帮助他们更好地完成任务。
作为预处理步骤,对于特定的机器学习模型也可能是有益的。在我的一个项目中,我能够在 50 次运行中增加 1.5%的平均准确率(CLAHE 0.9534%,没有 0.9384%)。这是一个显著的增加,这也让我相信这是一个非常好的预处理步骤。
我还不确定它是否会改变物体识别的生活,因为很难找到关于这个主题的好研究。如果你有一些好的研究成果,比如在人脸识别领域,请随意评论这个故事。
结论
我希望找到一些答案,也希望作为读者的你能为我寻找改进的物体检测和识别做出贡献。
我总是乐于讨论我感兴趣的话题,所以欢迎在下面发表评论。我打算继续学习这门学科。
增加可解释性以提高模型的稳健性

对抗性训练鼓励使用更相关的特征。
最近一项提高卷积神经网络(CNN)在图像分类任务中的鲁棒性的尝试揭示了鲁棒性和可解释性之间的有趣联系。使用对抗训练训练的模型,一种用对抗例子增加训练数据的训练过程,具有输入梯度,与没有对抗训练训练的模型相比,该输入梯度在质量上看起来使用输入的更相关的区域。这篇文章的封面照片显示了这一点(中间一排没有对抗训练,底部一排有对抗训练)。这是正则化技术的一个意想不到且受欢迎的好处,迄今为止,正则化技术已被证明是对抗对抗性例子的最有效的防御。因此,在某些情况下,提高模型的稳健性可以提高模型的可解释性。你可以在齐普拉斯等人的原文中看到更多关于 ImageNet 和 CIFAR10 的例子,然而这只是硬币的一面。虽然在一些任务/数据集上,CNN 可以胜过人类,但是它们远非完美,因为它们对诸如均匀噪声之类的图像破坏的鲁棒性较低,并且不能从一种破坏推广到另一种破坏。使 CNN 对一组讹误具有鲁棒性的一个天真的解决方案是使用这些讹误来增加训练数据,但是 Geirhos 等人已经证明这将导致欠拟合。考虑下面的三个图像,并尝试区分中间和右边的图像。

噪声可视化
椒盐噪声图像看起来类似于均匀噪声图像,然而仅用椒盐噪声增加训练数据对正确分类被均匀噪声破坏的图像几乎没有影响。对此的一种可能解释是,神经网络不像人类那样学会忽略噪声,而是适应特定的噪声分布,并且只对那些被训练过的噪声保持不变。盖尔霍斯等人的这项非常重要的工作在研究界引发了极大的兴趣,以进一步了解人类和计算机视觉之间的差异。也许通过弥合这一差距可以提高模型的可解释性和稳健性。我们稍后会看到这是否确实是这样,但我们首先描述人类视觉用于核心对象识别的特征和计算机视觉用于图像分类的特征中最基本的差异之一。
盖尔斯等人的后续工作以及贝克等人的已经观察到,CNN 在进行分类时存在纹理偏差。这意味着填充有高尔夫球纹理的茶壶轮廓将被归类为高尔夫球。如果目标是识别图像中的各种织物或材料,例如当总结服装图像的属性时,这种行为实际上是所期望的。然而,对于分类来说,这可能会导致将一幅具有不寻常喷漆作业的汽车图像分类为草地。人类在进行分类时偏向于使用形状,这一事实不仅仅是一种直觉的推测,而是彻底的受控实验的结果。参与者被呈现所谓的线索冲突图像,这些图像是通过在 ImageNet 图像上应用风格转移来创建的,以便它们具有期望的纹理。但是,形状信息会被保留。这些图像看起来类似于下面这些来自贝克等人的作品。

贝克等人的提示冲突图片。点击此处链接到许可证
然后,他们被要求从每张图片的 16 个类别中挑选。大多数情况下,参与者选择的是与图像中主要对象的形状相对应的类别,而不是叠加的纹理。作者随后提出,也许鼓励模型具有与人类相似的行为偏差会给人类视觉带来其他额外的好处,如腐败鲁棒性。为了实现这种偏好的形状偏差,他们创建了一个新的数据集,称为风格化图像网络(SIN),这是通过将绘画数据集的 AdaIn 风格转换应用到图像网络而获得的。这导致纹理对于分类来说是不可靠的特征,因为根据所使用的风格化,同一类别的图像将具有随机纹理。SIN 是一个更难分类的数据集,事实表明,在 ImageNet 上训练和评估的模型达到 92.9%的准确性,但在 SIN 上评估时,它仅达到 16.4%的准确性。相反,在 SIN 上训练和评估的模型达到 79%的准确度,而在 ImageNet 上评估时具有 82.6%的准确度。经过 SIN 训练的模型具有与人类更相似的形状偏好,这表明对风格化图像进行分类的能力不是通过记住每种风格来实现的,而是通过使用形状来实现的。更重要的是,通过对 SIN 的训练,提高了对讹误的鲁棒性。除了两种特定的讹误类型之外,由于形状偏差的增加,对所有其他被认为是讹误的鲁棒性都得到了提高。
当对抗训练被用于显式地使模型对对抗的例子鲁棒时,可视化的梯度使用更符合人类视觉的特征。罪恶训练过的模特也是这样吗?渐变可视化反映了前面提到的形状偏差吗?幸运的是,这些模型可以在网上获得,所以繁重的工作已经完成,只剩下梯度可视化。正如你在下面看到的,在 ImageNet 上训练的 ResNet 的梯度和在 SIN 上训练的 ResNet 的梯度之间有非常微小的差别,但是与通过对抗性训练获得的梯度完全不同。这一发现表明,可解释性、腐败鲁棒性和行为偏差之间的联系尚不清楚。此外,SIN 训练的模型的对抗性鲁棒性还没有被彻底表征,尽管简单的 FGS 攻击揭示了 ImageNet 和 SIN 训练的模型之间没有显著差异,在 1000 个 ImageNet 验证图像的子集上,前者具有 12.1%的准确性,而后者具有 14.3%的准确性。

因此,如果梯度可视化不能揭示训练 SIN 的明显好处,那么还有什么可以弥补人类和计算机视觉之间的差距呢?也许模仿人类的行为偏见是不够的。另外,人类视觉是多任务的,且可以执行对象跟踪、分割、分类等。这揭示了一个可能的问题,即视觉模型目前如何被训练为仅用于一个感兴趣的任务的筒仓。如果 CNN 或其他架构要展现出我们人类认为理所当然的相同属性,如果以多任务的方式利用几个监督来源进行训练,它们可能会更快地实现这个目标。事实上,在语言理解等领域,深度学习的极限几乎已经达到,因为研究人员意识到,当只从文本中学习时,对物体的大小和形状进行推理是非常困难的。将多项任务结合在一起是解决人类和计算机视觉之间最明显差异的一小步,但可能是必要的一步。然而,即使在这一步之后,考虑到对抗性例子是多么普遍,即使研究人员在过去 6 年中一直试图防御它们,也可能还有很长的路要走。
使用 Python 中的 scikit-image 增加数据的数量和多样性
理解大数据
Python 中的图像数据扩充库系列

深度学习技术在计算机视觉任务中取得了巨大成功,即图像识别、图像分割、对象检测等。这种深度学习技术严重依赖大数据来避免过度拟合。那么在数据有限的情况下,你会怎么做呢?你去做数据扩充。数据增强技术增强了训练数据集的规模和质量,因此可以使用它们建立更好的深度学习模型。在本文中,我们将研究一些标准的图像增强技术和一些帮助实现这些增强的流行库。
增强技术的类型
基于何时在流水线中执行,扩充可以被宽泛地分类为离线扩充和在线扩充。

增强类型|按作者分类的图片
常用的增强技术。
在进入增强库之前,让我们先看看一些图像增强技术:

常用的增强技术|作者图片
- 翻转表示水平或垂直翻转图像。
- 旋转是将图像顺时针或逆时针旋转给定角度。
- 裁剪涉及随机采样一段图像。
- 改变亮度包括增加或降低图像的亮度。
- 缩放— 图像可以向外或向内缩放。向外缩放时,图像尺寸会增大,而向内缩放时,图像尺寸会减小。
- 添加噪声是指在现有图像上添加高斯噪声。
探索数据集:作为数组的图像
与人类不同,计算机将图像视为数据点。图像只不过是包含数据点像素的标准 Numpy 数组。图像的像素越多,分辨率就越高。

图片来源:https://setosa.io/ev/image-kernels/
记住这一事实,让我们来探索一下本文中我们将要处理的数据集。该数据集属于 2020 年 3 月由 Kaggle 主办的植物病理学 2020 — FGVC7 ,由人工捕捉的 3651 张高质量的多种苹果叶部病害的真实症状图像组成。
给定一张苹果叶子的照片,你能准确评估它的健康状况吗?这场比赛将挑战你区分健康的叶子,感染了苹果锈病的叶子,有苹果黑星病的叶子,以及有不止一种疾病的叶子。
在本文中,我们将只使用来自训练数据集的图像。
导入必要的库和数据集
import numpy as np
import pandas as pd
from skimage.io import imshow, imread, imsave
import matplotlib.pyplot as plt
%matplotlib inline # Defining data path
Image_Data_Path = "./plant-pathology-2020-fgvc7/images/"train_data = pd.read_csv("./plant-pathology-2020-fgvc7/train.csv") # Loading the training images
def load_image(image_id):
file_path = image_id + ".jpg"
image = imread(Image_Data_Path + file_path)
return imagetrain_images = train_data["image_id"][:50].apply(load_image)
上传数据集后,让我们看看训练集中的一些图像
看看训练集中的一些图像
# plotting multiple images using subplots
fig,ax = plt.subplots(nrows=2,ncols=3,figsize=(30,16))
for col in range(3):
for row in range(2):
ax[row,col].imshow(train_images.loc[train_images.index[row*3+col]])
#ax[row,col].set_title(image_titles[i])
ax[row,col].set_xticks([])
ax[row,col].set_yticks([])

看看训练集中的一些图片|作者图片
你可以认为像素是以二维网格形式排列的微小信息块,像素的深度是指其中存在的颜色信息。让我们看看数据集中的任意图像。
image = train_images[15]
imshow(image)
print(image.shape)

树叶图片|作者图片
彩色图像表现为红色、蓝色和绿色的组合,所有其他颜色可以通过将这些原色以正确的比例混合来实现。
*# red filter [R,G,B]*
red_filter = [1,0,0]
*# blue filter*
blue_filter = [0,0,1]
*# green filter*
green_filter = [0,1,0]
*# matplotlib code to display*
fig,ax = plt.subplots(nrows=1,ncols=3,figsize=(30,16))
ax[0].imshow(image*red_filter)
ax[0].set_title("Red Filter",fontweight="bold", size=30)
ax[1].imshow(image*blue_filter)
ax[1].set_title("BLue Filter",fontweight="bold", size=30)
ax[2].imshow(image*green_filter)
ax[2].set_title("Green Filter",fontweight="bold", size=30);

彩色图片|作者图片
一幅灰度图像由每像素 8 位组成。这意味着它可以有 256 种不同的色调,其中 0 像素代表黑色,而 255 代表白色。例如,下图显示了以数组形式表示的灰度图像。灰度图像只有一个通道,其中通道代表一个维度。
*# import color sub-module*
from skimage import color
*# converting image to grayscale*
grayscale_image = color.rgb2gray(image)
grayscale_image.shape
imshow(grayscale_image)

灰度图像|作者图片
流行的图像增强包
有很多图像增强包。然而,在这个系列中,我们将涉及一些流行的,如:
- 撇帐
- OpenCV
- 伊姆高格
- 白蛋白
- Keras(ImageDataGenerator 类)
我们将使用上述五个库,通过代码示例来演示基本的增强技术。每个图书馆都相当庞大,值得拥有自己的一篇文章。因此,我将从众所周知的 scikit-image 库开始,为每个库写一篇文章。
使用 scikit 图像的数据增强
Scikit-Image 或 skimage 是一个开源的 Python 包,可以处理 numpy 数组。它是图像处理算法的集合。代码由合作者团队维护,完全由社区驱动,同时保持代码的质量并促进基于研究的教育。
装置
scikit-image 可以按如下方式安装:
pip install scikit-imageor conda install -c conda-forge scikit-image
导入库和必要的模块
让我们加载我们将用于各种图像处理操作的必要模块。skimage 库由各种模块组成,包含旋转、缩放、调整大小等功能,用于图像操作。
from skimage.io import imshow, imread, imsave
from skimage.transform import rotate,rescale, resize,
from skimage import color,data
from skimage.exposure import adjust_gamma
from skimage.util import random_noise
图像翻转
翻转可以是水平的,也可以是垂直的。用于翻转图像的函数是[numpy.flip()](https://numpy.org/doc/stable/reference/generated/numpy.flip.html)。这个函数有两种变体。当fliplr()函数用于向左或向右翻转任何数组时,flipud()函数用于向上/向下翻转数组。这意味着fliplr()反转矩阵中像素列的顺序,而flipu()反转矩阵中像素行的顺序。
*#Horizontally flipped*
hflipped_image= np.fliplr(image) *#fliplr reverses the order of columns of pixels in matrix*
*#Vertically flipped*
vflipped_image= np.flipud(image) *#flipud reverses the order of rows of pixels in matrix*
fig,ax = plt.subplots(nrows=1,ncols=3,figsize=(30,16))
ax[0].imshow(image)
ax[0].set_title("Original Image", size=30)
ax[1].imshow(hflipped_image)
ax[1].set_title("Horizontally flipped", size=30)
ax[2].imshow(vflipped_image)
ax[2].set_title("Vertically flipped", size=30);

翻转图片|作者图片
图像旋转
同样,我们可以顺时针方向或逆时针方向旋转图像。旋转是通过transform.rotate();功能实现的,该功能可将图像围绕其中心旋转一定角度。用户可以指定任何旋转角度的选择。
# clockwise rotation
rot_clockwise_image = rotate(image, angle=45) # Anticlockwise rotation
rot_anticlockwise_image = rotate(image, angle=-45)fig,ax = plt.subplots(nrows=1,ncols=3,figsize=(30,16))
ax[0].imshow(image)
ax[0].set_title("Original Image", size=30)
ax[1].imshow(rot_clockwise_image)
ax[1].set_title("+45 degree Rotation", size=30)
ax[2].imshow(rot_anticlockwise_image)
ax[2].set_title("-45 degree rotation", size=30);

旋转图像|作者图像
图像裁剪
对于裁剪图像,可以定义一个效用函数-randRange();以生成期望范围内的随机浮点值。然后,您可以将这些生成的范围值传递到另一个名为randomCrop(), 的函数中,该函数将图像作为输入,并根据所需的边界边距在中心进行裁剪
P.S:以下代码改编自 本 Kaggle 内核。
# source: [https://www.kaggle.com/safavieh/image-augmentation-using-skimage](https://www.kaggle.com/safavieh/image-augmentation-using-skimage)
import random
import pylab as pl
def randRange(a, b):
'''
a utility function to generate random float values in desired range
'''
return pl.rand() * (b - a) + adef randomCrop(im):
'''
croping the image in the center from a random margin from the borders
'''
margin = 1/3.5
start = [int(randRange(0, im.shape[0] * margin)),
int(randRange(0, im.shape[1] * margin))]
end = [int(randRange(im.shape[0] * (1-margin), im.shape[0])),
int(randRange(im.shape[1] * (1-margin), im.shape[1]))]
cropped_image = (im[start[0]:end[0], start[1]:end[1]])
return cropped_image fig,ax = plt.subplots(nrows=1,ncols=2,figsize=(20,12))
ax[0].imshow(image)
ax[0].set_title("Original Image", size=20)
ax[1].imshow(randomCrop(image))
ax[1].set_title("Cropped", size=20)

裁剪图像|作者提供的图像
亮度操作
exposure模块用于亮度操作。函数adjust_gamma对输入图像执行伽马校正。gamma 值越高,生成的图像越暗。
image_bright = adjust_gamma(image, gamma=0.5,gain=1)
image_dark = adjust_gamma(image, gamma=2,gain=1)fig,ax = plt.subplots(nrows=1,ncols=3,figsize=(20,12))
ax[0].imshow(image)
ax[0].set_title("Original Image", size=20)
ax[1].imshow(image_bright)
ax[1].set_title("Brightened Image", size=20)
ax[2].imshow(image_dark)
ax[2].set_title("Darkened Image", size=20)

图像中的亮度处理|作者提供的图像
图像大小调整和缩放
transform.resize()函数转换给定的图像以匹配特定的尺寸。这个函数可以插值放大或缩小图像。请确保在缩小图像时启用抗锯齿功能,以避免出现锯齿现象。 反 - 走样 是数字图像中锯齿状边缘的平滑。
image_resized = resize(image, (image.shape[0] // 2, image.shape[1] // 2),anti_aliasing=True) fig, ax = plt.subplots(nrows=1, ncols=2,figsize=(30,16))
ax[0].imshow(image)
ax[0].set_title("Original Image", size=20)
ax[1].imshow(image_resized)
ax[1].set_title("Resized image",size=20)

已调整大小的图片|作者图片
除了允许指定输出图像形状而不是比例因子外,resize()功能也用于相同的目的。
添加噪声
random_noise()是来自 skimage 的 util 模块的一个函数。它用于将各种类型的随机噪声添加到图像中。噪声是一种缺陷,它被添加到图像中以引入某种可变性。
noisy_image= random_noise(image)fig, ax = plt.subplots(nrows=1, ncols=2,figsize=(30,16))
ax[0].imshow(image)
ax[0].set_title("Original Image", size=20)
ax[1].imshow(noisy_image)
ax[1].set_title("Image after adding noise",size=20)

图像中的噪声添加|作者提供的图像
结论和后续步骤
数据扩充已被证明是提高分类任务准确性的有前途的方法。这在数据可用性有限的情况下尤其重要。Python 以 scikit-image 的形式提供了一个健壮的库,其中包含许多图像增强算法。它是免费的,不受限制的,背后有一个活跃的社区。查看文档以了解关于该库及其用例的更多信息。在接下来的几篇文章中,我们将讨论其他常用的增强库。敬请期待!
感谢
- 图标的名词项目:翻转图标标记;塞巴斯蒂安·贝拉卡扎尔·拉雷奥轮替;Setyo Ari Wibowo 的作物;视觉世界的亮度控制;图像由 ibrandify 阿瑟·史林的《噪声抖动》。
- 数据集参考:植物病理学 2020 挑战数据集对苹果叶部疾病进行分类
- 数据扩充|如何在数据有限的情况下使用深度学习—第二部分
- 深度学习的数据增强
使用 AWS 粘合书签的增量连接
实践教程
问题是
最近,我遇到了一个挑战,即在时间戳上将两个时间序列数据集连接在一起,而不要求两个数据集中的相应数据同时到达。例如,一个数据集上个月某一天的数据可能在一周前到达 S3,而另一个数据集上个月该天的相应数据可能在昨天到达。这是一个增量连接问题。

潜在的解决方案
- 也许可以通过在查询之前不连接数据来解决这个问题,但是我想对连接进行预处理,以便可以在任何比例下直接查询连接的数据。
- 您可以在每次管道运行时重新处理整个数据集。对于每天都在不断变大的数据集来说,这不是一个。
- 也可以手动实现一个系统,在两个表都着陆之前,不处理来自任何一个表的数据。这实际上是重新实现 AWS Glue 已经提供的一个特性:书签,我们将在下面利用它。
使用 AWS 粘合书签和谓词下推
AWS 粘合书签允许您仅处理自管道之前运行以来到达数据管道的新数据。在上述增量连接问题中,需要处理的相应数据可能已经到达并且已经在流水线的不同运行中被处理,这并没有完全解决问题,因为相应的数据将由书签馈送以在不同的作业中被处理,因此不会被连接。
我们提出的解决方案利用了 AWS Glue 的另一个特性,即使用谓词下推加载表的子集的能力。我们在 Glue ETL 工作中完成了以下 ETL 步骤:
# setup Glue ETL environmentimport sysfrom awsglue.transforms import *from awsglue.utils import getResolvedOptionsfrom pyspark.context import SparkContextfrom awsglue.context import GlueContextfrom awsglue.job import Jobfrom pyspark.sql.functions import split, colfrom awsglue.dynamicframe import DynamicFrame## @params: [JOB_NAME]args = getResolvedOptions(sys.argv, ['JOB_NAME'])sc = SparkContext()glueContext = GlueContext(sc)spark = glueContext.spark_sessionjob = Job(glueContext)job.init(args['JOB_NAME'], args)
使用 AWS Glue 目录中的 Glue 书签加载自上次管道运行以来到达的新数据。
table1_new = glueContext.create_dynamic_frame.from_catalog(database="db", table_name="table1", transformation_ctx='table1_new')table2_new = glueContext.create_dynamic_frame.from_catalog(database="db", table_name="table1", transformation_ctx='table2_new')
在新数据中找到受影响的分区。因为这是时间序列数据,所以按日期时间进行分区是有意义的。将这些分区写入可以在整个数据集上查询的下推谓词。
已经构建了谓词字符串,该字符串列出了在一个或两个表中有新数据的每个分区,现在我们可以从源数据表中加载“解锁”该数据。
we use the predicate string we previously built and load the table without using bookmarkstable1_unlock = glueContext.create_dynamic_frame.from_catalog(database="db", table_name="table1", push_down_predicate=table1_predicate)table2_unlock = glueContext.create_dynamic_frame.from_catalog(database="db", table_name="table2", push_down_predicate=table2_predicate)
现在,我们可以使用这两个表运行我们想要的任何连接转换。
然后,我们可以将这些表写入数据库,在我们的例子中是 S3。根据您正在进行的连接转换的类型,我们发现最好在“覆盖”模式下使用 Spark API 编写器,而不是 Glue DynamicFrame 编写器,因为我们希望删除以前运行时写入分区的任何旧数据,并只写入新处理的数据。
# set the overwrite mode to dynamicspark.conf.set("spark.sql.sources.partitionOverwriteMode","dynamic")final_df.write.partitionBy(["partition1", "partition2"]).saveAsTable("db.output", format='parquet', mode='overwrite', path='s3://your-s3-path')
注意,写入 Glue 目录的 PySpark API 模式似乎偶尔会导致表在被写入时变得不可用。
结论
将 AWS 粘合书签与谓词下推结合使用,可以在 ETL 管道中实现数据的增量连接,而无需每次都重新处理所有数据。选择一个好的分区模式可以确保您的增量连接作业处理接近所需的最小数据量。
使用 AWS 粘合书签的增量窗口函数
无序数据着陆问题
无序数据着陆问题
如果数据无序到达(相对于应用窗口函数的维度),对数据应用窗口函数是很重要的。为了清楚起见,让我们把这个例子中的时间序列数据作为我们的窗口维度。如果时间序列数据从一周的星期二到星期四到达,那么该周的星期一的数据在较晚的时间到达,则数据到达是无序的。

里卡多·戈麦斯·安吉尔在 Unsplash 上的照片
由于窗函数输出在时间空间上对其周围环境敏感,窗函数的结果将被到达的新的无序数据改变。所有受影响的数据都需要重新处理。
当数据无序到达时,您可以重新处理所有数据。但是,当数据量很大时,重新处理整个数据集变得不切实际。本文讨论了一种有效的方法,使用我在以前的文章中描述的构建 AWS 粘合谓词下推的方法。这种方法仅重新处理受已到达的无序数据影响的数据。
解决办法
粘附 ETL 作业环境设置
检查新数据
使用 AWS 粘合书签只将新数据输入粘合 ETL 作业。
new = glueContext.create_dynamic_frame.from_catalog(database="db", table_name="table", transformation_ctx='new')
为新数据涉及的每个分区找到最早的时间戳分区。
注意:在下面的示例中,数据被分区为partition1 > timestamp_partition,其中timestamp_partition是唯一的时间序列分区。
从需要处理/重新处理的整个数据集中构建数据的下推谓词字符串。对于没有无序数据的分区,手动定义一个数据窗口来解锁过去的数据,以确保正确处理新的有序数据。
注意:在下面的例子中,我们按照日期在timestamp_partition中进行分区。
对所有需要的数据应用窗口函数
现在,我们可以使用刚刚构建的谓词字符串加载所有需要处理/重新处理的数据。
然后,我们可以在加载的所有数据上定义我们的窗口。
在你的窗口上应用你的函数,这里我们以last函数为例。
为了确保在重新处理过程中被更改的任何旧数据被覆盖,请使用 PySpark API overwrite模式直接访问 S3。
结论
根据从 AWS 粘合书签传递的新数据构建下推谓词字符串仅允许处理/重新处理数据集的所需分区,即使在使用窗口函数时也是如此,窗口函数对其在数据集中的周围环境固有地敏感。
原载于https://data munch . tech .
独立日演讲:这次会持续多久?

过去 21 年印度独立日演讲中的前 200 个单词
21 年印度独立日演讲的 EDA 和对 2020 年 8 月 15 日演讲长度的预测
前言
几天前,我坐在自己的公寓里,思考着这个问题——“今年的独立日会和以往有什么不同吗?
当然会。原因很明显。
这个问题让我想到了另一个问题——“知道这次会有所不同,首相这次会说什么?
这是全国近 10 亿人渴望听到的一件事。
因为今年我们遇到了困难,目睹了近年来前所未有的悲剧。因此,首相的话应该反映一个正在慢慢恢复元气的国家的情绪。
动机
但是我有另一个问题—
这次他会说多长时间?
换句话说,这次传统的独立日演讲会持续多久?
从历史上看,在独立日,过去的总理们会详细谈论他们的政府发起的各种计划、成就、困难和未来的道路。
我认为这将是一个很好的机会,重温过去,窥视昔日的演讲,也许,预测今年的演讲会有多长。
我把代码片段放在这篇文章的最后,因为(惊喜,惊喜)数据可视化第一!!
你可以在我的 GitHub 库上找到整个项目。
数据采集
我浏览了 PMO 档案馆的公开网页,下载了现任和上两届总理的独立日演讲,一直追溯到 1999 年。最近几年,印度有过以下几任总理—
- 施里。阿塔尔·比哈里·瓦杰帕伊(1999-2003 年)
- 曼莫汉·辛格博士(2004-2013 年)
- 施里。纳伦德拉·莫迪(2014 年至今)
提醒一下——这些下载的文本是当时用印地语演讲的英文翻译。
数据预处理
我使用自然语言处理库, NLTK,来-
- 删除不必要的停用词;
- 去掉标点符号;
- 将单词标记化和词条化;
- 用词性标签(词类)标注每个单词;
最后,我只剩下一套 21 篇演讲稿,其中只包含了基本内容。
想象过去的话语
过去演讲中的热门词汇

历年演讲中使用最多的 50 个词(鸣谢:作者)
在过去的 21 年里,独立日演讲中出现频率最高的词显然是:国家、政府、年、今日、印度、世界、兄弟、姐妹。
有趣的是,现任总理什里在过去几年中非常频繁地使用这些词。纳伦德拉·莫迪与其前任相比。另一方面,‘印度’几乎被所有总理平等提及(这是意料之中的)。
谁说了什么?
- Shri。阿塔尔·比哈里·瓦杰帕伊
在他担任总理的 5 年里,什里。阿塔尔·比哈里·瓦杰帕伊被普遍称为现代印度真正的政治家,他在演讲中反映了这一绰号。可以看出,像'世界'、新'、国家'、民族'这样的词汇在他的独立日演讲中被频繁使用。

Shri 排名前 200 的单词。阿塔尔·比哈里·瓦杰帕伊的独立日演讲(鸣谢:作者)
- 曼莫汉·辛格博士
这位从 2004 年到 2013 年领导印度的学者和经济学家总理详细谈论了'发展''教育'、工作等等。在他的独立日演讲中。

曼莫汉·辛格博士独立日演讲中的 200 个单词
- Shri。纳伦德拉·莫迪
最近连任的现任总理在过去独立日的演讲中强调了穷人、农民、T42 人和印度人的利益。

Shri 排名前 200 的单词。纳伦德拉·莫迪的独立日演讲(鸣谢:作者)
历年的演讲长度
看看演讲的持续时间和文本长度,令人惊讶的是瓦杰帕伊的演讲是持续时间和长度最短的,而莫迪的演讲是迄今为止最长的。
在过去的 21 年里,演讲的篇幅稳步增长,莫迪当选后出现了大幅增长。2017 年演讲时长有明显下降。根据这篇文章,首相收到了抱怨他前一年(2016 年)长篇演讲的信件,这促使他保持简洁。
但这只是那一年的情况,因为接下来的两年,演讲又变得更长了。

过去 21 年的演讲长度(以分钟和单词为单位)
预测今年的演讲长度
自回归模型
看过以往的演讲时长,想到用一个简单的自回归(AR) 模型来预测今年的演讲时长。
在我看来,这些独立日演讲似乎是精心撰写和控制的,也着眼于历史,以确保事情忠于传统(至少在 2013 年之前是这样)。
最多,今年的演讲长度可能取决于去年的演讲长度(正如我之前写的轶事所证明的),因此 1 的滞后对于 ar 模型来说应该足够好了。此外,由于这是一个非平稳的时间序列,我差分一次,使它在拟合模型之前平稳。
为了测试这个简单的模型,我对它从 2010 年开始连续几年的演讲长度进行了训练,并进行了滚动预测。2011 年至 2019 年的产量如下所示。
*2011
predicted=41.497464, expected=34.000000
2012
predicted=34.293300, expected=32.000000
2013
predicted=32.275443, expected=28.000000
2014
predicted=27.779659, expected=65.000000
2015
predicted=64.317813, expected=86.000000
2016
predicted=94.102461, expected=96.000000
2017
predicted=101.639437, expected=57.000000
2018
predicted=52.350426, expected=81.000000
2019
predicted=81.350816, expected=92.000000
Test RMSE: 23.252*
所以这个模型在 2014 年显示了很大的误差,当时新总理当选了,他的讲话比他的前任还长!从那以后,这个简单的模型在 2017 年和 2018 年出现了错误,因为——看在上帝的份上,这只是一个自回归模型!!它只是依靠它前一年的价值来预测下一年的价值。
无论如何,这个模型似乎有一个+- 23 分钟的误差,对今年,2020 年的预测是
*>>> 94.7 +- 23 minutes*
因此,看起来首相可能会在独立日发表最长约 120 分钟、最短约 70 分钟的讲话!
免责声明
- 请对这一预测持怀疑态度,因为——它只是一个 AR 模型,并没有学到任何东西(除了更新它的回归系数),因为除了它以前的值,没有任何可供学习的特征。
- 这个预测是在独立日前夕做的,所以我在等着验证!
- 所有演讲都可以在项目管理办公室的档案中免费下载。
更新——首相今年发言 86 分钟,完全在预测误差之内!
代码片段
在这里,我展示了我编写的代码片段,以生成数据可视化和文本清理。
文本清洗和预处理
清理和预处理文本的功能—
*def speech_cleaner(text):
# Lower Case conversion
text = text.lower()
# Tokenize sentences to words
text = nltk.word_tokenize(text)
# Remove empty tokens
text = [w for w in text if len(w) > 0]
# Remove punctuations
punct = string.punctuation
text = [w for w in text if w not in punct]
# Remove stopwords
stopword = stopwords.words('english')
text = [w for w in text if w not in stopword]
# POST Tagging the text
pos_tags = pos_tag(text)
# Lemmatize the text
text = [WordNetLemmatizer().lemmatize(w[0]) for w in pos_tags]
# Removing one letter words
text = [w for w in text if len(w) > 1]
# Rejoin all words to get back speech
speech = " ".join(text)
return speech*
一个从本地目录读入文本并用前面的函数清理它的函数—
*def text_reader_cleaner(file):
text = []
with open(file, 'r') as f:
text = f.readlines()
clean_speech = ""
for i in text:
clean_speech = clean_speech + " " + speech_cleaner(i)
return clean_speech*
进一步预处理—
*all_speech = ""
all_words = pd.DataFrame([], columns=['year','words'])
for y, s in speech.items():
all_speech = all_speech + s
w = pd.Series(re.split("\W+",s))
w = w.drop(index=w.loc[w.values==''].index)
all_words = pd.concat([all_words,
pd.DataFrame({'year':len(w)*[y],
'words':w}),
], axis=0)
all_words = all_words.reset_index(drop=True)all_words['pos_tag'] = pd.DataFrame(pos_tag(all_words.words))[1]
all_words['chk'] = 1*

这是预处理后的语音输出
前 50 个词的热图
下面是分隔名词的代码片段—
*nouns = all_words.loc[all_words.pos_tag=='NN'].words.value_counts()/10
names = nouns.loc[nouns.values>5].index
names = names.drop('br')
word_year = pd.pivot_table(all_words, values='chk', index='words', columns='year', aggfunc=np.sum)*
这是你绘制热图的方法—
*fig,ax = plt.subplots(figsize=[10,10])
colors = ["orange", "blue", "limegreen"]
cmap0 = LinearSegmentedColormap.from_list("india_tricolor", colors)
sns.heatmap(word_year.loc[names[:50]], cmap=cmap0)
plt.title('Number of times the top 50 words were mentioned')*
词云生成器
这里有一个使用漂亮的 wordcloud 库生成 wordcloud 的函数
*def wc_generator(clean_speech, cmap=None):
if cmap is None:
cmap = LinearSegmentedColormap.from_list('india_tricolor', ['orange', 'white', 'green'])
wordcloud = WordCloud(
width=800, height=400,
background_color='black',
colormap=cmap,
max_words=200,
random_state=42
).generate(clean_speech)fig, ax = plt.subplots(dpi=400, figsize=[15,10])
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.figure()*
语音长度时间序列
为了绘制时间序列,你可以写这段代码—
*colors = ["orange", "white", "limegreen"]
cmap0 = LinearSegmentedColormap.from_list("india_tricolor", colors)
india_tricolor = cmap0(np.linspace(0,1,21))y = []
l = []
for year, text in speech.items():
y.append(year)
l.append(len(text))fig, ax1 = plt.subplots(dpi=300,figsize=[15,6])
ax2 = ax1.twinx()spt = pd.Series(speech_time).values
for y1, l1, c in zip(y,l, india_tricolor):
ax1.bar(y1, l1, color=c, edgecolor='k')
ax1.set_ylabel('Speech Length (words)')
ax2.plot(y,spt, marker='s',color='b')
ax2.set_ylabel('Speech Length (minutes)')plt.xticks(np.arange(1999,2020), np.arange(1999,2020).tolist())
plt.show()*
语音长度预测的自回归模型
为了进行滚动预测并检查预测误差,您编写了这个简单的代码片段(感谢 www.machinelearningmastery.com的杰森·布朗利!)—
*from statsmodels.tsa.arima_model import ARIMA
from sklearn.metrics import mean_squared_errorX = df.sp_len.values
size = int(len(X) * 0.6)
train, test = X[0:size], X[size:len(X)]
history = [x for x in train]
predictions = list()
for t in range(len(test)):
model = ARIMA(history, order=(1,1,0))
model_fit = model.fit(disp=0)
output = model_fit.forecast()
yhat = output[0]
predictions.append(yhat)
obs = test[t]
history.append(obs)
print()
print('predicted=%f, expected=%f' % (yhat, obs))
error = np.sqrt(mean_squared_error(test, predictions))
print('Test RMSE: %.3f' % error)*
那都是乡亲们!
再见!
揭开自动完成的神秘面纱—第 1 部分

照片由 Unsplash 上的 Dmitry Ratushny 拍摄
都是概率局长!
自动完成
你手机键盘应用程序的自动完成功能保存了多少次(或者有时毁掉了,取决于你想输入什么)你的对话?从我们每天发送的短信和电子邮件的数量来看,这个数字将是惊人的,你甚至可能不认为这是什么重要的事情,因为你已经习惯了这种经常被忽视和低估的技术。你甚至可能会继续说,“嗯,它有什么特别的,它很简单,我写一个单词,它就能预测接下来的事情。”

作者笔下的 autocomplete.jpeg
相信我,这看起来很简单。其实不是。在这个看似简单的事情背后有很多工作要做,以给你带来在网上大吵大闹时节省一些按键的便利。让我们揭开这个自动完成功能看似简单但并不简单的本质。
它只是预测…
预测是一个复杂的词。因为它有很多包装。我们在谈论什么样的预测?根据什么来预测?这个预测会如何进行呢?很多问题。因此,让我们为所有这些问题选择一个简单的答案。预测是基于某件事情发生的可能性。如果天气预报说明天会下雨,他们是在说明明天下雨的可能性。他们是如何做到的?根据过去几年的降雨记录。或者可能很多年。你明白了。
所以,当你在手机上写下一个单词时,你有没有注意到与这个单词最匹配的单词是如何立即出现的?这是因为底层软件试图预测你下一个可能写的单词。现在,它不会总是正确的,但它会尽最大努力列出一个单词列表,最好地补充您之前所写的内容。
可以这么说,自动完成就是预测你接下来可能会写什么!或者,我们可以说 autocomplete 会生成下一个最有可能的单词,不管我们已经写了什么。说到基于概率生成文本——在 NLP 中有一个特殊的主题叫做语言模型。
什么是语言模型?
维基百科对语言模型的定义对于理解这个主题的重要性来说并不那么鼓舞人心,但是不管怎样,让我们从这个开始吧。
统计语言模型是单词序列的概率分布。给定这样一个长度为 m 的序列,它分配一个概率 P(w1…wm)应用于整个序列。
是的……概率。好的。让我们开始吧。语言模型所做的是,对于一些文本(可以是一行或一段或任意长度的文本),它为单词或字符分配概率分数。但是这些分数是基于什么呢?好问题。答案是,它们可以基于任何标准,但语言模型最可能的用例是找出一个单词在一种语言中出现在另一个单词之后的可能性。让我们以下面的句子为例。
I ate burger.
你好奇的心可能会问,为什么是汉堡而不是比里亚尼?也许我可以吃炸肉排。或者可能是多纳·凯巴普。或者其他太多的事情。你的大脑几乎立刻就在试图挑选可以用来代替burger的词。因为,一个人可以吃的东西很多吧?庞大的自然选择和进化强化的大脑数据库可以很容易地将ate与可能的食物列表联系起来。
好吧,我们简化一下。让我们忘记我们只有这句话
ate ___________
在单词 eat 后填空。根据你的知识,你能想出多少单词。现在,问问你自己,为什么在吃这个词后面应该只有食物或者消耗品?为什么不能写汽车,山,电视等。?因为你大脑中的知识库说——“伙计,吃车没道理。”或者,你的大脑分配给某人吃车的概率非常低。如此之低以至于不再合理或重要。
所以回到手边的语言模型这个话题。它为一些文本分配概率。语言模型可以用于从翻译(是的,谷歌翻译使用一种高级语言模型)到问答到自动完成——任何你需要生成单词或文本或预测它们的地方。
对于 autocomplete,正如您已经理解的,我们正在查看一个单词,并试图预测下一个单词。所以,如果我把第一句话I ate burger.拿来,试着根据每个单词基于前一个单词的概率来建模,它应该变成这样一个等式:
在我们写方程之前,让我们给句子添加一些符号。为什么这样马上就要谈到这一点了!
现在对于这个等式-
等等,那不是条件概率吗?
是的。每个单词的存在都基于前一个单词存在的先验。事实上,这种基于条件概率的语言建模有一个名字。这些被称为马尔可夫模型。
虽然基于左上下文对单个单词进行建模的任务似乎比给整个句子分配概率分数更容易管理,但等式中的最后一项仍然需要对 n-1 个单词进行调节,这与对整个句子进行建模一样困难。由于这个原因,语言模型利用了马尔可夫假设,即假设现在,未来独立于过去。
马尔可夫模型表明序列中的下一个元素是基于它之前的元素。这就引出了一个问题,我们只考虑了前一个词。如果有更多的话呢?为了得到先验概率,我们可以选择多少个词,有没有一个标准的定义?答案是否定的,对此没有标准的定义。你问的这个字数,叫做窗口大小。窗口大小可以根据许多因素而变化,比如你的文本量等等。窗口的值会直接影响您的预测结果。此外,除了窗口大小还有一个因素。
n-grams
如果你看看上面的等式,我们只考虑了两个单词的组合。比如汉堡|吃了。像这样的两个词的组合被称为二元词。如果我们考虑三个词,它将被称为一个三元模型。四个?四方图等等。因此这种方法被称为 n 元语法。像窗口大小一样,如果你使用马尔可夫模型,克数也会对概率产生影响。我在句子中添加了 BEGIN 和 END,这样句子开头和结尾的单词可以在 n-gram 中对照这些标记进行测试。
其他句子呢?
假设我们坚持我们的方法,使用二元模型,只检查前一个单词。那么对于任何一个句子, s 和 n 个单词的语言模型的等式就是-
现在,如果我们想要一个三元模型呢?那么我们会检查前面的两个单词,而不是一个。
等等,怎么得到那个概率的值?
我很高兴你问了。我们使用一种被证明稳定的防弹统计方法,叫做最大似然估计 3 。它只有一个任务,计算出某件事情发生的可能性,这是一件已经发生的相关事情。既然我们在谈论单词,我们就这样做:
假设我们有一个由单词 a 和 b 组成的二元模型,我们需要概率 P(b | a)
当我们说计数时,我们实际上是指它们在某个文本数据集或语料库中出现的次数。
文集
对于外行来说,语料库是一个结构化的、定义良好的、带注释的包含文本的数据集。如果你对机器学习感兴趣,你应该知道这意味着什么。我们人类学习数百个单词,我们的语言中有数千甚至数百万个单词。我们可以很容易地选择它们,因为我们的大脑已经经历了数千年的自我训练,并通过基因的共享将训练经验传递下去。我们的计算机是孤独的,没有无限的内存。他们一次只能看到所有文本的一小部分。
我在社交网络上使用的非常规词汇呢?
是的关于那个。你可能已经注意到,你在手机上使用的键盘会记住你最常用的单词类型。当你越来越多地使用键盘时,它会存储你用得更多的单词,并给它们分配一个特定的重要性权重,这样它们总是比其他单词获得更高的概率。
但是马科夫不是卡拉什尼科夫冲锋枪的头儿!
他们有他们的局限性。虽然马尔可夫模型对于小句和文本数据集或语料库的表现令人钦佩,但当句子和语料库开始变大时,它们就开始打嗝了。这就是为什么对于高级的现实世界任务,我们倾向于使用神经语言模型。在这里,您可以选择更多的参数,而不仅仅是一些窗口大小和 n-gram。
同样,正如你从上面的 MLE 方程中看到的,我们使用了单词的频率。虽然使用频率很好,但有时可能会发生这样的情况,您的系统在一个语料库上训练,但缺少一个在实际训练语料库或系统附带的初始知识库中不存在的单词。该单词的 Count()将为 0,并且您的系统将为该单词分配一个 0 概率,这并没有真正的帮助,因为系统不会像预期的那样工作。相信我,没有人喜欢不能工作的软件。您可以对这类系统应用一些常见的补救措施,如平滑、对新单词使用特殊标记,或者将新单词添加到您的知识库等。
对于单独的平滑,您可以应用拉普拉斯平滑、alpha 平滑 5 6 、Jelinek Mercer 插值平滑 7 8 、Kneser Ney 平滑 9 等。
另一件事,正如亚夫·戈德堡提到的-
基于 MLE 的语言模型缺乏跨上下文的通用性。观察到黑色汽车和蓝色汽车并不影响我们对红色汽车事件的估计,如果我们以前没有看到它的话。
这篇文章越来越长了
是的是的。我知道。我将在这篇文章的下一部分讨论神经语言模型。在那之前,继续使用你的手机键盘,让它们努力预测下一个单词!
参考资料和资源
- 乔里斯·佩勒曼斯,诺姆·沙泽尔和西普里安·切尔巴。稀疏非负矩阵语言建模。计算语言学协会汇刊,4(1):329–342,2016。http://aclweb.org/anthology/Q16–1024
- 戈德堡,你好。自然语言处理的神经网络方法(人类语言技术综合讲座)。摩根&克莱普出版社。
- StatQuest:最大似然,解释清楚!!!
- 斯坦利. f .陈和约书亚.古德曼。语言建模平滑技术的实证研究。1996 年计算语言学协会第 34 届年会。http://aclweb.org/anthology/P96–1041·多伊:10.1006/csla
- 维基百科关于加法平滑的文章
- 马丁·茹拉夫斯基。语音和语言处理(第三版。草稿)
- 曼宁,克里斯托弗。统计自然语言处理基础(麻省理工学院出版社)
- https://en.wikipedia.org/wiki/Language_modelt18】↩︎
- 戈德堡,你好。自然语言处理的神经网络方法(人类语言技术综合讲座)(第 105-106 页)。摩根&克莱普出版社。Kindle 版。 ↩︎
- https://en.wikipedia.org/wiki/Maximum_likelihood_estimationt24】↩︎
- https://en.wikipedia.org/wiki/Markov_modelt28】↩︎
- 斯坦利. f .陈和约书亚.古德曼。语言建模平滑技术的实证研究。计算机语音和语言,13(4):359–394,1999。↩︎
- 约书亚·古德曼。语言建模的一点进步。更正,cs.CL/0108005, 2001 年。http://arxiv.org/abs/cs.CL/0108005doi:10.1006/csla . 2001.0174 .↩︎
- 弗雷德里克·耶利内克和罗伯特·默瑟。稀疏数据中马尔可夫源参数的插值估计。模式识别实践研讨会,1980 年。 ↩︎
- 斯坦利. f .陈和约书亚.古德曼。语言建模平滑技术的实证研究。计算机语音和语言,13(4):359–394,1999。↩︎
- 赖因哈德·科内瑟和赫尔曼·内伊。改进的 m-gram 语言建模的后退。声学、语音和信号处理,ICASSP-95,国际会议,第 1 卷,181-184 页,1995 年 5 月。doi:10.1109/icassp . 1995.479394 .↩︎
- 戈德堡,你好。自然语言处理的神经网络方法(人类语言技术综合讲座)(第 108 页)。摩根&克莱普出版社。Kindle 版。 ↩︎
索引匹配 VLOOKUP 功能的升级
电子表格/索引匹配
掌握电子表格最通用的功能之一

在上一篇文章中,我们讨论了如何以及何时使用 VLOOKUP 函数,以及在使用它们时我们可能会面临哪些问题。另一方面,本文将带您了解 VLOOKUP 的升级版本。此次升级结合了电子表格中的两个功能— 索引和匹配。让我们通过下面的例子来理解索引匹配的工作原理。
理解数据
像往常一样,让我们从我们最喜欢的数据源——ka ggle 中取一个例子。下面的截图是网飞数据的一个子集,其中包括截至 2019 年网飞上可用的电视节目和电影。

用于指数匹配演示的网飞数据
这个数据集由不同的节目和电影以及它们独特的show_id、我们正在考虑的country、节目添加时的date和实体发布时的year组成。它还包含节目/电影的rating、内容片段的duration和title。
现在考虑我们想要创建一个搜索方法,用户可以选择一个title并向用户显示关于该标题的信息。这种搜索方法看起来像这样:

搜索方法的外观示例
用户可以在上面的例子中输入任何title,我们将尝试从数据库中找到标题的type和rating。一个更简单的解决方案是通过 VLOOKUP。通过它我们可以很容易的找到题目的评分。虽然,我们需要改变表格的结构来获得标题的类型,因为 VLOOKUP 只能查看搜索值的右边。让我们看看索引和匹配公式如何帮助我们解决这个问题。
什么是索引?
电子表格中的索引公式如下所示:

Google 电子表格中的索引公式
INDEX帮助我们找到细胞的内容。它需要 3 个输入。
- 引用:我们要在其中查找值的表格。
- Row :从值所在的引用表开始算起的行数。这是一个可选值。如果没有提供值,它将把第一行作为值。
- Column :从值所在的引用表开始算起的列数。这是一个可选值。如果没有提供值,它将把第一列作为值。
为了在我们的表格中找到标题“Carrie Pilby”的类型,我们应用以下公式:
=INDEX(A1:H23,12,2)
我们选择完整表作为引用,我们发现该电影标题在第 12 行,并且我们知道标题的类型存储在引用表的第 2 列。这将给出“电影”的结果,这是绝对正确的!
但是你注意到这个有什么问题吗?我们实际上不得不计算行号和列号以获得 12 和 2 作为公式中的参数。这不容易,是吗?让我们找出世界上是否有其他方法可以帮助我们缓解这个过程。
什么是匹配?
电子表格中匹配公式如下所示:

匹配 Google 电子表格中的公式
MATCH 帮助我们找到表格中内容的相对位置。它需要 3 个输入。
- 搜索关键字:我们要查找的值。
- 范围:数值所在的行/列。请注意,range 只能接受一行或一列,不能同时接受两者。
- 搜索类型:出于所有实际目的,我们将该值设置为零。这表明我们正在寻找精确的值。这是一个可选项,默认情况下取值为 1。
MATCH 本质上给了我们搜索项所在的行号或列号。这不就是我们之前遇到的索引拼图的缺失部分吗?我们需要一种更简单的方法来找到搜索项的行号和列号,而不是手动计数。而 MATCH 恰恰给了你这些!
神圣的索引-匹配婚姻
上面的解释现在允许我们将索引和匹配公式连接在一起,以最少的麻烦获得我们需要的信息。下面是一个通用的指数匹配公式:
=INDEX(reference, MATCH(search_key, row, 0), MATCH(search_key, column, 0))
在上面的公式中,我们为索引提供了一个引用表,基本上就是所有信息所在的数据表。接下来,第一个匹配公式提供搜索词的行索引,而第二个匹配提供搜索词的列索引。最后,这两者的结合将为索引公式提供行和列索引,我们将得到我们想要的结果!让我们在网飞的例子中尝试一下。

用于查找内容类型的索引匹配
上面的公式在 INDEX 的第一个参数中选择整个表。然后通过匹配公式在整行内容标题中搜索 K1 中提到的电影标题,即 C1:C23。这将返回标题“Carrie Pilby”所在的行号。在第二个匹配中,它搜索 J2,这是我们想要查找的参数,在本例中为 Type。这将返回列名“Type”所在的列。并且一起将提供正确的结果,即电影。
类似地,下面是如何匹配表格中给定内容标题的评级的公式。

用于查找内容分级的索引匹配
与 VLOOKUP 比较
通常会比较使用哪个公式来查找给定内容的值。虽然 VLOOKUP 更容易理解并提供了一个简单的应用程序,但索引-匹配组合是一个强大的匹配,具有以下优点:
- 您可以使用 INDEX-MATCH 来查找符合多个标准的值。在上面的例子中,我们找到了带有内容名称标准和参数标准的
Type和Rating。这在 VLOOKUP 中并不容易实现。 - VLOOKUP 在左侧查找匹配项,并返回搜索项右侧的任何值。另一方面,索引匹配可以双向查看。在上面的例子中,type 在 title 的左边,rating 在右边,但是它仍然能够正确地找到两个结果。
了解索引匹配为您的电子表格军械库添加了一个极其通用的工具。索引匹配和数据透视表的知识可以真正帮助你提高你的分析技能。如果这是一个有用的内容,请在评论中告诉我!
指数跟踪——注意差距!
使用衍生工具的实际挑战和策略

你在密切跟踪吗?本·帕丁森在 Unsplash 上的照片
为什么要进行指数跟踪
许多机构和散户投资者面临的一个共同挑战是有效控制各种市场因素的风险敞口。有各种各样的指数旨在提供跨部门和资产类别的不同类型的风险,包括股票、固定收益、商品、货币、信用风险等。
这些指数中的一些可能很难或不可能直接交易,但投资者可以交易相关的金融衍生品,如果它们在市场上可用的话。例如,CBOE 波动率指数(VIX),通常被称为恐惧指数,不可直接交易,但投资者可以通过交易 VIX 的期货和期权获得该指数,并可能对冲市场动荡。
波动指数(VIX)
为了说明持有 VIX 债券的好处,可以考虑一下 2011 年标准普尔下调美国信用评级的事件。2011 年 4 月 18 日,S&P 对美国信用评级持负面展望的消息传出。如图 1(a)所示,在 2011 年 8 月 5 日官方降级后的几个月里,仅持有 SPDR 标准普尔 500 交易所交易基金(SPY)的投资组合将继续下跌约 10%。

(a)2011 年 4 月 1 日至 2011 年 9 月 30 日,以及(b)2014 年 1 月 1 日至 2014 年 12 月 31 日期间,100%投资于 SPY,90%投资于 SPY,10%投资于 VIX 的投资组合的历史投资组合价值。
相比之下,一个混合了间谍(90%)和 VIX (10%)的假设投资组合在降级期间将保持稳定,最终获得正回报。图 1(b)显示了 2014 年同一对投资组合。
两者都获得了大致相同的 15%的回报,尽管《间谍》一书明显比《间谍》和 VIX 的投资组合更不稳定。VIX 股市上涨应对了大规模的下跌(例如 2014 年 10 月 15 日),对投资组合的价值产生了稳定效应。
这个例子激发了对直接跟踪 VIX 和其他指数的交易策略的研究,或者实现任何关于指数或市场因素的预先指定的暴露。
指数跟踪的挑战
许多 ETF 或 etn 被宣传为通过维护与指数相关的证券组合(如期货、期权和掉期)来提供指数敞口。然而,一些 ETF 或 etn 经常达不到它们的既定目标,一些 ETF 或 etn 的表现往往远远低于既定目标。

VXX(蓝色)明显偏离 VIX(红色),在过去几年中损失了 93%以上。
一个例子是巴克莱的 iPath 标准普尔 500 VIX 短期期货 ETN (VXX),这也是最受欢迎的 VIX 交易所交易产品。3 VXX 跟踪 VIX 失败是有据可查的。事实上,这些 ETF 或 etn 大多遵循静态策略或时间确定性配置,不适应快速变化的市场。
跟踪问题与所有资产类别都相关,衍生品的使用也相当普遍。例如,许多投资者寻求投资黄金来对冲市场动荡。然而,由于储存成本,直接投资金条是困难的。为了获得敞口,投资者可能会在许多黄金 ETF 和衍生品中进行选择。
新的方法论
在我们最近的论文中,我们讨论了使用衍生品进行指数跟踪和风险敞口控制的一般方法。在市场和相关风险因素的非常一般的框架下,我们推导出一个公式,该公式将嵌入在衍生产品组合中的风险敞口(针对不同的风险因素)联系起来。
投资组合的对数收益可以分解如下:

右边的前两项表示投资组合的对数收益(LHS)与指数 s 及其驱动因子 Yᵢ的对数收益成比例,比例系数(β,ηᵢ)等于期望的风险敞口。然而,投资组合的对数收益受制于滑移过程 z。
滑点过程可用于量化投资组合收益与指数及其因素目标收益的背离程度。它不仅是潜在因素的已实现方差的函数,也是指数和因素之间的已实现协方差的函数。
滑点揭示了风险因素之间相互作用产生的潜在价值侵蚀。
指数跟踪可以看作是衍生品动态套期保值的逆问题。在传统的套期保值问题中,目标是交易基础资产,以便复制所讨论的衍生产品的价格演变,因此,基础资产的可交易性至关重要。
在我们提出的范式中,指数和随机因素可能不直接交易,但存在写在其上的交易衍生品。我们使用衍生工具以路径方式跟踪或更一般地控制与指数回报相关的风险敞口。因此,我们可以研究衍生产品的各种投资组合所产生的路径属性,并量化投资组合与预先指定的基准之间的差异(如果有的话)。我们的方法还允许投资者获得与模型中相关因素相关的杠杆或非杠杆风险。
回到 VIX
受 VIX 的启发,我们探索了我们的方法在 VIX 一些模型下的应用和意义。特别是,我们的方法和实例揭示了 VIX 均值回复行为与 VIX 衍生品定价和跟踪该指数及其相关因素之间的联系。我们考虑 CIR 模型下的跟踪和风险暴露控制问题

和双因子级联平方根(CSQR)模型

在我们的发现中,我们推导出使用期权或期货跟踪 VIX 或实现指数和/或其因素的任何敞口的交易策略。我们的投资组合采用明确的路径自适应 策略,而不是 VXX 和其他 etn 使用的时间确定性策略。
虽然我们选择了 VIX 作为我们的主要例子,我们的分析适用于其他均值回复价格过程或市场因素。
参考
T.Leung 和 B. Ward,使用衍生工具的动态指数跟踪和曝光控制[pdf;链接,应用数理金融,第 25 卷第 2 期,2018 年第 180–212 页
T.Leung 和 B. Ward,《用 VIX 期货追踪 VIX:投资组合的构建和表现》;链接,见应用投资研究手册, J. Guerard 和 W. Ziemba 编辑。,世界科学出版公司,2020 年
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
更多信息,请关注/联系 Linkedin:https://www.linkedin.com/in/timstleung/
使用投资组合优化方法的指数复制
市场指数的量化金融
距离我上次发帖已经整整一年了,我想写一写我最近在家期间做的一个项目。很难在网上找到实用的资源。有许多数学和理论性的学术论文,但我想支持那些寻找代码和门外汉理解的人,因为我已经花了 4 天时间研究和处理这个项目。
我将在这篇文章中省略大部分代码,但你可以在这里访问所有内容:
👉🏻回购链接
指数跟踪投资
是一种被动的投资策略,试图重新创建一个投资组合,产生类似于大盘指数的回报。这可以通过以下方式实现:
完全复制
指数的完全复制要求基金持有指数中所有资产的份额,并尽可能复制指数中每种资产的权重。交易指数中的非流动性资产可能会增加基金的交易成本,导致更高的费用率和更差的基金业绩。
投资组合优化
该项目的目的是通过减少跟踪误差,使用指数中最大资产的最优投资组合选择来复制指数。最终,我们将为投资组合中每个最大的资产生成一个权重,以仅用几个资产复制指数的表现。
跟踪误差

在这种情况下,基准是指数
信息比率

类似夏普比率的衡量标准,量化投资组合的主动回报/主动风险
Russell 1000 是富时罗素(FTSE Russell)维护的股票市场指数,跟踪整个美国股票市场排名最高的 1000 只股票,我们的目标是复制以下股票。测试期:2019–04–01 至 2019–04–30。
数据收集
市场指数会定期进行再平衡,以确保与当前市场保持同步。当富时罗素在 1984 年创立该指数时,印第安纳标准石油公司是美国市值最大的公司之一。今天,该公司已经解散,不存在了。
根据[年度重组时间表](https://www.ftserussell.com/press/ftse-russell-announces-schedule-annual-russell-us-index-reconstitution https://www.ftserussell.com/press/ftse-russell-announces-2018-russell-us-indexes-reconstitution-schedule),有一个“排名日”,在收盘时计算市值前 1000 家公司的排名。随后是在“生效日”进行重组之前的过渡期,在该日,市场以新重组的指数开盘。在用顶级公司来近似指数时,我们应该小心考虑这一点,因为它们(或它们的权重)可能会随着时间的推移而变化。我在 2018 和 2017 使用了富时重组摘要报告公布的指数前 10 名成分。训练数据取自 2018 年 6 月 25 日至 2019 年 2 月 28 日。
Market Cap of Top 10 in 2018 {'AAPL': 5016475823, 'AMZN': 483381822, 'GOOG': 694989876, 'MSFT': 7898764549, 'FB': 2917587472, 'BRK-B': 2444334034, 'JPM': 3601578394, 'XOM': 4614039868, 'JNJ': 2875386042, 'BAC': 10598321272}
基于罗素方法论的基准指数重构
我们将使用 Russell (第 4 页)的价格回报指数来重建包含前 10 个成分的指数。指数值(第 34 页)然后通过复合价格回报指数的每日回报百分比获得。索引的起始值等于基数,在 1978 年 12 月 31 日设置为 100。因此,在我们的基准日:2017 年 6 月 27 日,我们将使用^RUI's 收盘价= 1341.03(来自雅虎财经)作为我们的基准价。仅使用前 10 名,结果看起来一点也不接近。

根据实际指数对重新创建的基准进行总体评估
使用非负最小二乘(NNLS)优化的分配
其想法是在训练期间,在一个受约束的线性最小二乘模型中,根据指数价格拟合当前前 10 种成分的线性组合。所获得的系数将是非负的,因为这是一个只做多的投资组合。
每个系数取系数之和,作为测试期内每个组件的权重。权重的总和将是投资组合复制指数价格所需的杠杆数量。

目标是优化它,其中 x & A 是前 10 名的系数和历史价格,y 是指数价格

样本 x =前 10 名的历史价格
从库中调用的优化本质上是:
**from** **scipy.optimize** **import** nnls
result = nnls(trainX, trainY)
系数然后被用作该线性组合中的权重,其中杠杆系数是系数之和:


结果
虽然我也在测试期之前的 1 个月的维持期内验证了模型,但我将只展示测试集上的结果。

就价格和每日回报而言,复制的指数似乎在视觉上与实际指数匹配得很好。跟踪误差为 43 个基点(0.43%),RMSE(实际值)似乎相当低。
使用相对偏相关的分配
这种想法是,如果某个成分与指数的实际收盘点位相关性更高,就给它分配更多的权重。偏相关使来自 1)其他 IV 上指数的最小二乘回归和 2)其他 IV 上个体 IV 的最小二乘回归的残差相关。这说明了混淆和第三方的影响。我还忽略了负相关的成分,将其设置为 0。类似地,我们将对每个相关性求和以获得权重

相当于为 IV1 & DV 捕捉 D,为 IV2 & DV 捕捉 G
从库中调用的优化本质上是(其中 train 包括历史成分和实际指数价格:
**import** **pandas** **as** **pd**
train.pcorr()

使用相对部分相关值作为权重
如上所述,类似的线性组合方法将用于模拟实际。

结果

跟踪误差和回报 RMSE 高于基准。但是,RMSE 的价格要低很多。这可能是由于该模型在单独考虑每个组件的影响时过于简化。
使用动态时间弯曲(DTW)优化的分配
Pearson correlation 无法捕捉形状相似性,并将确定一对时间序列彼此不相关,即使它们可能非常相似并且只是不同相。这在领先/滞后变量及其对应变量之间可能很明显。这个想法是,如果一个组件与索引的 DTW 距离相对较短,从而具有更相似的形状,则向该组件分配更多的权重。

DTW 距离说明了形状的相似性。
目标是针对每个组件(x)和实际指数(y)进行优化:

从库中调用的优化本质上是:
**from** **tslearn.metrics** **import** dtw
trainX.apply(**lambda** x: dtw(x, trainY))

每个距离的倒数作为相似性的度量,相似性作为相似性总和的一部分,用作线性组合中的权重,以复制索引。
结果
跟踪误差,价格 RMSE &回报 RMSE 表现差于部分相关模型。这可能意味着形状相似性可能不是区分每个组件的重要因素。
使用非负矩阵分解的分配(NMF)
虽然 NNLS 是一种监督学习方法,但无监督 NMF 方法能够通过单个主成分来学习数据的表示。主成分将是资产的线性组合,使得由于该算法中的约束,系数将是非负的。我们的想法是找出每项资产对数据总体变化的相对重要性,并再次将其作为线性组合中的权重。

该算法通过优化 X 和 Y=WH 之间的距离,将数据分解为两个非负元素矩阵。x 由 W 中的线性组合表示,使用 h 中的系数。
从库中调用的优化本质上是:
**from** **sklearn.decomposition** **import** NMF
nmf = NMF(n_components=1)
nmf.fit(trainX)
coeffs = nmf.components_.tolist()[0]
结果

这种方法的问题是价格不能被正确地复制,因为我们不知道无监督学习方法中的杠杆因子,因此价格 RMSE 非常高。
使用粒子群优化算法的分配
PSO 模拟分散在搜索空间中的“社会生物”,并移动以找到最优解。这里的优化函数是最小化跟踪误差。

每个粒子代表一组随机初始化的投资组合权重。他们的行动受到(1)他们个人寻找的欲望和(2)群体或其邻居的集体行动的影响。

Bounds = [0,1],因为系数是非负的,并且组件的值不能大于索引。
网格搜索在 c1,c2,w 上执行。网格搜索的代码几乎与下面的块相同,它将为您提供在下面的块中使用的 best_pos,以进行最终优化。
**from** **pyswarms.utils.search.grid_search** **import** GridSearch
**from** **pyswarms.utils.search.random_search** **import** RandomSearch
**from** **pyswarms.single.global_best** **import** GlobalBestPSO
**from** **pyswarms.utils.plotters** **import** (plot_cost_history, plot_contour, plot_surface)**def** find_particle_loss(coeffs):
trainX_returns = trainX.pct_change().dropna()
trainY_returns = trainY.pct_change().dropna()
benchmark_tracking_error = np.std(trainX.dot(coeffs) - trainY)
**return** benchmark_tracking_error
**def** swarm(x):
n_particles = x.shape[0]
particle_loss = [find_particle_loss(x[i]) **for** i **in** range(n_particles)]
**return** particle_lossfeature_count = len(trainX.columns)
min_bound = feature_count*[0]
max_bound = feature_count*[1]optimizer = GlobalBestPSO(n_particles=1000,
dimensions=len(trainX.columns),
options=best_pos,
bounds=(min_bound,max_bound))
*# Perform optimization, cost=lowest particle_loss among all iterations*
cost, pos = optimizer.optimize(swarm,iters=100)

到目前为止,最低成本是从每一轮的所有粒子(系数集)中获得的。
结果
具有最低成本(跟踪误差)的粒子(系数组)将被用作系数,取系数之和作为权重,并在线性组合中用于重建索引。

NMF(跟踪误差:56 个基点,RMSE 价格:368.7,RMSE 回报率:0.006032)
NNLS(跟踪误差:43 个基点,RMSE 价格:27.37,RMSE 回报率:0.004587)
PSO 模型的跟踪误差最小。
结论
在训练期间,对前 10 种成分的价格和实际指数价格使用了以下定量方法:
- 非负最小二乘(NNLS)优化
- 相对偏相关
- 动态时间弯曲(DTW)优化
- 非负矩阵分解(NMF)
- 粒子群优化算法
然后,获得的权重用于分配投资组合,以模拟测试期间的指数价格和每日回报。然后通过跟踪误差和实际指数的 RMSE 价格/日收益率来衡量业绩。
在如此短的时间内,我从这个项目中学到了很多,它真的让我看到了定量方法在金融领域的更多应用。希望你喜欢阅读这篇文章,就像我喜欢创作它一样。
Numpy 中 1D、2D 和 3D 阵列的索引和切片
本文展示了 Numpy 数组从基本到高级的索引和切片。
来源:作者
数组索引和切片是数据分析和许多不同类型的数学运算的重要部分。我们并不总是使用整个数组、矩阵或数据帧。当我们处理数组的子集时,数组索引和切片是最重要的。本文将从基础知识开始,最终将解释 1D、2D 和 3D 阵列的切片和索引的一些先进技术。即使您以前已经使用过数组切片和索引,您也可以在本文中找到一些可以学习的东西。
1D 阵列切片标引
在笔记本中导入 Numpy,并生成一维数组。在这里,我使用的是 Jupyter 笔记本。您可以使用您选择的任何其他笔记本电脑。
import numpy as npx = np.array([2,5,1,9,0,3,8,11,-4,-3,-8,6,10])
基础标引
让我们做一些简单的切片。提醒一下,数组是零索引的,所以计数从零开始。x[0]将返回数组的第一个元素,x[1]将返回数组的第二个元素。
x[0]#output: 2x[3]#output: 9x[4]#output: 0
基础切片
现在转到一维数组的切片操作,
x[1:7]#output: array([5, 1, 9, 0, 3, 8])
这里 1 是下限,7 是上限。输出数组从索引 1 的元素开始,到索引 7 之前结束。换句话说,它包括索引 1 中的元素,但不包括索引 7 中的元素。
间隔切片
x[2::3]#output: array([ 1, 3, -4, 6])
在这种情况下,2 是起始索引,3 是间隔。所以返回的数组从索引二处的元素开始。之后,它会占据数组的每三个元素,直到结束。
说吧,我们不需要等到最后。我们只想输出到-4。在这种情况下,我们可以进一步对其进行切片。
x[2::3][0:3]
#output: array([ 1, 3, -4])
默认开始和结束
接下来,我将展示一个最常用的语法。x[0:4]用于返回前四个元素,对吗?相反,x[:4]可以用来做同样的事情。因为如果我们不定义任何下限,默认情况下它会从头开始。同样,如果我们不提到任何上限,它会一直输出到最后。当我们没有提到上限和下限时,我们得到整个数组作为输出。
x[:4]#output: array([2, 5, 1, 9])x[3:]#output: array([ 9, 0, 3, 8, 11, -4, -3, -8, 6, 10])x[:]
#output: array([2,5,1,9,0,3,8,11,-4,-3,-8,6,10])
带区间及上下限值切片
x[1:7:2]#output: array([5, 9, 3])
在 x[1:7:2]中,1 是下限,7 是上限,间隔中为 2。输出从索引 1 处的元素开始,到索引 7 处结束,但不是输出中间的每个元素,而是每隔一个元素输出一次。因为间隔是 2。
从有间隔的结束开始
x[-7::2]#output: array([ 8, -4, -8, 10])
这里,-7 表示从末尾开始的第七个元素,2 表示间隔。输出从底部的第七个元素开始,向上移动直到结束。
x[-7::-2]#output: array([8, 0, 1, 2])
2D 阵列切片标引
现在我们将使用一个二维数组进行同样的练习。我为这个视频做了一个 6×7 的矩阵。因为它足够大,可以显示一些有意义的操作。
y = np.arange(42).reshape(6,7)#array y comes out to be:
array([[ 0, 1, 2, 3, 4, 5, 6],
[ 7, 8, 9, 10, 11, 12, 13],
[14, 15, 16, 17, 18, 19, 20],
[21, 22, 23, 24, 25, 26, 27],
[28, 29, 30, 31, 32, 33, 34],
[35, 36, 37, 38, 39, 40, 41]])
输出行
最简单的方法是从二维数组中返回行。只需通过行数进行索引。
y[0]
#output: array([0, 1, 2, 3, 4, 5, 6])y[3]
#output: array([ 7, 8, 9, 10, 11, 12, 13])
输出列
返回列可能有点棘手。
y[:, 0]
#output: array([ 0, 7, 14, 21, 28, 35])y[:, 3]
#output: array([ 3, 10, 17, 24, 31, 38])
只输出一个元素
让我们看看如何从矩阵中返回一个数字。从这个矩阵中返回数字 17。从查找行开始。这是在第三行,这意味着该行的索引是 2,因为计数从 0 开始。接下来看看列索引。17 号在第四列。所以,列索引是 3。
y[2, 3]
#output: 17
返回第二列的前三个元素,作为图中的粗体数字

所有元素都在第 1、2 和 3 行。行索引是 0:3。下一步是计算列索引。所有三个元素都在第二列。也就是列索引 1。
y[0:3, 1]
#output: array([ 1, 8, 15])
将下面矩阵中前两列的部分元素输出为下面的粗体数字

所有元素都在第 1、2 和 3 行。行索引是 1:4。相应的列索引是 0 和 1。因此,列索引可以表示为 0:2
y[1:4, 0:2]#output:
array([[ 7, 8],
[14, 15],
[21, 22]])
从矩阵中输出这个三乘三子阵列(矩阵中的红色粗体元素)

解决这个问题的方法和之前的理论是一样的。数字的行索引是 2、3 和 4。所以我们可以把它切成 2:5。列索引也是 2、3 和 4。一片列也可以被 2:5 所占据。
y[2:5, 2:5]#output
array([[16, 17, 18],
[23, 24, 25],
[30, 31, 32]])
从第一行开始每隔一行打印一次

y[0::2]#output:
array([[ 0, 1, 2, 3, 4, 5, 6],
[14, 15, 16, 17, 18, 19, 20],
[28, 29, 30, 31, 32, 33, 34]])
这里,0 是下限,2 是区间。输出数组将从索引 0 开始,以 2 为间隔一直持续到结尾。
从第一列开始每隔一列打印。
在下面的代码中,':'意味着选择所有的索引。这里':'是选择所有的行。作为列输入,我们把 0::2。我已经在上面提到了它的功能。
y[:, 0::2]#output:
array([[ 0, 2, 4, 6],
[ 7, 9, 11, 13],
[14, 16, 18, 20],
[21, 23, 25, 27],
[28, 30, 32, 34],
[35, 37, 39, 41]])
这是做同样事情的另一种方法。在下面的代码中,0 是下限,7 是上限,2 是区间。下面的代码片段将输出与上面相同的矩阵。
y[:, 0:7:2]
3D 数组切片和索引
用下面这段代码做一个三维数组。在这里,它将从 0 到 44 的数字排列成三个形状为 3×5 的二维数组。输出将如下所示。
x = np.arange(45).reshape(3,3,5)#output:
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]],[[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]],[[30, 31, 32, 33, 34],
[35, 36, 37, 38, 39],
[40, 41, 42, 43, 44]]])
选择二维数组
我们可以通过简单的索引来访问其中的每个二维数组,如下所示:
x[0]#output:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])x[1]#output:
array([[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]])
打印第一个二维数组的第二行
选择第一个二维数组,就像我们之前用代码 x[0]展示的那样。然后加上这个来选择第二行:x[0][1]
x[0][1]#output:
array([5, 6, 7, 8, 9])
从数组中获取 22 号元素

我将分几步解决这个问题。
选择元素 22 所在的二维数组。这是第二个二维数组。所以用 x[1]来选择。
接下来,看看行索引在哪里。我们的目标元素位于所选二维数组的第二行。行索引为 1。我们可以选择代码为 x[1][1]的行。
最后,列索引是 2,因为从上图可以看出它是第三个元素。组合:
x[1][1][2]#output: 22
返回最后两个二维数组的第一行

首先,选择这些行所属的二维数组。一行在第二个二维数组中,另一行在第三个二维数组中。我们可以用 x[1:]选择这两个。因为这两行都是其对应的二维数组的第一行,所以行索引为零。
x[1:, 0]#output:
array([[15, 16, 17, 18, 19],
[30, 31, 32, 33, 34]])
切割列和行,打印最后两个二维数组的前两行的一部分,如图中红色粗体的数字

和前面的问题一样,所有的目标元素都在第二个和第三个二维数组中。所以,我们可以像以前一样用 x[1:]选择它们。所有元素都在两个二维数组的第一行和第二行。行索引应该表示为 0:2。列索引是 1:4,因为元素在第一、第二和第三列中。将所有这些结合在一起:
x[1:, 0:2, 1:4]#output:
array([[[16, 17, 18],
[21, 22, 23]],[[31, 32, 33],
[36, 37, 38]]])
我想制作一个视频,记录 1D、2D 和 3D 数组的切片和索引,使矩阵或多维数组索引更容易。我希望这有所帮助。
一些推荐的阅读材料:
使用 skiprows、skipfooter、使用 cols、index_col 和 header 选项将 CSV 文件导入为 Pandas data frame
使用 Python 对熊猫数据帧进行索引
索引用于使用“loc”和“iloc”功能访问数据帧中的值

在 Numpy 数组中,我们熟悉索引、切片和屏蔽等概念。类似地,Pandas 也支持数据帧中的索引。如果我们熟悉 Numpy 数组中的索引,那么 Pandas 中的索引将非常容易。
Python 中什么是索引?
从数据帧的特定行和列中选择值称为索引。通过使用索引,我们可以选择所有行和一些列或一些行和所有列。
为了更好地理解索引,让我们创建一个序列形式的样本数据。
输出序列看起来像这样,
1 a
3 b
5 c
dtype: object
现在,Python 提供了两种类型的索引
ExplicitImplicit
显式索引:
对于上面的数据集,如果我们将命令作为,
ds[1]它使用明确的指数
# If we pass the above command ds[1], the output will be'a'
这是显式索引。然而,如果我们传递命令ds[1:3],它将使用隐式索引样式,
命令ds[1:3]的输出将是,
3 b
5 c
dtype: object
这些切片和索引会导致某种混乱。为了避免这种情况,Python 提供了一些特殊的indexer属性:
- 通信线路(LinesofCommunication)
属性允许总是引用显式索引的索引和切片
- iloc
属性允许总是引用隐式索引样式的索引和切片
Python 代码中每个人都遵循和实践的一个常见表达是“显式比隐式好”
让我们以一个样本数据集为例,看看如何以不同的格式执行索引。
我们用的是来自 kaggle 的 NBA 球员数据。
数据集看起来像这样,

NBA 球员样本数据集
单柱的
为了显示数据帧中的单个列,我们将在 print 语句中提到列名。
输出将如下所示,

数据集中的单列
多列
我们来试着展示一下球员的‘年龄’、‘学院’、‘选秀年份’。我们可以用下面的方式显示多列,
多列将显示如下:

多列
。锁定方法
使用.loc方法进行索引。如果我们使用.loc方法,我们必须使用数据的标签名称来传递数据。
单行
为了显示数据帧中的一行,我们将在.loc方法中提到该行的索引名。
整行信息将显示如下:

单行信息
多行
与单行相同,在打印命令中传递行信息以显示信息。
输出将是,

多行
选择行和列
我们还可以使用.loc方法一次选择多行和多列。
输出将是这样的,

显示行和列
所有行和一些列
使用.loc方法显示所有包含一些列的行。
上面代码的输出将是这样的,

同样的输出可以通过简单地给出列名来实现,而不需要使用选择多个列中所示的** **.loc** 方法。**
输出将与上面的输出相同,

相同的输出没有。通信线路(LinesofCommunication)
。iloc 方法
使用.iloc方法步进。如果我们使用.iloc方法,我们必须使用其位置来传递数据。它非常类似于.loc方法,唯一的区别是.iloc使用整数来提取信息。
单行
我们必须在.iloc方法中传递一个整数来获取行信息。
输出将是,

单行使用。iloc 方法
多行
要选择多行,我们必须传递所选行的位置。
输出看起来像这样,

选择行和列
为了显示特定数量的行和列,我们为行创建一个整数列表,为列创建一个整数列表,并传递给iloc函数。
输出将是,

行和列 iloc 方法
所有行和一些列
为了显示所有的行,我们必须传递 ":" 和用于列的整数。
输出看起来会像这样,

所有行和部分列 iloc
如果数据集中的列是“int”或“float”类型,那么我们可以将所有的数字操作直接应用于该列,并根据我们的要求操作数据。
使用.loc方法的数值运算
输出将是这样的,

使用 loc 函数的数值运算
使用.iloc方法的数值运算
使用.loc方法,输出将与前一个相同

结论
我们可以用三句简单的话来总结这篇文章。
- 为了避免混淆显式索引和隐式索引,我们使用了
.loc和.iloc方法。 .loc方法用于基于标签的索引。.iloc方法用于基于位置的索引。
这是我们在 Python 中使用熊猫数据帧的索引方法时需要注意的三个主要语句。
感谢您阅读和快乐编码!!!
在这里查看我以前关于 Python 的文章
- Seaborn: Python
- 熊猫:蟒蛇
- Matplotlib:Python
- NumPy: Python
- 数据可视化及其重要性:Python
- Python 中的时间复杂度及其重要性
- Python 中的递归或递归函数
参考
- 数据索引与选择:https://jakevdp . github . io/python datascience handbook/03.02-Data-Indexing-and-Selection . html
- 用 Python 对数据帧进行索引、切片和子集化:https://data 木工. org/Python-ecology-lesson/03-index-slice-subset/index . html
- loc 和 iloc:https://camp . data camp . com/courses/intermediate-python/dictionary-pandas?ex=17
- 使用 iloc,loc,& ix 选择熊猫数据帧中的行和列:https://www . shanelynn . ie/select-Pandas-data frame-rows-and-columns-Using-iloc-loc-and-IX/
索引非常大的表

照片由 Pierre Bamin 在 Unsplash 上拍摄
数据工程
关于索引大型表的最佳实践以及如何使用分区来减轻索引负载的简短指南
本文最后一次更新于 2021 年 8 月 5 日。感谢约翰·特罗洛普指出一些令人尴尬的错别字。
低查询是任何数据或软件团队的主要问题之一。通常,要加快查询速度,第一反应就是创建所有能想到的索引。虽然索引被认为可以使查询更快,但是它们不能免除你在编写查询时犯下的错误。此外,创建索引是有代价的,如果没有考虑到这一点,可能会降低数据库各方面的性能,而不仅仅是读取数据。
大型表更容易出现查询速度慢的问题。我们可以在两种不同的设置中看到慢速查询——一种不是时间关键的,另一种是时间关键的。让我们先讨论一下什么是慢速查询对于关键的查询。如果您正在开发一个应用程序,一个好的经验法则是以这样一种方式编写您经常运行的查询,它们在 500 ms 内返回一个响应。报告和 BI 工具可能很棘手。有人曾经告诉我,运行一个 BI 控制面板需要一天的时间,他们对此并不感到困扰。
在大量使用大型表(> 10 亿条记录)之后,我意识到我们可以在对它们进行索引的同时处理一些事情。
1.修改索引;不要创建新的
在大表上创建和维护索引比在小表上成本更高。每当创建索引时,都会在磁盘上创建索引列+主键的副本,并且尽可能将索引保存在内存中。如果一个索引包含了查询所需的所有数据,它就永远不会进入实际的表。例如,如果您在customer_id 上过滤了数据并按year分组,并且索引在(customer_id, year)上,并且您没有在SELECT语句中查询任何其他内容,那么查询将不会到磁盘表中提取记录,因为索引满足查询的所有数据要求。
您应该努力为所有查询建立最佳索引,也就是说,索引应该覆盖大多数(如果不是全部)在过滤、分组、排序、选择等操作中应该使用索引的列。这些指数被称为覆盖指数。它们涵盖了您的查询要求。
更多的索引意味着更慢的插入;更多的索引意味着更多的磁盘和内存空间被占用。
索引设计很复杂。如果您的系统有各种各样的查询,单个甚至几个索引可能无法满足所有这些查询的要求。那很危险!如前所述,第一反应是创建一个适合您的查询的索引,而不是使用索引。
索引的开销很大。每次添加索引时,它在索引表上的写入速度都会变慢,因为每次有记录进来时,它必须平衡更多的 B 树结构。当 B 树写操作不是连续的时,成本肯定会更高,这就是为什么,通常情况下,最好选择一个现有的索引,并通过添加另一列或更改列顺序或两者兼而有之来修改它。
通过修改现有的索引来减少内存占用,而不是盲目地添加更多的索引。
要做到这一点,您必须对您的查询有深入的了解。最好有一个目录,告诉您哪个查询需要哪个索引,这样您对索引所做的修改就不会对其余的查询产生意外的影响。
MySQL 支持索引操作的在线更改——因此,如果您创建或删除一个索引,在索引创建过程中对表的读写不会受到影响。文档上是这么说的,但是我发现了一些问题。为了提高索引操作的性能,请使用 Percona 的 pt-online-schema-change 工具。它已经试过&测试过了。
2.一起使用索引和分区
平衡较大的 B 树比平衡较小的 B 树消耗更多的资源。分区将您的表分割成更小的子表,但是您无法了解这一点,除非您进入磁盘,看到为您的表创建了不同的表文件,而不是一个表文件。这同样适用于该表上的索引。
索引和分区的主要动机是相同的——为查询丢弃数据。除了使用分区修剪丢弃数据之外,分区还有我刚才提到的积极的副作用——它让我们可以平衡更小的树,重新计算更小的索引。
另一个经验法则是对非常大的表使用分区,例如至少有 1 亿行的表。一旦分区完成,对分区表的所有查询都必须在WHERE子句中包含partition_key,否则,这将是一次全表扫描——相当于对整个表的线性搜索。
分区产生更小的 B 树/索引,因此在插入时重新计算这些索引的工作量更少。
为了使索引工作,您应该有一个所有查询都可以使用的合适字段。您可以对数据使用许多不同类型的分区。点击了解更多信息。
3.不惜一切代价避免磁盘操作
虽然这应该通过创建覆盖索引来覆盖,但我认为它值得单独提及,因为索引只能帮助您隐藏糟糕的查询编写。磁盘操作成本很高。我一直用 Jim Gray 的类比来演示磁盘 I/O,因为在当前环境下理解这一点很重要。

吉姆·格雷著名的存储延迟类比
不使用索引的排序操作在磁盘上执行。磁盘很慢。为了避免磁盘操作,请确保在查询的EXPLAIN PLAN中寻找提示和信息。当你看到filesort的时候,要明白它会试图把整个表分块放入内存中。如果表太大,内存容纳不下,它将在磁盘上创建一个临时表,并在那里执行。留意有或没有组合using temporary的using filesort。每当 MySQL 无法使用索引执行排序时,using filesort就会出现在计划中。
要深入理解这一点,请仔细阅读 MySQL 优化人员的旧帖子。帖子虽然旧了,但是我觉得还是有相关性的,对这部分改动不多。
[## Sergey Petrunia 的博客“MySQL 如何执行 ORDER BY
在过去的几个星期里,出现了大量与订单/分组相关的优化错误,我是这些错误的修复者
s.petrunia.net](http://s.petrunia.net/blog/?p=24)
在排序时,有几件事你应该注意——记住你不能跳过索引中的列。您不能编写一个按x, z排序的查询,并期望它将索引完全用于一个索引。如果在第一列上有一个range过滤器或一个IN子句,那么索引也将不起作用。当两列(x, y)在查询中以不同的顺序排序时,例如ORDER BY x ASC, y DESC,它也不起作用。如果您没有注意到这几点,索引将不会执行查询。
这一点的本质是要让大家明白,也要确保使用索引进行排序,否则,这将是一个非常昂贵的操作。
处理数据库中的大型表很有趣。那是你真正理解数据库系统的复杂性,它的优点和缺点的时候。我建议您创建一个测试数据库,生成测试数据来填充一个大表,并运行查询来了解它是如何工作的。实践胜过理论。
感谢 Kai Sassnowski 的这次演讲,它验证并巩固了我多年来对 MySQL 索引的学习。
Kai Sassnowski 在 Laracon EU 上关于数据库索引的演讲
YOLOv5 如何解决 YOLOv3 遇到的歧义
现实世界中的数据科学
使用 YOLOv5 实现稳健的印度车牌检测

我对一般交通数据的结果
对那些可能不知道的人来说,一个新版本的 YOLO(你只看一次)在这里,即 YOLO v5。非常感谢 Ultralytics 将这个库放在一起。

来源:‘【https://github.com/ultralytics/yolov5】T4
YOLOv3 的问题是
你只看一次(YOLO)是一个最先进的,实时对象检测系统。在 Pascal Titan X 上,它以 30 FPS 的速度处理图像,在 COCO test-dev 上有 57.9%的 mAP。
YOLOv3 速度极快,精度极高。在 mAP 中,测得 5 IOU YOLOv3 与焦点损耗相当,但速度快 4 倍左右。此外,你可以简单地通过改变模型的大小在速度和准确性之间进行权衡,不需要重新训练!
YOLOv3 有一个问题,尽管如此精确,但它是有偏见的。偏向于图像中对象的大小。如果在训练时遇到较大的物体,它不能完美地检测到较小尺度的相同物体。

由于该模型是为较大的车牌训练的,所以它不能在这个非常小的图像中正确地检测到小的车牌
YOLOv3 检测图像中的特征,并学习如何利用这些信息识别物体。靠近起点的层检测非常简单的特征,如边缘,而更深的层可以检测更复杂的特征,如眼睛、鼻子或整张脸。然后,它使用所有这些它已经学会的特征,做出最终的预测。这就是该系统的缺陷所在——没有在 CNN 中任何地方使用的空间,并且用于连接层的汇集功能效率低下。
YOLOv5
YOLOv5 由三部分组成:
- 模型主干
- 模型头
- 模特脖子
模型头部有助于特征提取过程。模型主干由 CSP 网络组成,有助于从通过模型头部的张量中提取基本特征。CSPNets 也支持更快的推理。来自模型主干的张量通过具有特征金字塔的模型颈部,该特征金字塔试图消除相对于对象大小的偏差。
要了解有关要素金字塔的更多信息,请查看
[## 用于目标检测的特征金字塔网络
特征金字塔是识别系统中的基本组件,用于检测不同尺度的对象。但是最近…
arxiv.org](https://arxiv.org/abs/1612.03144)
要了解更多关于 YOLOv5 的信息,请查看这个。
CDT 月 12 日上午 8:08 更新:为了回应社区反馈,我们写了一篇更详细的帖子,比较…
blog.roboflow.ai](https://blog.roboflow.ai/yolov5-is-here/)
查看 YOLO 版本 5 库,网址为
这个资源库代表了 Ultralytics 对未来对象检测方法的开源研究,并结合了我们的…
github.com](https://github.com/ultralytics/yolov5)
对于我们的用例,我在
这个项目是一个后续项目,参考我们的数据准备在这个链接的培训,参考这个链接给…
github.com](https://github.com/sid0312/anpr_yolov5)
克隆存储库
git clone [https://github.com/sid0312/anpr_yolov5](https://github.com/sid0312/anpr_yolov5)
cd anpr_yolov5
检测车牌
要检测汽车图像中的车牌,请将其保存在目录的 sample_cars 文件夹中。把它命名为 example.jpg
python detect.py --source sample_cars/example.jpg --weights weights/best.pt --conf 0.4
结果
获取推理/输出目录中的最终图像。要获得检测过程的直觉,请查看以下笔记本
以下是一些结果

验证图像的批量预测
我们注意到 YOLOv5 正确地检测到了车牌,而 YOLOv3 根本没有检测到车牌


对测试样本图像的预测

测试样本图像预测
我是怎么做到的?
该存储库包括对原始 utlralytics 存储库的以下更改
已创建数据/license_plate.yaml
数据准备
- 步骤 1-从以下网址下载 JSON 格式的初学者数据集
标记在车辆牌照上的包围盒
www.kaggle.com](https://www.kaggle.com/dataturks/vehicle-number-plate-detection)
这是我们的起始数据集。将 JSON 文件上传到您的 Google Drive
- 步骤 2——将 JSON starter 数据集转换成 YOLO 格式
以下存储库是使用 YOLO v3 Darknet 和 Pytesseract 对印度车牌进行的端到端检测和识别。它是我们项目的先驱。这是一个有趣的个人项目本身!
- 创建文件夹结构

存储库的数据文件夹
- 在数据/图像文件夹中,创建两个文件夹,即 train 和 valid
- 训练文件夹由从步骤 2 获得的 201 个图像组成。这些是用来训练的
- 有效文件夹由步骤 2 中获得的 36 幅图像组成,用于验证

我的数据/图像/训练文件夹的内容

我的数据/图像/训练/有效文件夹的内容
只有图像不能用于检测,因为我们需要边界框的标签和每个图像的类。
单个类边界框标注的 YOLO 格式如下:
class_number x y width height
标签已经从步骤 2 中获得。
标签文件夹由训练和有效文件夹组成,分别由训练和验证图像的标签组成。

训练图像的标签
标签样本


验证图像的标签
接下来,我们创建 data/train.txt 文件
要获取该文件的内容,只需在命令提示符或终端中编写以下内容。确保您位于 anpr_yolov5 目录中
D:>git clone [https://github.com/sid0312/anpr_yolov5](https://github.com/sid0312/anpr_yolov5)
cd anpr_yolov5
python
>>import os
>>for image in os.list('data/images/train'):
path = 'D:/anpr_yolov5/data/images/train'
print(path+'/'+image)
您将获得以下输出

将输出复制到文件 data/train.txt 中
对 valid.txt 进行同样的操作
如果您打算在 Google Colab 上训练 Yolo v5,提交当前状态的存储库,不要复制上面的内容。提交您的存储库的当前状态并将其推送到 GitHub。
git add .
git commit -m"some msg"
git push
现在按照下面的笔记本,将打印日志的内容分别复制到 data/train.txt 和 data/val.txt 文件中
- 将 yolov5s.yaml 中的 nc 参数改为 1
- 再次重复 git 添加、提交、推送过程
- 查看以下笔记本了解培训流程
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/sid0312/anpr_yolov5/blob/master/yolov5_license_plate_train.ipynb)
注意:也可以使用 yolo5s.pt 砝码。我使用了随机初始化的权重,并对模型进行了 100 个时期的训练。
我的一些训练日志如下

我们用 mAP@0.5 实现了令人敬畏的性能,达到 0.978 或 97.8%,相当令人敬畏!

运行 100 个纪元后,我们得到
精度为 0.659
召回为 0.972
将@0.5 映射为 0.978
以 95%的置信度将@0.5 映射为 0.471
使用的资源
相关存储库
如果你跳过了培训部分,直接跳到了结论,我有更多的东西给你。找到车牌的感兴趣区域后,我们可以使用 pytesseract 将其用于字符识别
我以前为一个项目做过。您可以查看:
这将作为我们的初始数据集 git 克隆 https://github.com/pjreddie/darknet CD 暗网我们添加我们的处理…
github.com](https://github.com/sid0312/ANPR)
作者推荐的博客
如果你想了解更多关于物体检测算法和库的知识,我强烈推荐这个由 neptune.ai 撰写的博客
对象检测在图像中找到并识别事物,这是深度学习的最大成就之一…
海王星. ai](https://neptune.ai/blog/object-detection-algorithms-and-libraries)
作者说明
如果你喜欢我的文章,看看这些!
[## 使用 Tensorflow.js 优化浏览器上的人脸检测
基于浏览器的人脸检测器正是你所需要的
towardsdatascience.com](/face-detection-on-the-browser-with-tensorflow-js-27846a5fe954) [## 基于 U-网的 OCT 图像分割
使用 OCT 报告诊断糖尿病性黄斑水肿的深度学习方法。使用 Apache Mxnet 和…
towardsdatascience.com](/segmentation-of-optical-coherence-tomography-images-with-diabetic-macular-edema-the-gluon-82093cfd8e24) [## 使用 GluonCV 和 MxNet 计算网络摄像头上的人数
介绍
towardsdatascience.com](/counting-people-on-your-webcam-using-gluoncv-and-mxnet-d1a9f05c427d)
如果你希望在 Linkedin 上与我联系,这是我的简介
[## Siddhant Baldota -圣地亚哥超级计算机中心研究实习生| LinkedIn
我是一名计算机科学硕士研究生,积极致力于深度学习和计算机的应用
www.linkedin.com](https://www.linkedin.com/in/siddhant-baldota-051059180/)
快乐的计算机视觉和快乐的深度学习❤.
利用和尚艾进行印度舞蹈形态分类
这是由 HackerEarth 组织的深度学习竞赛,我在 5800 多名参与者中排名低于 70,数据增强在其中发挥了重要作用。
介绍
有如此多的印度古典舞形式,从图像中提取和理解动态人体姿态是一项具有挑战性的计算机视觉任务。

数据集的图像
在这篇博文中,我将展示我用什么方法对图片进行分类,以及它把我带到了排行榜的哪个位置。
数据从黑客地球竞赛页面下载,数据集由 364 幅图像组成,分属于 8 类,即曼尼普尔、巴拉塔纳蒂扬、奥迪西、卡塔卡里、卡萨克、萨特里亚、库奇普迪、和莫希尼亚特坦,每类约有 45 幅图像。
安装和下载数据
让我们从设置 Monk 及其依赖项开始:
!git clone [https://github.com/Tessellate-Imaging/monk_v1.git](https://github.com/Tessellate-Imaging/monk_v1.git)
!cd monk_v1/installation/Misc && pip install -r requirements_kaggle.txt
因为我在 Kaggle 上运行这个笔记本,所以我使用了边栏中的“+ Add data”选项并上传了数据。数据将在中提供../输入。
创造一个实验
我已经创建了一个实验,对于这个任务,我使用了 mxnet 胶子后端。
import os
import sys
sys.path.append("/kaggle/working/monk_v1/monk/");
from gluon_prototype import prototype
gtf = prototype(verbose=1);
gtf.Prototype("Dance_Form", "Using-resnet152_v1");
第一种方法
模型选择和培训
在第一种方法中,我使用不同的模型进行训练, resnet152_v1 给出了很好的结果,因此使用该模型进行训练。
gtf.Default(dataset_path="../input/final3/folder/",
model_name="resnet152_v1",
freeze_base_network=False,
num_epochs=10);gtf.Train();
经过 10 个历元的训练,我得到了 80%的验证准确率。
预言;预测;预告
通过这个模型,我预测了测试数据集中的类。
list_test=os.listdir("../input/data-test/test/");
from tqdm.notebook import tqdm
combined = [];
for i in tqdm(range(len(list_test))):
img_name = "../input/data-test/test/" + list_test[i];
predictions = gtf.Infer(img_name=img_name);
id_ = list_test[i]
label = predictions["predicted_class"];
combined.append([id_, label]);a = pd.DataFrame(combined, columns = ['Image', 'target']);
a.to_csv("submission.csv", index=False);
提交 submission.csv 文件后,我在排行榜上的排名低于 250,而在比赛中,大约有 5800+参与者。
直到现在,我还没有使用任何数据增强技术,结果也不错。
现在,在我的第二种方法中,让我们看看数据扩充对结果的影响。
第二种方法
数据扩充:- 数据扩充是增加数据数量和多样性的过程。我们不是在收集新数据,而是在转换已经存在的数据。深度学习神经网络的效率也随着可用数据量的增加而增加。
由于可用的数据非常少,所以我使用了数据扩充技术来转换数据。
对于数据扩充,我使用了 imgaug 库。
from imgaug import augmenters as iaa
import imgaug as ia
import imageioseq=iaa.Sequential([
iaa.Scale((224, 224)),
iaa.Sometimes(0.25, iaa.GaussianBlur(sigma=(0, 3.0))),
iaa.Fliplr(0.5),
iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)),
iaa.Affine(rotate=(-20, 20), mode='symmetric'),
iaa.Sometimes(0.25,
iaa.OneOf([iaa.Dropout(p=(0, 0.1)),
iaa.CoarseDropout(0.1, size_percent=0.5)])),
iaa.AddToHueAndSaturation(value=(-10, 10), per_channel=True)
])
这是数据集中图像数量的两倍。数据增广后,我用同样的 resnet152_v1 模型进行训练。
gtf.Default(dataset_path="../input/final3/folder/",
model_name="resnet152_v1",
freeze_base_network=False,
num_epochs=10);gtf.Train();
经过 10 个历元的训练,我得到了 94%的验证准确率。
使用这个模型,我预测了测试数据集中的类,并提交了 submission.csv 文件。这次我的排名在 70 以下,比上次好很多。
结论
因此,从这场比赛中,我们可以看到数据增强如何有助于提高模型的性能。
本文中的所有代码都位于这个 Github 链接上:
https://github . com/Shu bham 7169/MonkAI/blob/master/Dance _ Form _ class ification . ipynb
归纳学习与传导学习
浅谈归纳式和直推式学习方法
归纳和转导……在阅读机器学习的书籍和文章时,你可能会多次碰到这两个词。在本文中,让我们试着理解这两种学习方法的区别,以及如何根据我们的用例来使用它们。

图片由 Gerd Altmann 从 Pixabay 拍摄
理解定义
根据维基百科,
转导是从观察到的特定(训练)案例到特定(测试)案例的推理。相反,归纳是从观察到的训练案例中推理出通用规则,然后应用到测试案例中。
我们来分解理解一下这两个定义。
感应
归纳是从观察到的训练案例中推理出通用规则,然后应用到测试案例中。
归纳学习与我们俗称的 传统监督学习 相同。我们基于我们已经拥有的带标签的训练数据集来建立和训练机器学习模型。然后,我们使用这个训练好的模型来预测我们以前从未遇到过的测试数据集的标签。
转换
转导是从观察到的特定(训练)案例到特定(测试)案例的推理。
与归纳学习相反,直推学习技术预先观察所有数据,包括训练和测试数据集。我们从已经观察到的训练数据集学习,然后预测测试数据集的标签。即使我们不知道测试数据集的标签,我们也可以在学习过程中利用这些数据中存在的模式和附加信息。
示例直推式学习方法包括【TSVM】和 基于图的标签传播算法(LPA) 。
有什么区别?
既然你对归纳学习和直推学习的定义有了清晰的概念,让我们来看看它们有什么不同。这些定义基本上说明了它们的区别,但是让我们来看一下,这样会更清楚。
主要区别在于,在直推式学习过程中,当训练模型时,您已经遇到了训练和测试数据集。然而,归纳学习在训练模型时只遇到训练数据,并将学习到的模型应用于它从未见过的数据集。
转导不建立预测模型。如果一个新的数据点被添加到测试数据集中,那么我们将不得不从头重新运行该算法,训练该模型,然后使用它来预测标签。另一方面,归纳学习建立了一个预测模型。当遇到新的数据点时,没有必要从头重新运行算法。
更简单地说,归纳学习试图建立一个通用模型,根据一组观察到的训练数据点,预测任何新的数据点。这里你可以预测点空间中的任何一点,除了未标记的点。相反,直推式学习建立了一个模型,该模型符合它已经观察到的训练和测试数据点。这种方法使用标记点的知识和附加信息来预测未标记点的标记。
在通过输入流引入新数据点的情况下,直推式学习可能变得代价高昂。每次新的数据点到达时,您都必须重新运行一切。另一方面,归纳学习最初建立一个预测模型,新的数据点可以在很短的时间内用较少的计算来标记。

示例演练

图 1
首先,我将采用图 1 所示的例子。假设您有一组点,如图 1 所示。有四个标记点 A、B、C 和 d。我们的目标是标记(着色)从 1 到 14 的剩余未标记(未着色)点。如果我们对这个任务使用归纳学习,我们将不得不使用这 4 个标记点,并建立一个监督学习模型。

图 2
一眼看去,我们可以看到有两个独立的集群。然而,在归纳学习中,由于我们的训练样本数量非常少,因此很难建立一个捕捉数据完整结构的预测模型。例如,如果使用 最近邻 方法,则更靠近边界的点(例如 12 和 14)可以被着色为红色而不是绿色,因为它们更靠近红色点 A 和 B 而不是绿色点 C 和 D(如图 2 所示)。

图 3
如果我们有一些关于数据点的附加信息,例如基于相似性等特征的点之间的连通性信息(如图 3 所示),我们可以在训练模型和标记未标记点时使用这些附加信息。

图 4
例如,我们可以使用直推式学习方法,如基于半监督图的 标签传播算法 来标记未标记的点,如图 4 所示,使用所有已标记和未标记点的结构信息。沿着边界的点,例如 12 和 14,连接到更多的绿色点而不是红色点,因此它们被标记为绿色,而不是红色。
注意,我们能够应用诸如标签传播的直推式学习方法,因为我们在开始时已经遇到了所有的训练和测试数据点,并且测试数据具有一些可能有用的附加信息。如果一开始没有测试数据点,我们将不得不遵循归纳学习方法。
最后的想法
我们已经讨论了归纳学习和直推学习的区别,并通过一个例子。现在你已经对归纳和直推学习方法及其差异有了基本的概念,你可以在开发下一个机器学习模型时利用这些知识。
有兴趣可以看看我之前写的关于标签传播的文章。
基于图的标签传播的简单介绍
towardsdatascience.com](/label-propagation-demystified-cd5390f27472)
感谢您的阅读!我也很想听听你的想法、想法和建议。
干杯!
参考
[1]转导(机器学习)维基百科—https://en . Wikipedia . org/wiki/Transduction _(machine _ learning)
[2]归纳学习和直推学习的区别是什么—https://www . quora . com/What-is-the-difference-and-transductive-learning
[3]直推式推理与半监督学习—https://pdfs . semantic scholar . org/5a8c/38 E6 aadc 29 FB 995 d5b 9562 df0c 4365156256 . pdf
将您的分析工业化到企业级别
[系列:赢在分析](http://towardsdatascience.com/tagged/Winning in Analytics)!
本文是“在分析中取胜”系列文章的第 1 部分。让我们来看看成功扩展您的人工智能计划的关键促成因素。

亲爱的人工智能爱好者,我们喜欢实现我们数据的全部潜力!我们希望看到我们的分析概念证明成为现实!但是,将你的概念证明工业化的道路往往是艰难的。
那么,我们如何才能将您的组织从概念的少量分析证明转变为工业化分析,以实现企业人工智能?下面列出了可以帮助您扩展分析产品的关键考虑事项。
1.为您的数据平台带来稳定性
你的模型和你的数据一样好!确保数据平台的高稳定性和可用性,以快速扩展您的分析模型。如果不这样做,可能会导致在及时向决策引擎提供数据方面出现不必要的延迟。
- 自动化您的数据管道,以处理重复性和/或易出错的数据工程任务。
- 为了提高代码的质量,考虑一个组织范围的测试策略。
- 采用持续集成和持续部署将有助于在稳定的基础上迭代构建。
2.提前考虑模型管理和监控
虽然模型开发消耗了大部分注意力,但构建的人工智能模型只有在部署到生产中时才有用。模型管理和监控填补了这一重要空白,使您的人工智能模型可以投入生产。
除了部署和管理之外,还会监控模型在生产中的性能。随着模型随着时间的推移而恶化,需要进行再训练。模型管理还有助于版本化系统。通过调整模型的不同部分,生成的预测的准确性会有所不同。因此,为了跟踪模型和它们的权衡,版本控制是必不可少的。
模型管理和监控实现必须尽早纳入人工智能计划,并且对于努力进行自主分析的企业来说是至关重要的。
3.确保分析试点以工业化的心态构建
与在较小规模上构建以展示分析解决方案的可行性和潜力的概念证明不同,试点计划面向目标受众有限的生产环境。
对于人工智能计划从试点到产业化的过渡,重要的是,试点的建立应高度关注性能的稳定性和建议的可靠性。稳定可靠的试点可以快速过渡到生产。
4.确保你有合适的团队来扩展人工智能
引入以分析为中心的角色,如首席数据分析官、企业人工智能架构师、模型管理工程师、数据科学家、公民数据科学家等,以提高您组织的分析智商。
开始提升您的劳动力的技能,以解释建议并最大限度地发挥人工智能机器的价值!
5.利用组织外部的专业知识
说到实施,自己动手(DIY)的方法既费时又费钱。致力于特定于分析的“制造或购买或合作”战略,以利用其他组织的人工智能能力的进步。
利用其他组织的现有能力,加快您的分析运营之路!
“在分析中取胜”系列源于学习,旨在通过提供分析计划的快速启动来让读者受益。我希望听到您的反馈,以及您的组织在分析道路上走了多远!
如需了解更多信息,您可以通过 LinkedIn 联系我
工业 4.0 还是互联网 4.0?
了解工业 4.0

纳蕾塔·马丁在 Unsplash 上的照片
在这篇博客中,我将发表我的观点,并写下与工业 4.0 革命的概念和进步相关的最新技术趋势,我们都在见证和经历这一革命,尽管我们中的一些人已经意识到这一点,而一些人却对此视而不见。现在,完全取决于你是否注意到它,看到它,了解它,体验它或者只是像鸽子一样闭上眼睛,相信工业 4.0 看不到你。

那么,什么是工业 4.0,我为什么要关心?
根据维基百科,“工业 4.0 是对制造技术中当前自动化和数据交换趋势的一个名称。它包括信息物理系统、物联网、云计算、、【1】、、、【2】、、【3】、、【4】、、认知计算。
然而,用外行人的话来说,我可以把它定义为,新的或当前的工业革命,它利用了物理、数字系统和现代技术的综合力量,以这种方式,机器将执行大部分(如果不是全部)工作。
物联网
它是事物的互联网络;这里的事物可以是任何东西,如“设备”、“建筑物”、“汽车”、“桌子”、“椅子”,以及“你现在正在想的”或“以后可能想的”。所有这些和其他任何东西都可以通过互联网连接起来。工业 4.0(德国人怎么叫)或互联网 4.0(美国人怎么叫)或第四次工业革命,都可以归结为人、系统、设备,当然还有物联网中的“物”的前所未有的合并或连接。
这产生了新的业务方式,从而创造了新的增长和收入机会,这些机会可以通过利用互联设备和海量数据来实现(对不起,我指的是“大”或“智能”数据;在他们之间提供和交换。你绝对错了;等一下…这是一种夸张的说法,但老实说,如果你认为人工智能、机器学习、深度学习、大数据、物联网及其家族成员只是时髦的词汇,那你就错了。不,他们不是,他们已经成为日常业务,并将继续流行,甚至很快接管(在良好的意义上,而不是电影中显示的那种)每个行业。
工业革命:

2020,Chan Naseeb。保留所有权利。
第一次工业革命开始于 18 世纪 80 年代,产生了利用水和蒸汽动力机械生产设施。
第二个时代,开始于 30 年后,它带来了:大规模生产的电力
第三次工业革命开始于 20 世纪 60 年代末,提供了电子和信息技术。
第四,为互联世界和设备铺平道路。这意味着物理系统将通过使用机器学习、人工智能等由自动化系统控制。。尽管有好消息也有坏消息,但人类干预将保持在最低限度。好消息是我们将获得更好的表现,减少对人类的依赖,坏消息是,机器将接管许多(如果不是大部分的话)人类费力的工作。
虽然它的全面影响还有待观察,但我们可以看到它的潜力以及它迄今为止给我们带来了什么。

多梅尼科·洛亚在 Unsplash 上拍摄的照片
工业 4.0 中的一些流行词汇
- 物联网连接
- 机器学习
- 实时洞察
- 预测建模
- 流式分析等…
随着分析、物联网、数据科学和云计算的进步,更定制、更便宜、更可扩展的工厂解决方案成为可能,并且正在被发明。技术进步正在改变我们的日常生活和我们感知生活的方式。过去,经济只受几个因素的影响…但今天,它正受到技术突破和其他因素的影响,如商业发展、供应链和世界的全球连通性。如今,消费者行为比以往任何时候都更加重要。通过观察这些如今被称为预测智能的见解,企业可以规划他们的运营和供应链计划。
消费商品比任何人想象的都要容易。你可以足不出户,仅仅通过互联网就能买到任何东西。这意味着更多的竞争,以及对客户满意度和更好的消费者体验的更高要求。未能达到预期或迟到的企业将会被遗忘在尘埃中。你必须敏捷并适应不断变化的客户需求。如果你不能回答快速和频繁发生的动态,你最好选择一些其他业务是'没有业务'。作为一家企业,你必须积极主动,不断发展,否则就要做好被淘汰或至少被惩罚的准备。
工业 4.0 的主要构成要素如下图所示:

2020,Chan Naseeb。保留所有权利。
毫无疑问,工业 4.0 正在重新定义很多我们过去习以为常的事物、概念和想法。一些担忧包括与机器接管原本由人类承担的角色相关的风险。然而,它同时也是无可争议的事实和令人无比愉快的现象,为积极、迅速和巨大的变化提供了潜力。总之,我想让你放心,未来是关于协作智能的,而不仅仅是机器接管,正如我在早期的一篇关于增强人类智能的博客中所讨论的。
2020,Chan Naseeb。保留所有权利。
之前在 https://www.linkedin.com发布
工业 4.0:第四次工业革命现在
工业 4.0 正在彻底改变我们的生活、工作、与环境互动以及彼此互动的方式,为所有人创造一个更美好的世界

来源:Shutterstock
二十年前被认为是科幻小说的许多内容正在推动世界走向第四次工业革命。工业 4.0 将彻底改变商业格局,以及人类与环境和彼此之间的互动方式。
许多人预测它将开创一个慷慨的新时代:延长寿命,改善医疗保健,减少全球贫困,等等。其他人在革命期间用来推动变革的大量数据中看到了更黑暗的可能性。
无论如何,现实是,全球 GDP 预计将接近 90 万亿美元——比 20 年前的 1 万亿美元还要多。
正是这种快速的经济增长和技术创新将世界推向了第四次工业革命——工业 4.0。
工业 4.0 的技术
第四次工业革命的技术与训练人工智能和其他关键形式的现代技术所需的大量数据密不可分。对数据的需求导致数据收集呈指数级增长。
数据分析和商业智能已经需要对信息技术、数学和统计学的高度掌握。人工智能和机器学习算法有能力自动化和优化分析流程,这反过来又创造了变革性的商业洞察力。
在过去的两年里, 世界产生了 90%——每天 2.5 万亿字节——所有的数据。
这个数据和内容不一样。这是原始的、无组织的信息。
许多正在研究的尖端技术涉及设计人工智能系统,这些系统可以以有意义的方式筛选数据集,以便这些数据集可以被输入到神经网络中。
除了人工智能将继续在工业 4.0 中发挥核心作用,量子计算、3D 打印和物联网(IoT)都有望成为这一变化的基础。
2017 年欧洲专利局的一项研究发现,在过去三年中,与工业 4.0 相关的专利申请增加了 54%。
然而,标志着这场革命的不仅仅是这些技术进步。
世界经济论坛创始人兼执行主席克劳斯·施瓦布创造了“第四次工业革命”一词,他在 2016 年提出,这场革命“正在模糊物理、数字和生物领域之间的界限”。
这包括向智能设备的转移,从智能住宅到智能手表。这是物联网与人类物理生活的融合。
这次合并不仅仅是为了方便。它将彻底改变人们、企业和政府的运作方式。
“不是每个人都需要成为数据科学家,但每个人都需要有数据素养,”分析公司 Qlik、 的数据素养负责人乔丹·莫罗告诉美国消费者新闻与商业频道 。Morrow 继续指出,目前许多人和企业缺乏以有意义的方式分析和解释数据的必要技能。
第四次工业革命带来的社会变革
技术是一种工具。它不好也不坏。但是,它是为了什么目的而实施的,当然可以使它如此。
最经典的例子就是核技术,无论是核电站还是核弹,核技术都是基础。
第四次工业革命将把世界带向何方,将取决于推动变革者的目标。
施瓦布说:“从来没有一个时代有更大的希望,也没有一个时代有更大的潜在危险。”他预测,与革命相关的最大社会问题将是不平等。
推动积极变化
We Forum 发现,作为联合国 17 项全球目标基础的 169 项目标中,有 70%可以通过作为第四次工业革命一部分的现有技术来实现。****
按照这些思路,一家盈利性社会企业 Cangler 表示 其使命是解决 三个联合国可持续发展目标:一个没有贫困的世界,增加良好的健康和福祉,以及创建可持续发展的城市和社区。

来源:联合国可持续发展目标
在一个数据盲阻碍许多组织在世界上做好事的时代,Cangler 提供了企业数据分析的自动化和民主化。
“我相信面对新技术,人类将能够利用它们来造福我们。大多数人渴望美好的生活,而不是悲惨的生活,”华为首席执行官任郑飞在聚焦第四次工业革命的达沃斯科技会议 期间说道。
一般来说,与革命相关的一些预期社会趋势将是中产阶级的崛起、反向人才流失、清真经济和妇女赋权。
“零创新”的意图也会越来越强烈。这是产品开发和技术的重点,对世界产生“零”负面影响。这可能涉及从零排放和零事故的汽车到碳中和城市的一切。哥本哈根已经表示,它正在努力成为世界上第一个碳中和首都。
智能产品将无处不在,从智能服装、手表和手机,到智能建筑和智能城市。一个有望极大改善人们生活的智能产品将是智能城市:到 2025 年,这个行业的价值预计将达到 2.57 万亿美元。
这些 智慧城市 依靠物联网来收集数据,这些数据可用于提供更好地管理资产、资源和服务的见解。这些包括从垃圾收集系统到城市规划的一切。
到 2050 年,预计世界三分之二的人口将居住在城市地区,智能城市将成为为人口分配必要资源的关键。“大区域”也将崛起,这将是投资的关键中心,导致企业“城市作为客户”战略的想法——而不是专注于目标国家。
ABI 研究公司的一份报告已经敦促在城市中更积极地部署 5G ,以开辟新的经济价值。
到 2028 年,该技术预计将产生 2.5 万亿美元的直接贡献,8660 亿美元的间接贡献,以及 3.2 万亿美元的生产率增长。
工业 4.0 的阴暗面
虽然郑飞在达沃斯科技会议上对第四次工业革命技术持乐观态度,但历史学家尤瓦尔·诺亚·哈拉里显然不这么认为。
哈拉里说:“从最浅显的层面来看,这可能是 19 世纪工业革命的重演,当时领导人有机会在经济和政治上主宰世界。”“我把当前的军备竞赛理解为帝国主义的军备竞赛……如果你掌握了一个国家的所有数据,你就不需要派遣士兵。”
社会运作越来越依赖技术,这使社会更容易受到网络攻击和各种其他网络威胁。
安全性 的 提升,尤其是与物联网相关的,对于第四次工业革命的蓬勃发展至关重要。这是因为这些网络威胁可以做任何事情,从危及物理安全到造成生产停机,从而导致重大经济损失。
然而,在社会方面,也许更大的威胁将以不平等加剧的形式出现。
施瓦布并不是唯一一个担心第四次工业革命可能导致世界不平等加剧的人。
共同基金 的一份 报告指出:“由于在接入互联网、获得资金和技术能力方面的起点不同,第四次工业革命的技术采用不平等,可能会导致经济增长进一步不平衡。”。
随着自动化和人工智能继续取代越来越多的工作场所人员,这种不平等还可能产生雪球效应。
这些变化将与以往的工业革命有何不同?
无论这些变化是为了人类和地球的更好,还是为了双方都付出巨大代价,工业 4.0 都不像它的前辈。
Schwab 认为,变化的指数速度和新技术的引进速度将对社会产生前所未有的影响。
可以这样想:1 亿人 用了 75 年才开始使用电话。游戏 Pokemon Go 在一个月内就有这么多用户。
新技术的采用比人类历史上任何时候都要快。
最后的想法:工业 4.0——第四次工业革命就在眼前
随着世界进一步进入第四次工业革命,数据无处不在。无组织的和原始的,它塞满了企业的数字基础设施和拖垮系统。然而,从中获得的见解将继续推动智能世界的变革。
为了创造更好的产品和服务,以及做出更好的业务决策,您的团队必须精通数据。此外,您需要适当的系统来协调各种人工智能系统,以防止人工智能孤岛。
革命至此, 85%的数据科学项目失败 , 92%的此类失败 都是因为人和流程障碍。
加入 Cangler 早期采用者计划 成为第四次工业革命的一份子。使用这项新兴技术为您的公司赢得竞争优势,并为每个人创造一个更美好的世界。
“行业知识是数据科学家的一大优势”

数据科学招聘人员 马可·霍夫勒 接受了我关于他的工作和数据科学职位选拔流程的采访。他告诉我申请人需要具备哪些素质才能在这个过程中取得成功,哪些技能是次要的。
在大多数情况下,任何经验水平的求职者与公司的第一次接触都是通过招聘人员或人才获取合作伙伴。对于数据科学家来说,这是放置简历和其他文档的人。招聘人员实际上做什么来填补数据科学职位?他在申请过程中注意什么,她(他)有什么影响?招聘人员如何将数据科学视为外部专家?我在对马尔科·霍夫勒的采访中讨论了这些问题。他是总部位于德国的全球性批发公司 METRO AG 的人才收购合伙人。他负责 IT 和数字化领域的所有职位空缺。

Marco,您为数据科学职位招聘了多长时间?
自从三年前开始专业招聘以来,这些职位一直是我关注的焦点之一。然而,作为一名勤工俭学的学生,我也有一些这样的角色要扮演。
那么,这些年来你收到了多少份这些职位的申请?
我估计做了大概 125 次面试,看了大概 300 到 400 人的申请文件。
所以你也是一名把关人,负责做出第一次选择的决定?
这个性质必然是一个结果。然而,我会完全不同地定义我在这里的主要角色。首先,我是一名顾问,在感兴趣的候选人和我们公司的需求之间进行调解。在与候选人的一次联合对话中,我了解了去地铁的步骤是否对双方都合适,是否提供了令人兴奋的发展机会。对我来说,为我们的候选人提供关于潜在机会、任务和团队环境的良好的进一步信息流,以丰富看到招聘广告后的第一印象,这是非常重要的。这确保了双方在进入深入的招聘流程之前有一个良好的预期管理。
如果在第一次审查文件的过程中,已经发现没有合适的交叉点,那么就会出现你所说的守门人效应。
你会如何描述向你提出申请的候选人?
好的一面是,通常没有典型的候选人,我与各种不同的人物和背景进行了讨论。趋势当然是数学、统计、物理的学术背景。在几个案例中,我还与毕业后最初在大学研究环境中工作的候选人进行了交谈。
底线是,整个光谱可以分为两个极端,在这两个极端之间有各种混合形式,甚至是完全的职业改变者:一方面,有一些人主要专门解决对精确度/准确性有学术要求的问题。他们的目标是找到最 100%有效的解决方案、预测等。现在想转投商界。另一方面,有些候选人已经在私营经济中工作过,因此他们不仅追求最大的精确性,而且更注重有效地计划和投资时间。这个范围还体现在沟通能力上。在数据科学中,这是客户需求和该领域可开发内容之间的桥梁。
你能描述一下申请过程吗?
我们目前的招聘流程从预选面试开始。诸如候选人目前的工作、他/她的优势和愿望等问题将会被讨论。这个人改变的动机是什么,我首先要求的是专业技能,比如敏捷方法的知识,这对我们很重要。我还特别关注沟通技巧,以及候选人是否能够优先考虑并回应客户的愿望。我喜欢以视频面试的方式进行这一步,因为成本低,但你仍然可以找到个人的水平。
如果我在这第一步发现有一个共同的基础,下一步将是与部门的第一次讨论。这取决于候选人目前的位置,无论是在我们公司还是远程进行。
如果这种技术性更强的讨论也成功了,接下来就是下一次对话,无论如何都要在现场进行。除了进一步的技术讨论之外,主要重点是公司的价值观和文化。如果双方达成一致,那么这个过程就离开了我的职责范围,转而制定雇佣合同。这可以在两周内快速完成。
作为人才获取合作伙伴,你如何影响最终的招聘决定?
当然,最终的决定是由招聘经理做出的。然而,当然在参与这个过程的人之间有很多对话,比如他/她的员工和我。作为整个过程的主持人,我负责协调所有相关方之间的校准对话,很自然地,我对候选人的看法至少也会通过讨论间接地影响决策。
然而,对于招聘经理来说,一个非常相关的部分也是我对候选人是否能够以一种可理解的方式向来自该领域以外的同事展示和解释数据科学和机器学习的复杂主题的看法。毕竟,这是未来工作必不可少的一部分,招聘经理只需要具备技术知识,这样我的观点就能带来附加值。
如何看待以下属性或技能的意义:PhD?
根据我的经验,在德国的企业环境中,博士学位对我们来说并不重要。我不知道有哪个招聘经理会明确倾向于一个拥有研究生学位的候选人。
行业经验,以你的情况批发?
这些知识非常重要,或者至少绝对是一个很大的优势。定量方法是大多数考生所熟知的。然而,来自行业的背景知识允许员工更有针对性地进行分析。例如,在零售业,这些是某些易腐性或特殊的营销场合。
具体公司的财务数字?
我个人的看法是,这个信息相当不重要。我对此不太感兴趣。然而,候选人试图理解商业模式并得出相关的挑战,这是我明确感兴趣的。
技术技能在线认证?
在线教育提供商的认证对我来说是次要的。很明显,我更喜欢候选人能够令人信服地、全面地向我解释他们是如何在哪些问题和项目上使用技术的。作为一名非数据科学家,我需要了解他们是如何提出切实可行的解决方案的。由于有大量的证书提供者,对每个证书背后的价值进行详细分类并不总是容易的。
贵公司在选择数据科学家时是否使用了用例挑战?如果有,它们长什么样?
这样的挑战在我们公司总是适用。我们提前给候选人发了一份案例研究,里面包含了真实的数据。然后,他们应该想出一个解决方案,并考虑演示。我们将询问候选人从他或她的分析中学到了什么。
在这些情况下有最终的解决方案吗,或者这个任务还没有完成?
我们的案子总是公开讨论的。这反映了我们的日常生活,在日常生活中,最终必须做出假设,必须讨论结果。不仅仅是简单的事实,日常工作生活对它来说也太复杂了。
但是,我们希望在演示中使用某些核心论点。我们提前与组织中的相关人员协调这些一般要求以获得某些结果。
你希望达到什么样的硬性淘汰标准?
不是那个意思。除非有人给出很差的评价。这主要是指明显的技术缺陷。以我的经验,这是,例如,处理统计异常值,如何对待它们,最重要的是,如何证明这是合理的。然而,这些案例中并没有隐藏的、候选人必须发现的有意识的陷阱。
贵公司的数据科学团队是什么样的?
从组织上讲,它更像是一个枢纽,而不是一个封闭的团队。这意味着数据科学家在他们参与项目的部门和直接的数据科学同事之间来回奔波。现在,我们有了一个矩阵组织,数据科学家被分配到部门和数据科学部门。
就个性而言,我们有非常广泛的范围。学科范围从数学家、统计学家、物理学家到越来越多的计算机科学家。我们既有大约 26 岁的大学毕业生,也有 45 岁左右有大约 7 年具体工作经验的同事。对了,我们的性别比例差不多是 50/50,这让我们很开心。
一个数据科学家如何在你的组织中成就一番事业?有哪些进一步发展的途径?
我们的目标是让我们的员工在纵向和横向上都得到发展。这意味着积极的发展并不需要更高的职称紧随其后。每个人都应该为自己决定如何在组织内发展,而这个决定不受任何评估。举个例子,这通常意味着某个来自技术领域的人想要向经理的方向发展。但是也可以向产品发展。因此,产品负责人的角色可以是个人发展和职业生涯的一步。然而,总是有可能回到不同的焦点。
所以这也意味着一个想要多年做完全相同工作的数据科学家不会被批判性地看待?
完全正确。我们不拘泥于自动指令的发展或变化。当然,对新事物的普遍兴趣是必要的,但这可以发生在一个人自己的领域内。
如何看待数据科学家在贵公司以及总体上的波动?
在我看来,METRO 的数据科学家波动很低。不过我也觉得低波动是比较德国的现象。根据我的经验,在德国文化中,需要在雇主那里呆更长时间是根深蒂固的。这就是为什么我通常会从我的观察中得出结论,没有任何评估,一个团队越国际化,与本地招聘的团队相比,波动就越大,主要是在德国。
然而,对于数据科学家来说,市场需求也很高。这意味着市场机制表明,数据科学家比技术工人供应更多或需求更少的其他学科具有更高的波动率。
在您积极接触数据科学领域潜在候选人的工作过程中,有什么变化吗?
市场竞争变得更加激烈。即使是高度个性化的沟通也往往不会带来成功,因为许多公司和机构都是这样做的。这意味着你不会因此受到人们的关注。其他方法更有前途,可以说:在我们的办公室里举行技术活动,与我们的员工共同开发开源项目,等等。

最后,很高兴听到你对一个热门话题的个人看法:作为一个与数据科学家密切合作的人,但不是该领域的技术专家,你如何评估数据科学、机器学习和人工智能复合体的未来发展?积极的感受是否超过了对严重负面后果的恐惧?
首先,我觉得发展速度很令人振奋。可能性的范围不是线性发展的,而是指数发展的。就我个人而言,我在日常生活中注意到,在后台运行的自动化被越来越频繁地使用,然后以闪电般的速度在实现中。如果这会让我们的生活更舒适,我非常欢迎。我不想表达恐惧,但我很好奇社会将如何在这种舒适和失去匿名之间进行权衡。我相信,不同的国家也会有非常不同的趋势和发展,这当然今天已经可以看到。
我不相信“终结者情节”,我也不相信人类自我毁灭的事实。然而,我认为未来最令人兴奋的问题将是我们如何避免或补偿由于智能机器接管的日益自动化的环境而导致的社会扭曲。社会抗议会显著增加吗?社会阶层会分化还是会有足够多的新领域出现在劳动力市场上?因此,我们谈论的是数字化、人工智能、完全自动化和量子计算机时代的世界秩序。
你是否在质疑自己在数据科学领域的工作?那么为什么不使用 CRISP-DM 进行这次审查呢?你可以在 阅读我关于数据科学职业反思的文章 。
行业研究和如何展示你的项目
苹果 | 谷歌 | SPOTIFY | 其他
悟空莫汉达斯在 TDS 播客

背景图片由布莱克·康纳利
编者按:迈向数据科学播客的“攀登数据科学阶梯”系列由 Jeremie Harris 主持。Jeremie 帮助运营一家名为sharpes minds的数据科学导师初创公司。可以听下面的播客:
如果你试图保持你的机器学习技能敏锐或进入数据科学,项目建设是你可以着手的最重要的活动。但是一个项目不会给你带来太多好处,除非你能有效地展示它,并获得反馈来迭代它——直到最近,你还没有很多地方可以这样做。
最近,一个名为 MadeWithML 的开源项目正在试图改变这种情况,它创建了一个易于共享的众包数据科学和机器学习项目库,其创始人、前苹果 ML 研究员和初创公司创始人悟空·莫汉达斯在这一集的 TDS 播客中与我坐在一起,讨论数据科学项目、他在行业中进行研究的经历以及 MadeWithML 项目。
以下是我最喜欢的外卖:
- 雇主对机器学习项目的期望越来越高。制作一个 jupyter 笔记本并使用机器学习模型进行有趣的预测已经不够好了,超越这一阶段的关键一步是收集你自己的数据,以确保你解决了其他竞争对手没有解决的利基问题。
- 在项目中包含的另一个关键步骤是部署:将您的模型包装在一个基本的 web 应用程序中,使其易于共享和展示,这一点非常重要。你最不想做的事情就是向招聘经理介绍自己,给他们发 400 行代码让他们审查——相反,给他们发一个部署好的网络应用程序就像给他们一个有趣的玩具,让他们更有可能想与你合作。
- 机器学习从一开始就有一种开源文化,这迫使许多过去孤立、孤立甚至神秘的公司更新他们的运营,以便能够吸引机器学习人才。尤其是苹果公司很好地完成了这一转变,小悟空讲述了一些必要的重大文化转变。
- 许多人认为你需要一个 CS 学位才能从事数据科学或机器学习,但这与事实相去甚远。随着数据科学的成熟,重点已经从纯粹的技术技能转移到业务和产品技能。数据科学家和 ML 工程师能够解决重要问题已经不够了:他们现在必须善于识别值得解决的问题。这就是专业知识至关重要的地方——这也是那些来自非计算机专业背景的人经常开始做的事情。如果你以前是经济学家、金融家、社会工作者,或者你在任何特定领域有过经验,即使不是技术性的,你也能很好地理解在哪里可以利用 ML 来解决实际问题。
你可以在这里的推特上关注小悟空,查看用 ML 制作的和他们的推特账号,你也可以在这里的推特上关注我。
不平等和失业率最高的职业
根据新的就业数据,美国劳工统计局发现 13%的美国人失业,尽管这一总体数字代表着巨大的困难,但这一问题在劳动力的某些领域甚至更加严重。与去年同期相比,一些职业如“计算机和数学职业”的失业率从 1%上升到 4%,但其他职业如“食品准备和服务相关职业”的失业率从 5%飙升到 37%(2019 年 5 月对 20 年 5 月)。没有人做得很好,但经济的某些部分比其他部分更糟糕。事实上,由于失业的形式,不平等可能会放大 COVID 的经济影响。因此,经济复苏可能不仅需要了解 T4 是如何让许多人失业的,还需要了解在劳动力中受影响最深的领域。

链接至完整图像。2020 年 5 月,与前一年相比,BLS 每个主要职业群体的失业率都有所上升(显示了未经季节调整的失业率,但进行了年份比较)。这些职业在疫情之前的工资和他们的未保险率在这次复苏中也可能被证明是至关重要的。
首先,失业增加最多的职业也是那些收入较低的职业。数据显示,一个职业的失业率增长(与前一年相比)与其典型的(疫情之前的)收入中位数之间存在显著的负相关关系(p<0.05;斯皮尔曼的等级秩序;2019 年 5 月至 2010 年 5 月的失业率。换句话说,准备或应对此类事件所需财政资源较少的劳动力群体,也可能是失业率上升方面面临最大经济压力的地区。考虑到整整 39%的美国人甚至在疫情之前就已经无法轻松应对 400 美元的意外开支,COVID 的经济影响对那些财力最弱的人影响最大的可能性表明,许多人正面临严重的困难和可能的债务。

每个点代表一种职业。垂直位置显示工资中位数,水平位置显示失业率增加(2019 年 5 月至 2020 年 5 月)。分析使用主要职业类别。
第二,从事这些职业的人也是那些不太可能拥有健康保险的人。社会希望患病者寻求治疗,以减缓 COVID 等疾病的传播,并帮助患者康复。考虑到这一点,大约 9%的美国人表示,即使他们认为自己感染了 COVID,他们也不会寻求医疗服务,因为担心支付不起费用。对于目前压力最大的部分劳动力来说,情况可能尤其如此,因为数据显示,与前一年相比,某个职业的典型(疫情之前)未投保率与失业率的增加之间存在显著的相关性(p<0.05;斯皮尔曼的等级秩序;2019 年 5 月至 2010 年 5 月的失业率。这意味着那些处于劳动力“高度受影响”地区的人也可能是那些不太可能拥有保险和不太能够获得医疗保健的人。*

每个点代表一种职业。垂直位置显示未保险率,水平位置显示失业增加(2019 年 5 月至 2020 年 5 月)。分析使用主要职业类别。
收入和获得可负担得起的医疗服务方面的这些差距相互累积,对工作和失业人员都产生了影响。对于那些仍在工作的人来说,以高失业率衡量压力最大的职业群体(食品准备和服务相关)不仅看到超过五分之一的工人没有保险,而且工资也可能使他们难以为未来潜在的失业做准备。考虑到在本行业工作机会稀缺的情况下,出于必要继续工作的可能压力,美国应该担心这些工人在寻求护理或生病时需要工作方面的犹豫。对于最近失业的人来说,不到一半的人有资格获得医疗补助,五分之一的人根本没有资格获得任何公共保险补贴。这在德克萨斯和佛罗里达等 15 个州可能尤其如此,这些州尚未实施患者保护与平价医疗法案(奥巴马医改)下的医疗补助扩展计划,因为这些地方的新失业人员预计有资格获得较低费率的医疗补助(p<0.05;威尔科克森署名排名)[ 8 。这使得失业者面临巨大的开支(有资格获得补贴的人平均每月 145 美元,但没有资格获得补贴的人通常每月 300 至 700 美元),或者拿自己的健康做赌注。简而言之,由于许多专家预计 COVID 期间无保险率将会上升,在这个国家最需要医疗以向前发展的时候,获得医疗可能会变得更加遥不可及。
当国家为了前进而最需要医疗服务的时候,获得医疗服务可能变得更加遥不可及
由于许多人失去了工资,并可能经历一个无法获得负担得起的医疗保健的疫情,本分析强调了 COVID 之前存在的结构性动态,这可能使疫情加深了其经济影响。美国需要考虑它可能会让一些劳动力承担什么样的金融和健康风险,以及这些风险会如何影响整个社会。正如许多州发现的那样,即使“重新开放”,解决失业问题仍然非常复杂。考虑到这一点,这些数据突显出工资和保险的差距可能会加剧新就业者的困境,表明政府可能需要考虑额外的援助来度过难关。尽管如此,仍有机会通过改善对未来的反应来尊重最近的所有困难,这种反应理解如何对美国部分劳动力不利。
*请注意,联邦政府确实在运行专门为 COVID 护理覆盖未保险者的计划[ 13 ]。尽管如此,它仍然面临挑战,数据表明使用率仍然很低,报告表明一些人仍然看到大额账单[14][15]。
感谢 Shreyas Jayanna 和 Lisa Nash 对这篇文章的帮助。
想要在数据、设计和系统的交叉点上做更多的实验吗? 关注我获取更多 !
不等式:如何用 SQL、BigQuery 和 Data Studio 绘制洛伦兹曲线

所有维基百科页面中排名前 0.1%的页面获得了 25%的浏览量。最底层的 99%只获得了 42%的浏览量。而底层的 80% —只得到 4%。这只是一个例子——在本帖中,我们将回顾如何获得这个数据集和任何其他数据集的这些数字。
我们如何从 SQL 表中获取这些数字呢?
第 0 步:什么是 BigQuery?
如果这是您第一次使用 BigQuery,请准备好体验一次有趣的旅程。看看这篇文章:
如果你在注册 BigQuery 时遇到了困难,不用担心——现在注册和开始使用比以往任何时候都容易
towardsdatascience.com](/bigquery-without-a-credit-card-discover-learn-and-share-199e08d4a064)
步骤 1:您的数据、BigQuery 和 SQL
首先,我们需要定义数据集。在这种情况下,它是 2019 年 12 月期间英文维基百科中的所有浏览量-在删除所有特殊页面后:
WITH wiki_prefixes AS (
SELECT ['File:', 'Draft:', 'Help:', 'en:', '...'] x
)
, data AS (
SELECT *
FROM `fh-bigquery.wikipedia_extracts.201912_en_totals`
WHERE title NOT IN ('-', 'Main_Page')
AND (
title NOT LIKE '%:%'
OR REGEXP_EXTRACT(title, '[^:]*:')
NOT IN UNNEST((SELECT(x) FROM wiki_prefixes))
)
)
您需要为此数据集中的每一行提供一个连续的行号,按页面浏览量排序:
SELECT title, views, ROW_NUMBER() OVER (ORDER BY views) rn
FROM data
现在,您可以使用该行号将所有页面分成 1,000 个不同的存储桶:
SELECT 1+fhoffa.x.int(rn/(SELECT (1+COUNT(*))/1000 FROM data)) bucket
, COUNT(*) pages
, SUM(views) views
, STRING_AGG(title ORDER BY views DESC LIMIT 3) sample_titles
FROM (
SELECT title, views, ROW_NUMBER() OVER (ORDER BY views) rn
FROM data
)
GROUP BY 1
为了得到一个桶,我在第一行有一个子查询:(SELECT (1+COUNT(*))/1000 FROM data)。这得到了一个基于我的数据集中的总行数的数字,通过将每个行号除以这个值,我们得到了 1k 个不同的桶,从 0 到 999。这些桶中的每一个都有其页面的SUM(views),STRING_AGG(title ORDER BY views DESC LIMIT 3)用来保存一些样本标题以识别每个桶。
现在,我们将用一个新的查询来包围这个查询,该查询计算我们遍历 1k 个存储桶时的累计浏览量,以及所有这些页面的总浏览量:
SELECT SUM(views) OVER(ORDER BY bucket) cum_views
, SUM(views) OVER() total_views
FROM (
...
)
获得每一行的累计值和总计值的方法是OVER(ORDER BY bucket)对仅仅是OVER()。
下一步:获取视图的累积数量,然后除以总数:
SELECT ROUND(100*cum_views/total_views,3) cum_percent
FROM (
...
)
现在我们有了一个可以在 Data Studio 中绘制的累计百分比。让我们将所有内容放在一起,创建一个新表:
CREATE TABLE `wikipedia_extracts.201912_lorenz_curve`
AS
WITH wiki_prefixes AS (SELECT ['File:', 'Talk:', 'Template_talk:', 'Wikipedia:', 'Category:', 'User_talk:', 'Page:', 'Template:', 'Category_talk:' , 'User:', 'Author:', 'Portal:', 'Wikipedia_talk:', 'Portal_talk:', 'File_talk:', 'Draft:', 'Help:', 'Draft_talk:', 'en:', 'Book_talk:', 'Module:', 'MOS:', 'Special:', 'Book:'] x)
, data AS (
SELECT *
FROM `fh-bigquery.wikipedia_extracts.201912_en_totals`
WHERE title NOT IN ('-', 'Main_Page')
AND (
title NOT LIKE '%:%'
OR REGEXP_EXTRACT(title, '[^:]*:') NOT IN UNNEST((SELECT(x) FROM wiki_prefixes))
)
)SELECT ROUND(100*cum_views/total_views,3) cum_percent, *
FROM (
SELECT SUM(views) OVER(ORDER BY bucket) cum_views, *, SUM(views) OVER() total_views
FROM (
SELECT 1+fhoffa.x.int(rn/(SELECT (1+COUNT(*))/1000 FROM data)) bucket, COUNT(*) pages, SUM(views) views
, STRING_AGG(title ORDER BY views DESC LIMIT 3) sample_titles
FROM (
SELECT title, views, ROW_NUMBER() OVER (ORDER BY views) rn
FROM data
)
GROUP BY 1
)
)# 34.1 sec elapsed, 805.8 MB processed)

存储桶#991 到#1000,前 1%
步骤 2:在 Data Studio 中可视化
转到刚刚在 BigQuery 中创建的新表,按照以下步骤操作:
使用 Data Studio 探索
→保存
→创建新报告并共享



使用 Data Studio 浏览→保存→创建新报告并共享
→添加到报告中
→添加图表
→分散
→ X:时段 Y:累计百分比

添加到报表→添加图表→散点图→ X:时段 Y:累计百分比
这就是如何使用 Data Studio 和 BigQuery 通过几个步骤获得漂亮的洛伦兹曲线:
笔记
维基百科刚刚公布了他们的第 600 万篇文章,在这份报告中,我们统计了超过 1100 万页。这份报告是基于维基百科报告每小时的页面浏览量,来自他们的日志(加载在 BigQuery 中)——这些查询已经删除了我能找到的大多数“特殊”页面。如果你知道更好的清理这些日志的方法,请告诉我。
为了平衡这一点,我没有计算任何在 12 月份获得 0 浏览量的页面——我们在这里查看浏览量日志,所以零不会出现。
英语维基百科已经有 600 万篇文章,作者是 19 世纪加拿大学校的玛丽亚·伊莉斯·特纳·劳德…
en.wikipedia.org](https://en.wikipedia.org/wiki/Wikipedia:Six_million_articles) [## 维基百科:什么是文章?
“文章”属于维基百科页面的主命名空间(也称为“文章命名空间”或简称“主空间”)…
en.m.wikipedia.org](https://en.m.wikipedia.org/wiki/Wikipedia:What_is_an_article%3F) [## 帕累托分布
以意大利土木工程师、经济学家和社会学家维尔弗雷多·帕累托[1]的名字命名的帕累托分布是一种…
en.wikipedia.org](https://en.wikipedia.org/wiki/Pareto_distribution) [## 罗伦兹曲线
在经济学中,洛伦茨曲线是收入或财富分布的图形表示。那是…
en.wikipedia.org](https://en.wikipedia.org/wiki/Lorenz_curve)
洛伦兹曲线是一个图表,显示了底层 x %的人承担的总收入或财富的比例,尽管这对于有限的人口来说并不严格成立(见下文)。它通常用于表示收入分配,显示底层家庭占总收入的百分比。家庭的百分比标绘在 x 轴上,收入的百分比标绘在 y 轴上。它也可以用来显示资产的分布。在这种用法中,许多经济学家认为它是衡量社会不平等的一种手段。
后续步骤
- 要用 BigQuery 计算基尼系数,查看来自 Evgeny Medvedev 的帖子:
下面是在给定每日余额的情况下输出每天的基尼系数的查询:
medium.com](https://medium.com/google-cloud/calculating-gini-coefficient-in-bigquery-3bc162c82168)
- 要通过 BigQuery 和 Data Studio 互动查看2019 年顶级维基百科浏览量,请查看我的帖子:
维基媒体公布了他们 2019 年最受欢迎的页面——但我们能更深入吗?当然,这里有 BigQuery 和…
towardsdatascience.com](/interactive-the-top-2019-wikipedia-pages-d3b96335b6ae)
想要更多吗?
我是 Felipe Hoffa,谷歌云的开发者倡导者。在 @felipehoffa 上关注我,在【medium.com/@hoffa】的上找到我之前的帖子,在的【reddit.com/r/bigquery】上找到所有关于 BigQuery 的帖子。
缺乏经验的数据科学家如何抓住机遇

蒂姆·马歇尔在 Unsplash 上的照片
当技能遇到机会时,成长就会发生
在你获得成为数据科学家的技能后,最重要的事情是什么?
找份工作,开始数据科学的职业生涯。
我确定我不用教任何人在线申请。每个人都知道。
但是对于一个完全没有经验的数据科学家来说,很难找到第一个突破口。如果你没有数据科学或技术领域的学位,那就更难了。
在这种情况下,最好的办法是加入数据科学家社区。认识行业内的人,让人们知道你是他们中的一员。同时,了解他们使用的技术,了解你需要做些什么来成为社区的一部分。
如果你是一名自学成才的数据科学家,或者你经历了职业变化,这一点尤为重要。加入数据科学家社区需要做一些工作。
如果你想找份工作或自由职业,或者开始创业,你也必须参与进来,建立一个社区。我将在这篇文章中解释一些有效的方法。或许你已经在做其中的一些了。但是你可能会找到做更多事情的动力。
在这篇文章中,我将谈论这三个非常基本的想法:
- 炫耀你的技能。
- 与行业人士的直接对话
- 建立关系
展示你的技能
做一个投资组合,让它可信。添加一些元素来展示你的技能。这里有一些展示你技能的方法。
这是免费的,也是用您的代码创建配置文件的最简单的方法。无论你为了实践做了什么小的大的项目,用它们做一个漂亮的、组织良好的 GitHub 简介,并不断丰富它。
在你申请工作、开始建立关系网或者开始公开谈论你的技能之前,你需要有一个公开的个人资料来展示你的技能。它给了很多可信度和接受度。
雇主在你的求职申请中要求 Github 个人资料链接。所以对于编码人员来说,拥有一个 Github 配置文件几乎是强制性的。
一开始,我花了一些时间才知道 GitHub 个人资料可以在谷歌中排名。如果你在谷歌上搜索某个项目或主题,你会看到一些 Github 的简介出现在搜索结果中。
试试用这个“python 中的线性回归从头开始,GitHub”搜索。
你可以免费拥有一个精美的作品集来展示你的技能。如果你坚持定期发帖,你的个人资料也会变得受欢迎。
你会看到人们在他们的项目中使用你的代码,跟踪你,问你问题。
虽然这需要一些时间。大概 7/8 个月或者一年。但是即使你的 Github 档案不流行,你仍然可以在简历中使用你的 Github 档案链接。
写博客
这是展示你知道如何表达的最好方式之一。我从我的许多朋友那里听到“哦,不,写作不是我的事情”。
像其他技能一样,也需要时间来培养。但是如果你能习惯,那就太好了!
因为它会留在网上给所有人看。对你来说这几乎就是一笔资产。如果你经常做,你甚至可以从中赚钱。
这是一个很棒的写作平台!
如果你想拥有自己的个人域名,有一些免费的博客网站,比如 blogger.com 的。使用它。好消息是,它归谷歌所有。或者,另一个非常简单的方法是做一个 WordPress 博客。
你可以从 freenom 获得一个域名。一个免费的托管网站是 unlimitedfreehost.in 。可能还有其他免费资源。但是我以前用过。所以,这就是我分享这些的原因。下面是一篇关于它们的详细文章:
非常适合投资组合、开博客或创业
towardsdatascience.com](/unlimited-free-hosting-and-domain-5998e14f7bfe)
如果你只想要一个空间来制作文件夹和添加简历,这些免费网站是完美的。
但是如果你想认真对待博客,最好的办法是买一个你想要的域名。
与人直接对话
当你在 GitHub 上有了一个不错的作品集和一些可以炫耀的材料后,最有效的方法就是直接和人们交谈。
现在,去哪里找合适的人交谈呢?
以下是找到它们的地方:
社交媒体
我主要使用脸书、推特和 Linkedin。
在脸书,你可以免费加入很多数据科学家团体。
你会发现许多人分享他们的想法,寻求帮助,进行对话。
我建议,加入一些你认为适合你的群,参与到对话中来。
分享你的想法,好文章,课程,视频,或者你知道有帮助的资源。喜欢并评论别人的资料,回答别人的问题如果你知道的话。
当你愿意帮助别人时,你也会得到帮助。以下是我加入的一些脸书团体:
有很多这样的团体。选择你喜欢的。同样,在 Twitter 上关注业内人士,在 Linked In 上建立联系。
我通过 LinkedIn 上的关系找到了第一份实习工作
我只能说这三个社交媒体平台,因为我使用它们。如果你也使用其他平台,用它们来建立你的职业关系网。
这是两个非常有用的网站。我使用堆栈溢出。但是两个都不错。如果你还没有,现在就开始使用它们。他们在很多方面都很好。
首先,你可以直接展示你的知识。回答别人的问题,尽可能地参与一些对话。
你会看到在侧边栏的职位发布,有一个选项来上传您的个人资料,以匹配你与雇主。如果你是一个活跃的成员,并且经常使用它,你最终会感受到在一个技术社区中的好处。
在你能回答问题之前,你需要赢得分数。这并不难。你需要做的就是提问。它有一个很棒的社区。
当我做一个项目遇到困难时,我会在这里提问,大多数情况下,我会在前 10 分钟内得到回复。
你甚至不用问一个非常普通的问题。只要用这个问题搜索,你会看到其他人已经问过这个问题,并且已经有了答案。
如果你是堆栈交换/溢出的初学者,这可能会很棘手
我的一些朋友告诉我,他们不觉得它好。因为提问很难。但是并不难。可能需要一点时间来理解,如何提出一个问题来获得帮助。随着时间的推移,你会学会的。一旦你学会了,你就会爱上它。
每当你遇到问题时,你都有一个免费的社区来讨论它!!
过一段时间,你就能在那里回答别人的问题了。这是一个很好的方式来练习你的技能,也是向社区展示你的技能。
松弛通道
加入松弛渠道。在每个地区,都有聚会小组、学习小组、志愿者小组。这些团体中的大多数都有松散的渠道。加入他们。
他们在那些空闲频道上宣布事件、会议、聚会。你将能够保持更新。
此外,大多数 slack 频道都有一个工作板。他们在那里发布职位空缺。
建立关系
不要误会我!
建立关系意味着产生持久的影响,并与你遇到的人保持联系。有几种方法可以做到这一点。
聚会
我住在美国。在这里,我使用平台【meetup.com】和事件开始寻找专业的网络事件。后来,我在 Linked in 上与他们联系,现在我可以在 Linked in 和 twitter 上获得关于重要事件的信息。
现在我个人认识很多业内人士。我甚至接到我认识的人打来的电话,问我是否愿意接受一份新工作,或者我是否知道有人可以做这份工作。
如果你坚持参加活动、研讨会和会议,这种情况也会发生在你身上。你会一次又一次地遇到同样的人,进入技术对话,展示你的专业技能。
与人建立这种关系需要一些时间。
同时,你会从这些事件中学到很多。你可以了解其他成功人士的工作、新技术、学习平台等等。
会议
参加会议,并在会议甚至聚会上展示你的项目。这是展示你的技能和提高的好方法。你从中获得了如此多的自信。
你不必成为任何领域的专家来展示你的项目。你只需要好好准备。
选择一个项目或主题并准备它。
我第一次开始做演讲是在我刚刚参加网络课程的时候,没有任何专业经验。
聚会上有人告诉我,下一个应该由你来演讲。我说‘是’。在那之后,我极度紧张和害怕,直到我的陈述。我收到了很多积极的激励和鼓励,甚至有人给了我一个推荐!
从那以后,我抓住一切机会做演讲。这对我提高知识帮助很大。因为当我准备演讲的时候,我学习了很多!我敢肯定,当每个人都知道很多人会看他们讲话时,他们会额外学习。
你可能会发现这篇文章很有用。它有一个数据集的选择做项目,也有一些项目的想法:
一些有趣的数据集提升你的技能和投资组合
towardsdatascience.com](/all-the-datasets-you-need-to-practice-data-science-skills-and-make-a-great-portfolio-857a348883b5)
如果你开始参加聚会,参与社交媒体,你会看到你周围不断有许多大小活动,他们总是在寻找新的主持人。
在这些活动中做志愿者,慢慢地和人们交谈。
试着坚持做 3/4 个月,你会发现你认识这个地区大多数大公司的人。
组织
参加聚会和会议是件好事。但是如果你能参与组织活动、学习小组和会议就更好了。如果你没有太多的人脉,这种情况可能不会长期存在。
所以,先用我之前解释的技巧建立一些联系,然后进入你将采取主动组织的阶段。
听着,你不必一个人做所有的工作!
我第一次加入组织活动的团队是帮助收拾行李。第二次,我负责每周三次在他们的社交媒体页面上发帖,我每周和团队见一次面。
没花太多时间。但是我接触到了一些不可思议的人!
结论
我唯一需要警告你的是,请不要过度。
你必须给自己留点时间来学习和提高你的技能。除此之外别无选择。
我的建议是制定一个常规或计划。根据你的时间表,在一周或一天中的某个时间安排这个网络或社区发展。坚持下去。
否则,你会看到你只忙于社交活动,没有时间提高自己的技能。你不会想那样的。另一方面,你无法避免社交或网络。
因为如果你有技能,但不知道如何建立关系网,这将无助于你的职业发展。
所以,请想办法平衡两者。祝你好运!
更多阅读:
[## 一个完整的带有亚马逊产品评论数据的 Python 情感分析算法:一步一步
使用 Python 的 Scikit_learn 库的 NLP 项目
towardsdatascience.com](/a-complete-sentiment-analysis-algorithm-in-python-with-amazon-product-review-data-step-by-step-2680d2e2c23b) [## 学习机器学习和深度学习的优质免费课程
顶级大学高质量免费课程的链接
towardsdatascience.com](/great-quality-free-courses-to-learn-machine-learning-and-deep-learning-1029048fd0fc) [## Numpy 完全指南
日常工作中需要的所有数字方法
towardsdatascience.com](/a-complete-guide-to-numpy-fb9235fb3e9d) [## 使用 Python 从零开始的多类分类算法:分步指南
本文介绍两种方法:梯度下降法和优化函数法
towardsdatascience.com](/multiclass-classification-algorithm-from-scratch-with-a-project-in-python-step-by-step-guide-485a83c79992) [## Python Matplotlib 的日常备忘单
完整的可视化课程
towardsdatascience.com](/your-everyday-cheatsheet-for-pythons-matplotlib-c03345ca390d) [## 置信区间的完整指南,以及 Python 中的示例
对统计学中一个非常流行的参数——置信区间及其计算的深入理解
towardsdatascience.com](/a-complete-guide-to-confidence-interval-and-examples-in-python-ff417c5cb593)
传染病建模:超越基本 SIR 模型

我的上一篇文章解释了背景,并介绍了传染病建模的主题。如果你对 SIR 方程还没有很好的理解,你可能想先读一下那个来理解这个。这篇文章关注的是基本 SIR 模型的更复杂的变体,它将使你能够实现和编码你自己的变体和想法。下一篇文章将关注模型与现实世界数据的拟合,并将新冠肺炎作为案例研究。
首先,我们将从一个稍微不同的更直观的角度快速探索 SIR 模型。之后,我们派生并实现了以下扩展:
- “死亡”状态,指死于疾病的个体
- 一种“暴露”状态,针对已感染疾病但尚未传染的个体(这被称为 SEIR 模型)
- 依赖于时间的 R₀-values 这将允许我们对隔离、锁定等进行建模
- 与资源和年龄相关的死亡率这将使我们能够模拟过度拥挤的医院、有很多年轻人的人群……
作为状态转换的模型
快速回顾一下,看看我们定义的变量:
- N: 总人口
- S(t): 第 t 天易感人数
- I(t): 第 t 天感染人数
- R(t): 第 t 天康复的人数
- β: 感染者每天感染的预期人数
- D: 一个感染者已经并可能传播疾病的天数
- γ: 感染者每日痊愈的比例(γ = 1/D)
- R₀: 一个感染者感染的总人数(R₀ = β / γ)
这是基本方程:

在推导方程时,我们已经直观地将它们视为“方向”,它告诉我们第二天人口会发生什么(例如,当 10 个人被感染,康复率为 1/5(即伽马),那么第二天康复的人数应该增加 1/5 * 10 = 2)。我们现在将对方程的理解固化为从一个区间 S、I 或 R 到另一个区间的“方向”或【跃迁】——这将极大地简化事情,当我们稍后引入更多区间时,方程会变得混乱。
下面是我们需要的符号:
隔间是盒子(“状态”),就像这样:

从一个隔室到另一个隔室的过渡由箭头表示,其标签如下:

率描述了转变需要多长时间,人口是这种转变适用的个体群体,概率是个体发生转变的概率。
作为一个例子,让我们看看 SIR 方程中从易感者到被感染者的转变,β= 2,总人口为 100,10 人被感染,90 人易感。比率是 1,因为感染是立即发生的;过渡适用的人群是 2 * 10 = 20 个人,因为 10 个被感染的人每个感染 2 个人;可能性是 90%,因为 90/100 的人仍然会被感染。它对应于这个直观的符号:

而且更一般的,现在对于整个模型(对于 I → R,速率为γ,概率为 1 随着每个人的恢复):


正如你所看到的,箭头指向一个隔间在等式中加上;指向远离一个隔间的箭头减去。那不是太糟糕,是吗?花点时间去真正理解新的符号,看看它是如何用另一种方式来写方程的。**
对,我们现在理解了 SIR 模型,可以用 python 编码了,但是它已经有用了吗?它能告诉我们任何关于真实世界传染病的事情吗?答案是不在目前的状态下,该模型更多的是一个玩具,而不是一个有用的工具。让我们改变这一切!
引入新隔间
导出暴露隔间
许多传染病在具有传染性之前都有一个潜伏期,在此期间宿主还不能传播疾病。我们将这样的个体——以及整个隔间——称为Eexposed。
直觉上,我们会有 S → E → I → R 形式的转变:易感人群会感染病毒,从而暴露,然后被感染,然后康复。新的转变 S → E 将具有与当前的 S → I 转变相同的箭头,因为概率是相同的(所有易感者都可以被暴露),速率是相同的(“暴露”立即发生)并且群体是相同的(感染个体可以传播疾病并且每个每天暴露β个新个体)。从 I 到 R 的过渡也没有改变的理由。唯一的新转变是从 E 到 I 的转变:概率是 1(每个暴露的人都会被感染),总体是 E(所有暴露的人都会被感染),比率得到一个新的变量,δ (delta)。我们实现了这些转变:

从这些转换,我们可以立即推导出这些方程(再次,比较状态转换和方程,直到它对你有意义):

对暴露隔间进行编程
这应该不会太难,我们只需要修改上一篇文章中的几行代码( 再次,完整的代码在这里沿着 ,我只是在这里展示重要的位)。我们将在 100 万人口中模拟一种高传染性(R₀ =5.0)疾病,潜伏期为 5 天,恢复期为 7 天。
Imports needed:
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
方程和初始值现在看起来像这样:
我们随时间计算 S、E、I 和 R:
(标绘后)得到这个:

我们现在能够更真实地模拟真实的疾病,尽管仍然肯定缺少一个部分;我们现在将添加它:
导出死舱
对于非常致命的疾病,这个隔间非常重要。对于其他一些情况,您可能希望添加完全不同的区间和动态(例如在长时间研究一种疾病时的出生和非疾病相关的死亡);这些模型可以变得像你想要的那样复杂!

我们当前的状态转换
让我们考虑一下如何利用当前的转换添加一个 D ead 状态。人什么时候会死于这种疾病?只有在他们被感染的时候!这意味着我们必须增加一个过渡 I → D。当然,人不会马上死去;我们为人们的死亡率定义了一个新的变量ρ(rho)(例如,当死亡需要 6 天时,ρ将是 1/6)。回收率γ没有理由改变。所以我们的新模型看起来会像这样:

唯一缺少的是从感染到康复以及从感染到死亡的概率。这将是又一个变量(现在的最后一个!),即死亡率α。例如,如果α=5%,ρ = 1,γ = 1(因此人们在 1 天内死亡或康复,这是一个更简单的例子),100 人被感染,那么 5% ⋅ 100 = 5 人将死亡。剩下 95%的⋅ 100 = 95 人正在康复。总而言之,I → D 的概率是α,因此 I → R 的概率是 1-α。我们最终得出了这个模型:

这自然会转化为这些等式:

对死区进行编程
我们只需要对代码做一些细微的修改(我们将α设置为 20%,ρ设置为 1/9)…
…我们得出这样的结论:

请注意,我添加了一个“总计”,将每个时间步长的 S、E、I、R 和 D 相加,作为“健全检查”:区间的总和总是为 N;这可以给你一个提示,说明你的方程是否正确。
您现在应该知道如何向模型中添加一个新的区间:考虑需要添加和更改哪些转换;想想这些新转变的概率、人口和速率;画图表;最后写下方程式。对于这些模型来说,编码绝对是而不是最难的部分!
例如,您可能想要为需要去 ICU 的受感染个体添加一个“ICU”隔间(我们将在下一篇文章中完成)。想想人可以从哪个车厢进 ICU,出了 ICU 后可以去哪里等等。
时间相关变量
以下是我们目前使用的变量的更新列表:
- 总人口
- S(t): 第 t 天易感人数
- E(t): 第 t 天暴露的人数
- I(t): 第 t 天感染人数
- R(t): 第 t 天康复人数
- D(t):t 日死亡人数
- β: 感染者每天感染的预期人数
- D: 感染者已经并可能传播疾病的天数
- γ: 感染者每日痊愈的比例(γ = 1/D)
- R₀: 一个感染者感染的总人数(R₀ = β / γ)
- δ: 潜伏期的长短
- α: 病死率
- 人的死亡率(= 1/从感染到死亡的天数)
如您所见,只有区间会随时间变化(它们不是恒定的)。当然,这是极不现实的!举个例子,为什么 R₀-value 应该是常数?当然,全国范围内的封锁减少了感染者的感染人数,这就是它们的意义所在!自然地,为了更接近模拟真实世界的发展,我们必须让我们的变量随着时间而变化。
时间相关 R₀
首先,我们实现一个简单的改变:在第 L 天,一个严格的“锁定”被强制执行,将 R₀推至 0.9。在方程中,我们用β而不是 R₀,但我们知道 R₀ = β / γ,所以β = R₀ ⋅ γ。这意味着我们定义了一个函数
def R_0(t):
return 5.0 if t < L else 0.9
β的另一个函数调用这个函数:
def beta(t):
return R_0(t) * gamma
对,似乎很容易;我们只需相应地更改代码:
让我们画出一些不同的 L 值:



几天的时间就能让疾病的整体传播发生巨大的变化!
事实上,R₀可能从来没有从一种价值观“跳到”另一种价值观。相反,它(或多或少地)不断变化(可能上下波动几次,例如,如果社会距离措施放松,然后再次收紧)。你可以为 R₀选择任何你想要的函数,我只想给出一个常见的选择来模拟社交距离的最初影响:一个 逻辑函数 。
该函数(用于我们的目的)如下所示:

下面是这些参数的实际作用:
- r0 _ start 和 r0 _ end 是第一天和最后一天的 r0 值
- x_0 是拐点的 x 值(即 R_0 最急剧下降的日期,这可以被认为是主要的“锁定”日期)
- k 让我们改变 R_0 下降的速度
这些图可能有助于您理解参数:

同样,相应地更改代码:
我们让 R₀在第 50 天左右从 5.0 快速下降到 0.5,现在可以真正看到曲线在第 50 天后变平:

与资源和年龄相关的死亡率
与 R₀相似,对大多数真正的疾病来说,死亡率α可能不是常数。这可能取决于多种因素。我们将关注对资源和年龄的依赖性。
首先,让我们看看资源依赖。当更多的人被感染时,我们希望死亡率更高。想一想如何将它转化为一个函数:我们可能需要一个“基础”或“最佳”死亡率,用于只有少数人被感染(并因此得到最佳治疗)的情况,以及一些考虑到当前感染人口比例的因素。这是实现这些想法的函数的一个例子:

这里, s 是某个任意但固定的(这意味着我们为一个模型自由选择它一次,然后它随时间保持不变)比例因子,它控制感染比例应该有多大的影响;α_OPT 是最佳死亡率。例如,如果 s=1,有一半的人口在某一天被感染,那么 s ⋅ I(t) / N = 1/2,那么那一天的病死率α(t)为 50% + α_OPT。或者也许大多数人几乎没有任何症状,因此许多被感染的人不会阻塞医院。那么比例因子 0.1 可能是合适的(在同样的情况下,死亡率仅为 5% + α_OPT)。
更精细的模型可能会使死亡率取决于 ICU 病床或呼吸机的数量等。我们将在下一篇文章中对冠状病毒建模时做这件事。
年龄依赖就有点难了。为了完全实现它,我们必须为每个年龄组包括单独的隔间(例如,一个感染隔间用于 0-9 岁的人,另一个用于 10-19 岁的人……)。用 python 中的一个简单 for 循环就可以做到这一点,但是等式有点混乱。仍然能够产生良好结果的更简单的方法如下:
对于更简单的方法,我们需要两样东西:按年龄组的死亡率和该年龄组占总人口的比例。例如,我们可能有以下死亡率和按年龄组划分的人数(在 Python 字典中):
alpha_by_agegroup = {
"0-29": 0.01, "30-59": 0.05, "60-89": 0.20, "89+": 0.30
}
proportion_of_agegroup = {
"0-29": 0.1, "30-59": 0.3, "60-89": 0.4, "89+": 0.2
}
(这将是一个非常老的人口,40%在 60-89 岁之间,20%在 89 岁以上)。现在,我们通过将年龄组死亡率乘以该年龄组的人口比例相加来计算总平均死亡率:
α = 0.01 ⋅ 0.1 + 0.05 ⋅ 0.3 + 0.2 ⋅ 0.4 + 0.3 ⋅ 0.2 = 15.6%.或者在代码中:
alpha = sum(
alpha_by_agegroup[agegroup] * proportion_of_agegroup[agegroup]
for agegroup in alpha_by_agegroup.keys()
)
相当年轻的人口比例如下…
proportion_of_agegroup = {
"0-29": 0.4, "30-59": 0.4, "60-89": 0.1, "89+": 0.1
}
…平均死亡率仅为 7.4%!
如果我们想同时使用我们的资源依赖公式和年龄依赖公式,我们可以使用我们刚刚用来计算α_OPT 的资源公式,并在上面的资源依赖公式中使用它。
随着时间的推移,当然有更精细的方法来实现死亡率。例如,我们没有考虑到只有需要重症监护的危重病例才会挤满医院,并可能增加死亡率;或者死亡改变了我们最初用来计算死亡率的人口结构;或者感染对死亡率的影响应该在几天后发生,因为人们通常不会立即死亡,这将导致 延迟微分方程 ,这在 Python 中很难处理!再次强调,尽你所能地发挥创造力!
实施与资源和年龄相关的死亡率
这相当简单,我们甚至不需要改变我们的主方程(我们在方程中定义 alpha ,因为我们需要访问当前值 I(t))。
根据上面按年龄组和老年人口统计的死亡率(以及比例因子 s 为 1,所以许多人被感染对死亡率有很大影响),我们得出了这个图:

对于较年轻的人口(大约 8 万人而不是 15 万人死亡):

现在缩放系数只有 0.01:
对于年龄较大的人群(请注意,随着时间的推移,死亡率仅略微上升)…

…以及更年轻的人群:

概述
仅此而已!您现在应该能够添加自己的区间(可能是针对可能再次感染的个人的区间,或者是针对糖尿病患者等特殊风险群体的区间),首先通过状态转换符号以图形方式,然后正式通过等式,最后通过 Python 以编程方式!此外,您还看到了一些实现时间相关变量的示例,这使得模型更加通用。
所有这些应该可以让你设计出非常接近真实世界的 SIR 模型。当然,许多科学家目前正在研究这些模型(此链接可以帮助你找到一些当前的文章——注意,它们可能会变得非常复杂,但这仍然是深入了解该领域当前状态的一个很好的方式)。在下一篇文章中,我们将把重点放在设计模型并使其适合真实世界的数据,并将冠状病毒作为一个案例研究。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
传染病建模:使你的模型适合冠状病毒数据

在本文中,我解释了一些背景,并介绍了传染病建模和 SIR 模型的主题。我的上一篇文章对此进行了阐述,并扩展了基本的 SIR 模型。那里导出和实现的模型为这里使用的模型奠定了基础,所以你可能想先读两篇文章(或者如果你已经很好地理解了基本的 SIR 模型,就读最后一篇)。
这篇文章的重点是将一个扩展的 SIR 模型与真实的冠状病毒数据拟合,该模型具有依赖于时间的 R₀-values 和依赖于资源的死亡率,以便尽可能接近真实的数字,并对未来可能的发展做出明智的预测。但是在我们开始将数据拟合到我们的模型之前,让我们做一些经常被忽略的事情——让我们简单看看我们的模型不能做什么。
警告、陷阱、限制
“从本质上讲,所有的模型都是错误的,但有些是有用的”——乔治·博克斯,英国数学家
模型总是现实世界的简化。如果你想看一个与真实世界完全相似的模型,去外面吧!然而,这并不意味着它们不有趣,不能产生深刻的见解。记住以下几点很重要:
- 我们的微分方程系统对初始参数极其敏感;微小的变化会导致完全不同的结果。
- 我们正在根据不完整的初步数据进行推断。一些国家可能只统计直接由冠状病毒导致的死亡,其他国家可能统计个人被感染的所有死亡。有些人可能(有意或无意)报告不准确或不可靠的数据等。
- 我们假设所有人都是同质的,也就是说,我们没有考虑到一些地方是最初的热点地区,而另一些地方实施限制的时间更早、力度更大(我们需要更多的努力(从计算和数学上)来考虑这些事情)。
此外,针对我们的模型,我们做了以下假设(这些只是一些显而易见的假设,当然还有更多隐藏在等式中的假设):
- 死亡不会在有意义的程度上改变人口结构(我们先验地计算死亡率(使用爆发前的人口结构)并假设死亡不会高到显著改变人口结构(我认为这是一个相当弱的合理假设))。
- 只有危重病例才能填满医院,并且由于缺乏可用的护理,会导致更高的死亡率。
- 所有没有得到治疗的危重患者都会死亡。
- 个体在康复后是免疫的(目前这似乎是可能的,至少对绝大多数患者是如此。然而,一些报道可能会指出这是假的)。
- R₀只减少或保持不变。它不会增加。(因此,这个模型不允许我们对再次放松的措施建模;为此,我们需要一个不同的 R₀函数)
现在记住这一点,让我们开始建模:我们将首先非常快速地进行曲线拟合,然后推导出我们使用的模型,最后将我们的模型拟合到冠状病毒数据。
(非常简短的介绍)曲线拟合
稍后,我们将获得一些数据点(每天的累计死亡人数)和一个函数(我们的模型),该函数根据一些参数(死亡率、ICU 床位等)给出我们预测的每天的累计死亡人数。然后,我们想要拟合曲线,这意味着我们想要为我们的模型找到参数,以生成最接近真实数据的预测。我不会在这里深入任何数学背景,我只会用 Python 给出一个例子(这里省略了导入,它们在笔记本里)。
首先,生成一些数据(在本例中,是带有一些噪声的正态分布)来拟合:
看起来是这样的:

接下来,我们需要一个函数,它将 x 值作为第一个参数,将我们想要拟合的三个参数(我们称它们为 a,b,c )作为下一个参数。这是我们将用来拟合数据的函数;我们的曲线拟合库(不要担心,我们自己不必做任何繁重的工作)将改变参数,直到它找到一个好的拟合(并有希望找到我们用来生成数据的那些,即 a=21,b=6.1,c=1.2)。通过这个函数,我们生成一个曲线拟合模型(使用lm fit库)并传递一些参数的初始猜测。然后我们拟合数据。需要注意的是,一般的曲线拟合方法并不能保证找到全局最小值,我们对参数的初步猜测是至关重要的。**
这是输出—我们找到了我们的参数!

这就是我们需要的所有曲线拟合背景。现在,我们将使用模型来拟合数据:
拟合的扩展 SIR 模型
我们建立在上一篇文章中导出的模型基础上:个人是第一个SSS 易受感染的——他们可以感染冠状病毒(概率为 S/N)并成为 e 暴露者。他们还不能传播病毒。几天后(确切地说是 1/δ),他们被感染并传播了病毒。在感染的过程中,它们可以(超过 1/ρ天,概率为α)存活并最终恢复(1/γ天后):

为了提醒你,这里还有一些变量:
- N: 总人口
- S(t): 第 t 天易感人数
- E(t): 第 t 天暴露的人数
- I(t): 第 t 天感染人数
- R(t): 第 t 天康复人数
- 第 t 天死亡人数
- β: 感染者每天感染的预期人数
- D: 受感染者已经并可能传播疾病的天数
- γ: 感染者每日痊愈的比例(γ = 1/D)
- R₀: 一个感染者感染的总人数(R₀ = β / γ)
- δ: 潜伏期的长度
- α: 病死率
- ρ: 人的死亡率(= 1/从感染到死亡的天数)
我只想添加一个新的隔间:C**critical,用于需要重症监护的个人。这将使我们能够模拟人满为患的医院。当然,只有被感染的个体才能进入危急状态。从临界状态开始,它们要么死亡,要么康复。**
我们实现了这些转变:

好吧,这里有很多问号,让我们做一些思考!我们需要一个被感染的个体变得危急的可能性。这里不打算介绍越来越多的希腊字母,我们就叫它 p(I→C)吧。从逻辑上讲,从感染到康复的概率是 1-p(I→C)。
我们需要另一个概率,临界时死亡的概率:p(C→D)。同理,从感染到痊愈的概率是 1-p(C→D)。
现在我们只缺了感染后的重症率,重症时的死亡率,重症时的痊愈率。通过阅读目前的估计,我得到了以下数字(我从多个来源汇总了这些数字,可以随意使用不同的数字;随着时间的推移,应该会有更准确的数字):
- 从感染到危急的天数:12 天(→比率:1/12)
- 从危急到死亡的天数:7.5 天(→比率:1/7.5)
- 从危急到恢复的天数:6.5 天(→比率:1/6.5)
把这些都填进去:

分流和有限的资源
在意大利和其他受影响严重的地方,有很多关于分流的报道,这意味着医生必须在有限的可用资源中选择接受治疗的人。这可以被合并到如下模型中:
想象一下,一个国家拥有适合治疗严重冠状病毒病例的 B ICU 床位。如果有超过 B 的危重病人(数量是 C ,我们的危重车厢),所有在 B 以上的人都无法救治而死亡。例如,如果 B=500,C=700,那么有 200 名患者因为没有资源治疗而死亡。
这意味着 C-B 人因短缺而死亡。当然,如果我们的床位比重症病人多(例如 B=500,C=100),那么我们就不会有 C-B=-400 人死亡,这就说不通了。而是我们有 max(0,C-B) 人因为短缺而死(想想看:如果 C < B(床位比病人多),那么 C-B < 0,所以 max(0,C-B)=0,0 人因为短缺而死;如果 C > B(床位不够),那么 C-B > 0,所以 max(0,C-B)=C-B,C-B 的人因为短缺而死)。
因此,我们需要扩展我们的转换:从 C 开始,有两个我们必须关注的群体:max(0,C-B)人因为短缺而死亡,其余的人像我们上面推导的那样得到治疗。其余的是什么?嗯,如果 C < B(足够的床位),那么 C 人得到治疗。如果 C > B(床位不够),那么 B 人得到治疗。那就意味着“剩下的”——得到治疗的人数——是 min(B,C) (同样,如果 C < B,那么 min(B,C)=C 人得到治疗;若 C > B,则 min(B,C)=B 人得到治疗;数学检查)。
我们最终得到了这个修正的模型(所有超过可用床位数的人都会立即死亡;你可以把它改成花几天时间,以 75%的概率死去,等等。):

这些是它的方程式(注意床是时间的函数,我们一会儿就会讲到)

再一次,花些时间来看看这些方程是如何与上面的状态转换直接相关的。它们看起来很难,但它们只是描述图表的另一种方式。
时间相关变量
对于这个模型,我们只有两个与时间相关的变量:R₀(t(以及β(t),因为 R₀ = β / γ)和床位(t)。
对于 R₀(t),我们将再次使用以下逻辑函数:

对于床位(t ),这个想法是,随着病毒的传播,各国做出反应,开始建造医院,腾出床位,等等。因此,随着时间的推移,可用床位的数量会增加。一个(非常)简单的方法是将床位数量建模为

其中,Beds₀是可用的 ICU 病床总数,s 是某个比例因子。在此公式中,床位数增加了 s 倍,即每天的初始床位数(例如,如果 s=0.01,则在第 t 天=100,床位数(t) = 2 ⋅ Beds₀)
拟合模型
首先,让我们想想我们知道什么,我们想知道什么。这有助于我们找到哪些参数是我们可以修正的,哪些是我们想要拟合的。
这里是我们的模型需要的所有参数(这只是方程中的所有变量加上 R₀(t 函数中的变量)和 beds(t);):
- 总人口
- β(t): 感染者每天感染的预期人数
- γ: 感染者每日痊愈的比例(γ = 1/D)
- ****r₀_start(r₀(t 参数)
- ****r₀_end(r₀(t 参数)
- ****x₀(r₀(t 参数)
- ****k(r₀(t 参数)
- s (床中参数(t))
- ****beds₀(r₀(t 参数)
- δ: 潜伏期的长度
- p(I→C): 从感染到危急的概率
- p(C→D): 危急时死亡的概率
让我们来看一下这些:我们当然不需要去适应,我们可以只看我们想要建立疾病模型的地区的人口。Beds₀的情况也是如此,我们可以很容易地查找一个地区的 ICU 床位数(我已经用 Python 准备了所有的数据集来做这件事,我们将在下一节看到它们)。 δ 和 γ 固定为δ=1/9 和γ=1/3,这些是我通过论文阅读找到的最好的估算。关于 β(t) ,我们通过 R₀(t 和γ计算β,所以不需要为β寻找任何单独的参数。可以拟合床缩放因子s;不可否认,它在结果中并没有起很大的作用,因为到目前为止,由于短缺而没有接受治疗的人数与死亡总数相比是很少的。
我收集了概率 p(I→C) 和 p(C→D) 的两个估计值,按年龄分组(同样,我们将在下一节中讨论这些)。这将允许我们计算概率,就像我们在上一篇文章中推导的那样:按每个年龄组的人口比例加权。在这里,我们实际上将尝试拟合这些参数——直到现在,尝试拟合这些参数总是会产生非常接近收集的估计值的结果。
总而言之,我们只剩下这些参数来拟合:
- p(I→C)
- p(C→D)
- ****r₀_start(r₀(t 的参数)
- ****r₀_end(r₀(t 的参数)
- ****x₀(r₀(t 参数)
- ****k(r₀(t 的参数)
- s (床中参数(t))
补充和冠状病毒数据
我已经从联合国数据中收集并整理了年龄组、概率和 ICU 床位的数据。我们将从这里获取最新的案例号。让我们来看看:
首先,加载数据:
以下是从所有表格中摘录的内容,以便了解我们正在处理的问题:
- 床位表中有许多国家每 10 万居民的 ICU 床位数量。**
- 年龄组表显示了所有国家每个年龄组的人口数量。
- 概率表具有为每个年龄组的转变 I→C 和 C→D 收集的概率 I(两个独立的概率;仅使用 _1 或 _2)(我们不会使用它们,因为我们将尝试拟合转移概率)
- covid_data 是一个巨大的表格,显示了从 2020 年 1 月 22 日起每个地区每天的死亡人数。
例如,以下是全世界的总死亡人数:

并非所有国家和地区都包括在表中。然而,如果你想模拟一个没有包括在内的地区的爆发,你应该能够通过快速的谷歌搜索找到你需要的数据。
你可能已经注意到,我们只使用死亡人数的数据,而不是报告的病例数。原因很简单:确诊病例的报告非常嘈杂,而且很大程度上依赖于检测的数量(尽管有足够的检测,但并不是每个被感染的人都会接受检测)。例如,案例数量可能会从一天的 10000 增加到第二天的 15000,但这可能只是因为测试数量增加了 5000。总的来说,报道的死亡人数要准确得多——死亡人数很难被遗漏,所以报道的数字可能与真实数字非常接近。
编码模型
设置好所有数据后,我们现在可以开始编码我们的模型了。同样,这是方程式:

让我们把它们翻译成代码,就像在上一篇文章中一样(一个警告:我们在这里计算β有点简化,因为严格计算它会复杂得多,并且对结果的影响可以忽略不计;如果你好奇的话,你可以在这里看到扩展实现):
这实际上只是输入 Python 的方程式,没有什么令人兴奋的事情发生!现在,关于 R0 函数和整个模型,该模型采用参数拟合(有些我们已经知道)来计算 S、E、I、C、R 和 D 的曲线:
以下是我们在没有足够 ICU 床位的人群中模拟疾病时得到的结果(绘图功能在笔记本中):

在右下角的图表中,您可以看到由于资源短缺(没有足够的床位)导致的死亡人数激增。
对,我们现在有了模型和数据。让我们好好利用我们的曲线拟合技巧吧!
曲线拟合
首先,我们得到要拟合的数据和我们已经知道的参数,并且我们为那些我们不知道的定义初始猜测和上下限(以帮助曲线拟合并得到好的结果)——随意改变初始猜测和上下限。
一个非常重要但我们还没有谈到的参数是爆发 _ 转移:病例数据从 1 月 21 日开始,所以我们的模型会认为病毒在那一天开始传播。对于许多国家来说,这实际上可能是几天或几周之后或更早,这对试衣有很大影响。当然,我们仍然不知道每个国家第一个被感染的人是什么时候——用你最好的判断。例如,如果您认为您正在尝试适应的国家在 1 月 30 日出现了首例病例,您应该将 outbreak_shift 设置为-9。
(可悲的是,使用 outbreak_shift 作为附加参数并不容易,因为只允许整数(整天),整数编程相当困难(实际上是 NP 困难);我们将不得不求助于非常昂贵的计算。)
我们现在用零填充我们想要拟合的数据(每天的死亡人数),以说明疫情的变化。我们还定义了拟合的 x 值;这只是一个列表[0,1,2,…,总天数]。
为了进行拟合,我们需要一个函数,该函数将 x 值作为第一个参数(日期)和我们想要拟合的所有参数,并返回模型针对该 x 值和参数预测的死亡人数,以便曲线拟合器可以将模型预测与真实数据进行比较。这是:
没什么可做的了!只需初始化一个曲线拟合模型,根据我们定义的 inits、mins 和 maxs 设置参数,设置一个拟合方法(您可以在这里尝试不同的方法,例如, differential_evolution 可能效果不错),然后拟合:
最后,这是我们为意大利准备的服装:

不算太差!让我们看看装配工预测的参数:
太好了,它们看起来相当真实,并且与现实生活中报告的许多数据点一致!x0 是 84,所以数据从 1 月 21 日开始,爆发时间设置为 30 天,我们模型的第 84 天是 3 月 15 日。x0 是 R0 最急剧下降的日期,因此我们的模型认为主要的“锁定”发生在 3 月 15 日左右的意大利,非常接近真实日期。
让我们使用最佳拟合参数来看看我们的模型预测的未来(如果您查看笔记本中的代码,可以放大):

请注意,2020 年 3 月底左右,由于医院人满为患,死亡人数激增,增加了死亡率,最终约为 1.4%。
这是从 3 月到 5 月的放大预测——如果模型是正确的,意大利已经度过了最糟糕的时期,死亡人数在接下来的几个月应该会大幅下降。当然我们的模型认为 R0 会保持在 0.6 左右;如果它再次上升,锁定恢复,数字将再次开始增加!

概述
仅此而已!您现在应该能够(尝试)将您的模型与真实世界的案例数据相匹配,并有望做出准确的预测!在另一篇文章中,我们将为这样的模型构建一个仪表板,以实时查看不同参数的效果!
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
传染病建模:理解用于冠状病毒建模的模型
解释背景并从头推导 SIR 模型的公式。用 Python 对模型进行编码和可视化。

在过去的几周里,许多数据科学家、业余爱好者和爱好者开始阅读传染病建模。他们中的许多人直接进入建模,并盲目地将他们的模型与冠状病毒病例数相适应——而不了解模型背后的背景和理论。尽管由看起来令人生畏的数学组成,最广泛使用的模型——如果解释得好——并不太难理解。
这篇文章解释了背景,并介绍了传染病建模的主题。SIR 模型方程是从零开始用简单的例子推导和解释的。最后,用 Python 编写了一个简单的 SIR 模型。我的下一篇文章将关注基本 SIR 模型的更复杂的变体,并将使读者能够实现和可视化他们自己的变体和想法。另一篇文章将关注模型与现实世界数据的拟合,并将新冠肺炎作为案例研究。
背景
本系列并不意味着快速向你展示一些带有大量彩色曲线的图表,这些图表应该让你相信我的模型可以完美地预测世界各地的冠状病毒病例;相反,我将解释理解这些模型、形成自己对这些模型的看法以及实现自己的想法所需的所有背景。你只需要高中水平的微积分就能跟上解释;要理解编程部分,您需要对 python 有扎实的理解。
因此,记住这一点:
我们想建立传染病模型。这些疾病可以从一个群体传播到另一个群体;我们试图深入了解它们传播的速度,它们感染的人口比例,死亡的比例等等。模拟它们的最简单的方法之一(也是我们在这里关注的方法)是使用房室模型。分室模型将群体分成几个分室,例如:
- Sus 可接受(仍可被感染,“健康”)
- 我感染了
- 恢复(已经被感染,不能再被感染)
也就是说,我们可能有 N=1000 的人口(例如 1000 人),并且我们知道在时间 t(例如疾病爆发后 t=7 天)有 400 人被感染。这由 S(7) = 400 表示。SIR 模型使我们只需输入一些初始参数,就可以获得所有 t 天的所有值 S(t),I(t),R(t)。现在我将通过一个简单的示例来介绍必要的变量:
我们有一种新的疾病,x 病,对于这种疾病,感染者传染健康人的概率是 20%。一个人平均每天接触的人数是 5 人。因此,每天,一个被感染的人会遇到 5 个人,并以 20%的概率感染每一个人。因此,我们预计这个人每天会感染 1 人(20% ⋅ 5 = 1)。这是β(“beta”),一个感染者每天感染的预期人数。
现在人们可以看到,一个感染者拥有并能传播疾病的天数极其重要。我们称这个数字为 D 。如果 D=7,一个感染者四处走七天传播疾病,每天感染 1 人(因为β=1)。因此,我们预计一名感染者会感染 1⋅7(每天 1 人乘以 7 天)= 7 人。这是 R₀的基本繁殖数,一个感染者感染的总人数。我们只是用了一个直观的公式:R₀ = β ⋅ D
我们其实不需要别的,只需要一个小记号:γ(“gamma”)会是 1/D,所以如果你把 D 想成一个感染者患病的天数,你就可以把γ想成痊愈率,或者说感染者每天痊愈的比例。例如,如果目前有 30 人被感染,D=3(所以他们被感染了三天),那么每天,他们中的 1/3(所以 10)人会康复,所以γ=1/3。γ = 1/D,所以 D = 1/γ,R₀ = β ⋅ D,则 R₀ = β / γ。
在这里,您可以再次看到最重要的变量及其定义:
- N: 总人口
- S(t): 第 t 天易感人数
- I(t): 第 t 天感染人数
- R(t): 第 t 天康复人数
- β: 感染者每天感染的预期人数
- D: 一个感染者已经并可能传播疾病的天数
- γ: 感染者每日痊愈的比例(γ = 1/D)
- R₀: 一个感染者感染的总人数(R₀ = β / γ)
推导公式
我们现在想得到一整天的感染人数、易感人数、痊愈人数,仅仅从β、γ、n 就可以得到,现在很难得到一个直接的公式来表示 S(t)、I(t)、R(t)。然而,描述 S、I 和 R 的每日变化是相当简单的,即易感/感染/恢复的数量如何根据当前的数量而变化。同样,我们将通过示例推导公式:
我们现在处于疾病 x 爆发后的第 t 天。然而,一个感染者每天感染的预期人数是 1(所以β=1),一个感染者拥有和能够传播疾病的天数是 7(所以γ=1/7,D=7)。
假设 t 日,60 人被感染(所以 I(t)=60),总人口为 100(所以 N=100),仍有 30 人易感(所以 S(t)=30,R(t)= 100–60–30 = 10)。现在,S(t)和 I(t)和 R(t)如何变化到第二天?
我们有 60 名感染者。他们每人每天感染 1 人(那就是β)。但是,他们遇到的人,只有 30/100 =30%的人仍然易感,可以被感染(那就是 S(t) / N)。所以,他们感染了 60 个⋅人 1 个⋅人 30/100 = 18 人(再想想,直到它真正有意义:60 个感染者平均每天感染 1 人,但 100 人中只有 30 人仍会被感染,所以他们没有感染 60 ⋅ 1 人,而只有 60 ⋅ 1 ⋅ 30/100 人= 18 人)。所以,18 个易感者被感染,所以 S(t)变化负 18。代入变量,我们就导出了第一个公式:
第二天 S(t)的变化= - β ⋅ I(t) ⋅ S(t) / N
如果你熟悉微积分,你会知道我们有一个术语来描述函数的变化:导数 S'(t)或 dS/dt。(在我们推导并理解了所有的导数 S'(t),I'(t),R'(t)之后,就可以计算出每一天的 S(t),I(t),R(t)的值了。)
所以:S'(t) =- β ⋅ I(t) ⋅ S(t) / N
那么,感染的数量是如何变化的呢?这很简单:有一些新的人被感染,我们刚刚看到了这一点。“离开”S(t)“到达”I(t)的确切人数。因此,我们有 18 个新感染者,我们已经知道公式将类似于此:I'(t) = + β ⋅ I(t) ⋅ S(t) / N(当然,我们可以省略加号,这只是为了向您显示我们获得的量正好是 S(t)损失的量,因此我们只需改变符号)。只差一点:有些人会康复。记住,我们有γ,它是每天被感染恢复的比例,这正是我们需要的!
我们有 60 人被感染,γ=1/3,所以这 60 人中有三分之一康复了。那是 1/3 ⋅ 60 = 20。最后,我们得到公式:
I'(t) = β ⋅ I(t) ⋅ S(t) / N -γ ⋅ I(t)
再次,思考一下这个问题;第一部分是新感染的易感者。第二部分是追偿。
最后,我们来看最后一个公式,回收率的变化。这很简单:新恢复的正好是我们刚刚计算的 20 个;没有人离开“恢复”车厢。一旦痊愈,它们会保持免疫:
R'(t) = γ ⋅ I(t)
太好了,我们现在已经推导出(并且理解)了我们需要的所有公式!在这里,他们再次用一个更常见的符号表示导数,并像通常所做的那样省略了“(t)”。

这样的方程被称为常微分方程(ODEs) (你不需要任何关于它们的知识来理解这个系列)。
我们现在可以描述易感、感染和康复人数的 T2 变化。幸运的是,从这些公式中,我们可以计算出我们真正感兴趣的数字:S(t),I(t)和 R(t),即每天 t 中易感、感染和康复的人数。更幸运的是,我们自己一点也不需要做,python 提供了许多求解 ODEs 的工具!
编码模型
我们现在将编码并可视化一个示例模型。您可以随意复制代码和使用参数!我们首先定义一些参数:
我们现在实现我们上面推导的公式:
神奇的事情发生了:我们从函数 odeint 中得到我们的值 S(t)、I(t)和 R(t ),该函数采用我们上面定义的公式、初始条件以及我们的变量 N、β和γ,并计算 50 天的 S、I 和 R。
现在我们只需绘制结果并得出以下结论:

正如你所看到的,几乎 1000 人全部被感染只需要 30 天左右。当然,这里模拟的疾病具有非常高的 R₀值 4.0(回想一下,R₀ = β ⋅ D = 1.0 ⋅ 4.0)。仅仅将一个感染者每天感染的人数β改为 0.5,就会产生完全不同的情况:

如你所见,这些微分方程系统对初始参数非常敏感。这也是为什么很难正确模拟一种新疾病的爆发:我们不知道参数是什么,即使是微小的变化也会导致非常不同的结果。
结果
你现在应该对传染病建模的一些最重要的公式和思想有了坚实的掌握。对 R₀,β,γ等的理解。mean 使您不仅可以盲目地调整参数,还可以设计、改进和扩展您自己的模型。您现在应该能够理解接下来的部分了,在接下来的部分中,我们将更多地关注扩展现有的模型,并(在第 3 部分中)尝试对一个新出现的疫情进行建模。
传染病模型——基本原理
使用 R 中的简单二室模型的介绍

自古以来,传染病就一直困扰着人类。通常,传播是由宿主驱动的,然后宿主将感染传给其他个体。传染病模型的目标是捕捉这些传播动态。它们是对传染病传播的数学描述。
使用该模型,可以:
- 研究干预对疾病负担的影响
- 来预测不同干预的结果
一个简单的二室模型
考虑只有两个隔间的最简单的模型——感染(I)和恢复(R)。这个模型有助于我们回答以下问题:
人从 I 到 R 需要多久?(或从 I 到 R 的转换率)

假设:在任何时间点,I 区室中的每个个体都同样可能经历康复。
变速器动力学由以下微分方程控制:


上述方程的解是:


这里,γ代表回收率。γ值越高,恢复越快。
在隔室 I 中度过的时间以参数γ和平均值 1/ γ(平均传染期)为指数分布
在 R 中建立一个双室模型
R 中的 deSolve 包包含了求解一阶常微分方程组(‘ODE’)的初值问题的函数。
步骤 1 :定义感染和康复队列中的人数、康复率γ(γ=0.1)和随访持续时间(21 天)
initial_values<-c(I=10000,R=0) #10000 in infected cohort
parameters<-c(gamma=0.1)
time=seq(from=0,t=21,by=1)
第二步:指定模型功能
在模型函数中,指定微分方程。该函数有三个输入参数:
- 时间:我们希望求解模型的时间点
- 状态:存储每个时间点每个车厢的人数
- 参数:模型参数的名称和值
model_cohort<-function(time,state,parameters){
with(as.list(c(state,parameters)),{
dI=-gamma*I
dR=gamma*I
return(list(c(dI,dR)))
})
}
第三步:使用 deSolve 包中的 ode()求解模型
output<-as.data.frame(ode(y=initial_values,func = model_cohort,parms=parameters,times = time))
head(output)

我们看到输出是带有时间点的数据帧,即在每个时间点感染和恢复隔离室中的人数。
步骤 4:使用 ggplot2 绘制输出
out_long=melt(output,id="time") #To convert the dataframe to long formatggplot(data = out_long,
aes(x = time, y = value, colour = variable, group = variable)) +
geom_line() +
xlab("Time (days)")+
ylab("No: of people") +
labs(title = paste("No: infected and recovered for gamma = 0.1 days^-1"))+scale_color_discrete(name="State")

从图中,可以回答关于在每个时间点感染和恢复的人数的问题。平均传染期将是恢复率的倒数,即 1/0.1=10 天
改变伽马值
如果γ增加到比如说 0.5,我们观察到一半的感染群体在大约 2 天内恢复,而对于γ=0.1,需要大约 7 天。因此,γ值越大,恢复时间越短。

这个模型是基于相似原理的更复杂的房室模型的最简单的例子,比如 SIR 模型。在即将到来的帖子中会有更多关于它的内容:)
参考文献
- Soetaert,K. E .,Petzoldt,t .,& Setzer,R. W. (2010 年)。解 R 中的微分方程:包 deSolve。统计软件杂志, 33 。
- https://www . coursera . org/specializations/infectious-disease-modeling
通过观察专家来推断你的奖励
实现反向强化学习算法
照片由 Jehyun Sung 在 Unsplash 上拍摄
在强化学习(RL)中设计奖励函数可能很麻烦。很简单,我们的目标是采取行动增加未来的累积回报,并避免那些损害它的行为。然而,选择如何奖励现实任务中的行为,并以一种既可学又能表达代理人期望的目标的方式,并不简单。例如,如何将“可接受的”社会行为指定为一种功能?
逆向强化学习(iRL)是一种缓解这种设计问题的方法。我们没有试图自己设计一个奖励函数 r(s,a) ,而是让 RL 代理观察专家演示我们希望它学习的内容,并从他们的行为中推断专家的意图。通过这样做,代理使奖励函数符合专家的意图。
让我们深入研究一下。
我们的 iRL 实现将连接到生成敌对网络(GANs)。对于这一点,你会发现对【GANs 如何工作有一个基本的了解是非常有用的,尽管我在下面会做简要介绍。
RL 为 GAN
GANs 的快速细节
一个 GAN 由鉴别器 D 和发生器 G 组成。生成器旨在生成看起来尽可能接近训练中使用的真实图像的假图像。另一方面,鉴别器将给定的图像分类为真品或赝品。因此, D 和 G 都玩一个游戏,其中 D 试图最大化它正确地将输入 x 分类为真或假,和 G 最小化 D 将其输出标记为的可能性
实现这一点的损失函数是 D 和 g 输出的对数。
GAN 损失函数
其中:
- D (x) —鉴别器预测 x 为真/假
- G (x) —发电机输出
- D ( G (x)) —鉴别器对发电机输出的预测
我们可以将这一培训过程描述如下:
甘的作品(作者插画)
gan 与反向 RL 的关系
反向 RL 使用 GANs 的鉴别器的概念。iRL 中的鉴别器是政策和奖励函数的比率。我们一会儿就能看到它的全貌。
与 GAN 中的假图像和真图像相似,iRL 有两组数据——专家演示和策略与环境交互生成的过渡数据。两个转换集都包括状态-动作对,直到一个有限的时间步长 T (s₀,a₀,s₁,a₁,…,sT,aT)。将 iRL 与 GANs 联系起来,专家论证可以说是真实数据,而政策收集的样本是虚假数据。这意味着该策略现在充当生成器。
iRL 为 GAN(修改自 来源 )
鉴频器的目标以与 GAN 中相同的方式表示。
iRL 中鉴别器的最小最大物镜
该目标函数的第一部分试图增加所看到的样本是专家演示的可能性。第二部分降低了样本被正在运行的策略收集的可能性。
实现对鉴别器的培训
正如所看到的,训练鉴别器的目的是最大化输入正确分类为真或假的概率。为此,我们最大化损失函数:
iRL 鉴别器损耗函数
在实施中,这可以通过两个简单的步骤实现:
1.样本批专家轨迹τET20,正向通过D计算损耗log(D(τE))。
2.对收集到的一批策略轨迹 τF,顺传D进行采样,计算损失log(D(τF))。这里,我们避免做(最小化)log(1—D(τF))因为这无法在学习过程中提供足够的梯度。所以我们最大化log(D(τF))来代替。
代表 iRL 中的鉴别器
鉴别器 D 是奖励函数 r :
iRL 中的鉴别器:指数奖励函数与学习策略的比率
ψ代表奖励函数的可学习参数。作为学习奖励的函数,鉴别器也使用参数ψ。
更新鉴别器 D 更新学习的奖励函数 r(τ) 。当鉴别器是最优的,我们得到一个最优的回报函数。然而, r(τ) 以上的奖励函数在奖励的估计中使用整个轨迹 τ 。与使用单个状态、动作对 r (s,a)相比,这给出了较高的方差估计,导致较差的学习。
使用单个状态-动作对将解决高方差估计问题,但是也有一个缺点——它使得最优奖励函数与最优策略提出的监督动作严重纠缠。换句话说,习得的奖励会鼓励模仿专家的政策,当环境发生变化时,不能产生明智的行为。
这就是我们对鉴频器的最后改进。
创建一个解开的奖励函数
为了提取从环境中分离出来的奖励,对抗性逆 RL (AIRL)提出用这种形式修改鉴别器:
使用单个【状态-行动对】作为输入的鉴别器
我们可以进一步简化奖励函数 r(s,a,s’)为:
对抗性反 RL 奖励功能恢复优势
它现在由以下部分组成:
- g(s,a):估计状态-动作对的回报的函数逼近器。它被表达为只有状态 g(s)的函数,以将奖励从环境动态中分离出来
- h(s):控制 g(s)上不需要的整形的整形术语
下面是代码中的鉴别器和奖励函数。
g(s)收回最优报酬;h(s)类似于一个价值函数。

从学习的奖励函数中恢复优势 A(s,A)
这意味着 r(s,a,s’)恢复了优势。这就是有趣的地方。
执行策略更新
策略更新包括找到策略的对数的梯度乘以优势。
政策梯度更新*
在 iRL 中,由于我们没有观察到评估优势时使用的环境奖励,更新期间的更改将使用奖励函数来估算这些优势。更简单地说,由奖励功能恢复的优势在策略更新中找到用途。
在 iRL 中使用优势评估进行政策更新*
为了对 iRL 有一个直观的概述,这里有一个普通政策梯度(VPG)和应用于 VPG 的反向 RL 之间的整个伪代码的并排比较。
普通政策梯度(VPG)比较了 VPG 和反向 RL*
策略 π 被训练来最大化这个估计的回报 r(s,a,s’),并且当被更新时,学习收集与专家演示更难区分的轨迹。
运行反向 RL
反向 RL 培训的第一步是运行基于策略的 RL 算法来收集专家演示。我从两个方面着手:
- 收集最后 n 个策略更新的轨迹。例如,如果训练 250 个纪元,收集 230–250 个(最后 20 个)。这是 AIRL 论文中的方法。
- 收集平均剧集奖励高于某个奖励阈值的轨迹
上述两种收集专家数据的方法在反向 RL 平均回报方面似乎没有显著差异(至少在 250 个时期内)。我对此的解释是,( b)中的奖励阈值收集了(a)中看到的大部分发生在最后训练阶段的轨迹。
这里是在 HalfCheetah-v2 上的 iRL 在 100 个步骤上的平滑性能,使用了来自五个最终时期的专家数据。
iRL 策略和使用观察奖励的相同策略的半猎豹奖励比较。*
完整的 iRL 实现和复制细节在https://github.com/mugoh/rl-base/tree/master/rlbase/aiRL上。
下面是用于收集这些演示的策略的单次运行示例。
收集专家论证*
结论
反向强化学习允许我们向代理演示期望的行为,并试图使代理从演示中推断出我们的目标。将这个目标与演示结合起来可以恢复奖励功能。然后,收回的奖励鼓励代理人采取与专家试图实现的意图相似的行动。
恢复意图的好处是代理学习达到目标的最佳方式——它不会盲目模仿专家的次优行为或错误。因此,与专家策略相比,iRL 承诺了更理想的性能。
资源
反向 RL 知识库:Github 上的 air
关于反向 RL 的更多方法,请看这些作品:
[1] C. Finn、P. Christiano、P. Abbeel 和 S. Levine。生成对抗网络、逆向强化学习和基于能量的模型之间的联系,NIPS,2016。
[2] J. Fu,K. Luo,S. Levine,用对抗性逆强化学习学习鲁棒报酬,2018。
[3] X .彭,a .金泽,s .托耶,p .阿贝耳,s .莱文,变分鉴别器瓶颈:通过约束信息流改进模仿学习,逆 RL,和 GANs,,2019。
起点-终点流量和活动位置的推断
利用呼叫详细记录来推断移动性模式的一些主要技术的文献综述

移动建模的一个关键部分是推断用户的行程。当我们谈论旅行时,我们谈论的是在起点和终点之间的旅行,最终以一项活动结束。Calabrese 等人[1]探索了观察数据的使用,以计算这些 OD(起点-终点)流量。Wang 等人[2]做了同样的工作,但是使用了交通方式选择的概率、车辆占用率和呼叫详细记录。Yang 等人[3]表明,通过生成算法,如贝叶斯网和马尔可夫随机场分类,可以以合理的精度检测活动位置,如家、工作、购物、休闲和其他地方。
融合 cdr 和来自交通传感器的数据,Charisma 等人[4]能够开发 OD 矩阵。不同位置的交通流量计数用于验证起点-终点预测。为了确定真实的始发地-目的地,有必要对瞬时 OD 矩阵进行缩放,以匹配实际交通流。本研究的中心假设/限制在于:它忽略了“不同地点通话速率的异质性(例如,与使用固定电话线路的办公室相比,来往于火车站的通话可能更多,等等)。)".Augusto 等人[5]使用非监督学习算法,尝试从用户的 cdr 推断用户的出行,然后从出行行为中描述人口的移动性(例如,通勤者的百分比是多少,或者他们中有多少人在离家很远的地方工作)。
赵等人[6]的研究引人入胜,因为它提出了一种监督学习技术来获得用户出行的更详细特征。这暗示了一个被那些试图描述用户旅行的起点和终点的人严重忽视的问题。我们正在讨论检测除了那些通过查看 cdr 可以看到的地方之外,是否还有未知的访问过的地方。其解决方案依赖于 CDRs、SMSs 和移动互联网接入之间的数据融合技术,以形成标记数据,这些数据将成为训练和测试分类器的基础。所使用的数据集包含了 2013 年 11 月中国某城市 300 万用户的记录。然而,只有 100,000 名用户被随机选中。随着他们进行数据融合,这个数字下降得更多。这是因为只对使用移动互联网接入并在一个月内至少拨打/接收一次电话/短信的用户感兴趣。
整篇论文评估了三种不同方法的性能:人工网络、支持向量机和逻辑回归。本文不仅有助于更深刻地理解如何从移动计费数据中更准确地提取出行,而且有助于解决使用 CDR 数据获取用户路线的一个众所周知的问题——时间稀疏性。在大多数情况下,用户不会在他访问的每个位置拨打或接听电话,因此从 cdr 中提取不现实和不完整行程的概率很高。因此,提出了一个框架,其方案如图 1 所示。

图 1 —赵等人[6]使用的框架的总体方案。这个人物是他们改编的。
在这种情况下,我们有四层,正如我们在上面的图像右侧看到的那样(网络传感器、用户位置、移动状态和移动性)。第一层本质上是我们可以从 CDRs 获得的信息:被观察用户收到或发出呼叫的位置和时间。在一些本地化过程封装了子采样方法和位置不确定性和误差的处理之后,我们提出了用户存在,它是用户位置层的一部分。之后,是时候识别活动停止点了——也被作者命名为观察到的访问。每次两个连续的观察到的访问发生在不同的位置,我们就有一个位移。这两个元素的识别是通过一个运动状态识别来完成的,它把我们弹射到运动状态层。最后,本文更大的贡献——考察是否在每一次置换中我们都有一次隐藏的访问。这是通过前面提到的机器学习算法进行的,并构成了隐藏访问推理过程。一旦我们得到了未知站点和观测站点,我们就形成了 OD 出行,组成了我们的移动层。
将隐藏访问推理视为二元分类。对于位置 A 和 B 之间的每个位移:A)有一个隐藏的访问过的地方,或者 B)没有隐藏的访问过的地方。并非所有观察到的访问都进行了分析,而只是位移,这构成了本研究的局限性。这是一个限制,因为作者假设用户在两个(和相同的)观察到的访问站点之间的时间内不能访问任何不同的地方。因此,基本思想是使用 cdr 和 SMS 记录来提取特征,而来自移动互联网接入的数据被用作标签,作为地面真实数据。图 2 描绘了同一用户在一段时间内所做的位移序列,但是通过同一时间不同类型的数据(来自 cdr 和移动互联网访问)来观察。正如我们所看到的,有两种类型的用户转移需要更深入的分析。在情况 1 中,当通过 CDR 数据看到用户从 C 移动到 D 时,我们注意到移动互联网访问数据(MIAD)封装了隐藏的访问位置(W)。然而,在情况 2 中,尽管 MIAD 现有两个额外的记录,这些记录给出了流离失所目的地的同一地点(F)。因此,在这种情况下,不会显示额外的访问位置。

图 2 —两个不同数据源在相同时间窗内访问过的地点。该图改编自赵等人的工作[6]。
在此,从 cdr 中提取和选择几个特征:位移的空间特征、时间特征和用户的个人特征(例如,语音呼叫的数量或活动呼叫小时的数量)。测试了四种方法:一个简单的规则,假设没有隐藏的访问过的地方;逻辑回归;SVM(支持向量机)和人工神经网络(人工神经网络)。所有三个分类器都可以将 OD 旅行的正确分类提高 10%左右,无论是否隐藏了访问过的地点(与原始规则相比)。通过使用人工神经网络,有可能将该值增加到最大值 11.1%。
Bayir 等人[7]的研究是试图检测 OD 旅行中隐藏访问的极少数研究中的另一个。然而,他们试图施加时间约束或阈值。例如,如果两个不同的观察位置之间经过的时间高于某个阈值(例如 10 分钟或 1 小时),则假设在这两个不同的观察位置之间存在未知的访问位置。事实上,这是一个非常幼稚的解决问题的方法,因为我们最终会得到过多的与现实不符的旅游景点。原因是我们假设用户每隔 x 分钟(其中 x 是我们的阈值)强制性地访问至少一些新站点。因此,理论上,统计学习方法可以超越我们在这种情况下可以使用的任何启发式方法的效率。
在这个问题上,另一个值得注意的研究工作来自 Demissie 等人[8]。这项研究假装也使用 cdr 来估计用户从塞内加尔出发的旅行的起点和目的地。通勤和其他不规则的行程是推断出来的。将塞内加尔作为案例研究的国家很有吸引力,因为它提供了一个机会来展示交通基础设施薄弱的国家如何利用移动运营商的数据来推断移动行为,从而改善交通基础设施。为了辨别像工作场所和家庭这样的重要场所,他们分别检查了在以前定义的工作时间(从早上 8 点到晚上 7 点)和非工作时间(从晚上 7 点到早上 8 点)(总是在工作日)有呼叫活动的位置。
尽管前景看好,这项研究还是有一些局限性。为了逃避处理隐藏的访问地点,推断的地点是在地区一级。因此,没有提供对应于家庭或工作场所的蜂窝塔的精确位置。除了这种不方便,这只是推断跨地区的通勤位移;没有获得详细的通勤路线。此外,数据可以具有更大的时间窗口。虽然 cdr 涉及适当数量的用户(900 万)和记录(4300 万),但只分析了 2013 年 1 月的 cdr。
Jundee 等人[9]的论文也是值得注意的。一旦它提出两种不同的技术来推断通勤旅行中的确切路线(家到工作场所和工作场所到家),它就是创新的。为了正确检测这些通勤位置,进行了二次采样,因此“每个用户在早上通勤时间(上午 7 点-11 点)必须至少有 100 个连接,在晚上通勤时间(下午 3 点-7 点)必须有 100 个连接。”作者使用谷歌地图 API 来推断可能的通勤路线。利用之前估计的工作场所和家庭位置,他们让谷歌地图平台生成它认为每个用户最有可能的通勤方向。从这里开始,只需要应用一个方法,使我们能够在 API 建议的选项中选择正确的路线。现在正是需要前面提到的两种技术的时候。第一种是最小距离法。因此,假设我们正在计算从家到工作场所的确切路线,然后我们继续寻找在早晨激活的呼叫和各自的基站。其次,我们必须计算每条路线的 google API 给出的每个航路点与激活的每个基站之间的欧几里德距离。之后,我们对每个航点和每个基站获得的所有欧几里德距离求和,并除以航点的数量。之后,我们应该对 Google Maps API 建议的所有路线重复这个过程。最后,我们选择具有先前计算的和的较小值的路径。
在这一过程中,必须解决一个重要问题。API 给出的路点沿路线的距离并不相等,并且路径的路点数量可能不同。实际上,这意味着,例如,我们将拥有不同的点密度,这将导致计算不同数量的距离,从而扭曲结果。图 3 说明了这个问题。这表明我们试图计算航路点和基站之间的距离,因此,在路线的弯曲部分有更密集的红色区域。首先,添加一个网格并将其用作插值和外推航路点的参考。这个网格允许它们之间的空间标准化。对于每个路点,我们创建一个新的数据点,它将是单元网格的质心。图 4 举例说明了这个过程。

图 3——最小距离方法的直观表示。红线代表每个航路点和基站之间的欧几里德距离。每个红色圆圈代表检测到呼叫活动的基站。该图最初来自 Jundee 等人[9]。

图 4 —航路点插值和相应网格的可视化。该图最初来自 Jundee 等人[9]。
作者提出的第二种替代方法是最大重叠的方法。调用 Google Maps API 和插入给定点的步骤仍然存在。然而,我们不需要计算欧几里得距离,而是需要查看在路线中有多少个点落入基站覆盖区域。从图 5 中可以看出,具有更多点的路线是被选择的路线。

图 5-最大重叠方法。在绿色部分,我们有一个基站,可以检测到呼叫活动。该图最初来自 Jundee 等人[9]。
尽管这两种技术很有前途并且令人耳目一新,但是它们没有考虑每个基站位置的用户的呼叫频率。令人感兴趣的是,对活动较少的位置给予较低的重要性,而对那些呼叫活动被更定期地登记的位置给予较高的权重。
参考
[1] F. Calabrese 和 G. Di Lorenzo,“使用移动电话定位数据估计起点-终点流量”,第 36–44 页,2011 年。
[2] U. Areas,“了解城市地区的道路使用模式”,2012 年。
[3] Y. Yang,P. Widhalm 和 M. C. Gonz,“使用稀疏手机数据提取和标记移动性序列”,第一期,第 4276-4277 页。
[4] F. Charisma 和 M. C. Development,“利用移动电话通话数据开发起点-终点矩阵”麻省理工学院的教员公开发表了这篇文章。请分享引用访问 Citable 链接详细条款基于模拟的方法,“2018。
[5] G .奥古斯托等,“工作之旅:使用 CDR 估计海地主要大都市地区通勤模式的起点和终点”, Dev .英语。,第 3 卷,2017 年 10 月号,2018 年第 133–166 页。
[6] Z. Zhao,J. Zhao,H. Koutsopoulos,“基于监督统计学习的使用详细记录数据的个人级出行检测”,2016 年。
[7] M. Bayir、M. Demirbas 和 N. Eagle,“移动性分析器:发现移动用户配置文件的框架”,2014 年 3 月号。
[8] M. G. Demissie、F. Antunes 和 C. Bento,“利用移动电话数据推断始发-目的地流量:塞内加尔案例研究”,2016 年 7 月号。
[9] T. Jundee,“使用 CDR 数据推断通勤流量:葡萄牙里斯本的案例研究”,2018 年。
来自 TF Lite 模型的推论——基于预训练模型的迁移学习
在预先训练的 Tensorflow 模型上使用迁移学习创建一个 Tf Lite 模型,优化它,并运行推理。
在本文中,您将学习使用预先训练的模型,应用迁移学习,将模型转换为 TFLite,应用优化,并从 TF Lite 模型中进行推理。

先决条件:
张量流 2.0
创建数据集
我已经下载了数据集,并按照下面的结构解压文件。
用于提取数据并按照以下结构创建数据的 Python 代码在此处可用。

导入所需的库
**from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPooling2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from tensorflow.python.keras.applications import imagenet_utils
from tensorflow.python.keras.layers import Dense,GlobalAveragePooling2D
from tensorflow.keras.applications import DenseNet121
from tensorflow.python.keras.applications.densenet import preprocess_input
from tensorflow.keras.models import Model**
设置培训的关键参数
**BASE_PATH = 'Data\\dogs-vs-cats\\train\\'
TRAIN_PATH='Data\\dogs-vs-cats\\train_data\\'
VAL_PATH='Data\\dogs-vs-cats\\validation_data\\'****batch_size = 32
epochs = 60
IMG_HEIGHT = 150
IMG_WIDTH = 150**
重新缩放并对训练图像应用不同的增强
**train_image_generator = ImageDataGenerator( rescale=1./255, rotation_range=45, width_shift_range=.15, height_shift_range=.15, horizontal_flip=True, zoom_range=0.3)**
重标验证数据
**validation_image_generator = ImageDataGenerator(rescale=1./255)**
为训练和验证数据集生成批量归一化数据
**train_data_gen = train_image_generator.flow_from_directory(batch_size = batch_size, directory=TRAIN_PATH, shuffle=True, target_size=(IMG_HEIGHT, IMG_WIDTH), class_mode='categorical')****val_data_gen = validation_image_generator.flow_from_directory(batch_size = batch_size, directory=VAL_PATH, target_size=(IMG_HEIGHT, IMG_WIDTH), class_mode='categorical')**
在预先训练的模型上应用迁移学习
您可以使用任何一种预训练型号。我用过 DenseNet121,有 427 层。
# Create the base model from the pre-trained model MobileNet V2
**base_model = tf.keras.applications.DenseNet121(
input_shape=(IMG_WIDTH, IMG_HEIGHT,3), include_top=False, weights='imagenet')**
冻结基础预训练模型的所有权重,并在预训练模型的顶部添加几个层
**base_model.trainable = False
x=base_model.output
x=Flatten()(x)
x=Dense(512,activation='relu')(x)
output=Dense(2,activation='softmax')(x)
model=Model(inputs=base_model.input,outputs=output)
model.summary()**

您可以看到预训练模型的权重是不可训练的,只有添加的层权重是可训练的。
您可以使预训练模型权重的几个层成为可训练的,以帮助学习自定义数据集,从而获得更高的准确性。
**TRAINABLE_LAYERS= len(model.layers)-len(base_model.layers)+5
print(TRAINABLE_LAYERS)
for layer in model.layers[:-TRAINABLE_LAYERS]:
layer.trainable=False
for layer in model.layers[-TRAINABLE_LAYERS:]:
layer.trainable=True**

您可以看到可训练参数的数量增加了,这也将增加训练时间。
在自定义数据集上编译和训练模型
**model.compile(loss='categorical_crossentropy', optimizer=tf.keras.optimizers.RMSprop(lr=2e-5), metrics=['acc'])****epochs=20
step_size_train=train_data_gen.n//train_data_gen.batch_size
history =model.fit_generator(generator=train_data_gen,
steps_per_epoch=step_size_train,
epochs=epochs)**

在模型被编译和训练之后,我们现在可以开始将模型转换为 TF Lite,如下所示。
将预训练的转移学习模型转换为 TF Lite

来源:https://www.tensorflow.org/lite/convert/index
训练完模型后,您现在需要保存模型。
保存的模型将模型的架构、权重和偏差以及训练配置序列化到一个文件中。保存的模型可以很容易地用于共享或部署模型。
#save your model in the SavedModel format
**export_dir = 'saved_model'
tf.saved_model.save(model, export_dir)**
SavedModel 包含一个完整的 TensorFlow 程序,包括权重和计算。
saved_model 是保存在 export_dir, 上的元图,使用 lite 转换为 TFLite 模型。TFLiteConverter 。
# Converting a SavedModel to a TensorFlow Lite model.
**converter = tf.lite.TFLiteConverter.from_saved_model(export_dir)
tflite_model = converter.convert()**
将平面缓冲区 TFLIte 模型写入二进制文件,当前大小为 61 MB。
open("model_tl.tflite", "wb").write(tflite_model)

优化模型
边缘模型需要是轻量级的,并且具有低延迟来运行推理。轻量级和低延迟模型是通过减少预测所需的计算量来实现的,这是通过对 TF Lite 模型应用量化优化来实现的。
量化降低了用于表示张量流模型不同参数的数字的精度,以使模型轻量化。
量化应用于权重和激活。
**optimize="Speed"
if optimize=='Speed':
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_LATENCY]
elif optimize=='Storage':
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
else:
converter.optimizations = [tf.lite.Optimize.DEFAULT]**#reduce the size of a floating point model by quantizing the weights to float16
**converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()**#save the quanitized model toa binary file
**open("model_quant_tl.tflite", "wb").write(tflite_quant_model)**

量化 TF Lite 模型的大小
这里,我们针对速度优化了模型,然后将 32 位浮点转换为 16 位浮点,以减小模型的大小。
在应用优化后,TF Lite 型号的 61 MB 现在减少到 30MB。
优化后的模型可以部署到任何我们需要的边缘设备TF lite _ runtime . interpreter
在边缘运行推论
用优化的加载解释器。包含模型的执行图和分配张量的 tflite 模型
**import tflite_runtime.interpreter as tflite**
# Load TFLite model and allocate tensors.
**interpreter = tf.lite.Interpreter(model_content=tflite_quant_model)**#allocate the tensors **interpreter.allocate_tensors()**
得到输入和输出张量。
#get input and output tensors
**input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()**
对输入数据进行预处理
我们想要进行推断的输入图像需要与模型的输入数据相匹配。
读取图像,解码为张量并将图像预处理为所需的大小,转换为 float16 并添加批量维度
**import cv2**# Read the image and decode to a tensor
**image_path='Data\\dogs-vs-cats\\test1\\151.jpg'
img = cv2.imread(image_path)
img = cv2.resize(img,(IMG_WIDTH,IMG_HEIGHT))**#Preprocess the image to required size and cast
**input_shape = input_details[0]['shape']
input_tensor= np.array(np.expand_dims(img,0), dtype=np.float16)**
下面是我们试图预测的图像

狗对猫\test1\151.jpg
运行推论
通过设置张量将输入数据指向第 0 个数组以输入张量。通过调用解释器来运行推理
*#set the tensor to point to the input data to be inferred*
**input_index = interpreter.get_input_details()[0]["index"]
interpreter.set_tensor(input_index, input_tensor)***#Run the inference*
**interpreter.invoke()
output_details = interpreter.get_output_details()**
为我们的图像分类解释输出张量
**output_data = interpreter.get_tensor(output_details[0]['index'])
results = np.squeeze(output_data)
top_k = results.argsort()****for label, idx in train_data_gen.class_indices.items():
if top_k[idx]==1:
print("Prediction: " label)**

输出是狗。
结论:
对预训练模型使用自定义或预训练或应用迁移学习,保存模型,将模型转换为 TFLite 平面缓冲文件,针对延迟或存储进行优化,然后使用 TF Lite 解释器进行推理。
推断统计学:数据分析
统计学是数据科学中的基本主题之一,它提供了更深入了解数据的工具和方法。

图片由皮克斯拜的 Gerd Altmann 提供
数据科学家必须对统计学有更深入的理解,才能对给定的数据进行定量分析。尤其是构建机器学习算法,统计学发挥了重大作用。统计数据主要有两种类型。
- 描述统计学
- 推理统计学。
在之前的文章 探索性数据分析 中,“我们所做的所有分析,都是描述性统计。使用描述性统计,我们只是描述数据中存在或显示的内容。我们已经了解了如何使用各种方法和可视化技术来发现给定数据中的模式。
通过推理统计,我们试图得出超越数据的结论。有时,我们必须处理大量数据进行分析,这可能会花费太多的时间和资源。在这些情况下,我们使用推断统计。
推理统计:
推断统计学通过考虑原始数据中的样本数据,对大量数据进行推断和预测。它使用概率来得出结论。
从样本数据中“推断出见解的过程称为“推断统计学”
“推理统计学”的最佳现实例子是,通过天气预报预测下个月的降雨量。
为了理解推断统计,我们必须对概率中的以下基本主题有基本的了解。
- 概率的基本定义
- 概率的乘法法则
- 概率的加法法则
- nCr(组合)
我们可以在这里练习基本动作,
- 数学很有趣
- Mathopolis
随机变量:
让我们举一个赌场吃角子老丨虎丨机的真实例子。赌场如何确保他们的老丨虎丨机长期不赔钱?
这很简单。他们使用概率。
为了理解这一点,我们来玩个游戏,
- 拿一个装有 3 个红色球和 2 个蓝色球的袋子。
- 游戏是这样的,我们必须从袋子里挑选一个球,记下它的颜色,然后把球放在袋子里,再从袋子里挑选一个球,记下它的颜色,然后把它放进去。重复此过程共 4 次。这整个过程是一套。
- 进行该实验 75 次,即 75 组。
- 条件是,如果我们连续抽取红球四次,即集合包含所有红球,那么我们将获得$150。否则,我们将不得不向经销商支付 10 美元。
看看我们玩这个游戏,庄家长期是赢还是亏。为了理解这一切,我们将分三步来解决这个问题。
- 找出所有可能的结果。
- 求每个结果的概率。
- 使用概率,估计利润/损失。
1。可能的结果
让我们看看,如果我们从袋子里抽出一个球四次,我们能得到的所有可能的结果是。
- RRRR
- RBRR,RRBR,RRRB
- BBRR、BRBR、巴西、RBBR、巴西、RRBB
- BBBR,BBRB,BRBB,RBBB
- 双侧束支传导阻滞
总共有 16 种可能的结果。
2。每种结果的概率
明智的做法是量化结果,计算概率。通过使用“随机变量”,我们将量化结果。
随机变量:
- “X”表示随机变量。
- “X”的定义取决于我们的问题陈述。这里,我们感兴趣的是从袋子中抽出的红球的数量。
X =抽取的红球数量。
用 X 表示的可能结果是,
- RRRR——X = 4
- RBRR,RRBR,RRRB--X = 3
- BBRR、BRBR、巴西、RBBR、巴西、RRBB--X = 2
- BBBR,BBRB,BRBB,RBBB--X = 1
- BBBB——X = 0
因此,基于 X 值,我们可以说,如果 X=4,玩家赢得游戏,而对于剩余的所有 X 值,玩家输掉游戏。
在进行了 75 次实验后,将值存储在 excel 中,让我们将结果绘制成柱状图,我们会得到类似这样的图表,
这些值看起来像这样,

现在,表格的直方图看起来像这样,

概率的定义是
概率(P) =(有利结果)/(结果总数)
现在,让我们根据上图找出不同 X 值的概率。
P(X = 0)= 2/75 = 0.027
P(X = 1)= 12/75 = 0.160
P(X = 2)= 26/75 = 0.347
P(X = 3)= 25/75 = 0.333
P(X = 4)= 10/75 = 0.133
如果我们用表格来表示它们,它看起来像这样

概率分布
这张表被称为概率分布。
3。使用概率,估计利润/损失
既然我们现在知道了 X=0 到 4 的概率,让我们来计算一个玩家在一场游戏中抽取的红球总数。
0 红球玩家数= P(X = 0)* 75 = 2.025
1 红球玩家数= P(X = 1)* 75 = 12
2 红球玩家数= P(X = 2)* 75 = 26.025
3 红球玩家数= P(X = 3)* 75 = 24.975
4 红球玩家数= P(X=4)*75 = 9
于是,我们大概看到了游戏中 75 位玩家抽出的 178.875 个红球。
红球平均数= 178.875/75 = 2.385。
换句话说,我们可以期待一个玩家每局抽 2.385 个红球。该平均值称为预期值。
从数学上讲,对于一个随机变量 X,它可以取值 x1,x2,x3,……..,xn,期望值(EV)由下式给出:
EV(X)= x1∫P(X = x1)+x2∫P(X = x2)+x3∫P(X = x3)+………..+xn∫P(X = xn)
对于我们的游戏,n=4,
EV = 1 * 0.16+2 * 0.347+3 * 0.333+4 * 0.133 = 2.385。
如果我们还记得的话,在我们的游戏中,如果 X=4 ,玩家将获得150 美元,而对于剩余的所有 X** 值,玩家需要支付10 美元。**
现在,玩家得到 150 美元的概率等于玩家抽到四个红球的概率。
这意味着,对于剩余的所有情况,玩家必须支付 10 美元。
所以,X 可以取+150 和-10 的值
P(X=+150) = P(4 个红球)= 0.133
P(X=-10) = P(0、1、2 或 3 个红球)= 0.027+0.160+0.347+0.333 = 0.867
现在,X 的期望值(其中 X 是玩一次游戏后赢得的钱)
EV(X)= 150 * 0.133+(-10)* 0.867 =+11.28
这意味着,从长远来看,玩家平均可以从这场游戏中赢得+11.28,这对玩家来说非常好,但这种模式对游戏组织者来说是行不通的,因为他们正在赔钱。
如果赌场想要赚钱,他们需要确保玩家的期望值为负。为此,组织者不得不改变奖金,比如获胜的玩家可以获得100 美元的奖金,如果玩家输了,可以获得25 美元的奖金。
现在,EV(X)= 100 * 0.133+(-25)* 0.867 =-8.375
从长远来看,这种模式对赌场是有利可图的。
到目前为止,我们已经看到了如何通过实验来计算概率。在下一节中,我们将看到如何在没有实验的情况下计算概率。
从理论上计算概率
如果我们回忆一下问题陈述,袋子里有 3 个红球和 2 个蓝球。
得到 1 个红球的概率=(红球总数)/(球总数)= 3/5 = 0.6
同样的,
得到 1 个蓝球的概率= 2/5 = 0.4
计算一局抽中红球的概率,即,
对于 X=0,P(4 蓝)= 0.40.40.4*0.4 = 0.0256
对于 X=1,P(1 红 3 蓝)= 0.60.40.40.4,但是对于 1 红 3 蓝有 4 种组合,
最后,对于 X=1,P(X) = 4(0.60.40.40.4) = 0.1536
对于 X=2,P(X)= 6(0.6 * 0.6 * 0.4 * 0.4)= 0.3456
对于 X=3,P(X)= 4(0.6 * 0.6 * 0.6 * 0.4)= 0.3456
对于 X=4,P(X) = 0.60.60.6*0.6 = 0.1296
让我们看看实验和理论概率分布的直方图是什么样的,

作者图片
正如我们所看到的,概率的理论(计算)值与实验值相对接近。存在微小的差异是因为进行的实验数量很少。
二项式概率分布:P(X=r)
现在,让我们试着把上面的问题再推广一些。假设从袋子里抽出一个红色球的概率= P。现在,从袋子里抽出一个蓝色球的概率= 1-P。
现在,概率分布将会是,
对于 X=0,P(4 蓝)= (1-P)⁴
对于 X=1,P(1 红 3 蓝)= 4P(1-P)
对于 X=2,P(2 红 2 蓝)= 6*P (1-P)
对于 X=3,P(3 红 1 蓝)= 4P *(1-P)
对于 X=4,P(4 红)= P⁴
如果我们仔细观察上述概率值,我们可以观察到某种类型的公式,
公式看起来像这样,

二项式概率公式
这里,
n =总试验次数
p =成功概率
r = n 次试验后的命中次数
但是,我们应该使用二项分布,只有当它遵循这三个条件。
- 这个问题应该有固定的试验次数。
- 每次试验应该只有两种结果——要么成功,要么失败。
- 在所有的试验中,成功的概率应该是相同的。
这种二项式概率分布是离散随机变量中非常常见的一种概率分布。
累积概率:F(x)
X 的累积概率用 F(x)表示。定义为一个变量小于或等于 x 的概率。
F(x) = P(X≤x)
所以,对于我们游戏的理论概率分布,如果我们计算 F(3),它将是,
F(3)= P(X≤3)= P(X = 0)+P(X = 1)+P(X = 2)+P(X = 3)= 0.8704
累积概率在连续概率分布中更有帮助。
连续概率分布
到目前为止,我们已经看到了概率在离散随机变量中的作用。现在,让我们看看连续随机变量中的概率函数。
如果一个随机变量可以从一个数据中取无限个值,则称为连续随机变量。
例如,一个衡量雇员通勤时间的随机变量是连续的,因为有无限多的可能性可以发生。
由于时间是一个连续变量,随机变量取一个精确值的概率为 0。所以,为了计算概率,我们不取特定的值,而是取区间值。
假设我们必须计算员工每天通勤到办公室所花时间的概率,我们已经进行了一项调查,并有如下所示的概率值。

有了上面的概率值,我们现在可以找到如下的累积概率值:
x = 30 的累积概率为,
F(30)= P(X≤30)= P(0<X<20)+P(20<X<25)+P(25<X<30)
F(30)= 0+0.15+0.20 = 0.35
所以,给定概率值的累积概率看起来像,

如果我们在一个图表中绘制这个累积值,它被称为累积分布函数(CDF) 图表使用下面的 python 代码,

在 CDF 图表中有两点需要记住。
- 这些是单调非减函数。
- Y 轴上的最大值应该总是 1。
我们也可以用区间来绘制概率图。
这是概率密度图的样子,

来源— 维基百科
我们可以从上图中观察到,概率区间下的面积等于该区间的累积概率。
如果在一个连续的随机变量中,所有概率密度的值对于所有可能的值都相等,则称为均匀分布。
此外,在现实生活中,pdf 是最常用的,因为它比 CDF 更容易看到 pdf 的模式。
正态分布
最常用的一种 PDF 是正态分布/钟形曲线/高斯分布。
正态分布图是这样的,

作者图片
正如形状所示,大多数值通常位于该分布的中心附近。分布也将围绕中间对称。正态分布通常出现在自然发生的现象中。
正态分布也有助于理解数据分析的一些高级概念,如中心极限定理(CLT) 。我们将在下一篇文章中了解 CLT。
让我们详细研究一下正态分布。
- 分布在中间对称,称为均值(μ)。
- 在正态分布中,平均值、中值和众数是相等的。这意味着分布在中位数和众数上也是对称的。
正态分布有一个1–2–3 规则,遵循以下三个条件:
- 值在“ μ-σ ”和“ μ+σ ”之间的概率在 68%左右。
- 值在“ μ-2σ ”和“ μ+2σ ”之间的概率在 95%左右。
- 值在“ μ-3σ ”和“ μ+3σ ”之间的概率约为 99.7%。
这里【μ】是的平均值,****【σ】是的标准差。

来源— 维基百科
这意味着分布的尾部非常小。在正态分布曲线中,大多数值位于“ μ-3σ 和“ μ+3σ 之间。
举个例子,如果 μ = 30,和 σ = 5,取值在 25 和 45 之间的概率将是,
P(25
Now, the probability for the same values between 25 and 50 will be,
P(25
We know that from 1–2–3 Rule, the values are evenly distributed at Mean(μ), i.e., 50%的值≤ μ 和 50%的值为> μ。
这意味着,如果 P(μ-3σ < X < μ+3σ) = 99.7%, then P(X
Finally,
P(25
This is how we calculate, the probability values if the distribution follows Normal Curve.
Standard Normal Distribution
As we have seen, it does not matter what the values of μ 和 σ 为,我们感兴趣的是 X 距离均值(μ)的标准差(σ)有多远。
比方说, μ = 30,和 σ = 5,和 X=43.25。
我们可以说 X 距离μ8.25 个单位,即,
用标准差来说,我们可以说 X 距离均值1.65σ(μ)。
这个 1.65 的值叫做我们的随机变量的Z——得分。Z 得分可通过以下方式计算:
Z = (X-μ)/σ
这个变量 Z 称为标准化正态变量
所以,现在关于 Z 的 1–2–3 规则是,
- P(-1
- P(-2
- P(-3
The Standard Normal Distribution(Z) graph looks like this,

Source —维基百科
正如我们所见,标准化正态变量( Z )是一个比正态分布变量(X)更能提供信息的变量。
我们可以从这个表中找到 Z 的所有概率值这里。
Z 评分表的样本是这样的,

来源— Z 工作台
我们来举个例子;我们想求正态分布中随机变量在 1.65 个标准差以内的概率?
也就是说,我们要求 P 的值(μ-1.65σ < X < μ+1.65σ).
In terms of Z, we need to find the value,
P(-1.65
If we look into the table, w can find the values of,
P(Z=1.65) = 0.9505
P(Z=-1.65) = 0.0495
现在,概率= 0.901 = 90%
因此,大约 90%的值位于 1.65 个标准偏差之间。
这就是我们如何从表中计算 Z 值,并找出概率。
结论
这些是推断统计学中的主题,每个数据科学家都应该具备基本的知识。使用这个正态分布和标准正态分布概念,我们将了解更多关于数据科学中广泛使用的中心极限定理和假设检验。
感谢您阅读和快乐编码!!!
在这里查看我以前关于 Python 的文章
- 探索性数据分析(EDA): Python
- 使用 Python 对熊猫数据帧进行索引
- Seaborn:Python
- 熊猫:蟒蛇
- Matplotlib:Python
- NumPy: Python
- 数据可视化及其重要性:Python
- Python 中的时间复杂度及其重要性
参考
- 推断统计—概述:https://www . mygreatlearning . com/blog/Inferential-Statistics-An-Overview/
- 统计学在数据科学中的作用:https://www . top coder . com/Role-Of-Statistics-in-Data-Science/
- 推断统计:http://onlinestatbook.com/2/introduction/inferential.html
- 什么是推断统计?:https://www.statisticshowto.com/inferential-statistics/
- 描述性统计:https://conjointly.com/kb/descriptive-statistics/
- Z 评分表:【http://www.z-table.com/】T22
奖励可变的无限步旋转木马问题
利用继承修改撑杆跳开放式健身环境的步骤方法
在上一篇博文中,我们写了我们的第一个强化学习应用——cart pole 问题。我们使用深度 Q 网络来训练算法。正如我们在博客中看到的,固定奖励 +1 用于所有稳定状态,当翻筋斗失去平衡时,奖励 0 。我们最后看到:当侧翻接近 200 步时,往往会失去平衡。我们在博客结尾建议了一句话:最大步数(我们定义为 200)和固定奖励可能导致了这样的行为。今天,我们不限制步数和修改奖励,看看侧翻如何表现。
电线杆问题定义
当在 100 次连续试验中平均奖励大于或等于 195.0 时,认为横竿问题解决。这是考虑到 1.0 的固定奖励。由于它的定义,对每个平衡状态保持固定的奖励 1.0 并限制最大步数为 200 是有意义的。很高兴知道这个问题在之前的博客中已经解决。
横竿问题有以下终止发作的条件:
- 磁极角度超过 12 度。
- 推车位置超过 2.4 —推车中心到达显示屏边缘。
可变奖励
我们的目标是取消步数限制,给每个州一个可变的奖励。
如果 x 和 θ 分别代表小车位置和杆角度,我们将奖励定义为:
*reward = (1 - (x ** 2) / 11.52 - (θ ** 2) / 288)*
这里,小车位置和极角分量都被归一化到[0,1]区间,以给予它们相等的权重。让我们来看看 3D 图的 2D 视图的截图。

我们在图中看到,当横竿完全平衡时(即 x = 0 和 θ = 0 ),奖励最大(即 1 )。随着 x 和 θ 绝对值的增加,奖励减少,当 |x| = 2.4 和 |θ| = 12 时,奖励达到 0 。
让我们将 CartPole 环境 gym 类( CartPoleEnv) 继承到我们的自定义类, CustomCartPoleEnv,并覆盖步骤方法。在阶梯法中,我们写的是可变报酬,而不是固定报酬。
通过使用上面的代码块,制造了 TF-agent 的组件,并训练了深度 Q-网络。我们看到横翻在许多步后更加平衡和稳定。
示范
让我们看看使用可变奖励后我们的横竿表现的视频。
一集平均持续 35.4 秒。令人印象深刻,不是吗?
可能的改进
这里,只有当两个表达式(杆角度和推车位置)都达到极值时,奖励才变为零。我们可以采用不同的回报函数,当达到一个极端条件时,回报为零。我期望这样的奖励函数做得更好。因此,鼓励读者尝试这样一个奖励功能,并评论一下横竿的表现。快乐的春天!
无限可分分布
迈向稳定的分销之旅#2
什么是无限可分分布?
嗨,我是卢武铉( ρ )!欢迎来到“稳定分销之旅”系列
这是“稳定分布之旅”系列的第 2 部分。如果你错过了#1 " 厚尾分布",请查看这里的!
警告:不要被这个术语吓坏了
“无限可分分布”

资料来源:Pixabay
无限可分?
人们可以谈论物质、空间、时间、金钱或抽象数学对象(如连续统)的无限可分性或缺乏无限可分性。(维基)
1.【物质】直到量子力学的发现,物质是否无限可分的问题和物质是否可以无限切割成更小的部分(量子)的问题才得以区分。
2.金钱是无限可分的,因为它是以实数系统为基础的。每笔交易都有一个没用的精确点,因为这么小的金额对人类来说微不足道。它也适用于时间。虽然时间可能是无限可分的,但金融价格数据是在离散时间报告的。
3.【概率分布】我们这里要讲的!
定义
是时候看看“无限可分分布”的实际定义了。我将向您展示两种不同的定义,从最简单的开始。

来源:统计 Howto
想想我们熟悉的两个发行版
常态
我们知道对于正态分布,正态分布的和也是正态的。试着猜测如何构建满足上述定义的“n”独立同分布正态分布。答案如下图 2 所示。

两个正态分布的和
制服
与我们的直觉不同,均匀分布不是无限可分的。想看证明的,查这个。作为旁注,我们常犯的错误是两个均匀分布(如 U[-1,0]和 U[0,1])之和是一个均匀分布(如 U[-1,1])

资料来源:M.Grabchak 讲座
以上定义都是等价的。
无限可分分布的这种定义是有意义的,因为对于任何‘n’个我们可以分成‘n’个独立同分布的随机变量。
使用特征函数
判断一个函数是否能被无限整除的最简单的方法之一是看它的特征函数。这是因为如果分布的特征函数是每个独立同分布变量的特征函数,那么

所以我们可以从我们的原始概率函数,通过看它的逆,来推导出我们的被加数随机变量的特征函数

让我们用下面的 3 个例子来验证一下吧!!
“x=a”处的点质量(狄拉克δ分布)
我们从最简单明显的例子开始。这是点质量分布,没有任何随机性。显然这将是无限可分的。

图一。点式群体
虽然这可能不是一个有趣的问题,但很容易看出它是如何工作的。
正态分布

图二。正态分布
泊松分布

图 3。泊松分布
这三个是无限可分分布的例子。
对于更一般的无限可分分布,注意两个无限可分分布之和是无限可分的,即在卷积下闭合。[更多细节请查看这个惊人的 youtube 视频从 20:00 开始]
等等…
问:为什么我们需要知道无限稳定分布?
答:这只是因为调和稳定分布是无限稳定分布的一种。
还有一件事要谈,如果对你来说太沉重的话,可以跳过最后一件。
对于每一个单一的无限可分分布,它都有相应的特征函数。我将介绍一种表示,我们可以用它来指定每个无限可分分布的特征函数。
利维-钦钦代表权

请参见下面的蓝色大圆圈。
我们可以看到无限可分分布的类非常大。根据 Levy-Khintchine 表示,我们可以再次指定每个无限可分分布的特征函数。这个挺厉害的!想象一下,我们可以指定这样一大类分布的特征函数。

图 4。图表//改编自 Mantegna 和 Stanley (2000 年)
从上图中你注意到了什么?
虽然我们还没有讨论“稳定分布”(马上就要讲到),但是从上图可以看出
- 每个稳定分布都是无限可分的
- 不是每个无限可分的分布都是稳定分布
第二点的一个例子是“泊松分布”。从上面的图 3 中,我们看到泊松分布是无限可分的。然而,它并不稳定我会在后面谈到稳定分布时解释原因。
摘要
我们从高级理解到低级理解复习了“无限可分”这个概念。为了理解“缓和稳定(TS)分布”,有必要对无限可分性有一个基本的了解,因为 TS 属于它。希望这份文件有助于提高你的理解。如果你有任何问题,请在下面评论。我希望你对接下来会发生什么感到好奇。下一次,我将带着“稳定分布之旅[部分。3:幂律分布]”
参考:
- 【http://shannon.cm.nctu.edu.tw/prob/c28s08.pdf 号
- 斯蒂芬妮格伦 。【StatisticsHowTo.com】【概率中的无限整除:定义】对我们其他人来说是基础统计!https://www.statisticshowto.com/infinite-divisibility/
- https://en.wikipedia.org/wiki/Infinite_divisibility
- https://www.youtube.com/watch?time_continue=10&v = SJ 70 ie biy 1u&feature = emb _ logo
- https://www.youtube.com/watch?v=Sj70IEBIy1U
- 金融中的调和稳定分布和过程:数值分析,2008 年
- http://www.stats.ox.ac.uk/~winkel/ms3b10_s1.pdf
我还为上面所有的参考资料添加了超链接。请查阅参考资料了解详情。如果我错过了什么,我会在以后更新参考资料。
感谢您阅读本文档。如果您认为这份文件有用,请不要忘记与您的朋友分享。
无限不会变得相等

它们有不同的尺寸
学数学的时候,迟早会碰到无限大小的集合。没什么可怕的。我们熟悉的是ℕ的一组自然数,我们对它的理解已经足够了。
一旦我们理解了ℕ,感觉我们已经很好地掌握了无限这个概念,不是吗?
事实证明,无穷大比这更奇怪:它有不同的大小。
无限的大小
从绝对意义上来说,无限集合的大小是无限的。相对而言,看看集合 A 和 B,我们可以比较它们在大小上是相同还是不同。但是如果在两种情况下都是无穷大,你怎么做呢?
好吧,我们不会去数他们的元素,所以这不是一个选项。我们还能做什么?
现在,让我们假设 A 和 B 是有限的。如果不能对元素进行计数,我们如何检查它们的大小是否相同?一种选择是尝试在元素之间建立 1:1 的关系——也称为双射。

两个集合之间的 1:1 关系
如果可以证明存在 1:1 的关系,我们就有效地证明了 A 和 B 有相同数量的元素。它们大小一样。
假设同样的想法也适用于无限集合。如果我们可以在两个无限集合之间建立 1:1 的关系,我们就知道它们的大小相同。一组不可能比另一组更大或更小。
让我们用一些实验来验证我们的想法。
向无限集合中添加一些项
如果我们取ℕ,并在其中加入一个额外的项目,会发生什么?让我们将新项目标记为-1。
我们可以通过映射 n ↔ n+1 与ℕ建立 1:1 的关系。

将项目添加到无限集中
我们将所有的输入映射到不同的输出,在输出端我们覆盖了整个ℕ。这意味着我们有 1:1 的关系,所以总的来说,集合的大小是相同的。
事实证明,向无限集合中添加一个项目并不会使它变大。
如果我们添加了 10 个项目,我们可以将它们标记为-10…-1,我们可以使用 n ↔ n+10 作为我们的映射。
事实证明,向无限集合中添加任何有限数量的项目也不会使其变大。
希尔伯特酒店思维实验的总体思路是:在一个拥有无限房间的订满的酒店里,你总是可以转移现有的客人来容纳新的客人。

在无限酒店,你可以随时把客人转移到下一个房间,以便腾出 1 号房间——图片由 Unsplash 上的 Alfons Morales 拍摄
将无限集合的大小加倍
让我们给ℕ加上无穷多项,即所有的负整数。我们基本上是在比较ℤ,所有正整数和负整数的集合,和ℕ.从直觉上看,它的面积是ℕ的两倍,但是它会对我们建立一对一关系的能力产生影响吗?
一点也不。我们可以按顺序交替分配正数和负数,在它们之间来回跳跃,覆盖整个ℤ

一对一的关系ℕ ↔ ℤ
请注意,建立一个集合与自然数的 1:1 关系等同于对其元素进行枚举。枚举位置 n 和该位置的项目 x 成 1:1 的关系。
对于上面的映射,枚举是:
0↔0
1↔-1
2↔1
3↔-2
4↔2
5↔-3
…
事实证明,将一个无限集合的大小加倍并不会使它变得更大。
添加另一个维度
我们不看自然数,而是看自然数的对。就像平面上的坐标。让我们比较一下ℕ和ℕ。添加一个完整的独立维度很有可能在某种意义上比原始集合“更大”。
我们有效地增加了我们的集合,每个数字有无限多的项:我们为 0 增加了无限多的项,即(0,1),(0,2),(0,…),为 1 增加了无限多的项,即(1,1),(1,2),(1,…),等等。
毫无疑问,要完全列举出我们在ℕ的所有要素是困难的。
事实证明,如果我们遵循这个方案,我们仍然可以做到这一点:

ℕ的一个例子
我们绘制了下面的序列,填满了ℕ的整个目标空间
0 ↔ (0,0)
1 ↔ (1,0)
2 ↔ (0,1)
3 ↔ (0,2)
4 ↔ (1,1)
5 ↔ (2,0)
6 ↔ (3,0)
…
因为我们可以给出所有项目的无所不包的枚举,我们知道我们仍然在处理一个和ℕ.一样大的无限
事实证明,对无限集合中的项目数求平方并不会使其变大。
分解:分数
好吧,那ℚ呢,有理数集?
先搞清楚正有理数。
任何正有理数都可以用一对整数来表示,比如 1/2 或 5/9。所以实际上,ℚ的正面部分可以通过类似于我们用来绘制ℕ ↔ ℕ地图的对角化方案来绘制。
我们将不得不改变方案,以避免分母中的 0,并且我们将不得不跳过一些有理数,以说明并非所有的整数对都形成不同的有理数。这是因为我们必须处理 1/2 = 2/4 = 3/6 等可约分数。

所有正有理数的枚举,可约分数被跳过
有点繁琐,但还是。我们可以列举ℚ.所有的正数让我们称我们的映射函数为 m: ℕ → ℚ.
我们看到ℚ的阳性部分肯定不比ℕ大。如果有什么不同的话,由可约分数引起的重复使它潜在地“变小”。
ℚ消极的一面呢?为了涵盖ℚ积极和消极的两个方面,我们可以先将ℕ与ℤ对应起来。我们知道它们一样大。然后我们使用 m(z) 将任何正的 z 映射到ℚ,并将任何负的 z 映射到 -m(-z)以覆盖 ℚ 的负部分。
使用这种方法,我们可以链接 1:1 的关系,保证ℕ与ℚ:的大小相同
ℕ ↔ ℤ ↔ ℚ
那么一个无穷大的大小是如何增长的呢?
我知道你在想什么。你在等待一个无限大的集合,它显然比ℕ.大到目前为止,我们一直一无所获。
好吧,好吧。

让我们试着将ℕ提升到一个新的高度——图片来自pix abay的 Ralf Kunze
让我们看看我们已经尝试了什么:
- 我们尝试将固定数量的 k 项添加到ℕ中,试图形成一组不会移动的|ℕ|+k.大小,这也许并不奇怪。
- 我们看着ℤ,尝试一个两倍于ℕ.大小的布景我们基本上形成了一组大小为 k 的|ℕ|⋅,其中 k 为 2。如果我们用更大的 k 值去尝试,我们仍然不会有任何进展。我们来回跳跃的映射思想可以重复,因此我们可以容纳 2、4、8、16、32……倍于ℕ大小的集合,最终超过我们可能选择的任何 k。我们仍然和ℕ.保持着 1:1 的关系
- 我们看了看ℕ,基本上是想和|ℕ|⋅|ℕ|.的一套尺码进行比较我们再次得出了 1:1 的关系。一旦我们知道了ℕ和ℕ的面积一样大,我们就可以把我们的制图方法联系起来,确定ℕ和ℕ、ℕ⁴、ℕ⁵等的面积一样大。一次增加一个维度,我们最终可以证明ℕ和ℕ的大小是一样的。所以扩展到一个有限的维度集不会让一个集合变大。
我们唯一没有尝试的是大小的幂运算。让我们试着组成一套大小 2^|ℕ|.
动力装置
让我们回到有限集合上来。给定任意一个大小为 n 的集合 A ,构造一个大小为 2^n 的集合的经典方法是形成幂集 P(A) 。那是包含 A 的所有子集的集合。
所以例如集合 A={x,y,z} 有幂集合 P(A) = {{},{x},{y},{z},{x,y},{x,z},{y,z},{x,y,z},{ 。
你会注意到 A 的大小是 3,而 P(A) 的大小是 8=2。你可能想知道是否总是如此,事实也的确如此。这是最容易从结构上看出来的。
假设我们选择一些 A 并构造 P(A) 。如果我们给 A 增加一个额外的元素 e 形成A’,P(A’)比 P(A) 大一倍。这是因为P(A’)整齐地分割成两个大小相等的部分。第一部分包含 P(A) 的所有元素——这些正是A’中不包含新元素 e. 的子集。第二部分包含第一部分中每一项的孪生元素,形成A’中包含e 的所有子集。**
让我们从空集 A⁰开始,不断添加元素,从而形成 a,a 等。每一个连续的幂集都包含了前一个幂集的元素,以及这些幂集的副本,每个幂集都添加了新元素。
A⁰ = {},P(A⁰) = {{}},|P(A⁰)| = 2⁰
A ={ x },P(A )={{}, {x} },|P(A )| = 2
a = {x, y },p(a)= { { { },{x}, {y},{ x,y} },| p(a)| = 2
回到ℕ.让我们形成 P(ℕ)看看它是否仍然和ℕ.一样大我们需要尝试找到一种方法来列举 P(ℕ).的所有元素我们走吧。
枚举ℕ的子集
我不知道你怎么想,但我发现很难找到一种简单、系统的方法来列举自然数的所有可能序列。我们必须想出一些索引方案。
让我们画一个表,其中列代表自然数,每行代表一个子集。我们在每一列中放置一个 0 或 1,表示我们是否希望在该行的子集中包含相应的数字。行的顺序给出了我们的枚举顺序。
假设我们想通过编码空集开始我们的序列,然后是整个ℕ,然后形成各种模式,它可能看起来像这样。

枚举ℕ的子集
完美!看起来有一种方法来表示我们的枚举。我们现在可以考虑某种枚举所有子集的方案。
现在,假设我们已经找到了一个好的规则,并且确信我们的枚举编码了某一行中所有可能的子集。
幽默一下,看看我们桌子对角线上的数字组成的序列,然后翻转其中的每个元素。每个 1 都变成 0,每个 0 都变成 1。得到的序列显然编码了ℕ的某个子集,所以它应该是我们枚举中的某个行。

枚举ℕ子集的对话框
但与此同时,该序列保证不会出现在我们的枚举中。如果我们想声明“不,不,那个序列被 g 号覆盖了”,我们知道这不是真的。g 行不同于我们翻转的对角线序列,至少在位置 g,那是我们取原始值翻转的位置,所以不可能是相同的。由翻转对角线编码的ℕ子集不在我们的枚举中。这不可能。
最后,我们遇到了一个明显大于ℕ的集合,即ℕ.所有子集的集合它是如此的庞大,甚至没有办法去列举它的成员。
ℝ比ℕ大
好,我们已经找到了至少两种无穷集合。可枚举的集合,也称为可数无穷。甚至更大的集合,大到成员无法被枚举,像ℕ.幂集这些被称为不可数不定式。
事实证明,ℝis 的那组实数也比ℕ.大
想象一下,你试着枚举 0 到 1 之间的实数。您最终会做一些与我们的子集索引练习非常相似的事情,只是使用数字 0-9,而不是只有 0 和 1。

尝试枚举所有 0.xyz…
但是我们知道,即使你限制自己去列举那些只有 0 和 1 的数字,你已经有了一个不可数的集合。从 0 到 1 之间的实数已经比整个ℕ.还多
事实上,ℝ和 P(ℕ).一样大我们来讨论一下为什么会这样。
ℝ的大小
让我们假设 P(ℕ和ℝ.的面积一样大我们知道|P(ℕ)|相当于所有 0 和 1 序列的数目。
让我们看看ℝ的开放区间(0,1 ),让我们像以前一样用一个表格,用我们常用的数字 0-9 来列举其中的数字。我们用了比 0 和 1 更多的数字。显然,这使得这个集合至少和 P(ℕ).一样大但是大小可能一样吗?
可以在数字序列 0-1 和 0-9 之间建立 1:1 的关系。这是一个创建等效编码的问题。
做那件事有几种方法。想象一下计算机用来表示数字的二进制编码,或者连续的 1 和 0 的数量编码连续的数字。例如,考虑下面的想法,其中连续的 1 序列编码一个序列数字。

0–1 序列和 0–9 序列之间 1:1 关系的基本思想
从最初的想法进展到实际的绘图是一个乏味的过程。构造 1:1 可逆编码的细节可能是棘手的,因为严格的定义需要考虑各种边缘情况,例如 0.09999…等于 0.1 等。因此,在每个方向上找到一个内射映射,并使用施罗德-伯恩斯坦定理得出双射映射存在的结论通常更容易。
不用花时间在这种编码的细节上,让我们相信这种编码是存在的。因为它确实存在,我们已经确定 P(ℕ和区间(0,1) ∈ ℝ大小相同。
接下来,我们通过映射建立大小相同的区间(0,1)和(-1,1)
x ↔ 2x-1
我们通过将 0 映射到-1、0.5 映射到 0 和 1 映射到 1 来扩展和移动我们的区间,其中所有值都是线性插值的。
这是非常可逆的。回过头来我们可以计算 (x+1)/2 ,所以是 1:1 的关系。我们扩展了区间,并证明了两个区间的无穷大相同。
接下来,我们通过映射将区间(-1,1)缩放到(-π/2,π/2)
十.↔ (x⋅π/2)
通过除以π/2,这是可逆的,因此我们有 1:1 的关系,因此区间(-1,1)和(-π/2,π/2)的大小相同。
链接我们的映射,我们已经建立了区间(0,1)和(-π/2,π/2)的大小相同。当然,两个区间都包含无穷多个点,但是我们知道它们之间有 1:1 的对应关系。所以就无限的大小而言,它们是相等的。

(0,1)和(-π/2,π/2)通过 1:1 关系包含相同数量的点
注意,我们不能像以前一样,通过乘以一个常数来延伸到无穷大。
但是我们可以使用 切线功能来实现。

正切函数绘制了整个ℝ的时间间隔
我们可以通过映射将区间(-π/2,π/2)延伸到整个ℝ
x ↔ 谭(x)
在我们的区间上,使用【arctan(x),tan函数是完全可逆的,因此我们有 1:1 的关系,确定(-π/2,π/2)与整个ℝ.的大小相同

arctan 函数通过 tan 将我们的映射反转回我们的原始区间,因此我们的区间和ℝ之间有 1:1 的关系
通过一系列一对一的关系,我们已经建立了:
P(ℕ) ↔ (0,1) ↔ (-1,1) ↔ (-π/2,π/2) ↔ ℝ
因此 P(ℕ)和ℝ.一样大
我有问题!
是啊,我知道。现在我们发现了一个比ℕ大的无穷大,我们想知道是否有更大的,或者更小的,以及介于两者之间的大小呢?

无限确实有不同的大小——图片来自 Pixabay 的马里奥·霍弗
有比ℝ大的无限集合吗?
是的,任何集合的幂集都比原来的大。
例如,P(ℝ的面积比ℝ.的面积大
原因在康托定理中被优雅地概括为,你不能在任何集合 A 和它的幂集 P(A)之间形成 1:1 的关系。任何映射都不可能覆盖 P(A)中的所有值。
用专业术语来说:没有满射函数 f: A →P(A),所以也不可能有任何双射函数。电源组总是太大而无法覆盖。
有比ℕ更小的无限集合吗?
不,可数无穷集的任何子集不是有限就是可数无穷集。
这个想法是,如果你有一个可能比ℕ“小”的无限集合 a,你就能把它映射到ℕ.的某个子集然后,您可以根据该映射对 a 进行排序,从而枚举 a 的内容。成功枚举 a 的项目表明与ℕ存在 1:1 的关系,因此证明 a 与ℕ.的大小相同
请参阅 Kevin 的精彩文章,了解更多详细信息:
我身上有一个纹身。自然对我来说很有意义。它每天都让我想起这个世界的奇妙…
medium.com](https://medium.com/@kev.ullmann/the-smallest-infinity-7b27b1ecd639)
有没有大小在ℕ和ℝ之间的无限集合?
非常好的问题。还有一个开放式的。连续统假说认为不存在。但到目前为止没人知道。
我们所知道的是,这个问题的答案与集合论本身无关。换句话说,在我们目前的知识框架内,它可以以任何一种方式被假设,而不会导致与我们目前的知识体系不一致。
可怕吧。
InfluxDB 分析教程
使用 Knowi 连接到 InfluxDB 数据源,查询它,可视化您的数据,并通过基于搜索的分析提出更多问题。

戴维·舒尔茨在 Unsplash 上的照片
目录
介绍
维基百科将物联网定义为“一个由相互关联的计算设备、机械和数字机器组成的系统,这些设备具有唯一的标识符,能够在网络上传输数据,而无需人与人或人与计算机的交互。”举个例子,想象一个家庭安全系统和一个智能手表都可以自动向你的手机发送数据。
虽然物联网消除了数据传输过程中对人机交互的需求,但人机交互仍然是分析物联网数据的必要部分。为了与他们的物联网数据进行交互,人类需要一个可以安全存储数据的数据库和一个可以高效分析、可视化并最终从中获得洞察力的可视化平台。
这就是 InfluxDB 和 Knowi 的用武之地。InfluxDB 是一个开源数据库,由 InfluxData 的团队专门构建,用于存储时序物联网数据,Knowi 是一个分析和可视化平台,提供了与 InfluxDB 的广泛原生集成。Knowi 广泛的原生集成使其有别于许多其他分析平台,这些平台难以应对 InfluxDB 数据的非结构化性质,并确保您使用 Knowi 从 InfluxDB 实时查询物联网数据不会有任何问题。在本教程中,您将学习如何使用 Knowi 来分析和可视化来自 InfluxDB 的数据。
连接到 InfluxDB
一旦您登录到您的 Knowi 帐户,第一步是连接到 InfluxDB 数据源。为此,请按照下列步骤操作:
1)移动到屏幕左侧的面板,选择“数据源”
2)从“NoSQL 数据源”中找到并选择“InfluxDB”
3)这里会自动填写您的数据源、主机和数据库名称;您需要做的就是保存您的数据源。
祝贺您连接到 InfluxDB!
查询您的数据
当您保存您的数据源时,您应该会收到一个提示“Datasource added”。配置查询。为了设置您的第一个查询,请按照下列步骤操作:
1)点击“查询”
2)在执行任何其他操作之前,请在“报告名称*”中将您的报告命名为“InfluxDB Query ”,然后直接查看您的报告名称上方。您应该会在屏幕顶部看到一个新的警告,内容是“检索到的表”。使用查询生成器部分来发现和构建报告/查询。这意味着 Knowi 自动为存储在您连接的 InfluxDB 数据库中的每个表建立索引,现在您可以从这个索引中选择表。
3)向下滚动到“表格”,单击向下箭头,并选择“h2o _ 温度”这将使 Knowi 自动创建一个 InfluxDB 查询,调用 InfluxDB 数据库中水温表的前 1,000 行中的所有列。这个 1,000 的限制只是一个默认的限制,但是我可以毫无问题地处理更大的负载,所以继续删除 InfluxDB 中写着“限制 1000”的部分该水温表包含每六分钟在两个不同位置进行的水温测量,并以华氏度记录。
4)移至屏幕左下角,点击“加入”这将设置第二个查询构建器,您将在其中生成第二个查询,并最终将其与第一个查询连接起来。在第二个查询构建器中,我们将重复与第一个查询非常相似的过程。使用“Tables”下的向下箭头,选择“h2o_quality”,并从 Knowi 自动生成的 InfluxDB 查询中删除“limit 1000”。就像水温表一样,这个水质表也包含每六分钟进行一次的测量。
在我们进入第 5 步之前,我认为最好解释一下为什么需要采取这一步。水质是通过一种称为水质指数的度量标准来衡量的,在我们的水质表中简称为“指数”。与水温保持相当一致不同,水质指数非常不稳定,在一个小时的过程中,可以在 0 的最小测量值和 100 的最大测量值之间变化。为了让您了解这种波动性有多大,下面是我们将一天中的水温和水质指数可视化后的情况:

作者图片
我曾认真考虑过不在本教程中包含这张图片,因为它丑陋得足以将观众拒之门外,也愚蠢得足以让观众质疑它怎么可能出现在关于正确数据分析的教程中。不过,我最终还是加入了,因为我觉得有必要在每小时 6 次测量的基础上展示水质指数的波动性,我们希望避免以这种方式将其可视化。
这里的好消息是,与每小时 6 次测量的水质不同,一整天的平均水质指数实际上相当一致,我们完全可以在此基础上通过分析获得有价值的见解。这就是 Cloud9QL 的用武之地。Cloud9QL 是 Knowi 强大的 SQL 风格的语法,允许您在设置查询后对查询进行后处理,在这种情况下,Cloud9QL 将用于将水质指数转换为每日平均值,使您的查询更加简洁。现在,您已经确切地知道了我们为什么需要将测量值转换为日平均水质指数,以及我们将如何进行,您已经准备好进入第 5 步:
5)在刚刚设置的用于查询水质表的 InfluxDB 查询下面,将以下语法输入到 Cloud9QL 查询中:
select *, day_of_month(time) as Day;
select avg(index) as Index, time as Date, location
group by Day, location;
6)接下来,使用查询构建器左上角的眼睛图标预览这个特定查询的结果。正如你所看到的,你有两个不同地点每天的平均水指数。现在,在我们将水质表与水温表连接起来之前,我们需要将同样的过程应用于水温表。为此,向上滚动到您设置的第一个查询,查询水温表,并在 Cloud9QL 查询中输入以下语法:
select *, day_of_month(time) as Day;
select avg(degrees) as Temperature, time as Date, location
group by Day, location;
7)现在,在两个查询之间稍微向下移动一点到连接生成器。单击“加入构建器”将联接类型设置为内部联接,并将位置设置为位置,日期设置为日期。然后选择“保存”以保存您的加入。
8)这里的工作差不多完成了,但是您需要再次返回到 Cloud9QL,以我们想要的格式完成我们的查询。这一次,使用屏幕底部的“Cloud9QL Post Query”并输入以下语法:
Select Temperature, Index, Date, location as Location
order by Date, location
9)现在,点击屏幕左下角的“预览”。你应该看看圣莫尼卡和郊狼溪的每日水温和水质指数。如果您这样做了,这意味着您已经正确地做了所有的事情,这意味着您是时候单击“保存并立即运行”来运行您的查询了。
您的查询现已正式完成。干得好!
分析和可视化您的数据
现在您已经完成了查询,是时候利用 Knowi 的可视化功能来享受您的劳动成果了。保存并运行查询后,结果将作为数据集存储在 Knowi 的弹性数据仓库中。此外,您在保存查询之前查看的引用数据网格现在存储为一个小部件。为了可视化您的小部件并创建更多可视化效果,请按照以下步骤操作:
- 移动到屏幕左侧面板的顶部,选择“仪表板”然后,选择加号图标,将新仪表板命名为“InfluxDB 仪表板”,并单击“确定”
- 这个控制面板将作为您的小部件和您创建的所有其他小部件的主页。回到屏幕左侧的面板,这次选择“Widgets”。将您创建的新“InfluxDB Query”小部件拖到您的仪表板上。
- 将鼠标悬停在新部件的右上角,以显示省略号图标。选择它,然后向下滚动并选择“分析”将新屏幕左上角的“位置”栏拖到“过滤器”上在“值”下,键入带下划线的“coyote_creek”,然后单击“确定”
- 在屏幕顶部,选择“可视化”这将向您显示您的数据网格,它与您正在分析的数据没有太大的不同。要改变这一点,点击屏幕左上角“可视化类型”下的“数据网格”,将您的可视化更改为“区域”可视化。如果你做对了,你应该会看到一个面积图,它传达了平均水温保持非常一致,而水质有一个体面的数量每天的变化。
- 走到屏幕的右上角,选择“克隆”图标——它看起来像两张叠在一起的纸。将这个新部件命名为“Coyote Creek Daily”并选择“Clone”然后选择“添加到仪表板”
利用基于搜索的分析进行深入研究
虽然点击并拖动指标到过滤器区域并手动设置过滤器并不太难,但有时您只想用简单的英语提问并实时收到结果。这就是 Knowi 基于自然语言处理的搜索分析功能的用武之地。假设您希望只显示另一个位置(Santa Monica)的数据,而不是查看仍有波动的日平均值,您希望查看周平均值。下面是如何做到这一点:
- 回到第一个小部件的右上角,选择省略号图标,然后选择“分析”键入“显示圣莫尼卡每周的温度、指数和日期”并输入。这将自动计算水温和水质指数的周平均值。
- 前往屏幕顶部的“可视化”,将“可视化类型”更改为“区域”
- 选择“克隆”图标,并将这个新部件命名为“圣莫尼卡周刊”,然后选择“克隆”然后选择“添加到仪表板”
摘要
回顾一下,您通过连接到 InfluxDB 数据库开始了本教程。然后,您设置了一个查询,从两个单独的表中提取水温和水质指数的日平均值,并使用 Knowi 的连接构建器将它们连接起来;该查询的结果作为数据集存储在 Knowi 的弹性数据仓库中。接下来,您构建了一个仪表板,以可视化作为查询结果获得的原始数据,并创建了一个区域可视化,以一种更容易看到的方式传达一些结果。最后,您使用基于搜索的分析,以不同的方式分析数据的不同部分。
信息图算法
一种社区发现算法

在格文-纽曼(混合参数= 0.2,平均节点度= 16)合成网络(mscthesis.herokuapp.com)中运行 Infomap 算法后检测到的社区。
描述
信息图算法试图最小化成本函数。划分是基于给定网络中连接模式引起的流量[1]。
考虑到发送者假装将网络内的随机路径传递给接收者,假设如下:该消息的大小旨在被最小化。一个直接的策略是给每个节点分配一个不同的名称(代码)并将相应的序列发送给接收者。后者将能够基于适当的码本对消息进行解码。考虑到路径是由相同大小的𝑁码以二进制语言描述的,每个码字的最小长度𝐿为:

用更简洁的方式描述同一条路径的另一种方法是使用霍夫曼编码。该方法在于根据随机路径的遍历节点访问频率(无限长随机行走的平均节点访问频率),将不同长度的代码与每个节点相关联。哈夫曼编码本身已经是一种有效的方式来传输零星或不连续的独立节点,这些节点构成了我们假装要编码的随机路径。实际上,香农的信源编码定理指出,当我们使用𝑛码字来描述随机变量𝑋的𝑛态时,最小描述长度(MDL)由随机变量本身的熵给出:

如果目标是传输完整路径或所属节点的重要序列,则可以使描述更有效。为了实现这一点,网络被划分成模块,并且为每个模块定义不同的代码簿。这允许不同的节点被给予相同的标识。这不仅意味着为每个模块定义了模块码本(包括退出码),而且还定义了索引码本,以在随机漫步机进入不同模块时进行标记。在这些分层描述的情况下,MDL 由每个模块和索引码本使用频率的加权平均值给出:

被 𝑞 = ∑(m)(j=1) 𝑞j 每个小区的退出概率之和,𝐻(𝑄)小区间移动的平均码长, 𝑝(i)(⊙) = 𝑞i + ∑(m)(β∈i) 𝑝β 在一个小区内随机行走的停留概率𝑐和𝐻(𝑃)模码本的平均码长。

在(3)中插入(4)和(5):

考虑一个未加权且无向的网络,𝑞𝑚是模块𝑚的退出概率,𝑝𝛼是相对权重𝑤𝛼,其计算方法是将连接到𝛼的边的总权重除以图中所有链接的总权重的两倍。
这样,通过压缩网络的描述长度,它被划分成反映网络动态的模块。当节点之间的连接表示给定数量的流而不仅仅是这些节点之间的相似性时,这特别有用。算法 1 中 Infomap 算法的伪代码。
Infomap 方法表明,社区发现算法也可以用来解决压缩问题。

参考
[1] M. Rosvall,D. Axelsson 和 C. T .博格斯特伦,“地图方程”,《欧洲物理杂志专题》,第 178 卷,第 1 期,第 13–23 页,2009 年。
信息驱动的金融标杆

对分笔成交点不平衡棒线的非正式审查
介绍
您可能知道,原始财务数据由分笔成交点组成,代表市场交易。每一笔市场交易的特征是日期、时间、价格和交易的合约或股票数量。

取自证券数据库的原始分笔成交点数据示例
为了表示金融时间序列,通常使用棒线,棒线是分笔成交点的集合。但是有几种方法可以聚集信息;由于这个原因,许多种类的酒吧存在(时间酒吧是最常见的)。
观察市场 5 分钟,记下第一个观察到的价格(开盘价),最低价(最低价),最高价(最高价)和属于所选时间间隔的最后一个价格点(收盘价),你就建立了一个 5 分钟棒线!
然而,与人类不同,市场并不遵循时间表。它们不以固定的时间间隔处理信息。他们宁愿一件一件地做,一笔一笔地做。那么,如果我们放弃时钟,开始用不同的逻辑对市场价格进行采样,会怎么样呢?例如,我们可以使用音量时钟来构建音量条;或者,我们可以在每次观察到一定数量的新交易时,构建分笔成交点和样本价格。成交量和分笔成交点是已知的抽样方法,我不认为它们值得一整篇文章,因为你可以在网上找到大量的信息。
但是,如果我们使用一个信息时钟会发生什么呢?如果我们在每次市场上出现意想不到的数量的信息时对价格进行采样,会怎么样?这正是信息驱动酒吧背后的理念。很有趣,不是吗?我们将介绍最简单的信息驱动棒线:分笔成交点不平衡棒线。马科斯·洛佩兹·德·普拉多在他的书《金融机器学习的进步》中提出了这些观点(AFML)。
什么是分笔成交点不平衡棒线?
简而言之,为了建立这种棒线,我们假设分笔成交点不平衡代表知情交易(分笔成交点不平衡将很快被定义)。因此,每当我们观察到一个意想不到的不平衡量时,我们就对市场价格进行采样,并创建一个新的棒线。用德·普拉多的话说:
信息驱动棒线的目的是当新信息到达市场时更频繁地取样。在这种情况下,“信息”一词在市场微观结构的意义上使用。[……]通过使取样与消息灵通的交易者的到来同步,我们也许能够在价格达到新的均衡水平之前作出决定。
AFML 给出的定义
考虑 t=1,…,T 的一系列分笔成交点{(p_t,v_t)},其中 p_t 和 v_t 表示时间 T 的价格和成交量。分笔成交点规则为 t=1,…,T 定义了一系列分笔成交点符号{b_t},其中 b_t 可以是 1 也可以是-1。

AFML 给出的刻度线的定义
接下来,分笔成交点不平衡可以定义为 T 个分笔成交点上分笔成交点符号的部分总和。

AFML 对蜱不平衡的定义
现在,只要分笔成交点的不平衡超过我们的预期,我们就应该对棒线取样。这意味着我们必须计算每个棒线的运行 不平衡,并将其与我们的预期进行比较。当当前不平衡的绝对值大于绝对预期不平衡时,我们将关闭该棒线。
书中将每根棒线开始时的期望不平衡定义为每根棒线的期望分笔数(T)与分笔符号的无条件期望(b_t)的乘积。此外,该书指出,我们可以使用指数加权移动平均(EWMAs)来估计这些时刻。

AFML 给出的每个条形开始时预期不平衡的定义
特别是:
- 我们可以使用先前棒线的实际分笔成交点数量 T 的 EWMA 来估计每根棒线的预期分笔成交点数量
- 我们可以使用前一个滴答的滴答符号的 EWMA 来估计滴答符号的无条件期望值
回顾
马科斯·洛佩斯·德·普拉多指出,我们应该利用信息时钟来对市场价格进行采样。分笔成交点不平衡棒线只是这个概念最简单的应用,我们应该在此基础上发现有趣的见解。我们应该对信息和预期信息提出新的定义。毕竟,马科斯·洛佩斯·德·普拉多刚刚为我们指明了方向,或许我们不应该把他的实施细节看得太重。为什么?
首先,建议的棒线生成机制受到您如何初始化其参数的严重影响—要生成不平衡棒线,您必须初始化每个棒线的预期分笔成交点数量(下面的 init_T)、分笔成交点符号的无条件预期(E[b_t])以及定义用于更新我们预期的两个指数平均值的 alphas。
下图显示了通过一千多次模拟获得的结果。它表明,随着定义 EWMA(T)的α的增加,相同时间间隔产生的棒线数量减少。此外,当我们增加用于初始化该机制的 T 值时,杆的数量减少。

每个模拟中生成的条形数与初始化参数的散点图。x 轴表示用于更新预期刻度数的 alpha。init_T 是我们用来初始化 EWMA(T)的值。EWMA(b_t)的α一直保持在 0.005 不变。刻度线的无条件期望值总是用 0.5 初始化。例如:如果你用 EWMA(T)的 alpha 值稍大于 0.2,init_T 接近 2000 来初始化这个机制,你得到的一个月的数据少于 10 根棒线。
很自然地,结果条的数量越多,我们在每个条中包含的信息量就越少。

每个模拟中棒线关闭时的中值不平衡散点图。例如:如果您的不平衡中值为 2000,则在给定模拟中创建的 50%的棒线已经关闭,不平衡≤ 2000,50%的棒线已经关闭,不平衡≥ 2000。在 x 轴上,您可以找到已创建的条的数量。条形的数量越多,每个条形的中值信息含量越低。
这意味着当我们选择如何初始化棒线生成机制时,我们粗略地选择了我们将用来关闭棒线的不平衡阈值。
上面的图只显示了该机制产生至少 3 个条的情况。重要的是要认识到,如果初始化的预期不平衡太高,该机制将只产生几个条,或者甚至很难产生单个条;如果太低,我们反而会产生太多的条纹。当你选择的初始参数完全错误时,我们的机制不会自动调整。

在本例中,第一个预期不平衡阈值设置得太高,并且没有为整个月的数据生成柱线。
其次,虽然我喜欢我们的期望是动态的这个想法,但是我并不真正理解所建议的实现。如果我们跟随 AFML 对市场进行采样,我们会得到不同的棒线:每个棒线都有不同的信息内容。这可能很棒,但关键是我们在每个条形中包含的信息量及其动态几乎不受我们的控制。****
再看一下上面预期失衡的定义。b_t 的无条件期望值的绝对值可以假定为[0,1]中的值,因此真正定义期望不平衡的是期望的分笔成交点数量。这意味着,如果最后一根棒线需要更多(更少)的分笔成交点,则下一根棒线的预期不平衡可能会更高(更低)。但是你怎么能证明这个想法呢?如果在关闭最后一根棒线之前,只花了很多分笔成交点就达到了你预期的不平衡水平,为什么你的不平衡预期会增加呢?
关闭酒吧的门槛应该由其他因素决定。理想情况下,当当前的不平衡达到一个重要的阈值时,我会关闭一个棒线,这个阈值告诉我价格将在接下来的 X 个成交量棒线中受到影响。这一显著阈值是否应该保持不变是一个研究问题。
结论
鉴于上面提到的几点,我决定(目前)坚持使用一个以持续的不平衡期望为特征的实现。这意味着,每次我想要构建 TiB 时,我都必须指定将用于关闭每个棒线的不平衡阈值。
正如 Gerald Martinez 在他的有趣的文章中写的关于不平衡棒线的文章“不平衡棒线的目标是在达到新的平衡之前及早发现市场方向性的转变”。带着这个目标,我将继续学习,以了解如何提高我对这个概念的理解。特别是,我想了解是否存在重要的阈值,以及是否可以动态地指定它们。
写这篇文章,分享我的想法,展开讨论。因此,如果您有任何问题或疑问,欢迎您的评论。
奖金部分
达到不平衡水平的概率取决于分笔成交点水平(计算不平衡的分笔成交点数量)。下图显示了不同分笔成交点的滚动失衡的经验分布。

不同分笔成交点范围内的滚动绝对不平衡分布。在 5000 个分笔成交点的范围内,可能会观察到 50–100 的绝对不平衡。在 100 个分笔成交点上不可能观察到同样的不平衡。
下面您会看到一个用恒定预期不平衡范例创建的 TiB 图。蓝点是用音量时钟采样的价格。

使用恒定预期范例创建的分笔成交点不平衡条(图中的烛台状)示例。DAX 期货合约。蓝点是音量条的结束点。
附录和代码
每个图都基于 2019 年 12 月到期的 DAX 期货合约的分笔成交点数据。从 2019 年 1 月 11 日到 2019 年 11 月 30 日,我使用了一个月的 ticks。不同的数据可能会得到不同的结果。
下面你可以找到一些意大利面条代码来复制我的分析,甚至用你的分笔成交点数据创建不平衡棒线。如果稍微修改一下 spaghetti 脚本,您将能够使用一个恒定的期望不平衡范例来创建 bar ids。
意大利面条代码创建不平衡 _ 酒吧 _ 身份证,再现和改善我所做的
使用机器学习的信息图信息组织——综述

由 Unsplash 上的 Gris Olmedo 拍摄的照片
利用机器学习自动化信息图生成过程。讨论信息可视化领域的最新研究。
信息图对于以更易理解的方式向观众展示信息至关重要。随着它们的使用扩展到许多(如果不是全部的话)专业领域,如新闻、科学、研究、广告、商业,关于自动生成漂亮的和以用户为中心的信息图的过程的研究已经成为数据可视化社区的最新特征。
在这一系列的文章中,我们将讨论 5 篇开创性的研究论文,它们集中在为不同类型的数据自动生成漂亮的信息图的过程上。

信息图表示例。[1]
目前,有许多非常强大的设计软件和代码库支持从数据生成信息图。下面的列表提到了一些您可能想看看的工具和库。然而,当设计信息图时,过程并不简单。要创作一件非常吸引人的艺术品,需要昂贵的劳动力,而且通常非常耗时。每一条小信息,从选择要突出的主题,到选择颜色组合,创建信息图所需的技能也是多种多样的。
支持信息图生成的软件
- Microsoft Powerpoint(设计理念)
- Microsoft PowerBI —用于开发数据可视化仪表板
- Adobe Illustrator
- (舞台上由人扮的)静态画面
帮助创建信息图表的 Javascript 包
- D3.js
- Highcharts.js
自动化信息图表设计
最近在信息可视化方面的研究显示,人们对自动化/半自动化复杂的信息图生成过程越来越感兴趣。然而,这项研究的主要目的并不是完全摆脱人类的控制,而是专注于开发技术,以支持设计师的决策过程。为了研究这项研究,我们将论文大致分为 5 类:
- 时间线信息图设计自动化
- 图标设计自动化
- 基于信息流的自动化
- 基于文本的自动化
- 图像图表融合自动化
时间线信息图生成[1,2]

从时间序列信息图中提取模板组件并拟合新数据。[1]
顾名思义,这些方法试图为基于时间的数据自动设计信息图。其中一种方法直接在已经存在的时间线信息图的位图图像上工作,以提取全局和局部信息。全局信息可以是以下类型:方向、布局(统一、分面、分段等。)和表示类型(径向、线性等。).类似地,本地信息是关于包含信息图中一条信息的边界框,例如,文本框、图标等。这些方法使用现有的卷积神经网络来绘制边界框或分割局部信息的信息图,并通过分类来预测全局信息的值。提取模板信息后,我们可以用新的信息替换旧的信息,自动得到新的信息图。

时间线说书人。[2]
另一方面,有一个名为 Timeline Storyteller [2]的可视化仪表板,它直接获取时间线数据的原始 CSV/Excel 表,并生成信息图,用户可以根据自己的设计选择定制这些信息图。用户可以用非常大的时间序列数据集设计信息图和动画,并将他们选择的图片导入这些信息图,如示例所示。试试时间线说书人这里。
图标设计自动化[3]

复合图标生成。[3]
我们列表中的下一个类别是关于设计复杂图标的技术。因此,给定一个输入文本,例如,房屋清洁,任务就是给出一个语义上有意义的图标。现在,通过查询中的每个单词搜索图标的问题可能看起来很简单,例如,一个图标代表“房子”,另一个图标代表“清洁”。现在把这两个图标结合起来,我们就有了一个复合图标。尽管这对于简单的查询来说是正确的,但是语义标记图标的数据却很少。因此,我们需要想办法将现有的标记图标的语义知识扩展到其他没有被很好探索的领域。为此,使用来自自然语言处理的经过充分研究的单词嵌入可能是有用的。

从文本查询开发复合图标管道。[3]
给定一个查询文本,我们为每个被注释并与现有数据集中的图标相关联的单字计算最近的单词。然后,基于样式兼容性对从查询词提取的图标进行排序。为了测量样式兼容性,为每个描述其样式的图标生成一个嵌入向量。所以两个图标的风格向量越接近,它们的风格就越相似。为此,我们可以训练 CNN 来生成这些风格嵌入。该模型是在现有的 1000 个人管理的复合图标数据集上训练的,其中复合图标内的各个图标被认为在风格上更相似,而不是在另一个输入复合图标中出现的该图标的不同风格。

对于拼图的最后一部分,当基于语义和样式兼容性过滤图标时,它们基于空间兼容性放置。为了计算空间兼容性,研究了来自 1k 人工管理的复合图标的图标,以基于每个图标生成模板(如上图所示)。这样做是为了产生另一个图标相对于当前图标可以放置在哪里的想法。使用该信息,图标被放置在模板中以生成复合图标。
基于信息流的自动化[4]
转到文本类别,这项工作的重点是提取信息图中的信息流。
给定一个信息图图像,信息流基本上是一种显示图像中视觉组位置方向的方式。视觉组是包含信息图表中的片段的信息,这些片段被重复以呈现完整的画面。这些视觉群体的流动被称为叙事流。

信息图表中的信息流方向。[4]
本文根据所研究的视觉群体及其在 13k 信息图表图像数据集中的位置,将这些叙事流模式分为 12 类。对象检测 CNN 最初用于检测信息图中包含图标和文本的视觉组,然后研究位置以生成信息流图。

从由 YOLO 网络检测的包围盒中生成信息流路径。[4]
本文讨论了一种流提取算法,将 CNN(【YOLO】)检测到的包围盒根据接近度和大小分组为视觉组,然后检测这些视觉组的流,预测最终的视觉信息流。除此之外,该系统还能够执行反向选择和分类,其中用户绘制信息流的方向,并且系统获取具有相似流向的相关信息图。此外,如上所述,下图显示了信息流的 12 个分类类别。

信息图表中的 12 类信息流。[4]
本文还研究了基于这 12 个类别的信息图中不同元素的空间分布,如下所示。

每个叙事流类别中元素的空间分布。[4]
基于文本的自动化[5]

为报表自动生成的信息图: 超过 20%的智能手机用户是社交网络用户 。[5]
这个系列中的另一个系统被称为文本到即时消息系统。给定一个统计报表,这个系统试图直接提出完整的信息图设计。与其他信息图管理工具不同,在其他工具中,用户需要/可以编辑信息图的最终设计,Text-to-Viz 生成这些定义良好、美观的信息图,不需要编辑。如果用户不需要创建设计丰富的信息图,但需要简单快捷的东西以更好的方式呈现一条统计信息,那么这个系统的最佳用例就是这种情况。根据这篇文章,最常见的信息图表有 4 种类型:

每个类别的信息图及其出现百分比。[5]
- 基于统计的:包含图表、象形图等的信息图。用于呈现统计信息。
- 基于时间轴:显示时间轴信息。
- 基于过程的:一步一步的行动演示。
- 基于位置:在地图上显示信息。
根据这项研究,由于大约 50%的信息图是基于统计的,其中大约 45%是基于比例的,所以他们只尝试为这组信息图创建一个自动信息图生成系统。之后,下一步是研究基于比例的信息文本的不同部分。下面显示了一个例子,他们试图分类和提取要单独设计的信息。

对基于比例的信息的不同部分进行分类。[5]
接下来,设计空间需要根据不同元素的放置位置进行划分。研究人员提出了 20 种模板设计,可以根据论文中提到的规则放置不同的元素。

根据模板设计信息图。[5]

设计模板时考虑的规则。[5]
图像图表融合自动化[6]

嵌入图表的图像。[6]
自动信息图表生成列表中的最后一项技术是设计包含聊天内容的图像的技术,如上图所示。一项关于摄影信息图表的调查显示了常用于呈现嵌入图像中的数据的图表类型[6]。分别是条形图【41.2% 】,饼图【21.4% 】,折线图【9.4% 】,散点图【2.2%】。除了图表之外,嵌入该信息的其他方式是单个分割对象:其中图形沿着水平/垂直轴被分割成更小的部分,并且这些分割的面积可以基于我们试图比较的不同量的比率。接下来是多个调整大小的对象,其中图像内的对象根据它们试图描绘的数据来调整大小。使用关于如何和在哪里表示信息的信息,研究人员通常遵循下面显示的管道来生成最终的信息图。

将图表嵌入图像的工作流程。[6]
因此,从给定的数据集中,选择相关的变量,并收集对应于这些变量的图像。当用户选择这些图像中的一个时,就会为所选择的变量生成图表。这些将被嵌入在选定的图像。在这一阶段,用户可以拖动图像上的一个区域来嵌入图表,或者他们可以从该图像中选择特征(例如霍夫线)来用作在这些图像上覆盖图表的锚点。

利用掩蔽技术嵌入图表。[6]

基于图像特征(本例中为霍夫线)的图表嵌入。[6]
总的来说,用休线和“饼图/条形图等”来表示“趋势/时间线数据(折线图)”是合理的用掩蔽技术。为了微调这些嵌入,可以为每种类型的图表计算不同类型的失真。例如,比较高线和折线图的斜率可以给出折线图嵌入图像的程度的估计失真。这些值用于优化图表在图像上的拟合,以生成美学信息图像。最后,所有这些都在一个界面中实现,用户可以使用他们的领域知识或设计技能来微调这些自动生成的结果。
结论
我们讨论了在不同类型的数据集上生成信息图的方法:时间线、图标、文本和图表。所有这些方法都侧重于信息图的某个方面,侧重于它们试图表示的数据类型。这些线索通常是对已经存在的信息图表进行调查的结果,然后使用该信息来自动化该过程。这仍然是一个很有前途的新的研究领域。未来的研究方向可以是探索更多种类的信息图,然后将现有技术与新技术相结合,创建一种更全面、更通用的技术,以自动化/半自动化这一繁琐的信息图生成过程。
参考
[1]走向自动化信息图设计:基于深度学习的可扩展时间线自动提取,Zhutian Chen 等。阿尔,2019
[2]时间线说书人,马修·布雷默等。阿尔,2019
[3] ICONATE:复合图标的自动生成与构思,赵南轩等.阿尔,2020
[4]探索信息图表中的视觉信息流,最小。鲁。et。阿尔,2020
[5] Text-to-Viz:从与比例相关的自然语言语句中自动生成信息图。崔薇薇等人。艾尔。, 2019
[6]信息图像:将数据嵌入专题图像,Darius Coelho 等人。艾尔。, 2020
基础设施即代码—优点与缺点
行业笔记
构建高质量软件的基本方法

如今,大多数软件公司必须频繁发布产品,以消除缺陷或引入新功能。此外,如果他们有基于云的产品,他们需要定期调配和管理云服务。这些任务可以手动执行,但效率非常低。
您可以通过编写代码来供应和管理云服务。这种方法被称为代码基础设施或 IaC。在本文中,我首先描述了使用 IaC 解决方案的好处。然后,我分享我使用这种方法的经验。
IaC 方法使我们能够:
- 再造云服务无数,
- 监控云配置轻松、
- 在开发管道中自动执行云供应,以及
- 选择更灵活的云服务提供商。
我再解释一下。
为什么基础设施是代码?
—重复
由于多种原因,您必须在开发过程中多次配置云基础架构(例如网络、安全和存储)。例如,如果一个实例在集群中关闭,您的服务将停止工作。在这种情况下,您必须重新进行云配置,并且希望与之前的配置完全一致。
—监控
在 IaC 解决方案中,一切都是用人类和机器可读的语言编写的,比如 YAML 或 JSON。因此,配置文件可以在版本控制系统中存档和标记,以备将来使用。因此,团队领导或 CTO 可以轻松地监控或检查这种配置。请注意,您只需要监视配置文件,而不需要 IaC 解决方案创建额外的文件。
举例。让我们假设工程团队选择了 AWS 基础设施,并分配了几个带有 16 个 CPU 的 EC2 实例来交付产品。使用 IaC 解决方案,领导可以轻松观察 EC2 实例的类型,并防止公司花费不必要的金额。这是一个在复杂产品中非常需要的透明度。
—自动化
您可能希望在持续集成和部署或 CI/CD 管道中巧妙地嵌入云供应步骤。不建议每次想要部署解决方案时都执行云供应步骤,尤其是在开发环境中。但是,您可能希望在产品发布渠道中包含云供应步骤,尤其是在云配置发生变化的早期。
举例。你想搭建舞台,发布配置完全相同的环境。但是,配置会不断变化,因为您仍然不确定许多细节。您可以使用 IaC 解决方案来确保拥有相同的环境。另外,你对 YAML 文件做了一些修改,服务停止工作。您有一个截止日期,没有时间调试。您只需要将它回滚到过去的某个功能点。借助 IaC 解决方案,您可以访问以前的云配置。
—灵活性
如果你通过使用所有的本地技术栈将自己锁定在一个云服务提供商身上,这将是非常昂贵的。云服务提供商的本地技术堆栈可能与其对手不兼容。因此,您可能无法轻松地迁移到其他服务,这可能会导致无法负担每月的账单。
二。我使用 IaC 的体验如何?
在我最近的经历中,我负责构建和管理 CI/CD 管道。我与产品经理密切合作发布产品。没有 IaC 解决方案,我无法交付任务。在这里,我想分享一下我的经历。
将开发局限于某个特定的供应商是很昂贵的。
在早期,我们获得了价值几千美元的信用额度来使用 AWS。我们可以开始使用所有 AWS 技术栈来开发我们的解决方案。然而,与许多同行相反,我认为应该是供应商不可知的,即使该供应商是亚马逊。
如果我们将自己锁定在一个供应商身上,我们将无法控制每月的账单,并且我们不能轻易将其最小化。例如,如果我们收到使用其他云服务的信用,我们将服务迁移到新主机就不容易了。所以,我选择了 Terraform 而不是 CloudFormation 来配置更灵活的云基础设施。
请注意,我无意在本文中详细描述 CloudFormation vs Terraform 的优缺点。
甚至 AWS EC2 实例也可能永久关闭。
在我们在 AWS 上设置云服务几周后,我们收到了一封来自 Amazon 的电子邮件,称集群中的一个 EC2 实例由于硬件问题将被永久关闭。我们在一张 JIRA 卡片上注意到了这个问题,并把它放在了我们的待办事项中,但它很容易被我们忽略。
在一个美丽的星期一,我们的云服务突然遇到了一个不寻常的错误。知道我们有一个交付的最后期限,它就不再那么漂亮了!经过调查,我们发现该错误是由于 EC2 实例关闭引起的。多亏了 Terraform,我们能够快速可靠地重建 EC2 集群。
阶段和发布环境必须完全相同。
当一些客户开始定期使用我们的解决方案时,我们将 stage 环境添加到我们的开发工作流中。阶段环境降低了在发布中失败或遇到意外行为的风险。
我们必须确信阶段和发布环境总是相同的。即使是很小的差异也可能导致失败。使用 IaC 方法是构建相同开发环境的最佳实践。所以,我们也用了它。
我们不得不多次配置云基础设施。
在早期,我们只有一个单一的开发环境。因此,我们没有想到 IaC 解决方案的必要性。然而,我们到达了一个点,我们有三个开发环境:开发、阶段和发布。因此,我们必须配置比以前多三倍的云基础架构。
另外,我们不知道每个环境需要什么样的云配置。因此,我们必须进行实验来找到最佳配置。显然,如果没有 IaC 解决方案,我们不可能进行这些实验。
我们每次都需要将一个文件复制到 EC2 实例中。
在开发过程中的某个时候,我们决定将 DockerHub 帐户设为私有。为了确保 CI/CD 管道顺利工作,我们必须存储帐户凭证,并在需要时检索它们。
为了遵循最佳实践,我们应该在 AWS secret manager 之类的密码库中存储凭证。由于我们有一个确定的截止日期,并且我们想对公众关闭我们的 DockerHub 帐户,我们选择了一个更简单的方法。我们设法在 EC2 实例的云供应阶段存储凭证文件。这不是最好的方法,但至少相对提高了安全性。
不公司对一切都有行业标准。
我们必须尽可能快地发展。我们有竞争对手,我们希望远远领先于他们。因此,我们总是使用能为我们提供更好用户体验的解决方案。例如,我们发现 Terraform 与它的替代品相比,为我们提供了:
- 一种对人类友好的开发语言,
- 写得非常好和更新的文件,和
- 易于理解的开发管道。
像亚马逊这样的公司对所有的云服务都有自己的解决方案;然而,他们不一定是最好的或最受欢迎的。例如,AWS 的 IaC 解决方案有 CloudFormation ,但 Terraform 正在成为这种背景下的领先解决方案。
临终遗言
我所有的经历只是让我对基础设施如代码或 IaC 解决方案更感兴趣;尤其是 Terraform。您可能不需要以高级方式使用 IaC 解决方案。但是,开始使用这种方法来逐步解决您的挑战和需求是非常重要的。如果你开始使用这种方法,你一定会喜欢它。
感谢阅读!
如果你喜欢这个帖子,想支持我…
[## 通过我的推荐链接加入 Medium—Pedram Ataee 博士
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
pedram-ataee.medium.com](https://pedram-ataee.medium.com/membership)
Python 中的继承:数据科学家的基础
用一个具体的例子来理解基础!

克里斯托夫·高尔在 Unsplash 上拍摄的照片
类继承是面向对象编程中的一个重要概念。它使我们能够扩展现有类的能力。为了创建一个新的类,我们使用一个可用的类作为基础,并根据我们的需要扩展它的功能。因为我们通过使用基类中可用的方法和数据定义来构建新类,所以开发和维护时间减少了,代码可重用性增加了。
这篇文章将向你介绍 Python 中类继承的基础知识。
让我们编写一个 Python3 代码,其中包含一个简单的类继承示例;
import pandas as pd
import random**# BASE CLASS
*class* CSVGetInfo:**
**""" This class displays the summary of the tabular data contained
in a CSV file """** instance_count = 0 **# Initializer / Instance Attributes** *def* __init__(*self*, *path*, *file_name*):
CSVGetInfo.increase_instance_count()
self.path = path
self.file_name = file_name
print("CSVGetInfo class object has been instantiated") **# Instance Method**
*def* display_summary(*self*):
data = pd.read_csv(self.path + self.file_name)
print(self.file_name)
print(data.head(self.generate_random_number(10)))
print(data.info())
return data **# Class Methods
@*classmethod*** *def* increase_instance_count(*cls*):
cls.instance_count += 1
print(cls.instance_count) **@*classmethod*** *def* read_file_1(*cls*):
return cls("/Users/erdemisbilen/Lessons/", "data_by_artists.csv") **@*classmethod*** *def* read_file_2(*cls*):
return cls("/Users/erdemisbilen/Lessons/", "data_by_genres.csv") **# Static Methods
@*staticmethod*** *def* generate_random_number(*limit*):
return random.randint(1, limit)**# SUB CLASS *class* CSVGetColumnDetails(*CSVGetInfo*):**
**""" This class displays the summary of a column in a tabular data
contained in a CSV file """** **# Initializer / Instance Attributes** *def* __init__(*self*, *path*, *file_name*, *column_name*):
CSVGetInfo.__init__(self, path, file_name)
self.column_name = column_name
print("CSVGetDetail class object has been instantiated") **# Instance Method**
*def* display_column_summary(*self*):
data = self.display_summary()
print(data[self.column_name].describe()) **@*classmethod*** *def* read_file_1(*cls*, *column_name*):
return cls("/Users/erdemisbilen/Lessons/", "data_by_artists.csv",
column_name)if __name__ == '__main__':
data = CSVGetColumnDetails.read_file_1("danceability")
data.display_column_summary()

Python 中的继承
在上面的 Python 代码中,我们有 CSVGetInfo 基类,它包含几个方法和数据定义。
display _ summary(self)实例方法使用 path 和 file_name 中提供的值打印 CVS 文件中包含的表格数据的摘要。
还有几个类方法,read _ file _ 2(cls)increase _ instance _ count(cls),缓解基类的对象实例化。**
假设我们想要创建一个新类csvgetcolumndedetails,以获取表格数据中特定列的汇总信息。我们可以从头开始编写一个新的类,但是更好的方法是继承和扩展 CSVGetInfo 类中已经可用的一些方法和数据定义。
****# BASE CLASS
*class* CSVGetInfo:
....
....****# SUB CLASS *class* CSVGetColumnDetails(*CSVGetInfo*):
....
....****
【class name】是 Python 用来创建子类的继承语法。在我们的例子中,我们的基类是CSVGetInfo,我们的扩展子类是*csvgetcolumndedetails。*****
子类中的属性初始化
我们调用我们基类的 init 方法来实例化 路径 和 文件名 属性。我们将这些属性从基类派生到子类。
仅在我们的子类级别可用的 column_name 属性用表示 CSVGetColumnDetails 的实例的 self 符号进行实例化。****
****# Initializer / Instance Attributes
** *def* __init__(*self*, *path*, *file_name*, *column_name*):
CSVGetInfo.__init__(self, path, file_name)
self.column_name = column_name
print("CSVGetDetail class object has been instantiated")**

Raul Varzar 在 Unsplash 上拍摄的照片
扩展基类中可用的方法
然后我们在基类派生的display _ summary()方法的帮助下,在我们的子类中创建新方法。我们在子类中使用并扩展了display _ summary()的功能来定义一个新方法。
****# Instance Method**
*def* display_column_summary(*self*):
data = self.display_summary()
print(data[self.column_name].describe())**
这个新方法在我们的子类中,【display _ column _ summary】(self),** 显示特定列的摘要,通过使用数据 【显示 _ 摘要】**方法返回。这个子类方法还有一个子类属性 column_name。****
重写基类中可用的方法
请注意,我们有 read_file_1 类方法,它们都在我们的基类和子类中定义了不同的实现。
基类中的read _ file _ 1class 方法只是传递了 path 和 file_name 值来实例化基类对象,而子类中的方法用一个附加参数 column_name 来实例化子类对象。
这意味着子类中的 read_file_1 方法覆盖了基类中可用的相同方法。当这些方法被调用时,它们执行它们独特的实现。
****# BASE CLASS
*class* CSVGetInfo:
....
....
** **@*classmethod*** *def* read_file_1(*cls*):
return cls("/Users/erdemisbilen/Lessons/", "data_by_artists.csv")**# SUB CLASS *class* CSVGetColumnDetails(*CSVGetInfo*):
....
....** **@*classmethod*** *def* read_file_1(*cls*, *column_name*):
return cls("/Users/erdemisbilen/Lessons/", "data_by_artists.csv",
column_name)**

乔希·考奇在 Unsplash 上拍摄的照片
类继承中的命名约定
基类中可能有一些方法或属性(实例变量)只在基类中使用。它们被称为私有方法,并以双下划线约定_ _ private method name命名。这些方法不应该在基类之外调用,包括子类。
基类中还可能有一些其他的方法或属性,它们只在基类或子类定义中使用。它们被称为受保护的方法,并以单条下划线约定_ protected method name命名。这些方法应该只在基类和子类结构中调用。
关键要点
- 继承增加了代码的可重用性,减少了开发和维护时间。
- 继承允许我们定义一个类,它接受并扩展基类中所有可用的方法和数据定义。
结论
在这篇文章中,我解释了 Python 中类继承的基础。
这篇文章中的代码和使用的 CSV 文件可以在我的 GitHub 资源库中找到。
我希望这篇文章对你有用。
感谢您的阅读!
数据和人工智能领域的创新和专利思维
我们如何专注于推动数据和人工智能创新,以及在专利建设过程中需要考虑哪些因素才能产生更大影响
当我写下这些想法时,我希望所有人在这个前所未有的时代都平安无事。当我们被逼到绝境或受到挑战时,我们通常会尽力做到最好。如果你参考下面埃德蒙·姆比安卡的话,这反映了一些事情。
“当你不害怕无情地推动自己推倒所有限制之墙时,伟大就会发生”——埃德蒙·姆比亚卡
创新和数据科学之间存在明显的界限。成功的端到端数据科学项目的框架需要结构化的思维、迭代方法和多种方法或实验来产生成功的影响。创新思维是非常重要的,也是相互关联的。

当我们寻求创新、撰写披露或专利时,我们需要注意以下关键方面。这在数据科学的背景下非常重要。
- 这个想法是新的吗?即什么是“新颖性”
- 它不明显吗?
- 有用吗?
- 是否启用,能否以适当的细节实现?
- 它有重大的商业价值和影响吗?
在处理数据科学设置时,以上几点完全相同。我们思考业务问题,了解目标,进行设计思考以推测问题和解决方法,更重要的是了解每个角色的想法和期望,将业务问题与数据问题相关联,进行探索性的数据分析,进行数据管理、数据争论、针对“需求”的数据转换,定义或制定功能,使用功能选择算法,试验各种不同的算法组合,评估结果,再次迭代并继续,直到我们获得最佳结果,呈现结果以衡量影响和价值创造,结束反馈循环等等。这些方法中的大多数都是迭代的,在过程的大部分时间里需要“跳出框框”的思维,不同的方法可以是新颖的,在分析的基础上选择“最佳方法”。
创新文化,它的审查过程,思考多种方法来定义一个新的方法是非常关键的核心创新。当我们处理数据科学过程来解决任何业务问题时,这反映了很多。同时,我们需要很好地理解这个过程。我们需要在数据科学的披露创造过程中引导自己。
以下是关于可视为检查表项目的关键维度的想法:
清单 1:检查想法是否“新颖”/“新颖”

a)它与我开发或使用的任何产品、方法相似吗?据我所知,还有类似的吗?
b)它与我所学的任何技术相似吗?与我的相关学习技巧有关联吗?
c)在一些网站上进行搜索,例如谷歌专利、谷歌学术、ResearchGate、CiteSeer、IEEE 电子图书馆、ACM 数字图书馆等,看看是否有更接近这个想法的网站已经存在。
d)您可能以前没有使用过这些产品,但是它们可能以某种形式适用。我们能检查那个方面吗?
e)让我们参考专利数据库,在那里我们将得到一些描述的类似方法。他们离这个发明近吗?
f)在任何一家公司,都会有当地的知识产权律师或相关机构在这个过程中提供帮助。最好带着这些发现和信息去找他们,解决他们可能有的任何疑问。
现有技术搜索:
在进行披露工作时,先有技术搜索极其重要。我们需要确保搜索与我们的方法相关和接近的现有技术,以及我们的方法或想法如何区别于其他现有技术。现有技术可以是许多不同的形式,如出版物或现有产品,或服务,或一些带有公式方法的博客文章等。出版物(可能是最容易获得的现有技术类型)的例子可以是专利本身、用户手册、网页、产品手册、教科书、公开的专利申请、杂志、期刊、会议论文、博士论文和类似的人工制品。对于我们来说,将出版物视为现有技术,其参考日期必须早于我们申请的申请日。
清单 2:检查想法是否“不明显”

Sharon McCutcheon 在 Unsplash 上拍摄的照片
非显而易见往往会绊倒新的评估者,因为显而易见的法律概念比显而易见的直觉概念更精确。充分理解和内化法律概念需要一些实践。
对于普通技术人员来说,一些有用的操作模型可以使用不同的点,例如大专文凭持有者、受过相关产品培训的工程或计算机科学课程的特定级别、了解 SQL、存储过程及其用法的从业者等等。
清单 3:检查想法是否“有用”?

由 Kaung Myat Min 在 Unsplash 上拍摄的照片
我们可以着眼于在我们的创新中看到“有用性”方面,并尝试基于以下一些问题进行探索。
- 它解决什么问题?(从数据科学的角度来看,这看起来很合适,因为我们从项目开始就已经着手于基于业务需求的问题解决方法)
- 它是否支持任何功能来执行某项功能?
- 如果实现的话,发明会像描述的那样工作吗?在评估过程中,描述不需要完整,只要合理就行。(从数据科学的角度来看,我们需要确保我们有一个可重现的方法,并有清晰的重现步骤。这一点非常重要,因为再现性是数据科学解决方案的关键方面,以证明基于特定输入的结果,从而建立管道中使用的通用方法)
清单 4:检查想法是否处于“启用实施”模式?
易于实施:
- 这个想法是否足够详细,可以帮助 XYZ 轻松实现和使用它?(从数据科学的角度来看,概述整个方法的详细步骤是必须的)
- XYZ 解释过数据如何转化为结果吗?(如下图所示)

缺乏对清单要点的支持:
检查想法中的以下短语:
- “本发明可以随时间分析系统”
- “建议使用可以解决业务问题的预测分析算法”
- “系统能够解释参数来解决问题”
- “系统中的智能代理可用于做出决策”
- “数据被传送到智能系统”
清单 5:检查创意是否有“商业价值”?

詹姆斯·图斯在 Unsplash 上的照片
- 它能被检测到吗?(例如,如果是:发明是否在用户界面上,或在文档或其他描述中表现出来,等等?这有助于熟悉特定领域的任何人创建可实施的解决方案或产品)
- 它有战略价值吗?(例如,如果是:现有产品确实使用它,或者战略产品将来可能会使用它;基于这一点,这一想法可能有助于某一特定公司阻止竞争对手在同一领域创造价值)
- 有许可价值吗?(例如,它可能很棒:即可能被广泛实践或被主要竞争对手实践;也很难解决)
如果我们在预期商业价值和审查过程中有争议的发明现有技术的相关性之间绘制图表,我们可以将四个更广泛的领域分类如下:
第 1 类或第 1 类—哪个具有最高的商业价值
第 2 类或第 2 类——大多数发明可能属于这一类,具有商业价值,但低于第 1 类
第 3 类或第 3 类—商业价值稍低
第 4 类或第 4 类—完全没有商业价值,可以放弃

因此,总而言之,创新和数据科学是相互关联的。迭代方法有助于定义多种方法,并鼓励基于实验的结果,在结果中进行细化,以获得更好的成功,并对数据和人工智能产生影响。整个框架有助于建立创新思维,同时推动端到端数据科学计划取得成功。需要考虑诸如新颖性、有用性、非显而易见性、可实施性、可检测性、商业价值等关键方面。我们还必须考虑如何以这样一种方式创造创新,这种方式可能属于上述示意图中的类别 1 和类别 2,这意味着商业价值较高,而现有技术的相关性相对较低。
免责声明 :这里的帖子是来自我的经验、想法和各种来源的阅读的个人观点,不一定代表任何公司的立场、策略或观点。
使用一维卷积层的创新聊天机器人
虚拟助理项目
从头开始使用深度学习和 Conv-1D 层构建聊天机器人

【freepik.com】来源:免费图片来自
自过去十年以来,聊天机器人的受欢迎程度一直在上升。聊天机器人通常用于快速回答特定网站上最常见的问题。聊天机器人节省了时间,也减少了人力和开支。聊天机器人有很多种,每一种都专门针对一个或几个领域。了解你想构建哪种聊天机器人的最佳方法如下
如果你想建立聊天机器人,最好的方法是寻找你的目标受众、公司或企业。制作特定的聊天机器人是理想的,因为你可以大大提高不同任务的性能。
在本文中,我们将介绍如何使用一维卷积层构建一个很酷的聊天机器人。这个聊天机器人的目的是作为虚拟助理项目的智能聊天机器人。我将使用 witty.txt 数据集。预处理数据集的链接将在文章末尾与代码一起提供。您可以选择其他数据集,如专业数据集或护理数据集。我更喜欢机智的数据集,因为我更喜欢从我的聊天机器人那里收到讽刺的有趣评论,而不是严肃的东西。另一组数据的链接可以从这里查阅。这是微软官方的 bot builder 个性聊天。都是问答的形式。英语中的其他个性聊天数据集是关心、热情、友好和专业的。你可以根据自己的方便随意选择其中的任何一个。
注: 这是虚拟助手系列的 part-3。同一主题将有更多即将到来的部分,我们将介绍如何使用深度学习技术和 python 构建自己的虚拟助手。

来源:来自 freepik.com 的免费图片
简介:
我们将使用一维卷积层构建一个创新的聊天机器人。这种方法允许我们最大化或最小化一组特定值的强度。这最适合文本数据,因为我们将对一组选择性文本数据进行优先级排序。我们将使用基于“文本分类”的方法来构建我们的聊天机器人。为了更好地了解 1-D 卷积层,我们可以将它们称为创建卷积核的层,卷积核在单个空间(或时间)维度上与层输入进行卷积,以产生输出张量。如果 use_bias 为真,则创建一个偏置向量并添加到输出中。最后,如果激活不是“无”,它也应用于输出。要了解更多关于一维卷积层的信息,请参考这里的。现在有很多独特的聊天机器人正在开发,对它们的需求比以往任何时候都高。聊天机器人将在我们的虚拟助理项目中发挥重要作用,因为我们将使用它与我们交流。当我们不在的时候,聊天机器人也可以代替我们与其他用户交流。
方法:
我们将为我们的聊天机器人使用基于“文本分类”的方法。我们的第一步是将 witty.txt 数据集加载到一个变量中。我将在文章的最后在 GitHub 库中提供预处理过的数据集。这意味着我们不需要太担心清洁部分。然而,重要的是将我们的问题和回答分开,并将它们存储在单独的变量中。然后,我们将继续将数据分为训练数据集和验证数据集。
我们的下一步是将数据标记化,并将文本转换成序列。然后,在将我们的测试和训练响应转换为分类数据后,我们将对数据应用填充。最后,我们将确保扩展训练和测试问题的维度,以便以合适的格式通过一维卷积层。如果需要,我们也可以使用手套向量,因为它包含预先训练的单词向量。
然后,我们将继续构建我们的模型架构,该架构将使用大量一维卷积层完全定制。然后,我们将查看模型图并训练我们的模型,即拟合模型。最后,我们将使用图表可视化模型在训练和验证数据上的性能。我们还将研究如何使用我们保存的权重建立一个预测网络。

来源:照片由 Cookie 在 unsplash 上的 Pom
数据预处理:
如前所述,我将使用 witty.txt 数据集。我们将对数据集执行的第一步是将它们分成两个独立的列表。这些列表将是问题列表和响应列表。问题列表将存储所有问题,响应列表将存储所有相应的答案。一堆问题有很多重复的答案。总共有 89 个独特的答案,但重复是有意义的。这是因为许多问题可能有几乎相同的答案。
隔离前的数据集如下所示:
['你能问我一些关于我的事情吗?',“不用了,我很好。"]
将数据集分开后,数据集的第一个问题和答案如下所示:
问题 1:你能问我一些关于我的事情吗?回答 1:不,我很好。
完成分离步骤后,我们将当前的问题和响应数据集以 80:20 的比例分成训练和验证数据集。
在下一步中,我们将使用 Keras Tokenizer 函数对数据进行标记。
标记化: 标记化是指将较大的文本数据、短文或语料库拆分成较小的片段。这些较小的片段可以是较小的文档或文本数据行的形式。它们也可以是一本单词词典。
Keras Tokenizer 允许我们向量化文本语料库,方法是将每个文本转换为整数序列(每个整数是字典中某个标记的索引)或向量,其中每个标记的系数可以是二进制的,基于单词计数,基于 tf-idf。要了解更多关于使用 Keras 的 Tokenizer 类和文本数据预处理的信息,请访问这里。
在训练和测试问题的标记化之后,我们将把数据集的标记化器转储到 pickle 文件中。这可以在以后通过模型执行预测时加载 pickle 文件来访问。我们还将把训练和测试响应转换成分类格式,即把单词转换成二进制整数的向量类。
然后,我们将填充相应的问题训练和测试序列。这是为了确保我们的培训和验证输入具有固定的形状。最后一步是将测试和训练输出扩展成一个三维数组。这是将输入传递到 1-D 卷积层所需的形状。预处理的代码片段如下所示。完整的代码将在文章的最后提供,并带有一个到 GitHub 库的链接。

来源:克里斯托弗·高尔在 unsplash 上拍摄的照片
构建模型:
我们将以函数式 API 的方式构建模型。我们将有一个输入层,它将接受(max_len,)形状的输入。这是因为我们所有的文本数据都是按照最大长度的顺序填充的。因此,最大尺寸将被限制为最大长度。然后,我们将把这个输入传递到一个嵌入层。这样做的主要原因是为更高维度的输入数据创建嵌入,即将正整数转化为固定大小的密集向量。
然后我们将这个嵌入层传递到 3 个独立的一维卷积层。每个 conv-1D 层都有一个大小递增 4 的过滤器。我们从第一个 conv-1D 层的 4 个初始滤波器开始,然后我们有 8 个用于下一个卷积层,12 个用于最后的 conv-1D 层。它们都具有 relu 的激活功能。这通常是大多数任务的首选激活功能。我们将内核大小设为 3,并将初始化器设为 he_normal。我们将连接为 3 个卷积层接收的整个输出,并通过最大池层传递它们。maxpool 层用于对从 concatenate 层接收的输出进行下采样。然后,我们将通过一个辍学层。这是为了避免在文本数据的验证过程中过度拟合。
我们的下一步是将整个数据从漏失层传递到另外 3 个 conv-1D 层。这 3 个卷积层的表现和我们之前的完全一样。我们不需要修改任何东西。计算完这三个卷积层后,我们将再次连接它们,并通过 maxpool 1-D 层进行下采样。然后,我们将通过下一个丢弃层来丢弃一些额外的数据,以防止过度拟合。
下一个代码块将由最终的 1-D 卷积层、展平层和最终的下降层组成。我们的下一步是将数据从之前的 dropout 层传递到最终的 conv1D 层。我们将使接收到的输出变平,这样我们就可以让它通过密集层。在通过密集层之前,我们将再次使用最终下降来防止验证过程中的过拟合。
我们代码的最后一块将包含完全连接的层。我们将有一个带有 relu 激活功能的隐藏层,有 50 个隐藏节点。然后,我们将得到具有 softmax 激活函数的最终输出层,节点的数量将等于可能的唯一输出的数量。softmax 层将为我们提供每个预测的概率列表。最后,我们将使用输入层和输出层来定义我们的模型。读者可以随意添加或删除某些层。探索和试验各种激活函数、初始化器和单元数量是很好的。
让我们看看构建模型的全部代码。然后,我们将继续查看模型概要和模型图。
模型摘要:

模型图:

回访:
我们将使用的回调类似于我们在虚拟助手项目系列中以前的回调。让我们先看看它们——
我们将导入培训我们的模型所需的 3 个回调。3 个重要的回调是 ModelCheckpoint、ReduceLROnPlateau 和 Tensorboard。让我们看看每个回调函数执行什么任务。
- ModelCheckpoint —这个回调用于存储我们的模型在训练后的权重。通过指定 save_best_only=True,我们只保存模型的最佳权重。我们将使用 val_loss 指标来监控我们的培训。
- ReduceLROnPlateau —该回调用于在指定数量的时期后降低优化器的学习率。这里,我们将耐心指定为 3。如果损失在 3 个时期后没有改善,那么我们的学习率相应地降低 0.2 倍。这里用于监控的度量是损失函数。
- tensor board—tensor board 回调用于绘制图形的可视化,即精度和损耗的图形绘制。这里,我们将只查看训练和验证数据的图。
我们将把基于度量损失的最佳模型保存到文件 chatbot.h5 中。在访问预测功能和尝试预测每个问题的回答时,该文件将是至关重要的。我们将等待 3 个时期来改善损失。如果没有改善,那么我们将降低学习率。最后,如果需要,我们将使用 tensorboard 函数来可视化图形和直方图。
编译并拟合模型:
下面是编译和拟合模型的代码块。
我们正在最后一步编译和装配我们的模型。在这里,我们正在训练模型并将最佳权重保存到 chatbot.h5,这样我们就不必重复地重新训练模型,并且可以在需要时使用我们保存的模型。在这里,我对训练和验证数据都进行了训练。但是,如果您愿意,可以选择仅使用训练数据进行训练。我们使用的损失是 categorical _ crossentropy,它计算标签和预测之间的交叉熵损失。我们将使用的优化器是 Adam,学习率为 0.001,我们也将使用度量准确性来编译我们的模型。经过 50 个时期的训练,我们的结果如下所示:

图表:

预测:
我们将对用户输入的文本进行预测。为此,加载我们存储在 pickle 文件中的记号赋予器是很重要的。然后,我们将加载我们保存的模型的权重。我们将对输入的文本序列进行标记和填充。在标记化和填充之后,我们将预测用户对输入问题的响应。预测将通过保存的模型权重来完成。我们加载的模型将做出每一个预测。我们将在预测阶段使用 try 和 except 语句块。如果在预测过程中出现错误,我们不希望程序被终止。只有当用户明确传递“停止脚本”命令时,程序才会结束。让我们看一些使用这个脚本的预测—
进入你的台词:怎么了
有时候我喜欢从令人敬畏的状态中休息一下。
输入你的台词:你还好吗?
不,我很好。进入你的行列:你觉得什么有吸引力?我不是公认的美容专家。
输入你的台词:停止脚本
结束节目…..
该模型能够对大多数问题做出合理的预测。由于我们的模型在大约 70%的验证准确率后开始过度拟合,因此还有改进的空间。更多的事情,如正规化和寻找最佳辍学率是一些可以改善。可以通过更好的预处理步骤对该模型稍加改进。也可以使用其他方法,如注意顺序到顺序的实现。这篇文章的完整代码将在文章的下一部分提供。
注意:有时当你输入一个文本时,它可能不会返回任何输出。这可能是因为它做出了越界预测。然而,重新输入相同的文本,它会给你一个输出。

来源:卡洛斯·穆扎在 unsplash 上的照片
观察:
我们能够实现总体高准确度和验证准确度以及总体低损耗和验证损耗。该模型能够对用户输入的文本数据做出合理的预测。如前所述,还有改进的余地。总而言之,这是一个基于“文本分类”的聊天机器人的好模型。
就这样,我们到了文章的结尾。我们能够使用一维卷积层开发一个创新的聊天机器人。该项目的完整代码可以在这里找到。请随意探索和创新供参考的笔记本电脑。 GitHub 库包含了这个项目所需的所有文件和笔记本。我希望你们都像我写这篇文章一样喜欢阅读这篇文章。大呼应用 AI 牛逼。如果你们发现任何改进,请随时告诉我。非常感谢你的时间,我希望你们都有一个美好的一天!
用人工智能修复——找回你的图像![PyTorch]
Python-PyTorch
用 PyTorch 和 Python 解决图像修复问题

你知道你那本布满灰尘的相册里的童年旧照片可以修复吗?是啊,那种每个人都牵着手享受生活的感觉!不相信我?看看这个—
修复是一个保护过程,在这个过程中,艺术品受损、退化或缺失的部分被填充,以呈现完整的图像。【1】此工艺可应用于实物和数字艺术媒介,如油画或丙烯画、化学摄影版画、三维雕塑,或数字图像和视频。——https://en.wikipedia.org/wiki/Inpainting
图像修复是人工智能研究的一个活跃领域,人工智能已经能够提出比大多数艺术家更好的修复结果。在本文中,我们将讨论使用神经网络的图像修复,特别是上下文编码器。本文解释并实现了在 2016 年 CVPR 上展示的关于上下文编码器的研究工作。
上下文编码器
要开始使用上下文编码器,我们必须了解什么是自动编码器。自动编码器在结构上由编码器、解码器和瓶颈组成。通用自动编码器旨在通过忽略图像中的噪声来减小图像尺寸。然而,自动编码器并不专用于图像,也可以扩展到其他数据。自动编码器有特定的变体来完成特定的任务。

自动编码器架构
现在我们知道了自动编码器,我们可以将上下文编码器描述为自动编码器的一个类比。上下文编码器是一个卷积神经网络,它被训练成根据图像区域的周围环境生成任意图像区域的内容——即上下文编码器接收图像区域的周围数据,并试图生成适合图像区域的内容。就像我们小时候玩拼图游戏一样——只是我们不需要生成拼图块;)
我们这里的上下文编码器由一个将图像的上下文捕获为紧凑的潜在特征表示的编码器和一个使用该表示产生缺失图像内容的解码器组成。缺少图像内容?—因为我们需要一个庞大的数据集来训练神经网络,所以我们不能只处理修复问题图像。因此,我们从正常的图像数据集中分割出部分图像,以产生修补问题,并将图像馈送到神经网络,从而在我们分割的区域产生缺失的图像内容。
[重要的是要注意,输入到神经网络的图像有太多的缺失部分,经典的修复方法根本无法工作。]
氮化镓的使用
GANs 或生成对抗网络已被证明对图像生成极其有用。生成性对抗网络运行的基本原理是,一个生成器试图“愚弄”一个鉴别器,而一个确定的鉴别器试图得到该生成器。换句话说,两个网络分别试图最小化和最大化一个损失函数。
更多关于甘氏的信息在这里—https://medium . com/@ hmrishavbandyopadhyay/generative-adversarial-networks-hard-not-EEA 78 C1 d3c 95
区域遮罩
区域遮罩是我们遮挡的图像部分,以便我们可以将生成的修复问题反馈给模型。通过遮挡,我们只是将该图像区域的像素值设置为零。现在,我们有三种方法可以做到这一点—
- 中心区域:将图像数据分块的最简单方法是将中心正方形小块设置为零。虽然网络学习修复,但是我们面临泛化的问题。网络不能很好地概括,只能学习低级特征。
- 随机块:为了解决网络像在中心区域掩码中那样“锁定”在被掩码区域边界上的问题,掩码过程被随机化。不是选择单个正方形小块作为遮罩,而是设置多个重叠的正方形遮罩,这些遮罩占据图像的 1/4。
- 随机区域:然而,随机块屏蔽仍然具有网络锁定的清晰边界。为了解决这个问题,必须从图像中去除任意形状。可以从 PASCAL VOC 2012 数据集获得任意形状,将其变形并作为遮罩放置在随机图像位置。

从左起— a)中心区域遮罩,b)随机块遮罩,c)随机区域遮罩[来源:https://arxiv.org/abs/1604.07379】
在这里,我只实现了中心区域的蒙版方法,因为这只是让你开始用人工智能修复的一个指南。请随意尝试其他遮罩方法,并在评论中告诉我结果!
结构
现在,您应该对该模型有所了解了。让我们看看你是否正确;)
该模型由编码器和解码器部分组成,构建了该模型的上下文编码器部分。这部分也作为发生器产生数据,并试图欺骗鉴别器。鉴别器由卷积网络和 Sigmoid 函数组成,最终输出一个标量。
失败
模型的损失函数分为两部分:
- 重建损失-重建损失是 L2 损失函数。它有助于捕捉缺失区域的整体结构及其上下文的一致性。数学上,它被表达为—

L2 损失
这里需要注意的是,只使用 L2 损失会给我们一个模糊的图像。因为模糊的图像减少了平均像素误差,从而使 L2 损失最小化——但不是以我们希望的方式。
2.对抗性损失——这试图使预测“看起来”真实(记住生成器必须欺骗鉴别器!)这有助于我们克服失去 L2 会给我们带来的模糊印象。数学上,我们可以表达为—

对抗性损失
这里一个有趣的观察是,对抗性损失促使整个输出看起来真实,而不仅仅是丢失的部分。换句话说,对抗性网络使整个图像看起来更真实。
总损失函数:

模型的总损失
让我们建造它!
现在,既然我们已经清楚了网络的要点,让我们开始建立模型。我将首先建立模型结构,然后进入训练和损失函数部分。该模型将在 python 上 PyTorch 库的帮助下构建。
让我们从发电机网络开始:
网络的生成器模型-作为 python 模块实现
现在,鉴别器网络:
鉴频器网络——实现为一个模块
现在开始训练网络吧。我们将把批量大小设置为 64,将时期数设置为 100。学习率设置为 0.0002。
用于训练发生器和鉴别器的训练模块
结果
让我们看一看我们的模型已经能够构建什么!
第零时段的图像(噪声)

零历元图像
第 100 个纪元的图像—

第 100 个纪元的图像
让我们看看模型中包含了什么—

中央区域掩蔽图像
那个来自这个?耶!很酷吧。
实现您的模型版本。观看它重现你童年的照片——如果你足够优秀,你可能会重现人工智能修复的未来。那么,你还在等什么?
如果你的实现有任何问题,请在评论中告诉我。来帮忙了:)
查看我的博客以获得更快的更新,并订阅优质内容:D
克罗伊斯,吕底亚(小亚细亚)的国王,曾经问特尔斐的神谕,他是否应该对波斯开战…
www.theconvolvedblog.vision](https://www.theconvolvedblog.vision)
Hmrishav Bandyopadhyay 是印度 Jadavpur 大学电子与电信系的二年级学生。他的兴趣在于深度学习、计算机视觉和图像处理。可以通过以下方式联系到他:hmrishavbandyopadhyay@gmail.com | |https://hmrishavbandy . github . io
使用 Keras 和 TensorFlow 的图像输入管道
使用 Keras 和 TensorFlow 为深度学习模型的自定义图像数据集创建输入管道的指南
其次,在本系列的 中,学习如何使用 Kera 预处理、Tensorflow 和 tf.data 从自定义数据 创建输入管道来加载和创建图像序列和测试数据集。

这里使用的数据集是来自 Kaggle 的 Intel 图像分类,文章中的所有代码都在 Tensorflow 2.0 中工作。
英特尔图像分类数据集分为训练数据集、测试数据集和验证数据集。我们将仅使用训练数据集来学习如何使用不同的库加载数据集。
使用 Keras 预处理创建深度学习的输入管道
imagedata generator类为图像数据生成批量张量,并将像素值从 0 到 255 缩小到 0 到 1 之间的值。
我们可以对训练图像数据集应用不同的实时数据增强,如旋转图像、缩放图像、水平翻转或垂直翻转等。数据扩充不适用于验证或测试数据集。
**import pandas as pd
import numpy as np
import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img, array_to_img
import tensorflow as tf****IMG_WIDTH=200
IMG_HEIGHT=200
batch_size=4****train_dir = r'\CV\Intel_Images\seg_train\seg_train'
test_dir = r'\CV\Intel_Images\seg_pred\seg_pred'
val_dir = r'\CV\Intel_Images\seg_test\seg_test'****image_gen_train = ImageDataGenerator(rescale=1./255,
zoom_range=0.2,
rotation_range=65,
shear_range=0.09,
horizontal_flip=True,
vertical_flip=True)****image_gen_val = ImageDataGenerator(rescale=1./255)**
一旦imagedata generator的实例被创建,使用flow _ from _ directory()从目录 中读取图像文件。
【flow _ from _ directory()期望图像数据具有如下所示的特定结构,其中每个类具有一个文件夹,并且该类的图像包含在该类文件夹中。

文件夹结构为flow _ from _ directory()imagedata generator方法
**train_data_gen = image_gen_train.flow_from_directory(batch_size=batch_size,directory=train_dir,
shuffle=True, target_size=(IMG_HEIGHT, IMG_WIDTH,3), class_mode='sparse')****val_data_gen = image_gen_val.flow_from_directory(batch_size=batch_size,
directory=val_dir, target_size=(IMG_HEIGHT, IMG_WIDTH,3), class_mode='sparse')**
class _ indexes . keys()将从字典中的数据集中提取类名
**train_data_gen.class_indices.keys()**

创建一个简单的深度学习模型,编译它,并使用 Keras 预处理生成的数据集训练模型
**model=tf.keras.Sequential(
[
tf.keras.layers.InputLayer(input_shape=(200, 200, 3)),
tf.keras.layers.Conv2D(filters=32, kernel_size=3, strides=(2, 2), activation='relu'),
tf.keras.layers.Conv2D(filters=64, kernel_size=3, strides=(2, 2), activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(6)
])**#Compile the model
**model.compile(optimizer='rmsprop', loss='sparse_categorical_crossentropy',
metrics=['accuracy'])**#Fitting the model
**history = model.fit(train_data_gen,steps_per_epoch=len(train_data_gen)//batch_size, validation_data=val_data_gen, epochs=2)**
使用 TensorFlow 为深度学习创建输入管道
使用 Tensorflow 的输入管道将创建张量作为模型的输入。
- 使用打开图像文件tensor flow . io . read _ file()
- 解码文件的格式。这里我们有一个 JPEG 文件,所以我们用三个颜色通道的 decode_jpeg() 。
- 调整图像尺寸以匹配深度学习模型的输入层的输入尺寸。
- 使用 TensorFlow 将图像转换为 float 数据类型,然后将 0 到 1 之间的值归一化为 0 到 255。
- tf.stack() 创建一个堆叠的张量作为行数据
**def create_dataset_tf(img_folder):
class_name=[]
tf_img_data_array=[]
for dir1 in os.listdir(img_folder):
for file in os.listdir(os.path.join(img_folder, dir1)):
image= os.path.join(img_folder,dir1, file)
image = tf.io.read_file(image)
image = tf.io.decode_jpeg(image, channels=3)
image = tf.image.resize(image, (200,200))
image = tf.cast(image / 255., tf.float32)
tf_img_data_array.append(image)
class_name.append(dir1)
return tf.stack(tf_img_data_array, axis=0),class_name*****img_folder=r'CV\Intel_Images\seg_train\seg_train'******tf_img_data, class_name=create_dataset_tf(img_folder)***
将文本标签转换成数字代码
为类的所有唯一值创建一个字典
**target_dict={k: v for v, k in enumerate(np.unique(class_name))}
target_dict**

根据字典将 class_names 转换成它们各自的数值
**target_val= [target_dict[class_name[i]] for i in range(len(class_name))]**
创建一个简单的深度学习模型,编译它,训练模型。
它与我们之前在起诉 Keras.preprocessing()时创建的模型相同。 这里唯一的变化是输入图像数据和类名,这是一个张量值的列表来拟合模型。
**model=tf.keras.Sequential(
[
tf.keras.layers.InputLayer(input_shape=(200, 200, 3)),
tf.keras.layers.Conv2D(filters=32, kernel_size=3, strides=(2, 2), activation='relu'),
tf.keras.layers.Conv2D(filters=64, kernel_size=3, strides=(2, 2), activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(6)
])**#Compile the model
**model.compile(optimizer='rmsprop', loss='sparse_categorical_crossentropy',
metrics=['accuracy'])**#Fitting the model**history = model.fit(x=tf_img_data, y=tf.cast(list(map(int,target_val)),tf.int32), epochs=2)**
使用 tf.data 创建深度学习的输入管道
tf.data API 允许我们构建复杂的输入管道,同时读取不同格式的大量数据,然后应用转换。
在 TF . data for image processing pipeline 中,元素是单个训练示例,具有一对张量来表示图像及其对应的标签。
导入库和设置基本参数
**import numpy as np
import os
import tensorflow as tf****data_dir=r'\CV\Intel_Images\seg_train\seg_train'
batch_size = 32
img_height = 200
img_width = 200**
TF . data . dataset . list _ files()使用匹配模式从文件的目录列表创建数据集。
**list_ds = tf.data.Dataset.list_files(str(data_dir + '\\*\\*'), shuffle=False)**# get the count of image files in the train directory
**image_count=0
for dir1 in os.listdir(data_dir):
for files in os.listdir(os.path.join(data_dir, dir1)):
image_count+=1****list_ds = list_ds.shuffle(image_count, reshuffle_each_iteration=False)**
从目录名创建类别标签
**class_names = np.array(sorted([dir1 for dir1 in os.listdir(data_dir)]))**
将数据集拆分为 train 和 Val。
验证数据集占总数据集的 20%,训练数据集占整个数据集的 80%。
**val_size = int(image_count * 0.2)
train_ds = list_ds.skip(val_size)
val_ds = list_ds.take(val_size)**
为表示一对张量的单个训练/确认示例创建输入管道组件,以表示图像及其对应的标签。
#To process the label **def get_label(file_path):** # convert the path to a list of path components separated by sep **parts = tf.strings.split(file_path, os.path.sep)** # The second to last is the class-directory **one_hot = parts[-2] == class_names**# Integer encode the label **return tf.argmax(tf.cast(one_hot, tf.int32))**# To process the image
**def decode_img(img):** # convert the compressed string to a 3D uint8 tensor **img = tf.image.decode_jpeg(img, channels=3)** # resize the image to the desired size **return tf.image.resize(img, [img_height, img_width])**# To create the single training of validation example with image and its corresponding label **def process_path(file_path):
label = get_label(file_path)**# load the raw data from the file as a string **img = tf.io.read_file(file_path)
img = decode_img(img)
return img, label**
设置自动调谐;这将有助于在运行时将并行性级别的决策委托给 tf.data ,以优化 CPU/GPU 利用率。
**AUTOTUNE = tf.data.experimental.AUTOTUNE**
# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.
**train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)
val_ds = val_ds.map(process_path, num_parallel_calls=AUTOTUNE)**
为性能配置数据源
为了配置数据源的性能,使用预取。
TF . data 中的预取允许数据的预处理和训练步骤的模型执行重叠。
当模型正在执行训练步骤 100 时,输入管道正在读取步骤 101 的数据。
**def configure_for_performance(ds):
ds = ds.cache()
ds = ds.shuffle(buffer_size=1000)
ds = ds.batch(batch_size)
ds = ds.prefetch(buffer_size=AUTOTUNE)
return ds****train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)**
创建一个简单的深度学习模型
模型的输入是 tf.data.Dataset
**model=tf.keras.Sequential(
[
tf.keras.layers.InputLayer(input_shape=(200, 200, 3)),
tf.keras.layers.Conv2D(filters=32, kernel_size=3, strides=(2, 2), activation='relu'),
tf.keras.layers.Conv2D(filters=64, kernel_size=3, strides=(2, 2), activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(6)
])**#Compile the model
**model.compile(optimizer='rmsprop', loss='sparse_categorical_crossentropy',
metrics=['accuracy'])**#Fitting the model
**history = model.fit(train_ds,validation_data=val_ds,epochs=3)**
结论:
我得到的最好的训练时间是使用 tf.data,因为有预取,这是使用 AUTOTUNE 在并行级别上委托决策。
参考资料:
从目录中的图像文件生成 tf.data.Dataset。如果您的目录结构是:然后调用…
keras.io](https://keras.io/api/preprocessing/image/)
卷积神经网络内部

作者图片
简介
卷积神经网络(CNN) 是用于识别、分类等的深度学习算法之一。最常用于分析视觉图像,这是做、设计或实现它的困难任务之一。在这里,网络的每一层都与下一层的所有神经元相连。从 20 世纪 50 年代的一项生物学实验开始,这个领域已经有了很大的进步和发展。通常,几十年前,计算机很难识别猫和狗,但现在它已经变得像一个“你好世界项目”。
在过去的几十年里,图像识别或计算机视觉已经成为一个在研究、分析和预测方面越来越有兴趣、持续和进步的伟大课题。我们人类识别图像及其类型的方式,电子机器已经训练自己更深入地识别和看待事物。计算机视觉比人类视觉认知系统更擅长从图像中识别模式。
计算机视觉或 i 图像识别由深度学习算法驱动,该算法使用 CNN 来获得图像的感觉。它不仅能识别模式,还能记忆应该为每个输入图像提供的理想输出(在监督学习的情况下),或者通过扫描轮廓和颜色等特征对图像的组成部分进行分类。然后在扫描这些图像时使用这些内存。
当第一次进入 CNN 模型时,真的很难更深入地理解它。所以,我试着用基本而简短的回答来弄清楚 CNN 的内幕。

作者图片
人工神经网络中的多隐层前馈神经网络通常被称为(DNN)深度神经网络。卷积神经网络也是一种前馈神经网络。到目前为止,可以说 CNN 是一种广泛应用于识别和图像处理的识别算法,它具有结构简单、训练参数少、适应性强等特点。
因为神经网络接收输入(张量)并通过一系列隐藏层对其进行转换。每个隐藏层由一组神经元组成,其中每个神经元都与前一层中的所有神经元完全连接。
在每一层,单元被组织成称为特征地图的二维网格。这些特征图中的每一个都是卷积的结果,即相同的卷积层(权重集)被应用于该层中的每个位置。因此,在 2-D 网格上特定位置的单元只能从该层上类似位置的单元接收输入。并且对于特征图中的每个单元,附加到输入的权重是相同的。
当卷积层完成后,其他一些计算也完成了。其中之一是交叉特征归一化。这里,单元在特征地图中的特定空间位置的活动除以单元在其他特征地图中的相同位置的活动。另一个常见的操作是合用。池缩小了要素地图的大小。这一整套操作合起来称为【层】。网络的架构是由层数和与其相关的各种参数的选择来定义的,例如卷积滤波器的大小。
在卷积层内部,我们需要指定滤波器的数量、滤波器大小、填充、激活函数/非线性。
让我们和其他人讨论其中的一些。

图:CNN 架构 Img Ref:neur idines
简而言之,CNN 包含以下不同层:
a .致密层
b .卷积层
c .最大池层
d .辍学
所以,了解了它的基本架构之后,问题来了我们如何用代码设计卷积神经网络?
这个问题看起来很难,但实际上并不难。Python 有很好的库和框架来设计神经网络,不管它是 CNN,RNN T21 还是其他什么。我们唯一需要了解的是层、池和它们内部的其他参数。
让我们用一种简单的方法来设计它,并以抽象的方式选择最佳参数和超参数。
卷积层是卷积网络的核心构建模块,承担大部分繁重的计算工作。选择层数时,最好从最小的层开始,然后逐渐增加层的尺寸,或者从大的模型层开始,然后逐渐减小。当使用较大的模型时,选择我们最初构建的模型有多大变得非常困难。
当更深的网络能够开始收敛时,退化问题就暴露出来了:随着网络深度的增加,精度达到饱和(这可能不足为奇),然后迅速退化。出乎意料的是,这种退化不是由过拟合引起的,并且向适当深度的模型添加更多层导致更高的训练误差。
训练精度的下降表明,并不是所有的系统都同样容易优化。
虽然给出了相同数量的可训练参数,但可能出现在使用更多层或每层更多单元之间做出决定的情况。从这个意义上来说,通常更深比更宽更好。另一种使深度模型更容易的方法是添加连接非连续层的跳过连接。像我们可以使用 ResNet 架构类型的连接。
跳跃连接还为梯度更容易地回流创建了额外的路径。这使得更容易优化早期的层。在神经网络设计中,使用跳过连接是一种常见的模式。
汇集层
池层使表示更小、更易管理,并独立地在每个激活图上操作。汇集层接受三维体积,需要三个超参数,它们的空间范围为****F,步距为 S** ,并产生三维体积,其中 W=(W1-F)/S+1 , H=(H1-F)/S+1 , D2=D1 。池层引入了零参数,因为它计算输入的固定函数。我们不使用零填充来合并层。**
使用内核或过滤器模型时,通常最好使用 3X3 或 1X1 内核,因为大多数时候它工作得最好。我们可以将 3X3 内核相互堆叠,以获得更大的感受野。使用 1X1 滤镜的一个好处就是可以用于降维。
摘要
简而言之,我们可以说卷积层是接受体积为W1 * H1 * D1(Weights、 H eights 和 D epth)的层,这需要四个超参数,其中滤波器的数量被定义为 K,它们的空间范围** F, 步距 用数量为的零填充 P. 利用上述输入,卷积层产生大小为 W2H2D2 的体积,其中 W2 =(W1-F+2P)/S+1,H2 =(H1-F+2P)/S+1 (即宽度和高度通过对称相等地计算)和**D2 = k . K 重量和 K 偏差。在输出体积中, d- th 深度切片(大小为 W2*H2 )是在输入体积上以 S、步距执行 d- th 滤波器的有效卷积的结果,然后偏移 d- th 偏置。****

图:带过滤器的 CNN
感谢阅读。
参考文献:
1。https://arxiv.org/pdf/1506.01195.pdf
2。https://en.wikipedia.org/wiki/Convolutional_neural_network
3。https://www . Forbes . com/sites/cognitive world/2019/06/26/the-present-and-future-of-computer-vision/# 185 e 3778517d
4.https://cs231n.github.io/convolutional-networks/
**7.【https://www.youtube.com/watch?v=fTw3K8D5xDs **
8.https://keras.io/api/applications/resnet/
9.https://arxiv.org/pdf/1512.03385.pdf
逻辑回归
逻辑回归背后的理论和直觉,并使用 Python 代码实现它
这是一系列博客的一部分,在这里我将通过使用数学和代码来展示不同方面和机器学习算法的理论。这包括使用 Python 代码的算法的通常建模结构和对它为什么以及如何工作的直觉。

在这篇博客结束时,你会知道:
- 逻辑回归在数学上如何工作以及如何编码。
- 为什么逻辑回归是线性分类器。
- 如何评价你做的模型?
介绍
逻辑回归是当有人了解到分类时引入的首批算法之一。你可能已经读过回归和预测变量的连续性。分类是对离散变量进行的,这意味着您的预测是有限的,并且是基于类别的,就像二元结果的是/否、真/假。然而,简单地猜测“是”或“不是”是相当粗糙的。考虑到噪音,而不仅仅是给出一个二进制的答案,通常是有用的。
简而言之,我们想要概率,这意味着我们需要拟合一个随机模型。事实上,最好是给定输入变量 P(Y|X ),得到响应 Y 的条件分布。因此,如果我们的模型说有 51%的机会下雨,但没有下雨,这比它说有 99%的机会下雨要好(尽管即使是 99%的机会也不是一件确定的事情)。这就是为什么它被称为逻辑回归而不是分类的原因,因为它预测的概率是连续的(但有限的)。
很漂亮,对吧?但是,你一定在想,即使结果是有限的,线性回归也可能处理它。这里的有一个全面的答案,它非常直观,每当你试图将回归假设曲线拟合到离散数据并引入异常值时,这条线将试图拟合异常值,因此你需要将假设阈值改为较小的值,否则你的预测将会不准确。
现在让我们进入有趣的部分…
建模
我们有一个二元输出变量 Y,我们希望将条件概率 P(Y = 1|X = x)建模为 X 的函数。现在,逻辑回归属于学习的广义线性模型(GLMs) 家族。所以问题出现了“我们如何使用线性回归来解决这个问题?”
- 这个想法是让 P(x) 是 x 的线性函数,x 的每一个变化都会影响概率。这里的概念问题是 P 必须在 0 和 1 之间,线性函数是无界的。此外,在许多情况下,我们可能会看到“收益递减”——当 P 已经很大(或很小)时,改变 P 相同的量需要 x 比 P 接近 1/2 时有更大的变化。线性模型做不到这一点。
- 下一个最好的想法是让 log(P(x)) 是 x 的线性函数,这样改变一个输入变量会使概率乘以一个固定的量。

图 1-对数(x)曲线
正如你在上面看到的,对数只在一个方向上有界限。这意味着,与负向变化相比,x 向正向的变化可能不会显著影响结果。
3.最后,对两边值域有界的 log(P(x))的最佳修改是 logistic(或 logit)变换,log(P(x)/(1p(x))。这也是代表成功与失败比率的日志的事件的日志(赔率)。这条弯弯曲曲的线,也称为 s 形曲线,将是我们对这个模型的假设。在 logit 曲线的图形中可以看到有界性质:

图 2
所以,在线性回归或 OLS 中我们的假设是:

等式:1.1
如果我们将新发现的变换等同于上面的等式,以限制和投射概率而不是连续结果,我们得到:

等式:1.2
求解 P 我们会得到:

等式:1.3
现在,为了识别类别,我们可以假设一个阈值(=0.5),并相应地指定:

等式:1.4
现在让我们完成一些编码工作,从可视化概率空间和预测空间开始。
导入模块
为了演示该算法,我们将使用 Iris 数据集,这是一个流行的初始分类数据集。让我们只导入和利用 2 个类(存在 3 个类)。
为了保持最大 3 维的数据来可视化每一步,我们将只考虑萼片长度和萼片宽度,当然还有标签。
运行上面的脚本后,您会看到类似这样的内容:

图 3
这显示了属于类别 0 和 1 的要素的概率空间。
决定边界
Eq:1.3 和 1.4 的意思是当(β0 + x 1 β1+x2.β2) >0 时猜 1,否则猜 0。所以逻辑回归给了我们一个线性分类器。分隔两个预测类的决策边界是以下问题的解决方案—

等式:1.5
一维的点,二维的线(这种情况下),等等...也可以计算点 X 离判定边界的距离。

等式:1.6
等式 1.6 也表示判定边界的等式。现在让我们看看预测空间。
运行上面的脚本后,您会看到类似这样的内容:

图 4
正如你所看到的,可能会发现存在一个边界,可以将这个空间分成两个部分,分别属于 0 类和 1 类。逻辑回归将利用概率以及预测值空间(如上)来构建 0 类和 1 类之间的线性决策边界。
现在我们已经完成了建模部分。我们要优化的参数是β0,β1,β2。为了做到这一点,我们有一个非常巧妙的技巧。
最大似然估计
这是一种最大化参数正确归属/拟合数据的可能性的策略。这是许多其他统计方法用来优化参数的相同策略。这与线性回归的区别在于,我们不能在这里使用相同的(残差)方法。我们会知道为什么。要做到这一点:
- 在对数(赔率)空间中可视化所有点。这意味着你必须考虑等式 1.2。将β0、β1、β2 初始化为一些随机值,并为 log(odds)空间制作候选拟合线(2d 的平面)。

图 5
- 现在将数据点投影到直线上,并计算所有点的可能性。
请注意,这里的概率不是作为曲线下的面积(在概率空间中)来计算的,而是作为轴值来计算的,因此它与可能性相同。
候选线的总可能性将是所有个体可能性的乘积,如下式所示。
注意:在计算类 0 的可能性时,可能性将被计算为(1-P(x))

图 6

等式:1.7
现在我们的目标是最大化这个关于参数的似然函数。为了达到这个目的,我们需要对它求导,但问题是对 f(x)求导。g(x)需要变得难以处理的副产品。所以我们将这个等式转换成对数似然,然后求解。
在对数转换和重新排列变量之后,您会看到类似这样的内容:

等式:1.8
现在,通过使用等式 1.2、1.3 替换这些值并重新排列变量,您将看到:

等式:1.9
上面的等式比等式 1.7 更容易微分。现在,我们必须对上述方程 w.r.t β0,β1,β2 进行微分,以获得最佳值。因此,我们将区分并概括这三者:

等式:1.10
注意,上面的方程是一个超越方程,它没有闭合解。所以,我们不能用 python 代码来解决这个问题,所以我们用数字来解决。
你一定在想,如果我们要用数字来解决这个问题,那么花时间去理解这一切有什么意义。我们必须明白,最大似然法是所有优化算法的基础,也是被广泛使用的。这很简单,也很有效,我们仍然会在数值方法中使用对数似然法。
尽管存在许多数值方法来解决这个问题,例如用于数值优化的牛顿方法。对于这个博客,我们将使用我们古老的梯度下降。继续代码:
首先,定义我们的成本函数,它就是我们的对数似然函数。
现在定义梯度下降函数。
在这之后,我们将做一些矩阵操作来准备模型的输入。
然后是训练部分…
在上面代码的输出中,您将看到模型的优化参数。
现在让我们看看模型如何根据数据和其他超参数进行收敛。
运行上面的脚本后,我们可以看到模型的成本随着迭代的进行而非线性降低。

图 7
我们刚刚构建的逻辑模型的决策边界可以使用下面的代码可视化。
注意,直线的斜率和截距可以用等式 1.6 计算。
运行上述脚本将绘制以下内容:

图 8
瞧啊。我们刚刚使用逻辑回归对虹膜数据集进行了线性分类。
现在,我们有了这个数据的最佳决策边界和曲线(sigmoid ),但是你怎么知道它是否有用呢? 我们如何评价这样的东西?
R -决定系数和 p 值
对于广义线性模型:线性回归/OLS,我们通过计算决定的 R 系数及其显著性的 p 值来实现。如果您还记得,线性回归中的 R-决定系数是使用(残差)计算的,但在使用逻辑回归进行分类的情况下,这种方法没有意义,因为在 log(odds)维度中,数据点被推到+∞和-∞,因此残差没有意义。
这个问题的解决方案是麦克法登的伪作。这种方法非常类似于 OLS 的 R,所以非常容易理解。
让我们首先快速回顾一下 OLS-R。它给出了一个比较系数值,表明 Y(目标)的总变化中有多少是由 X(直线)的变化描述的。
SE=平方误差

等式:1.11
换句话说,就是最差拟合(SE_mean)和最佳拟合(SE_line)的对比结果而已。
现在我们用逻辑回归的方法来讨论 R。就像线性回归一样,我们首先需要找到最佳拟合,并将其与差拟合进行比较。现在,在 log(odds)空间中你的最佳拟合线的对数似然性(见图 6)将代表 LL(fit) 来填充等式 1.11 中的 SE(line)。
这里的奥秘在于计算的是坏拟合线。别担心,这也很直观。在线性回归建模中,我们最差的拟合是 y =均值(y)。在这种情况下,我们将做非常类似的事情。

图 9

等式:1.12
- 首先,通过忽略其他特征并简单地取如等式 1.12 中所述的对数(样本比率)来计算最差拟合线,并将其转换到概率空间中。
- 现在,计算最差拟合线的点的所有对数似然的总和。这会给你 LL(整体概率)。
- 令人惊讶的是,用上述方法计算的总对数似然类似于计算—> P =(class = 1 的总数据)/总数据。
现在我们有了 ll(总体概率)->差拟合的度量
和 LL(拟合)- >最佳拟合的度量。所以你会是:

等式:1.13
r 将在[0,1]的范围内,0 代表最不适合,1 代表最适合。
P 值
现在,我们将使用 p 值计算 R 的显著性。计算 p 值非常简单。

等式:1.14
在这种情况下,自由度将是 3(需要 3 个轴上的信息)-1(只需要对数(奇数)轴的截距)=2。现在,在计算上述方程的 LHS 后,您可以从下表中找到 p 值:

图 10
对评估的每一个部分进行编码可能是一个忙乱的过程,这要感谢 statsmodels 已经处理好了。它不仅会显示 R 和 p 值,还会显示大量有助于更好地评估模型的其他信息。
从导入 statsmodels 模块开始
由于我们讨论的是特征之间的线性分离,因此我们将与标注的关系定义为线性。
运行上面的脚本将获得以下结果:

我们可以观察到我们的 P 值是 1.00,因为我们的数据是线性可分的,还可以观察到我们的对数似然性是低的,符合高 R 值。
逻辑回归的几点和假设:
- 我们在这个博客中只讨论了二元分类,但是你也可以在多类问题中应用逻辑回归。假设有 k 个类,而不是有一组参数β0,β,0:(k 1)中的每个类 c 将有自己的偏移β0_c 0 和向量β_c,预测的条件概率将是:

- 逻辑回归假设决策边界是线性的。因此,如果您事先知道您的数据包含非线性决策边界,那么也许不同的算法可能会证明比这个更好。
- 逻辑回归吐出的不是类别而是概率。
- 多重共线性困扰着每一个算法,因为它扭曲了统计显著性的测试。因此,在运行该算法之前,尝试识别并解决它们。
你已经到达终点了!
恭喜你!陪我到最后,理解机器学习最重要的算法之一,也奠定了同样的基础。
感谢阅读。有想法或反馈?下面评论!
使用 Tensorflow 和 RapidMiner Studio 通过人工智能进行内部威胁检测
在 tensorflow 和 rapidminer studio 中使用 US-CERT 内部威胁数据进行神经网络创建和建模的 A-Z 教程,面向网络安全专业人员。
这篇技术文章将教你如何预处理数据,创建自己的神经网络,以及使用 US-CERT 的模拟内部威胁数据集训练和评估模型。这些方法和解决方案是为非领域专家设计的;尤其是网络安全专业人员。我们将从数据集提供的原始数据开始我们的旅程,并提供不同预处理方法的示例,以使其“准备好”供人工智能解决方案摄取。我们最终将创建可重复用于基于安全事件的其他预测的模型。在整篇文章中,我还将根据您企业中现有的信息安全计划指出适用性和投资回报。
注意:要使用和复制我们使用的预处理数据和步骤,请准备花 1-2 个小时阅读本页。陪着我,在数据预处理部分尽量不要睡着。许多教程没有说明的是,如果你是从零开始;做这样的项目时,数据预处理会占用你 90%的时间。
在这篇混合文章和教程结束时,您应该能够:
- 将 US-CERT 提供的数据预处理成人工智能解决方案就绪格式(特别是 Tensorflow)
- 使用 RapidMiner Studio 和 Tensorflow 2.0 + Keras,通过预处理的样本 CSV 数据集创建和训练模型
- 执行数据的基本分析,选择人工智能评估的领域,并使用所描述的方法了解组织的实用性
放弃
作者按原样提供这些方法、见解和建议,不做任何担保。在将本教程中创建的模型作为安全程序的一部分之前,如果没有进行充分的调整和分析,请不要在生产环境中使用这些模型。
工具设置
如果您希望跟随并自己执行这些活动,请从各自的位置下载并安装以下工具:
- 选择:从头开始动手,试验自己的数据变化:下载完整数据集:ftp://ftp.sei.cmu.edu/pub/cert-data😗*注意:它非常大。请计划有数百个免费空间*
- 选择:如果你只是想跟随并执行我所做的,你可以从我的 Github (点击仓库并找到 tensor flow-insider threat)【https://github.com/dc401/tensorflow-insiderthreat】T2 下载预处理的数据、Python 和解决方案文件
- 可选:如果你想要一个不错的 Python IDE:Visual Studio 2019 社区版安装适用的 Python 扩展
- 要求: Rapidminer Studio 试用(或者教育执照,如果适用于你的话)
- 必需:Python 环境,使用 Python 3.8.3 x64 位版本
- 需要:从命令行通过“pip install < packagename >”安装 python 包 : (numpy,pandas, tensorflow ,sklearn
流程概述
对于任何数据科学学科的新人来说,重要的是要知道,你花费的大部分时间将用于数据预处理和分析你所拥有的数据,其中包括清理数据、标准化、提取任何额外的元见解,然后对数据进行编码,以便为人工智能解决方案摄取数据做好准备。
- 我们需要以这样一种方式提取和处理数据集,即它由我们可能需要作为“特征”的字段构成,这只是为了包含在我们创建的人工智能模型中。我们需要确保所有的文本字符串都被编码成数字,以便我们使用的引擎可以摄取它。我们还必须标记哪些是内部威胁和非威胁行(真正的肯定和真正的否定)。
- 接下来,在数据预处理之后,我们需要选择、设置和创建函数,我们将使用这些函数来创建模型和神经网络层本身
- 生成模型;并检查准确性、适用性,确定数据管道的任何部分所需的额外修改或调整
动手检查数据集和手动预处理
检查原始 US-CERT 数据需要您下载必须解压缩的压缩文件。请注意,与我们在数据预处理结束时将使用和减少的量相比,这些集合有多大。
在本文中,我们通过直接访问 answers.tar.bz2 节省了大量时间,该文件包含 insiders.csv 文件,用于匹配哪些数据集和提取的单个记录是有价值的。现在,值得说明的是,在提供的索引中,在扩展数据(如文件)和心理测量相关数据中有相关的记录号。在本教程中,我们没有使用扩展元,因为在我们的例子中,需要额外的时间将所有内容关联和合并到一个 CSV 中。

要查看从相同数据中提取的更全面的特征集,请考虑查看这篇名为“基于图像的内部威胁分类特征表示”的研究论文当我们检查我们的模型准确性时,我们将在文章的后面引用那篇论文。
在对数据进行编码并准备好让函数读取它之前;我们需要提取数据,并将其分类到我们需要预测的列中。让我们使用优秀的旧 Excel 向 CSV 中插入一列。在截图之前,我们从场景 2 的“insiders.csv”中引用的数据集中获取并添加了所有行。

Insiders.csv 真阳性指数
scenarios.txt 中描述了场景(2):“用户开始浏览工作网站,并向竞争对手寻求就业机会。在离开公司之前,他们使用拇指驱动器(比以前的活动频率明显更高)来窃取数据。”
检查我们的预处理数据,包括其中间和最终形式,如下所示:

情景 2 的中间复合真阳性记录
在上面的照片中,这是所有不同记录类型的一个片段,这些记录类型基本上相互附加,并按日期正确排序。请注意,不同的向量(http 对电子邮件对设备)不容易对齐,因为它们在列中有不同的上下文。这无论如何都不是最佳选择,但因为内部威胁场景包括多种事件类型;这就是我们现在要做的。这是数据的常见情况,您将尝试根据时间和与特定属性或用户相关的多个事件进行关联,就像 SIEM 所做的那样。

需要整合的不同数据类型的比较
在聚合集中;在将场景 2 的 insiders.csv 中提到的所有项目移动到同一个文件夹后,我们合并了相关的 CSV。制定整个“真阳性”数据集部分;我们使用的 powershell 如下所示:

使用 powershell 将 CSV 合并在一起
现在我们有一个完全不平衡的数据集,只有真正的阳性。我们还必须添加真正的负面因素,最好的方法是在 50/50 的无威胁活动场景中使用等量的记录类型。安全数据几乎从来不会出现这种情况,所以我们会尽我们所能,如下所示。我还想指出的是,如果您在 OS shell 中进行手动数据处理——您导入变量的任何内容都在内存中,不会被释放或自行进行垃圾收集,正如您可以从我的 PowerShell 内存消耗中看到的那样。在一系列数据操作和 CSV 争论之后,我的使用量增加到了 5.6 GB。

内存不会自动释放。我们还计算每个 CSV 文件中的行数。
让我们看看 R1 数据集文件。我们需要从我们在真阳性数据集提取中使用的文件名中提取我们已知的 3 种类型中每一种类型的确认真阴性(非威胁)(同样,它来自具有良性事件的 R1 数据集)。
我们将合并来自登录、http 和设备文件的所有 3 个 R1 真阴性数据集的许多记录。注意,在 R1 真阴性集合中,我们没有发现增加我们集合数据集不平衡的电子邮件 CSV。
使用 PowerShell,我们计算每个文件中的行的长度。因为我们有大约 14K 的来自真正端的行,所以我任意地从真负端取出来自每个后续文件的前 4500 个适用的行,并将它们附加到训练数据集,这样我们既有真正的,也有真负的。我们必须添加一列来标记哪些是内部威胁,哪些不是。

从 3 个互补 CSV 中提取真阴性记录
在预处理我们的数据时,我们已经添加了下面所有感兴趣的记录,并从 R1 数据集中选择了各种其他真阴性无威胁记录。现在,我们已经将威胁和非威胁基线连接在一个 CSV 中。在左侧,我们添加了一个新列来表示查找和替换场景中的真/假 or (1 或 0)。

对内部威胁真/假列进行编码的标签
上面,你也可以看到我们开始将真/假字符串转换为数字类别。这是我们通过手动预处理对数据进行编码的开始,这可以省去我们在 RapidMiner Studio 中的后续步骤中看到的麻烦,并为 Tensorflow 使用 Python 中的 Pandas Dataframe 库。我们只是想说明您必须执行的一些步骤和注意事项。接下来,我们将继续处理我们的数据。在走完全自动化的路线之前,让我们强调一下使用 excel 函数可以做些什么。

根据提供的日期和时间计算 Unix 纪元时间
出于演示的目的,我们还将手动将日期字段转换为 Unix 纪元时间,正如您所见,它变成了一个带有新列的大整数。要删除 excel 中用于重命名的旧列,请创建一个新表,如“scratch ”,并将旧日期(非纪元时间戳)值剪切到该表中。参照工作表以及您在单元格中看到的公式来达到这种效果。这个公式是:"=(C2-日期(1970,1,1))86400* "不带引号。

编码向量列和特征集列映射
在我们上一个手动预处理工作示例中,您需要格式化 CSV 以通过标签编码数据进行“分类”。您可以通过脚本中的数据字典将此自动化为一次性编码方法,或者在我们的示例中,我们向您展示了在 excel 中映射它的手动方法,因为我们有一组有限的相关记录向量(http 是 0,email 是 1,device 是 2)。
您会注意到,我们没有处理用户、源或操作列,因为它有大量需要标签编码的唯一值,手工处理是不切实际的。使用 RapidMiner Studio 的“turbo prep”功能,我们能够完成这一点,而不需要上面所有的手动争论,同样,在下面的脚本片段中,通过 Python 的 Panda 也可以完成其余的列。现在不要担心这个,我们将向 case 展示每个不同的人工智能工具的步骤,并以最简单的方式做同样的事情。
#print(pd.unique(dataframe['user']))
#https://pbpython.com/categorical-encoding.html
dataframe["user"] = dataframe["user"].astype('category')
dataframe["source"] = dataframe["source"].astype('category')
dataframe["action"] = dataframe["action"].astype('category')
dataframe["user_cat"] = dataframe["user"].cat.codes
dataframe["source_cat"] = dataframe["source"].cat.codes
dataframe["action_cat"] = dataframe["action"].cat.codes
#print(dataframe.info())
#print(dataframe.head())
#save dataframe with new columns for future datmapping
dataframe.to_csv('dataframe-export-allcolumns.csv')
#remove old columns
del dataframe["user"]
del dataframe["source"]
del dataframe["action"]
#restore original names of columns
dataframe.rename(columns={"user_cat": "user", "source_cat": "source", "action_cat": "action"}, inplace=True)
上面的代码片段是使用 python 的 panda 库的示例,该示例将列操作和标签编码为对原始数据集中的每个字符串值唯一的数值。尽量不要被这件事缠住。我们将在 Rapidminer Studio 中向您展示所有这些数据科学工作的简单而全面的方法
对于防御者来说,这是重要的一步:鉴于我们使用的是从 US-CERT 格式化的预先模拟数据集,并非每个 SOC 都可以访问相同的统一数据来应对自己的安全事件。很多时候,您的 SOC 只有原始日志可以导出。从投资回报的角度来看,在进行您自己的 DIY 项目之前,请考虑一下工作量,如果您可以自动将日志的元导出为 CSV 格式,Splunk 或其他 SIEM 等企业解决方案或许可以帮您做到这一点。您必须关联您的事件,并添加尽可能多的列来丰富数据格式。您还必须检查如何保持一致性,以及如何以 US-CERT 必须使用类似方法进行预处理或接收的格式自动导出这些数据。尽可能利用 SIEM 的 API 功能将报告导出为 CSV 格式。
带着我们的数据集走过 RapidMiner Studio
是时候使用一些基于 GUI 的简化方法了。RapidMiner 的桌面版是 Studio,从 9.6.x 开始的最新版本在工作流程中内置了 turbo prep 和自动建模功能。由于我们不是领域专家,我们肯定会利用这一点。让我们开始吧。
注意:如果您的试用期在阅读本教程并使用 community edition 之前过期,您将被限制在 10,000 行。需要进一步的预处理,以将数据集限制为 5K 的真阳性和 5K 的真阴性(包括标题)。如果可以的话,使用教育许可证,它是无限的,并且可以每年更新,你可以在一个有资格的学校注册,邮箱是. edu。

RapidMiner 工作室
开始时,我们将启动一个新项目,并利用 Turbo Prep 功能。对于 community edition,您可以使用其他方法或通过左下角的 GUI 手动选择操作员。但是,我们将使用企业试用版,因为它对于初次用户来说很容易完成。

导入未处理的 CSV 聚合文件
我们将只导入未处理的真阳性数据的聚合 CSV 此外,删除第一行标题并使用我们自己的标题,因为原始行与 HTTP 向量相关,并不适用于数据集中的后续 USB 设备连接和电子邮件相关记录,如下所示。
注意:与我们的预处理步骤(包括标签编码和缩减)不同,我们还没有在 RapidMiner Studio 上这样做,以展示我们在“turbo prep”功能中可以轻松完成的全部工作。我们还将启用引号的使用,并将其他缺省值留给适当的字符串转义。

接下来,我们将列标题类型设置为适当的数据类型。



通过该向导,我们进入 turbo prep 选项卡进行查看,它向我们显示了分布情况和任何错误,例如需要调整的缺失值以及哪些列可能有问题。让我们首先确保我们首先将所有这些真正的积极因素识别为内部威胁。单击“generate ”,我们将通过在所有行中插入一个新列来转换该数据集,并使用逻辑“true”语句,如下所示

我们将保存列的详细信息,并将其导出以供以后进一步处理,或者我们将使用它作为基础模板集,以便在此之后开始预处理 Tensorflow 方法,从而使事情变得简单一些。



导出后,正如你在上面看到的,不要忘记我们需要用真正的负面数据来平衡数据。我们将重复同样的导入真正底片的过程。现在,我们应该在 turbo prep 屏幕中看到多个数据集。

在上面,即使我们只导入了 2 个数据集,记住通过添加一个名为 insiderthreat 的列(真/假布尔逻辑)来转换真正值。我们对真正的否定做同样的事情,你最终会得到 4 个这样的列表。
在我们开始做任何有趣的事情之前,我们需要将真正的积极因素和真正的消极因素合并到一个“训练集”中。但首先,我们还需要删除我们认为不相关的列,如交易 ID 和网站关键字的描述列,因为其他行数据都没有这些;和将包含一组对计算权重无用的空值。

重要提示:正如我们在其他研究论文中提到的,选择包含复杂字符串的计算列(也称为“特征集”)必须使用自然语言处理(NLP)进行标记化。这增加了除标签编码之外的预处理要求,在 Tensorflow + Pandas Python 方法中,通常需要处理多个数据帧,并根据每个记录的列键将它们合并在一起。虽然这在 RapidMiner 中是自动完成的,但在 Tensorflow 中,您必须将其包含在预处理脚本中。关于这个的更多文档可以在这里找到。
请注意,我们没有在我们的数据集中这样做,因为您将在稍后的优化 RapidMiner Studio 建议中看到,更重的权重和对日期和时间的强调是更有效的功能集,复杂性更低。另一方面,对于不同的数据集和应用程序,您可能需要 NLP 进行情感分析,以添加到内部威胁建模中。
完成您的训练集:虽然我们没有说明这一点,但在 Turbo prep 菜单中导入真阴性和真阳性后,单击“merge”按钮,选择两个转换的数据集,并选择“Append”选项,因为两个数据集都已按日期预先排序。
继续到自动模型特征
在 RapidMiner Studio 中,我们继续“自动建模”选项卡,并利用我们选择的聚合“训练”数据(记住训练数据包括真阳性和真阴性)来预测 insiderthreat 列(真或假)

我们也注意到我们的实际余额是多少。我们仍然不平衡,只有 9001 条非威胁记录与大约 14K 的威胁记录。它是不平衡的,如果你愿意,可以用额外的记录来填充。现在,我们将接受它,看看我们能用不那么完美的数据做些什么。

在这里,自动建模器用绿色和黄色推荐不同的特性列以及它们各自的相关性。有趣的是,它是估计数据的高相关性,但稳定性不如行动和向量。
重要的想法:在我们的头脑中,我们会认为所有的特性集都适用于每个专栏,因为我们已经尽可能地减少了相关性和复杂性。还值得一提的是,这是基于一个单一的事件。请记住,正如我们在 insiders.csv 的答案部分看到的那样,内部威胁通常会发生多个事件。绿色指示器向我们展示的是独一无二的单一事件识别记录。

我们无论如何都要使用所有的列,因为我们认为这些都是可以使用的相关列。我们还转到模型类型的下一个屏幕,因为我们不是领域专家,所以我们将尝试几乎所有的模型,我们希望计算机多次重新运行每个模型,找到输入和特征列的优化集。
请记住,功能集可以包含基于现有列洞察的元信息。我们保留标记化的默认值,并希望提取日期和文本信息。显然,带有自由格式文本的项目是带有所有不同 URL 的“Action”列,以及我们希望应用 NLP 的事件活动。我们想要在列之间建立关联,列的重要性,以及解释预测。

注意,在上面的例子中,我们在批处理作业中选择了大量的处理参数。在运行 Windows 10 的 8 核单线程处理器、24 GB 内存和配有 SSD 的镭龙 RX570 value 系列 GPU 上,所有这些模型在所有选项设置下总共需要大约 6 个小时才能运行。完成所有工作后,我们在屏幕对比中测试了 8000 多个型号和 2600 多个功能组合。

据 RapidMiner 工作室;深度学习神经网络方法不是最佳 ROI 拟合;与线性一般模型相比。虽然没有错误——但这令人担忧,这可能意味着我们的数据质量很差,或者模型存在过拟合问题。让我们来看看深度学习,因为它也指出了潜在的 100%准确性,只是为了进行比较。

在上面的深度学习中,它针对 187 种不同的特征集组合进行了测试,优化的模型显示,与我们自己的想法不同,哪些特征会是好的,主要包括向量和动作。我们看到更多的重量放在了有趣的单词和日期上。令人惊讶的是;作为优化模型的一部分,我们在操作中没有看到任何与“电子邮件”或“设备”相关的内容。

不要担心,因为这并不意味着我们大错特错。这只是意味着它在训练中选择的特征集(列和提取的元列)在训练集中提供了较少的错误。这可能是因为我们的数据集中没有足够多样或高质量的数据。在上面的屏幕中,你看到了一个橙色的圆圈和一个半透明的正方形。
橙色圆圈表示模型建议的优化器功能,正方形是我们最初选择的功能集。如果你检查规模,我们的人类选择的特征集是 0.9 和 1%的误差率,这使我们的准确性接近 99%的标志;但只有在更高复杂性的模型中(需要神经网络中更多的层和连接),才能让我感觉好一点,并告诉你在从表面上解释所有这些时需要谨慎。
调整注意事项
假设你不完全信任这样一个高度“100%准确的模型”。我们可以尝试以普通的方式使用我们的功能集作为纯令牌标签来重新运行它。我们不会提取日期信息,不会通过 NLP 进行文本标记化,我们也不希望它基于我们的原始选择自动创建新的功能集元。基本上,我们将使用一组普通的列来进行计算。

所以在上面,让我们重新运行它,看看 3 个不同的模型,包括原始的最佳拟合模型和深度学习,我们绝对没有优化和额外的 NLP 应用。因此,这就好像我们只在计算中使用编码标签值,而不在其他地方使用。

在上面的例子中,我们得到了更糟糕的结果,误差率为 39%,几乎所有模型的准确率为 61%。在不使用文本标记提取的情况下,我们的选择和缺乏复杂性是如此之少,以至于即使更“原始”的贝叶斯模型(通常用于基本的电子邮件垃圾邮件过滤引擎)似乎也一样准确,并且具有快速的计算时间。这一切看起来很糟糕,但让我们再深入一点:

当我们再次选择深度学习模型的细节时,我们看到准确性以线性方式攀升,因为更多的训练集群体被发现并验证。从解释的角度来看,这向我们展示了一些东西:
- 我们最初关于只使用唯一编码值来关注向量和动作频率的特征集的想法,与分析师在数据中发现威胁的可能性一样大。从表面上看,我们发现内部威胁的几率最多有 10%的提高。
- 它还表明,尽管行动和向量最初被认为是“绿色的”,但对于更好的输入选择,唯一的记录事件实际上与内部威胁场景相反,我们需要为每个事件/警报考虑多个事件。在优化的模型中,使用的许多权重和标记是时间相关的特定和动作标记词
- 这也告诉我们,我们的这个数据集的基础数据质量相当低,我们将需要额外的上下文,并可能需要对每个独特事件的每个用户的情绪分析,这也是心理测量. csv 文件中包含的 HR 数据度量' OCEAN '。通过 NLP 使用令牌;当在我们的数据预处理中执行这些连接时,我们可能会调整以包括空值混合的列,以包括来自原始数据集的网站描述符单词,并且可能包括必须基于时间和事务 ID 合并到我们的训练集中作为关键字的 files.csv
部署优化的(或未优化的)模型
虽然本节没有显示屏幕截图,但 RapidMiner studio 的最后一步是部署您选择的优化或非优化模型。在 studio 的上下文中进行本地部署,除了重用您真正喜欢的模型和通过 Studio 应用程序的交互加载新数据之外,不会为您做太多事情。您将需要 RapidMiner 服务器来自动进行本地或远程部署,以便与生产应用程序集成。我们在这里不举例说明这些步骤,但是在他们的网站上有很棒的文档:https://docs . rapid miner . com/latest/studio/guided/deployments/
但是 Tensorflow 2.0 和 Keras 呢?
也许 RapidMiner Studio 不适合我们,每个人都在谈论 Tensorflow (TF)是领先的解决方案之一。但是,TF 没有 GUI。新的 TF v2.0 安装了 Keras API,这使得创建神经网络层的交互更加容易,同时可以将 Python 的 Panda 数据框中的数据输入到模型执行中。让我们开始吧。
正如您从我们的手动步骤中回忆的那样,我们开始数据预处理。我们重新使用相同的场景 2 和数据集,并将使用基本的标签编码,就像我们在 RapidMiner Studio 中对非优化模型所做的那样,以向您展示方法上的比较,以及最终都是基于转换为库的算法函数的统计数据这一事实。再次使用截图,记住我们做了一些手动预处理工作,将 insiderthreat、vector 和 date 列转换为类别数值,如下所示:

如果您希望在我们运行 Python 脚本进一步预处理之前查看中间数据集,我已经在 Github 上放置了一份半清理数据的副本:

让我们研究一下 python 代码,以帮助我们达到我们想要的最终状态,即:

代码可复制如下:
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import feature_column
from tensorflow.keras import layers
from sklearn.model_selection import train_test_split
from pandas.api.types import CategoricalDtype
#Use Pandas to create a dataframe
#In windows to get file from path other than same run directory see:
#https://stackoverflow.com/questions/16952632/read-a-csv-into-pandas-from-f-drive-on-windows-7
URL = 'https://raw.githubusercontent.com/dc401/tensorflow-insiderthreat/master/scenario2-training-dataset-transformed-tf.csv'
dataframe = pd.read_csv(URL)
#print(dataframe.head())
#show dataframe details for column types
#print(dataframe.info())
#print(pd.unique(dataframe['user']))
#https://pbpython.com/categorical-encoding.html
dataframe["user"] = dataframe["user"].astype('category')
dataframe["source"] = dataframe["source"].astype('category')
dataframe["action"] = dataframe["action"].astype('category')
dataframe["user_cat"] = dataframe["user"].cat.codes
dataframe["source_cat"] = dataframe["source"].cat.codes
dataframe["action_cat"] = dataframe["action"].cat.codes
#print(dataframe.info())
#print(dataframe.head())
#save dataframe with new columns for future datmapping
dataframe.to_csv('dataframe-export-allcolumns.csv')
#remove old columns
del dataframe["user"]
del dataframe["source"]
del dataframe["action"]
#restore original names of columns
dataframe.rename(columns={"user_cat": "user", "source_cat": "source", "action_cat": "action"}, inplace=True)
print(dataframe.head())
print(dataframe.info())
#save dataframe cleaned up
dataframe.to_csv('dataframe-export-int-cleaned.csv')
#Split the dataframe into train, validation, and test
train, test = train_test_split(dataframe, test_size=0.2)
train, val = train_test_split(train, test_size=0.2)
print(len(train), 'train examples')
print(len(val), 'validation examples')
print(len(test), 'test examples')
#Create an input pipeline using tf.data
# A utility method to create a tf.data dataset from a Pandas Dataframe
def df_to_dataset(dataframe, shuffle=True, batch_size=32):
dataframe = dataframe.copy()
labels = dataframe.pop('insiderthreat')
ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
if shuffle:
ds = ds.shuffle(buffer_size=len(dataframe))
ds = ds.batch(batch_size)
return ds
#choose columns needed for calculations (features)
feature_columns = []
for header in ["vector", "date", "user", "source", "action"]:
feature_columns.append(feature_column.numeric_column(header))
#create feature layer
feature_layer = tf.keras.layers.DenseFeatures(feature_columns)
#set batch size pipeline
batch_size = 32
train_ds = df_to_dataset(train, batch_size=batch_size)
val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)
test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)
#create compile and train model
model = tf.keras.Sequential([
feature_layer,
layers.Dense(128, activation='relu'),
layers.Dense(128, activation='relu'),
layers.Dense(1)
])
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(train_ds,
validation_data=val_ds,
epochs=5)
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
在我们的场景中,我们将从 Github 获取数据。我已经在注释中包含了使用 os import 从本地文件导入到磁盘的方法。需要指出的一点是,我们使用 Pandas dataframe 构造和方法,通过输入的标签编码来操作列。请注意,这不是 RapidMiner Studio 向我们报告的优化方式。
在第二轮建模中,我们仍然使用我们在前面屏幕中重新运行的相同特性集列;不过这次是在 Tensorflow 进行方法演示。

注意,在上面的数据类型中,vector 仍然显示“object ”,这是一个错误。我急得要命,发现我需要更新数据集,因为我没有像我最初想的那样将所有值作为类别数字捕获到向量列中。很明显,我漏了一个。一旦这一切都被纠正,错误消失,模型训练运行没有问题。
与 RapidMiner Studio 不同,我们不只是有一个大型训练集,并让系统为我们做这件事。我们必须将训练集分成更小的部分,这些部分必须根据以下内容进行批处理,作为使用已知正确的真/假内部威胁数据进行训练的模型的子集,并保留一部分进行分割,剩余部分仅进行验证。

接下来,我们需要选择我们的特征列,这也是我们编码的 5 列数据中的“非优化”列。我们在管道的每轮验证(时期)中使用 32 的抽样批量,正如我们在早期定义的那样。

请注意,我们还没有执行任何与张量相关的操作,甚至还没有创建模型。这只是数据准备和建立供给张量的“管道”。下面是当我们使用 Keras 以连续格式使用层创建模型时,我们使用 Google TF 的教程演示优化器和损失函数编译模型,重点是准确性。我们尝试用 5 轮来拟合和验证模型,然后打印显示。
欢迎来到剩余的 10%旅程,将人工智能应用于您的内部威胁数据集!

让我们再次运行它,现在我们看到像上次一样有大约 61%的准确率!这再次证明,您的大部分成果将来自数据科学过程本身以及预处理、调优和数据的质量。你选择哪种核心软件解决方案并不重要。没有在变化的特征集合中进行优化和测试的多模型实验模拟;我们的原始模型最多只比随机抽样好 10%,人类分析师可能会也可能不会查看相同的数据。

人工智能在网络安全领域的投资回报率在哪里
对于可以在单个事件上完成的简单项目任务,作为警报,而不是使用非领域专家的事件;通过 SOC 或威胁搜索实现人工智能的防御者可以更快更好地实现被认为异常或不使用基线数据的 ROI。例如,异常用户代理字符串可能显示 C2 病毒感染,K-means 或 KNN 聚类基于网络威胁情报 IOC,可能显示特定的 APT 相似性。
Github 上有一些很棒的精选列表,可以给你的团队一些想法,让他们用一些我们在本文中展示的简单方法去做其他的事情。无论你选择使用哪种软件解决方案,我们的警报有效载荷很可能真的需要应用 NLP 和一个大小合适的神经网络来进行更精确的建模。请随意修改我们的基本 python 模板并亲自试用。
将大约 60%的准确率与其他真实世界的网络使用案例进行比较
我不得不承认,一开始我对自己相当失望;即使我们知道这不是一个带有标签和输入选择的优化模型。但是当我们将它与社区中其他更复杂的数据集和模型进行交叉比较时,比如 Kaggle :它真的没有我们最初想象的那么糟糕。
微软为社区举办了一场恶意软件检测比赛,并提供了丰富的数据集。比赛最高分显示预测准确率为 67%,这是在 2019 年,有超过 2400 支球队参赛。一名成员分享了他们的代码,该代码获得了 63%的分数,免费向公众发布,如果你想进一步研究,可以作为一个很好的模板。他标题为 LightGBM 。

与排行榜积分相比,面向公众的解决方案仅“差”5%在数据科学领域,5%的差异是一个巨大的数字吗?是的(尽管这也取决于你如何衡量信心水平)。因此,在 2400+个团队中,最好的模型取得了大约 68%的成功准确率。但是从预算投资回报率的角度来看,当 CISO 要求他们下一财年的资本支出时,68%对大多数安全项目来说是不够的。
虽然有些令人沮丧,但重要的是要记住,有专门的数据科学和开发运营专业人员花费他们的整个职业生涯来完成这项工作,以使 models u 达到 95%或更高的范围。为了实现这一点,需要大量的模型测试、额外的数据和额外的特征集提取(正如我们在 RapidMiner Studio 中看到的那样)。
对于将人工智能应用于内部威胁,我们将何去何从?
显然,这是一项复杂的任务。迪肯大学的研究人员在年发表了一篇名为“基于图像的内部威胁分类特征表示法 n”的论文,该论文在文章的前面部分简要提到过。他们讨论了根据同一 US-CERT CMU 数据集提供的大量数据创建特征集的方法,并创建了可用于预测分类的“图像”,准确率达到 98%。
在论文中,研究人员还讨论了对先前模型的检查,如针对内部威胁的“诱饵”,该模型使用不平衡数据最多也有 70%的准确性。有足够预算的安全程序可以在数据科学家和开发运营工程师的帮助下从头开始制作内部模型,他们可以将这份研究报告转化为适用的代码。
网络防御者如何在 AI 方面变得更好,并开始在内部开发技能?
少关注解决方案,多关注数据科学和预处理。我拿了 EdX 的 Data8x 课件(总共 3 个)和参考的书(也是免费的)提供了很多细节和方法,任何人都可以用来正确地检查数据,并知道他们在这个过程中在看什么。本课程集和其他课程集可以真正增强和提高现有的网络安全技能,让我们做好如下准备:
- 评估提供“人工智能”服务和解决方案的供应商的实际效率,例如询问使用了哪些数据预处理、功能集、模型架构和优化功能
- 构建用例,并在被视为异常的情况下,通过更明智的人工智能特定建模选择来增强他们的 SOC 或威胁搜索程序
- 能够将高质量数据传输并自动化到经过验证的可靠模型中,以实现高效的警报和响应
关闭
我希望你喜欢这篇关于内部威胁的网络安全应用的文章和教程简介,或者使用两种不同的解决方案将任何数据设置到神经网络中。如果您对专业服务或 MSSP 感兴趣,以加强您组织的网络安全,请随时联系我们,电话:www.scissecurity.com
洞察力无处不在。
你的数据包含洞察力。是的,你的!
数据科学不是为那些受过正规 it 培训的人保留的。任何有动机的人都可以跳上他们的笔记本电脑,开始挖掘、调查和想象。
他们可以从手头的数据着手。天哪,我们到处都有——通常数量非常大。在我们的工作和生活中,我们不断地抛出数据——尽管这些数据的质量因来源而异,但如果你告诉我,从你可以访问的数据中提取不出任何有价值的东西,我是不会相信你的。我想证明,即使是从最初可能会忽略的简单数据源中,也完全有可能获得洞察力。

照片由S O C I A L C U T在 Unsplash 上拍摄
那交易是什么?
在某些行业,比如金融业,通常不缺乏可供分析的数字数据——但我意识到,其他行业可能不存在这种情况。因此,为了表明这些原则更普遍地适用于其他类型的组织,我们将放弃这些数字,研究一个相当通用的数据文件。
对于那些渴望了解数据是如何被处理的人,你可以跟随我上传到 GitHub 的 Jupyter 笔记本。 Python 用于此分析。 Numpy 和 Pandas 用于数据操作和计算。所有的图都是使用 Matplotlib 生成的。

数据文件的前几行。
我们正在使用工作进展(WIP)文档,该文档用于记录自 2019 年以来已完成的许多精算工作项目的详细信息。我们有:
- 成员名称:任务已完成的成员的名称
- 计算类型:所需的计算类型
- 请求日期:请求工作的日期
- 截止日期:要求完成工作的日期
- 完成者:谁完成了这项工作
- 检查者:谁检查了工作
- 审核人:谁审核并批准了该工作
- 发送日期:作品完成并发送出去的日期
- 期限到了吗?:工作是否在截止日期前及时完成,即发送日期是在截止日期之前还是同一天
一旦我们检查了数据的完整性,并处理了任何错误或缺失的值,我们就可以开始了。
谁在做什么?
假设我们想跟踪 Alice 和 Bob 在工作流程中接触每个角色的程度,我们想确保他们都获得了经验并取得了进步。经过一些处理后,我们可以计算出自 2019 年初以来,爱丽丝和鲍勃每个月完成、检查和审查了多少个案例:

爱丽丝和鲍勃参与这些工作任务。
表格固然很好,但是我们的大脑不能像一个好的可视化一样真正掌握表格数据。让我们来绘制这些发现:

现在我们可以更清楚地了解这些趋势。
我们可以看到,Alice 最初做了许多案例,但现在已经转变为更多的检查角色。同样,Bob 在 2019 年初主要是检查案例,而现在他正在审查他看到的大多数案例。这两个指标都很好地表明了我们的员工正在学习和接受挑战!
我们是否按时完成了任务?
我们可能会签订某种服务水平协议,以确保我们的工作速度足够快。提供低于约定水平的服务会损害我们与客户的关系。如果他们最终去找我们的竞争对手寻求更好的服务,我们可能会失去业务。记住这一点,让我们看看最近我们是否按时完成了任务。

看起来…好吗?这有点难以判断
同样,让我们用图表来表示数据:

看起来我们有点不稳定
看起来我们通常保持 80%到 100%的案例按时交付的服务水平。然而,从 2019 年 7 月到 10 月,服务水平有相当大的下降。如果我们还没有意识到,我们会深入了解为什么我们的团队表现不佳,并解决这个问题。我们人手不足吗?那是一个特别繁忙的时期吗?我们是否需要雇用更多的长期或临时工作人员来应付?
有时候,数据分析产生的问题比它回答的问题还多,但是如果它们是正确的问题,那么我们就在朝着正确的方向前进,并增加价值。
我们错过了什么案子的最后期限?
按时完成对我们的团队和我们与客户的关系都很重要。让我们来看看在错过最后期限时最容易出问题的案例。

等着吧…
像往常一样,让我们看看是否可以用一种更清楚地揭示正在发生什么的方式来绘制这些数据:

啊哈!
有意思!有一些类型的计算相对来说很少收到,但是它们在我们错过最后期限的所有案例中占了很大比例。换句话说,不管出于什么原因,我们在这方面都差得不成比例。
潜在的行动可能是对团队如何处理这些情况进行更多的在职指导,或者可能是向全公司的培训和发展团队反馈,在新员工入职时需要更彻底地涵盖这些类型的计算。
洞察力无处不在
希望这在某种程度上证明了,当涉及到您的数据时,几乎总是有一些有趣的东西需要研究。我们仅仅触及了这个相当基础的数据集所能提供的皮毛。限制因素不是技术。它不是在现实世界中应用数据科学的机会的可用性。它甚至不是知识——有无穷无尽的资源可供我们学习。
限制因素是动机。学习曲线一开始可能很难管理,我们在学习过程中都会遇到问题。其中一些问题可能看起来无法克服,并可能导致我们在愤怒和沮丧中放弃。但是,寻求这些棘手问题的解决方案是我们发展最快的领域。只要你坚持努力,这些问题就能够也一定会被克服。
您可能不认为自己是数据科学家,但事实上,任何人都可以学习在工作中应用这些工具。所以我鼓励你——挑选一份你认为可能包含有用见解的数据。一旦你开始探索和使用它,你将很快证明自己的能力。
更多信息和积分
Andrew Hetherington 是英国伦敦的一名见习精算师和数据爱好者。
图片:由S O C I A L C U T在 Unsplash 上拍摄的望远镜照片。
洞察力是王道——如何获得洞察力并避免陷阱
很难找到对数据集如何运行的直观理解!然而,连贯地解释你的系统是如何工作的,对于找到一种建模或分析任何特征的方法是至关重要的。坚持到最后,找出为什么最初的洞察力是良好分析的关键,你必须做什么来形成你的理解,以及如何轻松避免和克服问题。
我在一个 5 人团队中一直在做一个项目,利用澳大利亚的天气数据来预测能源需求。它历时半年,模仿了一个经典的数据科学项目。从数据收集开始,转移到清理、建模,然后撰写报告。进行到一半的时候,我发现了一件事——我还在清理数据,尽管有另外四个人在做这件事,但还是花了很长时间!看起来我们有一百万个功能需要处理,其中大部分都离很远,很难使用。我认为这是一个学习更多不同的(奇特的)技术的机会,这些技术可以用来插入(填充)缺失的数据。但是… 我完全误解了我的项目。
我们不明白我们的数据是如何工作的,所以必须考虑 100 个特征,而不是 3 个…

约翰·巴克利普在 Unsplash 上的照片
这是一个幼稚的错误,但却给了我几个宝贵的教训:
- 低质量/不相关的数据弊大于利
- 我的团队的工作只能在被理解的情况下完成
现在不要担心,我们确实按时完成了,有一个模型和完整的报告!但是…只有在我考虑了这些缺陷之后,我的团队才能像一台运转良好的机器一样运转。因此,在这里,我们将探讨如何找到洞察力并从中受益,以及如何避免一直存在的缺陷和潜在的陷阱(每个人在某个时候都会遇到)。
强调理解数据如何运作的重要性很容易,但要发现它却很难。有了教程、kaggle 竞赛和简单的初学者练习,就很容易了……理解和翻译部分已经轻而易举地交给你了。只要拿出你的金叉(代号)和刀(合奏模型),开始切割(测试)和你能吃的 whala(高性能模型)!
然后你取得进展,开始一些真正的项目…哦,不。也许没有一个放之四海而皆准的策略,但是我们可以通过适当地设置自己,让这个过程变得更顺利,更少痛苦。

杨静在 Unsplash 上的照片
从哪里开始
只是酷……不,请等等!
代码很重要,但是我要告诉你一个小秘密——当你知道过程时,花费的时间会更少。Bbubbbut…如何在第一次开始之前了解流程?简单,解释任务目标。缺失的目标是你想从项目中得到的。任务目标包括模型和报告本身,但也包括您需要学习的内容、您将经历的阶段以及需要考虑的挑战。
我以为我的目标是尽我所能创造最好的模型来预测能源需求,哈哈哈。我完全错了!
我的目标不是预测能源需求…因为那几乎是不可能的。我真正想要的是识别和模拟短期内发生的能源需求趋势和季节模式,以及温度如何适应这个等式。它包括导入数据,研究哪些变量是有用的,创建图表以直观地显示数据的外观/工作方式,然后最终创建一个模型来具体测量温度和能源需求之间的关系。主要的困难在于了解能源时间序列是如何工作的,以及如何指导我的团队完成这个过程的每个阶段。还很啰嗦吗?最终目标可能是一个报告,展示了在我们得到一个模型之前一切是如何工作的,但是实际上,模型只是工作的 10%!
虽然很容易把它放在一边…说它是软的,不必要的计划,现在不太可能直接影响项目。事实上……是的,这是额外的工作,也很公平,如果你不是被迫像这样计划每件事的话。如果你有更好的选择,请告诉我。如果没有,试一试。它可能不会马上影响到你,但是它将有助于缓解大问题,并阐明所有事情是如何联系在一起的!

凯尔·格伦在 Unsplash 上的照片
找出下一步去哪里
但是我不知道如何做这些… 不要担心,随着时间的推移,你会明白的。请记住:
一旦开始,道路似乎就不那么崎岖不平了!
如果你不知道从哪里开始,找出你需要学习的内容,并找到学习的方法。简单的教程和视频是开始的好方法。然后,一旦你对事情应该是什么样子和该做什么有了一个模糊的想法,就开始吧。简单地跟着这条路走,看看它通向哪里!
对于数据科学项目,要知道实用的步骤和流程。我在我的机器学习领域指南文章中解释了这些,该文章详细介绍了该过程的每一步!如果你想了解更多,像动手机器学习和百页机器学习书这样的书是非常有用的。
为了在团队中更好地工作,确保你了解协作编码工具(所有解释在这里)和如何领导。《极端所有权》这本书是一个关于团队合作和领导力的惊人指南(不是专门针对数据科学的,但 Jocko Willink 的建议仍然适用)。

Josh Calabrese 在 Unsplash 上拍摄的照片
避免崩溃
一切都进行得如此顺利…直到我意识到我们仍然在项目中途清理数据。一切似乎都很好,进展似乎还不错,不完美…但很好。
即使你已经为自己的成功做好了准备,而且一切都进展顺利,事情也可能会变糟!但是……我很幸运,因为一位老师告诉我要定期做一件事:
做一个简单的进度日志,特别是评论你做了什么,结果如何,以及可以做些什么来改进。

Toa Heftiba 在 Unsplash 上拍摄的照片
它创造了奇迹!在了解我需要完成多少任务后,我没有感到压力,而是能够区分优先次序并执行,因为我知道哪里可能出错,并且我可以解释。我知道我的团队可能会分心,失去注意力,所以我确保抓住要点,强调我们试图完成的事情,而不是写下狭窄的任务。我知道很难调整自己的节奏,所以我数了数还剩多少周,确保每个人都明白。我知道编码对大多数人来说是特别具有挑战性和威胁性的,所以我做了一个简短的概述,关于它将涉及什么/它应该看起来像样本代码。简而言之,我说明了自己的弱点,并设法扭转了糟糕的局面。
这个过程每周只需要大约 5 分钟,极大地提高了进度。
你所要做的就是反思你的行为,考虑什么能进一步帮助你。
这个导致简单可行的步骤。
感谢阅读!
我希望你喜欢这本书,并且发现它很有帮助!请随时与任何人分享这可能会有所帮助。
我其他关于实用编码技巧、机器学习、起步项目和网页抓取的文章可能会比较有意思。
在推特上关注我的更新。
深刻的贷款违约分析
深入分析
可视化洞察并发现贷款违约的贷款信用风险模型中的驱动特征

(图片由作者提供)
L ending Club 是最大的在线贷款市场,为个人贷款、商业贷款和医疗程序融资提供便利。借款人可以通过快速的在线界面轻松获得低利率贷款。
与大多数其他贷款公司一样,向“高风险”申请人发放贷款是财务损失(称为信用损失)的最大来源。信用损失是指当借款人拒绝付款或带着所欠的钱逃跑时,贷款人所损失的金额。换句话说,违约的借款人给贷款人造成的损失最大。
因此,使用数据科学、探索性数据分析和来自 Lending Club 的公开数据,我们将探索和计算出贷款违约背后存在的驱动因素,即作为违约强指标的变量。此外,公司可以利用这些知识进行投资组合和风险评估。

关于 Lending Club 贷款数据集
该数据集包含通过2007–2011发放的所有贷款的完整贷款数据,包括当前贷款状态(当前、已核销、已完全支付)和最新支付信息。其他功能包括信用评分、财务查询次数和收款等。该文件是一个大约 39,000 个观察值和 111 个变量的矩阵。数据集中的一个单独文件中提供了一个数据字典。数据集可以在 Kaggle 上下载。
问题
- 我们正在处理哪组贷款数据?
- 我们有哪些类型的功能?
- 我们需要治疗缺失值吗?
- 贷款状态分布如何?
- 具有其他特征的贷款违约分布是怎样的?
- 我们可以为画出什么样的图来推断与贷款违约的关系?
- 主要描述贷款违约的驱动特征有哪些?
特征分布
- 贷款特征,如贷款金额、期限、目的,显示有关贷款的信息,帮助我们发现贷款违约。
- 人口统计变量,如年龄、就业状况、关系状况,这些信息显示了对我们无用的借款人概况。
- 行为变量,如下一个付款日期、EMI、拖欠显示提供贷款后更新的信息,在我们的情况下,这些信息并不有用,因为我们需要通过违约分析来决定是否批准贷款。
下面是我们将在本文中看到的内容的快速概述:
- 数据集概述(贷款分布)
- 数据清理(缺失值、标准化数据、异常值处理)
- 指标推导(宁滨)
- 单变量分析(分类/连续特征)
- 双变量分析(箱线图、散点图、小提琴图)
- 多变量分析(相关热图)
数据/库导入
*# import required libraries*
import numpy as np
print('numpy version:',np.__version__)
import pandas as pd
print('pandas version:',pd.__version__)
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.set(style="whitegrid")
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (12, 8)
pd.options.mode.chained_assignment = None
pd.options.display.float_format = '**{:.2f}**'.format
pd.set_option('display.max_columns', 200)
pd.set_option('display.width', 400)*# file path variable*
case_data = "/kaggle/input/lending-club-loan-dataset-2007-2011/loan.csv"
loan = pd.read_csv(case_data, low_memory=False)
数据集有 111 列和 39717 行
数据集概述
# plotting pie chart for different types of loan_status
chargedOffLoans = loan.loc[(loan["loan_status"] == "Charged Off")]
currentLoans = loan.loc[(loan["loan_status"] == "Current")]
fullyPaidLoans = loan.loc[(loan["loan_status"]== "Fully Paid")]data = [{"Charged Off": chargedOffLoans["funded_amnt_inv"].sum(), "Fully Paid":fullyPaidLoans["funded_amnt_inv"].sum(), "Current":currentLoans["funded_amnt_inv"].sum()}]investment_sum = pd.DataFrame(data)
chargedOffTotalSum = float(investment_sum["Charged Off"])
fullyPaidTotalSum = float(investment_sum["Fully Paid"])
currentTotalSum = float(investment_sum["Current"])
loan_status = [chargedOffTotalSum,fullyPaidTotalSum,currentTotalSum]
loan_status_labels = 'Charged Off','Fully Paid','Current'
plt.pie(loan_status,labels=loan_status_labels,autopct='**%1.1f%%**')
plt.title('Loan Status Aggregate Information')
plt.axis('equal')
plt.legend(loan_status,title="Loan Amount",loc="center left",bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()

(图片由作者提供)
*# plotting pie chart for different types of purpose*
loans_purpose = loan.groupby(['purpose'])['funded_amnt_inv'].sum().reset_index()plt.figure(figsize=(14, 10))
plt.pie(loans_purpose["funded_amnt_inv"],labels=loans_purpose["purpose"],autopct='%1.1f%%')plt.title('Loan purpose Aggregate Information')
plt.axis('equal')
plt.legend(loan_status,title="Loan purpose",loc="center left",bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()

(图片由作者提供)
数据清理
*# in dataset, we can see around half of the columns are null*
*# completely, hence remove all columns having no values*
loan = loan.dropna(axis=1, how="all")
print("Looking into remaining columns info:")
print(loan.info(max_cols=200))
我们剩下以下几列:
Looking into remaining columns info:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 39717 entries, 0 to 39716
Data columns (total 57 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 39717 non-null int64
1 member_id 39717 non-null int64
2 loan_amnt 39717 non-null int64
3 funded_amnt 39717 non-null int64
4 funded_amnt_inv 39717 non-null float64
5 term 39717 non-null object
6 int_rate 39717 non-null object
7 installment 39717 non-null float64
8 grade 39717 non-null object
9 sub_grade 39717 non-null object
10 emp_title 37258 non-null object
11 emp_length 38642 non-null object
12 home_ownership 39717 non-null object
13 annual_inc 39717 non-null float64
14 verification_status 39717 non-null object
15 issue_d 39717 non-null object
16 loan_status 39717 non-null object
17 pymnt_plan 39717 non-null object
18 url 39717 non-null object
19 desc 26777 non-null object
20 purpose 39717 non-null object
21 title 39706 non-null object
22 zip_code 39717 non-null object
23 addr_state 39717 non-null object
24 dti 39717 non-null float64
25 delinq_2yrs 39717 non-null int64
26 earliest_cr_line 39717 non-null object
27 inq_last_6mths 39717 non-null int64
28 mths_since_last_delinq 14035 non-null float64
29 mths_since_last_record 2786 non-null float64
30 open_acc 39717 non-null int64
31 pub_rec 39717 non-null int64
32 revol_bal 39717 non-null int64
33 revol_util 39667 non-null object
34 total_acc 39717 non-null int64
35 initial_list_status 39717 non-null object
36 out_prncp 39717 non-null float64
37 out_prncp_inv 39717 non-null float64
38 total_pymnt 39717 non-null float64
39 total_pymnt_inv 39717 non-null float64
40 total_rec_prncp 39717 non-null float64
41 total_rec_int 39717 non-null float64
42 total_rec_late_fee 39717 non-null float64
43 recoveries 39717 non-null float64
44 collection_recovery_fee 39717 non-null float64
45 last_pymnt_d 39646 non-null object
46 last_pymnt_amnt 39717 non-null float64
47 next_pymnt_d 1140 non-null object
48 last_credit_pull_d 39715 non-null object
49 collections_12_mths_ex_med 39661 non-null float64
50 policy_code 39717 non-null int64
51 application_type 39717 non-null object
52 acc_now_delinq 39717 non-null int64
53 chargeoff_within_12_mths 39661 non-null float64
54 delinq_amnt 39717 non-null int64
55 pub_rec_bankruptcies 39020 non-null float64
56 tax_liens 39678 non-null float64
dtypes: float64(20), int64(13), object(24)
memory usage: 17.3+ MB
现在,我们将删除所有人口统计和客户行为特征,这些特征对于信贷审批的违约分析毫无用处。
*# remove non-required columns*
*# id - not required*
*# member_id - not required*
*# acc_now_delinq - empty*
*# funded_amnt - not useful, funded_amnt_inv is useful which is funded to person*
*# emp_title - brand names not useful*
*# pymnt_plan - fixed value as n for all*
*# url - not useful*
*# desc - can be applied some NLP but not for EDA*
*# title - too many distinct values not useful*
*# zip_code - complete zip is not available*
*# delinq_2yrs - post approval feature*
*# mths_since_last_delinq - only half values are there, not much information*
*# mths_since_last_record - only 10% values are there*
*# revol_bal - post/behavioural feature*
*# initial_list_status - fixed value as f for all*
*# out_prncp - post approval feature*
*# out_prncp_inv - not useful as its for investors*
*# total_pymnt - post approval feature*
*# total_pymnt_inv - not useful as it is for investors*
*# total_rec_prncp - post approval feature*
*# total_rec_int - post approval feature*
*# total_rec_late_fee - post approval feature*
*# recoveries - post approval feature*
*# collection_recovery_fee - post approval feature*
*# last_pymnt_d - post approval feature*
*# last_credit_pull_d - irrelevant for approval*
*# last_pymnt_amnt - post feature*
*# next_pymnt_d - post feature*
*# collections_12_mths_ex_med - only 1 value*
*# policy_code - only 1 value*
*# acc_now_delinq - single valued*
*# chargeoff_within_12_mths - post feature*
*# delinq_amnt - single valued*
*# tax_liens - single valued*
*# application_type - single*
*# pub_rec_bankruptcies - single valued for more than 99%*
*# addr_state - may not depend on location as its in financial domain*
colsToDrop = ["id", "member_id", "funded_amnt", "emp_title", "pymnt_plan", "url", "desc", "title", "zip_code", "delinq_2yrs", "mths_since_last_delinq", "mths_since_last_record", "revol_bal", "initial_list_status", "out_prncp", "out_prncp_inv", "total_pymnt", "total_pymnt_inv", "total_rec_prncp", "total_rec_int", "total_rec_late_fee", "recoveries", "collection_recovery_fee", "last_pymnt_d", "last_pymnt_amnt", "next_pymnt_d", "last_credit_pull_d", "collections_12_mths_ex_med", "policy_code", "acc_now_delinq", "chargeoff_within_12_mths", "delinq_amnt", "tax_liens", "application_type", "pub_rec_bankruptcies", "addr_state"]
loan.drop(colsToDrop, axis=1, inplace=True)
print("Features we are left with",list(loan.columns))
我们只剩下 ['loan_amnt ',' funded_amnt_inv ',' term ',' int_rate ',' partition ',' grade ',' sub_grade ',' emp_length ',' home_ownership ',' annual_inc ',' verification_status ',' issue_d ',' loan_status ',' purpose ',' earliest_cr_line ',' inq_last_6mths ',' open_acc ',' pub_rec ',' revol_util ',' total_acc']
现在,通过移除/输入来处理缺失值:
*# in 12 unique values we have 10+ years the most for emp_length,*
*# but it is highly dependent variable so we will not impute*
*# but remove the rows with null values which is around 2.5%*loan.dropna(axis=0, subset=["emp_length"], inplace=True)*# remove NA rows for revol_util as its dependent and is around 0.1%*loan.dropna(axis=0, subset=["revol_util"], inplace=True)
现在,我们将一些特征列标准化,以使数据兼容用于分析:
*# update int_rate, revol_util without % sign and as numeric type*loan["int_rate"] = pd.to_numeric(loan["int_rate"].apply(lambda x:x.split('%')[0]))loan["revol_util"] = pd.to_numeric(loan["revol_util"].apply(lambda x:x.split('%')[0]))*# remove text data from term feature and store as numerical*loan["term"] = pd.to_numeric(loan["term"].apply(lambda x:x.split()[0]))
删除贷款状态为“当前”的记录,因为贷款当前正在运行,我们无法从这些贷款中推断出任何有关违约的信息。
*# remove the rows with loan_status as "Current"*
loan = loan[loan["loan_status"].apply(lambda x:False if x == "Current" else True)] *# update loan_status as Fully Paid to 0 and Charged Off to 1*
loan["loan_status"] = loan["loan_status"].apply(lambda x: 0 if x == "Fully Paid" else 1)*# update emp_length feature with continuous values as int*
*# where (< 1 year) is assumed as 0 and 10+ years is assumed as 10 and rest are stored as their magnitude*loan["emp_length"] = pd.to_numeric(loan["emp_length"].apply(lambda x:0 if "<" in x else (x.split('+')[0] if "+" in x else x.split()[0])))*# look through the purpose value counts*
loan_purpose_values = loan["purpose"].value_counts()*100/loan.shape[0]
*# remove rows with less than 1% of value counts in paricular purpose*
loan_purpose_delete = loan_purpose_values[loan_purpose_values<1].index.values
loan = loan[[False if p in loan_purpose_delete else True for p in loan["purpose"]]]
异常值处理
查看每个特征的分位数值,我们将处理某些特征的异常值。
*# for annual_inc, the highest value is 6000000 where 75% quantile value is 83000, and is 100 times the mean
# we need to remomve outliers from annual_inc i.e. 99 to 100%*
annual_inc_q = loan["annual_inc"].quantile(0.99)
loan = loan[loan["annual_inc"] < annual_inc_q]*# for open_acc, the highest value is 44 where 75% quantile value is 12, and is 5 times the mean
# we need to remomve outliers from open_acc i.e. 99.9 to 100%*
open_acc_q = loan["open_acc"].quantile(0.999)
loan = loan[loan["open_acc"] < open_acc_q]*# for total_acc, the highest value is 90 where 75% quantile value is 29, and is 4 times the mean
# we need to remomve outliers from total_acc i.e. 98 to 100%*
total_acc_q = loan["total_acc"].quantile(0.98)
loan = loan[loan["total_acc"] < total_acc_q]*# for pub_rec, the highest value is 4 where 75% quantile value is 0, and is 4 times the mean
# we need to remomve outliers from pub_rec i.e. 99.5 to 100%*
pub_rec_q = loan["pub_rec"].quantile(0.995)
loan = loan[loan["pub_rec"] <= pub_rec_q]
这是我们的数据在清理和标准化功能后的样子:

(图片由作者提供)
度量派生
- 发行日期不是标准格式,我们也可以将日期分为月和年两栏,这样便于分析
- 日期时间中的 Year 要求 year 介于 00 到 99 之间,在某些情况下 year 是一位数,即 9 编写一个将转换此类日期的函数,以避免日期转换中出现异常。
def standerdisedate(date):
year = date.split("-")[0]
if(len(year) == 1):
date = "0"+date
return datefrom datetime import datetime
loan['issue_d'] = loan['issue_d'].apply(lambda x:standerdisedate(x))
loan['issue_d'] = loan['issue_d'].apply(lambda x: datetime.strptime(x, '%b-%y'))*# extracting month and year from issue_date*
loan['month'] = loan['issue_d'].apply(lambda x: x.month)
loan['year'] = loan['issue_d'].apply(lambda x: x.year)*# get year from issue_d and replace the same*
loan["earliest_cr_line"] = pd.to_numeric(loan["earliest_cr_line"].apply(lambda x:x.split('-')[1]))
宁滨连续特征:
*# create bins for loan_amnt range*
bins = [0, 5000, 10000, 15000, 20000, 25000, 36000]
bucket_l = ['0-5000', '5000-10000', '10000-15000', '15000-20000', '20000-25000','25000+']
loan['loan_amnt_range'] = pd.cut(loan['loan_amnt'], bins, labels=bucket_l)*# create bins for int_rate range*
bins = [0, 7.5, 10, 12.5, 15, 100]
bucket_l = ['0-7.5', '7.5-10', '10-12.5', '12.5-15', '15+']
loan['int_rate_range'] = pd.cut(loan['int_rate'], bins, labels=bucket_l)*# create bins for annual_inc range*
bins = [0, 25000, 50000, 75000, 100000, 1000000]
bucket_l = ['0-25000', '25000-50000', '50000-75000', '75000-100000', '100000+']
loan['annual_inc_range'] = pd.cut(loan['annual_inc'], bins, labels=bucket_l)*# create bins for installment range*
def installment(n):
if n <= 200:
return 'low'
elif n > 200 and n <=500:
return 'medium'
elif n > 500 and n <=800:
return 'high'
else:
return 'very high'
loan['installment'] = loan['installment'].apply(lambda x: installment(x))*# create bins for dti range*
bins = [-1, 5.00, 10.00, 15.00, 20.00, 25.00, 50.00]
bucket_l = ['0-5%', '5-10%', '10-15%', '15-20%', '20-25%', '25%+']
loan['dti_range'] = pd.cut(loan['dti'], bins, labels=bucket_l)
将创建以下箱:

(图片由作者提供)
可视化数据洞察力
*# check for amount of defaults in the data using countplot*
plt.figure(figsize=(14,5))
sns.countplot(y="loan_status", data=loan)
plt.show()

(图片由作者提供)
从上图我们可以看出,在总共 35152 条记录中,约有 16%即 5062 人是违约者。
单变量分析
*# function for plotting the count plot features wrt default ratio*
def plotUnivariateRatioBar(feature, data=loan, figsize=(10,5), rsorted=True):
plt.figure(figsize=figsize)
if rsorted:
feature_dimension = sorted(data[feature].unique())
else:
feature_dimension = data[feature].unique()
feature_values = []
for fd in feature_dimension:
feature_filter = data[data[feature]==fd]
feature_count = len(feature_filter[feature_filter["loan_status"]==1])
feature_values.append(feature_count*100/feature_filter["loan_status"].count())
plt.bar(feature_dimension, feature_values, color='orange', edgecolor='white')
plt.title("Loan Defaults wrt "+str(feature)+" feature - countplot")
plt.xlabel(feature, fontsize=16)
plt.ylabel("defaulter %", fontsize=16)
plt.show()# function to plot univariate with default status scale 0 - 1
def plotUnivariateBar(x, figsize=(10,5)):
plt.figure(figsize=figsize)
sns.barplot(x=x, y='loan_status', data=loan)
plt.title("Loan Defaults wrt "+str(x)+" feature - countplot")
plt.xlabel(x, fontsize=16)
plt.ylabel("defaulter ratio", fontsize=16)
plt.show()
a .分类特征
*# check for defaulters wrt term in the data using countplot*
plotUnivariateBar("term", figsize=(8,5))

(图片由作者提供)
从上面的“期限”图中,我们可以推断,违约率在期限内不断增加,因此,3600 万英镑贷款违约的可能性小于 6000 万英镑。
**is term benificial -> Yes**
*# check for defaulters wrt grade in the data using countplot*
plotUnivariateRatioBar("grade")

(图片由作者提供)
从上面的“等级”图中,我们可以推断出违约率随着等级的增加而增加,因此贷款违约的几率随着等级从 A 向 g 的增加而增加。
**is grade benificial -> Yes**
*# check for defaulters wrt sub_grade in the data using countplot*
plotUnivariateBar("sub_grade", figsize=(16,5))

(图片由作者提供)
从上面的“路基”图中,我们可以推断出违约率在路基中增加,因此贷款违约的机会随着路基从 A1 向 G5 移动而增加。
**is sub_grade benificial -> Yes**
*# check for defaulters wrt home_ownership in the data*
plotUnivariateRatioBar("home_ownership")

(图片由作者提供)
从上面的“房屋所有权”图中,我们可以推断这里的违约率是恒定的(其他人的违约率相当高,但我们不知道那里有什么,所以我们不会考虑它进行分析),因此违约率不取决于房屋所有权
**is home_ownership benificial -> No**
*# check for defaulters wrt verification_status in the data*
plotUnivariateRatioBar("verification_status")

(图片由作者提供)
从上面的“验证 _ 状态”图中,我们可以推断出违约率正在增加,并且未验证用户的违约率小于已验证用户的违约率,但是对分析没有用处。
**is verification_status benificial -> No**
*# check for defaulters wrt purpose in the data using countplot*
plotUnivariateBar("purpose", figsize=(16,6))

(图片由作者提供)
从上述“目的”图中,我们可以推断,除“小企业”外,所有目的类型的违约率几乎是恒定的,因此违约率将取决于贷款的目的
**is purpose benificial -> Yes**
*# check for defaulters wrt open_acc in the data using countplot*
plotUnivariateRatioBar("open_acc", figsize=(16,6))

(图片由作者提供)
从上面的“open_acc”图中,我们可以推断,对于功能 open_acc,违约率几乎是恒定的,因此违约率不依赖于 open_acc 功能
**is open_acc benificial -> No**
*# check for defaulters wrt pub_rec in the data using countplot*
plotUnivariateRatioBar("pub_rec")

(图片由作者提供)
从上面的“pub_rec”图中,我们可以推断出违约率几乎在增加,因为 0 的违约率较小,而值为 1 的 pub_rec 的违约率较大,但由于其他值与 0 相比非常小,因此我们不会考虑这一点
**is pub_rec benificial -> No**
b .连续特征
*# check for defaulters wrt emp_length in the data using countplot*
plotUnivariateBar("emp_length", figsize=(14,6))

(图片由作者提供)
从上面的“雇员长度”图中,我们可以推断出违约率在这里是常数,因此违约率不依赖于雇员长度
**is emp_length benificial -> No**
*# check for defaulters wrt month in the data using countplot*
plotUnivariateBar("month", figsize=(14,6))

(图片由作者提供)
从上面的“月”图中,我们可以推断出违约率在这里几乎是常数,没有用
**is month benificial -> No**
*# check for defaulters wrt year in the data using countplot*
plotUnivariateBar("year")

(图片由作者提供)
从上面的“年”图中,我们可以推断出违约率在这里几乎是常数,没有用
**is year benificial -> No**
*# check for defaulters wrt earliest_cr_line in the data*
plotUnivariateBar("earliest_cr_line", figsize=(16,10))

(图片由作者提供)
从上面的“earliest_cr_line”图中,我们可以推断,除了 65 岁左右的年份,所有目的类型的违约率几乎都是恒定的,因此违约率不依赖于人的 earliest_cr_line
**is earliest_cr_line benificial -> No**
*# check for defaulters wrt inq_last_6mths in the data*
plotUnivariateBar("inq_last_6mths")

(图片由作者提供)
从上面的“inq_last_6mths”图中,我们可以推断,违约率不会随着 inq_last_6mths 类型的增加而持续增加,因此没有用
**is inq_last_6mths benificial -> No**
*# check for defaulters wrt revol_util in the data using countplot*
plotUnivariateRatioBar("revol_util", figsize=(16,6))

(图片由作者提供)
从上述“革命”图中,我们可以推断,违约率是波动的,有些违约率为 100%,并且随着规模的增加而增加,因此违约率将取决于革命的特点
**is revol_util benificial -> Yes**
*# check for defaulters wrt total_acc in the data using countplot*
plotUnivariateRatioBar("total_acc", figsize=(14,6))

(图片由作者提供)
从上面的‘total_acc’图中,我们可以推断出,对于所有的 total_acc 值,违约率几乎是恒定的,因此违约率不依赖于 total _ ACC 特性
**is total_acc benificial -> No**
*# check for defaulters wrt loan_amnt_range in the data using countplot*
plotUnivariateBar("loan_amnt_range")

(图片由作者提供)
从上面的“贷款 _amnt_range”图中,我们可以推断出违约率正在增加贷款 _amnt_range 值,因此利率将取决于贷款 _amnt_range 特征
**is loan_amnt_range benificial -> Yes**
*# check for defaulters wrt int_rate_range in the data*
plotUnivariateBar("int_rate_range")

(图片由作者提供)
从上面的“int_rate_range”图中,我们可以推断出违约率随着 int_rate_range 值的增加而降低,因此违约率将取决于 int_rate_range 特性
**is int_rate_range benificial -> Yes**
*# check for defaulters wrt annual_inc_range in the data*
plotUnivariateBar("annual_inc_range")

(图片由作者提供)
从上述“年度收入范围”图中,我们可以推断违约率随着年度收入范围值的增加而降低,因此违约率将取决于年度收入范围特征
**is annual_inc_range benificial -> Yes**
*# check for defaulters wrt dti_range in the data using countplot*
plotUnivariateBar("dti_range", figsize=(16,5))

(图片由作者提供)
从上面的“dti_range”图中,我们可以推断违约率随着 dti_range 值的增加而增加,因此违约率将取决于 dti_range 特性
**is dti_range benificial -> Yes**
*# check for defaulters wrt installment range in the data*
plotUnivariateBar("installment", figsize=(8,5))

(图片由作者提供)
从上述“分期付款”图中,我们可以推断违约率随着分期付款值的增加而增加,因此违约率将取决于 dti_range 特征
**is installment benificial -> Yes**
因此,以下是我们从上述单变量分析中推导出的重要特征:
**term, grade, purpose, pub_rec, revol_util, funded_amnt_inv, int_rate, annual_inc, dti, installment**
双变量分析
*# function to plot scatter plot for two features*
def plotScatter(x, y):
plt.figure(figsize=(16,6))
sns.scatterplot(x=x, y=y, hue="loan_status", data=loan)
plt.title("Scatter plot between "+x+" and "+y)
plt.xlabel(x, fontsize=16)
plt.ylabel(y, fontsize=16)
plt.show()
def plotBivariateBar(x, hue, figsize=(16,6)):
plt.figure(figsize=figsize)
sns.barplot(x=x, y='loan_status', hue=hue, data=loan)
plt.title("Loan Default ratio wrt "+x+" feature for hue "+hue+" in the data using countplot")
plt.xlabel(x, fontsize=16)
plt.ylabel("defaulter ratio", fontsize=16)
plt.show()
用条形图和散点图在 y 轴上绘制关于贷款违约率的两种不同特征。
*# check for defaulters wrt annual_inc and purpose in the data using countplot*
plotBivariateBar("annual_inc_range", "purpose")

(图片由作者提供)
从上面的图中,我们可以推断出它没有显示任何相关性
**related - N**
*# check for defaulters wrt term and purpose in the data*
plotBivariateBar("term", "purpose")

(图片由作者提供)
正如我们在图上看到的直线,违约率随着每一个目的贷款期限的增加而增加
**related - Y**
*# check for defaulters wrt grade and purpose in the data*
plotBivariateBar("grade", "purpose")

(图片由作者提供)
正如我们在图上看到的直线,违约率随着各种用途的 wrt 等级而增加
**related - Y**
*# check for defaulters wrt loan_amnt_range and purpose in the data*
plotBivariateBar("loan_amnt_range", "purpose")

(图片由作者提供)
正如我们在图上看到的直线,违约率在每种用途下都增加
**related - Y**
*# check for defaulters wrt loan_amnt_range and term in the data*
plotBivariateBar("loan_amnt_range", "term")

(图片由作者提供)
正如我们在图上看到的直线一样,每一个期限的违约率都在增加
**related - Y**
*# check for defaulters wrt annual_inc_range and purpose in the data*
plotBivariateBar("annual_inc_range", "purpose")

(图片由作者提供)
正如我们在图上看到的直线,违约率在 wrt annual_inc_range 的各种用途下都会增加
**related - Y**
*# check for defaulters wrt annual_inc_range and purpose in the data*
plotBivariateBar("installment", "purpose")

(图片由作者提供)
正如我们在图上看到的直线一样,除了小企业之外,每个目的的 wrt 分期付款的违约率都在增加
**related - Y**
*# check for defaulters wrt loan_amnt_range in the data*
plotScatter("int_rate", "annual_inc")

(图片由作者提供)
正如我们在图上看到的直线,上述特征之间没有关系
**related - N**
*# plot scatter for funded_amnt_inv with dti*
plotScatter("funded_amnt_inv", "dti")

(图片由作者提供)
正如我们在图上看到的直线,上述特征之间没有关系
**related - N**
*# plot scatter for funded_amnt_inv with annual_inc*
plotScatter("annual_inc", "funded_amnt_inv")

(图片由作者提供)
正如我们在图上看到的斜率模式,上述特征之间存在正相关关系
**related - Y**
*# plot scatter for loan_amnt with int_rate*
plotScatter("loan_amnt", "int_rate")

(图片由作者提供)
正如我们在图上看到的直线模式,上述特征之间没有关系
**related - N**
*# plot scatter for int_rate with annual_inc*
plotScatter("int_rate", "annual_inc")

(图片由作者提供)
正如我们在图上看到的密度降低的负相关模式,上述特征之间存在某种关系
**related - Y**
*# plot scatter for earliest_cr_line with int_rate*
plotScatter("earliest_cr_line", "int_rate")

(图片由作者提供)
正如我们在图上看到的密度增加的正相关模式,上述特征之间存在相互关系
**related - Y**
*# plot scatter for annual_inc with emp_length*
plotScatter("annual_inc", "emp_length")

(图片由作者提供)
正如我们在图上看到的直线模式,上述特征之间没有关系
**related - N**
*# plot scatter for earliest_cr_line with dti*
plotScatter("earliest_cr_line", "dti")

(图片由作者提供)
用箱线图和小提琴图在 y 轴上绘制关于贷款违约率的两种不同特征。
*# function to plot boxplot for comparing two features*
def plotBox(x, y, hue="loan_status"):
plt.figure(figsize=(16,6))
sns.boxplot(x=x, y=y, data=loan, hue=hue, order=sorted(loan[x].unique()))
plt.title("Box plot between "+x+" and "+y+" for each "+hue)
plt.xlabel(x, fontsize=16)
plt.ylabel(y, fontsize=16)
plt.show()
plt.figure(figsize=(16,8))
sns.violinplot(x=x, y=y, data=loan, hue=hue, order=sorted(loan[x].unique()))
plt.title("Violin plot between "+x+" and "+y+" for each "+hue)
plt.xlabel(x, fontsize=16)
plt.ylabel(y, fontsize=16)
plt.show()*# plot box for term vs int_rate for each loan_status*
plotBox("term", "int_rate")

(图片由作者提供)

(图片由作者提供)
贷款期限越长,利率越高,违约几率也越大
*# plot box for loan_status vs int_rate for each purpose*
plotBox("loan_status", "int_rate", hue="purpose")

(图片由作者提供)

(图片由作者提供)
int_rate 相当高,其中贷款对于每个目的值都是默认的
*# plot box for purpose vs revo_util for each status*
plotBox("purpose", "revol_util")

(图片由作者提供)

(图片由作者提供)
在贷款违约的情况下,revol_util 更适用于各种用途价值,对于信用卡来说,revol _ util 相当高
*# plot box for grade vs int_rate for each loan_status*
plotBox("grade", "int_rate", "loan_status")

(图片由作者提供)

(图片由作者提供)
int_rate 随着每个年级而增加,并且每个年级的违约者的中位数接近 int_rate 的非违约者的 75%分位数
*# plot box for issue_d vs int_rate for each loan_status*
plotBox("month", "int_rate", "loan_status")

(图片由作者提供)

(图片由作者提供)
违约者的 int_rate 随着每个月而增加,其中每个月的违约者的中位数接近非违约者的 int_rate 的 75%分位数,但是每个月几乎是恒定的,没有用
因此,以下是我们从上述双变量分析中推导出的重要特征:
**term, grade, purpose, pub_rec, revol_util, funded_amnt_inv, int_rate, annual_inc, installment**
多元分析(相关性)
*# plot heat map to see correlation between features*
continuous_f = ["funded_amnt_inv", "annual_inc", "term", "int_rate", "loan_status", "revol_util", "pub_rec", "earliest_cr_line"]
loan_corr = loan[continuous_f].corr()
sns.heatmap(loan_corr,vmin=-1.0,vmax=1.0,annot=True, cmap="YlGnBu")
plt.title("Correlation Heatmap")
plt.show()

(图片由作者提供)
因此,来自上述多变量分析的重要相关特征是:
**term, grade, purpose, revol_util, int_rate, installment, annual_inc, funded_amnt_inv**
最终调查结果
在分析了数据集中所有可用的相关特征后,我们已经结束,为 Lending Club 贷款违约分析推导出主要的驱动特征:
贷款违约分析的最佳驱动特征是: 期限、等级、用途、周转、利率、分期、年度公司、基金 _ 资产 _ 投资
















浙公网安备 33010602011771号