TowardsDataScience-博客中文翻译-2020-七十五-
TowardsDataScience 博客中文翻译 2020(七十五)
k 近邻(KNN)算法
寻找最近邻居的算法

图片来自 Unsplash 的 Joshua J. Cotten
目录:
- 什么是 KNN?
- KNN 算法的工作原理
- K 变了会怎样?
- 如何选择合适的 K?
- KNN 的局限性
- KNN 的实际应用
- 结论
1.什么是 KNN?
k 近邻(KNN)是一种有监督的机器学习算法。监督机器学习算法的目标是学习一个函数,使得 f(X) = Y,其中 X 是输入,Y 是输出。KNN 既可用于分类,也可用于回归。在本文中,我们将只讨论分类。虽然对于回归来说,只是一个微小的变化。
KNN 的特性在于它是一种懒惰的学习算法和一种非参数方法。
懒学习是指算法学习时间几乎为零,因为它只存储训练部分的数据(没有学习一个函数)。然后,存储的数据将用于评估新的查询点。
非参数方法是指不假设任何分布的方法。因此,KNN 不必为分布寻找任何参数。而在参数方法中,模型发现新的参数,这些参数又将用于预测目的。KNN 唯一的超参数(由用户提供给模型)是 K,这是为了比较需要考虑的点数。

k-最近邻居。来源
上图中,黄色是查询点,我们想知道它属于哪一类(红色还是绿色)。
K=3 时,考虑黄点的 3 个最近邻点,并且基于多数将类分配给查询点(例如,2 个绿色和 1 个红色-则它属于绿色类)。类似地,对于 K=5,5 个最近邻被考虑用于比较,并且大多数将决定查询点属于哪个类。这里需要注意的一点是,如果 K 的值是偶数,那么在进行多数表决时可能会产生问题,因为数据具有偶数个类(即 2 个)。因此,当数据具有偶数个类时,选择 K 作为奇数,当数据具有奇数个类时,选择偶数。
2.KNN 算法的工作原理
在训练阶段,模型将存储数据点。在测试阶段,计算从查询点到来自训练阶段的点的距离,以对测试数据集中的每个点进行分类。可以计算各种距离,但最流行的是欧几里德距离(用于较小维度的数据)。
查询点(q)和训练数据点(p)之间的欧几里德距离被定义为

点 p 和 q (n 维点)之间的欧几里德距离。来源
也可以根据数据使用其他距离度量,如 Manhattan、Hamming 和 Chebyshev 距离,这超出了本文的范围。
让我们用一个例子来学习它:
我们有 500 个 N 维点,300 个是 0 类,200 个是 1 类。
计算查询点类别的步骤是:
- 从查询点开始计算所有 500 个点的距离。
- 基于 K 的值,K 个最近邻被用于比较目的。
- 假设 K=7,7 个点中有 4 个是 0 类,3 个是 1 类。然后基于多数,查询点 p 被分配为类别 0。
3.K 变了会怎样?

分离红色和蓝色类的决策表面,k=1(左)和 k=5(右)。作者图片
K=1 意味着它将采用一个最近邻,并基于此对查询点进行分类。划分类别的表面将非常不平坦(许多顶点)。
这里出现的问题是,如果数据中存在异常值,决策面会将其视为数据点。因此,KNN 将在训练数据集上表现出色,但会在测试数据集(看不见的数据)上对许多点进行错误分类。这被认为是过度拟合,因此,KNN 对异常值很敏感。
随着 K 值的增加,表面变得平滑,不会将异常值视为数据点。这也将在测试数据集上更好地概括模型。
如果 K 值非常大,模型将会欠拟合,并且将无法对新的数据点进行分类。例如,如果 K 等于数据点的总数,则无论查询点位于何处,模型都会根据整个数据集的多数类对查询点进行分类。
选择正确的 K 值将给出准确的结果。但是如何选择呢?
4.如何选择合适的 K?
在实际问题中,数据集分为三个部分,即训练、验证和测试数据。在 KNN,训练数据点被存储,并且没有学习被执行。验证数据是用来检验模型性能的,测试数据是用来预测的。
要选择最佳 K,请在训练数据集和验证数据集上绘制模型的误差(误差= 1-精度)。最佳 K 是验证误差最低的地方,并且训练和验证误差彼此接近。

错误率和 K. 来源
5.KNN 的局限性
时间复杂度和空间复杂度是巨大的,这是 KNN 的一大劣势。时间复杂度指的是模型评估查询点的类别所花费的时间。空间复杂度是指算法使用的总内存。如果我们在训练中有 n 个数据点,并且每个点是 m 维的。那么时间复杂度是 O(nm)量级,如果我们有更高维的数据,这将是巨大的。因此,KNN 不适合高维数据。
另一个缺点是,如果数据点远离存在的类(没有相似性),KNN 将分类该点,即使它是一个离群值。为了克服时间复杂性的问题,可以使用 KD-Tree 和 LSH(Locality Sensitive Hashing,Locality Sensitive Hashing)等算法,这不在本文讨论范围之内。
6.KNN 的实际应用
- KNN 可以用于推荐系统。虽然在现实世界中,推荐系统使用更复杂的算法。KNN 不适合高维数据,但 KNN 是一个很好的系统基线方法。许多公司为其消费者提供个性化推荐,如网飞、亚马逊、YouTube 等。
- KNN 可以搜索语义相似的文档。每个文档都被视为一个向量。如果文档彼此靠近,这意味着文档包含相同的主题。
- KNN 可以有效地用于检测异常值。一个这样的例子是信用卡欺诈检测。
7.结论
K-最近邻(KNN)是在给定 k 值的情况下识别最近邻。它是一种懒惰学习和非参数算法。KNN 在低维数据集上工作,而在处理高维数据时面临问题。
k-最近邻(kNN)-解释
详细的理论解释和 scikit-learn 实现

k-最近邻(kNN)是一种受监督的机器学习算法,可用于解决分类和回归任务。我认为 kNN 是一种来自现实生活的算法。人们往往会受到周围人的影响。我们的行为受到从小一起长大的朋友的指导。我们的父母也在某些方面塑造了我们的性格。如果你和热爱运动的人一起长大,你很可能最终也会热爱运动。当然也有例外。kNN 的工作原理类似。
一个数据点的价值是由其周围的数据点决定的。
- 如果你有一个非常亲密的朋友,并且大部分时间都和他/她在一起,你们最终会分享相似的兴趣和享受相同的东西。也就是 k=1 的 kNN。
- 如果你总是和一群 5 人在一起,这个群体中的每个人都会对你的行为产生影响,你最终会成为 5 人中的平均水平。那就是 kNN,其中 k=5 。
kNN 分类器通过多数表决原则确定数据点的类别。如果 k 设置为 5,则检查 5 个最近点的类。根据多数类进行预测。类似地,kNN 回归取 5 个最近点的平均值。
我们观察接近的人,但是数据点是如何确定接近的?测量数据点之间的距离。测量距离的方法有很多。欧几里德距离(闵可夫斯基距离与 p=2)是最常用的距离度量之一。下图显示了如何计算二维空间中两点之间的欧几里德距离。它是使用点的 x 和 y 坐标之差的平方来计算的。

在上面的例子中,欧几里德距离是(16 + 9)的平方根,也就是 5。二维中的欧几里得距离让我们想起了著名的勾股定理。
对于二维空间中的两个点来说,这似乎非常简单。每个维度代表数据集中的一个未来。我们通常有许多具有许多特征的样品。为了能够清楚地解释这个概念,我将回顾一个二维空间中的例子(即 2 个特征)。
你可以访问这个 github repo 中的所有代码。放心用吧!
让我们从导入库开始:

Scikit-learn 提供了许多有用的功能来创建合成数据集,这对实践机器学习算法非常有帮助。我将使用make _ blobs函数。

此代码创建了一个数据集,包含 100 个样本,分为 4 类,特征数为 2。使用相关参数可以轻松调整样本、特征和类别的数量。我们还可以调整每个集群(或类)的分布程度。让我们想象一下这个合成数据集:

对于任何有监督的机器学习算法,将数据集划分为训练集和测试集是非常重要的。我们首先训练模型,并使用数据集的不同部分对其进行测试。如果这种分离没有完成,我们基本上是用模型已经知道的一些数据来测试模型。我们可以使用 train_test_split 函数轻松实现这种分离。

我们可以分别使用 train_size 或 test_size 参数指定有多少原始数据用于训练或测试集。训练集的默认分离度为 75%,测试集的默认分离度为 25%。
然后我们创建一个 kNN 分类器对象。为了显示 k 值的重要性之间的差异,我创建了 k 值为 1 和 5 的两个分类器。然后使用训练集训练这些模型。 n_neighbors 参数用于选择 k 值。默认值为 5,因此不必显式写入。

然后我们预测测试集中的目标值,并与实际值进行比较。

为了查看 k 值的影响,让我们可视化 k=5 和 k=1 的测试集和预测值。



结果似乎非常相似,因为我们使用了一个非常小的数据集。然而,即使在小数据集上,不同的 k 值对某些点的预测也是不同的。
如何找到最佳 k 值
- k=1 :模型太具体,没有很好的概括。它对噪音也很敏感。该模型在训练集上实现了高精度,但是在新的、以前看不到的数据点上将是差的预测器。因此,我们很可能以一个过度拟合的模型而告终。
- k=100 :该模型过于一般化,在训练集和测试集上都不是一个好的预测器。这种情况被称为欠适配。
我们如何找到最佳的 k 值?Scikit-learn 提供了 GridSearchCV 函数,使我们能够轻松检查 k 的多个值。让我们使用 scikit-learn datasets 模块下的数据集来查看一个示例。

在导入所需的库并加载数据集之后,我们可以创建一个 GridSearchCV 对象。

我们不需要分割数据集,因为 cv 参数分割数据集。cv 参数的缺省值是 5,但是我明确地写了它来强调为什么我们不需要使用 train_test_split。
cv=5 基本上将数据集分成 5 个子集。GridSearchCV 进行 5 次迭代,每次使用 4 个子集进行训练,1 个子集进行测试。通过这种方式,我们能够将所有数据点用于训练和测试。
我们可以使用 best_params_ 方法检查哪些参数能给出最佳结果:

在这种情况下,k 的最佳值是 12。
k 近邻的利弊
优点
- 简单易懂
- 不做任何假设,因此可以在非线性任务中实现。
- 适用于多个类别的分类
- 处理分类和回归任务
缺点
- 随着数据点数量的增加,会变得非常慢,因为模型需要存储所有的数据点。
- 内存效率不高
- 对异常值敏感。离群也有一票!
感谢您的阅读。如果您有任何反馈,请告诉我。
我关于机器学习算法的其他帖子
用于异常检测的 k-最近邻(kNN)
用于异常值和异常检测的小数据科学

妮娜·斯特雷尔在 Unsplash拍摄的照片
k-最近邻
kNN 是一种监督 ML 算法,经常用于数据科学中的分类问题(有时也用于回归问题)。这是一种最简单但被广泛使用的算法,有很好的使用案例,如构建推荐系统、人脸检测应用等。
最近邻族的基本假设是相似的观测值彼此接近,异常值通常是孤立的观测值,远离相似观测值的聚类。

kNN 概念图(图片:作者)
由于本文的目的是讨论一个用例——异常检测,所以我不会深入讨论 kNN 的更多细节。但是如果你感兴趣的话,可以看看所有最近邻算法的文档,网上有很多描述 kNN 如何工作的资料。如果你在评论中留言,我可以提供一些有用的资源。
用于异常检测的 kNN
虽然 kNN 是一种有监督的 ML 算法,但当涉及到异常检测时,它采用一种无监督的方法。这是因为在该过程中没有实际的“学习”,并且在数据集中没有预先确定的“异常值”或“非异常值”的标记,相反,它完全基于阈值。数据科学家任意决定截止值,超过该值的所有观察结果都被称为异常(我们将在后面看到)。这也是为什么没有训练测试数据分割或准确性报告。
今天的文章是我的异常、异常值和欺诈检测算法系列的继续,并附有实际操作的示例代码。我之前的 8 篇文章谈到了异常检测领域中可用的不同工具和技术,如果您有兴趣了解它们,请访问以下链接:
现在让我们继续用 Python 编程语言做一个 kNN 算法的简单演示。
步骤 1:导入库
这个演示只需要很少的库:pandas和numpy用于处理数据,matplotlib用于可视化(可选),而sklearn用于导入 kNN 算法。
# import libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import NearestNeighbors
第二步:数据准备
我正在使用来自 Github repo 的著名的虹膜数据集,所以你可以跟着练习,不用担心从哪里得到数据,如何清理它。
# import data
data = pd.read_csv("[https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv](https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv)")# input data
df = data[["sepal_length", "sepal_width"]]
现在,让我们将选择用于建模的两个变量可视化。
# scatterplot of inputs data
plt.scatter(df["sepal_length"], df["sepal_width"])

数据准备的最后一步是将特征列转换为数组。
# create arrays
X = df.values
第三步:建模
像大多数机器学习实现一样,实际建模只需很少的努力。首先,用您选择的参数实例化模型,然后使模型适合您的数据。就是这样!
kNN 中的关键参数是 n_neighbors ,它决定了用于计算测量点距离的邻居数量。
# instantiate model
nbrs = NearestNeighbors(n_neighbors = 3)# fit model
nbrs.fit(X)
步骤 4:异常检测
既然我们已经拟合了模型,接下来是提取模型输出的时候了—(a)数据点之间的距离和(b)相关的指数值—这些输出可用于检测异常。
# distances and indexes of k-neaighbors from model outputs
distances, indexes = nbrs.kneighbors(X)# plot mean of k-distances of each observation
plt.plot(distances.mean(axis =1))
绘制数据集中每个观测值的平均距离。

正如我们所看到的,距离度量中有一些尖峰,这些尖峰是数据集中潜在的异常或异常值。
现在,数据科学家面临一个最重要的决策——确定过滤异常的截止值。
如上图所示,一些截止值可能是-0.25、0.20、0.15 (y 轴),每个值过滤的异常值数量越来越多。
对于这个演示,让我们慷慨地选择 0.15 作为临界值,以获得更多的异常值。慷慨的原因是能够进一步检查数据,这样我们就不会遗漏异常值。
# visually determine cutoff values > 0.15
outlier_index = np.where(distances.mean(axis = 1) > 0.15)
outlier_index

# filter outlier values
outlier_values = df.iloc[outlier_index]
outlier_values

绘图 5(可选):绘制异常
我们已经在步骤 4 中识别了异常数据点,但是我们可以采取额外的步骤来可视化异常数据点。
# plot data
plt.scatter(df["sepal_length"], df["sepal_width"], color = "b", s = 65)# plot outlier values
plt.scatter(outlier_values["sepal_length"], outlier_values["sepal_width"], color = "r")

摘要
在本文中,我演示了如何实现 kNN——一种机器学习算法——来识别数据集中的异常。目的是展示一些简单的步骤来建立直觉,但是当然,现实世界的实现需要更多的实验来找出对于特定的环境和行业什么是有效的,什么是无效的。例如,在本演示中,我们停在了第 4 步,但现实世界中的数据科学家会更进一步,检查并重新检查过滤器数据点,以便与其他工具或领域专家进行双重检查。
感谢关注,要了解更多关于我的工作,你可以在 Twitter 或 LinkedIn 上关注我
k-最近邻解释-第 2 部分
了解最近邻的距离计算是如何进行数学计算的!

来源:U 形数据上的 KNN
在这个故事中,我们将讨论用于计算两个向量之间距离的不同类型的距离测量指标。这个度量的应用是在 K-NN 算法中寻找最近的邻居。我们将研究这些距离在 Python 中的实现。
这篇文章是以前写的关于 K-NN 的第 1 部分的延续。如果你还没有读过,读一读再回来。
KNN 算法背后的科学解释!
medium.com](https://medium.com/analytics-vidhya/k-nearest-neighbour-explained-part-1-5e5e9192050)
欧几里得距离
这是一种距离测量技术,通过直接将空间中的两点首尾相连来计算它们之间的距离。让我们看看下图所示的 2D 平面,平面上有点 p(p1,p2) 和 q(q1,q2) 。现在我们需要找到这些点之间的距离,所以我们使用毕达哥拉斯定理来计算两点之间的距离,这就是欧几里得距离。

来源:维基百科上的欧几里德距离
对于点 p(p1,p2) 和 q(q1,q2) 我们有二维向量,因此使用以下公式计算距离:

现在,以同样的方式,我们应用坐标为 p(p1,p2,p3) 和 q(q1,q2,q3) 的三维向量

因此,如果我们在空间中有一个 n 维向量(我们不能直接可视化),那么使用相同的模式,我们将计算两点之间的距离,


因此,作为一个结论,空间中任意两点之间的距离是通过使用一条称为欧几里德距离的直线直接将这些点首尾相连来计算的。
Python3.7 中 3D 矢量实现的欧几里德距离
曼哈顿距离
第二个令人惊叹的距离计算方法是曼哈顿距离,也称为 【出租车距离】 因为就像出租车穿过城市的街道到达城市中的一个点一样,曼哈顿距离是通过计算绝对距离的总和来计算的。

来源:维基百科上的曼哈顿距离
那么,为什么它被称为曼哈顿呢?曼哈顿距离被命名为 曼哈顿 是因为当我们从卫星上看纽约市的曼哈顿区域时,道路和车道看起来完全像是对称网格图案因此,对于出租车来说,要在城市内从一个点行驶到另一个点,它必须遵循在 x 轴上移动一个动作和在 y 轴上移动一个动作的策略,这就是绝对行驶路径。

来源:纽约曼哈顿谷歌地图
曼哈顿距离可以使用 L1 范数的概念来计算,其中 p(p1,p2,…,pn) 和 q(q1,q2,…,qn) 是 n 维向量。

汉娩距
有一种惊人的距离查找技术叫做 【汉明距离】 它通常用于查找两个字符串之间的对称距离,计算方法是找出两个字符串中所有位置的不相等字符,然后将它们相加,计算出总的不相等字符值。

来源:汉明距离维基百科
为什么叫海明距离?汉明距离是以理查德·汉明的名字命名的,他在关于汉明码的基础论文中介绍了这个概念。
为了找出两个字符串 S1 和 S2 之间的距离,我们开始同时从左到右一个接一个地探索两个字符串中的所有字符,每当第一个字符串中的字符与第二个字符串中相同位置的字符不相等时,我们就将距离的计数增加 1,这仅仅意味着只有当两个字符串中的字符不匹配时,计数才增加。
"汉明距离只在两个弦的长度完全相同时有效."
例如,“ karolin ”和“ kathrin ”之间的距离是 3,因为第一个字符串的位置 3、4 和 5 处的字符对于第二个字符串是不同的,这使距离值增加了 1。
汉明距离在 Python 3.7 中的实现
余弦距离或余弦相似度
余弦相似度是在两个向量 X1 和 X2 之间测量的角距离,这意味着 X1 和 X2 之间的角度的。角度越小,其 cos(角度) 越高,因此其余弦相似度越高。
"余弦相似性表示两个向量之间的方向相似性"

来源:奥雷利两个项目之间的余弦相似度
例如,角度为 0 的两个向量具有 cos(0 )=1 ,这是最高的相似度,而角度为 90 的向量给出 cos(90 )=0 ,从而给出向量之间的‘0’相似度。同样,当两个向量之间的角度达到 180 时,相似度甚至变成'-1’。
给定两个向量 X1 和 X2,它们的 Cos-Sim 可以计算为:

余弦相似距离在 Python 3.7 中的实现
由 Paras Varshney 撰写的关于数据科学的更多文章:
一个实用的方法来计算模型的性能和在 Python 中的实现,涵盖了所有数学…
medium.com](https://medium.com/@pv009/how-to-evaluate-machine-learning-model-performance-in-python-135b4ae27f7e) [## 如何建立一个能让你找到工作的数据科学投资组合?
学会制作一个关于你的强有力的作品集!
medium.com](https://medium.com/datadriveninvestor/how-to-build-a-data-science-portfolio-that-can-get-you-a-job-9f8d113739b3) [## “正态分布”的功效
理解钟形曲线背后的科学!
medium.com](https://medium.com/analytics-vidhya/the-powers-of-normal-distribution-4cbb06e4a955)
更多数据科学和机器学习相关文章关注我上 中 。想给我买杯咖啡吗?在 LinkedIn 上和我连线。
谢谢!**
k 近邻(kNN)算法:常见问题和 Python 实现

测试数据科学家关于 kNN 算法及其 Python 实现的问题
k 近邻被认为是最直观的机器学习算法之一,因为它易于理解和解释。此外,直观地演示一切是如何进行的也很方便。然而,kNN 算法仍然是一种常见的非常有用的算法,用于各种分类问题。如果你是机器学习的新手,请确保测试自己对这个简单而又精彩的算法的理解。关于它是什么以及它是如何工作的,有很多有用的资料来源,因此我想以我个人的观点来看一下你应该知道的 5 个常见或有趣的问题。
k-NN 算法在测试时间而不是训练时间上做更多的计算。
那绝对是真的。kNN 算法的思想是找到一个 k 长的样本列表,该列表接近我们想要分类的样本。因此,训练阶段基本上是存储训练集,而在预测阶段,算法使用存储的数据寻找 k 个邻居。
为什么需要为 k-NN 算法缩放数据?
假设一个数据集有 m 个“示例”和 n 个“特征”。有一个特征维度的值正好在 0 和 1 之间。同时,还有一个从-99999 到 99999 不等的特征维度。考虑到欧几里德距离的公式,这将通过给予具有较高幅度的变量较高的权重来影响性能。
k-NN 算法可用于输入分类变量和连续变量的缺失值。
这是真的。在处理缺失值时,k-NN 可以用作许多技术中的一种。通过确定训练集中“最接近”的样本来估算新样本,并对这些要估算的邻近点进行平均。scikit 学习库提供了一种使用这种技术快捷方便的方法。
注:在计算距离时,NaNs 被省略。
示例:
from sklearn.impute import KNNImputer
# define imputer
imputer = KNNImputer() #default k is 5=> *n_neighbors=5*
# fit on the dataset
imputer.fit(X)
# transform the dataset
Xtrans = imputer.transform(X)
因此,缺失值将被其“邻居”的平均值所替代。
欧氏距离总是这样吗?
虽然欧几里德距离是最常用和教授的方法,但它并不总是最佳决策。事实上,仅仅通过查看数据很难得出正确的指标,所以我建议尝试一组数据。但是,也有一些特殊情况。例如,汉明距离用于分类变量的情况。
阅读更多: 每个数据科学家都应该知道的 3 个文本距离
为什么我们不应该对大型数据集使用 KNN 算法?
以下是 KNN 算法中出现的数据流的概述:
- 计算到训练集中所有向量的距离并存储它们
- 对计算的距离进行排序
- 存储 K 个最近的向量
- 计算 K 个最近向量显示的最频繁类别
假设你有一个非常大的数据集。因此,存储大量数据不仅是一个糟糕的决定,而且不断计算和排序所有值的计算成本也很高。
Python 实现
我将把实施分为以下几个阶段:
- 计算到训练集中所有向量的距离并存储它们
- 对计算的距离进行排序
- 计算 K 个最近向量显示的最频繁类别,并进行预测
计算训练集中所有向量的距离并存储它们
值得注意的是,有大量不同的选项可供选择作为衡量标准;但是,我想用欧几里德距离作为例子。这是计算向量间距离最常用的度量,因为它简单明了,易于解释。一般公式如下:
欧几里德距离= sqrt(sum I to N(x1 _ I-x2 _ I))
因此,让我们用下面的 Python 代码来总结一下。 注意:不要忘记从“数学”模块导入 sqrt()。
对计算出的距离进行排序
首先,我们需要计算单个测试样本和我们训练集中所有样本之间的所有距离。获得距离后,我们应该对距离列表进行排序,并通过查看它们与测试样本的距离,从我们的训练集中挑选“最近”的 k 个向量。
C 计算 K 个最近向量显示的最频繁类别并进行预测
最后,为了做一个预测,我们应该通过调用我在上面附上的函数来得到我们的 k 个“最近的”邻居。因此,剩下的唯一事情就是计算每个标签出现的次数,并选择最频繁的一个。
让我们通过将所有的函数组合成一个单独的类对象来总结一切。这里有一个更一般化的代码版本,请花些时间浏览一下。
比较
让我们将我们的实现与 scikit learn 提供的实现进行比较。我将使用一个简单的玩具数据集,它包含两个预测值,即年龄和薪水。因此,我们希望预测客户是否愿意购买我们的产品。

显示前 5 个条目的表格
我将跳过预处理,因为这不是我想关注的;然而,我使用了一种训练测试分割技术,并在之后应用了一个标准缩放器。不管怎样,如果你感兴趣,我会在 Github 上提供源代码。
最后,我将定义两个模型并拟合我们的数据。请参考上面提供的 KNN 实现。我选择 5 作为我们的默认 k 值。注意,对于后一种模型,默认度量是闵可夫斯基,并且 p=2 相当于标准欧几里德度量。
model=KNN(5) *#our model*
model.fit(X_train,y_train) predictions=model.predict(X_test)*#our model's predictions***from** **sklearn.neighbors** **import** KNeighborsClassifier
classifier = KNeighborsClassifier(n_neighbors = 5, metric = 'minkowski', p = 2)*#The default metric is minkowski, and with p=2 is equivalent to the standard Euclidean metric.*
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)
结果

上图显示,两种型号表现出相同的性能。精度结果是 0.93,这是一个相当好的结果。下图是我们测试集结果的可视化。我提供一个单一的数字,因为两个模型是相同的。然而,我个人建议使用已经提供的实现,因为我们的实现简单而低效。此外,不要每次都写完全相同的代码会更方便。

我们测试集结果的可视化
摘要
总之,K-最近邻被认为是最直观的机器学习算法之一,因为它易于理解和解释。此外,直观地演示一切是如何进行的也很方便。在本文中,我们回答了以下问题:
- k-NN 算法在测试时间而不是训练时间上做更多的计算。
- 为什么需要为 k-NN 算法缩放数据?
- k-NN 算法可用于输入分类变量和连续变量的缺失值。
- 欧氏距离总是这样吗?
- 为什么我们不应该对大型数据集使用 KNN 算法?
此外,我提供了 KNN 算法的 python 实现,以便加深您对内部发生的事情的理解。完整的实现可以在我的 Github 上找到。
有用的资源
KNN 和 K-Means 是最常用和最广泛使用的机器学习算法之一。KNN 是监督学习…
medium.com](https://medium.com/analytics-vidhya/why-is-scaling-required-in-knn-and-k-means-8129e4d88ed7) [## 每个数据科学家都应该知道的 3 种文本距离
无论您是刚刚开始接触数据科学,还是已经在该领域工作了很长时间,您都需要了解这三个文本…
towardsdatascience.com](/3-text-distances-that-every-data-scientist-should-know-7fcdf850e510) [## 基于 K-最近邻算法的机器学习基础
k-最近邻(KNN)算法是一个简单,易于实现的监督机器学习算法,可以…
towardsdatascience.com](/machine-learning-basics-with-the-k-nearest-neighbors-algorithm-6a6e71d01761)
虹膜数据集上的 k-NN
k-最近邻(k-NN)是一种基于实例的监督学习算法,它通过将一个新实例与在训练中已经看到的存储器中已经存储的实例进行比较来对该新实例进行分类。
使用以下步骤计算未知实例的类:
- 计算未知实例和所有其他训练实例之间的距离。
- k 个最近邻居被识别。
- k 个最近邻居的类别标签被用于通过使用像多数投票这样的技术来确定未知实例的类别标签。

k-NN 分类示例(图像源)
例如,在上面的图像中,如果 k 值为 3,分类器可以将未知实例分类为 B 类,如果 k 值为 7,则分类为 A 类。
这篇文章关注的是使用 Iris 数据集进行 kNN 的超参数调优。然后,使用最佳超参数对测试集实例进行分类,并计算模型的最终精度。实现是从零开始的,不依赖于现有的 python 数据科学库。
调整的超参数有:
- 距离度量:欧几里德、归一化欧几里德和余弦相似性
- k 值:1、3、5 和 7
欧几里德距离 欧几里德空间中两点 p 和 q 之间的欧几里德距离计算如下:

归一化欧几里德距离
归一化欧几里德距离是指点经过归一化后,点与点之间的欧几里德距离。
余弦相似度 余弦相似度是两个非零向量之间的相似性度量。两个向量 A 和 B 之间的余弦相似度计算如下:


现在,让我们进入用 Python 实现的分类器。为了便于理解,本节分为不同的步骤。
第一步。
加载所需的库。
**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**
**import** **operator**
**import** **matplotlib.pyplot** **as** **plt**
第二步。
将虹膜数据集加载到 Jupyter 笔记本中。数据集是 csv 格式的,可以很容易地使用熊猫库读入数据帧。数据集有四个属性萼片长度、萼片宽度、花瓣长度和花瓣宽度,以及每个实例的类标签。
data = pd.read_csv('iris.data', header=**None**, names=['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'class'])
数据帧可以显示如下:
print(data)

第三步。
将数据集分为开发集和测试集。它可以通过随机化索引然后根据索引分割数据帧来划分。
indices = np.random.permutation(data.shape[0])
div = int(0.75 * len(indices))
development_id, test_id = indices[:div], indices[div:]
development_set, test_set = data.loc[development_id,:], data.loc[test_id,:]
print("Development Set:**\n**", development_set, "**\n\n**Test Set:**\n**", test_set)
计算开发集和测试集的平均值和标准偏差,以计算归一化的欧几里德距离。
mean_development_set = development_set.mean()
mean_test_set = test_set.mean()
std_development_set = development_set.std()
std_test_set = test_set.std()
从开发和测试集中检索“class”列,并将其存储在单独的列表中。
test_class = list(test_set.iloc[:,-1])
dev_class = list(development_set.iloc[:,-1])
第四步。
定义计算距离度量值的函数:欧几里德、归一化欧几里德和余弦相似性
**def** euclideanDistance(data_1, data_2, data_len):
dist = 0
**for** i **in** range(data_len):
dist = dist + np.square(data_1[i] - data_2[i])
**return** np.sqrt(dist)
**def** normalizedEuclideanDistance(data_1, data_2, data_len, data_mean, data_std):
n_dist = 0
**for** i **in** range(data_len):
n_dist = n_dist + (np.square(((data_1[i] - data_mean[i])/data_std[i]) - ((data_2[i] - data_mean[i])/data_std[i])))
**return** np.sqrt(n_dist)
**def** cosineSimilarity(data_1, data_2):
dot = np.dot(data_1, data_2[:-1])
norm_data_1 = np.linalg.norm(data_1)
norm_data_2 = np.linalg.norm(data_2[:-1])
cos = dot / (norm_data_1 * norm_data_2)
**return** (1-cos)
定义返回 k 个最近邻的函数
**def** knn(dataset, testInstance, k, dist_method, dataset_mean, dataset_std):
distances = {}
length = testInstance.shape[1]
**if** dist_method == 'euclidean':
**for** x **in** range(len(dataset)):
dist_up = euclideanDistance(testInstance, dataset.iloc[x], length)
distances[x] = dist_up[0]
**elif** dist_method == 'normalized_euclidean':
**for** x **in** range(len(dataset)):
dist_up = normalizedEuclideanDistance(testInstance, dataset.iloc[x], length, dataset_mean, dataset_std)
distances[x] = dist_up[0]
**elif** dist_method == 'cosine':
**for** x **in** range(len(dataset)):
dist_up = cosineSimilarity(testInstance, dataset.iloc[x])
distances[x] = dist_up[0]
*# Sort values based on distance*
sort_distances = sorted(distances.items(), key=operator.itemgetter(1))
neighbors = []
*# Extracting nearest k neighbors*
**for** x **in** range(k):
neighbors.append(sort_distances[x][0])
*# Initializing counts for 'class' labels counts as 0*
counts = {"Iris-setosa" : 0, "Iris-versicolor" : 0, "Iris-virginica" : 0}
*# Computing the most frequent class*
**for** x **in** range(len(neighbors)):
response = dataset.iloc[neighbors[x]][-1]
**if** response **in** counts:
counts[response] += 1
**else**:
counts[response] = 1
*# Sorting the class in reverse order to get the most frequest class*
sort_counts = sorted(counts.items(), key=operator.itemgetter(1), reverse=**True**)
**return**(sort_counts[0][0])
第五步。
使用开发数据集,迭代所有开发数据实例,并计算每个 k 值和每个距离度量的类。
*# Creating a list of list of all columns except 'class' by iterating through the development set*
row_list = []
**for** index, rows **in** development_set.iterrows():
my_list =[rows.sepal_length, rows.sepal_width, rows.petal_length, rows.petal_width]
row_list.append([my_list])
*# k values for the number of neighbors that need to be considered*
k_n = [1, 3, 5, 7]
*# Distance metrics*
distance_methods = ['euclidean', 'normalized_euclidean', 'cosine']
*# Performing kNN on the development set by iterating all of the development set data points and for each k and each distance metric*
obs_k = {}
**for** dist_method **in** distance_methods:
development_set_obs_k = {}
**for** k **in** k_n:
development_set_obs = []
**for** i **in** range(len(row_list)):
development_set_obs.append(knn(development_set, pd.DataFrame(row_list[i]), k, dist_method, mean_development_set, std_development_set))
development_set_obs_k[k] = development_set_obs
*# Nested Dictionary containing the observed class for each k and each distance metric (obs_k of the form obs_k[dist_method][k])*
obs_k[dist_method] = development_set_obs_k
*#print(obs_k)*
计算开发集的准确性
*# Calculating the accuracy of the development set by comparing it with the development set 'class' list created earlier*
accuracy = {}
**for** key **in** obs_k.keys():
accuracy[key] = {}
**for** k_value **in** obs_k[key].keys():
*#print('k = ', key)*
count = 0
**for** i,j **in** zip(dev_class, obs_k[key][k_value]):
**if** i == j:
count = count + 1
**else**:
**pass**
accuracy[key][k_value] = count/(len(dev_class))
*# Storing the accuracy for each k and each distance metric into a dataframe*
df_res = pd.DataFrame({'k': k_n})
**for** key **in** accuracy.keys():
value = list(accuracy[key].values())
df_res[key] = value
print(df_res)

绘制条形图以比较超参数的性能。
*# Plotting a Bar Chart for accuracy*
draw = df_res.plot(x='k', y=['euclidean', 'normalized_euclidean', 'cosine'], kind="bar", colormap='YlGnBu')
draw.set(ylabel='Accuracy')

注意 :如果 k=1 的精度值为 100%,则忽略 k=1,因为这通常意味着过拟合。将其替换为 numpy.nan. 的值
df_res.loc[df_res['k'] == 1.0, ['euclidean', 'normalized_euclidean', 'cosine']] = np.nan
第六步。
找到最佳超参数。
*# In case the accuracy is the same for different k and different distance metric selecting the first of all the same*
column_val = [c **for** c **in** df_res.columns **if** **not** c.startswith('k')]
col_max = df_res[column_val].max().idxmax(1)
best_dist_method = col_max
row_max = df_res[col_max].argmax()
best_k = int(df_res.iloc[row_max]['k'])
**if** df_res.isnull().values.any():
print('**\n\n\n**Best k value is**\033**[1m', best_k, '**\033**[0mand best distance metric is**\033**[1m', best_dist_method, '**\033**[0m. Ignoring k=1 if the value of accuracy for k=1 is 100%, since this mostly implies overfitting')
**else**:
print('**\n\n\n**Best k value is**\033**[1m', best_k, '**\033**[0mand best distance metric is**\033**[1m', best_dist_method, '**\033**[0m.')

第七步。
使用测试集和最佳超参数来计算最终精度。
*# Creating a list of list of all columns except 'class' by iterating through the development set*
row_list_test = []
**for** index, rows **in** test_set.iterrows():
my_list =[rows.sepal_length, rows.sepal_width, rows.petal_length, rows.petal_width]
row_list_test.append([my_list])
test_set_obs = []
**for** i **in** range(len(row_list_test)):
test_set_obs.append(knn(test_set, pd.DataFrame(row_list_test[i]), best_k, best_dist_method, mean_test_set, std_test_set))
*#print(test_set_obs)*
count = 0
**for** i,j **in** zip(test_class, test_set_obs):
**if** i == j:
count = count + 1
**else**:
**pass**
accuracy_test = count/(len(test_class))
print('Final Accuracy of the Test dataset is ', accuracy_test)

使用余弦相似性作为距离度量并且 k 值为 5,实现了大约 97%的最终精度。这个模型给出了非常好的结果。
完整的代码可以在 GitHub 库中找到。
https://stack overflow . com/questions/18424228/Cosine-Similarity-between-2-number-lists
https://machine learning mastery . com/tutorial-to-implement-k-nearest-neighbors-in-python-from-scratch/
数据科学/大数据实验室——第 4 部分,共 4 部分:3 节点集群中的 Kafka 和 Zookeeper over Ubuntu
实验室数据
使用 Hadoop、Spark、Hive、Kafka、Zookeeper 和 PostgreSQL 在 Raspberry Pi 4 或 VMs 集群中组建数据科学/大数据实验室
这段文字可以用来支持在任何 Ubuntu 20.04 服务器集群中的安装,这就是设计良好的分层软件的妙处。此外,如果您有更多的节点,您可以随意分发软件。本文假设您知道 Linux 命令行,包括 ssh、vim 和 nano。
我不建议从少于三个树莓开始,因为你需要设置通信,并且 Zookeeper 和 Kafka 都需要奇数个节点。如果您尝试使用单个节点,可以使用本指南。尽管如此,性能可能会令人失望——对于单节点,我建议虚拟机具有合理数量的 RAM 和处理器。
由于篇幅原因,我不得不将教程分成四部分:
- 第一部分:简介、操作系统和联网
- 第二部分:Hadoop 与 Spark
- 第三部分:PostgreSQL 和 Hive
- 第四部分:卡夫卡、动物园管理员和结论
所有配置文件均可在【1】:获得
[## ptaranti/RaspberryPiCluster
Hadoop+Spark+Hive+Kafka+Postgresql raspberry 集群(ubuntu 20.04)的配置文件
github.com](https://github.com/ptaranti/RaspberryPiCluster)
免责声明 : 此文免费提供给大家使用,风险自担。我小心地引用了我所有的资料来源,但是如果你觉得遗漏了什么,请给我发个短信。由于不同的软件版本可能会因其依赖性而表现出不同的行为,我建议使用我在第一次尝试中使用的相同版本。

6.卡夫卡
Kafka(https://kafka.apache.org/)是一个健壮的消息代理,广泛用于实例化管道。它的保留功能可以处理激增的信息或让消费者离线进行维护的需求。
此外,与几乎所有大数据解决方案一样,Kafka 可以快速从单个节点升级到具有复制功能的完整集群。
学习卡夫卡的主要文献是《卡夫卡:权威指南》一书2。该电子书可在以下网址免费获得
什么是卡夫卡,它是如何工作的?在这本全面的电子书中,你会得到阿帕奇卡夫卡的全面介绍…
www.confluent.io](https://www.confluent.io/resources/kafka-the-definitive-guide/)
非常感谢合流!
卡夫卡一天可以轻松处理从千兆字节到甚至千兆字节的数据。这远远超出了我的实验室集群能力。然而,我决定安装 Kafka 最初作为一个单一的节点,然后分发它以允许使用数据管道,例如从 Tweeter 收集实时信息。
6.1 动物园管理员
第一步是安装 zookeeper 服务器,因为 Kafka 依赖它来分发元数据。我在以下站点安装了最新的稳定版本:
https://zookeeper.apache.org/releases.html
https://downloads . Apache . org/zookeeper/zookeeper-3 . 6 . 1/Apache-zookeeper-3 . 6 . 1 . tar . gz
pi@pi3:~/tmp$ wget [https://downloads.apache.org/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz](https://downloads.apache.org/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz)
pi@pi3:~/tmp$ tar -xzvf apache-zookeeper-3.6.1-bin.tar.gz
pi@pi3:~/tmp$ sudo mv apache-zookeeper-3.6.1-bin /opt/zookeeper
pi@pi3:~/tmp$ cd /opt/
pi@pi3:/opt$ ls
**hadoop hadoop_tmp hive zookeeper**
pi@pi3:/opt$ sudo chown -R pi:pi zookeeper
[sudo] password for pi:
pi@pi3:/opt$
pi@pi3: /opt$ sudo mkdir /opt/zookeeper_data
pi@pi3: /opt$ sudo chown -R pi:pi zookeeper_data
创建文件:
/opt/zookeeper/conf/zoo . conf
现在,您可以在单个节点中启动 zookeeper:
pi@pi3:/opt$ /opt/zookeeper/bin/zkServer.sh startZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
检查服务:
pi@pi3:/opt$ sudo netstat -plnt | grep 2181
tcp6 0 0 :::2181 :::* LISTEN 2511/java
现在我们在 pi3 上本地运行 zookeeper。接下来,我们将安装卡夫卡。
6.2 卡夫卡
卡夫卡安装成单个音符就没那么麻烦了。我按照书上的说明做了,但是把安装文件夹改为/opt,我的用户是 pi。
我下载了最新的稳定版本
卡夫卡 _ 2.13–2 . 5 . 0 . tgz:
Apache 软件基金会主页
www.apache.org](https://www.apache.org/dyn/closer.cgi?path=/kafka/2.5.0/kafka_2.13-2.5.0.tgz)
和往常一样,我把它保存在 /home/pi/tmp
以下命令用于提取文件、将其发送到/opt 并调整文件夹和访问权限:
pi@pi3:~/tmp$ tar -xzvf kafka_2.13-2.5.0.tgz
pi@pi3:~/tmp$ sudo mv kafka_2.13-2.5.0 /opt/kafka
pi@pi3:~/tmp$ cd /opt/
pi@pi3:/opt$ ls
hadoop hadoop_tmp hive kafka zookeeper zookeeper_data
pi@pi3:/opt$ sudo chown -R pi:pi kafkapi@pi3:/opt$ sudo mkdir /opt/kafka-data
pi@pi3:/opt$ sudo chown -R pi:pi /opt/kafka_data
编辑文件
/opt/Kafka/config/server . propertys,
c 悬挂以下参数:
log.dirs=/opt/kafka_data
开始卡夫卡:
pi@pi3:/opt$ /opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties
注意:如果你没有指明另一种方式,卡夫卡和动物园管理员需要一个开放的终端。启动这些服务时。最初为每个服务使用一个终端/远程会话。之后教程将展示如何以透明的方式做到这一点。
检查端口 9092:
pi@pi3:/opt$ sudo netstat -plnt | grep 9092
tcp6 0 0 :::9092 :::* LISTEN 3014/java
以下命令将允许您确保 Kafka 正常运行:
第一次启动动物园管理员:
pi@pi3:~$ /opt/zookeeper/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
现在,您可以启动 Kafka,用生产者和消费者创建一个 Kafka 主题并测试它:
pi@pi3:~$ /opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.propertiespi@pi3:~$ /opt/kafka/bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
Created topic test.pi@pi3:~$ /opt/kafka/bin/kafka-topics.sh --zookeeper localhost:2181 --describe --topic test
Topic: test PartitionCount: 1 ReplicationFactor: 1 Configs:
Topic: test Partition: 0 Leader: 0 Replicas: 0 Isr: 0pi@pi3:~$ /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
>message test 1
>message test 2pi@pi3:~$ /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
message test 1
message test 2
^C Processed a total of 2 messages
6.3 将 Zookeeper 和 Kafka 改为集群
注意:卡夫卡和动物园管理员都建议你有奇数个节点。我用了 3 个,没问题。
pi1
pi@pi1:~$ sudo mkdir /opt/zookeeper_data
pi@pi1:~$ sudo mkdir /opt/zookeeper
pi@pi1:~$ sudo mkdir /opt/kafka
pi@pi1:~$ sudo mkdir /opt/kafka_datapi@pi1:~$ sudo chown -R pi:pi /opt/zookeeper_data
pi@pi1:~$ sudo chown -R pi:pi /opt/zookeeper
pi@pi1:~$ sudo chown -R pi:pi /opt/kafka
pi@pi1:~$ sudo chown -R pi:pi /opt/kafka_data
pi2
pi@pi2:~$ sudo mkdir /opt/zookeeper_data
pi@pi2:~$ sudo mkdir /opt/zookeeper
pi@pi2:~$ sudo mkdir /opt/kafka
pi@pi2:~$ sudo mkdir /opt/kafka_datapi@pi2:~$ sudo chown -R pi:pi /opt/zookeeper_data
pi@pi2:~$ sudo chown -R pi:pi /opt/zookeeper
pi@pi2:~$ sudo chown -R pi:pi /opt/kafka
pi@pi2:~$ sudo chown -R pi:pi /opt/kafka_data
pi3
pi@pi3:/opt$ rsync -vaz /opt/zookeeper/ pi2:/opt/zookeeper/
pi@pi3:/opt$ rsync -vaz /opt/kafka/ pi2:/opt/kafka/
pi@pi3:/opt$ rsync -vaz /opt/zookeeper/ pi1:/opt/zookeeper/
pi@pi3:/opt$ rsync -vaz /opt/kafka/ pi1:/opt/kafka/
编辑删除以前的注释(pi1、pi2、pi3)
/opt/zookeeper/conf/zoo . conf
创建文件:
该文件应该只有 zookeeper 节点的 id(参见 GitHub)
pi1 ->1,
pi2 ->2,
pi3 ->3,
对于卡夫卡,我们需要编辑(在所有节点中):
/opt/Kafka/config/server . properties
更改参数:
**broker.id=1 # 2, 3 acoording to the node**
(1 用于 pi1,2 用于 pi2,3 用于 pi3
并且:
**zookeeper.connect= pi1:2181, pi2:2181, pi3:2181**
现在卡夫卡是动物园管理员将作为一个集群运行。您需要在所有节点中启动它。
6.3.1 监控您的 Kafka 集群
有一些监控 Kafka 集群的工具。我认为有一个完整环境的外观和感觉是很好的。
正文[3]:
[## Apache Kafka 集群的 UI 监控工具概述
阿帕奇卡夫卡最好的监控工具有哪些?
medium.com](https://medium.com/@giorgosmyrianthous/overview-of-ui-monitoring-tools-for-apache-kafka-clusters-9ca516c165bd)
概述一些可用的工具。卡夫卡本身没有这样的工具。
o 选择安装 Kafka 工具。个人使用是免费的,这是我的情况。Kafka 工具可以安装在 windows、mac 和 Linux 上。我选择将它安装在我的 windows 笔记本上,以减少我的覆盆子的工作量。
Kafka Tool 是一个 GUI 应用程序,用于管理和使用 Apache Kafka 集群。它提供了直观的用户界面,允许…
www.kafkatool.com](https://www.kafkatool.com/)
下面我展示了我与分布式节点的实际接口:

最后,下面的帖子提供了关于 Kafka 工具的额外信息[4]:
概观
medium.com](https://medium.com/enfuse-io/gui-for-apache-kafka-e52698b00c42)
7.启动集群
我为每个节点编写了一个脚本来启动所有服务——因为我有时会忘记启动特定的服务。您将在 pi 用户的主文件夹中找到名为 cluster-start.sh 的脚本。该脚本使用 ssh 连接来启动其他节点中的服务,我将它复制到我的所有节点中。
您可以使用 Hadoop、Yarn、Hive 和 Kafka 工具的 web UI 来检查集群状态。
我的最终架构如下图所示:

服务的分布如下表所示:

我还在笔记本上用了一个超过 VirtualBox 的 Ubuntu 虚拟机,有 RStudio,R,Anaconda,TensorFlow。
结论
我祝贺你完成了所有的安装。我知道解脱和快乐的感觉!😄
现在你有一个完整的环境来试验和训练!
我要感谢我引用的所有作者。
我授权任何人在引用出处之前复制本教程的部分内容。如果一个实质性的部分是必要的,请只链接它。
欢迎任何评论和问题!
1 P. G .塔兰蒂。https://github.com/ptaranti/RaspberryPiCluster
2 N. Narkhede 等人卡夫卡:权威指南:大规模实时数据和流处理。奥莱利媒体公司(2017 年)
[3] G. Myrianthous。Apache Kafka 集群 UI 监控工具概述 (2019)
[4]欧·格里戈里安。阿帕奇卡夫卡的图形用户界面 (2019)
Apache Kafka: Docker 容器和 Python 中的例子

罗斯·索科洛夫斯基在 Unsplash 上的照片
如何使用 Docker 安装 Kafka 并在 Python 中产生/消费消息
A pache Kafka 是一个流处理软件平台,最初由 LinkedIn 开发,2011 年初开源,目前由 Apache Software Foundation 开发。是用 Scala 和 Java 写的。
汇流流简介
卡夫卡的关键概念
Kafka 是一个分布式系统,由服务器和客户端组成。
- 一些服务器被称为代理,它们构成了存储层。其他服务器运行 Kafka Connect 以事件流的形式导入和导出数据,从而将 Kafka 与您现有的系统持续集成。
- 另一方面,客户端允许您创建读取、写入和处理事件流的应用程序。客户可以是生产者或消费者。生产者向 Kafka 写入(产生)事件,而消费者从 Kafka 读取并处理(消费)事件。
服务器和客户端通过高性能的 TCP 网络协议进行通信,并且完全解耦,互不可知。
但是什么是事件?在 Kafka 中,事件是一个有键、值和时间戳的对象。或者,它可以有其他元数据头。你可以把一个事件看作一个记录或一条信息。
一个或多个事件被组织在主题中:生产者可以编写不同主题的消息/事件,消费者可以选择读取和处理一个或多个主题的事件。在 Kafka 中,您可以配置一个主题的事件应该保留多长时间,因此,它们可以在需要时被读取,并且在消费后不会被删除。
消费者以自己的速度消费一个主题的事件流,并可以提交其位置(称为偏移)。当我们提交偏移量时,我们设置了一个指向消费者使用的最后一条记录的指针。
在服务器端,主题被划分和复制。
- 出于可扩展性原因,主题被分区。它的活动分散在不同的卡夫卡经纪人那里。这允许客户同时从/向许多代理读取/写入。
- 为了可用性和容错性,每个主题也可以被复制。这意味着不同数据中心的多个代理可能拥有相同数据的副本。
关于卡夫卡如何工作的详细解释,请查看其官网。
介绍够了!让我们看看如何安装 Kafka 来测试我们的示例 Python 脚本!
使用 Docker 安装 Kafka
作为数据科学家,我们通常会发现 Kafka 已经安装、配置好了,随时可以使用。为了完整起见,在本教程中,让我们看看如何安装一个 Kafka 实例进行测试。为此,我们将使用 Docker Compose 和 Git 。如果没有安装,请在您的系统上安装它们。

图片作者。卡夫卡 docker 知识库。
在您的工作目录中,打开一个终端并克隆 Apache Kafka 的 docker 映像的 GitHub 存储库。然后更改存储库文件夹中的当前目录。
git clone https://github.com/wurstmeister/kafka-docker.git
cd kafka-docker/
在 kafka-docker 中,创建一个名为docker-compose-expose . yml的文本文件,包含以下内容(您可以使用您最喜欢的文本编辑器):
version: '2'
services:
zookeeper:
image: wurstmeister/zookeeper:3.4.6
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
ports:
- "9092:9092"
expose:
- "9093"
environment:
KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9093,OUTSIDE://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
KAFKA_LISTENERS: INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092
KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_CREATE_TOPICS: "topic_test:1:1"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
现在,您已经准备好使用以下命令启动 Kafka 集群:
docker-compose -f docker-compose-expose.yml up
如果一切正常,你应该会看到动物园管理员和卡夫卡的日志。

图片作者。动物园管理员和卡夫卡的日志。
万一你想停下来,就跑吧
docker-compose stop
在 kafka-docker 文件夹中的一个单独的终端会话中。
关于 Kafka docker 的连通性的完整指南,请查看这是 wiki 。
Python 中的生产者和消费者
为了用 Python 为 Kafka 创建第一个生产者/消费者,我们需要安装 Python 客户机。
pip install kafka-python
然后,用下面的代码创建一个名为 producer.py 的 Python 文件。
from time import sleep
from json import dumps
from kafka import KafkaProducerproducer = KafkaProducer(
bootstrap_servers=['localhost:9092'],
value_serializer=lambda x: dumps(x).encode('utf-8')
)for j in range(9999):
print("Iteration", j)
data = {'counter': j}
producer.send('topic_test', value=data)
sleep(0.5)
在上面的代码块中:
- 我们已经创建了一个 KafkaProducer 对象,它连接到我们的本地 Kafka 实例;
- 我们已经定义了一种方法来序列化我们想要发送的数据,将它转换成 json 字符串,然后编码成 UTF-8;
- 我们每 0.5 秒发送一个事件,主题名为“topic _ test”,迭代的计数器作为数据。除了 couter,你可以发送任何东西。
现在我们准备启动生成器:
python producer.py
该脚本应该每半秒钟打印一次迭代次数。
[...]
Iteration 2219
Iteration 2220
Iteration 2221
Iteration 2222
[...]
让生产者终端会话保持运行,并在一个单独的名为 consumer.py 的 Python 文件中用下面几行代码定义我们的消费者。
from kafka import KafkaConsumer
from json import loads
from time import sleepconsumer = KafkaConsumer(
'topic_test',
bootstrap_servers=['localhost:9092'],
auto_offset_reset='earliest',
enable_auto_commit=True,
group_id='my-group-id',
value_deserializer=lambda x: loads(x.decode('utf-8'))
)for event in consumer:
event_data = event.value
# Do whatever you want
print(event_data)
sleep(2)
在上面的脚本中,我们定义了一个 KafkaConsumer,它联系服务器“localhost:9092”并订阅主题“topic_test”。由于在生产者脚本中消息是 jsonfied 和编码的,这里我们通过使用 value_deserializer 中的 lambda 函数对其进行解码。此外,
- auto_offset_reset 是设置 OffsetOutOfRange 错误时重置偏移量的策略的参数;如果我们设置了“最早”,那么它将移动到最早的可用消息,如果设置了“最新”,那么它将移动到最近的消息;
- enable_auto_commit 是一个布尔型参数,表示是否会在后台定期提交偏移量;
- group_id 是加入的消费群的名称。
在循环中,我们每 2 秒钟打印一次事件的内容。除了打印,我们可以执行任何任务,比如将它写入数据库或执行一些实时分析。
此时,如果我们跑
python consumer.py
我们应该收到类似于以下内容的输出:
{'counter': 0}
{'counter': 1}
{'counter': 2}
{'counter': 3}
{'counter': 4}
{'counter': 5}
{'counter': 6}
[...]
Python 生产者/消费者类参数的完整文档可以在这里找到。
现在你已经准备好用 Python 写卡夫卡了!
参考
- https://kafka.apache.org/
- https://github.com/wurstmeister/kafka-docker
- https://kafka-python.readthedocs.io/en/master/index.html
- https://medium . com/big-data-engineering/hello-Kafka-world-the-complete-guide-to-Kafka-with-docker-and-python-f788e 2588 CFC
- https://towardsdatascience . com/Kafka-python-explained-in-10-line of-code-800 E3 e 07 dad 1
卡夫卡,为了你的数据管道?为什么不呢?
使用 Docker、Kafka 和 Kafka Connect 创建流管道

我们在这个项目中所建造的
Kafka 于 2011 年由 LinkedIn 开发并开源,此后它迅速从消息队列发展成为一个成熟的流媒体平台,拥有丰富的生态系统。除了 LinkedIn 之外,许多科技公司,如 Airbnb、Spotify 或 Twitter,都将 Kafka 用于其关键任务应用程序。
Kafka 可以用于很多事情,从消息传递、web 活动跟踪到日志聚合或流处理。从我作为数据专业人士的角度来看,Kafka 可以用作数据流管道的核心组件,以支持实时用例,如欺诈检测、预测性维护或实时分析。
有整本书都是关于卡夫卡的,开始阅读可能会让人望而生畏。然而,在这个项目中,我将向您展示使用 Docker、Kafka 和 Kafka Connect 创建流数据管道是多么容易。
商业问题
让我们定义一些要努力解决的业务问题。
假设你是一名数据工程师,在一家不断有用户注册的电子商务网站工作。营销团队希望向每一位注册的客户发送一封个性化的电子邮件。新提出的功能有一些问题:
- 注册服务与电子邮件服务相结合。换句话说,每次市场需求发生变化,你都必须对注册服务做出改变,如果你不小心的话,这可能会导致整个事情的发生。
- 市场营销要求电子邮件应该在用户注册时立即发送。用工程术语来说,他们指的是从客户注册开始的 5 秒钟内。
- 个性化模型与您的注册服务托管在不同的网络上。
与客户数据相关的另一个业务问题是,您的 CEO 希望每个员工都知道当前的客户数量以及他们从哪里注册。她让管理团队在办公室中央安装几个大显示器,而您的团队必须创建一个将在这些显示器上显示的仪表板。
- 您当前的数据仓库每天只获取用户数据,因此您不能使用现有的批处理管道。
- 仪表板服务也在不同的网络上,因此您不能直接查询生产数据库。
在研究了几个选项后,您意识到使用 Kafka 和运行在 Docker 上的 Kafka Connect 似乎是解决您的问题的最佳选项。以下是你研究后的发现。
卡夫卡是什么?

Kafka 是一个用 Scala 和 Java 编写的开源流处理平台。根据 Kafka 网站的说法,流媒体平台有三个关键能力:
- 发布和订阅记录流,类似于消息队列或企业消息传递系统。
- 以容错的持久方式存储记录流。
- 在记录流出现时处理它们。
Kafka 通常用于构建对数据流做出反应的实时应用程序,或者可靠地在系统或应用程序之间获取数据的实时数据管道。在我们的用例中,我们需要将生产系统(Postgres DB)中的数据传输到 se 团队正在开发的一个单独的电子邮件服务(MySQL DB ),以及数据团队的数据湖 S3。
关于卡夫卡,这里有一些你应该熟悉的概念:
- Broker: Kafa broker 接收来自生产者的消息,并通过惟一偏移量存储它们。代理还允许消费者通过主题、分区和偏移量获取消息。
- 消息:是卡夫卡中的一个数据单位。您可以将每条消息视为数据库中的一条记录。
- 主题和分区:每个主题都是一个命名的消息流。一个主题由一个或多个分区组成。分区允许 Kafka 通过跨代理分发数据来进行水平扩展。
卡夫卡连线?

Kafka Connect ,Kafka 的一个开源组件,是一个将 Kafa 与数据库、键值存储、搜索索引、文件系统等外部系统连接起来的框架。以下是一些与 Kafka Connect 相关的概念:
- 连接器:连接器是一个逻辑作业,负责管理 Kafka 和其他系统之间的数据复制
- 源连接器:将数据从系统复制到 Kafka 的连接器
- 接收器连接器:将数据从一个或多个 Kafka 主题复制到系统的连接器
- 任务:每个连接器实例协调一组任务,将数据从一个系统复制到 Kafka,反之亦然
Docker 和 docker-compose?
Docker 是一种容器技术,它允许我们将一个应用程序打包成它需要的所有部分,比如库和依赖项。您可以使用 Docker 在本地计算机上快速有效地部署这些服务,而不必在本地计算机上安装 Kafka、Kafka Connect 和所有数据库。
Docker-compose 是一个高级命令,它允许您使用 YAML 配置文件,通过一个命令来部署 Docker 容器。
建筑
抛开所有术语,让我们来看看这个解决方案的架构。

我们解决方案的架构
对于我们的示例,我们将使用 Kafka connect 从本地生产数据库中捕获 Users 表中的更改,并写入 Kafka 主题。两个连接器将订阅上面的主题,并将任何更改写入我们的电子邮件服务的 MySQL 数据库以及我们的数据湖 S3。
有趣的部分
现在,这是有趣的部分!让我们开始吧。
克隆我的回购
首先,通过在您的终端上键入以下命令来克隆我的回购:
[g](https://github.com/tuanchris/kafka-pipeline)it clone [https://github.com/tuanchris/kafka-pipeline](https://github.com/tuanchris/kafka-pipeline)
cd kafka-pipeline
Kafka 最近越来越受欢迎,因为企业依赖它来驱动任务关键型应用程序和数据…
github.com](https://github.com/tuanchris/kafka-pipeline)
安装 Docker 和 docker-compose
我们将在这个项目中使用 Docker 和 docker-compose ,你可以快速查找如何为你的操作系统安装它们。
创造环境
假设您已经安装了conda,那么您可以创建一个新的 env 并通过运行以下命令来安装所需的包:
conda create -n kafka-pipeline python=3.7 -y
conda activate kafka-pipeline
pip install -r requirements.txt
我们将需要 PostgreSQL 来连接到我们的源数据库(Postgres)并生成流数据。在 Mac OS 上,您可以通过运行以下命令使用 Homebrew 安装 PostgreSQL:
brew install postgresql
pip install psycopg2
你可以谷歌一下如何为其他平台安装 PostgreSQL
启动生产数据库(Postgres)
我们使用 docker-compose 以最小的努力启动服务。您可以使用以下命令启动 Postgres 生产数据库:
docker-compose -f docker-compose-pg.yml up -d
您的 Postgres 数据库应该运行在端口 5432 上,您可以通过在终端上键入docker ps来检查容器的状态。
生成流数据
我写了一个简短的脚本来使用 Faker 库生成用户数据。该脚本将在我们的 Postgres 数据库中每秒生成一条记录,模拟一个生产数据库。您可以使用以下命令在单独的终端标签中运行脚本:
python generate_data.py
如果一切设置正确,您将看到如下输出:
Inserting data {'job': 'Physiotherapist', 'company': 'Miller LLC', 'ssn': '097-38-8791', 'residence': '421 Dustin Ramp Apt. 793\nPort Luis, AR 69680', 'username': 'terri24', 'name': 'Sarah Moran', 'sex': 'F', 'address': '906 Andrea Springs\nWest Tylerberg, ID 29968', 'mail': 'nsmith@hotmail.com', 'birthdate': datetime.date(1917, 6, 3), 'timestamp': datetime.datetime(2020, 6, 29, 11, 20, 20, 355755)}
据此,我们模拟了每秒钟都有新客户数据的生产数据库。很整洁,是吧?

您可以使用 SQL 客户机(如 DataGrip 或 DBeaver)连接到 Postgres 数据库,以双重检查数据是否正在写入 Users 表。连接字符串应该是jdbc:postgresql://TEST:password@postgres:5432/TEST
开始我们的卡夫卡经纪人
很好,现在我们已经有了一个运行着数据流的生产数据库,让我们开始模拟的主要组件。我们将运行以下服务:
- Kafka broker: Kafa broker 接收来自生产者的消息,并按唯一偏移量存储它们。代理还允许消费者通过主题、分区和偏移量获取消息。
- Zookeeper: Zookeeper 跟踪 Kafka 集群节点以及 Kafka 主题和分区的状态
- Schema registry: Schema registry 是一个获取和服务元数据(关于数据的数据)的层,比如数据类型、精度、小数位数…并提供不同服务之间的兼容性设置。
- Kafka Connect: Kafka Connect 是一个框架,用于连接 Kafka 与外部系统,如数据库、键值存储、搜索索引和文件系统。
- Kafdrop: Kafdrop 是一个开源的 web UI,用于查看 Kafka 主题和浏览消费群体。这将使检查和调试我们的消息更加容易。
我们可以通过运行以下命令来启动所有这些服务:
docker-compose -f docker-compose-kafka.yml up -d
等待几分钟,让 docker 下载图像并启动服务,然后您可以继续下一步。您可以使用以下命令查看上一个命令完成后的日志输出:
docker-compose -f docker-compose-kafka.yml logs -f
配置源连接器
接下来,我们将使用 Kafka connect rest API 配置我们的生产数据库(Postgres)的源连接器。将以下内容粘贴到您的终端:
curl -i -X PUT http://localhost:8083/connectors/SOURCE_POSTGRES/config \
-H "Content-Type: application/json" \
-d '{
"connector.class":"io.confluent.connect.jdbc.JdbcSourceConnector",
"connection.url":"jdbc:postgresql://postgres:5432/TEST",
"connection.user":"TEST",
"connection.password":"password",
"poll.interval.ms":"1000",
"mode":"incrementing",
"incrementing.column.name":"index",
"topic.prefix":"P_",
"table.whitelist":"USERS",
"validate.non.null":"false"
}'
当您看到HTTP/1.1 201 Created时,连接器已成功创建。这个命令的作用是向 Kafka Connect 实例发送一个包含我们的配置的 JSON 消息。我将在这里解释一些配置,但是您可以在这里参考配置的完整列表。
connector.class:我们使用 JDBC 源连接器连接到我们的生产数据库并提取数据。connection.url:我们源数据库的连接字符串。由于我们用的是 Docker 的内网,所以数据库地址是 Postgres。如果要连接到外部数据库,请用数据库的 IP 替换 Postgres。connection.user&connection.password:我们数据库的凭证。poll.interval.ms:轮询新数据的频率。我们每秒都在轮询。mode:轮询时更新每个表的模式。我们使用增量键(索引),但是我们也可以使用时间戳或批量更新来更新。topic.prefix:向卡夫卡写数据的题目前缀。table.whitelist:要在我们的数据库中查找的表名列表。您还可以设置一个query参数来使用自定义查询。
随着 Kafdrop 实例的运行,您可以打开浏览器并转到localhost:9000来查看我们的P_USERS主题。你可以进入主题,看看我们主题的一些示例消息。

就这样,你就有了流向卡夫卡的用户数据流。
创建 MySQL 接收器连接器
先从 Mysql 说起吧。通过运行以下命令启动 Mysql 数据库:
docker-compose -f docker-compose-mysql.yml up -d
这是我们的配置:
curl -i -X PUT http://localhost:8083/connectors/SINK_MYSQL/config \
-H "Content-Type: application/json" \
-d '{
"connector.class":"io.confluent.connect.jdbc.JdbcSinkConnector",
"tasks.max":1,
"topics":"P_USERS",
"insert.mode":"insert",
"connection.url":"jdbc:mysql://mysql:3306/TEST",
"connection.user":"TEST",
"connection.password":"password",
"auto.create":true
}'
就是这样。您生成的数据现在应该从 Postgres 流到 Mysql。让我们回顾一下 Mysql sink 连接器的属性:
insert.mode:如何将数据插入数据库。你可以在insert和upsert之间选择。topics:从中读取数据的主题connection.url:接收器连接 URLconnection.user&connection.password:汇凭证auto.create:不存在时自动创建表格
让我们查询 MySQL 数据库,看看我们的数据是否在那里。我们可以看到记录计数和最大时间戳都在更新!

通过查询 SQL 数据库,我们可以实时看到新的数据
创建 S3 水槽连接器
要将数据写入 S3,同样简单明了。您需要在docker-compose-kafka.yml文件中设置环境变量:AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY。之后,您可以使用以下配置创建 S3 连接器:
curl -i -X PUT -H "Accept:application/json" \
-H "Content-Type:application/json" http://localhost:8083/connectors/SINK_S3/config \
-d '
{
"connector.class": "io.confluent.connect.s3.S3SinkConnector",
"s3.region": "ap-southeast-1",
"s3.bucket.name": "bucket-name",
"topics": "P_USERS",
"flush.size": "5",
"timezone": "UTC",
"tasks.max": "1",
"value.converter.value.subject.name.strategy": "io.confluent.kafka.serializers.subject.RecordNameStrategy",
"locale": "US",
"format.class": "io.confluent.connect.s3.format.json.JsonFormat",
"partitioner.class": "io.confluent.connect.storage.partitioner.DefaultPartitioner",
"internal.value.converter": "org.apache.kafka.connect.json.JsonConverter",
"storage.class": "io.confluent.connect.s3.storage.S3Storage",
"rotate.schedule.interval.ms": "6000"
}'
一些值得注意的配置:
s3.region:你的 S3 桶的区域s3.bucket.name:写入数据的桶名topics:读取数据的主题format.class:数据格式。您可以从JSON、Avro和Parquet中选择
管道
瞧,你的管道现在完成了。通过几个 docker-compose 配置文件和连接器配置,您已经创建了一个支持近实时数据分析功能的流管道。相当强大的东西!
后续步骤
现在用户数据在 Kafka 和我们的水槽中。电子邮件服务可以实时获取客户数据,轮询推荐 API,并在 2 秒钟内向客户发送欢迎电子邮件。同样,利用数据湖中的数据,您可以为您的 CEO 创建一个实时仪表板。
但是您不必就此止步,因为 Kafka 及其组件是可横向扩展的。您可以使用 Kafka 为大部分(如果不是全部)管道供电。一些公司运行 Kafka 集群,拥有数千个生产者和订户。当然,在这样的规模下,除了简单的概念验证设置之外,还有更多工作要做。但是有一些托管的 Kafka 服务,你可以开箱即用,比如 AWS 上的 MSK,或者 Confluent(多平台)。您还可以添加更多组件来处理实时数据,如 Spark Streaming、KSQL、Beam 或 Flink。
打扫
如果您没有运行任何其他 docker 容器,您可以使用以下命令关闭这个项目的 docker 容器:
docker stop $(docker ps -aq)
或者,您可以通过运行以下命令来清理本地下载的 docker 映像:
docker system prune
结论
在这个项目中,我们使用 Docker、Kafka 和 Kafka Connect 构建了一个流数据管道,这让我们的营销团队和首席执行官非常高兴。有了我们构建的东西,其他团队可以很容易地从那里得到它,交付我们的涉众所要求的东西。
如果你以前从未使用过 Kafka,我鼓励你自己尝试这个项目。如果你有兴趣阅读类似的东西,neptune.ai 的人写了一篇关于如何用 Kedro 构建数据科学管道的优秀文章。
快乐学习:)
卡夫卡在行动:用 Python 和融合的卡夫卡构建分布式多视频处理管道
实时大规模数据处理和机器学习。

我们将会建造什么
介绍
试图通过建立一个项目来学习任何主题是一种有趣而直观的方式来加强我们的理解。在这篇文章中,我们将通过这样做来探索卡夫卡。
我们将会建造什么
想象一下这样一个场景,我们有多个来源生成视频流,我们需要近乎实时地处理和存储数据(如上图)。卡夫卡是这种情况下的完美契合。
先决条件
- 对卡夫卡有基本的了解会有所帮助,但是如果你觉得舒服,你可以随时随地探索和学习。
- 你需要在你的系统中安装 docker ,因为我们将使用它来运行应用程序,然而,安装软件包的二进制版本也可以。
我们开始吧
开始卡夫卡
我们将使用夏羽·马瑞克的惊人项目kafka-stack-docker-compose在 Docker 中运行 Kafka。首先,您需要克隆回购:
git clone [https://github.com/simplesteph/kafka-stack-docker-compose.git](https://github.com/simplesteph/kafka-stack-docker-compose.git)
然后,根据集群配置,您可以运行所需的 docker-compose 文件。在本文中,我们将保持简单,用一个 zookeeper 和一个 kafka 服务器运行一个集群。假设您已经启动了 Docker,运行:
cd kafka-stack-docker-compose
docker-compose -f zk-single-kafka-single.yml up
我们现在已经通过两个简单的步骤启动了 Kafka 集群!
正在启动 MongoDB
我们将使用 MongoDB 来存储处理后的数据。同样,我们将使用 Docker 来运行 MongoDB。首先,我们需要创建一个docker volume ,这个将帮助我们在磁盘中持久保存数据,即使我们停止并移除容器。要创建体积管路,请执行以下操作:
docker volume create data-mongodb
data-mongodb 是我们卷的名称。接下来,我们将启动 MongoDB 服务器实例,并在其上挂载data-mongodb卷。运行:
docker run -v data-mongodb:/data/db -p 27017:27017 --name mongodb -d mongo
这将自动提取 MongoDB 映像并启动容器。
好吧!现在我们已经有了 Kafka 和 MongoDB,让我们开始研究这个项目。
卡夫卡在行动
我们将要使用的代码可以在这个 repo 中找到。将 repo 克隆到工作区中。
git clone [https://github.com/wingedrasengan927/Distributed-Multi-Video-Streaming-and-Processing-with-Kafka.git](https://github.com/wingedrasengan927/Distributed-Multi-Video-Streaming-and-Processing-with-Kafka.git)
接下来安装必要的依赖项。最好为项目创建一个单独的虚拟环境,然后安装。
cd Distributed-Multi-Video-Streaming-and-Processing-with-Kafka
pip install -r requirements.txt
卡夫卡主题
我们要做的第一件事就是创造一个卡夫卡式的话题。要创建主题运行:
python create_topic.py
创建卡夫卡主题
这里我创建了一个名为multi-video-stream的主题,复制因子为 1 和 3 个分区。您可以试验复制因子和分区数量,但是要记住相应地更改Admin Client(第 6 行)中的服务器配置,还要注意副本的数量不能超过集群中服务器的数量。
卡夫卡制片人
Producer 应用程序从视频中读取帧,并将它们发布到 Kafka 主题。让我们浏览一下代码。
生产者应用
在开始时,我已经提到,我们将与多个来源产生视频流。我们需要一种在本地环境中模拟这种情况的方法。我们可以通过使用并发性并在一个线程中处理每个视频来做到这一点。
Kafka Producer 是线程安全的——我们可以创建单个 Producer 实例,并在多个线程间共享它。
在上面的代码中,我将所有的函数打包成一个类,当我们实例化这个类时,我们创建了一个 Kafka Producer。
方法publishFrame负责从视频中读取帧并将它们发布到卡夫卡主题。我们在这里使用opencv进行视频操作。在对 produce 方法的调用中,我们传递了以下参数:
- 主题:我们要将数据发送到的主题的名称。请记住,我们之前已经创建了主题。
- 值:这是实际的视频帧数据,被序列化为字节。
- on_delivery: 生产方法是异步的。它不会等待确认消息是否已经传递。我们传入一个回调函数,该函数记录关于所产生的消息或错误(如果有的话)的信息。回调作为调用
poll或flush方法的副作用被执行和发送。 - 时间戳:给出数据时间属性信息的值。注意,这里我传递的是帧数,而不是绝对时间,因为它更相关。
- headers: Headers 包含我们想要发布到主题的任何关联元数据。请注意,回调函数不会记录标头。
还要注意,我们每三帧发布一次,每一帧后等待一段时间。这是因为在现实世界中,我们以特定的 fps 从源获得帧,并且在每个连续帧之间没有太多的信息差异,尤其是在机器学习的背景下。这也有助于减少 Kafka 服务器上的负载。
start方法将每个视频映射到一个线程,并发运行应用程序。
要启动 Producer 应用程序,将您的视频放入video文件夹,在第 47 行相应地更改扩展名,然后运行:
python producer_app.py
这将同时开始向 Kafka 主题发布视频帧。您应该会看到关于所记录的生成消息的信息。
现在让我们看看另一面。
卡夫卡消费者
消费者应用程序订阅 Kafka 主题来接收数据。我们通过图像分类模型对数据进行推理,然后将结果存储到 MongoDB 数据库中。让我们浏览一下代码。
消费者应用
消费者在一个消费者群体中运作。组中的每个消费者从独占分区读取数据。如果一个组中的消费者数量超过了分区的数量,一些消费者将处于非活动状态。
在我们的消费者应用程序中,我们有多个属于同一个组的消费者同时从 Kafka 主题中读取数据。注意,与生产者不同,消费者不是线程安全的,每个线程需要有一个单独的消费者实例。
我们用run方法完成从接收数据到处理和存储数据的所有操作。首先,我们对来自主题的数据进行轮询,如果没有错误并且消息有效,我们将继续进行进一步的处理。
注意,消费者从主题中一次轮询一批消息,并将它们存储在内部缓冲区中,并从那里读取。
一旦我们收到消息,我们就对它进行解码,从中提取时间戳和元数据,并将其附加到一个数组中。
批量操作
如果你观察,我们不是一个接一个地处理消息,而是批量处理数据并对数据执行操作。这提高了效率和吞吐量。
一旦数据批次形成,我们就将其传递给图像分类模型,在我们的情况下,该模型是在 ImageNet 上训练的 ResNet50 模型。该模型每帧输出标签及其相应的置信度。我们只挑选最上面的标签和它的置信度并存储它。
接下来,我们将获得的结果插入 MongoDB 数据库。数据在数据库中的组织方式是,我们将每个视频作为一个集合,在每个集合中,我们都有包含该帧信息的记录或文档。该文档具有帧号、帧标签和置信度作为其字段,使得查询数据变得容易。此外,请注意,正如我们之前讨论的那样,我们正在向数据库中执行批量插入。
在这之后,我们完成了数据的处理,我们想把同样的事情告诉卡夫卡。Kafka 使用偏移量来跟踪消费者轮询的数据记录的位置,因此即使消费者倒下了,Kafka 也能够从它停止的地方读回来。我们希望如何提交偏移量以及遵循哪种交付语义由我们决定。这里,我们在数据处理完成后提交偏移量。这遵循了至少一次交货的语义。
注意:因为我们手动提交偏移量,所以在配置文件中我们必须将enable.auto.commit属性设置为False
注意:在至少一次交付语义中,如果消费者停止使用或处理出错,消息有可能被再次处理。为了避免重复的消息,我们必须维护幂等系统。例如,在我们的例子中,我们确保将一个惟一的文档插入到一个集合中,这样即使再次处理一个消息,数据库中也不会有任何重复。
好吧,让我们回到代码上。要运行消费者应用程序,请在第 108 行设置主题,在第 124 行更改视频名称(注意:这些名称必须与我们通过生产者发布的视频名称相匹配,并且这些名称也将是数据库中的集合名称),确保消费者的数量不超过第 128 行中的分区数量,然后运行:
python consumer_app.py
如果您同时启动生产者应用程序和消费者应用程序,它看起来会像这样并排:
左:制片人;右图:消费者
还可以可视化存储在 MongoDB 中的数据。 Robo3T 是一个很好的工具:

在 Robo3T 中可视化文档
在生产中部署
生产中的事情会变得更加复杂。幸运的是,我们在云平台上有托管服务,如谷歌云发布/订阅(T1)或 T2 亚马逊 kine sis(T3),这让我们的工作变得更容易。最好在生产中使用它们。
此外,在本文中,我们没有讨论生产者和消费者的配置,但是基于用例对它们进行调优是非常重要的。例如,在某些情况下,延迟可能是高优先级,我们可能不关心数据丢失或数据顺序,而在其他情况下,数据可能被赋予高优先级。需要相应地配置生产者和消费者。
对于生产中的机器学习,最佳实践是使用 Tensorflow 服务 API ,而不是在消费者应用中初始化模型。
此外,最好使用云中的托管数据库来存储数据。
结论
这让我们走到了尽头!Kafka 正在大量的项目中使用,并且还在继续增长。这一点非常重要。下面我提到了一些额外的资源,可以帮助你加深对卡夫卡的了解。
希望这篇文章是有帮助的。如果您有任何反馈或想与我取得联系,请在ms.neerajkrishna@gmail.com 给我留言。
在推特上连线吧!
额外资源
- 夏羽·马瑞克在《我的世界》上的精彩课程
- 汇合者拥有关于卡夫卡的惊人的文档和博客。
Kaggle 第一名得主作弊,10,000 美元奖金宣布不可收回
一个团队如何获得私人数据,构建一个假的人工智能模型,并从一个收养被忽视的宠物的平台上获得资金

骗子们从一个收养无家可归和被忽视的宠物的平台 Petfinder.my 上偷东西。像素图像
Kaggle 刚刚宣布第一名队伍 Bestpetting【1】,因作弊被取消 Petfinder.my 比赛资格。该团队爬上宠物收养网站收集私人排行榜答案,并将这些数据隐藏在他们的提交材料中,以赢得 2019 年 4 月 9 日的第一名。一等奖从 25,000 美元的奖金池中拿出 10,000 美元。在这篇文章中,你会发现 Kaggle 的背景,其竞争的黑暗面,以及相关资源的链接。
链接
什么是卡格尔比赛
Kaggle(谷歌的子公司)是一个围绕比赛建立的在线社区,旨在建立机器学习模型。该平台的奖金高达 150 万美元,吸引了形形色色的追随者。此类竞赛提供了一个数据集,以及将用于决定获奖作品的指标。竞争者分析给定的数据,构建模型以匹配期望的结果,并提交他们的结果(通常与他们的代码一起)。为了防止作弊,机器学习比赛包括没有标记的数据,并在两个阶段使用:
- 当比赛结束时,数据集的“私人”部分(竞争者仅拥有未标记的数据)用于选择获胜者。这些数据理想地代表了模型在从未见过的数据上的表现。
- 为了在比赛期间对参赛者进行排名,团队提交的内容将根据“排行榜”专用数据集的一部分进行评分。像“私人”测试数据一样,竞争对手也有这些数据,但没有标签。仅针对排行榜指标进行优化的团队往往会因为不适合数据集的“私有”部分而失败。
用私人数据作弊
这种竞赛形式的结果是,如果一个团队获得了私有测试数据集的真实答案,那么它就一定会赢。作弊团队制作的模型将是无效的,使比赛无效。
在这种情况下,作弊者将私人答案和提交的答案打包在一起。其他攻击可能更难检测。其中一种方法是使用完整的数据集优化超参数,创建一个似乎巧合地更有效的模型。也许作弊团队选择了一种更容易被发现的方法,因为他们根本没有能力创建一个值得登上排行榜的模型,或者他们太厚颜无耻了。
缓解这些问题的方法是将私有数据完全排除在竞争之外。提交的内容必须包括提供 API 来生成预测的代码。这也将防止竞争者知道特征在私人和排行榜数据中的分布。
卡格尔的黑暗面
Kaggle 竞赛有许多潜在的问题。我在一次检测信用卡欺诈的比赛中偶然发现了一个例子。一个流行的模型正在使用来自未来的信息进行训练,这将使它在实践中无法使用——银行没有水晶球。许多模型以产生更高分数的方式使用数据集,但是使模型对竞赛组织者无用。这些模特仍然可以赢得比赛,因为他们没有违反任何规则。

卡格尔模型中不切实际的一个例子
由于这些漏洞和潜在的无用结果,竞赛组织者必须格外警惕和小心他们的数据和规则。有些要求在多轮比赛中获胜,有些则在大量的顶级作品中平均分配奖金。
惯犯
这不是帕维尔第一次违背卡格尔比赛的宗旨,或者被指控作弊。看来卡格尔过去没有谴责和采取这些策略。

帕维尔·普莱斯科夫承认在另一场比赛中刮伤。

一个谴责 Kaggle 作弊的帖子,Pavel Pleskov 评论为“垃圾邮件”。
这些疑虑不仅仅被卡格尔忽略了,从卡格尔制作的采访中可以看出,帕维尔是一位著名的大师。

结果
除了被剥夺他的奖金并被禁止进入 Kaggle 平台,我还联系了帕维尔的雇主 H2O.ai,请他发表评论。这是英格丽·伯顿的回答:
今天早些时候,我们已经知道了这个情况。他不再隶属于 H2O.ai,立即生效。我们还将联系 Petfinder.my,看看我们如何帮助他们。
我没有找到关于费多尔·多布里扬斯基的进一步信息,他也被禁止进入 Kaggle。根据 Kaggle 的调查,他们选择不禁止 Narek Maloyan。
卡格尔更光明的未来
Kaggle 一直是推动机器学习成为可能的巨大力量。获奖的作品通常会展示最佳的工具和实践,并激发人们发明新的技术。尽管不切实际的模型和作弊伤害了竞赛组织者、Kaggle 品牌和整个生态系统,但好处和潜力远远大于坏处。
也许这是 Kaggle 新篇章的标志。如果他们想重建对平台及其社区失去的信任,他们还有很多事情要做。推动可重复、公平和有用的模型构建竞赛,正是机器学习所需要的。让我们希望我们得到它。

1最佳团队包括:帕维尔·普莱斯科夫、纳雷克·马洛扬和费多尔·多布里扬斯基。
编辑 2020–06–05—pet finder . my 于 2020–01–28 宣布 Bestpetting 团队发布道歉并返还被盗资金。
Kaggle 第三名解决方案— Jigsaw 多语言毒性评论分类
方法、知识和代码
我最近参加了 Kaggle 的拼图多语言毒性评论分类挑战赛,我们的团队(ACE 团队)在最终的排行榜上获得了第三名。在这篇博客中,我描述了问题陈述,我们的方法,以及我们从竞赛中学到的东西。我还在博客末尾提供了我们全部代码的链接。
问题描述
比赛的目标是检测在线互动期间用户评论中的毒性(例如粗鲁、不尊重或威胁)。这是一个非常现实的问题,因为最近社交媒体上的钓鱼和仇恨越来越多。
该问题被设置为一个普通的文本分类问题,其中人们必须预测(文本)评论有毒的概率,并根据 ROC AUC 指标对提交的内容进行评估
问题中最有趣的部分是——必须用 6 种不同的语言来识别毒性,其中 3 种语言根本没有训练数据,其余 3 种语言的训练数据也很少。
该比赛由谷歌公司 Jigsaw 组织,该公司开发工具来处理在线内容中的毒性、虚假信息、骚扰和激进化等问题。这是 Jigsaw 举办的第三次毒性检测竞赛(尽管是第一次多语言竞赛)。
为什么问题具有挑战性?
检测毒性不仅仅是检测文本中的辱骂性词语。作为一个例子,考虑下面的评论,它没有任何辱骂的话,但仍然是有毒的
我只想找点乐子,扫兴船长。我猜你年轻的时候从来没有生活过。那可能有 100000000000000000 岁了
除此之外,如果你试图解决跨多种语言的问题,它会变得相当棘手。
解决方案概述

上图高度概括了我们最终解决方案的各个组件,以及它们各自的得分(ROC)和权重,最终得分为 0.9523。
最终的解决方案是以各种方式训练的不同基础模型的混合。上图中的“罗伯塔”代表从罗伯塔·XLM 架构派生的模型,而单声道 Bert 代表根据特定语言的文本预先训练的 Bert 基础模型。
技术概述
下面的流程图提供了我们解决方案的高级技术概述。我将在接下来的部分分享各种细节

训练数据/预处理
我们在竞赛中使用以下数据集进行模型训练:
使用分层抽样从上述项目中准备列车数据,以确保等级平衡。
将标记的英文数据翻译成目标语言有助于缺少目标语言的标记数据,但不如目标语言本身的数据好,因为翻译过程去除了文本的一些微妙之处,而这些微妙之处有时对检测毒性很重要。
预训练模型
自 2018 年以来,基于 Transformer 架构的预训练(迁移学习)模型在 NLP 中非常流行。从概念上讲,它们是在大量(万亿字节)文本数据上训练的深度学习模型,因此它们学习语言(单词、文本)的非常好的数字表示。这些表示在各种下游任务中很有用。你可以在我的早期博客中阅读更多关于变形金刚和转移学习的细节
罗伯塔·XLM 是谷歌的伯特在架构方面的变体,预先接受了 100 多种语言的培训,是比赛中的主力。它的表现出人意料地好,甚至在其他语言上只有英语训练数据的情况下也表现不错。
除了上面描述的多语言模型,我们还使用了针对感兴趣的特定语言预先训练的 Bert 模型。正如人们所预料的那样,与多语言模型相比,这些单语模型对于它们被训练的单种语言表现得更好(对于给定的模型容量,每种语言的性能随着我们增加语言的数量而下降)。但是这种方法在实践中稍显逊色,因为如果处理大量语言,在生产中维护特定于语言的模型会很麻烦。
模特培训
这是很多艺术和经验发挥作用的地方。我们使用各种策略进行模型训练:
- 多阶段训练:在逐渐变难的任务上训练模型,在刚刚标记的英语数据上进行示例训练,然后逐渐移动到更难的任务,示例伪标签,然后在验证数据上进行最后一轮(时期)训练,因为这接近于测试数据
- 针对特定领域数据的无监督训练:【RoBERTa 等庞大的语言模型通常是在新闻、维基百科等通用数据集上训练的——这可能与你的特定任务数据的内容/结构/词汇有很大不同。虽然获得标记数据总是一个昂贵的提议,但通常有更大的未标记数据(在这种情况下只是原始文本数据)的可用性,这些数据可用于预训练。这有助于稍后进行特定任务监督训练时的表现
- 多重平均:将我之前描述的所有不同类型的数据集放在一起的训练样本数量达到了数百万。我们观察到,模型在训练期间很快饱和,并在大约 200,000 个样本后停止改善。我们使用数据的随机子集训练各种模型,并使用这些模型对测试数据集的预测进行平均
预测和混合/集成
众所周知,混合各种不同模型的预测往往优于潜在的单个模型预测,并且通常是改善最终预测的最佳方式。
如“解决方案概述”中所述,我们的最终解决方案融合了 4 个模型系列的预测。我们在每个家庭内训练了多倍模型(对不同数据子集的训练)最终得到大约 30(!!)奇款。
我们对每个系列内的多倍预测进行了直接平均,并对不同系列模型的预测进行了加权平均。我们没有真正的质量数据集,底层模型看不到,来提供整个家庭的权重,所以我们使用一些直觉,领导委员会的反馈和实验来确定这些权重。
测试时间增强(TTA)是一种技术,在这种技术中,我们不仅对测试示例进行预测,还对它的一些变体进行预测,以获得更好的最终预测。我们在一些底层模型中采用了这种技术,它给了我们一个小小的提升,下面是它的工作原理:
- 对测试数据集中的原始注释进行预测
- 对原始评论的各种语言翻译进行预测
- 对原始评论及其翻译的预测进行加权平均
五金器具
深度学习模型在 GPU 上运行比在 CPU 上运行快得多已经不是什么秘密,但是谷歌的 TPU 甚至比 GPU 还要快。它们在内存(允许更大的批量)和速度(允许快速实验)方面都是非凡的,并使训练过程不那么痛苦。
我们在比赛期间广泛使用了 Kaggle 和 Google Colab 提供的免费 TPU 配额来训练我们的模型。
密码
这是到我们完整代码的链接
ka ggle/学术与现实世界数据科学分析
(初学者 40 分钟阅读。文末免费指导链接)
“被《哈佛商业评论》、IBM 等公司的报告所吸引,我将职业生涯转向了数据科学。我已经完成了数据科学的整个在线专业。我擅长 Python。我已经建立了像……这样的机器学习模型。…在我的 Kaggle 项目中。我非常擅长构建 ML 模型。尽管数据科学有很多机会,但我仍然发现很难找到第一份工作。为什么招聘人员对雇佣有相关实习/工作经验的数据科学家更感兴趣?”
如果这些是你问自己的问题,你今天来对地方了。现实世界中的数据科学与技术课程和学术项目所教授的完全不同。这是唯一的原因,也是为什么招聘人员希望你在招聘前在个人资料中加入过去的数据科学实习/经验。拥有强大的数据科学技术背景总是有帮助的,但现实世界的经验更是锦上添花。

时代广场:纽约市(演员表:Self)
在本文中,我们将使用一个非常常见的客户流失(客户保留)建模分析问题来理解学术项目和现实项目之间的差异。如果你擅长讲故事,你或许可以在简历中展示一个学术项目,作为一个真实世界的行业赞助项目,并在下一次面试中显得更有前途。

图一
分析流程:(针对客户流失预测数据科学项目)
1)定义问题:
卡格尔:
阅读客户流失的问题陈述。浏览各列以了解数据。跳入数据中。
现实世界:
管理层的问题陈述非常含糊。我们必须最后确定我们正在处理的到底是什么问题。在项目的后期过程中,问题陈述不能改变。
首先,我们需要定义客户流失。流失可能是永久流失,也可能是临时流失(其中客户会在一定时间后返回),具体取决于领域。
流媒体服务提供商(如网飞)有暂时的流失现象。我们需要定义一个停用天数的阈值,称之为流失。比如说 D+15,D+30(D+X =停用后的天数)。这个定义需要大量的头脑风暴、领域知识以及最终管理层的批准。
在暂时搅动问题中,可能发生订户搅动多次的情况。而在永久性流失问题中,客户永远不会回来。暂时的和永久的流失有不同的方法。
任何流失项目的问题陈述将是识别高风险流失客户并试图留住他们。
2)检查可行性。例如,所需数据和其他资源的可用性:
卡格尔:
必须足够可行,才能上传到这个平台上。所有的数据集都是可用的。不需要外部数据,没有外部数据可能会使问题变得不可行。
真实世界:
解决这个问题可行吗?我们是否拥有所需的数据和资源?有可能实现吗?
我们能想到一些可能导致客户流失的因素吗,包括客户人口统计、客户产品特征、外部变量?这些因素的数据可以利用吗?
如果模型准备好了,有可能实现吗?(可能不总是)。
实施的成本是多少?我们真的获利了吗?
例如,对于贷款流失(余额转移)的银行领域问题,即使我们使用机器学习获得了高风险客户,因为所有贷款条款都是固定的,所以你无法为客户提供任何东西来留住他/她。即使利率是可变的,并且联系客户告知他们有资格获得更低的利率,所有的误报都会导致银行的巨大损失。因此,在这种情况下,做客户流失建模可能没有意义。
3)估算 ROI,预期收益:
卡格尔:
不需要。没问过。
现实世界:
解决这个问题值得吗?
对于像流失这样的预测建模项目,关联每个真阳性、真阴性的近似收益和每个假阳性和假阴性的损失,我们可以估计 ROI。它包含了执行项目、实施项目等的所有费用。如果投资回报率更低,这个项目就没有意义。
4)问题分类:描述性/预测性/规定性:预测性
【Kaggle 和现实世界:
由于我们预测客户流失的可能性,这是一个预测分析项目。如果问题是确定哪种产品的流失率最高,那么它就是一个描述性分析项目,如果问题是找到流失率最低的最佳销售价格,那么它就是一个说明性分析项目。为了能够选择必要的工具和资源,将问题分类到合适的箱中是很重要的。
4.2)预测:
让我们直接讨论预测分析,因为我们正在处理客户流失建模。
a)再检查一下,简单的特征分析是否能让你找到高危人群?
卡格尔:
这不是我们被要求提交的。
现实世界:
用目标变量客户流失对每个变量进行二元可视化,我们可以知道每个变量对客户流失的影响。使用一些重要的变量,我们可以获得高风险的概况/特征,并使用简单的 SQL 查询找到它们的提升。例如,年龄在 30-35 岁之间、居住在纽约市、年份为 3 年的客户流失的可能性是其他客户的 2.6 倍。找到一些高风险的特征并只针对它们,可以节省我们在机器学习上投入的时间和资源。在进入机器学习之前,我们需要比较这两种方法的投资回报率。
b)决定分析单位、目标变量和要包含的行
卡格尔:
每行的主键是分析单位。我们希望找到每一行的预测。目标变量列已经可用。因此,分析单位和目标变量都被设置为包括在模型库中。
真实世界:
让我们讨论一下流媒体服务公司(比如网飞)的临时流失问题。
我们必须问一个问题,我们到底在预测什么?这并不像看起来那么简单。我们只是预测客户流失的可能性吗?令人惊讶的不是。概率随着时间而变化。客户 A 在 2020 年 1 月流失的概率可能不同于 2019 年 10 月。我们预测客户在特定的时间流失的概率。我们希望找到导致客户流失的高风险特征,而不是导致客户流失的高风险客户。因此,模型库中的一行将对应于某一时刻的客户简档。如果我们以月为单位考虑时间,则对于同一客户,模型库将有“n”个条目/行,其中“n”是客户的年份(以月为单位的网络年龄)。因此,
分析单位= {客户,时间(月)}
目标变量的定义应该与第 1 部分的问题陈述中的定义完全相同。假设我们定义了:失活+15 天作为目标变量(流失)

表 1:理解分析单元
在这种情况下,模型库中的行不应该只表示最新的客户数据,还应该表示与时间(这里是月)相关的客户数据。
我们举个例子。
我在 2018 年 1 月加入了流媒体订阅。充值日期为每月 1 日(假设不是自动充值)。
如果我在 1 日之前没有充值,我将从 2 日起被取消激活。如果我在那个月的 15 号之前没有充值,我会被认为在那个月被“搅了”。
因此,目标变量也可以定义为,
一个月内搅动=“停用至一个月的 15 日”

表 2:每月 2 日的我的数据和每月最后一天的目标变量
比如,我在 2019 年 1 月搅拌,2019 年 3 月返回,2019 年 5 月再次搅拌,2019 年 8 月返回。如果我停用(4 月 1 日不充值),2020 年 4 月我会流失的概率有多大?
这是我的数据行在模型库中的样子。它由我每月的数据组成。同样,所有客户都有历史数据。因此,我们预测的是客户在特定时间流失的可能性。
仅选择相关的观察结果:
在选择要包含在模型库中的观测值之前,我们应该考虑一下模型部署。比方说,该公司正计划给高风险客户打电话,向他们提供折扣以留住他们。他们也想给活跃客户打电话吗?没道理。他们只想给在月 1 日没有充值的客户打电话,这些客户目前已经停用,以防止他们在 D+15(流失)后再次充值。话虽如此,我们只想找到一个去激活的客户流失的概率,而不是活跃的客户。这使得我们从模型库中排除了在当月 1 日进行充值的那些月份的客户资料(客户一直处于活动状态),仅考虑停用情况。(这是使用“第一次充电”变量确定的)

表 3:样本客户(me)在模型库中的最终行
c)手动进行特征工程,创建新特征,修改现有特征
卡格尔:
除了要素编码之外,从现有要素创建新要素、修改现有要素的范围较小。
现实世界:
现实世界的问题完全依赖于特征工程。没有填鸭式的特征。我们必须从多个来源获取数据,将其转换为可用的形式,并从中创建新的功能以包含在模型库中。这需要大量使用数据操作、连接。等等。与 Python/R 相比,NoSQL SQL 更适合执行此任务。在流媒体服务的流失预测问题中,我们可以创建如下变量:

表 4:变量和来源
我们必须有创造性。这与其说是科学,不如说是艺术。我们必须了解这个领域,以便能够创建新的变量。
我们也可以将多个变量组合成一个新的变量。或者修改现有变量以增加其预测能力。
d)探索性数据分析
卡格尔:
几个图来理解 Python/R 上的数据,查看分布。等等。没有演示要点,专注于更好地调整模型。
现实世界:
管理层想要一个带有切片器的仪表板,显示所有的变量关系。他们不会相信你给他们展示了多少形象化的东西。每次都会请求许多特别报告。交流结果是这项工作的重要组成部分,如果没有充分的探索性数据分析和数据挖掘,这是不可能的。一般来说,像 Excel,Tableau,PowerBI 等工具。在 EDA 行业中使用。
e)去除多重共线性,进行特征选择:
【Kaggle 和现实世界:
两者都涉及平等的工作。
f)尝试不同的 ML/DL 算法,在验证和测试数据上评估模型:
卡格尔:
尝试很多算法。做超参数调整。使用最复杂的算法。切换到 DL。你所要做的就是尽量减少误差。注重准确性!!超越记分牌。
现实世界:
准确很重要,但钱更重要。努力使投资回报最大化(后面会讲到)。建立一个能带来更多利润的模型。管理层不会理解和批准暗箱操作。使用简单的可解释算法,如逻辑回归、分类、树、正则化等。避免深度学习。
ghij)模型部署和实施、自动化、跟踪和更新:
卡格尔:
项目结束了。只需上传结果。专注于记分牌。
现实世界:
如果模型没有正确实现,预测就没有用。制定模型部署策略需要大量的头脑风暴和领域专业知识。要联系多少人?怎么联系?联系谁?什么时候联系?预期收益是否超过实施成本?
让我们以银行贷款的客户流失模型为例。机器学习给我们每个客户下个月流失(余额转移)的概率。
要联系多少人口?
针对多少高风险客户?我们需要设置一个增益最大的概率阈值。

要设置一个概率阈值,我们必须考虑与 TP、FP、TN、FN 相关的成本停在收益最大的概率。
回报=每个 TP 和 TN 的预期利润-每个 FP 和 FN 的预期损失
如何联系?
交流方式。用什么来留住他们?较低的利率,或任何其他好处。
联系谁?
我们是否只考虑流失概率来确定目标人群?我们还必须包括这种变动带来的财务损失。客户流失的可能性很低,但如果流失,损失会很大,必须联系他。
什么时候联系?
EMI 付款日期前几天?紧接着?或者任何时候。
预期收益是否超过实施成本?
如果向高风险客户提供较低的利率来留住他们,假阳性将会给银行造成巨大损失。我们还有足够的利润吗?如果没有,一切都是徒劳。
在所有这些都完成之后,在需要的时候,自动化模型来对新数据进行评分。这是通过使用一组在云上定期运行的 python 脚本来生产模型代码来实现的。通常,每个月都会对客户进行评分。一个月后,我们需要跟踪模型性能,计算我们为公司节省了多少。可以使用各种方法,如测试和控制、A/B 测试来跟踪实际新数据的模型性能。实施部分似乎比预测建模部分更具挑战性。如果模型的性能开始每月逐渐下降,这可能是因为自变量和因变量之间的关系随时间而变化。这个模型需要翻新。在高度动态的情况下,模型经常需要翻新。
希望你能感受到现实世界中的事情有多复杂。
注意:本文无意批评学术课程或 Kaggle 平台。
感谢读者的耐心。
参考:
自己
注意:我正在完成数据科学的硕士学位,想在美国找一份数据科学分析的全职工作。感谢任何线索。
【https://www.linkedin.com/in/kashyap-bhuva/ 号
kbvbhuva@gmail.com
Kaggle 基础知识:我的第一个数据科学挑战演练
初学者的 Kickstarter 包!

罗纳尔多·德·奥利维拉在 Unsplash 上的照片
新冠肺炎·疫情的爆发迫使全世界都不得不改变他们的生活方式,整天呆在室内。有了从通勤和郊游中节省下来的所有额外时间,我决定去追求一些我以前不可能去做的事情。其中一个是卡格尔。
在我之前的所有项目中,我都做过视觉数据集,所以想尝试一些不同的东西。我想了解完整的流程,从数据清理开始,到各种转换,到特征选择,最后是机器学习建模。为了做到这一点,我拿起了一个带有大量数据集的初级挑战: 房价:高级回归技术 。我设定了低于 1k 的目标(~前 20%)。
正如预期的那样,我 90%的时间花在了数据清理和特征工程上,剩下的 10%花在了将机器学习模型应用于这些方面。我明白了“了解你的数据”有多重要。在没有任何数据工程的情况下,盲目地把它喂给 SOTA 模型只会让你走得更远。我不得不阅读许多博客和 Kaggle 笔记本,但我虔诚地遵循的是 [this](https://www.kaggle.com/agodwinp/stacking-house-prices-walkthrough-to-top-5) 。在这一篇中,我将用非常简单的词语和例子来概述我所遵循的过程,以便像我这样的初学者可以知道从哪里开始。
作为参考,这是我的笔记本,里面有完整的代码,这样你就可以跟着解释走了
数据清理和特征工程:https://github . com/Shikhargupta/ka ggle _ house _ pricing/blob/master/Feat _ engg . ipynb
特征重要性和建模:https://github . com/Shikhargupta/ka ggle _ house _ pricing/blob/master/ensemble . ipynb
埃姆斯住宅数据集

在 Unsplash 上由 Breno Assis 拍照
在进入这个过程之前,让我们先了解一下正在讨论的数据集。它有 80 列(特征),每一列描述房子的一个特定方面(例如,邻居、公用设施、屋顶类型等)。)在决定其价格(目标变量)时可能起作用,也可能不起作用。它由总共 2920 个观察值组成,其中 1460 个将用于拟合(训练数据),其余的用于确定你的模型执行得有多好(测试数据)。我们的目标是通过考虑特征(可能不是全部)来尽可能准确地预测房屋的销售价格。我建议你通过数据描述来习惯每个字段的含义。评估的标准是预测值的对数和观察销售价格的对数之间的 均方根误差(RMSE) 。分数越低,你的模型预测越好!
数据清理(异常值和 NAN)

首先,我们将清理数据集,以避免在将它输入到模型中时出现任何错误或差异。
永远记住,最终目标是训练我们的机器学习模型,数据应该以同样的方式准备。请注意我们执行的任何操作最终可能会提高或降低回归器/分类器的效率。
例如,一个 NAN 字段的出现可能会使训练例程抛出一个错误。我们预测的另一个杀手可能是一个 离群值 。我们的住房数据是手工收集和存储的,很容易出现人为错误。一个明显的大(20 间卧室)或小(10 平方。制成 LotArea)的观察可能会使我们的模型向错误的方向摇摆,从而影响我们的分数。我们要么需要去掉这些数据点,要么适当地估算这些值。
就 Ames Housing 数据集而言,我们在离群值方面做得很好。作者已经在论文中指出了可疑的异常值,我已经在这个图中显示出来了

带有 GrLivArea > 4000 的数据点是异常高销售价格和 LivArea 的异常值,应被删除。虽然没有提到其他任何东西,但我发现“GarageYr”这一特征有一处不一致,它描述了车库在房子中建造的年份。这个值是 2027 ,这是一个遥远的未来。我没有摆脱观察,而是把它归因于模式。在此之前,我通过检查“GarageType”属性来确保房子有车库。在做出任何改变之前,了解你的数据是很重要的,所以要注意这些微小但重要的方面。
对于南,我绘制了一个图表,显示了至少具有其中一个特征的所有特征。然后我逐一分析它们,并决定如何处理丢失的值。他们中的大多数都被那个特征的模式所取代,但是也有一些特殊的情况,就像这样-
在没有地下室的情况下,我们可以将地下室平方英尺的缺失值估算为 0
特征工程

照片由 Isaac Smith 在 Unsplash 上拍摄
这无疑是这个过程中最重要也是最耗时的部分。我的方法是一次拿一个。)并应用变换。这听起来可能很麻烦,但是请相信我,这将大有帮助。我的方法是用不同的图表将形象化(seaborn 给了你漂亮的图表!)并以此为基础做出我的决定(放弃或保留它们以及任何更改)。这将是运用你分析能力的好时机。这里没有火箭科学,数据集非常直观(卧室数量越多,价格越高)且符合逻辑。我将用几个大类的例子来解释我所做的。
多项式
如果你计划回归一个巨大的数据集,线性不应该是唯一的方法。某些特征可能与目标变量有某种关系,这种关系不能用单一程度来表示。因此,我精心挑选了 10 个最相关的变量(从相关矩阵中),创建了它们的平方、立方和平方根版本,并将其添加到数据集。
连续特征
这些是像 LotArea、GarageArea、1stFlrSF 等具有连续值的。对于这类特性,我的策略是用销售价格(我们的目标变量)绘制它们的分布图和散点图。这是“空地”的一个片段

左图:分布图;右图:销售价格散点图
散点图显示,地段面积对销售价格的影响可能不太显著,但它确实存在,我们会保留它。左图显示了这种特征分布的正偏斜程度。永远记住,分布越接近正态,你的预测模型表现得越好。所以,总是尝试转换你的数据,使其更正常-y. 通常用来这样做的技术是——对数转换和宁滨。我要在这里找根木头。
一些特征可能看起来是连续的,但是当转换成分类的时候会更适合。例如,与年份相关的特征(房屋建造的年份、房屋改造的年份等。).此外,其他不可或缺的功能,如卧室的数量,游泳池的数量,车库可以容纳的汽车。如果转换成绝对的,它们都会更有意义,我也是这样做的。
分类特征
所有非连续变量都是分类变量。我在这里遵循的做法是使用带状图和每个类别的平均销售价格来可视化特征。让我们以加热质量控制(加热质量)为例:

左:Stripplot 右:平均
第一个让我看到每个类别中房屋的数量,并指出任何差异(我们将在后面看到如何做到)。第二个帮助我决定是否将它作为一个有序的特征(用一个整数替换每个类别)或者创建虚拟变量。这个例子很明显是有序的(例如最高的评级和最高的平均价格等等),所以我们将用有序的整数来代替它们。 箱线图 也是可视化数据的有效方法。
掉落(无用)特性
我们希望保持我们的特征空间尽可能密集,以从我们的模型中获得最大的效率。因此,我们试图去掉那些我们认为对目标变量贡献不够大的特征。我遇到了一些,这里有一些例子。

街道:通往物业的道路类型
带状图显示,大多数房屋的街道类型为“ Pave ”,而“ Grvl 的数量可以忽略不计。这一特征在所有房价中几乎保持不变,因此对目标贡献不大。我们可以放弃这个功能。

公摊面积:公摊面积平方英尺
类似地,对于 PoolArea ,大多数观察值为 0(几乎所有的房子都没有游泳池),因此在预测中对我们没有太大帮助。我们可以放弃。
特征重要性
即使在对所有特征进行了广泛的分析之后,一些多余的特征也可能会被肉眼所忽略。我们将使用 XGBoost 内置的 feature importance 函数来进一步识别无关紧要的列,并在拟合我们的模型之前删除它们。让我们首先获得转换后所有 324 个特性的索引。

与销售价格相关的功能的重要性。相当一部分是零。
我们可以看到,我们的许多功能对确定销售价格没有贡献,因此我们将删除它们。删除得分为 0 的特性后,我们的数据集从 324 列减少到 218 列!
机器学习建模

奥马尔·弗洛雷斯在 Unsplash 上拍摄的照片
最后,我们开始这一切的部分。坦率地说,我们 90%的工作已经完成。如果你有一个结构良好的密集数据集,建模将是一件轻而易举的事。我准备了一个最著名的回归模型的列表,我想用这些模型来拟合我的数据(在本节的后面列出)。然后,我将测试数据分成测试集和验证集。我在测试集上训练模型,并对验证进行评估。这有助于我直观地看到哪个型号的性能更好。这里是 XGBoost 回归器的一个例子。
如果你注意到,我对销售价格进行了对数变换,因为它给出了更好的分布。在得到结果的同时,我通过取值的指数将价格转换回原来的比例。
参数调谐
每个回归模型都有自己的一组参数,这些参数对它所依据的数据集高度敏感。如果你想要高度优化的结果(你做到了!),那么必须有一组性能最佳的参数。传统的方法是使用 GridSearchCV 进行网格搜索,但这需要相当大的计算能力。如果你无法访问 GPU,最好避免使用它(我的 MacBookPro 花了 7 个多小时进行 XGBoost,仍然可以完成搜索)。另一种方法是做一个“参数扫描,其中我们通过改变一个参数来评估我们的训练,而保持其他参数不变。这要求人们对可能适合我们正在扫描的参数的值的范围有一个公平的想法。下面是一个为 RidgeRegressor 求α的例子。

alpha~75 给出了最低的 RMSE,并且是该数据集的最佳可能值
合奏
所以到目前为止,我们有来自个体回归模型的分数。但是,如果我们可以权衡所有模型的预测,并得到一个综合结果,这不是更好吗?每个型号都有自己的特色。有些人更擅长从数据中提取某些信息,有些人更容易受到其他信息的影响。如果我们“咨询”各种模型,然后得出最终预测,那就更好了。这被称为组装。在这种情况下,我们通过训练数据训练我们的所有模型,并在预测时合并结果。这种组合可以是任何值—所有值的平均值、加权平均值等。我使用了加权平均值选项,并根据各个模型在验证集上的表现来决定权重。这是代码。
结论
虽然在表面上试验不同的模型可能会给你好的结果,但重要的是要理解背后的数学,以便将来你可以通过推理选择回归变量。此外,我的方法肯定不是解决房价问题的最佳方法,你可以设计你自己的方法,所以,继续努力吧!
Kaggle 发布了 CORD-19——新冠肺炎上的人工智能挑战

图片来自 Pixabay 的 Vektor Kunst
找出人工智能在这场国际危机中可以帮助解决的关键任务。
由新型冠状病毒(即新型冠状病毒)引起的冠状病毒疾病 2019,通常缩写为新冠肺炎,在过去 3 个月里已经成为疫情,蔓延到国际上超过 100 个地方,包括许多欧洲国家和美国。截至今天(2020 年 3 月 17 日),美国有超过 4000 例病例和 75 例死亡,预计这些数字在接下来的一周左右会上升,使这种呼吸系统疾病的预防和治疗成为国家层面的首要任务。
为了帮助解决这个问题,来自领先人工智能研究所的研究人员和领导者,包括艾伦人工智能研究所和微软,以及联邦政府机构(即国家医学图书馆)进行了广泛的合作,结果发布了关于新冠肺炎、新型冠状病毒和其他种类冠状病毒的学术文献的新冠肺炎开放研究数据集(CORD-19)。

CORD-19 数据组件的主要合作者
Kaggle & CORD-19
这个数据集可以在 Kaggle 的网站上找到,任何人工智能研究人员都可以通过下面的链接公开访问。人工智能领域的研究人员不会对 Kaggle 感到陌生——这是一个由数据科学家和机器学习研究人员组成的在线社区。
AI2 大学、CZI 大学、MSR 大学、乔治城大学、美国国家卫生研究院和白宫的人工智能挑战
www.kaggle.com](https://www.kaggle.com/allen-institute-for-ai/CORD-19-research-challenge)
作为谷歌公司的一部分,Kaggle 因组织各种机器学习和数据科学挑战而闻名,包括当前的一项——新冠肺炎开放研究数据集挑战,或简称为 CORD-19 挑战。
CORD-19 数据集包含超过 29,000 篇文章,其中 13,000 篇有全文。所有这些文章都与冠状病毒的研究有关,如病例报告、传播途径、环境因素和治疗策略探索。然而,并非所有这些文章都不是机器可读的,因此很难利用人工智能工具来提取有用的信息,以帮助我们抗击这种传染病。
幸运的是,艾伦人工智能研究所的研究人员努力工作,帮助人工智能研究人员将这一庞大文献的内容转化为机器可读的形式,这使得使用机器学习方法进行数据和文本挖掘成为可能。
关键科学问题
美国 NASEM 和世卫组织的新兴传染病和 21 世纪健康威胁常设委员会确定了应对这场国际危机至关重要的 10 个科学问题。
这些问题包括研究病毒的传播和潜伏,感染新冠肺炎的风险因素,病毒的起源,以及治疗这种疾病的正确医疗方法。
挑战任务的完整列表可以在 Kaggle 的网站上找到。
每项任务的获胜者将获得 1000 美元的奖金。获胜的提交材料是根据评估标准得分最高的材料。
结束语
这个 CORD-19 已经吸引了 122,000 次浏览和超过 3,000 次下载。70 多名研究人员为这一挑战做出了贡献。尤其是最新的日下载量已经超过 2000。
我希望更多的人工智能研究人员能够帮助应对这一挑战。

CORD-19 挑战的当前活动
SQL 中的巨大竞争
探索性数据分析和特征工程

介绍
没有什么比通过简单的行动来学习新的东西或使一项技能更上一层楼更强大的了。在本文中,我将使用 SQL (Postgres)进行探索性分析,并为我的机器学习模型创建一个转换后的特征训练集。
虽然 Python 或 R 是当前数据科学和机器学习的事实语言,但拥有 SQL 的坚实基础有时会帮助您更快地迭代,并允许您快速浏览您的数据。归根结底,我们处理的大部分数据都存在于关系数据库中。能够流畅地编写 SQL 查询将允许您轻松地处理数据,并快速开始您的分析。
目标
虽然 Python 将是我的首选方法,但我想看看我是否能在 SQL 中完成所有的探索性分析和特性工程。我的目标是展示 SQL 对于一个人的工作流是多么强大和补充。尽管 SQL 的一个明显限制是数据的本地可视化能力,但是您仍然可以通过快速编写查询和输出结果来获得巨大的收益。我们开始吧!
我的设置
- macOS Mojave 版本 10.14.6
- PostgreSQL 12.2
- pgAdmin 4.21 (SQL web 查询工具)
- psql (终端访问数据库和表格)
在我的后续文章中,我用 Python 完成了我的监督分类模型,并分享了我在 Kaggle 的公共领导力板上获得的最高分。看看这里!
[## Kaggle 泰坦尼克号竞赛:Python 中的模型构建和调优
最佳拟合模型、特征和排列重要性以及超参数调整
towardsdatascience.com](/kaggle-titanic-competition-model-building-tuning-in-python-12f4f74436b5)
探测
我对泰坦尼克号沉没的研究表明,在运送乘客上救生艇时,妇女和儿童比其他人更优先。这个概念将在我如何分组和分析 Kaggle 数据集的过程中发挥重要作用。
此外,还讨论了是将训练和测试数据集分开,还是将它们结合起来用于特征工程和选择。在大多数情况下,前者有助于避免数据泄露。
通常的做法是将测试数据集放在一边,忘记它,只使用训练数据集来估算和设计特征。对于这个练习,我决定将训练和测试结合起来,这样我就有更多的数据来预测存活率。这是一个固定的宇宙,我们不期望新的数据流入预测管道。
首先,我从 Kaggle 下载了 train.csv 和 test.csv 文件,并将这些文件导入到我在 Postgres 数据库中创建的两个表中。接下来,我将这两个表结合起来,创建了我的第一个工作表(titanic_train_test_raw)。
为了将记录插入到我的表中,我在终端上通过键入“ psql postgres”打开 psql。这是 PostgreSQL 命令行工具。我运行了以下两个 psql 复制命令,将 CSV 文件插入到我的表中。
\copy titanic_train_raw from ‘file/path/train.csv’ delimiter ‘,’ csv HEADER;\copy titanic_test_raw from ‘file/path/test.csv’ delimiter ‘,’ csv HEADER;
为了更好地理解数据,我计算了训练集中每个可用特性的 survival_rate。我没有在这里分享整个输出,因为我将在整篇文章中一点一点地分享它们。然而,这让我对哪些特性值得深入挖掘,以及每个特性的相对重要性有了一个清晰的认识。
1。缺失值
让我们更仔细地看看丢失的值,看看哪些潜在的特性需要估计,或者由于稀疏性而被丢弃。缺失值的计算是通过组合训练和测试数据来完成的。因为测试数据没有幸存目标特征,所以组合的幸存列有 31.93%的值缺失。还有年龄、舱位、票价、上船分别少了 20.09%、77.46%、0.08%、0.15%。

2。总体存活率
从训练数据集中,我计算了存活百分比和未存活百分比。在训练数据中的 891 名乘客中,只有 38.38%的人幸存。此外,这个分析让我看到目标类并不是太不平衡——大约是 60%/40%的比例。

3。按性别和年龄分列的存活率
与男性乘客相比,女性乘客生还的可能性最高。仅从性别来看,培训数据告诉我们,女性的存活率约为 74.2%,而男性为 18.89%。

使用纯 SQL,我创建了 10 个 bin(age _ cohort)来对不同的年龄进行分组。我不打算对年龄组进行任何精确的划分,因此容器的数量是任意的,但是创建足够多的容器来查看相关的模式。最关键的信息之一从这个观点中浮现出来。虽然在所有年龄组中女性的存活率仍然很高,但 9 岁或更小的男性的存活率接近 60%(数据输出中的第 9 行)。单就性别而言,男性的存活率低于 20%,但通过对年龄组的数据进行切片,我们看到男性的一个亚组具有相对较高的存活率——儿童。

4。按票价和每位乘客的平均票价生存
为了快速了解与生存相关的票价,我使用了一个窗口函数,将乘客平均分成 6 个箱,并创建了统计数据以进行更仔细的检查。这是一种快速且不实用的宁滨方法,因为相同的票价金额可能会落入不同的箱中,如 fare_min 和 fare_max 所示。
乍一看,随着票价变得更贵,存活率似乎会上升。与此同时,fare_mean 和 fare_stddev 从 bin 5 跳到 bin 6。最高的 fare_max 价格为 512.3292 美元,最低的 fare_min 价格为 0 美元。票价栏有些杂音。持续持有的是,女性存活率远高于男性。基于 fare_grouping 属性,女性存活率比男性高 2 倍—9 倍(survival_ratio)。

我很快发现票价代表的是机票的总成本,而不是每位乘客的票价。比如机票 PC 17755,有四个乘客。卡德扎是一个富裕的家庭,和他们的两个雇员沃德小姐和勒苏雷先生一起乘坐头等舱旅行。

为了了解每张机票的成本,我用每张机票上的乘客总数除以票价金额,并按 Pclass 对平均值进行分组。在检查票证功能时,我看到了家庭、混合组和附加到单个票证的个人。因此,使用每张机票上的乘客人数产生了较小的标准差,并给了我信心,这将提供相对更准确的每位乘客的平均票价,而不是使用其他 Kaggle 人常用的[SibSp(兄弟姐妹和配偶)+ ParCh(父母和子女)+ 1 (PassengerId)]。

平均而言,头等舱每位乘客的票价约为 32 美元,二等舱约为 12 美元,三等舱约为 8 美元。这种平均去除了原始票价特征中的相当多的噪声。并且 fare_mean 看起来与 Pclass 高度相关。因此,Pclass 和 fare_per_passenger 这两个特性可能是多余的。稍后,我们可能希望在模型构建期间删除其中的一个。
5。基于来自原始名称特征的标题的生存
有 17 个独一无二的称号,有的存活率很高;然而,大多数都不常见。训练数据中只有两个乘客的标题是少校,一个乘客的标题是 Sir。为了使每个分组对建模具有相关性和影响力,我将不常用的头衔分成四类——先生、夫人、小姐和主人——从而创建了一个 title_grouping 特性。比如 Mlle,是 Mademoiselle 的缩写,卷成 Miss。
题主之所以有意思,是因为它的存活率比较高,而且在训练数据中也有不少。在此期间,男孩被授予这一头衔,直到他们成年。现在我们有了一种方法,当所有的女孩和女人都被归入“夫人”或“小姐”时,我们可以使用“头衔分组”来识别男孩。

我按每个标题 _ 分组计算了存活率,数字很能说明问题。通过把男孩从男性群体中分离出来,男性的存活率下降了。相比之下,男生的存活率将近 60%。在最终的训练数据集准备工作中,我将把这个特性编码成数值。

6。基于是女人还是孩子的生存
我偶然看到克里斯·德奥特的文章,是关于他基于用姓氏和头衔对乘客进行分组而创建的一个名为“女人-孩子-团体”的功能。本质上,它关注的是群体生存。考虑到这一点,我创建了一个二元特征来标记每位乘客是男是女。is_woman_child = 1 表示所有妇女和儿童,而 is_woman_child = 0 表示所有成年男子。对于 title_grouping 来说,这个标志可能是多余的,并且可能导致模型过拟合,但是让我们看看这是如何实现的。

7。基于舱室水平面(又名甲板)的生存
我为此做的一些读数显示,大多数三等舱乘客位于 F 和 g 舱层。因此,更仔细地查看客舱层是有意义的,尽管 77%的值丢失了。我假设较低的客舱高度会降低乘客的生还几率。

RMS泰坦尼克号船中部剖面图
在做了一些分析后,我观察到当乘客属于较低阶层和较低客舱等级时,存活率会下降。我使用 Pclass 和 apollowed 创建了一个逻辑来近似每个乘客的客舱级别,我将在特性工程部分对此进行更深入的探讨。

单独着手不会告诉你一个生存的故事,如下所示,但我相信它可以用来创建新的功能,将具有相对更高的预测能力。泰坦尼克号最初停靠在英国的南汉普顿,然后前往法国的瑟堡。最后,在驶往纽约之前,在爱尔兰的皇后镇停留。
顺便提一下,有两名乘客丢失了上船值,但我查找了这些乘客,他们都在英格兰的南汉普顿登船。
我假设登船位置和船舱所在的甲板(船舱级别)之间存在关联。换句话说,每个登机地点都有一组特定的客舱,并且有某种组织形式,根据登机地点,客舱将首先被填满。因此,举例来说,如果你有一张以 F 开头的三等舱船票,F 代表船舱所在的甲板,你最有可能从英国的南汉普顿登船。

特征转换和工程
现在,我已经了解了原始的训练特征,并对乘客存活率有了更好的了解,是时候巩固我们的发现,并开始整合优化的训练数据集以进行模型拟合了。
1。is _ one _ family/is _ mix _ group/is _ alone
假设:我假设同一个票号定义了一起出行的乘客。此外,我还假设,如果一个人是一张机票上的唯一乘客,那么这个乘客就是一个单独的旅行者,同时可能有其他家庭成员或亲戚乘坐不同的机票旅行。因此,我根据从原始姓名特征中提取的票号和姓氏对乘客进行分组。

这种假设是有代价的,但是我假设这包含了大多数的团队场景。以这种方式划分组的主要目的是概括船上的人口。
- 如果给定的机票有多个乘客的单个姓氏,则认为是一个家庭,其中 1 为真,0 为假(is_one_family)。这主要是为了标记一起旅行的家庭。因此,如果乘客是单个机票系列的一部分,则该标志被标记为 1。
- 如果给定的机票有多个姓氏和多个乘客,这将被标记为混合组(is_mix_group)。例如,票号 1601 有 7 个不同的姓氏。总共有 67 张票附有两个或两个以上的姓氏。我这里只展示前 12 名的门票。

- 如果给定的机票只有一个姓和一个乘客,这是一个单独旅行的乘客(is_alone)。仔细看看男性人口,单独旅行的成年男性乘客的存活率最低(15.57%),相比之下,有家庭的成年男性(17.46%)和有家庭的男孩(57.5%)。

一眼看去,没有家庭或属于混合群体的成年男性乘客生还几率最低。我们确实在这个输出中看到了一些有趣的模式。和家人一起旅行的男性乘客存活率最高。最有可能的是,这些男性乘客是男孩。下面我来验证一下。

当我把男孩从男性人口中分离出来时,情况就清楚多了。男孩的存活率比成年男子高。

2。家庭规模
为了确定每个乘客的家庭规模,添加 SibSp、ParCh 和当前乘客(+1)是合乎逻辑的。然而,根据机票号码和姓氏来确定最大家庭规模比在乘客层面定义更有意义。
我坚持家庭一起旅行的假设,在这种情况下,在同一张机票上。因此,SibSp、ParCh 和 current passenger 的总和(表示家庭规模)与一个票号和姓氏相匹配。我创建了一个映射 SQL 子查询,其中如果您有相同的机票号码和姓氏,那么家庭规模(SibSp + ParCh + 1)将被映射到乘客。
一旦把逻辑放在一起,我就按照家庭规模和 Pclass 来看平均存活率。相对较大的家庭存活率较低。可以大致推断,如果你是一个大家庭的一员,你就死了。还有,你一个人就死了。由于四人或四人以上的机票屈指可数,很难一概而论大团体的生存。然而,根据现有的数据,值得看看家庭规模在预测存活率方面是否有一定的相对重要性。

3。建立第一个合并特征表:titanic_train_test_raw_v2
我现在正在整理我的第一个基于以上所有发现的合并表。在这一步中,我将加入新的特性并转换现有的特性,以便更好地使用模型。以下是所有新增内容和增强功能的列表。
- 将性别特征编码为女性= 1,男性= 0
- 从姓名特征中提取姓氏
- 添加标题分组功能,我在前面分享过
- 添加 is_woman_child 要素
- 从客舱特征中提取客舱级别(甲板)
- 将装载特征编码为 S = 0,C = 1,Q = 2
- 添加基于票号和姓氏的 family_size 特征
- 添加 is_one_family、is_mix_group 和 is_alone 特征
- 通过将票价除以在每张票上找到的乘客 Id 的数量,添加 fare_per_passenger 功能


4。建立第二个合并特征表:titanic_train_test_raw_v3
使用前面创建的一些特性,我创建了第二个统一表(v3 ),以添加更多特性并进行额外的更改。在使用 SQL 时,最好以这种方式构建多个表,因为它有助于保持事物的有序性,并通过使用更小的块使 SQL 更具可读性。
- 年龄缺失值:填写缺失的年龄值(第 11 行&第 44–52 行)。我按照 Pclass、性别和 title_grouping 对数据进行分组,计算每个分组的平均年龄。我选择了平均值,而不是中间值,因为两组数字是相似的。我还计算了平均值的标准差来检查可变性。
- 另外,我创建了一个名为 Age_bucket 的特性(第 12 行)。我决定将连续的年龄变量放入 7 个容器中。由于年龄要素包含估计平均值,因此最好将其转换为分类要素,以最大限度地减少连续要素中的噪声。
- Fare_bucket &票价缺失值:在我的探索性分析中,我计算了每个乘客每个舱位等级的平均票价,很明显,价格与舱位等级密切相关。我用与每个乘客的 Pclass 相关联的 fare_per_passenger 来填充缺失的票价值。同时,我创建了 5 个箱来创建分类特征。
- Title_grouping: 该特性中的四个文本字符串标签被转换为数值。(主机= 0,夫人= 1,小姐= 2,先生= 3)
- Cabin_level&Cabin level missing values:我填充缺失的 cabin_level 值的方法是通过 Pclass、Embarked 和 Cabin _ level(其中 Cabin 不为空)来计算所有乘客。接下来,我将附属于 Pclass、Embarked 和 cabin_level 的乘客数量按降序排列,对于 Pclass + Embarked 的每个组合,我将抓取附属于它的乘客数量最高的 cabin_level。
这是构建 titanic_train_test_raw_v3 表的子查询。

如果 Pclass = 1,apolled = 0,那么 cabin_level = C.
如果 Pclass = 1 且 Embarked = 1,则 cabin _ level = c。
如果 Pclass = 1,apolled = 2,那么 cabin _ level = c。
如果 Pclass = 2 且 Embarked = 0,则 cabin _ level = f。
如果 Pclass = 3 且 Embarked = 0,则 cabin _ level = g。
以此类推!
5。构建“妇女-儿童-群体”修改逻辑
我继续尝试用 SQL 做一些修改来重新创建克里斯·德奥特的特征。我将回顾我所做的,在我的后续文章中,我将测试该特性的影响和重要性。
-
首先,每个乘客的头衔被标为男人、女人或男孩。与此同时,所有男性头衔都被贴上了“非群体”的标签,因为女性和儿童被赋予了生存的优先权。
-
接下来,我计算了每个乘客的姓氏频率。此频率查看整个数据集,而不是票证级别。并且任何姓氏频率为 1 或更少的乘客(如果有的话)被标记为“noGroup”因此,家庭中的妇女和儿童优先于独自旅行的妇女。
-
在这个阶段,基于更新的姓氏特征,使用训练数据的幸存目标特征来计算幸存概率。在这一点上,大多数姓氏已经改变为“noGroup”,因此,所有乘客的生存将使用这个更新的姓氏特征来概括。
-
最后,使用标题和姓氏 _ 生存,我创建了一个新的二进制标志,标题 _ 姓氏 _ 生存。当最终的训练和测试数据集被创建时,这个逻辑被合并。我创建了两个表来捕捉每一个——titanic _ train _ ml _ features _ v 0 和 titanic_test_ml_features_v0。

- ML 训练数据集:titanic_train_ml_features_v0

- ML 测试数据集:titanic_test_ml_features_v0(与训练数据集相同,只是缺少幸存特征。)

摘要
这篇文章提供了相当多的信息。我使用纯 SQL 进行了探索性分析和特性工程。我利用 GROUP BY、窗口函数、聚合函数、子查询、WITH 子句、HAVING 子句和其他 SQL 技术来分割数据。

约书亚·阿拉贡在 Unsplash 上拍摄的照片
下一步是导出最终的训练和测试数据集,以便使用 Python 进行分析。在我的后续文章中,我将使用 Python 测试不同的 ML 模型,了解特性的重要性,并使用 RandomizedSearchCV 和 GridSearchCV 调优所选的模型。最后,我会将我的预测提交给 Kaggle,看看我在其他条目中的排名如何!
以下是我在后续文章中所涉及内容的概述:
- 导入库
- 准备训练和测试数据帧
- 相关系数矩阵
- 创建辅助函数:输出模型统计信息
- 多重拟合模型和最佳拟合模型
- 创建助手功能:输出 RF 特征重要性排序
- 具有随机森林特征重要性、排列重要性和层次聚类的特征选择
- 随机森林分类器
- GridSearchCV:随机森林分类器
- 结论:最新结果和最终想法
如果您有任何问题、意见或反馈,请告诉我。谢谢!
Kaggle 泰坦尼克号竞赛:Python 中的模型构建和调优
最佳拟合模型、特征和排列重要性以及超参数调整

保罗·比昂迪在 Unsplash 上的照片
背景
我用 SQL 进行了初步的探索性分析和特性工程。在我的上一篇文章中,我展示了 SQL 在研究关系数据库中的数据时是多么强大。对于更多的上下文,可能值得在阅读本文之前检查一下,尽管这不是必需的。你可以在这里找到文章!
探索性数据分析和特征工程
towardsdatascience.com](/kaggle-titanic-competition-in-sql-78ae3cd551ce)
我将使用之前在“Kaggle Titanic Competition in SQL”文章中准备的训练/测试数据集来预测乘客存活率。
概观
- 导入库
- 准备训练和测试数据帧
- 相关系数矩阵
- 创建辅助函数:输出模型统计信息
- 多重拟合模型和最佳拟合模型
- 创建助手功能:输出 RF 特征重要性排序
- 具有随机森林特征重要性、排列重要性和层次聚类的特征选择
- 随机森林分类器
- GridSearchCV:随机森林分类器
- 结论:最新结果和最终想法
导入库
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inlinefrom sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import Perceptron
from sklearn.linear_model import SGDClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC, LinearSVC
from sklearn.naive_bayes import GaussianNBfrom sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import RandomizedSearchCV, GridSearchCV
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import confusion_matrix
from sklearn.metrics import precision_score, recall_score, roc_auc_score
准备培训和测试数据帧
使用 Pandas,我将 CSV 文件作为数据帧导入。如果你读过我的“Kaggle Titanic Competition in SQL”一文,train_df.info()的结果集应该看起来很熟悉。对于模型训练,我从 15 个特征开始,如下所示,不包括 Survived 和 PassengerId。
train_df = pd.read_csv(‘file/path/data-train.csv’)
test_df = pd.read_csv(‘file/path/data-test.csv’)

相关系数矩阵
作为第一步,我使用 Pandas 和 Seaborn 中内置的 corr 函数创建了一个成对相关矩阵来可视化数据。它以默认方法计算皮尔逊 相关系数(线性关系)。我还使用了 Spearman 和 Kendall 方法,这两种方法在 pandas.DataFrame.corr 中都有
所有的结果看起来都差不多。相对而言, 斯皮尔曼的 等级-顺序相关性 方法,其测量单调关系,在这里可能是最好的,而无需深入研究不同类型特征的相关性和关联性的概念。一个警告是, Spearman 将把名词性特征视为序数特征。
只是作为一个旁注,在这一点上,我所有的特征都已经转化为由二进制(二分法)、序数(分类和有序)、名词性(分类和不有序)和连续特征组成的数值。我想快速了解哪些特征是相互关联的,以及明显特征之外的重要程度。
如果我要更深入地探究这个练习的细节,那么我们还需要讨论分类特征之间的关联以及二元和连续特征之间的相关性。在测量两个标称特征之间的关联时,我们将不得不深入到 克莱姆氏 V 或皮尔森的 卡方检验。然而,在我看来,这应该是获得初始基线读数的足够好的方法。如果我错过了什么,请随时告诉我。

你可以在这里找到。
我生成了相关系数热图,并注意了 0.8 到 1.0 相关范围内的绝对值。这些相关性阈值是任意的,稍后我将查看各种阈值来确定什么最有效。
train_corr = train_df.drop(columns=["survived", "passengerid"]).corr(method='pearson')
plt.figure(figsize=(18, 12))
sns.set(font_scale=1.4)
sns.heatmap(train_corr,
annot=True,
linecolor='white',
linewidth=0.5,
cmap='magma');

皮尔逊
在使用 0.8 作为我的皮尔逊相关阈值对这些数字进行深入研究后,我发现了这些对(如下所示;df_corr 的输出)是高度相关的。稍后,我将利用 Spearman 和其他方法为我的最终模型选择重要的特性。
# Pearson’s correlation analysis using an arbitrary correlation threshold (absolute values)corr_threshold = 0.8
train_corr_abs = train_corr.abs()feature_1 = []
feature_2 = []
corr_coeff = []
for col in train_corr_abs:
for idx, val in enumerate(train_corr_abs[col]):
if ((val >= corr_threshold) and (val < 1)):
feature_1.append(col)
feature_2.append(train_corr_abs[col].index[idx])
corr_coeff.append(val)df_corr = pd.DataFrame({‘feature_1’: feature_1,
‘feature_2’: feature_2,
‘corr_coeff’: corr_coeff})
df_corr

来自 df_corr 的结果;输出包含重复项。

重复项被删除,剩下六个高度相关的配对。
识别出高度相关的对后,这种分析将有助于以后处理任何回归或线性模型。高度多重共线性会导致要素或系数估计值对模型中的微小变化变得敏感。这也会影响非线性模型。
底线是多重共线性特征可能会创建一个无效的模型,并且对特征重要性的理解可能会有偏差。我不打算把精力放在具有轻度多重共线性的配对上。现在,我将暂时搁置这个问题,到时候再直接解决这个问题。
train_corr = train_df.train_df.drop(columns=["survived", "passengerid"]).corr(method='spearman')
plt.figure(figsize=(18, 12))
sns.set(font_scale=1.4)
sns.heatmap(train_corr,
annot=True,
linecolor=’white’,
linewidths=0.5,
cmap=’magma’)

斯皮尔曼
train_corr = train_df.drop(columns=["survived", "passengerid"]).corr(method='kendall')
plt.figure(figsize=(18, 12))
sns.set(font_scale=1.4)
sns.heatmap(train_corr,
annot=True,
linecolor=’white’,
linewidths=0.5,
cmap=’magma’)

肯德尔
创建辅助函数:输出模型统计信息
首先,我通过拟合 X_train 和 y_train 来训练九个不同的模型。为了加快我的工作流程,我创建了一个输出模型性能和诊断指标的函数,以快速查看数字并确定哪个模型可能工作得最好。这些度量在函数的 docstring 中列出。
此外,我定义了一个管道对象(下面的第 27 行),其中包含一个缩放器和一个估算器的实例。在使用随机森林的少数情况下,我不会缩放 X_train 和 X_test,因为没有必要这样做。
多重拟合模型和最佳拟合模型
助手函数有三个参数。首先,它需要一个字典,将模型的名称(字符串)作为键,将模型类实例化作为值。其次,它需要特征训练数据集(X_train ),最后需要目标类数据(y_train)。让我们检查结果!
随即,随机森林和决策树以 98.54%的准确率脱颖而出。我知道决策树倾向于过度拟合,所以我并不太惊讶。另一方面,随机森林是决策树的集合,旨在通过采用要素和行的随机子集来创建决策树森林并对预测结果进行投票,从而最大限度地减少过度拟合。这个随机过程产生了一个更好的模型,具有更高的偏差和更低的方差。
仔细观察,使用 Kfold 为 10 的交叉验证的准确性分数对于随机森林和决策树产生了 84.07%和 81.3%的更真实的分数。其他脱颖而出的模型还有 KNN、SVM、逻辑回归和线性 SVC,都获得了可观的分数。高标准偏差表明模型可能无法用新数据很好地概括,所以我也注意到了这一点。
让我们仔细看看精度和召回。在这种情况下,最大限度地提高精确度和召回率是有意义的,F1 的高分就表明了这一点。虽然有一个精度-召回权衡,相对较高的精度[TP/(TP+FP)]给了我正面预测的准确性。相比之下,相对较高的召回率[TP/(TP+FN)]给出了模型正确检测到的实际阳性率的%。回忆也称为真阳性率(TPR)和敏感度。此外,我想要 ROC 曲线下的高 AUC。结果,我把列表缩小到四个模型——随机森林、KNN、逻辑回归和线性 SVC。
最终,我选择了 random forest,尽管其他模型的分数稍好一些。在我看来,这些细微的差别可以忽略不计。目标是在特征选择过程中利用随机森林的基于杂质的特征重要性和排列重要性。

创建助手功能:输出 RF 特征重要性排序
为了使用随机森林快速输出特性重要性排序,我创建了一个助手函数来完成这项工作。它输出一个 Pandas 数据框,其中包含按等级顺序排列的要素名称及其对应的要素重要性分数。
具有 RF 特征重要性、排列重要性和层次聚类的特征选择
迭代 1
回到相关系数矩阵,有五对标记为高度相关或彼此关联。使用 X_train 和 X_test 定义的所有特性,如下所示,我检查了 RF 的特性和排列重要性的结果。我还使用了层次聚类和 Spearman 的相关矩阵来辅助特征选择。
X_train = train_df.drop([“survived”, “passengerid”], axis=1)
y_train = train_df[“survived”]
X_test = test_df.drop([“passengerid”], axis=1)rf_base = RandomForestClassifier(n_estimators=100, random_state=0)
rf_base.fit(X_train, y_train)n = len(X_train.columns)
importance_scores = rf_base.feature_importances_
rf_feature_ranking(n, importance_scores)

随机森林特征重要性
RF 的特性重要性是衡量什么特性是重要的一个坚实的开端,但并不总是给出一个明确的重要性视图,并且可能会产生误导。RF 特征重要性的潜在机制是有偏差的。它往往高估了某些特征的重要性,例如连续或高基数分类特征。简而言之,对决策树森林中的每个特征的杂质减少进行平均,然后基于该平均值对特征进行排序。这里有一个好的读这个和这个和这个!
共线特征也将是一个问题。因此,仅利用基于杂质的特征重要性的 RF 平均下降不会显示全貌,必须是更好地理解特征重要性的许多工具之一。
在这一点上,我关心的是共线特征。因此,我利用排列重要性和层次聚类来确定哪些特性是相关的。从概念上讲,在排列重要性中,它使用验证集计算要素的基线精度。接下来,它置换单个列/特征的所有值,并使用测试数据集测量相对于基线精度的变化。这将对每个特征重复。
在我的研究中,我在 Scikit-Learn 的网站上看到了一篇关于这个特定主题的内容丰富的文章。我将利用这里找到的代码,完成我的特性选择过程。此外,我将依靠领域知识和引导试错法来看看什么样的特性组合会有最好的结果。

排列重要性相对来说比特征重要性更可靠,尽管前者也会受到共线特征的影响,并会增大受影响特征的重要性。来自两个初始视图的一个令人满意的建议是,is_alone、is_mix_group 和 is_one_family 不会给模型增加太多价值。
对于层次聚类,树状图上的 y 轴代表接近度或相异度。随着它越来越接近 0,聚类特征之间的距离越来越近,表示相关性/关联性。在这次迭代中,我检查了所有低于 1.5 的聚类——这是一个任意的阈值。这里使用的代码块也可以在 S cikit-Learn 的网站上获得。

左边是树状图,右边是斯皮尔曼相关矩阵
使用树状图,我仔细观察了具有两个特性(例如,pclass 和 cabin_level)的较小集群,并试探性地确定了哪些特性可能需要删除。我决定放弃 age,因为它与 age_bucket 高度共线,是一个连续的特性。此外,我决定去掉 sex 和 fare,因为它们的相关特征对模型的贡献是一样的。因此,在下一次迭代中总共删除了 7 个特征——年龄、性别、票价、单身、组合和家庭
计算特征和排列重要性
生成层次聚类和 Spearman 相关矩阵
迭代 2
让我们来看看更新后的结果。在这个迭代中,我使用了 9 个特性,它们代表了新的 X_train 和 X_test。

X_train.info()
我使用了 output_model_stats 函数来比较性能指标和原始随机森林指标。迭代 2 指标附加到“rf_base —迭代 2”索引。总的来说,该模型的性能比具有所有功能的模型稍差。最有可能的是,第一个随机森林模型是过度拟合的(相对较低的偏差和较高的方差),在此阶段不应引起关注。

记住 X_train 只包含 9 个特性,如上图。
基于更新的特征和排列重要性排序,apollowed 在两者中都非常接近于零。我决定在下一次迭代中放弃这个特性。

我决定放弃 fare_bucket 和 age_bucket。在我看来,用于创建票价桶的平均每位乘客票价计算很可能没有足够的数据来很好地概括,并且票价异常值在训练数据中挥之不去。
在使用排列重要性观察了 age_bucket 相对于 pclass 和 is_woman_child 的排名后,类似的逻辑思维落到了 age _ bucket 上。同时,fare_bucket 和 age_bucket 相互关联。我的直觉告诉我,保留这些特征最有可能减少偏差,增加方差。因此,模型的泛化能力会降低。

如树状图所示,0.5 下左起的第一个集群由 pclass 和 cabin_level 组成。pclass 和 cabin_level 之间的距离非常近,Spearman 的相关矩阵显示这些是相关的。我犹豫要不要放弃 pclass 或 is_woman_child,因为在我的探索性分析中,这两个特征都显示出与乘客存活率高度相关。
随机森林的随机性创建根节点和分裂以创建内部节点和叶节点会减少共线要素的影响,但不会完全减少。在我看来,在这个使用随机森林的场景中同时使用这两个共线的特征并没有坏处。
迭代 3
在这个阶段,更新的 X_train 和 X_test 数据集包含 5 个特征,我推断这 5 个特征是最相关的。

X_train.info()
接下来,我输出了性能指标(“rb_base —迭代 3”),并将它们与早期的结果进行了比较。accuracy_cv_score 高于前两次迭代。精确度提高了很多,这意味着在模型检测到的所有阳性(TP + FP)中发现了更多的真阳性(TP)。这是一个好迹象。正如预期的那样,召回率略有下降,这意味着该模型在实际真阳性(TP + FN)中检测真阳性(TP)的能力有所下降。F1 评分从第 2 次迭代开始改善,ROC 曲线下的 AUC 上升至新高。

在仔细研究了特性重要性、排列重要性和 Spearman 相关矩阵的树状图之后,我决定用这些特性来生成我的第一个 Kaggle 提交文件。此时,我并不关心一对相关的特性。


我用带 X_test 的训练好的模型输出预测的 y_test (y_pred_base)。我创建了我的提交文件,并提交给 Kaggle。我可以用这个提交获得 80.382%的准确率。我认为这是一个相当可观的分数。
rf_base = RandomForestClassifier(n_estimators=100, random_state=0)
rf_base.fit(X_train, y_train)
y_pred_base = rf_base.predict(X_test)df_output = pd.concat([test_df[‘passengerid’], y_pred_df], axis=1, sort=False)
df_output = df_output.rename(columns={“passengerid”: “PassengerId”})
df_output.to_csv(‘gender_submission.csv’, index=False)

随机森林分类器
在 Scikit-Learn 的文档页面中可以找到对 RandomizedSearchCV 的很好的解释。了解 Python 面向对象的方法很好。Scikit-Learn 中的模型类对象包含参数、属性和方法。
用于应用这些方法的估计器的参数通过对参数设置的交叉验证搜索来优化。
与 GridSearchCV 相反,不是所有的参数值都被尝试,而是从指定的分布中采样固定数量的参数设置。尝试的参数设置的数量由 n_iter 给出。
如果所有参数都以列表形式显示,则进行无替换取样。如果至少有一个参数作为分布给出,则使用替换抽样。强烈建议对连续参数使用连续分布。"
我主要关注 rs_grid 变量下面列出的 6 个超参数。关于所有参数的详细概述,文档页面包含了大量信息。
随机森林超参数
- n_estimators: 这代表了森林中决策树的数量。默认值设置为 n_estimators=100。
- 标准:该功能测量分割的质量。例如,年龄是可以作为根节点的特征。基于分裂标准,它分裂成内部节点和叶节点,直到当一个分支达到最低 gini 杂质时树停止生长(缺省设置为 gini,第二个选项是信息增益的熵)。
- max_features: 寻找最佳分割时要考虑的随机特征子集的数量。
- max_depth: 树的最大深度。如果没有,则扩展节点,直到所有叶子都是纯的,或者直到所有叶子包含少于 min_samples_split 样本。
- min_samples_split: 拆分内部节点所需的最小样本数。
- min_samples_leaf: 一个叶节点所需的最小样本数。任何深度的分裂点只有在左和右分支的每一个中留下至少 min_samples_leaf 训练样本时才会被考虑。
随机搜索 CV 参数
- 估计器:模型类实例化,用于对最佳参数进行随机搜索。
- param_distributions: 以参数名(
str)为关键字的字典,以及要尝试的分布或参数列表。 - n_iter: 被采样的参数设置的数量。
- cv: 决定交叉验证的拆分策略。
- 详细:控制详细程度;详细度越大,输出/日志消息越长。
- random_state: 伪随机数生成器状态,用于从可能值列表中随机均匀采样,而不是从 scipy.stats 分布中随机均匀采样。
- n_jobs: 并行运行的作业数量。除非在
[joblib.parallel_backend](https://joblib.readthedocs.io/en/latest/parallel.html#joblib.parallel_backend)上下文中,None表示 1。-1指使用所有处理器。
随机搜索用了大约 5 分钟,使用了我所有的处理器能力(n_jobs=-1)。param_distributions 包含 8,232 种设置组合(72277*6)。对于我的随机搜索,我将 cv 设置为 5,这等于分层折叠的数量。因此,如果我从 GridSearchCV 开始,总共将尝试 41,160 个参数设置或拟合。这将需要很长时间来运行。然而,使用 RandomizedSearchCV,它从所有可能的设置中采样 n_iter=200,从而在这种情况下将任务或拟合的数量降低到 1000。以下是这次随机搜索的最佳超参数值。

RandomizedSearchCV 的最佳参数属性

通过设置 verbose=3,您会得到一个关于正在发生的事情的很好的输出。
让我们比较一下我之前的测试结果。accuracy_cv_score 增加了大约 1.1%,accuracy_cv_stddev 下降到大约 4%。准确率也有所提高(91.47%),而召回率有所下降。F1 的整体成绩有所提高。AUC 分数稳定在 89%。利用我目前所学的知识,目标是在一个较小的设置集上运行网格搜索,并测量增量。

GridSearchCV:随机森林分类器
GridSearchCV 类似于 RandomizedSearchCV,除了它将基于定义的模型超参数集(GridSearchCV 的 param_grid)进行穷举搜索。换句话说,它将从上面经过所有的 41,160 次拟合。然而,我正在利用以前的经验,减少每个超参数的值列表。关于 GridSearchCV 参数的详细概述,请看文档页。
“用于应用这些方法的估计器的参数通过在参数网格上的交叉验证网格搜索来优化。”

GridSearchCV 中的 best_params_ attribute

详细=3
总的来说,除了 AUC 略有上升之外,没有太大的改善。无论如何,这证明了调整正确的超参数集和覆盖广泛的设置可以提高模型预测。因此,学习利用 RandomizedSearchCV 和 GridSearchCV 成为机器学习工作流的重要部分。但是,您还需要知道您希望在调优过程中投入多少时间和精力,因为增益可能很小。

作为最后一步,我生成了更新的提交文件并提交给 Kaggle。即使进行了超参数调优,对于这组特性和这组优化的超参数,我的分数仍然保持在 80.382%。
结论
最新结果
通过反复试验和扩展超参数设置,我达到了当前 80.861%的站立得分,根据 Kaggle 的说法,这属于前 6%。在我看来,这是一个相当坚实的分数。

最后的想法
- 这个项目强化了特征工程是强大的观点。用于预测存活率的六个特征中有五个是工程特征,它们捕捉了原始特征不能捕捉的信息。
- 此外,对主题有足够的背景知识(阅读关于泰坦尼克号的内容)是有帮助的,这在探索性分析阶段很有帮助。
- 花足够的时间探索(切片和切块)数据有助于建立直觉,这有助于特征工程、聚合和分组数据集。
- 当这些部分就位后,网格搜索和随机搜索等技术有助于逐步改进模型。
- 最后,我相信我们不能轻易忽视领域知识和机器学习中的引导试错法的重要性。这些可以被创建成输入,并且模型可以帮助量化它们的重要性。
请随时分享您的意见、反馈和/或问题。如果你对探索性分析和特性工程感兴趣,可以看看我的第一篇文章——“SQL 中的ka ggle Titanic Competition”感谢阅读!
探索性数据分析和特征工程
towardsdatascience.com](/kaggle-titanic-competition-in-sql-78ae3cd551ce)
资源
如果你正在寻找关于机器学习、数据分析和提高 Python 编程技能的好参考书,我推荐这三本书。
- 使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习:构建智能系统的概念、工具和技术第二版
- 用于数据分析的 Python:与 Pandas、NumPy 和 IPython 的数据角力第二版
- 流畅的 Python:清晰、简洁、有效的编程第一版
Kaggle 用户调查仪表板-2019 年

仪表板主页[Image [0]]
使用 R、Flexdashboard 和 Highcharter 库制作的仪表板,用于分析 Kaggle 在 2019 年进行的用户调查。
当我们告别 2019 年时,我想探索和分析数据科学生态系统的状态,特别是女性在数据科学中的参与以及长期的 R vs Python 辩论。那时我偶然发现了 Kaggle 在 2019 年 10 月进行的一项调查,他们在这里提供了。这是最大的调查之一,有 19,717 份回复。
在这个仪表板中,我试图分析两个主要主题——
- STEM 中的女性。
- 数据科学中的 R vs Python。
这篇博文分为三个不同的部分——主页、STEM 中的女性和 R vs Python。我将在这里介绍主要的发现。
主页
在大约 19 000 名受访者中,大多数是男性。

性别分布[图片1]
大多数受访者拥有硕士学位。

教育分布[图片2]
25-29 岁是受访者中最常见的年龄组。

年龄分布[图片 3]
印度的受访者人数最多,其次是美国。

地理分布[图片[4]]
数据科学家和软件工程师是最常见的职业。

名称分布[图片[5]]
STEM 中的女性
人口统计、教育、职称和工资

人口统计、教育、职位和薪水图[Image [6]]
见解 —
- 接近 50%参与调查的人拥有硕士学位。
- 47%的女性受访者拥有硕士学位,而男性为 43%。
- 数据科学和软件工程师是两个最受欢迎的职业。接受调查的学生人数几乎等于数据科学家的人数。
- 24%的学生是女性,而男性为 20%。
- 与男性相比,更多的女性是学生、统计学家、产品/项目经理、数据分析师和研究科学家。
- 与女性相比,更多的男性是数据科学家、软件工程师、DBA/DB 工程师和数据工程师。
- 女性失业率为 6.87%,男性失业率为 4.46%。
工作中的机器学习

工作中的机器学习图[图片[7]]
见解
- 大多数受访者正在探索 ML 模型,并可能在工作中的某一天将模型投入生产。紧随其后的是在过去的两年里将模型投入生产的人数。
- 与男性(18%)相比,更多的女性(20.22%)在工作中不使用 ML。
- 与女性(16.05%)相比,更多男性(19.69%)在工作中拥有成熟的管理团队方法的团队中工作。
- 大多数受访者在规模为 1-2 或 20+ ie 的数据科学团队中工作。要么是小型探索团队,要么是羽翼丰满的团队。
- 与男性(23.08%)相比,更多的女性(24.48%)在 20 人以上的团队中工作。
- 与女性(19.44%)相比,更多男性(22.47%)在 1-2 人团队中工作。
数据科学中使用的工具和技术

数据科学图中使用的工具和技术[Image [8]]
见解
- MySQL 和 PostgresSQL 是使用最多的 RDBMS 产品。
- 使用 MySQL 的女性(23.51%)多于男性(22.28%)。使用 PostgresSQL 的男性(15.73%)多于女性(13.42%)。
- Scikit-learn 是迄今为止最受欢迎的 ML 框架,被近 50%的受访者使用。Keras 在受欢迎程度上紧随其后。
- 与男性(22.98%)相比,更多的女性(25.32%)使用 Python 中的 scikit-learn。与男性(2.72%)相比,更多女性(3.52%)使用 Caret(R 中的 ML 库)。
- 男性比女性使用 PyTorch、Tensorflow、Keras 等深度学习框架。
- Matplotlib 和 Seaborn 是最流行的数据可视化库。第三个是 ggplot2 库。
- 使用 matplotlib 图书馆的男性(34.11%)多于女性(31.47%)。与男性(12.71%)相比,更多的女性(17.41%)使用 ggplot2 图书馆。
- Jupyter notebook/lab 是最受欢迎的编辑器,被超过 50%的受访者使用。VScode 和 RStudio 紧随其后。
- Kaggle 内核和 Google Colab 是最受欢迎的托管笔记本服务。
ML(自然语言处理和计算机视觉)中使用的算法

ML (NLP 和计算机视觉)图中使用的算法[图片[9]]
见解
- 单词嵌入是最流行的 NLP 技术,其次是编码器解码器模型。
- 自动模型选择是最常用的工具,其次是数据扩充技术。
- 图像分类是最常用的计算机视觉方法。
编码经验和建议

编码体验和建议图[图片[10]]
见解
- 近 50%的受访者花了 0-2 年时间编写代码来分析数据。
- 在编写代码以分析数据方面,女性(28.88%)比男性(23.79%)拥有不到 1 年的经验。与女性相比,有超过 1 年编写代码经验的男性更多。
- Python 是最流行的编程语言,其次是 SQL 和 r。
- Python 是迄今为止最推荐给初学者的语言,超过 50%的受访者推荐它。r 紧随其后。
- 与女性(73.38%)相比,更多男性(79.8%)推荐 Python。而与男性(8.94%)相比,更多的女性(11.4%)建议进行 R。
数据科学媒体和课程平台

数据科学媒体和课程平台[Image [11]]
见解
- Kaggle 是最受关注的数据科学媒体来源,其次是博客,如走向数据科学。
- 与男性相比,更多的女性使用 Kaggle 和博客内容。
- Coursera、Kaggle、Udemy 和 University 是最受欢迎的通过课程学习数据科学的来源。
- 通过大学课程学习的女性(13.55%)多于男性(10.77%)。
R vs Python
哪些是最流行的编程语言?

流行编程语言 plot [Image [12]]
见解
- Python 是最流行的编程语言,其次是 SQL 和 r。
- 与使用 r 相比,更多的人只使用 Python。
R/Python 用在哪里?

R/Python 世界地图[Image [13]]
见解
- 美国和印度是使用 R 和 Python 最多的国家。
- 美国有更多的 R 用户,而印度有更多的 Python 用户。
谁在用 R 和 Python?

R/Python 人口统计图[Image [14]]
见解
- 25-29 岁年龄段的人使用 R/Python 最多。
- 与其他名称相比,数据科学家使用 R 和 Python 最多。软件工程师比 R 用户更多地使用 Python。
- Python 用户在所有工资范围内都一致地获得更多工资。
- 与 Python 相比,更多的统计学家使用 R。
- 更多有 1-2 年编码经验的人使用 Python,而更多有 3-5 年编码经验的人使用 r。
- 与所有其他教育学位相比,拥有硕士学位的人更多地使用 Python 和 R。
ML 中使用的算法(NLP、AutoML 和计算机视觉)

ML (NLP、AutoML 和计算机视觉)图中使用的算法[Image [15]]
见解
- 深度学习算法主要由 Python 用户使用。
- NLP 和计算机视觉领域的大部分工作都是用 Python 完成的。
感谢您的阅读。欢迎提出建议和建设性的批评。:)你可以在 LinkedIn 和 Twitter 找到我。您可以在这里查看仪表盘。
你也可以在这里查看我的其他博客文章。
Kaggle 的微型课程——我最喜欢的数据科学介绍
这就是为什么 Kaggle Learn 是数据科学最友好的入门

照片由 Fotis Fotopoulos 在 Unsplash 上拍摄
截至本月,Kaggle 拥有超过 500 万注册用户,是世界上最大的数据科学和机器学习社区。该平台提供了大量可供公众下载的数据集、资源、数据科学项目和竞赛,可以让您轻松入门。我最喜欢的资源是他们的 Kaggle Learn 。
Kaggle Learn 是一套 14 门微型课程,由 Kaggle 营销为“获得独立数据科学项目所需技能的最快方法”这些课程通过让你体验一系列的主题,提供了该领域的一些最好和最快的介绍。该平台从 Python、机器学习、数据可视化、SQL、深度学习、自然语言处理(NLP)和强化学习等方面对这些话题进行了精彩的阐释。
但是为什么我认为这是你能得到的最友好、最有趣的数据科学介绍呢?这些迷你课程的一个很大的特点是,它们给你一个尝试各种事情的机会;从用 python 写基本函数,到用 SQL 写高级查询,构建自己的视频游戏机器人。即使你只触及表面,你也可以马上尝试各种各样的主题!
Python
这个迷你课程让你有机会对 Python 语言及其语法有一个基本的了解。

照片由 Hitesh Choudhary 在 Unsplash 上拍摄
每个迷你课程被分成更小的章节,然后是编码练习题。在本课程中,您将学习函数、布尔、条件、列表、循环、列表理解、字符串和字典的基础知识。这些足以让您快速(但也是实用的)领略这种最著名的数据科学语言。
机器学习入门和中级机器学习
事实上,这是两门课程。这两个微型课程,像他们系列的其他课程一样,都写得非常好,非常吸引人。它们简明扼要,并有丰富的实例。
第一门课程向你介绍机器学习中使用的不同类型的模型。其余的章节探索了模型验证、欠拟合、过拟合、随机森林和一个新增加的关于 AutoML!
第二个课程让你准备好处理缺失值、分类变量、管道、交叉验证和数据泄漏。
数据可视化
这个迷你课程探索各种可视化技术,并教你如何以及何时使用折线图、条形图、热图、散点图和密度图。它还讨论了发行版以及选择正确可视化的方法。

我个人非常喜欢好的数据可视化课程。我一次又一次地看到,人们用太杂乱、太复杂而无法阅读或完全脱离上下文的可视化方式来可视化他们数据中的某些指标、属性或见解。这个小课程用基本术语解释了每种可视化类型应该在哪里使用。
熊猫
这个迷你课程可以快速有效地建立最基本的熊猫工具。它从教你如何创建、读取和写入数据开始。然后,它将转移到您作为数据科学家每天都会使用的技术,进行任何类型的数据清理。这些包括:索引,选择,合并,排序,重命名,分配,分组和各种清理黑客,你将不得不做清理你的数据和准备你的数据集。本课程也再次讨论了缺失值的处理问题。

特色工程
是时候改进你的模型了!在这个小型课程中,您将学习创建基线模型、对分类数据进行编码、生成特征以及选择最适合您的模型的特征。
深度学习
令人惊讶的是,这些课程让你很快就能尝试像深度学习和 NLP 这样的东西,即使是非常基础的水平!
本课程探索了各种章节和技术。你先快速总结一下深度学习和计算机视觉的基础知识。然后,您将学习如何从卷积构建模型,如何在 TensorFlow 和 Keras 中编程,如何使用迁移学习构建高度精确的模型,以及如何使用数据扩充为模型训练提供更多数据。
SQL 简介和高级 SQL
想了解 SQL 查询是如何工作的?简介课程通过让您熟悉使用最常见的关键字(如 SELECT、FROM、WHERE、GROUP BY、HAVING、COUNT、ORDER BY、AS 和 WITH)来解释如何编写各种基本的 SQL 查询。
顾名思义,高级微课通过引入连接和联合以及解释分析函数、嵌套数据和重复数据来更深入地研究 SQL。
地理空间分析,自然语言处理,游戏 AI 和强化学习

在地理空间分析课程中,您将学习如何使用 GeoPandas 创建您的第一张地图,以及制作交互式地图和 choropleth 地图。在第三和第四章中,除了邻近分析的基础知识之外,您还将学习如何操作地理空间数据。
自然语言处理课程是简短和初级的(适合这种小型课程)。它以一个非常简短的 NLP 介绍开始,介绍文本分类,最后以一章关于单词向量结束。
迷你课程系列的最后一门课程是关于游戏人工智能和强化学习的。这个课程很有趣,也是入门系列的一个很好的总结。在这里,你将编写你的第一个游戏代理,实现一些技巧使你的代理更聪明,最终你将使用极大极小算法使你的代理更聪明。
我认为这一系列迷你课程是让有抱负的数据科学家对该领域更加感兴趣的一种奇妙方式。通过让初级数据科学家尝试各种各样的主题,Kaggle 完全击中了要害!
感谢 Kaggle 团队精彩的 Kaggle Learn 迷你课程系列!
10 分钟后卡格尔的泰坦尼克号比赛|第一部分
机器学习教程| 第二部分→ | 第三部分→→
使用决策树分类器|机器学习教程,用不到 20 行代码完成您的第一场 Kaggle 竞赛
既然你正在阅读这篇文章,我确信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过Linkedin来连线吧!请不要犹豫发送联系请求!Orhan g . Yal n—Linkedin

由 Florian Olivo 在 Unsplash 上拍摄的照片
如果你对机器学习感兴趣,你可能听说过 Kaggle 。Kaggle 是一个平台,在这里你可以用 Python 和 R 学习很多关于机器学习的知识,做数据科学项目,还可以(这是最好玩的部分)参加机器学习竞赛。比赛会随着时间的推移而改变和更新。目前,《泰坦尼克号:机器从灾难中学习》是平台上的初学者比赛。在这篇文章中,我们将用不到 20 行 Python 代码创建一个准备好上传的提交文件。为了能够做到这一点,我们将使用 Pandas 和 Scikit-Learn 库。
泰坦尼克号和臭名昭著的事故
皇家邮轮泰坦尼克号开始服役时是水上最大的船只,1912 年 4 月 15 日,它在第一次前往美国的航行中与冰山相撞后沉没。航行中有 2224 名乘客和船员,不幸的是,其中 1502 人死亡。这是 20 世纪和平时期最致命的商业海上灾难之一。

伤亡人数如此之高的主要原因之一是乘客和船员没有足够的救生艇。虽然运气在事故中幸存下来起了一定作用,但一些人,如妇女、儿童和上层阶级的乘客比其他人更有可能幸存下来。我们将计算这种可能性,以及特定特征对存活可能性的影响。我们将用不到 20 行代码来完成这个任务,并准备好一个提交文件。 …让我们开始吧!
下载数据
Titanic 数据集是一个开放的数据集,你可以从许多不同的存储库和 GitHub 帐户访问它。然而,从 Kaggle 下载肯定是最好的选择,因为其他来源可能有稍微不同的版本,可能不提供单独的训练和测试文件。因此,请访问此链接下载数据集(Train.csv 和 Test.csv)开始。
通常我们的 Train.csv 文件在 Excel 中是这样的:

表 1。CSV 格式的训练数据集
在将它转换成 Excel 中的表格(数据->文本到列)后,我们得到这样的视图:

表二。文本到列操作后的定型数据集
好多了,对吧!现在,我们可以清楚地看到,我们有 12 个变量。虽然“幸存”变量表示特定乘客是否在事故中幸存,但其余的是关于该乘客的基本信息。以下是变量的简要说明:

表 3。关于训练数据集特征的信息
加载并处理培训数据

我假设您已经安装了 Python 环境。不过,如果你的电脑上没有 Python,你可以参考这个链接用于 Windows,参考这个链接用于 macOS。在确保您的系统上安装了 Python 之后,打开您最喜欢的 IDE,并开始编码!
Note that using a [Google Colab Notebook](http://colab.research.google.com) is another option, which does not require local Python3 installation. To have access to the Google Colab Notebook with the full code, consider signing up to [the Newsletter](https://subscribe.to/ogyalcin/) using the slider below.
首先,我们将加载训练数据进行清理,并为训练我们的模型做好准备。我们将(I)加载数据,(ii)删除具有空值的行,(iii)选择“Survival”列作为我的响应变量,(iv)删除目前不相关的解释变量,(v)将分类变量转换为哑变量,我们将用 7 行代码完成所有这些:
创建模型并训练
为了揭示生存变量和其他变量(或者特征,如果你愿意)之间的关系,你需要选择一个统计机器学习模型,并用处理后的数据训练你的模型。

图 4。泰坦尼克号案例的简化决策树模式(图片由作者提供)
Scikit-learn 为此提供了几种算法。我们将选择决策树分类器,这是一个基本但强大的机器学习算法。得到这个:我们只需要 3 行代码来揭示生存(表示为 y)和选择的解释变量(表示为 X)之间的隐藏关系
进行预测并保存结果
在揭示了存活率和所选解释变量之间的隐藏关系后,我们可以为预测阶段准备我们的测试数据。Test.csv 文件与 Train.csv 文件略有不同:它不包含“Survival”列。这是有意义的,因为如果我们知道所有的答案,我们可以伪造我们的算法,并在手写后提交正确的答案(等等!有些人已经这样做了。).无论如何,我们的测试数据在预测阶段需要几乎相同的清理、修饰、准备和预处理。我们将用 5 行代码来实现这一点:
现在我们的测试数据是干净的,并为预测做好了准备。最后,对给定的测试文件进行预测,并将其保存到内存中:
这么容易,对!在保存这些预测之前,我们需要获得适当的结构,以便 Kaggle 可以自动对我们的预测进行评分。还记得吗,我们将 PassengerId 列作为一个单独的数据集保存到内存中(如果您愿意,可以称之为 DataFrame)?现在,我们将把预测数据集分配(或附加)给 PassengerIds(注意,它们都是单列数据集)。最后,我们将从内存中获取数据,并将其保存为 Kaggle 要求的 CSV(逗号分隔值)格式。

图 5。彼得罗·马蒂亚在 Unsplash 上拍摄的照片
现在您可以访问 Kaggle 的泰坦尼克号比赛页面,登录后即可上传您的提交文件。
你能爬到顶端吗?
肯定不是!我们试图实现一个简单的机器学习算法,让你能够参加一场纸牌游戏比赛。随着您对这些基本代码的改进,您将能够在接下来的提交中获得更好的排名。
订阅时事通讯获取完整代码
在本教程的第 2 部分和第 3 部分,我们将实现更高级的方法来提高我们的精度性能。如果你想获得 Google Colab 上的教程代码和我的最新内容,可以考虑订阅邮件列表:✉️
更新!
该系列的第二部分已经出版,请查看:
改进我们的代码,以获得更好的结果,为 Kaggle 的大赛与数据分析和可视化和…
towardsdatascience.com](/kaggles-titanic-competition-in-10-minutes-part-ii-3ae626bc6519)
该系列的第三部分已经出版,请查看:
在 Kaggle 的泰坦尼克号比赛|机器中使用自然语言处理(NLP)、深度学习和 GridSearchCV
towardsdatascience.com](/kaggles-titanic-competition-in-10-minutes-part-iii-a492a1a1604f)
喜欢这篇文章
如果你喜欢这篇文章,可以考虑看看我的其他文章:
[## 使用 MNIST 数据集在 10 分钟内完成图像分类
利用 TensorFlow 和 Keras |监督深度学习使用卷积神经网络来分类手写数字
towardsdatascience.com](/image-classification-in-10-minutes-with-mnist-dataset-54c35b77a38d) [## 使用卷积自动编码器在 10 分钟内降低图像噪声
在时尚 MNIST 的帮助下,使用深度卷积自动编码器清洁(或去噪)有噪声的图像
towardsdatascience.com](/image-noise-reduction-in-10-minutes-with-convolutional-autoencoders-d16219d2956a) [## 利用生成性对抗网络在 10 分钟内生成图像
使用无监督深度学习生成手写数字与深度卷积甘斯使用张量流和…
towardsdatascience.com](/image-generation-in-10-minutes-with-generative-adversarial-networks-c2afc56bfa3b) [## TensorFlow Hub & Magenta 在 5 分钟内实现快速神经风格转换
利用 Magenta 的任意图像风格化网络和深度学习,将梵高的独特风格转移到照片中
towardsdatascience.com](/fast-neural-style-transfer-in-5-minutes-with-tensorflow-hub-magenta-110b60431dcc)
10 分钟后卡格尔的泰坦尼克号比赛|第二部分
←第一部分 |机器学习教程| 第三部分→
改进我们的代码,通过数据分析和可视化以及梯度推进算法为 Kaggle 的大赛获得更好的结果
在本教程的第一部分中,我们开发了一个不到 20 行的小 python 程序,让我们得以参加第一届 Kaggle 比赛。
使用决策树分类器|机器学习,用不到 20 行代码完成您的第一次 Kaggle 竞赛…
towardsdatascience.com](/kaggles-titanic-competition-in-10-minutes-part-i-e6d18e59dbce)
然而,由于我们没有进行良好的数据探索和准备来更好地理解数据和构建模型,因此该模型的表现不是很好。在教程的第二部分,我们将使用 Seaborn 和 Matplotlib 来探索数据集。此外,新的概念将被引入和应用于一个更好的执行模式。最后,我们将在第二次提交中增加我们的排名。

使用 Jupyter 或 Google Colab 笔记本
对于您的编程环境,您可以选择以下两个选项之一: Jupyter Notebook 和 Google Colab Notebook :
Jupyter 笔记本
正如在第一部分中提到的,您需要在系统上安装 Python 来运行任何 Python 代码。还有,需要安装 Numpy、Pandas、Matplotlib、Seaborn 等库。此外,您需要一个 IDE(文本编辑器)来编写代码。当然,您可以使用自己选择的 IDE。不过我强烈推荐安装 Anaconda 发行的 Jupyter 笔记本。Jupyter Notebook 利用了 iPython ,它提供了一个交互式外壳,为测试你的代码提供了很多方便。所以,如果你还没有使用它,你一定要检查一下。
谷歌 Colab 笔记本
Google Colab 建立在 Jupyter 笔记本之上,并为您提供云计算功能。不需要完成以上所有步骤,你可以创建一个 Google Colab 笔记本,它预装了这些库。所以,它更加流线型。比起 Jupyter,我更推荐 Google Colab,但最终还是要看你自己。
探索我们的数据
为了能够创建一个好的模型,首先,我们需要探索我们的数据。 Seaborn ,一个统计数据可视化库,非常方便。首先,让我们记住数据集的样子:

表 1。我们培训数据的前 5 行(按作者列出的表格)
这是你在上面看到的变量的解释:

表二。对变量的解释(表格由作者提供)
所以,现在是时候探索这些变量对生存概率的影响了!
我们的第一个猜想是,一个人的性别(男-女)和他/她的生存概率之间存在相关性。为了能够理解这种关系,我们根据存活和非存活标签创建了男性和女性类别的条形图:

图二。男性和女性的存活数(按作者分列)
正如你在图中看到的,女性比男性有更大的生存机会。因此,性别必须是我们模型中的一个解释变量。
其次,我们怀疑乘客等级和存活率之间也有关联。当我们绘制 Pclass 对抗 Survival 时,我们得到下面的图:

图 3。不同乘客等级的幸存人数(作者提供的数字)
正如我们所怀疑的,乘客级别对一个人的生存机会有很大的影响。看来,如果有人乘坐三等舱旅行,那么他很有可能无法生还。所以 Pclass 对生存概率肯定是有解释力的。
第三,我们还怀疑船上兄弟姐妹的数量(SibSp)和船上父母的数量(Parch)在解释生存机会方面也很重要。因此,我们需要绘制 SibSp 和 Parch 变量与存活率的关系图,我们得到如下结果:

图 4。基于船上兄弟姐妹和父母的幸存人数(作者提供数据)
因此,我们得出这样的结论:随着船上兄弟姐妹数量或船上父母数量的增加,生存的机会也会增加。换句话说,和家人一起旅行的人有更高的生存机会。
我们模型的另一个潜在解释变量(特征)是上船变量。当我们着手对抗生存的阴谋时,我们获得这样的结果:

图 5。基于装载港口的生存统计(作者提供的数据)
很明显,登上南安普敦港的人没有其他人那么幸运。因此,我们也将在我们的模型中包括这个变量。
到目前为止,我们检查了 5 个分类变量(性别、Plclass、SibSp、Parch、apollowed),似乎它们都在一个人的生存机会中发挥了作用。
现在是时候研究我们的数字变量票价和年龄了。首先,我们希望看到年龄对生存机会的影响。因此,我们绘制年龄变量(seaborn.distplot):

图 6。存活率与年龄的关系图(作者提供的数据)
我们可以看到,18 岁以下的儿童存活率较高,而 18 岁以上、35 岁以下的人,这个比率较低。年龄在生存中起着作用。
最后,我们需要看看票价是否有助于解释生存概率。因此,我们绘制票价变量(seaborn.distplot):

图 7。幸存者与票价的关系图(作者提供的数据)
总的来说,我们可以看到,随着乘客支付的车费增加,生存的机会也增加,正如我们所预料的那样。
我们将忽略三列:Name、Cabin、Ticket,因为我们需要使用更高级的技术将这些变量包含在我们的模型中。为了说明如何从这些变量中提取特征:您可以对乘客的姓名进行标记,并派生出他们的头衔。除了先生和夫人之类的头衔,你还会发现其他头衔,如主人或女士等。当然,这在那天晚上拯救谁的问题上起了作用。因此,您可以利用给定的名称列以及客舱和机票列。
检查数据中的空值
空值是我们的敌人!在泰坦尼克号数据集中,我们有一些缺失值。首先,我们将在删除训练数据集的幸存列后合并这两个数据集。
我们需要得到关于空值的信息!有两种方法可以完成这个任务:。info() 功能和热图(更酷的方式!).为了能够检测到空值,我们可以使用 seaborn 的热图,代码如下:
这是结果。黄线是缺失的值。

图 8。空值的热图(作者提供的图)
有很多遗漏的年龄和客舱值。“已装船”列中缺少两个值,而“票价”列中缺少一个值。让我们先处理这些。或者,我们可以使用。 info() 功能以文本形式接收相同的信息:

图 9。联合泰坦尼克号数据的空值信息(作者提供的图表)
读取数据集
由于在第一部分中已经涉及到,我们将不再讨论数据集的细节。使用下面的代码,我们可以导入 Pandas & Numpy 库并读取 train & test CSV 文件。
从上面我们知道,在训练集和测试集中我们都有空值。我们需要估算这些空值,并分别为模型拟合和预测准备数据集。
输入空值
解决数据集中缺失值问题有两种主要方法:丢弃或填充。放弃是简单而天真的出路;虽然,有时它实际上可能表现得更好。在我们的例子中,我们将填充它们,除非我们决定完全删除整个列。
我们的数据集的初始外观如下:

表 3。训练数据集的初始外观(按作者排列的表格)
我们将进行几次插补和转换,以获得完全数字化的干净数据集,从而能够用以下代码拟合机器学习模型(它还包含插补):
清理训练数据集的 Python 代码
在训练数据集上运行此代码后,我们得到了以下结果:

表 4。训练数据集的干净版本(按作者列出的表)
没有空值、字符串或类别会妨碍我们。现在,我们可以将数据分成两部分,特征(X 或解释变量)和标签(Y 或响应变量),然后我们可以使用 sklearn 的 train_test_split() 函数在训练数据集中进行训练测试拆分。
**Note:** We have another dataset called *test*. This isn’t very clear due to the naming made by Kaggle. We are training and testing our model using the train dataset by splitting it into *X_train*, *X_test*, *y_train*, *y_test* DataFrames, and then applying the trained model on our test dataset to generate a predictions file.
创建梯度推进模型和训练

图 10。梯度推进算法的可视化(图片由作者提供)
在第一部分中,我们使用了一个基本的决策树模型作为我们的机器学习算法。另一个众所周知的机器学习算法是梯度提升分类器,由于它通常优于决策树,我们将在本教程中使用梯度提升分类器。下面分享的代码允许我们导入梯度提升分类器算法,基于它创建一个模型,使用 X_train 和 y_train DataFrames 拟合和训练模型,最后在 X_test 上进行预测。
现在,我们有了预测,也知道了答案,因为 X_test 是从列车数据帧中分离出来的。为了能够衡量我们的成功,我们可以使用混淆矩阵和分类报告。您可以通过运行以下代码来实现这一点:
这是输出结果:

图 11。混淆矩阵和分类报告我们的结果(图由作者)
我们获得了大约 82%的准确率,这可以被认为是非常好的,尽管仍有改进的空间。
为卡吉尔比赛创建预测文件
现在,我们有了一个训练有素的工作模型,可以用来预测 test.csv 文件中乘客的生存概率。
首先,我们将使用以下代码清理和准备数据(与我们清理训练数据集的方式非常相似)。请注意,在以“ids”的名称删除 PassengerId 列之前,我们将它保存为一个单独的 dataframe。
最后,我们可以预测测试数据帧的存活值,并根据需要使用以下代码写入 CSV 文件。
这样你就有了一个新的更好的 Kaggle 竞赛模型。我们在代码中做了一些改进,提高了大约 15–20%的准确性,这是一个很好的改进。正如我上面提到的,仍然有一些改进的空间,准确率可以提高到 85–86%左右。然而,在我看来,记分牌的分数并不十分可靠,因为许多人使用了不诚实的技术来提高他们的排名。
这个迷你系列的第三部分
在第三部分中,我们将使用更先进的技术,如自然语言处理(NLP)、深度学习和 GridSearchCV,以提高我们在 Kaggle 的泰坦尼克号比赛中的准确性。
在 Kaggle 的泰坦尼克号比赛|机器中使用自然语言处理(NLP)、深度学习和 GridSearchCV
towardsdatascience.com](/kaggles-titanic-competition-in-10-minutes-part-iii-a492a1a1604f)
既然您正在阅读这篇文章,我相信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过Linkedin来连线吧!请不要犹豫发送联系请求!Orhan g . Yal n—Linkedin
订阅时事通讯获取完整代码
如果你想获得 Google Colab 上的教程代码和我的最新内容,可以考虑订阅我的 GDPR 兼容 时事通讯 !✉️
10 分钟后卡格尔的泰坦尼克号比赛|第三部分
←第一部分 | ←第二部分 |机器学习教程
在 Kaggle 的泰坦尼克号竞赛|机器学习教程中使用自然语言处理(NLP)、深度学习和 GridSearchCV

图一。正在 Unsplash 上建造的泰坦尼克号
如果你关注了我关于 Kaggle 的泰坦尼克号比赛(Part-I 和 Part-II)的教程系列,或者已经参加了比赛,你就对整个故事很熟悉了。如果你不熟悉,既然这是后续教程,强烈推荐你去看看这个教程系列的比赛页面或者 Part-I 和 Part-II 。在该系列的第三部分(最终版)中,(I)我们将使用自然语言处理( NLP )技术来获取乘客的头衔,(II)创建一个人工神经网络(ANN 或 RegularNet)来训练模型,以及(III)使用网格搜索交叉验证来调整 ANN,以便我们获得最佳结果。
开始吧!
背景
教程第一部分
在这个系列教程中,我们试图保持事情简单,慢慢地清晰地发展故事。在本教程的第 1 部分,我们学习了用不到 20 行代码编写一个 python 程序来参加 Kaggle 的竞赛。事情尽可能保持简单。我们清理了非数字部分,处理了空值,使用 train.csv 文件训练了我们的模型,在 test.csv 文件中预测了乘客的存活情况,并将其保存为 csv 文件以供提交。
使用决策树分类器|机器学习,用不到 20 行代码完成您的第一次 Kaggle 竞赛…
towardsdatascience.com](/kaggles-titanic-competition-in-10-minutes-part-i-e6d18e59dbce)
教程第二部分
由于我们在第一部分中没有适当地研究数据集,所以我们在第二部分中使用 Matplotlib 和 Seaborn 重点研究数据研究。我们通过使用聚合函数来估算空值而不是丢弃它们,更好地清理数据,并最终从分类变量中生成哑变量。然后,我们使用 RandomForestClassifier 模型代替 LogisticRegression,这也提高了精度。与第一部分中的模型相比,我们实现了大约 20%的精度提升。
改进我们的代码,以获得更好的结果,为 Kaggle 的大赛与数据分析和可视化和…
towardsdatascience.com](/kaggles-titanic-competition-in-10-minutes-part-ii-3ae626bc6519)
教程的第三部分

图二。具有一个隐藏层的人工神经网络图(由作者提供)
我们现在将使用 Name 列来导出乘客的头衔,这在他们的生存机会中扮演了重要的角色。我们还将使用 Keras 创建一个人工神经网络(ANN 或 RegularNets)来获得更好的结果。最后,为了调整 ANN 模型,我们将使用 GridSearchCV 来检测最佳参数。最后,我们将生成一个新的 CSV 文件进行提交。
准备数据集
就像我们在第一部分和第二部分中所做的那样,我将开始清理数据并输入空值。这一次,我们将采用一种不同的方法,并结合两个数据集进行清理和输入。我们已经讨论了为什么我们用第二部分的方法估算空值;因此,我们会直接给你代码。如果你觉得有些操作没有意义,你可以参考第二部分或者下面的评论。然而,由于我们在第二部分中看到 18 岁以下的人有更大的生存机会,我们应该增加一个新的特征来衡量这种影响。
数据清理和空值插补
使用 NLP 导出乘客标题
我们将删除不必要的列,并从上面的分类变量中生成虚拟变量。但是首先,我们需要从“名称”列中提取标题。为了理解我们在做什么,我们将从运行下面的代码来获取前 10 行 Name 列值开始。
命名前 10 行的列值
这是我们得到的结果:

图 3。前 10 行的名称列值(按作者排序)
名称列值的结构如下:
, 。<first-name/>
因此,我们需要根据点和逗号分割这些字符串,并提取标题。我们可以通过下面的代码来实现这一点:
拆分名称值以提取标题
一旦我们运行这段代码,我们将有一个标题列,其中包含标题。为了能够看到我们有什么样的标题,我们将运行:
对标题进行分组并获得计数

图 4。唯一书目数量(按作者分列)
似乎我们有四大群体:'先生,'夫人,'小姐,'老爷',以及其他。然而,在将所有其他标题归类为其他标题之前,我们需要注意法语标题。我们需要用下面的代码将它们转换成相应的英文标题:**
法语到英语标题转换器
现在,我们只有军官和皇家头衔。把他们组合成其他人是有意义的。我们可以通过下面的代码实现这一点:
将所有非主要头衔合并为其他头衔(包括军官和皇家头衔)

图 5。最终唯一书目数量(按作者统计)
数据准备的最后一笔
现在我们的标题更易于管理,我们可以用下面的代码创建虚拟列并删除不必要的列:
数据准备的最后一笔
创建用于训练的人工神经网络

图 6。具有两个隐藏层的人工神经网络图(由作者提供)
使用标准定标器标准化我们的数据
为了得到好的结果,我们必须使用 Scikit Learn 的标准定标器来定标我们的数据。标准缩放器通过移除平均值并缩放至单位方差(即标准化)来标准化要素,这与最小最大缩放器不同。标准化和规格化之间的数学差异如下:

图 7。标准化与规范化(作者提供的图表)
我们将选择 StandardScaler()来缩放数据集,并运行以下代码:
扩展训练和测试数据集
建立人工神经网络模型
将我们的数据标准化后,我们可以开始构建我们的人工神经网络。我们将创建一个输入层(密集),一个输出层(密集),和一个隐藏层(密集)。在每一层之后,直到输出层,我们将应用 0.2 的正则化下降来对抗过拟合。最后,我们将使用 Keras 分类器建立模型,将 GridSearchCV 应用到这个神经网络上。因为我们有 14 个解释变量,所以我们的 input_dimension 必须等于 14。由于我们将进行二进制分类,因此我们的最终输出图层必须为幸存或未幸存分类输出单个值。中间的其他单元是“试一试值,我们选择了 128 个神经元。
用 Keras 分类器构建人工神经网络
网格搜索交叉验证
在构建人工神经网络之后,我们将使用 scikit-learn GridSearchCV 来找到最佳参数,并调整我们的人工神经网络以获得最佳结果。我们将使用下面的代码尝试不同的优化器、时期和 batch _ sizes。
基于 Keras 分类器的网格搜索
运行这段代码并打印出最佳参数后,我们得到以下输出:

图 8。最佳参数和精确度
请注意,我们没有在 GridSearchCV 中激活交叉验证。如果您想在 GridSearchCV 中添加交叉验证功能,请在 GridSearch 中选择一个 CV 值(例如,cv=5 )。
用最佳参数拟合模型
既然我们找到了最佳参数,我们可以用最佳参数值重新创建分类器,并用以下代码拟合我们的训练数据集:
用最佳参数拟合
既然我们获得了预测,我们就可以进行最后的操作来准备提交。需要注意的一点是,我们的人工神经网络给出了生存概率,这是一个连续的数字变量。然而,我们需要一个二元分类变量。因此,我们还使用下面的 lambda 函数进行必要的操作,将连续值转换为二进制值(0 或 1 ),并将结果写入 CSV 文件。
创建提交文件
恭喜

图 9。深度学习与旧算法(作者图)
你创造了一个人工神经网络来分类泰坦尼克号乘客的幸存者。只要有大量数据,神经网络就被证明优于所有其他机器学习算法。由于我们的数据集仅由 1309 行组成,一些机器学习算法如梯度提升树或具有良好调谐的随机森林可能优于神经网络。但是,对于具有大量数据的数据集,情况并非如此,如下图所示:
我会说,泰坦尼克号数据集可能位于旧算法优于深度学习算法的交叉点的左侧。然而,我们仍将达到高于 80%的准确率,大约在自然的准确率水平。
订阅时事通讯获取完整代码
既然你正在阅读这篇文章,我相信我们有着相似的兴趣,并且现在/将来会从事相似的行业。那么我们就通过 Linkedin 来连线吧!请不要犹豫发送联系请求!Orhan g . yaln—Linkedin
如果你想获得 Google Colab 上的教程代码和我的最新内容,可以考虑订阅我的 GDPR 兼容 时事通讯 !✉️
软件工程师用卡尔曼滤波器
深入探讨卡尔曼滤波器,有史以来最广泛和最有用的算法之一。

在和我的朋友交谈时,我经常听到:“哦,卡尔曼滤波器……我通常研究它们,理解它们,然后我就什么都忘了”。好吧,考虑到卡尔曼滤波器(KF)是世界上最广泛的算法之一(如果你环顾你的房子,你拥有的 80%的技术可能都有某种 KF 在里面运行),让我们试着一劳永逸地弄清楚它们。
在这篇文章结束时,你将对 KF 的工作原理、背后的想法、为什么需要多种变体以及最常见的变体有一个直观而详细的了解。
状态估计
KFs 是所谓的状态估计算法的一部分。什么是状态估计?想象你有一个系统(姑且把它当做一个黑盒)。这个黑匣子可以是任何东西:你的风扇,一个化学系统,一个移动机器人。对于这些系统中的每一个,我们可以定义一个状态。状态是我们想要知道的变量的向量,它可以描述系统在特定时间点所处的“状态”(这就是为什么它被称为状态)。“能描述”是什么意思?这意味着,如果你知道在时间k的状态向量和给系统的输入,你就可以知道(使用一些系统工作的知识)系统在时间k+1的状态。
例如,假设我们有一个移动的机器人,我们关心知道它在空间的位置(我们不关心它的方向)。如果我们将状态定义为机器人位置(x, y)及其速度(v_x, v_y),并且我们有一个机器人如何移动的模型,这将足以精确定位机器人在哪里以及下一个时刻它将在哪里。
所以状态估计算法估计系统的状态。为什么要估计呢?因为在现实生活中,系统的真实状态是外部观察者永远无法了解的。通常,有两种情况:您可以测量状态,但测量受到噪声的影响(每个传感器只能产生一定精度的读数,这可能对您来说不够)或者您无法直接测量状态。例如,使用 GPS 计算上述移动机器人的位置(我们决定将位置作为状态的一部分),这可能会产生高达 10 米的测量误差,这对于您能想到的任何应用来说可能都不够。
通常,当您进行状态估计时,您可以安全地假设您知道系统的输入(因为它是您给出的)和输出。由于输出是测量的,因此也会受到一定测量噪声的影响。由此,我们将状态估计器定义为一个系统,它接收你想要估计其状态的系统的输入和输出,并输出系统状态的估计。
传统上用x表示状态,用y或z表示输出,u为输入,tilde_x为估计状态。

系统和状态估计器框图。
卡尔曼滤波器
您可能已经注意到,我们已经讨论了一些错误:
- 您可以测量系统的输出,但传感器会产生测量误差
- 你可以估计状态,但是作为一个估计,它有一定的可信度。
除此之外,我说过你需要系统的某种知识,你需要知道系统“行为”的模型(后面会有更多),你的模型当然不是完美的,所以你会有额外的误差。
在 KFs 中,您使用高斯分布处理所有这些不确定性。高斯分布是一种很好的表示不确定事物的方式。你当前的信念可以用分布的均值来表示,而标准差则表示你对自己的信念有多自信。
穿着 KF:
- 您的估计状态将是一个具有特定均值和协方差的高斯随机变量(这将告诉我们算法有多“信任”其当前估计)
- 您对原始系统输出测量的不确定性将用一个均值为 0 的随机变量和一个特定的协方差来表示(这将告诉我们对测量本身的信任程度)
- 你的系统模型的不确定性将由一个均值为 0 的随机变量和一个特定的协方差来表示(这将告诉我们有多信任我们正在使用的模型)。
我们举几个例子来理解这背后的想法是什么。
- 坏模型,好传感器
让我们再次假设你想跟踪一个机器人的位置,你在传感器上花了很多钱,它们给你厘米级的精度。另一方面,你对机器人一点也不感兴趣,你谷歌了一下,发现了一个非常基本的运动模型:随机行走(基本上是一个运动仅由噪声给出的粒子)。很明显,你的模型不是真的好,不能真的被信任,而你的测量是真的好。在这种情况下,您可能会用非常窄的高斯分布(小方差)来模拟测量噪声,而用非常宽的高斯分布(大方差)来模拟不确定性。 - 坏的传感器,好的模型
相反,如果你有坏的传感器(例如 GPS ),但你花了很多时间来为你的系统建模。在这种情况下,您可能会用非常窄的高斯分布(小方差)来模拟模型不确定性,而用非常宽的高斯分布(大方差)来模拟测量噪声。

宽方差与小方差高斯分布。
估计的状态不确定性呢?KF 会根据评估过程中发生的事情来更新它,你唯一要做的就是将它初始化为一个足够好的值。“足够好”取决于你的应用,你的传感器,你的模型,等等。一般来说,KF 需要一点收敛到正确的估计。
KF 是如何工作的?
正如我们所说,为了让 KF 工作,你需要对系统有“一些了解”(一个“不确定的”,也就是不完美的模型)。尤其是 KF,你需要两种型号:
- 状态转换模型:给定某时刻
k的状态和输入,给出某时刻k+1的状态的函数。

- 测量模型:给定某一时刻的状态
k,给出同一时刻的测量值的函数

稍后,我们将看到为什么我们需要这些函数,让我们先看一些例子来理解它们的含义。
状态转换模型
这个模型告诉你你的系统如何随时间演化(如果你还记得的话,之前我们提到过一个状态必须足够描述性才能推断出系统随时间的行为)。这很大程度上取决于系统本身以及你对系统的关注程度。如果你不知道如何为你的系统建模,一些谷歌搜索会有所帮助。对于移动的物体(如果以适当的采样率测量),可以使用恒速模型,假设物体以恒定的速度移动,对于车辆,可以使用独轮车模型等。让我们假设,以某种方式,我们得到了一个模型。我们在这里做了一个重要的假设,这是 KF 工作所必需的:你当前的状态仅仅依赖于先例。换句话说,系统状态的“历史”浓缩在前一个状态中,也就是说,给定前一个状态,每个状态都独立于过去。这也被称为马尔可夫假设。如果这不成立,你就不能仅仅用先例来表达当前的状态。
测量模型
测量模型告诉你输出(可以测量的)和状态是如何联系在一起的。直觉上,您需要这个,因为您知道测量的输出,并且您想要在估计期间从它推断状态。同样,这种模式因情况而异。例如,在移动机器人示例中,如果您关心位置,并且您有 GPS,则您的模型是身份函数,因为您已经在测量状态的噪声版本。
每个步骤的数学公式和解释如下:

那么 KF 实际上是如何工作的呢?该算法分两步工作,称为预测和更新。让我们假设我们在时间k并且我们在那个时间有我们估计的状态。首先,我们使用状态转换模型,我们使估计的状态发展到下一个时刻(1)。这相当于说:给定我当前对状态的信念、我拥有的输入和我对系统的了解,我期望我的下一个状态是这样的。这是预测步骤。
现在,由于我们也有了输出和测量模型,我们实际上可以使用真实的测量来“校正”预测。在更新步骤中,我们取期望状态,计算输出(用测量模型)(2),并与实际测量输出进行比较。然后我们以一种“聪明的方式”使用两者之间的差异来修正我们对状态(3)的估计。
通常,我们用顶点-表示,在校正之前,来自预测步骤的状态估计。 K 称为卡尔曼增益。这才是真正的聪明之处: K 取决于我们对度量的信任程度,我们对当前估计的信任程度(这取决于我们对模型的信任程度),并根据这些信息 K “决定”用度量对预测的估计进行修正的程度。如果我们的测量噪声与我们对来自预测步骤的估计的信任程度相比是“小”的,我们将使用测量来大量校正估计,如果相反,我们将最小程度地校正它。
注意:为了简单起见,我写方程时就好像我们在处理正态变量,但是你必须考虑到,在每一步我们都在处理随机高斯变量,因此我们需要通过函数传播变量的协方差,而不仅仅是均值。
举个例子吧。让我们想象一下,我们正在(再次)跟踪一个机器人的位置。真实位置以灰色显示,在时间k我们认为机器人处于绿色位置,估计协方差表示为椭圆(如果您不熟悉这种表示,请看这里的)。粗略地说,从椭圆的形状可以看出,与向前运动方向上的定位相比,我们的滤波器在这一步对横向定位更有信心。在预测步骤之后,我们使用状态转换模型让系统进化,我们认为新的位置是红色的。由于椭圆在横向方向上变得更大,我们现在对新的估计位置不太确定(例如,因为我们不太信任模型)。然后我们读取我们的全球定位系统,我们得到了黑色的位置。利用更新步骤,实际位置估计将是深绿色虚线。如果我们更信任模型(与测量噪声协方差相比更低的协方差),则估计将更接近红色,或者如果我们更信任测量(与模型不确定性相比更低的噪声测量协方差),则估计将更接近测量。

KF 算法每一步的实际位置和估计的例子。
KFs 家族
根据 KFs 使用的模型类型(状态转换和测量), KFs 可以分为两大类:如果模型是线性的,就有线性卡尔曼滤波器,而如果模型是非线性的,就有非线性卡尔曼滤波器。
为什么有区别?假设你的变量是高斯型的,当通过线性函数时,高斯型变量仍然是高斯型变量,如果通过非线性函数,这就不成立。这打破了卡尔曼假设,因此我们需要找到修复它的方法。
历史上,人们发现了两种主要的方法:用模型作弊和用数据作弊。如果你在模型中作弊,你基本上是将当前估计值周围的非线性函数线性化,这样你就把自己带回了工作的线性情况。这种方法被称为扩展卡尔曼滤波器 ( EKF )。这种方法的主要缺点是你必须能够计算出f()和h()的雅可比矩阵。或者,如果你用数据作弊,你使用你的非线性函数,但是然后你试着“高斯化”(如果这个词存在的话)你做的非高斯分布。这是通过一种称为无味变换的智能采样技术实现的。这种变换允许您用均值和协方差来描述(近似地)分布(只有高斯分布才由前两个矩完全描述)。这种方法叫做无迹卡尔曼滤波 ( UKF )。理论上,UKF 优于 EKF,因为与线性化模型得到的近似相比,无迹变换给出了结果分布的更好近似。在实践中,你必须有相当大的非线性,才能真正看到大的差异。
KF 在行动
既然说了这么多关于一个带 GPS 的移动机器人,我就针对这个案例做了一个简短的演示(想玩的话可以在这里找到代码)。使用独轮车模型生成机器人运动。用于 KF 的状态转换模型是一个恒速模型,其状态包含 x 和 y 位置、转向角及其导数。
机器人正在及时移动(黑色显示的真实位置),在每一步你都会得到一个非常嘈杂的 GPS 测量,它会给出x和y(红色)并估计位置(蓝色)。您可以尝试不同的参数,看看它们如何影响状态估计。如你所见,我们可以进行非常嘈杂的测量,并得到真实位置的良好估计。

KF 在行动:一个机器人的真实路径(黑色)是用来自噪音测量(红色)的 KF(蓝色)跟踪的。
奖励:卡尔曼增益的直观意义
让我们看看线性 KF 情况下的卡尔曼增益公式,并尝试更深入地了解增益是如何工作的。

其中P_k是当前估计状态的协方差(我们对估计有多有信心),C是测量模型的线性变换,使得y(k) = Cx(k)和 R 是测量噪声的协方差矩阵。请注意,分数符号并不真正正确,但它使可视化发生的事情更容易。
根据等式,如果 R 变为 0,则我们有:

代入我们定义的算法步骤(3),我们可以看到,我们将完全忽略预测步骤结果,并且我们使用测量模型的逆变换来获得仅来自测量的状态估计。
相反,如果我们非常信任模型/估计,P_k将趋向于 0,给出:

因此,我们有一个与预测阶跃输出相同的最终估计。
需要注意的是,我交替使用了“信任模型”和“信任当前估计”。它们并不相同,但它们是相关的,因为我们对预测步骤的估计的信任程度是我们对模型的信任程度的组合(因为预测步骤是仅使用模型完成的),加上我们对先前过滤步骤的估计的信任程度。
额外收获 2:图书馆
有很多很好的在线计算 KFs 的库,这里是我最喜欢的一些。
作为一名围棋爱好者,我将从这个非常好的围棋库开始,它有几个预先实现的模型:
为具有非均匀时间的连续时间索引模型实现卡尔曼滤波和平滑的软件包…
github.com](https://github.com/rosshemsley/kalman)
对于 Python,可以看一下https://pykalman.github.io/。
结论:我们深入了解了什么是状态估计,卡尔曼滤波器如何工作,它们背后的直觉是什么,如何以及何时使用它们。我们介绍了一个玩具(但现实生活中的)问题,并看到了如何用卡尔曼滤波器解决它。然后,我们更深入地了解了卡尔曼滤波器的实际功能。
干杯!
空手道俱乐部一个用于图形表示学习的 Python 库

空手道俱乐部是一个无监督的机器学习扩展库,用于 NetworkX Python 包。
空手道俱乐部 由最先进的方法组成,对图形结构化数据进行无监督学习。参见此处的文档。简单来说就是小规模图挖掘研究的瑞士军刀。首先,它提供了节点和图级别的网络嵌入技术。第二,它包括多种重叠和非重叠社区检测方法。实施的方法涵盖了广泛的网络科学 (NetSci,Complenet) 、数据挖掘 (ICDM,CIKM,KDD) 、人工智能 (AAAI,IJCAI) 和机器学习 (NeurIPS,ICML,ICLR) 会议、研讨会和著名期刊的文章。
一个简单的例子
空手道俱乐部让现代社区探测技术的使用变得相当容易(参见这里的附带教程)。下面的代码片段在合成图上使用了重叠社区检测算法。

设计原则
当我们创建空手道俱乐部时,我们使用了面向 API 的机器学习系统设计观点,以便制作一个终端用户友好的机器学习工具。这种面向 API 的设计原则需要一些简单的想法。在本节中,我们将通过适当的示例详细讨论这些想法及其明显的优势。
封装的模型超参数和检查
通过使用适当的 Python 对象的构造器来创建无人监管的空手道俱乐部模型实例。这个构造函数有一个默认的超参数设置,允许合理的开箱即用模型使用。简单地说,这意味着最终用户不需要非常详细地理解内部模型机制就可以使用我们框架中实现的方法。我们设置这些默认的超参数来提供合理的学习和运行时性能。如果需要,这些模型超参数可以在模型创建时用构造函数的适当参数化来修改。超参数存储为公共属性,以允许检查模型设置。

我们通过上面的代码片段演示了超参数的封装。首先,我们想用标准的超参数设置为一个由 NetworkX 生成的鄂尔多斯-雷尼图创建一个嵌入。构建模型时,我们不改变这些默认超参数,我们可以打印尺寸超参数的标准设置。第二,我们决定设置不同数量的维度,因此我们创建了一个新模型,并且我们仍然可以公开访问维度超参数。
类的一致性和不扩散
空手道俱乐部中的每个无监督机器学习模型都是作为一个独立的类来实现的,它继承了 估计器类 。在我们的框架中实现的算法具有有限数量的公共方法,因为我们不假设终端用户对与特定技术相关的算法细节特别感兴趣。通过使用fit()方法来拟合所有模型,该方法采用输入(图形、节点特征)并调用适当的私有方法来学习嵌入或聚类。节点和图嵌入由get _ embedding()公共方法返回,集群成员通过调用 get_memberships() 检索。**

在上面的代码片段中,我们创建了一个随机图,以及带有默认超参数的模型,我们使用 publicfit()方法拟合这个模型,并通过调用 publicget _ embedding()方法返回嵌入。通过更改模型导入和构造函数,这个示例可以被修改为创建一个walk lets嵌入,只需很少的工作—这些修改导致了下面的代码片段。******

看这两个片段, API 驱动设计 的优势是显而易见的,因为我们只需要做一些修改。首先,必须改变嵌入模型的导入。第二,我们需要改变模型结构,默认的超参数已经设置好了。第三,由 DeepWalk 和 Walklets 类提供的公共方法行为方式相同。用 fit() 学习嵌入,并由 get_embedding()返回。 当用于特征提取的上游无监督模型表现不佳时,这允许对代码进行快速和最小的改变。
****标准化数据集摄取我们将空手道俱乐部设计为在模型拟合时使用标准化数据集摄取。实际上,这意味着具有相同目的的算法使用相同的数据类型进行模型训练。详细地说:
- 基于邻域和结构节点嵌入技术使用单个 网络 x 图 作为 fit 方法的输入。
- 属性节点嵌入过程以一个 NetworkX 图 作为输入,特征表示为一个 NumPy 数组 或一个 SciPy 稀疏矩阵 。在这些矩阵中,行对应于节点,列对应于特征。
- 图级嵌入方法和统计图指纹以 NetworkX 图 的 列表作为输入。
- 社区检测方法使用一个 NetworkX 图 作为输入。
高性能模型力学
图形挖掘算法的底层机制是使用广泛可用的 Python 库实现的,这些库不依赖于操作系统,并且不需要其他外部库的存在,如 TensorFlow 或 PyTorch 的存在。空手道社内部的图形表示使用 NetworkX 。密集线性代数运算用 NumPy 完成,它们的稀疏对应使用 SciPy 。隐式矩阵分解技术利用 GenSim 包,依赖图形信号处理的方法使用 PyGSP。
标准化输出生成和接口
空手道俱乐部 的标准化输出生成确保了用于相同目的的无监督学习算法总是以一致的数据点排序返回相同类型的输出。这个设计原则有一个非常重要的结果。当某种类型的算法被相同类型的算法替换时,使用上游无监督模型的输出的下游代码不必改变。具体来说,使用我们的框架生成的输出使用以下数据结构:
- 节点嵌入算法 (邻域保持、属性化和结构化)调用get _ embedding()方法时,总是返回一个 NumPy 浮动数组 。数组中的行数是顶点数,行索引总是对应于顶点索引。此外,列数是嵌入维数。
- 全图嵌入方法 (谱指纹,隐式矩阵分解技术)返回一个 Numpy 浮动数组 当get _ embedding()方法被调用。行索引对应于单个图形在输入图形列表中的位置。同样,列表示嵌入维度。
- 社区检测程序 返回一个 字典 当get _ memberships()方法被调用时。节点索引是关键字,对应于关键字的值是顶点的社区成员。某些图聚类技术创建节点嵌入,以便找到顶点聚类。当调用get _ embedding()方法时,这些返回一个 NumPy 浮点数组 。该数组的结构类似于节点嵌入算法返回的数组。
我们通过下面的代码片段演示了标准化的输出生成和接口。我们创建随机图的聚类,并返回包含聚类成员的字典。使用外部社区库,我们可以计算这些集群的模块性。这表明标准化的输出生成使得与外部图形挖掘和机器学习库的接口变得容易。

限制
空手道俱乐部目前的设计有一定的局限性,我们对输入进行假设。我们假设 NetworkX 图是无向的,由单个 强连通分量 组成。所有算法都假设节点是用整数连续索引的,起始节点索引为 0。此外,我们假设图不是多部分的,节点是同质的,边是不加权的(每条边有一个单位权重)。
在整个图形嵌入算法的情况下,图形集中的所有图形必须修改先前列出的关于输入的要求。基于 Weisfeiler-Lehman 特征的嵌入技术允许节点具有单个字符串特征,可以使用 特征 键访问该特征。如果没有这个关键字,这些算法默认使用度中心性作为节点特征。
人工智能时代的卡尔·马克思

Robynne Hu 在 Unsplash 上的照片
人工智能会验证卡尔·马克思吗?
如果一个自由社会不能帮助许多穷人,它就不能拯救少数富人。——约翰·肯尼迪
人工智能的短期影响取决于谁来控制它,而长期影响则取决于它是否能被控制。——斯蒂芬·霍金
人类即将迎来人类历史上最重大的发展之一。人工智能算法和机器人技术已经对人类努力的几乎每一个领域进行了革命性的变革。但是机器人和算法会取代我们所有的工作吗?
迄今为止,卡尔·马克思的预言被证明是错误的。在发达经济体中,共产主义革命尚未发生,无产阶级专政尚未建立,资本主义也没有崩溃。但是新技术的出现可能会在 21 世纪证明马克思是正确的。
马克思的预言
arx 的预言基于几个前提。第一个是永久失业阶层的形成,即“劳动力后备军”,这是由于资本家引入了节省劳动力的技术,在竞争的压力下,他们不得不通过削减工资或采用新技术来降低生产成本。工业后备军的存在对就业者的工资施加了向下的压力,从而降低了工人的生活质量。马克思认为,由于技术进步,永久失业阶层的规模随之扩大,苦难和剥削也随之增加。
马克思主义分析的第二个假设是市场集中度上升,因为较弱的公司被较强的公司取代。
对马克思来说,垄断和“技术失业”人数的增加导致了不平等和人民贫困化的快速增长,然后人民开始革命并推翻政府。(这是对马克思预言的粗略概述:我不会在这里关注理论本身的缺陷。)
因此,马克思预测的正确性取决于技术对就业市场的影响。这反过来又取决于人性的基本方面。
我们无法预测即将到来的变化的确切时间、速度和范围;然而,因为这些结果取决于人类,我们可以勾勒出潜在的最终结果:要么新技术将完全取代人类,要么一些工作将留给我们来完成。在后一种情况下,适当的措施可以防止重大的社会动荡,并帮助我们过渡到一种新的社会。在前一种情况下,人类将逐渐失去价值,超级智能算法的出现将标志着进化史的转折点。
几千年来,关于现实本质的问题,虽然在哲学上很重要,但在现实世界中几乎没有用处。但是现在我们人类的未来取决于答案。
现实的本质
如果宇宙是一元论的,计算机可以有意识并且有能力在就业市场上完全取代人类。拜伦·里斯在《第四时代》中指出,如果是二元论,一些工作将留给人类,因为我们与人工机器的性质不同。
一元论(也称为唯物主义或物理主义)认为物质和精神、身体和精神之间没有区别:只有一种终极物质。一元论者认为,我们只是以各种方式相互作用的原子群。我们没有自由意志。换句话说,人类是机器:无生命物质和有生命物质之间没有区别,因为我们都是由原子组成的。一元论者否认灵魂的存在。DNA 的共同发现者弗朗西斯·克里克在他的评论中总结了一元论的观点,“你,你的快乐和悲伤,你的记忆和你的野心,你的个人认同感和自由意志,实际上只不过是神经细胞及其相关分子的巨大集合的行为。”
相比之下,二元论认为某种东西区分了人和无生命的物体,人和动物,物质和精神。我们是活的物体,而不是死的机器:我们不仅仅是一堆原子。在我们身上有一些至今无法理解和辨认的东西,我们可以称之为灵魂或意识。
二元论最著名的支持者之一是哲学家弗兰克·卡梅伦·杰克逊,他设计了玛丽的房间思想实验。玛丽是一位才华横溢的科学家,她知道关于颜色的一切,包括光子的性质,它如何触发大脑对世界的感知,哪些波长刺激视网膜的特定反应等。然而,她一生都呆在黑白房间里,从灰色屏幕上学习颜色。如果她走出房间,看到真实的世界,她会学到新的东西吗?如果是这样的话,经历一些事情和了解一些事情是不同的,在这个世界上有一些事情是科学无法解释的——这证明了这个世界是二元论的。
一元论的结果
斯蒂芬·霍金赞同一元论的观点,他认为,“生物大脑所能达到的和计算机所能达到的并没有很大的区别。因此,从理论上来说,计算机可以模仿人类的智力,甚至超越它。”
如果宇宙是一元论的,机器人和算法迟早会在就业市场上完全取代人类。因为,如果人类是没有灵魂或意识的机器,随着技术的进步,算法将逐渐超过我们,并执行目前由人类执行的所有任务:从在工厂工作和提供食物到创作艺术作品和写书。
正如尤瓦尔·赫拉利在 21 世纪的 21 个教训中所写的,“从长远来看,没有一个工作会绝对不受自动化的影响”,包括那些涉及情感的工作,比如艺术,因为“情感不是某种神秘的现象——它们是生化过程的结果”。
根据一元论的推理,技术已经超越了我们的身体能力,取代了许多简单的机械工作。现在它开始侵入认知能力的领域:例如,算法已经能够比人类更好地检测出癌症。因此,随着技术变革步伐的加快,越来越多的人将会失业。如果我们不采取行动,不可能的共产主义革命可能会成为现实。
在没有政府干预的情况下,不平等性无疑将大幅上升,绝大多数人口的生活水平将下降。由于人工智能行业的垄断趋势,行业竞争者也将减少(领先公司从用户那里获得更多数据,从而改进算法,使产品更好,吸引更多用户,等等)。).这符合马克思的预测,即新技术的引入导致永久失业阶层的形成和更高的不平等。
此外,预计人口将在未来几十年开始下降,从长远来看——比如说,几个世纪后——人类物种可能会灭绝,为由算法统治的世界秩序铺平道路。
二元论的结果
这是最悲观的情况。但是,如果我们假设宇宙是二元论的,那么算法将承担大部分工作,但需要复杂身体能力或社交技能的工作将留给我们。
在这种情况下,可能会有大量的失业人员,一支工业后备军,但只有一些工作会自动化,而不是像一元论范式中的所有工作。
二元论者声称,机器不具备同理心、创造力或批判性思维。二元论者也可能认识到,即使科学揭穿了灵魂、自由意志等的存在。,将人类置于与机器相同的水平,科学或人类思维使用传统的科学方法所能理解和研究的东西是有限的。
弗里德里希·尼采认为,“不可理解的……不一定是不聪明的”,因为可能存在“一个逻辑学家被放逐的智慧王国”我们人类无法从整体和复杂性上把握世界,这就是为什么我们求助于使用理论结构,其中最重要的是语言、数学、逻辑、理性和科学。这些都是认识现实的具体方法。
但是,会不会有一些理论结构无法捕捉的东西,一些将人类与宇宙中其他物体区分开来的东西?毕竟,我们首先是一个善于思考的物种;我们思考这些关于我们存在的基本问题的事实本身可能就是我们不是机器的证据。正如一个老笑话所说,如果我们只是一群原子,那么研究原子的科学家只是一堆原子在研究其他原子。但也许人类不仅仅是一群原子:也许有一些东西让我们与众不同——无论是创造力、灵魂还是意识——科学还无法掌握,而“一堆原子”由于其简单性也永远无法理解。但是,套用 E. M. Pugh 的话来说,如果我们大脑的设计简单到足以让我们理解它,那么我们的大脑就太简单了,无法破译我们的内部运作。因此,我们永远无法确定我们完全了解自己。
因为,正如纳西姆·塔勒布所言,“没有证据并不等于没有证据”:我们所能理解的是有限的,而且,如果我们用生物化学过程来解释生命,这并不一定意味着我们的存在完全由生物化学决定。如果我们不知道某件事,这并不一定意味着某件事(灵魂或意识)不存在。
自由市场能拯救我们吗?
T2:二元论并不像一元论那样描绘出一幅黯淡的未来图景。根据二元论观点,如果没有外部力量,我们将面临技术领域的失业,但不会有大规模的就业,让我们 99.99%的人缺乏资源。
在二元情景中,有两种可能性:自由市场的力量将抵消自动化的负面影响,只需要最少的政府干预(例如,对一些工人进行再教育或在他们转向新工作时提供临时社会福利);或者,实质性的政府干预(某种形式的普遍基本收入)将变得必要。
有理由认为,自由市场可以在政府干预最少的情况下消除技术革命的负面影响。
自动化不是零和游戏。即使我们失去了很多工作,由于我们的多才多艺和创造力,我们可以创造出无限的新工作。纵观历史,新技术不断被引入,并预计会导致大量失业,但从长远来看,就业率一直保持相当稳定。我们从来没有失业,因为人们总是想出新的事情来做。正如约翰·肯尼迪所说,“如果人们有能力发明新的机器让人们失业,他们就有能力让这些人重新工作。”
世界经济论坛的这项研究预测,到 2022 年,人工智能将创造约 1.33 亿个工作岗位,并消除约 7500 万个工作岗位,净增加 5800 万个工作岗位(该研究没有解决长期后果)。
我们是否会面临大规模失业还远未确定,因为通过降低消费者成本,新技术将让公民有能力在其他商品和服务上花更多的钱,从而推高总需求并鼓励生产者扩大生产从而创造更多就业。
新技术的效应将更加平均地传播,每个人都将有机会相对容易地向社会阶梯的顶端移动。
拜伦·里斯(Byron Reese)认为,我们不会面临令人担忧的高技能劳动力缺乏和大量低技能失业工人的局面。比方说,如果对人工智能工程师的需求上升,但收银员被机器人取代,我们就不必将收银员重新培训为人工智能工程师。相反,大学教授可以成为人工智能工程师;博士候选人可以填补教授的工作;博士生的工作可以由高中教师来完成;中学或小学教师可以从事中学教师的工作,等等。最后,我们的收银员,经过一番努力,可以在小学教编程,让机器人去执行单调、枯燥、不人道的收银员工作。由于科技的发展,每个人都可以提升社会地位,并看到收入的增加。这是看不见的手在起作用。
此外,由于莫拉维克悖论,新技术不会只影响蓝领工人。
莫拉维克原理指出,出于进化的原因,机器人革命的步伐将比人工智能革命的步伐慢,因为我们很难复制机器人经过数十万年进化磨练的能力,如感觉运动技能,而我们最近开发的能力,如抽象和数学推理,更容易重现。这就是为什么算法已经击败了国际象棋冠军,并比人类更好地检测癌症,而机器人仍然无法在人类的水平上踢足球。正如李开复在《人工智能的超能力》中所说,“人工智能擅长思考,但机器人不擅长移动手指。”正如汉斯·莫拉维克写道:“让计算机在智力测试或玩跳棋时表现出成人水平的表现相对容易,但在感知和移动方面,让它们拥有一岁儿童的技能却很难或不可能。”
蓝领工作需要体力劳动,这使得机器人很难取代他们,而许多低技能的白领工人(职员、办公室辅助人员、股票经纪人等。)已经被算法取代了。因此,至少在机器人革命获得动力之前,我们不应该期望不相关的阶层(如果它形成的话)仅仅由低工资工人组成。
麦肯锡的研究证实了莫拉维克悖论。据麦肯锡称,到 2030 年,对“办公室支持”工作(金融和 IT 工作者、行政助理)的需求将下降 20%,而对“不可预测的体力工作”(机械安装、维修和农业田间工作)的需求预计将增长 6%。
由于机器人革命将比人工智能革命慢,工人阶级将而不是受到人们可能预期的严重打击。关键的挑战将不是工作稀缺,而是需要对人们进行再培训和再教育。
然而,自由市场是否能够独自抵消自动化的负面影响,这是有争议的。技术迟早会在大多数技能上超过我们,取代大多数工作。自由市场可能会在短期内帮助我们,但从长期来看,工作岗位将会越来越少,政府需要采取行动来抵消负面影响。
让我粗略总结两种潜在的未来情景:
一元论:所有工作都将自动化。要么(a)算法将创造一个新的后人类世界秩序,要么(b)人类将利用人工智能和生物技术来升级自己,在算法统治的时代生存下来。
二元论:绝大多数工作将会自动化,但有些会留给我们。要么(a)需要政府采取重大行动,要么(b)由于自由市场,政府干预将是有限的,甚至是不必要的。
自由市场资本主义及其敌人
道德马克思主义者可能会援引新技术的出现以及由此导致的大规模技术失业,作为将生产手段集中在国家手中的理由。例如,Y. Varoufakis 建议我们必须“撕毁生产资料私有制的旧观念,并强制进行变革,这必须包括机器、土地和资源的社会所有权。”
但是,即使我们面临大规模失业,对生活在贫困线以下的人征收负所得税或全民基本收入也没有理由不能解决这个问题。新技术将如此富有成效,以至于即使是适度的累进税也能为那些受到新技术负面影响的人提供资助。生产手段的国有化对于解决技术带来的问题并不重要。
马克思的预言不会在二十一世纪实现。卡尔·马克思相信“政治的无能”和政府无力改变体制。但是,在十九世纪和二十世纪,发达国家政府采纳了社会主义计划的精华部分,从而使共产主义变得无关紧要(比如,德国总理奥托·冯·俾斯麦向西方引入了政府资助的社会计划体系)。
这场革命并非不可避免,只要我们解决这个体系的缺陷。即使马克思的预测在我们今天最接近实现,但由于人工智能行业的垄断趋势和由此产生的技术失业,如果我们采取正确的步骤,马克思的“历史命运的必然规律”将不会实现,就像过去一样。
与此同时,威权主义者认为,在经济规划中实施人工智能将消除对自由市场的需求。他们说,供求力量在决定产品的内在价值方面非常强大,但通过分析有关经济、人们的需求和偏好的数据,算法可以用来模拟价格机制。弗里德里希·哈耶克(Friedrich Hayek)认为,由于关于世界的知识分散在许多参与者中,无法获得这些知识的中央计划者将在商品和服务的定价和分配上做出错误的决策。但是多亏了人工智能 T2,中央计划者能够获得和使用这样的信息。正如阿里巴巴创始人马云所说,“大数据将使市场变得更加智能,并使计划和预测市场力量成为可能,从而使我们最终实现计划经济。”
然而,问题是,尽管人工智能驱动的中央计划和对公民的极权控制可能擅长决定消费者的欲望,从而决定产品的真实价格,但它仍然缺乏资本主义制度的创新,正如本文指出的那样。因为消费者如何告知人工智能规划师他们对尚不存在的产品的渴望?正如史蒂夫·乔布斯的名言,“消费者不知道他们想要什么,直到我们向他们展示。”
打破过去的模式并在旧知识的基础上创造全新的东西是不可能的:进步的产生要归功于那些敢于挑战传统智慧的人打破旧习惯。如果人工智能驱动的中央规划者将他们的经济决策建立在过去的数据基础上,那么由此产生的经济将不会是创新的:创新大多(尽管不总是)来自独立的发明家——像托马斯·爱迪生、詹姆斯·瓦特、莱特兄弟、亚历山大·贝尔、比尔·盖茨、史蒂夫·乔布斯、埃隆·马斯克和马克·扎克伯格——而不是来自政府资助的项目。
集中计划还会消除许多市场参与者之间的竞争所带来的优势。国家对经济的控制通常会导致经济停滞和缺乏创新。自由推动创造力和非传统思维,鼓励伟大的头脑追求未知,拓展我们理解的边界。自由市场并不完美,在某些情况下,应该由有限的政府干预来补充——但是,即使在人工智能时代,它们仍将是继续我们技术进步的最佳方式。我们不应该成为专制辩护者的牺牲品,他们声称算法会让自由市场过时。
寻找意义
任何工作都是如此没有人性和危险,以至于出于人道的原因,我们应该愿意把它们交给机器人和算法。正如比尔·盖茨所说,“技术正在释放我们对人类同胞与生俱来的同情心。”技术将帮助我们发现我们是谁,并使我们能够从事真正适合人类的活动,从而促进我们发现自己的真实本性。在 AI 接管大多数任务并授权我们追求让我们真正成为人类的东西之后,我们最终将不再纠结于不断优化和满足我们的物质需求。
对卡尔·马克思来说,社会的最终状态可以用“各尽所能,按需分配”的原则来定义新技术可以提供我们所有的个人需求,同时让我们从事我们选择的努力。
马克思认为,在社会发展的某个阶段,当新技术的生产力足以满足每个人的需求时,共产主义是可能的。我们不应该否认人工智能和机器人技术可以提供这种技术的可能性。然而,尽管看起来很矛盾,但马克思在某种意义上是一个自由意志主义者,因为他厌恶国家,并将一个无国家的社会想象为我们的最终目的地,拥有足够的资源最终让人类获得马克思所认为的真正自由——摆脱物质必要性和国家庇护和压迫的自由,以及自由从事非物质追求的能力。
为未来做准备
如果人工智能和机器人开始对我们现有的社会体系构成根本性挑战,我们不应该反对有限和合理的国家干预。采取教条式的自由放任态度既是妄想,也是危险的。正如 Friedrich Hayek 在通往奴役之路中所写的,“自由主义者的论点是支持尽可能充分地利用竞争的力量,作为协调人类努力的一种手段,而不是作为让事情保持原样的论点。”
在自由民主国家,政治制度的存在是为了确保弱者和少数人受到保护,免受多数人的暴政统治。无限制的自由违背了它自己的目的,因为对一个人如何行使自己的自由缺乏限制常常导致侵犯他人的权利。
因此,在经济学中,就像在政治中一样,绝对不受限制和约束的自由放任政策是不可取的。正如国家对社会和政治自由的行使加以限制,以确保自由不会弄巧成拙,为了确保公平和捍卫正义,国家应调控经济,并对人民的经济自由加以某些限制,以维护其他人的权利和自由,因为“如果一个自由社会不能帮助许多穷人,它就不能拯救少数富人。”因此,经济干预主义不是限制,而是保护人民的自由。
人工智能时代将带来历史上最全面的发展,我们不应屈服于开放社会敌人的思想的常年吸引力。人工智能时代将给我们的文明带来相当大的压力,但我们不应该屈服于压力,而是应该永远记住,正如丹尼尔·德德尼和 g .约翰·伊肯伯里所说的那样,“对自由民主问题的补救措施是更自由的民主,自由主义包含着自我救赎的种子。”认识到自己的易错性,愿意与他人进行理性的对话以试图更接近真相,将真相置于意见之上,通过承认所有群体利益的两党共识来解决社会弊病——这些都是捍卫我们社会的工具。
我们创造了这个世界:我们不能将我们的责任外包给历史命运的法则。即使存在这样的规律,它们也是我们自己思考的产物:如果我们想证明错误,证明马克思的悲观预测再次错误,我们就必须准备采取必要的措施。
历史不会朝着一个特定的方向前进,但是人们会并且能够改变自己的进程。正如卡尔·波普尔所说,“虽然历史没有终点,但我们可以把我们的终点强加给它;虽然历史没有意义,但我们可以赋予它意义。”
原载于 Areo 杂志
保持 Jupyter 笔记本运行,即使浏览器关闭
保持 Jupyter 笔记本运行的方法及其缺点
连续几天打开浏览器标签来运行 Jupyter 笔记本文件并不是最令人兴奋的工作。可能会很麻烦。以下是我找到的一些解决问题的方法。每种解决方案都有其优点和缺点,所以不再多说,让我们开始探索每一种解决方案吧!

使用 Google Colab
协作实验室,或简称为“Colab”,允许我们在没有配置和计算资源(如 GPU / TPU)的情况下运行 Python 代码。使用它,我们甚至可以通过在 CLI 命令前添加前缀%来运行一些 bash 命令。这种方法的好处是它是免费的,允许从 Drive 或 Github 导入文件/数据集。它与 Google Drive 很好地集成在一起,我们可以编写代码来自动从 Drive 加载一些数据集,并将网络/结果保存到 Drive。
然而,它有几个缺点。首先,它有有限的计算使用量。一旦达到限制,它将停止运行代码,不久之后,文件/变量值将丢失。然而,极限并不是限制性的。我发现这对于在一些数据集上训练神经网络来说已经足够好了,比如叶子分类数据集。此外,如果您需要更大的计算使用/资源,可以连接到一个本地运行时。
另一个缺点是你不能关闭浏览器标签太长时间,也就是超过 90 分钟。根据我的经验,这可以通过连接到一个本地运行时来延长。
最后,当选项卡关闭时,它可能会丢失写入的日志。当您需要将所有日志都写入 Jupyter 笔记本文件时,这可能是一个问题。处理这种情况的一些方法是将输出记录到另一个文件中,或者使用特定的记录器。
将其作为 python 脚本运行
有多种方法可以将 Jupyter 笔记本文件作为 python 脚本运行。
1。将其转换成 python 文件
最简单的方式是在浏览器中打开 Jupyter 笔记本文件,点击文件>下载为> Python(。py)。之后,我们可以像运行典型的 python 文件一样运行输出文件:
python file_name.py
但是,记录在 Jupyter 笔记本上的文件会丢失。
2。直接使用命令提示符运行
另一种方法是直接使用 CLI 运行 jupyter 笔记本。它将允许我们在整个执行过程中将所有日志记录打印在 jupyter 笔记本文件中。为此,有两种程序可供选择, runipy 或 nbconvert 。要安装 runipy 或 nbconvert,我们可以使用 pip/conda 。
# Using pip
pip install ipython
# Using conda
conda install ipython
如果我们使用 runipy 并安装了它,要运行 jupyter 笔记本,我们可以键入:
runipy MyNotebookFileName.ipynb
要将每个单元格的输出保存回笔记本文件,请运行:
runipy MyNotebookFileName.ipynb
如果我们使用并安装了 nbconvert,要运行 jupyter 笔记本,我们可以键入:
jupyter nbconvert --to notebook --execute mynotebook.ipynb
对于 runipy 和 nbconvert ,在这两个站点中还可以找到其他几个配置选项,如超时、报告生成和输出文件生成。
为了保持这个命令在远程服务器上运行,即使我们与远程服务器断开连接,我们可以配置 screen 或 tmux ,并在其中任何一个中运行 Jupyter 的命令。
然而,我发现这种方法的一个缺点是缺少向用户显示的日志记录。因此,即使脚本会错误地停止执行,也很难跟踪代码的进度。当我使用这种方法时,我利用 nvidia-smi 和 htop bash 命令来尝试猜测程序的当前状态。
使用远程桌面到服务器
这是迄今为止我最喜欢的方法。TLDR,它处理了以前方法的所有缺点。它允许我看到代码的进度以及每个单元的输出。即使当我断开连接时,脚本也保持运行。
1。在服务器上配置远程桌面
如果服务器已经配置了远程桌面,您可以跳过此步骤。这一步可能是所有步骤中最棘手的一步,尤其是当服务器的操作系统版本过时时。
a.通过 SSH 连接到服务器
b.安装一些软件包
sudo apt update
sudo apt install -y ubuntu-desktop xrdp
PS:如果你在服务器上没有 sudo 权限,或者,你可以使用wget从 Github 安装这个包,然后从源代码编译它。如果下载的xrdp版本有一些错误或者与操作系统不兼容,你可能也需要这样做来降级xrdp的版本。
c.在服务器上编辑 RDP 配置文件/etc/xrdp/xrdp.ini。最低配置可能如下所示:
[globals]
bitmap_cache=yes
bitmap_compression=yes
port=3389
crypt_level=low
channel_code=1
max_bpp=24
[xrdp1]
name=sesman-Xvnc
lib=libvnc.so
username=ask
password=ask
ip=127.0.0.1
port=ask-1
请注意所写的端口,这对于建立连接非常重要。此外,如果您的服务器是 EC2 实例,我们需要适当地编辑安全组,以允许端口3389中的入站 TCP 连接。
d.重新启动 xrdp
sudo service xrdp restart
e.为 RDP 连接安装窗口管理器。这包括更改用户的.xsession文件的内容。
sudo apt install -y xfce4 xfce4-goodies
echo xfce4-session >~/.xsession
您已经准备好连接了!💃🏽💃🏽
2。在您的计算机中设置远程桌面客户端
这一步将允许您的计算机连接到服务器。根据您电脑的操作系统,操作方法会有所不同。
对于 Linux,安装 vinagre 并打开。输入服务器的 IP 地址、用户名和 RDP 端口。然后,单击连接。
对于 Windows 或其他系统,可以使用远程桌面查看器完成上述步骤。

我的 Kali Linux 计算机上的远程桌面查看器
对于 Mac,我使用的是微软远程桌面。正确填写表格,然后单击添加。

Mac 版微软远程桌面。
之后,系统会提示您输入凭据。让港口保持原样。

xrdp 登录表单
一旦你通过认证,你应该会看到你的桌面。

远程桌面!
3。在服务器的浏览器中运行 jupyter 笔记本
这可以通过在终端中键入jupyter notebook来完成,这将打开一个浏览器。然后,在浏览器中导航到相应的 jupyter 笔记本文件并将其打开。
单击工具栏上的单元格>全部运行。

然后关闭远程桌面客户端应用程序。切记不要关闭浏览器!😉😉
全部完成!现在,您可以让浏览器在远程桌面上运行,并随时断开连接。您也可以通过重新连接来检查程序的进度。
保持数据科学项目的正常运行
办公时间
速赢如何为突破赢得时间
你的数据科学项目时间不多了,你还没有取得突破。预测建模充满了不确定性,但企业不理解这一点,或者更糟的是,不在乎。你需要传递一些东西,而且要快。你有什么选择?

他们称之为数据科学是有道理的
数据科学工作是实验性的。很多在规划阶段看起来可行的项目,最终都会失败。也许输入数据的预测性不如预期。或者目标变量不一致且定义不当。或者你不能得到你想要的数据。项目可能会因为超出您控制的原因而失败,因为没有人会预料到数据问题。
但是其他项目失败是因为你在取得改变游戏规则的突破之前没有时间了。
如何不去追逐突破
你担心如果你的模型不够好,它将永远不会出现。这使得用复杂模型追逐突破变得很有诱惑力。
最近就中了这个圈套。我的团队试图根据一系列记录和损失信息来预测保险索赔何时结束。尝试使用简单的文本表示以及最新的损失信息快照未能产生可接受的模型。所以我尝试用伯特向量来特征化文本,并通过一个递归神经网络来传递损失信息的完整时间序列。这是一个死胡同。我对此并不后悔,但它耗费了一个多月的开发时间。
增值
交付增值是敏捷软件开发的核心原则。现在,我已经听到了无数反对在数据科学团队中使用敏捷的观点。我将把我的反驳留到下一天,但是增量价值的这个方面是解决我们的小突破-最后期限困境的关键。
我将分享一些你可以交付给企业的速赢,这些速赢可以为你赢得宝贵的时间,直到实现突破。
快速成功案例
部署基准模型
你的模型的第一个版本不需要完美。一个天真的或者基准模型通常比什么都没有对用户更有价值。下面是一些可能有用的基准模型的例子。
- 均值或中值模型—对于回归任务,一个始终预测均值或中值的简单模型可能比没有要好。你甚至可以通过预测组内的平均值来加强它。
- 过去等于未来—对于预测任务,考虑发布一个简单的模型,预测过去将完全等于未来。这个基准很难被超越。
- 最受欢迎—对于推荐任务,很难比预测所有用户最受欢迎的商品更好的了。先考虑出货这个基准。
- 发挥创造力——您能为您的任务想出一个可能部分解决客户问题的基准模型吗?
当然,如果您决定发布一个基准模型,设定对业务的期望是很重要的。验证模型的第一个版本中的低客户信任不会有长期的影响也很重要。
解决一个子问题
你最终要解决的问题可能层次很高或者范围很广。在这种情况下,逐步解决和交付问题的组成部分是可能的。
让我们回到前面提到的保险索赔问题。预测索赔何时结束实际上范围很广。有许多不同类型的索赔和许多不同的原因,每种索赔都会比预期的时间长。例如,有律师参与的索赔肯定会比没有律师参与的索赔耗时更长。因此,如果我们可以将问题的范围限制在预测律师参与的风险,建模工作将变得更加容易处理,并且仍然为客户提供价值。
做一些工程
在一天结束时,你必须展示你和你的团队正在为客户创造价值。如果上面的快速胜利对你来说不是一个选项,考虑通过贡献代码或任何类型的数据到产品中来展示你是一个多么有团队精神的人。即使在最好的时期,数据科学和软件或数据工程之间的界限也可能是模糊的。如果你认为这能给你带来足够的善意和空间,让你最终取得突破,那就好好利用这一点。
这可能意味着挑选一些与部署模型或创建数据管道相关的票证。或者这可能意味着对自己的业务逻辑的更大承诺,每个人都知道这应该属于工程,但他们没有时间来构建(我在两家不同的公司看到过这种情况,所以我假设这是常见的)。
明智地追求突破
现在,您已经为产品带来了一些立竿见影的效果,并为自己赢得了几个月的时间。去追求突破,明智地使用你辛苦挣来的时间。
通过数据测试保持数据整洁
对您的数据进行测试,并满怀期望地提高您的管道质量

在软件工程中,用特定于语言的框架编写测试是减少错误和提高代码质量的最佳实践。然而,在数据科学和数据工程的世界中,您正在构建的管道和模型的质量不仅仅取决于编写的代码,它主要取决于您正在使用的数据。在本文中,我们将看到如何为我们的输入数据编写测试,以避免不愉快的意外。因此,我们可以保证我们的机器学习模型或建立在这些数据上的 ETL 管道的正确行为。
在本文中,我们将关注 Python 代码,并使用 great-expectations 包进行测试。我们将专注于 Pandas 数据帧,但是 PySpark 和其他工具的测试也受到了 great-expectations 的支持。
测试示例数据集
对于这个例子,我决定使用来自约翰·霍普金斯大学系统科学与工程中心(CSSE)的新冠肺炎数据。
为什么是这个数据集?我使用这个数据集是因为它由几个批次组成。有一个。自 Covid 19 开始以来每天的 csv 文件。数据的质量和信息量随着时间而变化。因此,我们可以在特定日期可用的数据子集上构建我们的测试。随后,我们可以将这些测试应用于新的、看不见的数据,并确保数据内容符合预期。
首先,让我们创建一个所有文件的列表,这些文件是我们希望稍后在管道中加载和使用的:
我们将首先只检查最旧的文件和最新的文件,而不是立即加载所有文件。因此,我们可以看到列的外观,并评估数据质量。
这个仅仅关于列名的概述已经表明随着时间的推移发生了巨大的变化。添加了几个额外的列,并更改了一些列的命名。这意味着我们不能加载所有。csv 文件并连接它们,无需任何额外的预处理步骤。
基于获得的信息,我们可以编写第一个测试来检查我们以后使用的所有列是否都出现在每个文件中:
这里,我们首先用 great_expectations dataset 对象包装了最新数据文件的 DataFrame 对象。这仍然像一个熊猫数据帧,但带来了一些额外的功能。然后,我们用 expect_column_to_exist() 方法创建了第一个测试,称为期望。我们将这种方法应用于 DataFrame 列的定义列表,以确保这些列确实存在。在本例中,我们创建了 5 个期望(5 个不同列的一种期望)。最后,我们创建了一个 expect-config 对象来描述所创建的测试。这个对象可以作为 JSON 文件保存和加载。
到目前为止,我们只创建了这些测试,并将它们保存在一个配置文件中。现在,让我们对我们的两个数据文件应用这些测试,看看它们是否成功:
ge.read_csv() 方法是对应的 Pandas 方法的包装器,并提供了定义期望套件的机会,该套件是我们的配置对象,应该用于数据验证。我们可以用 validate() 应用已定义的测试,并用 success() 检查它们是否成功。结果显示,对最后一个数据文件的测试成功,但对第一个文件的测试失败。这个输出和预期的一样,第一个文件的测试失败了,它有一个不同的列命名。我们可以使用以下命令查看更多详细信息:
在这里,我们迭代每个单独的期望,并检查它是否成功。如果没有,我们将附加信息打印到控制台。输出告诉我们,数据集中没有必要的列“Country_Region”、“Last_Update”和“Active”。我们可以通过简单的列重命名来解决前两个问题。如果缺少“活动”列,则必须进行计算。
必要的数据清理和数据验证可以总结为一个功能:
这个函数做必要的数据准备,如果其中一个定义的测试失败了,就会引发一个错误。否则,它返回有效的 DataFrame 对象。
现在,在成功地检查了基础知识之后,我们可以考虑对各个列进行一些更高级的测试。例如,我们可以检查“确认”、“死亡”和“恢复”列。我们知道这些列都应该是整数类型并且是正数。此外,如果没有有效的“Country_Region”或“Last_Update”条目,则整个数据行将毫无价值。所以我们也应该测试这个。
因为我们已经对最新的数据文件应用了这些测试,所以我们立即发现“Active”列有问题,它包含负值。我们应该在额外的预处理步骤中处理这些情况。
额外的数据清理似乎足以在所有定义的测试中获得成功。现在,我们可以加载所有文件并开始使用它们,而不用担心输入数据中的任何意外行为。
最终注释
Great-expectations 是一个强大的工具,可以帮助您检查数据源的一致性并保证数据质量。有许多预定义的期望,您可以轻松定义自己的期望。本例中显示的内容只是演示基础知识。Great-expectations 提供了很多更有趣、更强大的特性,比如 Data Docs,它可以为您的验证结果创建漂亮的 HTML 结果。查看教程和文档以了解更多信息:
永远要知道从你的数据中能得到什么。远大前程通过数据帮助数据团队消除管道债务…
github.com](https://github.com/great-expectations/great_expectations)
似乎有几种方法可以生成和应用具有很高期望的测试。因为这些技术对我来说也很新,请告诉我,是否有比上面代码中应用的方法更高级的方法。
感谢阅读!
请保持距离

来自 Pexels 的 Anna Shvets 的照片
乱世中保持社交距离的一个例子
免责声明:这篇文章无意引起恐慌。无论是流行病学还是数学建模,我都不是专家。下面采用的方法充满了已知的和潜在的假设。这意味着推动社会距离和自我隔离。这是一篇观点文章,而不是公共政策的建议。
2019 年 11 月:在中国湖北省一个经常被遗忘的城市武汉,人们在潮湿的市场上做着一天的生意,对即将在世界上爆发的浩劫知之甚少。
快进到 2020 年 3 月。
新的一年来了又去,随之而来的是来自中国的关于一种新病原体的第一个故事,这种病原体是世界前所未见的:新冠肺炎。
席卷中国大陆,现在已经遍布全球,几乎就像取自反乌托邦小说。
当它到达我居住的国家印度的海岸时,我不禁感到有点害怕和担心。来自受影响国家的故事是可怕的、沉闷的和绝望的。就在昨天(2020 年 3 月 20 日),意大利经历了最糟糕的一天,一天之内就有近 700 人死于这种可恶的病毒。
我必须承认,我没有把这种威胁当回事,就像我这个年龄段的许多人一样。在午餐时,在走廊的谈话中,以及在 Whatsapp 上,我们经常听到下面的观点。
“哦,如果它感染了很多人,那又怎么样……只有 2%的人死亡。这比中东呼吸综合征或 H1N1 甚至普通流感都要低得多。我们为什么要担心这个?”
事后看来,争论中通常被忽视的是受害者的年龄严重混淆了这一点。
统计理论告诉你要小心数字。请谨慎使用这些数字。对数字要有耐心。
你总是需要哄着数字给出见解。
年龄越大,死亡率越高。且在 65 岁以上显著增高。
新冠肺炎是婴儿潮一代杀手。
就像 20 多岁的普通印度人一样,我童年的大部分夏天都是在祖父母家度过的,我对那些夏天有很多珍贵的记忆。很长一段时间,因为他们的持续存在,我确信他们是不可战胜的。他们会一直在那里。现在,我第一次害怕了。
我非常害怕。
以至于在过去的一周左右,我一直在温习流行病学理论。从梅在 1982 年的论文中引入了基本的再生数 Rₒ,到迪克曼、奥多、汉斯·黑斯特比克和汤姆·布里顿最近的工作,他们形式化了 Rₒ.的定义和性质
这篇文章着眼于采用一种疾病模型,让我们深入了解社会距离和隔离是如何有所帮助的。
确实如此,相当明显。
模拟新冠肺炎:疾病不可能(或者是?)
由于这个系统的数学本质,下面的部分可能会很枯燥。我会尽我所能,尽量保持内容简洁。然而,并不是所有的数学都可以被过滤,所以请原谅我。
在这一部分中,我们将尝试为德国共享的数据拟合模型。同样的分析可以在其他国家进行,只要数据是公开的,不用担心抽样偏差和代表性偏差。
在这个关键时刻,重申以下事实是至关重要的,即这一分析和研究结果绝不是对现实的准确描述,仅仅因为各种假设在现实生活中变得无效。
最终,这一分析应该会促使读者呆在家里。为做出这样的决定感到骄傲和满意。
在模拟新冠肺炎时,我们不是在模拟个人可能性。我们没有足够的公开数据。我们正在尝试的是在传染病的行为下建立人口模型。
虽然有各种各样的模型( R: earlyR,EpiEstim ),但我们将实现的模型是其中最简单的。模型越复杂,内部工作的假设就越多;在当前疫情肆虐、威胁生命的情况下,我不会做出任何我不完全理解的假设。
我们采用的模型称为 SIR 模型。1927 年在《皇家统计杂志》上首次讨论,它是一个动态模型,将人口/军政府分成三大组:
- 易感:任何没有被感染但可能被感染的人都被认为是易感者
- 受感染:任何感染并传播疾病的个人都被认为是受感染的
- 移除:任何因康复、隔离或死亡而不在感染或易感类别的个人被视为移除
这个模型的一个关键假设是感染保证了未来的免疫力。所以像流感这样的疾病不能用 SIR 框架来建模,而水痘和麻疹可以。截至目前,新冠肺炎还没有表现出任何康复病人复发的行为。
此外,我们不做任何假设人口的生命。这些是出生率,以及由新冠肺炎病毒以外的原因导致的死亡率。
从一个群体到另一个群体的运动受一组微分方程支配。

SIR 模型下的状态运动
这些方程很重要,因为它们求解的参数。
β、γ是该模型中最重要的两个元素。
- β控制着接触率,即每个感染者每天被感染的平均接触次数
- γ控制每天的清除率或恢复/死亡/隔离人员的比例
在最近的公共政策术语中,
- β是控制你的社交距离的参数(β越低,联系越少)
- γ控制你的自我隔离策略(γ越高,传染期越短)
- 总的来说,rₒ=(β/γ)∞每个原发病例对应的继发病例数
如果在这篇文章的结尾有什么是你应该记住的,那就是这个。
降低你的贝塔系数,增加伽玛系数。句号。
解了这些方程,你就能理解疾病是如何发展的。
现在,我可以听到你说“够了,理论…真正的模特在哪里?
我们提取了德国的数据,因为他们的数据似乎是维护得最好的(由罗伯特·科赫研究所),通过运行一个简单的 python 脚本,从他们的维基百科页面提取数据。其他被考虑的国家有意大利和美国。
注:印度的数据不完整,人们担心该国的测试是否充分。西班牙某些天的数据不完整。
抛弃时间序列索引,我们采用从第一天开始的天数表示法。让我们绘制数据。

使用 Python 的**scipy** 模块,我们求解常微分方程,得到β和γ的估计值。
def SIR(y, t, N, beta, gamma):
S, I, R = y
dSdt = -beta * S * I / N
dIdt = beta * S * I / N - gamma * I
dRdt = gamma * I
return dSdt, dIdt, dRdt
def loss(parameters, data, method='l2'):
size = len(data)
beta, gamma = parameters
init_conditions = S_0, I_0, R_0
t = np.arange(0, size)
ret = odeint(SIR, init_conditions, t, args=(N, beta, gamma))
S, I, R = ret.T
if method == 'l2':
return np.sqrt(np.mean((I - data) ** 2))
elif method == 'l1':
return np.mean(abs(I - data))
elif method == 'RSS':
return np.sum((I - data) ** 2)
# optimization using the L-BFGS bounded optimizer
optimal = minimize(
loss,
[0.5, 0.5],
args=(df.total_confirmed_cases.values, 'l2'),
method='L-BFGS-B',
bounds=[(0, 1), (0, 1)]
)
在对未来 50 天(总计 80 天)做出预测后,让我们评估模型的拟合度。
我们得到的 RMSE 为 625, MAPE(平均百分比误差)为 23%。

考虑到模型拟合不算太差,我们能看出什么?
- Rₒ = 1.9 ≈ 2
- β = 0.65
- γ = 0.35
这与世卫组织估计的 2 比 2.5 略有出入。
德国监测传染病的联邦公共卫生组织罗伯特·科赫研究所(Robert Koch Institute)估计,新冠肺炎的基本生殖数在 2.4 到 3.3 之间。
常规疾病研究认为,如果 Rₒ > 1,那么这种疾病应该被认为是一种流行病。(咄)
那现在怎么办?
如何控制 Rₒ?

如果你还记得上一节提到的,有两种方法可以减少 Rₒ:
- β必须减少。这更容易分析和模拟。
- γ必须增加。这更难做到,因为你在和疾病的传染期玩游戏。
但在探讨为什么我们必须降低 Rₒ之前,让我们先画一条大家都很熟悉的曲线。

是的,臭名昭著的珠穆朗玛峰从现在常见的“平坦曲线”的讨论。
让我们评估一下,如果我们采取一种简单的策略来疏远自己,会发生什么。比方说,今天在德国进行了一些社交距离干预,在接下来的 n 天中,联系率降低了 50%,之后,更谨慎地降低了 20%。换句话说
- β = βₒ if t < 21st March, 2020
- β = 0.5βₒ if t ≥ 21st March, 2020 and t < n days from 21st March
- β = 0.8βₒ if t ≥ n days from 21st March
Now, we can change n 对于各种配置如:7 天,14 天。
当我运行这个模拟时,模型的行为方式让我大吃一惊。

曲线变平了!
如今,这些干预措施中争论最激烈的部分之一是时机。在上述模拟中,我们从当天(即 2020 年 3 月 21 日)开始将联系率降低 50%。在图上,这是第 26 天。
如果这发生在疫情高峰期,比如说第 40 天,接近 2%的人口被感染,会发生什么?

瞧啊。
2%可能看起来不多,但这是针对整个德国人口的。可怜的 2%相当于 160 万人。
因此,在新冠肺炎问题上,早期干预是有益的。
从上面的可视化中可以注意到一点,随着干预的进行和感染人数的下降,易感的人数仍然很大。这意味着一旦干预结束,就要更加谨慎。正如上面模拟的那样,β值的轻微下降也会导致感染的显著增加。
这是一个相当简单的策略,只取决于时间。
如果可以获得不同年龄的数据,可以形成针对年龄组和人口统计细分的策略,并以模拟的形式进行测试。
摘要
总而言之,
- 社交距离是好的,但是越早越好。
- 隔离自己是好的,但是越早隔离越好。
- 以上两项在当前至少 14 天内都是必须的,以减轻医疗保健系统的压力。
在局势得到控制之前,不值得冒险与人交往。
最后一点,重要的是要指出这个分析纯粹是说明性的。当然,我们使用了实际数据,并使模型与之相适应。但是疾病建模有如此多的细微差别,我没有这方面的专业知识。此外,鉴于此次疫情,考虑到检测的频率,人们对数据的质量提出了质疑。
这些是影响样本的偏差因素,我们必须认识到这一点。
本文中使用的简单 SIR 模型有许多局限性。然而,在我们现在谈论的大规模爆发中,这种简化似乎是可以接受的。
此外,它假设个体之间是同质混合的,这太简单了。例如,我们可以将人口按照他们的位置分成不同的年龄组,并对他们之间的相互作用进行建模。这可能会更真实地反映人口是如何形成的。
同样,为了使曲线变平的效果可视化,我认为一个简单的模型是可以的。
从这里得到的启示并不是模型已经预测了一切,我们都在劫难逃。没有一个模型是正确的。
相反,关注社交距离有多重要。关注自我隔离能有什么帮助。拉平曲线。
呆在家里,注意安全。
文献和参考资料:
- 迪克曼、奥多、汉斯·黑斯特比克和汤姆·布里顿。2013.理解传染病动力学的数学工具。普林斯顿大学出版社。
- W. O .科马克和 A. G .麦肯德里克。1927."对流行病数学理论的贡献."英国皇家学会学报,A 辑 115:700–721。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
使用 nbQA 保持 Jupyter 笔记本的可维护性

由 Julia Joppien 在 Unsplash 上拍摄的照片
我们数据科学家喜欢 Jupyter 笔记本:它们支持快速原型制作,让我们用代码讲述故事,并允许我们彻底探索数据集。然而,任何试图将 Jupyter 笔记本套件置于版本控制之下的人都会告诉你,它们真的很难维护。
数据科学家喜欢 Jupyter 笔记本电脑…
这有许多原因,例如:
- 实现快速原型制作
- 让你用代码讲故事
- 允许您彻底探索您的数据集
…但是 Python 代码质量工具没有!
如果我们想使用以下任何一种优秀的工具:
[flake8](https://flake8.pycqa.org/en/latest/)(风格指南强制执行)[pylint](http://pylint.pycqa.org/en/latest/)(建议重构,带来代码味道)[mypy](http://mypy-lang.org/)(检查静态类型注释)- 还有很多很多…
然后,我们需要放弃我们非常喜欢的 Jupyter 笔记本,转而使用 Python 脚本。
我们能两全其美吗?
是啊!
[nbQA](https://github.com/nbQA-dev/nbQA)允许你在 Jupyter 笔记本上运行任何标准的 Python 代码质量工具。就像你通常在 Python 脚本上运行flake8一样:
my_script.py:1:1: F401 'pandas as pd' imported but unused
[nbQA](https://github.com/nbQA-dev/nbQA)允许您在 Jupyter 笔记本上运行它!
my_notebook.py:cell_1:1:1: F401 'pandas as pd' imported but unused
查看此演示,了解一些示例:

作者图片
用作提交前挂钩
如果你使用预提交,这里有一个例子,告诉你如何编写一个钩子,根据black格式化你的笔记本,检查它们是否遵循flake8,并用mypy对它们进行类型检查:
nbQA 还能做什么?
查看 nbQA 文档了解如何配置[nbQA](https://github.com/nbQA-dev/nbQA)以及它能做什么。
再也不要写不可维护的 Jupyter 笔记本了
如果您将[nbQA](https://github.com/nbQA-dev/nbQA)集成到您的工作流程中(参见文档中关于如何使用[pre-commit](https://pre-commit.com/)或在持续集成期间使用它的示例),那么您将能够保留 Jupyter 笔记本的所有优点,而不必牺牲它们的可维护性。
保持数据的包容性,同时不稀释您的结果
性别案例研究:如何将数据公平纳入数据分析?

假设您正在调查 10,000 人中的 100 人。你想分析你的 100 人样本的数据,以得到关于整个 10,000 人的可能行为和偏好的答案。
你项目的一部分关注性取向的公平。你不想遗漏任何人,而且你知道,在人们选择“异性恋或同性恋”的情况下,提出一个关于性取向的问题是不够全面的。你咨询了专家和当地社区,决定在这个问题中包括“异性恋、同性恋、女同性恋、双性恋、泛性或无性”选项。
一旦你的回答来了,你就有了来自这些类别的回答者的数据,然而只有少数回答者被确定为双性恋,只有一个人分别被确定为泛性和无性。当试图分析这些数据来代表所有这些取向的反应时,你意识到你从一些类别中获得的数据如此之少,以至于你不能说出关于它们的任何统计相关的东西,你不能从一个人的数据中推断出你的 10,000 人口中所有无性认同者的偏好和可能的观点。
与其完全忽略那些回答很少的类别,不如将它们合并到一个合并的类别中,这样可以更好地代表它们。当你发表你的发现时,你把你的结果框定为异性恋、同性恋和其他,这正是你试图避免的。人们对自己没有得到很好的代表感到愤怒和受伤,并觉得自己被归为“其他”一类。接受您调查的回答者感觉被欺骗了,因为他们被问到了您刚刚组合的详细问题。
这种数据类别的“崩溃”或“合并”一直在发生,不仅仅是性取向。几乎所有的人口统计问题都容易在调查中受到限制,或在分析中被压缩;种族、民族、性别、语言等。想象一下,在一项调查中列出所有可能的口语选项是多么困难,在统计学上又是多么无用。我们怎样才能做到包容而不使少数群体的类别变得如此之小,以至于只有多数群体的数据才具有统计相关性?
竞争优先事项:
- 尊重受访者的多样性非常重要。
- 重要的是你展示的结果在统计学上有意义。
选项 1:折叠
当在初步分析后将数据分类折叠成“异性恋/非异性恋”时,第一个伦理问题是,它将分类框定为异性恋是正常的,而其他人是“其他的”。第二,它以一种他们没有给自己分类的方式给你的回答者分类,去掉了你提供给他们的选择机构。当人们在面向公众的调查中使用大量的包容性类别,只是为了显得具有包容性,掩盖自己与公众的关系,同时计划以任何方式压缩数据时,最不道德的崩溃情况就会发生。
从数学的角度来看,将性取向分成两组是一个问题,因为你的结果会变得不那么准确。男同性恋、女同性恋或双性恋受访者之间的态度和行为可能会有很大差异,这一点很重要,需要衡量和承认。如果你只报道异性恋/非异性恋,你的结果会掩盖这一点。
选项 2:不崩溃
如果你有一堆数据类别,但只有少量的回答,这将降低你对总体人口的统计确定性。当一种身份有数百个回应,而另一种身份只有一个回应时,说类似“73%的异性恋和 88%的无性认同者赞成新法律”的话是不可接受的。你必须用他们的统计置信度来报告你的发现,这几乎总是对应于该类别中的回答者的数量。
因此,不折叠会导致一个问题,即只有大多数类别,即有大量响应的类别,才具有很强的统计意义。你的包容努力实际上削弱了最没有代表性的群体的声音。当然,在许多情况下,你只是在组之间有统计学上的置信度差异。如果您的回答者分三类,分别是 60%、30%和 10%,您仍然可以报告他们中的每一类,只包括他们统计权重的差异。
那么,该怎么办呢?当然,一如既往,答案是“视情况而定。”这取决于你试图回答的研究问题。这取决于和你一起工作的人需要知道什么。这取决于你收集数据的人对他们的代表性有什么感觉。这些只是其中的几个因素。
您可以做什么:
- 在制作调查之前和分析之前,决定如何处理这个。
- 以多种方式报告你的结果,包括折叠、未折叠和混合视角。
- 对你正在与你的数据团队、你的调查受访者和你的听众解决的困境、妥协和选择保持透明。
在创建调查或进行分析之前,在项目设计阶段决定如何处理这个问题是显著增加项目公平性的第一个方法。如果你决定最重要的是在最后有三个类别,有很强的统计可信度,你可以为此设计一个系统。假设您已经预先决定报告前三个类别:最多的回答者、第二多的回答者和所有剩余回答者的组合。这给了你很多优势。它将允许在调查中询问两个或三个以上的类别,从而增加包容性。它将允许你不假设那三个类别是什么;你不知道在所有的调查中,异性恋受访者永远会多于双性恋受访者。它可以让你告诉调查对象你打算如何分析数据,这样当你合并一些类别时,他们就不会感到不公平。在项目设计中有各种各样的方法来解决这个问题,包括包含什么问题,如何加权类别,如何报告类别,等等。提前决定你的项目系统和最佳实践将帮助你回避许多股权问题。
你不必只以一种方式报告你的发现。你可以用一种显示最强统计意义的方式来分解你的结果;也许双性恋者、无性恋者和女同性恋者确实对某个问题有同样的感觉,结合他们的数据会让他们的反应更有说服力。然后也可以单独显示所有类别,同时包括关于统计置信度的信息,以向您的受众显示您的调查确实包括了泛性取向,即使您没有得到该类别中的任何受访者。您可以创建一个混合体,其中一些类别以您认为最有意义的方式折叠。也许你报告了他们回答的交叉类别中的取向:最有可能说是:女同性恋、双性恋和泛性取向;最有可能说不:同性恋、异性恋和无性取向。向你的听众提供所有的信息增加他们对你的报告和方法的信心,同时强化你的结果。
最后,在这个问题上,你必须对项目的所有利益相关者保持透明:从事该项目的人,参与该项目的人,以及你的发现的观众。数据科学与人类在本质上充满了艰难的决策和妥协。不要精心设计调查,从回答者中去除代理,不要隐藏不同类别之间统计置信度的差异,不要隐藏你所做的假设和选择。这可能很难,因为你往往倾向于做这些事情来保护股权。让人们看到你是如何处理这样的问题的,只会增加信任和你的数据项目的真正公平。
原载于 2020 年 1 月 17 日 https://weallcount.com。
“我们都算” 项目分享例子,构建工具,并提供旨在帮助更好地理解数据的培训和教育——以便我们可以使数据对每个人来说更加透明和公平。因为你做数学题的时候,我们都算。
保持我们数据的真实性
完美的数据故事是无聊的故事。它们也是糟糕的科学。

Jr Korpa 在 Unsplash 上拍摄的照片
项目组和我遇到了一个问题。我们的客户在我们帮助优化的广告活动中投入了数百万美元。然后,我们实施了一项跟踪计划,看看这场运动是否奏效。很多事情都取决于它,现在结果出来了。
问题?确实有两个问题。第一个是,虽然这场运动对我们的大多数观众起了作用,但它在一个关键的州不起作用,我们不知道为什么。
另一个问题是,在其他地方,这场运动在也进行得很好。鉴于这场运动的时间跨度很短,其影响高得不合理。这似乎是一个好问题,但事实并非如此。如果我们不相信这些数字,为什么我们的客户会相信?
我们需要对正在发生的事情有一个解释,一个能解释这一切的故事。如果我们找不到,麻烦就在前面。
我们通常热情洋溢地谈论数据故事。我们讨论如何发现改变游戏规则的见解,如何使用出色的可视化技术让这些见解更容易被更广泛的受众所接受。
那都是好的和真实的。但是数据故事也有我们应该更多谈论的黑暗面。
它源于这样一个事实,在本质上,故事是谎言。他们有议程,即使他们有一个真实的核心。他们圆了角落,忽略了不方便的事实。
相比之下,好的数据科学是关于寻找真理的,不管它是什么。这是关于拥抱混乱和细微差别,关于接受有时数据不会产生一个答案,无论我们如何努力。
忽视数据科学和故事之间的紧张关系可能是危险的。它产生了基于糟糕的数据科学的简洁的小故事。为了产生这些数据,数据科学家忽略、合理化甚至隐藏不方便的数据。他们避免问尖锐的问题。这让他们和他们的观众离真相越来越远。
这不是假设的危险。在学术界、医学界和商界,这种情况时有发生。
问题是,那些被抹平的故事甚至都不是特别好。毕竟,数据科学家很少学习讲故事的艺术。就像刚起步的小说家写好人做好事一样,他们讲述了数据完全按照其应有的方式运行的故事。很无聊,毫无意义,也没教会我们什么。
我们如何才能成为更好、更诚实的数据故事讲述者?
作为数据科学家,真理是我们的朋友。它让我们和我们的观众走上了通往成功的最直路。这也造就了更好的故事。这就是为什么保持我们的数据故事的真实性非常重要。
以下几个步骤将帮助您讲述一个美丽而真实的数据故事:
1。先做好准备。
你应该预料到杂乱的数据,你应该对此有一个计划。
在实践中,这意味着现在收集数据,以便以后帮助您以不同的方式分割返回数据。例如,对你的因变量进行多种测量通常是个好主意。这有助于你确定你观察到的模式是由真实的东西驱动的,还是由那个变量的定义驱动的。也会帮你讲更多微妙的故事。例如,程序没有改变 X,但它改变了 y。
你还应该收集你认为可能有重大影响的关键独立变量的数据。这似乎是显而易见的,但要做到这一点尤其困难。我参与了无数的调查,事后我非常希望我们刚才问了一个额外的问题。
2。让你自己和你的观众处于探索奥秘的心态中。
当我们想到阅读或观看一部推理小说时,我们想找出大的答案,但我们也期待一些松散的结局,一些在它结束后让我们继续好奇的东西。这是数据故事的完美心态。
在实践中,当在忙碌的高管面前演示时,你应该总是尽早清晰地阐述你的关键发现,但要在其中加入一些神秘感。例如:“我们发现 X 和 Y 细分市场最有可能购买您的产品。但是我们也注意到了一些奇怪的现象——Y 群体更有可能在工作日的早上购买你的产品。这让我们发现了一些东西,我们相信这可以显著改善您在 Y 细分市场的战略,几分钟后我们将向您展示这一点。”
3。分享你的过程
在演讲中,这不需要花费超过一两分钟的时间,但重要的是要设身处地地为你的听众着想,带他们一起踏上旅程。
例如:“我们对 Y 段的惊人观察使我们假设它是由变量 a 引起的。所以我们研究了它,但排除了它。但后来我们认为变量 B 可能是原因,我们确实发现变量 B 与 Y 群体在工作日早上购买你的产品的倾向密切相关。”
分享你的过程会带来几个真正有价值的好处。首先,它有助于重申你的严谨性,增加你的听众对你的发现的信任。第二,当他们和你一起经历这个过程时,你的观众自然会意识到你的工作不是什么外星火箭科学,而是他们也可以参与的事情。这将鼓励他们提出其他想法和解释,这将改进你的工作,并使整个过程更有吸引力和乐趣。毕竟,你的听众通常比你有更多的领域知识。
4.将遗留问题作为未来调查的机会
像一个真正的谜,有一些松散的结束是一件好事。数据科学是一个迭代过程,在这个过程中,每个答案都可能引发许多其他问题。让你的观众处于一种迭代的心态对他们有好处,对你有好处,也有利于让你的故事越来越接近真相。
回到我的团队,我们有几个选择来处理我们的两个数据问题。最简单的方法就是把它们扫到一边。如果我们无视自己的疑虑,我们就有了一个伟大的成功故事。这种异常状态可以被视为统计噪声。为什么要把事情复杂化?
但是,抛开严重的道德疑虑,讲述这个简单的故事很容易适得其反。如果下一波跟踪数据显示该活动并没有真正发挥作用呢?如果这些问题告诉我们一些重要的事情呢?
所以相反,我们接受了混乱。通过排除替代解释的过程,我们发现有证据表明,该活动确实像看起来那样有效——但只是在一些关键绩效指标(KPI)上,特别是在一些推动大部分改善的微观细分市场上。这为我们的客户提供了比简单的成功故事更有价值和可操作的信息。
至于那个竞选失败的异常状态,无论我们如何努力,我们仍然目瞪口呆。数据很奇怪。
直到我们和客户分享了我们的困惑。我们解释了如何着手试图理清这些混乱的数据。然后美好的事情发生了。客户的州主管沉浸在他所在州的日常现实中,他提供了两个我们通常不会考虑的解释。我们后来在数据中发现了支持这两种观点的证据。
我们以一个既好又诚实的故事结束了那场演讲。这不是一个完美的故事,它有一些松散的结尾,但这就是好的数据故事的全部。
保管东西。秘密
向黑客大军隐藏 API 密钥的指南。

照片由卢瑟·博特里尔(https://unsplash.com/photos/EsBufnuK4NE)拍摄
作为一名数据科学家或软件工程师,在你的职业生涯和个人项目中,你将不可避免地与 API(应用编程接口)进行交互。虽然许多 API 提供“免费增值”服务,允许用户每天免费请求一定数量的请求,但一旦超过这一限制,就会产生巨额账单。北卡罗来纳州立大学(NCSU) 完成的一项研究扫描了 13%的 GitHub 存储库,发现每天都有数千个新的独特代码被泄露。黑客不仅可以为他们不幸的目标积累荒谬的账单,他们甚至可以对国家安全构成威胁。NCSU 能够在一个西欧国家的主要政府机构的网站上找到 AWS 凭证。正如您在本文中可能想到的,我们需要一种方法来保持这些 API 凭证的秘密,同时仍然能够在线呈现我们的代码。
与编程世界中的大多数事情一样,这可以通过几种方式来实现。我将在本文中概述我最喜欢的方法,主要是因为它简单易用。此外,本教程是为使用 Unix 命令行(macOS 或 Linux)的人编写的,但稍加修改也可以在 Windows 操作系统上复制。
制作一个秘密文件夹
我们要保存这些密钥的位置是在我们主目录的一个文件夹中。首先导航到主目录并编写以下代码:
mkdir .secret
这将在主目录中创建一个名为.secret的新目录。“.”意味着这个文件夹是隐藏的,它不会显示在主目录中。如果你想检查它是否确实存在,你可以在主目录中输入ls -a,它会在你所有的其他文件中列出。
创建 JSON 文件
使用您选择的文本编辑器,我的偏好是 Sublime Text ,您现在需要创建一个 JSON 字典,其中包含您给定项目所需的所有 API 键。该结构的一个示例如下所示:
{
"API_Key" : "<YOUR API KEY GOES HERE>"
}
记得把这个文件保存在你的主目录下,扩展名为.json。这就是将文件定义为 JSON 的原因,与代码的格式无关。
将 JSON 文件移动到。秘密目录
在您的主目录中,编写以下代码,将 JSON 文件从主目录移动到我们刚刚创建的.secret文件中。
mv ~/<JSON FILE NAME> ~/.secret/<JSON FLE NAME>
从文件中提取 API 密钥
现在,在你的 python 脚本中,你需要定义一个使用json库来解码 JSON 文件的函数。
剩下的就是使用上面的函数,将文件路径作为参数。要访问该字典中的特定 API 键,只需选择相应的字典键,在本例中为“API_Key”。瞧,API 键现在作为它自己的对象存储在您的脚本中。
这是所有的乡亲。我希望这对你有帮助,在你编码的时候保持安全!
跟上数据工程:数据工程师资源指南

凯文·Ku 在 Unsplash 上的照片
今年早些时候,在 LinkedIn 2020 年新兴工作报告中,数据工程师的角色在美国新兴工作排名中名列第八——年招聘增长率为 33%。最近,Robert Half Technology 的薪酬指南将数据工程列为 2021 年薪酬最高的 IT 工作。根据 Robert Half 的说法,数据工程人才将继续获得高于平均水平的薪酬,因为组织将严重依赖“能够将大量原始数据转化为可操作信息以进行战略制定、决策和创新的个人”
随着对数据工程师需求的增加,数据团队必须准备好合适的工具和资源,以确保该角色保持高效的工作流程,而不是像最近的调查所引用的那样,将大部分时间花在现有系统的维护上。
必须承认,数据工程领域正在快速发展,不断有新的开源项目和工具发布,“最佳实践”也在不断变化,随着企业数据需求的增加,数据工程师比以往任何时候都更加捉襟见肘。不仅如此,数据工程师最近亲眼目睹了数据湖和数据仓库的混合,现代仓库通过将计算与存储分开来模糊二者的区别。这种混合已经将过去的基本“ETL”管道发展成更复杂的编排,经常是从仓库中读取数据和向仓库中写入数据。此外,随着数据科学家和数据分析师同事开始实施他们的工作,数据工程师需要与这些职能部门进行更多协作,并进一步赋予这些角色更多权力。由于所有这些压力和不断的变化,很难跟上这个空间(甚至进入它!).
从播客到博客,以下是资源综述——包括新数据工程师和经验丰富的专业人士——希望了解数据工程领域的最新动态。
数据工程播客
在这个领域,很难有比数据工程播客更贴切的了。每周一集,节奏很容易跟上。然而,跟上主题是另一回事。话题从公司讨论他们的数据架构和技术挑战到深入研究开源和付费产品。
我在下面强调了一些有趣的情节:
Presto Distributed SQL Engine:我们已经如此习惯于聚合数据以备查询,从另一个角度考虑这种模式很有启发性——联合查询执行以查询/组合数据所在的位置。听到这种方法的利弊有助于为数据工程师的工具箱添加另一个工具。
Jepsen: 传奇的 Jepsen 项目一直在深入研究分布式系统是如何设计、构建的,或许最重要的是,它们如何处理故障情况。虽然在堆栈中比普通的日常堆栈更深,但是更熟悉我们所依赖的和正在构建的分布式系统(当我们将多个不同的系统联系在一起时)是一件好事。
非盈利数据专家:本期节目的嘉宾是一家非盈利机构的数据基础设施总监,她分享了在预算严格的情况下处理大量数据源和合规性变化是多么具有挑战性——这是当今初创公司(或本案例中的非盈利机构)的许多数据专家都可以理解和借鉴的。
订阅这个播客是每周花些时间保持领先的好方法。
InfoQ 的大数据
也许播客不是你的风格,或者也许你渴望一周不止一次。如果你正在寻找更多的资源(多种格式,包括播客、文章、演示文稿等等),InfoQ 的大数据部分是一个深入挖掘的好地方。该公司一直在通过创建一个由工程师和从业者组成的编辑社区来为自己命名,而不是记者,其内容反映了这一选择。大数据部分涵盖了广泛的主题,包括人工智能,机器学习和数据工程。虽然它并不完全专注于数据工程,但它是一种了解更多相邻空间的有益方式。
令人惊叹的大数据
我是软件社区创建 GitHub 库的趋势的忠实粉丝,GitHub 库拥有专注于特定领域的精选资源列表(又名牛逼列表)。在我的 Clojure 时代, awesome-clojure 是查找不同数据库适配器或 linters 的绝佳资源。幸运的是,大数据有一个“太棒了”,其中包括数据工程和公共数据集的子部分(这些似乎总是会派上用场)。在该项目大受欢迎之前,监管似乎有点严格;别担心,即使拥有一个庞大的公共数据集列表——例如,在能源领域——也是非常有价值的。
无论是以招聘增长率、业务需求还是工具集的发展来衡量,数据工程领域都在快速发展。幸运的是,可用资源保持同步。虽然很容易迷失在日复一日的项目中,但我已经能够重新燃起热情,并通过后退一步了解更新的范式/技术来跟上这个领域。有了这个资源列表,我希望你们都能找到这样做的起点!
跟上 PyTorch 闪电和九头蛇
我如何使用 PyTorch Lightning 1.1 和 Hydra 1.0 的新特性将我的训练脚本缩减了 50%

努力跟上!— 来源
2021 年 02 月 09 日更新:这个故事是关于 PyTorch Lightning 0.9.0 和 Hydra 1.0.0rc4 的。从那时起,他们已经发布了他们的正式生产就绪版本,我也发布了这个故事的第二版,其中包括了所有最新的变化。我把这个故事留给后人,但请查看第二版*!***
介绍
上周, PyTorch Lightning 0.9.0 和 Hydra 的第四个候选版本 1.0.0 发布了,充满了新功能和大部分最终 API。我认为这是一个很好的机会让我重温我的边项目 Leela Zero PyTorch ,看看这些新版本是如何融入其中的。在这篇文章中,我将谈论这两个库的一些新特性,以及它们如何帮助 Leela Zero PyTorch。我不会在这里过多地谈论关于 Leela Zero PyTorch 的细节,所以如果你想更多地了解我的副业项目,你可以在这里阅读我以前关于它的博文。
PyTorch 闪电 0.9.0
对于 PyTorch Lightning 团队来说,这是一个重要的里程碑,因为他们正在努力工作以发布 1.0.0 版本。它引入了许多新特性和一个更接近最终版本的 API。在我们开始之前,如果你想了解更多关于这个版本的信息,请查看官方的博客文章。如果你想了解更多关于 PyTorch Lightning 的知识,请查看 Github 页面和官方文档。
结果
你有没有发现自己重复地实现*_epoch_end方法,只是为了从你的*_step方法中聚集结果?您是否发现自己在如何正确记录您的*_step和*_epoch_end方法中计算出的指标时被绊倒了?你并不孤单,PyTorch Lightning 0.9.0 引入了一个叫做Result的新抽象来解决这些问题。
Result、TrainResult和EvalResult两种。顾名思义,TrainResult用于训练,EvalResult用于验证和测试。它们的接口很简单:您指定在实例化期间要操作的主要指标(对于TrainResult,要最小化的指标,对于EvalResult,要检查点或提前停止的指标),然后您指定要记录的附加指标。让我们看看它们是如何在我的项目中使用的:
TrainResult 和 EvalResult 有助于您不重复度量记录。
在training_step()中,我指定了要最小化的总损耗,并记录了总损耗(也指定要在进度条中显示)、均方误差损耗、交叉熵损耗以及最后的精度(使用 PyTorch Lightning 的新度量包计算,稍后将讨论)。我不需要编写代码来在纪元级别聚合它们,因为TrainResult会处理这些。事实上,您可以使用TrainResult指定每个指标应该聚合和记录的级别(步骤、时期或两者都有),它会自动为您处理一切。
类似地,在validation_step()中,我指定了用于检查点的总损失,并记录总损失、均方误差损失、交叉熵损失和准确性。同样,我不需要编写validation_epoch_end(),因为聚合和日志记录是由EvalResult处理的。此外,我不需要为test_step()重复我自己,只需调用validation_step()并为要记录的指标重命名键。
得益于Result,您可以立即看到我的代码变得更加简单、可读性更好、可维护性更高。你可以在这里了解更多信息。
韵律学
PyTorch Lightning 团队在 0.8 中继续他们的工作,在 0.9.0 中引入了更多的度量实现。PyTorch Lightning 中的每一个指标实现都是一个 PyTorch 模块,并且有其对应的功能,使用起来非常简单灵活。对于我的项目,我决定集成 accuracy 的功能实现,这只是导入它并在适当的*_step方法中调用它的问题。
函数精度在 training_step()方法中被调用。
PyTorch Lightning 现在包含许多其他指标实现,包括高级 NLP 指标,如 BLEU score。你可以在这里阅读更多关于它的。
照明数据模块
PyTorch Lightning 的另一个棘手问题是处理各种数据集。直到 0.9.0,PyTorch Lightning 对如何组织你的数据处理代码保持沉默,除了你使用 PyTorch 的数据集和数据加载器。这无疑给了您很大的自由,但也使您很难保持数据集实现的整洁、可维护和易于与他人共享。在 0.9.0 中,PyTorch Lightning 在LightningDataModule中引入了一种新的组织数据处理代码的方式,封装了数据处理中最常见的步骤。它有一个简单的接口,有五种方法:prepare_data()、setup()、train_dataloader()、val_dataloader()和test_dataloader()。让我们回顾一下它们在我的项目中是如何实现的,以理解它们的作用。
prepare_data():该方法适用于任何在主流程中必须完成的事情,然后再派生出分布式培训的子流程。下载、预处理或保存到磁盘等任务是这种方法的理想选择。需要注意的一点是,在这里设置的任何状态都不会被带到分布式培训中的子流程,因此您应该注意不要在这里设置任何状态。在我的项目中,我依赖 Leela Zero 来预处理 Go sgf 文件,所以我决定跳过实现这个方法,但是我可以在技术上实现这个方法中的预处理步骤。- setup():该方法用于分布式培训的每个子流程中必须完成的任何事情。您应该构造实际的 PyTorch
Datasets并在这里设置任何必要的状态。在 Leela Zero PyTorch 中,我初始化了我的Datasets,它从磁盘读入数据,并将其转换为张量,并保存为状态。 *_dataloader():这是你初始化DataLoaders进行训练/验证/测试的地方。在我的例子中,我简单地使用在setup()中构建的数据集以及在LightningDataModule初始化期间传递的配置来初始化DataLoaders。
现在,只需要将LightningDataModule转换成trainer.fit()和trainer.test()就可以了。您也可以想象这样一个场景,我为不同类型的数据集(比如国际象棋游戏数据)实现了另一个LightningDataModule,培训师也会同样接受它。我可以更进一步,使用 Hydra 的对象实例化模式,在各种数据模块之间轻松切换。
九头蛇 1.0.0rc4
1.0.0rc4 使 Hydra 更加接近其 1.0.0 正式版本。它包含许多错误修复和一些重要的 API 更改,使该库更加成熟和易于使用。在我们开始之前,如果你想了解更多关于九头蛇的信息,请查看官方网站以及官方文档!
@hydra.main()
您可以将这个装饰器添加到任何接受 OmegaConf 的DictConfig的函数中,Hydra 将自动处理您脚本的各个方面。这本身并不是一个新特性,但是我最初决定不使用这个特性,因为它接管了输出目录结构和工作目录。我实际上使用了 Hydra 的实验性 Compose API 来解决这个问题,我将在后面讨论。然而,在与 Hydra 的创建者 Omry 交谈后,我意识到这不仅不是推荐的方法,而且我还失去了 Hydra 提供的一些很酷的功能,如命令行界面的自动处理、自动帮助消息和 tab 补全。此外,在使用一段时间后,我发现 Hydra 的输出目录和工作目录管理非常有用,因为我不必在 PyTorch Lightning 端手动设置日志目录结构。你可以在 Hydra 的基础教程中读到更多关于这个装饰者的内容。
打包指令
在 Hydra 0.11 中,配置只有一个全局名称空间,但在 1.0.0 中,您可以使用 package 指令在不同的名称空间中组织配置。这允许您保持 yaml 配置文件的平整和整洁,没有不必要的嵌套。让我们来看看 Leela Zero PyTorch 的网络规模配置:
“@package group”表示此配置应在当前组下,在本例中为“网络”。

网络大小配置已按规定添加到“网络”下。请注意“board_size”和“in_channels”来自数据配置(composition!)
如您所见,包指令使您的配置更易于管理。你可以在这里阅读更多关于包指令及其更高级的用例。
实例化对象
Hydra 提供了一个特性,可以根据配置实例化一个对象或调用一个函数。当您希望您的脚本有一个简单的接口在各种实现之间切换时,这是非常有用的。这也不是一个新功能,但它的界面在 1.0.0rc4 中有了很大的改进。在我的情况下,我使用它在网络大小、训练记录器和数据集之间切换。我们以网络规模配置为例。
“大”、“巨型”和“小型”网络的配置
基于所选配置实例化网络。请注意,您可以传入额外的参数来实例化(),就像我在这里对 cfg.train 所做的那样。
NetworkLightningModule对其__init__()、network_conf和train_conf接受两种说法。前者从配置中传入,后者在instantiate() ( cfg.train)中作为额外参数传入。你所要做的就是在命令行中输入+network={small,big,huge}来选择不同的网络大小。您甚至可以想象通过用不同的_target_创建一个新的配置,并在命令行中传递配置名,来选择一个完全不同的架构。不需要通过命令行传递所有的小细节!你可以在这里阅读更多关于这个模式的信息。
撰写 API
尽管 Hydra 的 Compose API 不是编写脚本的推荐方式,但它仍然是编写单元测试的推荐方式,并且非常有用。我用它来为主培训脚本编写单元测试。同样,这并不是一个新特性,但是 Hydra 1.0.0rc4 确实为使用 Python 的上下文管理器的 Compose API 引入了一个更干净的接口(with语句)。
您可以使用 Hydra 的 Compose API 轻松编写配置字典。它有助于保持单元测试的整洁和易于调试。
你可以在这里阅读更多关于 Compose API 的内容,以及如何在这里使用它进行单元测试。
未使用的功能:结构化配置和变量插值
Hydra 1.0.0rc4 中还有很多其他特性我没有利用,主要是因为我还没有足够的时间来集成它们。我将讨论本节中最大的一个问题——结构化配置。
结构化配置是 1.0.0 中引入的一个主要新特性,它利用 Python 的 dataclasses 来提供运行时和静态类型检查,这在应用程序变得复杂时非常有用。我可能会在将来有时间的时候整合它们,所以请继续关注另一篇博文!
结论
我的新旧训练脚本。行数从 56 增加到 28。五折优惠!
自从我写了关于 Leela Zero PyTorch 的第一篇博文以来,Hydra 和 PyTorch Lightning 都引入了许多新的特性和抽象,可以帮助您极大地简化 PyTorch 脚本。正如你在上面看到的,我的主要训练脚本现在只有 28 行,而以前是 56 行。此外,训练管道的每个部分,神经网络体系结构,数据集和记录器,都是模块化的,易于交换。这使得迭代更快,维护更容易,重现性更好,让您可以专注于项目中最有趣和最重要的部分。我希望这篇博文对你“跟上”这两个了不起的库有所帮助!你可以在这里找到 Leela Zero PyTorch 的代码。
跟上贝茨
NLP 镇最受欢迎的家庭

莱昂纳多·大久保俊郎在 Unsplash 上的照片
如果你稍微关注一下 NLP 世界,或者甚至是 ML 新闻,你最有可能遇到 Google 的 BERT 模型或者它的一个亲戚。如果您还没有并且仍然偶然看到这篇文章,那么让我荣幸地向您介绍 BERT——强大的 NLP 怪兽。
伯特是什么?
BERT 代表BI directionalEn coderR表示来自Ttransformers,是 Google 的一个语言表示模型。它使用两个步骤,预训练和微调,为广泛的任务创建最先进的模型。
它与众不同的特点是跨不同下游任务的统一架构——这些是什么,我们将很快讨论。这意味着相同的预训练模型可以针对各种最终任务进行微调,这些最终任务可能与训练的任务模型不相似,并给出接近最先进的结果。

BERT 由两个步骤组成。来源:论文。
正如你所看到的,我们首先在预训练任务上同时训练模型。一旦预训练完成,同一模型可以针对各种下游任务进行微调。请注意,单独的模型针对特定的下游任务进行了微调。因此,单个预训练模型可以在微调后生成多个下游任务特定模型。
伯特建筑
简单来说就是 一堆变压器的编码器 。你可以在我之前的文章中详细了解变形金刚。或者,如果你已经对它有了一些模糊的想法,请查看这个绝对是 BERT 中使用的编码器块的 3D 炸弹图。说真的,你不能错过这个!
或者我喜欢称之为类固醇引起的注意。💉💊
towardsdatascience.com](/transformers-89034557de14)
现在让我们来看看一些我们都不会记得的数字,但是如果没有它们,我们的理解会感到不完整,所以这里什么都不说:
L =层数(即堆栈中的#个变换器编码器块)。
H =隐藏大小(即 q,k 和 v 向量的大小)。
A =关注头数。
- 伯特基 : L=12,H=768,A=12。
总参数=110M! - 伯特大号 : L=24,H=1024,A=16。
总参数=340M!!
什么使得它是双向的?
我们通常通过在一些不相关的任务上训练它来创建语言模型,但是这些任务有助于开发对模型中单词的上下文理解。这种任务通常包括预测下一个单词或彼此非常接近的单词。这种训练方法不能扩展并用于双向模型,因为它会让每个单词间接“看到自己”——当你从相反的方向再次接近同一个句子时,你已经知道会发生什么了。一个数据泄露的案例。
在这种情况下,模型可以轻易地预测目标单词。此外,我们不能保证该模型,如果经过完全训练,在某种程度上已经学会了单词的上下文含义,而不仅仅是专注于优化琐碎的预测。
那么伯特是如何做到双向预训练的呢?它通过使用一个称为屏蔽 LM 的过程来实现这一点。稍后会有更多的细节,所以请继续读下去,我的朋友。
预训练伯特
BERT 模型在以下两个无监督的任务上被训练。
1.掩蔽语言模型(MLM)
此任务启用模型的深度双向学习方面。在此任务中,随机屏蔽(用[MASKtoken 替换)一定百分比的输入标记,模型尝试预测这些屏蔽的标记,而不是整个输入序列。然后,来自该模型的预测标记被馈送到词汇表上的输出 softmax 中,以获得最终的输出单词。
然而,这在预训练和微调任务之间产生了不匹配,因为后者在大多数下游任务中不涉及预测屏蔽词。这通过我们如何屏蔽输入令牌的微妙变化得以缓解。
大约 15%的单词在训练时被屏蔽,但是所有被屏蔽的单词都不会被[MASKtoken 替换。
- 80%的时间用[ 屏蔽令牌。
- 10%的时候用随机代币。
- 10%的时间,未改变的输入令牌被屏蔽。
2.下一句预测(NSP)
LM 并不直接捕捉两个句子之间的关系,而这种关系在许多下游任务中是相关的,例如问答(QA)和自然语言推理(NLI) 。通过对二值化 NSP 任务的训练,该模型被教导句子关系。
在这个任务中,选择了两个句子——A 和 B——进行预训练。
- 50%的时间 B 实际上是 a 后面的下一句话。
- 50%的时间 B 是从语料库中随机抽取的句子。
培训——输入和输出。
该模型同时在上述两个任务上被训练。这是通过输入和输出的巧妙运用而成为可能的。
输入

伯特的输入表示。来源:论文。
该模型需要接受单个句子或明确打包在一个标记序列中的两个句子的输入。作者注意到“句子”可以是连续文本的任意跨度,而不是实际的语言句子。一个[SEP]标记用于分隔两个句子,以及使用一个学习过的片段嵌入来指示一个标记作为片段 A 或 b 的一部分。
问题#1: 所有的输入都是在一个步骤中馈入的——与顺序馈入输入的 RNNs 相反,模型 不能保持输入令牌的排序 。每种语言的词序都很重要,无论是语义上还是句法上。
问题#2: 为了正确执行下一个句子预测任务,我们需要能够 区分句子 A 和 B 。固定句子的长度可能限制太多,并且是各种下游任务的潜在瓶颈。
这两个问题都是通过向我们的原始令牌添加包含所需信息的嵌入并将结果用作我们的 BERT 模型的输入来解决的。以下嵌入被添加到令牌嵌入中:
- 片段嵌入 :它们提供了特定标记所属句子的信息。
- 位置嵌入 :它们提供了单词在输入中的顺序信息。
输出
如何同时预测两个不同任务的产出?答案是通过使用不同的 FFNN + Softmax 层,该层建立在来自最后一个编码器的输出的顶部,对应于期望的输入令牌。我们将最后一个编码器的输出称为最终状态。
第一个输入令牌总是一个特殊分类【CLS】令牌。对应于该令牌的最终状态被用作分类任务的聚集序列表示,并被用于下一句预测,其中它被馈送到预测标签“ IsNext 或“ NotNext ”的概率的 FFNN + Softmax 层。
对应于[ MASK ] tokens 的最终状态被输入 FFNN+Softmax,以从我们的词汇表中预测下一个单词。
微调伯特
通过交换适当的输入或输出,可以对各种下游任务进行微调。在一般情况下,为了训练特定于任务的模型,我们向现有的 BERT 添加一个额外的输出层,并对结果模型进行微调——所有参数,端到端。增加输入/输出层而不改变 BERT 模型的一个积极结果是,只需要从头开始学习最少数量的参数,使得过程快速、成本和资源高效。
为了让你了解它的速度和效率,作者声称,从完全相同的预训练模型开始,论文中的所有结果在单云 TPU 上最多可以在1 小时内复制,在 GPU 上最多可以在几小时内复制。

在各种下游任务上微调 BERT。来源:论文。
在句子对分类和单句分类中,对应于[ CLS 记号的最终状态被用作进行预测的附加层的输入。
在 QA 任务中,在微调期间引入了开始(S)和结束(E)向量。问题作为句子 A 输入,答案作为句子 b 输入。单词 i 作为答案区间开始的概率计算为 T i (对应于第 i 个输入标记的最终状态)和 S(开始向量)之间的点积,后面是段落中所有单词的 softmax。端跨采用类似的方法。
从位置 i 到位置 j 的候选区间的得分定义为 S T i + E T j ,以 j ≥ i 的最大得分区间作为预测
GPT——远房表亲
伯特是产生这些突破性成果的唯一模型吗?不是。OpenAI 的另一个模型,叫做 GPT,已经在网上引起了轰动。
但是很多人没有意识到这两个模型有一个共同点,那就是这两个模型都重用了一个 Transformer 组件。如前所述 BERT 将变压器的编码器部分作为其构建模块。同时, GPT 使用变压器的解码器部分作为其构建模块。

来源:论文。
请注意,由于编码器的双向自我关注,BERT 中的双向连接。与此同时,GPT 的连接只是单向的,从左到右,由于解码器的设计防止查看未来的预测——更多信息请参考变形金刚。
伯特一家
如果我们不把一些工作得很好的东西拿来,并试图重新创造或修改它,那就不是 21 世纪了。伯特建筑也不例外。以下是一些最流行的变体:
- 阿尔伯特 由谷歌和更多-本文描述了参数减少技术,以降低内存减少和提高 BERT 模型的训练速度。
- 罗伯塔 脸书——本文认为最初的 BERT 模型训练不足,并表明经过更多的训练/调整,它可以超越最初的结果。
- ERNIE :百度通过知识整合增强表示——受 BERT 掩蔽策略启发,学习通过知识掩蔽策略增强的语言表示,包括实体级掩蔽和短语级掩蔽。
- 蒸馏伯特——使用 Huggingface 模型蒸馏的较小伯特。
你可以在 the GLUE 排行榜查看更多伯特风格的模特。
结论
- BERT 是一个堆叠变压器的编码器模型。
- 它有两个阶段——预训练和微调。
- 预训练是计算和时间密集型的。
- 然而,它独立于它最终完成的任务,因此相同的预训练模型可以用于许多任务。
- GPT 和伯特没什么不同,是一个堆叠变压器的解码器模型。
- 伯特有许多变种。
参考文献+推荐阅读
- 变压器——如果您想更深入地了解上述编码器/解码器架构。
- 论文——很容易阅读,而且他们也稍微阐述了一些实际的细节。值得一读。
- 杰伊·阿拉玛的博客。
- 官方 GitHub 回购。
- 更多 BERT 车型。
我很高兴你坚持到这篇文章结束。🎉我希望你的阅读体验和我写这篇文章时一样丰富。💖
尽请查看我的其他文章 这里 。
如果你想联系我,我会选择Twitter。
把你的孩子的自行车变成键盘,让他们在隔离期间保持活跃
在这个简短的教程中,我将带你了解将任何自行车变成类似街机的电脑游戏控制器的过程。
尽管没有树立健康生活方式的最佳榜样,我和妻子还是努力吃绿色食品,避免太多垃圾食品,保持身材。另一方面,我们 5 岁的孩子对任何体育活动都不感兴趣,除非这能让他更接近他的(我的……)iPad。
通常情况下,这个问题可以通过做一个孩子来部分解决,这包括大量的跑步,爬山,摔倒…还有最近的骑自行车!但不幸的是,随着新冠肺炎·疫情的出现,我们真的做不到这些。
所以,我把他的自行车变成了键盘。
现在,他可以一边玩他最喜欢的电脑游戏,一边锻炼身体!在这篇短文中,我将带你经历建造你自己的键盘自行车的过程。

基础:
第一步是通过让后轮自由旋转而不接触地面,并允许车把自由转动,将自行车变成室内训练自行车。如果你的孩子被向前推,你不应该进行以下步骤。
旋转踏板时,有许多方法可以让自行车保持在原位。将自行车悬挂在天花板上,在车轮下的地板上挖洞等等。我个人用训练轮来支撑车尾,但这是你发挥创造力的地方,更重要的是,要负责。我有意避免谈论我实现这一部分的太多细节(你可以从本文中的各种图片和 gif 中得到一个很好的想法……),因为确保自行车的安全使用是你的责任。
这个计划

在将自行车固定好以便可以在适当的位置踩踏之后,我们将连接传感器来捕捉后轮的旋转、车把的位置和一些用于额外控制的按钮(这些可以在以后轻松编程以映射任何键盘按键)。来自所有传感器的数据将被 Arduino 捕获和转换,Arduino 将充当键盘,并将击键发送到运行(很可能是赛车)游戏的计算机。
五金器具
我们必须使用一块可以作为 USB 键盘的板。我用的是 Arduino 莱昂纳多。
我使用了 3 种传感器:
1 。 A1302 霍尔效应传感器 —该传感器在接近磁场时会改变其输出电压。我们将使用它将后轮的旋转转换为向前按键。
2。 10K 欧姆线性电位器 —用于将车把方向转换为左/右键。
3。 微动开关 —用作额外控制器。我强烈建议使用这种类型的开关(限位开关),不要使用一些花哨的按钮。这些开关非常灵敏,而按钮有时对孩子来说很难按下。
连接零件
霍尔效应传感器
通过将磁铁放在后轮上,并将传感器靠近(尽可能靠近而不接触车轮),我们可以在磁铁经过传感器时感应到车轮的旋转。我使用了两个等间距的磁铁(即大约 180 度)。

用于连接磁体的尖端-
你可能会找到一个更优雅的解决方案,但我在这里使用的是用塑料包装缠绕磁铁,就像糖果包装一样(我指的是上面 gif 中看到的随着轮子旋转的白色斑点)。然后使用松散的两端将磁铁绑在车轮的辐条上,并用热胶固定。
为了让传感器(这是指 gif 中的红色垂直杆,传感器本身位于其末端)尽可能靠近车轮,我将它安装到一根软线上(我使用了一些重型电线,但任何可以弯曲并保持其位置的电线都可以)。
电位计
电位计需要连接到车把的枢轴点。在那一点上应该有一个内六角扳手的套筒。我使用了一个合适的驱动位,并将其连接到电位计。最初,我的计划是将两部分焊接在一起,但驱动位的可焊性很低(没有)。最后,我拿了一根短吸管(在下面的 gif 中以紫色显示),从两侧粘上电位计和驱动器位,并注入热胶,将所有东西粘在一起。它像岩石一样坚固。

至于把电位计固定在自行车车架上,你还是需要发挥创意。我的解决方案(可以在预告片 gif 和文章结尾的图片中看到,显示了从自行车上拆下的所有组件)是基于制作一个有机玻璃“臂”来固定电位计,可能不适用于您孩子的自行车。这个想法很简单,电位计需要和把手一起旋转。尽管很简单,但实施起来可能相当具有挑战性…
开关
我把其中一个开关放在(冗余的)前轮刹车杆后面,另一个放在不冗余的后轮刹车杆后面,断开这个刹车,这样通过踩刹车来压开关,感觉很自然。

再说一次,我不承担任何责任。如果你觉得你在第一部分做的支撑不够坚固,担心阻碍和/或断开刹车,你可以,也应该把按钮放在别的地方。没有对错,只要舒服安全就好。我把自己限制在两个按钮上,但是你显然可以在板子允许的范围内尽可能的高。
接线

关于提前思考的一个注记。
在完成键盘自行车版本 1.0 后,我开始改进它,确保我可以轻松地断开所有组件,并尽快重新组装它们,这需要一些调整,如果我一开始就想到这一点,就可以避免。我花了将近 2 个小时升级到键盘自行车版本 2.0 ,但是现在用不到一分钟就可以组装/拆卸。

另一点要记住的是什么是固定板的最佳位置。我不经意地把它放在了我儿子上下自行车的一侧。回想起来,我应该选择另一边…
密码
如硬件部分所述,键盘自行车设置由 3 种传感器组成:霍尔效应传感器、电位计和按钮。我将分别解释每个组件的代码。
霍尔效应传感器
当车轮旋转且磁铁经过传感器时,霍尔效应传感器被“激活”,导致输出电压发生变化。对于这一部分,每当电压的绝对变化超过某个阈值(hall_effect_threshold)时,我就打开键(在我的情况下是前进键)。然后我让它一直开着,开始倒数一定的时间(drive_decay_const)。这允许调整你从每个“尖峰”得到的运动量。增加drive_decay_const的值以获得更多的移动。
电位计
在这里,我们基本上试图将转动车把的“模拟”运动转换成“二进制”的左或右点击。如果你只是想做一些小的调整,连续的按压就太戏剧化了,所以转动的量需要用“点击量”来表示。我是通过在设定的时间间隔(interval)激活和取消旋转运动来做到这一点的,这样旋转车把超过某个阈值,就会开始间歇地按压。此外,当按钮被激活时,我增加了一个延迟,这个延迟随着转动的次数而增加。因此,对于更高角度的转弯,按钮将被按下更长的时间(即,每次点击将更长),从而导致更积极的转弯。另外,注意我在设置时初始化了pot_center。这对于电位计从插座上断开的情况很有帮助。不用重新定位中心,你只需重置棋盘,中心就会被重置。
开关
这里没什么特别的。只需更换激活的钥匙,以满足您的需求。这里的代码是为了玩 SuperTuxKart ,这是一个很棒的儿童赛车游戏,但这辆自行车显然可以适应许多其他游戏。我们也用它来演奏《我的世界》,效果很好。
/*
bicycle_keyboard
*/#include "Keyboard.h"
const int hall_effect_threshold = 1 // threshold for hall effect sensor.
const int turn_threshold = 35; // threshold for detecting a left/right movement.
const int drive_decay_const = 100; // drive_decay speed of car (larger => slower decreasing / faster car)
const int turn_decay_const = 0.75; // multiplier for intensity of turn. higher value => sharper turns.
const char button_1_val = ' '; // value for button 1
const char button_2_val = 'n'; // value for button 2
const long interval = 200; // interval for allowing not allowing turns.
const int button_1 = 2; // button_1 pin
const int button_2 = 3; // button_2 pin
int pot_center = 500; // center point for potentiometer. this value is being reset in setup.
int prev_hallSensorValue = 0; // initial value for sensor
const int delay_time = 1; // delay between reads
int drive_decay = 0; // initial drive_decay value
unsigned long previousMillis = 0; // initial value
bool allow_turn = true; // allow turn is a boolean to only allow turns every passing interval
int turn_amount = 0; // initial value
void setup() {
Serial.begin(9600);
Keyboard.begin();
pinMode(button_1, INPUT);
pinMode(button_2, INPUT);
pot_center = analogRead(A1);
}
void loop() {
unsigned long currentMillis = millis();
int hallSensorValue = analogRead(A0);
int pot = analogRead(A1);// Serial.println(hallSensorValue);
// Serial.println(pot); delay(delay_time); // delay in between reads for stability // DRIVE:
if (abs(hallSensorValue- prev_hallSensorValue) >1){
prev_hallSensorValue = hallSensorValue;
Keyboard.press(KEY_UP_ARROW);
drive_decay = drive_decay_const;
}
else{
if (drive_decay <= 0){
Keyboard.release(KEY_UP_ARROW);
}
else{
drive_decay -=1;
}
}if (allow_turn==true){//TURN RIGHT
if (pot < pot_center - turn_threshold) {
Keyboard.press(KEY_RIGHT_ARROW);
}
// TURN LEFT
if (pot > pot_center + turn_threshold){
Keyboard.press(KEY_LEFT_ARROW);
}}
if (currentMillis - previousMillis >= interval) { // interval has passed
previousMillis = currentMillis;
turn_amount = abs(pot-pot_center); // switch allow turn state:
if (allow_turn == true) {
if (turn_amount > turn_threshold){
delay(turn_amount); //keep button pressed longer the more aggressive the turn.
}
allow_turn = false;
} else {
allow_turn = true;
}
// release the turn keys:
Keyboard.release(KEY_RIGHT_ARROW);
Keyboard.release(KEY_LEFT_ARROW);
} //check buttons
if (digitalRead(button_1) == HIGH){
Keyboard.press(button_1_val);
}
else{
Keyboard.release(button_1_val);
} if (digitalRead(button_2) == HIGH){
Keyboard.press(button_2_val);
}
else{
Keyboard.release(button_2_val);
}
}
摘要
最后,我希望我很好地解释了如何制造键盘自行车。如果你选择建立一个,而发现我还没有,不要犹豫,发表评论或给我发消息。
保留您的 mLab MongoDB 实例:从 Heroku 分离。
实践教程
如何在 2020 年 11 月 10 日通过从 Heroku 分离 mLab 来保存你的数据不被删除。

约翰·巴克利普在 Unsplash 上拍摄的照片
如果您使用 mLab 托管的 MongoDB 实例作为 Heroku 附加组件,请花些时间通过分离它来迁移它。分离不需要迁移或对应用程序代码进行任何更改,您的环境变量将保持不变。你仍然需要在 2021 年 1 月 12 日之前迁移,那时 mLab 作为一个整体关闭并终止所有实例。
这是因为 MongoDB 在 2018 年收购了 mLab,并已决定结束服务,以让用户将数据库迁移到 MongoDB Atlas。
我们在 2020 年 7 月 10 日首次发送的电子邮件中收到了这一通知。邮件称,2020 年 11 月 10 日之后,Heroku 将不再支持 mLab 插件。这将导致任何依赖 mLab 的应用程序无法运行,并删除存储在 mLab 上的所有数据。
以下是这封邮件的副本:
亲爱的 Heroku 客户:
我们发现您是以下安装了 mLab MongoDB 附加组件的应用程序的所有者或合作者。请注意,这可能是部分列表。
弗拉斯克-皮蒙戈
mLab 团队已选择停止此附加组件。mLab MongoDB 插件将于 2020 年 11 月 10 日从所有 Heroku 应用中移除。
有许多解决方案可以让我们的软件在云中运行。最简单的是我们将在本文中深入研究的,从 Heroku 附加组件中分离我们的 mLab 帐户。我们可以稍后处理迁移,并将写一篇包含一些选项的文章。我们会在准备好的时候更新文章。
指南:从 Heroku 分离 mLab
步骤 1:登录 mLab 并进入确认屏幕。先别确认!
在 Heroku 上,查看您想要修改的应用程序,然后单击 mLab 插件。这应该会带你到 mLab 的网站。单击帐户。在这里你可以找到右上角的“脱离 Heroku”按钮。这将使您进入下面看到的协议页面。先别确认!
请注意这里的三个要点:
- 你仍然需要在 2021 年 1 月 21 日之前迁移到 MongoDB atlas。换句话说,这种分离是暂时的,我们将在明年一月迁移。
- 您的电子邮件地址将成为 mLab 的管理员帐户,您可以通过电子邮件重置密码来重置您的密码。不幸的是,事实并非如此。在写这篇文章的时候,重置邮件里的 URL 把你带到了一个非功能性的页面。
- 其次,当您从 Heroku 分离时,您的 Heroku 配置变量可能会被自动删除。在你完成这个过程之前,确保你的应用不依赖于任何
MONGO*_URI变量,如果需要的话保存它们。您可能需要重置它们。

协议页面
第二步:从你的 Heroku 配置变量中获取 URI 并保存它
要检查您的应用程序对MONGO*_URI变量,的使用情况,请转到 Heroku.com,然后转到您的应用程序,再转到设置,然后检查您的配置变量。在我们的例子中,我们发现了MONGODB_URI。然后,我们将变量保存在一个文本文件中,以便与我们的 mLab 用户名和部署标识符(位于复选框页面的底部)一起妥善保管。将这些数据保存在文本文件中可以作为备份,以防在此过程中丢失。
这是加倍重要的,因为如果你有同样的问题,密码重置我做的,你也可能无法登录到您的 mLab 管理面板发现 URI。您将需要这些信息来保持您的应用程序正常工作,并在将来进行迁移。
步骤 3:完成 mLab 的分离,接受条款
回到我们在第一步中找到的确认页面。这一次,继续接受条款并确认。
现在,您的 mLab 帐户不再与 mLab Heroku 附加组件相关联。
单击分离后,可能需要一段时间才能在 Heroku 端删除配置变量。现在是从我们的 Heroku 项目中删除附加组件的好时机。
不要注销 mLab,因为您可能无法重新登录。
步骤 4:删除 Heroku 端的 mLab 插件
为此,请单击应用下的“配置加载项”。然后单击 mLab 横幅最右侧的下拉菜单,并选择删除附加组件。

从 Heroku 删除 mLab MongoDB
确认附加组件删除并将其移除。
步骤 5:仔细检查连接字符串在 mLab 端没有改变,如果它被删除,则获取保存的 URI 并将其设置为 Heroku 配置变量
现在我们回到 mLab,看看连接字符串在 mLab 方面是否仍然有效。这可以在 home →MongoDB Deployments 下看到。选择数据库并查看字符串。它与你保存在文本文件中的匹配吗?如果是这样的话,你不需要做任何事情。如果已经更改,请确保在 Heroku config vars 下更新该变量。
第六步:重新部署应用
接下来,您将在 Heroku 上重新部署应用程序。您应该能够通过应用程序访问您的数据库,并通过分离看到持久化的数据。
大功告成!
再一次,这是保持你的数据库在 2020 年 11 月 10 日之后的十分钟快速修复。我们将在后面的文章中进一步研究迁移选项。
Keras 101:一个简单的(和可解释的)用于房价回归的神经网络模型
TL;DR:使用带有神经网络的波士顿数据集预测房价,并采用 SHAP 值来解释我们的模型。完整的笔记本可以在这里找到。
在本帖中,我们将介绍一些数据探索的基础知识,并使用 Keras 构建一个模型,以帮助我们预测波士顿(MA)地区某栋房屋的销售价格。作为这个模型在现实世界中的一个应用,你可以想象成为一个真正的国家代理人,寻找一个工具来帮助你履行日常职责,至少对我来说,与直觉相比,这听起来相当不错。
在这个练习中,我们将使用 Plotly 库,而不是老式的 matplotlib,因为它有更多的交互图,这无疑有助于理解数据。我们还将使用 Scikit-Learn 和 Keras 来构建模型,使用 Pandas 库来操作我们的数据,使用 SHAP 库来为我们训练好的模型生成解释。
导入数据集
在本例中,我们将使用包含波士顿数据集的 sklearn.datasets 模块。您也可以使用 keras.datasets 模块,但是这个模块不包含要素的标签,所以我们决定使用 scikit 的模块。让我们也把它转换成熊猫的数据帧,并打印它的头部。
from sklearn.datasets import load_boston
import pandas as pdboston_dataset = load_boston()df = pd.DataFrame(boston_dataset.data, columns=boston_dataset.feature_names)
df['MEDV'] = boston_dataset.targetdf.head(n=10)
探索性数据分析
熟悉数据集是帮助您理解数据并从结果中得出更好的结论和解释的基本步骤。
首先,让我们绘制一些箱线图,这将有助于我们更好地可视化数据分布中的异常和/或异常值。如果你对什么是盒图以及它如何帮助我们更好地可视化我们的数据分布感到困惑,这里有一个来自 Ross (1977)的简短描述:
在描述统计学中,箱线图是一种通过四分位数以图形方式描绘数字数据组的方法。箱形图也可能有从箱形图(须状图)垂直延伸的线,表示上下四分位数之外的可变性,因此称为箱形图和箱形须状图。异常值可以绘制为单个点。
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import mathtotal_items = len(df.columns)
items_per_row = 3
total_rows = math.ceil(total_items / items_per_row)fig = make_subplots(rows=total_rows, cols=items_per_row)cur_row = 1
cur_col = 1for index, column in enumerate(df.columns):
fig.add_trace(go.Box(y=df[column], name=column), row=cur_row, col=cur_col)
if cur_col % items_per_row == 0:
cur_col = 1
cur_row = cur_row + 1
else:
cur_col = cur_col + 1 fig.update_layout(height=1000, width=550, showlegend=False)
fig.show()
这将输出以下箱线图:

这些结果证实了我们最初的假设,即在一些列中有异常值。让我们为每个特征和目标变量绘制一些散点图,以及它们的截距线:
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import math
import numpy as nptotal_items = len(df.columns)
items_per_row = 3
total_rows = math.ceil(total_items / items_per_row)fig = make_subplots(rows=total_rows, cols=items_per_row, subplot_titles=df.columns)cur_row = 1
cur_col = 1for index, column in enumerate(df.columns):
fig.add_trace(go.Scattergl(x=df[column],
y=df['MEDV'],
mode="markers",
marker=dict(size=3)),
row=cur_row,
col=cur_col)
intercept = np.poly1d(np.polyfit(df[column], df['MEDV'], 1))(np.unique(df[column]))
fig.add_trace(go.Scatter(x=np.unique(df[column]),
y=intercept,
line=dict(color='red', width=1)),
row=cur_row,
col=cur_col)
if cur_col % items_per_row == 0:
cur_col = 1
cur_row = cur_row + 1
else:
cur_col = cur_col + 1 fig.update_layout(height=1000, width=550, showlegend=False)
fig.show()

从这个初步的数据探索中,我们可以得出两个主要结论:
- RM(每所住宅的平均房间数)和 LSTAT(人口的较低地位百分比)与目标变量之间有很强的线性相关性,RM 为正相关,LSTAT 为负相关。
- 有一些包含异常值的记录,我们可以对其进行预处理,以便为我们的模型输入更多的规范化数据。
数据预处理
在我们进行任何数据预处理之前,将数据分成训练集和测试集是很重要的。我们不应该对我们的数据进行任何类型的预处理,而不应该忘记我们不应该将信息从我们的测试集泄露到其他的测试集中。对于这一步,我们可以使用 scikit-learn 中的 train_test_split 方法。在这种情况下,我们将使用 70%的数据用于训练,30%的数据用于测试。我们还设置了一个 random_state 种子,以保证方法的可重复性。
from sklearn.model_selection import train_test_splitX = df.loc[:, df.columns != 'MEDV']
y = df.loc[:, df.columns == 'MEDV']X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=123)
为了向我们的神经网络提供标准化的输入,我们需要执行数据集的规范化。这可以被看作是减少可能由现有特征引起的规模差异的一个步骤。我们通过从数据中减去平均值并除以标准偏差来执行标准化。再强调一次,为了避免测试集的任何信息泄露,这种标准化只能通过使用训练集的平均值和标准偏差来执行。
mean = X_train.mean(axis=0)
std = X_train.std(axis=0)X_train = (X_train - mean) / std
X_test = (X_test - mean) / std
建立我们的模型
由于该数据集中呈现的数据量很小,我们必须小心不要创建过于复杂的模型,否则会导致数据过度拟合。为此,我们将采用基于两个密集层的架构,第一个具有 128 个神经元,第二个具有 64 个神经元,两者都使用 ReLU(整流线性单元)激活功能。具有线性激活的密集层将被用作输出层。
为了让我们知道我们的模型是否正确学习,我们将使用均方误差损失函数,并且为了报告它的性能,我们将采用平均误差度量。
通过使用来自 Keras 的汇总方法,我们可以看到我们总共有 10,113 个参数,这对我们来说是可以接受的。
from keras.models import Sequential
from keras.layers import Densemodel = Sequential()model.add(Dense(128, input_shape=(13, ), activation='relu', name='dense_1'))
model.add(Dense(64, activation='relu', name='dense_2'))
model.add(Dense(1, activation='linear', name='dense_output'))model.compile(optimizer='adam', loss='mse', metrics=['mae'])
model.summary()
训练我们的模型
这一步非常简单:用我们的特征和它们的标签来拟合我们的模型,总共 100 个历元,保留 5%的样本(18 个记录)作为验证集。
history = model.fit(X_train, y_train, epochs=100, validation_split=0.05)
通过绘制损失和平均误差,我们可以看到我们的模型能够学习数据中的模式,而不会发生过度拟合(如验证集曲线所示):
fig = go.Figure()
fig.add_trace(go.Scattergl(y=history.history['loss'],
name='Train'))fig.add_trace(go.Scattergl(y=history.history['val_loss'],
name='Valid')) fig.update_layout(height=500, width=700,
xaxis_title='Epoch',
yaxis_title='Loss')fig.show()

我们训练模型的训练和验证损失。我们可以看到,我们的模型显然能够学习我们的数据模式,而不存在数据过度拟合。
fig = go.Figure()
fig.add_trace(go.Scattergl(y=history.history['mean_absolute_error'],
name='Train'))fig.add_trace(go.Scattergl(y=history.history['val_mean_absolute_error'],
name='Valid')) fig.update_layout(height=500, width=700,
xaxis_title='Epoch',
yaxis_title='Mean Absolute Error')fig.show()

训练集和验证集的训练和验证平均绝对误差(MAE)。
评估我们的模型
为了正确评估我们的模型是否能够在现实世界中工作,我们必须使用我们的测试集来评估它。下面我们通过使用 evaluate 方法以及测试集中的特性和目标来实现。
mse_nn, mae_nn = model.evaluate(X_test, y_test)print('Mean squared error on test data: ', mse_nn)
print('Mean absolute error on test data: ', mae_nn)
这为我们提供了以下输出:
152/152 [==============================] - 0s 60us/step
**Mean squared error on test data: 17.429732523466413
Mean absolute error on test data: 2.6727954964888725**
与传统方法的比较
首先让我们尝试一个简单的算法,线性回归:
lr_model = LinearRegression()
lr_model.fit(X_train, y_train)y_pred_lr = lr_model.predict(X_test)
mse_lr = mean_squared_error(y_test, y_pred_lr)
mae_lr = mean_absolute_error(y_test, y_pred_lr)print('Mean squared error on test data: ', mse_lr)
print('Mean absolute error on test data: ', mae_lr)**Mean squared error on test data: 28.40585481050824
Mean absolute error on test data: 3.6913626771162575**
现在使用决策树回归器:
tree = DecisionTreeRegressor()
tree.fit(X_train, y_train)y_pred_tree = tree.predict(X_test)mse_dt = mean_squared_error(y_test, y_pred_tree)
mae_dt = mean_absolute_error(y_test, y_pred_tree)print('Mean squared error on test data: ', mse_dt)
print('Mean absolute error on test data: ', mae_dt)**Mean squared error on test data: 17.830657894736845
Mean absolute error on test data: 2.755263157894737**
打开黑匣子(也就是解释我们的模型)
有时候,对大多数人来说,一个好的结果就足够了,但是有些情况下,我们需要解释我们的模型用来执行预测的主要组件是什么。对于这个任务,我们可以依靠 SHAP 库,它允许我们很容易地创建我们的特性及其对模型输出的影响的概要。我不会深入 SHAP 的细节,但如果你有兴趣了解更多关于它是如何工作的,你可以查看他们的 github 页面或者甚至看一下他们的 T2 论文。
import shap
shap.initjs()explainer = shap.DeepExplainer(model, X_train[:100].values)
shap_values = explainer.shap_values(X_test[:100].values)shap.summary_plot(shap_values, X_test, plot_type='bar')

从这个简单的图中,我们可以看到对模型输出有影响的主要特征是:
- LSTAT: %人口的较低地位
- RM:每个住宅的平均房间数
- RAD:放射状公路可达性指数
- DIS:到五个波士顿就业中心的加权距离
- 氮氧化物:氮氧化物浓度(百万分之一)——这可能与该地区的绿化程度有关
- CRIM:城镇人均犯罪率
这清楚地证实了我们最初的 EDA 分析,其中我们指出 LSTAT 和 RM 特征与模型结果高度相关。
结论
在这篇文章中,我们已经表明,通过使用神经网络,我们可以轻松地超越传统的机器学习方法。我们还表明,即使在使用更复杂的模型时,与其他技术相比,我们仍然可以通过使用 SHAP 值来解释我们的模型的结果。
此外,我们需要记住,所探索的数据集可能已经过时,为了更好地反映当前的情况,可以执行一些功能工程(如校正通货膨胀的价格)。
参考
波士顿数据集:https://www . cs . Toronto . edu/~ delve/data/Boston/Boston detail . html
scikit learn:https://scikit-learn.org/stable/
熊猫:【https://pandas.pydata.org/】T4
https://github.com/slundberg/shap SHAP 项目页面:
SHAP 论文:https://papers . nips . cc/Paper/7062-a-unified-approach-to-interpretation-model-predictions . pdf
工程师和科学家概率统计导论。https://www . Amazon . com . br/DP/b 007 zbzn 9 u/ref = DP-kindle-redirect?_encoding=UTF8 & btkr=1
Keras 的准确性指标
通过在 Python 中运行简单的实验来理解它们

乌古尔·佩克尔在 Unsplash 上拍摄的照片
介绍
Keras 是 Python 的深度学习应用编程接口。它为评估分类器提供了五种不同的准确性指标。本文试图通过实验探索这些指标的组成和计算,从基础层面解释这些指标。
Keras 提供以下准确度指标
- 准确(性)
- 二元精度
- 分类准确性
- TopK 分类准确性
- 稀疏 TopK 分类准确度
对于每个指标,我们运行以下实验
- 从逻辑上定义和计算准确性——假设。
- 用 Keras 的方法计算精度。
- 如果(1)和(2)同时存在,将逻辑定义归于 Keras 的方法。
准确(性)
精确度计算预测值(yPred)与实际值(yTrue)相匹配的百分比。
对于一个记录,如果预测值等于实际值,则认为它是准确的。
然后我们通过将准确预测的记录数除以记录总数来计算准确率。
密码
输出

二元精度
二进制精度计算二进制标签的预测值(yPred)与实际值(yTrue)相匹配的百分比。
由于标签是二进制的,yPred 由等于 1 的预测概率值组成。
郑重声明:
- 如果概率高于阈值,则分配 1,否则分配的值为 0。
- 如果赋值等于实际值,则认为是准确的。
然后,我们通过将准确预测的记录数除以记录总数来计算二进制精度。
可以调整阈值(默认值= 0.5)来提高二进制精度。
密码
输出

问题 1。在上面的实验中,当我们将阈值改为(i) 0.4 和(ii) 0.49 时,二进制精度的值是多少?
分类准确性
分类精度计算一次性标注的预测值(yPred)与实际值(yTrue)相匹配的百分比。
郑重声明:
- 我们使用 argmax()确定最大值出现的索引。
- 如果 yPred 和 yTrue 相同,则认为是准确的。
然后,我们通过将准确预测的记录数除以记录总数来计算分类准确性。
由于分类准确性寻找最大值的索引,yPred 可以是 logit 或预测的概率。
密码
输出

问题 2。以下数据的分类准确度值是多少?

提示。上面的 yPred 可能看起来不寻常,因为它有多个 1。但是,Keras 处理它们时不会抛出任何错误,因为当最大值出现多次时,argmax()会返回第一个匹配项的索引。
TopK 分类准确性
TopK 分类准确性计算目标(非零 yTrue)在前 K 个预测(yPred)中的记录的百分比。
郑重声明:
- 我们按照概率值的降序排列 yPred 预测。
- 如果非零 yTrue 的索引中存在的 yPred 的秩小于或等于 K,则认为它是准确的。
然后,我们通过将准确预测的记录数除以记录总数来计算 TopK 分类准确性。
密码
输出

问题 3。上述实验输出 100%作为 TopK 分类准确率的最小 K 是多少?
稀疏 TopK 分类准确度
稀疏前 K 分类准确性计算整数目标(yTrue)在前 K 个预测(yPred)中的记录的百分比。
yTrue 由非零目标的索引(0 到 n-1)组成,而不是像 TopK 分类精度中那样的一次性目标。
郑重声明:
- 我们按照概率值的降序排列 yPred 预测。
- 如果非零 yTrue 的索引中存在的 yPred 的秩小于或等于 K,则认为它是准确的。
然后,我们通过将准确预测的记录数除以记录总数来计算稀疏 TopK 分类准确度。
密码
输出

问题 4。上述实验输出 100%作为稀疏 TopK 分类准确率的最小 K 是多少?
结论
概括地说,Keras 提供了五种不同的度量来衡量分类器的预测准确性。根据数据的性质,特定的方法可能比其他方法更有帮助,也更相关。看完这篇文章,我希望你能明智地选择一个指标,并准确地解读它。
答案
- ㈠100%,㈡80%
- 100%
- K = 4
- K = 2
更多信息,请参考 Keras 的文档 。
最后,我想感谢我的朋友萨姆校对了这篇文章。
Keras 和 R:用序列模型预测血糖水平
这个例子说明了如何使用 Keras 和 R 来实现基于回归的神经网络。
随着 TensorFlow 2.0 的出现, Keras 现在是这个版本的默认 API。Keras 用于构建深度学习目的的神经网络。因此,Keras 是对大型数据集进行分析的非常有用的工具。
然而,你知道 Keras API 也可以在 R 中运行吗?
在这个例子中, Keras 用于生成一个神经网络,目的是解决 r 中的一个回归问题
具体来说,皮马印第安人糖尿病数据集用于使用相关特征预测患者的血糖水平。
在这方面,本文概述了:
- R 中的特征选择方法
- 如何在 Keras 中定义顺序模型
- 验证和测试模型预测的方法
数据集
在这个例子中,Pima Indians 糖尿病数据集被分成三个独立的数据集。
训练和验证: 皮马-印度人-diabetes1.csv 。原始数据集的 80%是从完整数据集分割出来的。反过来,该数据集的 70%用于训练模型,剩余的 30%用于验证预测。
测试: 皮马-印第安人-糖尿病 2.csv 和皮马-印第安人-糖尿病 3.csv 。原始数据集的剩余 20%用作看不见的数据,以确定模型生成的预测在处理全新数据时是否表现良好。 pima-indians-diabetes2 包含特征(或自变量),而 pima-indians-diabetes3 包含因变量(血糖水平)。
特征选择
特征选择的目的是确定那些对因变量影响最大的特征。
在我们的例子中,有八个特征,其中一些在确定血糖水平时比其他的更重要。
这里使用的两种特征选择方法是:
- 相关图
- 多元线性回归
相关图
相关图使我们能够直观地确定:
- 与因变量高度相关的特征
- 彼此高度相关的特征
如果某些特征与血糖水平高度相关,那么这表明这些特征在预测血糖水平方面是重要的。具有低相关性的特征被指示为不重要。
然而,彼此高度相关的特征将表明这些特征中的一些是多余的(因为它们实际上试图解释相同的事情)。
这是第一个相关图:
M <- cor(diabetes1)
corrplot(M, method = "circle")

我们可以看到胰岛素和结果变量与葡萄糖变量特别相关,而年龄和怀孕和胰岛素和皮肤厚度之间也有相关性。
但是,我们可以更详细地了解并获得每个特征的特定相关系数:
corrplot(M, method = "number")

多元线性回归
多元线性回归的目的是:
- 在解释因变量时,确定每个特征的系数的大小和性质。
- 确定每个特征的重要性或不重要性。
以下是线性回归的结果:
Call:
lm(formula = Glucose ~ Pregnancies + Outcome + Age + DiabetesPedigreeFunction +
BMI + Insulin + SkinThickness + BloodPressure, data = diabetes1)Residuals:
Min 1Q Median 3Q Max
-68.709 -18.148 -2.212 15.176 80.950 Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 78.401064 6.363612 12.320 < 2e-16 ***
Pregnancies -0.481865 0.363730 -1.325 0.18575
Outcome 25.590805 2.384153 10.734 < 2e-16 ***
Age 0.527262 0.106097 4.970 8.8e-07 ***
DiabetesPedigreeFunction 0.052534 3.198192 0.016 0.98690
BMI 0.318452 0.167106 1.906 0.05718 .
Insulin 0.082208 0.009843 8.352 4.8e-16 ***
SkinThickness -0.202236 0.077372 -2.614 0.00918 **
BloodPressure 0.083865 0.058081 1.444 0.14929
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1Residual standard error: 24.94 on 590 degrees of freedom
Multiple R-squared: 0.362, Adjusted R-squared: 0.3533
F-statistic: 41.84 on 8 and 590 DF, p-value: < 2.2e-16
在 5%的水平上,结果、年龄、胰岛素和皮肤厚度被认为是显著的。其他特征在 5%的水平上被认为是不重要的。
使用 Breusch-Pagan 进行异方差检验
在这种情况下,没有必要对多重共线性进行正式测试,因为相关图显示了彼此高度相关的要素。
然而,可能存在异方差(跨标准误差的不均匀方差),例如,由于患者的年龄不同。为了检验这一点,进行了 Breusch-Pagan 检验——p 值低于 0.05 表示存在异方差。
> bptest(fit) studentized Breusch-Pagan testdata: fit
BP = 36.585, df = 8, p-value = 1.372e-05
由于表明存在异方差,所以运行稳健的回归——特别是使用 Huber 权重。这样做的目的是降低数据集中异常值的价值。
> # Huber Weights (Robust Regression)
> summary(rr.huber <- rlm(Glucose ~ Pregnancies + Outcome + Age + DiabetesPedigreeFunction + BMI + Insulin + SkinThickness + BloodPressure, data=diabetes1))Call: rlm(formula = Glucose ~ Pregnancies + Outcome + Age + DiabetesPedigreeFunction +
BMI + Insulin + SkinThickness + BloodPressure, data = diabetes1)
Residuals:
Min 1Q Median 3Q Max
-68.627 -16.842 -1.543 15.576 83.793 Coefficients:
Value Std. Error t value
(Intercept) 78.3319 6.2990 12.4357
Pregnancies -0.4675 0.3600 -1.2984
Outcome 25.0513 2.3599 10.6152
Age 0.5448 0.1050 5.1881
DiabetesPedigreeFunction -0.5482 3.1657 -0.1732
BMI 0.3297 0.1654 1.9935
Insulin 0.0925 0.0097 9.4912
SkinThickness -0.2530 0.0766 -3.3032
BloodPressure 0.0673 0.0575 1.1706Residual standard error: 24.53 on 590 degrees of freedom
在 590 自由度上,双尾 t 临界值如下:
> abs(qt(0.05/2, 590))
[1] 1.963993
当 t 统计量> t 临界值时,零假设被拒绝。对此,结局、年龄、身体质量指数、胰岛素、皮肤厚度的 t 值绝对值大于临界值。
考虑到相关图和多元线性回归的发现,选择结果、年龄、胰岛素和皮肤厚度作为分析的相关特征。
数据准备
既然已经选择了相关特征,就可以构建神经网络了。在此之前:
- 最大-最小归一化用于在 0 和 1 之间缩放每个变量。这是为了确保变量之间有一个共同的范围,以便神经网络可以正确地解释它们。
normalize <- function(x) {
return ((x - min(x)) / (max(x) - min(x)))
}maxmindf <- as.data.frame(lapply(df, normalize))
attach(maxmindf)
maxmindf<-as.matrix(maxmindf)
- 训练验证集被分成 70/30。
ind <- sample(2, nrow(maxmindf), replace=TRUE, prob = c(0.7,0.3))X_train <- maxmindf[ind==1, 1:4]
X_val <- maxmindf[ind==2, 1:4]
y_train <- maxmindf[ind==1, 5]
y_val <- maxmindf[ind==2, 5]
顺序模型
现在,定义了顺序模型。四个输入特征(结果、年龄、胰岛素、皮肤厚度)包括在输入层中,该层中定义了 9 个神经元。定义一个具有 60 个神经元的隐藏层,并且定义一个具有 1 个神经元的线性输出层。
正如法尔哈德·马利克在本文中所解释的,每层神经元的数量配置如下:
- 输入层:输入层的神经元数量计算如下:
Number of features in the training set + 1
在这种情况下,由于训练集中有 8 个特征,因此相应地定义了 9 个输入神经元。
- 隐藏层:定义一个隐藏层,因为单个层适用于处理大多数数据集。隐藏层中神经元的数量确定如下:
Training Data Samples/Factor * (Input Neurons + Output Neurons)
在这种情况下,将因子设置为 1,该因子的目的是防止过度拟合。因子可以取 1 到 10 之间的值。输入层中有 9 个神经元,输出层中有 1 个神经元,训练集中有 599 个观察值,隐藏层被分配了 60 个神经元。
- 输出层:由于这是结果层,输出层默认取值 1。
model <- keras_model_sequential()
model %>%
layer_dense(units = 9, activation = 'relu', kernel_initializer='RandomNormal', input_shape = c(4)) %>%
layer_dense(units = 60, activation = 'relu') %>%
layer_dense(units = 1, activation = 'linear')summary(model)
以下是输出:
Model: "sequential"
________________________________________________________________________________
Layer (type) Output Shape Param #
================================================================================
dense (Dense) (None, 9) 45
________________________________________________________________________________
dense_1 (Dense) (None, 60) 600
________________________________________________________________________________
dense_2 (Dense) (None, 1) 61
================================================================================
Total params: 706
Trainable params: 706
Non-trainable params: 0
________________________________________________________________________________
该模型现在经过 30 个时期的训练,并基于其损失和平均绝对误差进行评估。假设因变量为区间,则使用均方差来确定预测值和实际值之间的偏差。
model %>% compile(
loss = 'mean_squared_error',
optimizer = 'adam',
metrics = c('mae')
)history <- model %>% fit(
X_train, y_train,
epochs = 30, batch_size = 50,
validation_split = 0.2
)
模型评估
预测值和实际值会按比例还原为其原始格式:
model %>% evaluate(X_val, y_val)
model
pred <- data.frame(y = predict(model, as.matrix(X_val)))
predicted=pred$y * abs(diff(range(df$Glucose))) + min(df$Glucose)
actual=y_val * abs(diff(range(df$Glucose))) + min(df$Glucose)
df<-data.frame(predicted,actual)
attach(df)
以下是输出:
$loss
0.0266957393988254
$mae
0.132186755537987Model
Model: "sequential"
________________________________________________________________________________
Layer (type) Output Shape Param #
================================================================================
dense (Dense) (None, 9) 45
________________________________________________________________________________
dense_1 (Dense) (None, 60) 600
________________________________________________________________________________
dense_2 (Dense) (None, 1) 61
================================================================================
Total params: 706
Trainable params: 706
Non-trainable params: 0
________________________________________________________________________________
这是损失和平均绝对误差的曲线图:

该模型产生的损失略高于 2%,平均绝对误差略高于 13%。
MLmetrics 库也可用于计算 MAPE(平均绝对百分比误差)。
install.packages("MLmetrics")
library(MLmetrics)
MAPE(predicted, actual)
验证集的 MAPE 为 18% 。增加模型中隐藏层的数量并不能提高 MAPE,因此决定在模型配置中保留一个隐藏层。
预测和测试数据
尽管这个模型显示了强大的预测能力,我们的工作还没有完成。
虽然该模型在验证数据上表现良好,但我们现在需要评估该模型在完全看不见的数据上是否也表现良好。
从 pima-indians-diabetes2 加载特征变量,并再次调用 max0min 归一化:
normalize <- function(x) {
return ((x - min(x)) / (max(x) - min(x)))
}maxmindf2 <- as.data.frame(lapply(df2, normalize))
attach(maxmindf2)
使用 R 中的预测函数,为葡萄糖变量生成预测:
pred_test <- data.frame(y = predict(model, as.matrix(maxmindf2)))
predicted_test = pred_test$y * abs(diff(range(diabetes1$Glucose))) + min(diabetes1$Glucose)
predicted_test
然后将预测值与 pima-indians-diabetes 中的实际值进行比较 3:
actual_test = diabetes3$Glucose
df2<-data.frame(predicted_test,actual_test)
attach(df2)
df2

现在,使用测试值计算平均绝对百分比误差:
MAPE(predicted_test, actual_test)
计算出 17%的平均百分比误差:
0.177895157636775
观察到,虽然平均百分比误差略高于使用训练和验证数据计算的误差,但是该模型在测试集上的所有未观察到的观察中预测血糖水平仍然表现良好。
结论
在本例中,我们看到:
- 如何在 R 中实现特征选择方法
- 使用 Keras API 构建一个神经网络来分析回归数据
- 使用测试数据的仪表预测精度
非常感谢你的时间!你也可以在 michael-grogan.com 找到更多我的数据科学内容。
免责声明:本文是在“原样”的基础上编写的,没有担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。
Keras,告诉我我的书的类型
利用递归神经网络的能力进行分类。

Shutterstock 上的十亿张照片
对于任何希望深入了解递归神经网络(RNN)如何工作的人来说,我希望这个简单的教程是一个很好的读物!
我们使用的数据集包括我从 GoodReads 收集的书籍描述和流派分类,这是一个使用 RNN 的分类方法解决典型分类问题的很好的例子。对于这个项目,我们将把我们的问题简化为一个二元分类问题,我们将使用 RNN 对全文图书描述进行情感分析!
想想这有多神奇。我们将训练一个人工神经网络如何“阅读”书籍描述并猜测其流派。
由于理解书面语言需要跟踪一个句子中的所有单词,我们需要一个递归神经网络来保存以前出现过的单词的“记忆”,因为它随着时间的推移“阅读”句子。
特别是,我们将使用 LSTM(长短期记忆)细胞,因为我们真的不想太快“忘记”单词——句子中早期的单词会显著影响句子的意思。
GitHub 资源库这里
这里是我们这个项目需要的一些重要的库——Numpy、Pandas、matplotlib、Plotly 和 Tensorflow。我们将使用 Keras——运行在 TensorFlow(或 CNTK 或 Theano)之上的东西。Keras 允许我们更少地考虑原始模型拓扑,直接投入到简单快速的原型开发中。实验越快,结果越好:)
import numpy as np
import pandas as pdimport matplotlib.pyplot as plt
import tensorflow
import plotly.offline as pyoff
import plotly.graph_objs as go
pyoff.init_notebook_mode()
让我们首先导入我从好的阅读中收集的数据,看看我们需要处理什么。
bookdata_path = 'book_data.csv'
testdata_path = 'book_data18.csv'
book = pd.read_csv(bookdata_path)
test = pd.read_csv(testdata_path)book.columns
' book_authors ':作者姓名字符串
' desc 图书':描述字符串
' book_edition ':图书字符串的不同版本
' book_format ':精装/平装字符串
' book_pages ':一本书的页数
“图书评级”:图书评级浮动
' book_rating_count ':评分数 int
' book_review_count ':评论数 int
' book_title ':图书字符串标题
“体裁”:书串的体裁
' image_url ':图书图像 url 字符串
数据清理和数据探索
这一步占用了每个数据科学家的大部分时间。我们查看数据框中的每一列,找出我们可能面临的任何潜在问题。
一些常见问题包括:
- 缺少值
- 涉及不同的语言
- 非 Ascii 字符
- 无效描述
- 描述中缺少空格,例如 HelloILike toEat
我建议写下你的数据清理步骤的所有发现,这样你就可以不断地查阅你的笔记,确保你不会错过任何一个步骤!
事不宜迟,以下是我的发现。
- 语料库中存在多种语言——我是想保留所有语言还是只保留英语描述?我的数据集中的整体语言分布如何?
- 每本书至少有一个用户定义的流派,我的数据集中有多少流派?流派分布是怎样的?有多少独特的流派?
1。删除无效格式的描述
因为我们在预测类型,类型将是我们的标签,而特征将来自每本书的描述。我发现在一些条目中有格式错误——这就是 langdetect 出现的地方。我们将实现一个函数来删除任何具有无效描述格式的行。
from langdetect import detectdef remove_invalid_lang(df):
invalid_desc_idxs=[]
for i in df.index:
try:
a=detect(df.at[i,'book_desc'])
except:
invalid_desc_idxs.append(i)
df=df.drop(index=invalid_desc_idxs)
return dfbook = remove_invalid_lang(book)
test = remove_invalid_lang(test)
2.仅获取英文描述
我注意到在我的数据集中涉及到许多语言。为了简单起见,我只想要英文的书籍描述。
book[‘lang’]=book[‘book_desc’].map(lambda desc: detect(desc))
test['lang']=test['book_desc'].map(lambda desc: detect(desc))
langdetect 允许我们将每个描述映射到一个 ISO 639-1 值,以使我们在过滤掉英文描述时更加轻松。用它!然后,我将从维基百科中检索语言列表及其各自的 ISO 值。
lang_lookup = pd.read_html('[https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes')[1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes')[1)]
langpd = lang_lookup[['ISO language name','639-1']]
langpd.columns = ['language','iso']def desc_lang(x):
if x in list(langpd['iso']):
return langpd[langpd['iso'] == x]['language'].values[0]
else:
return 'nil'book['language'] = book['lang'].apply(desc_lang)
test['language'] = test['lang'].apply(desc_lang)

从图中可以清楚地看到,绝大多数描述都是英文的。让我们仔细看看其他语言的分布。

用这些一行程序从我们的测试和训练数据集中检索所有的英语书!
book = book[book['language']=='English']
test = test[test['language']=='English']
3.查看所有可用的流派
这就是我们的流派专栏的样子。我们有许多由“|”分隔的用户定义的风格,所以我们必须清理它。
幻想|年轻人|小说
在每个数据科学项目中,了解数据的分布非常重要,最好的方法是绘制图表!我真的很喜欢使用 Plotly 进行数据可视化,但是 matplotlib 和 seaborn 也可以完成这项工作。
这是我的功能,获取每本书的所有流派,并绘制成图表。
def genre_count(x):
try:
return len(x.split('|'))
except:
return 0book['genre_count'] = book['genres'].map(lambda x: genre_count(x))plot_data = [
go.Histogram(
x=book['genre_count']
)
]
plot_layout = go.Layout(
title='Genre distribution',
yaxis= {'title': "Frequency"},
xaxis= {'title': "Number of Genres"}
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

我必须说,大多数书都有大约 5-6 种类型,而且分布非常均匀。
def genre_listing(x):
try:
lst = [genre for genre in x.split("|")]
return lst
except:
return []book['genre_list'] = book['genres'].map(lambda x: genre_listing(x))genre_dict = defaultdict(int)
for idx in book.index:
g = book.at[idx, 'genre_list']
if type(g) == list:
for genre in g:
genre_dict[genre] += 1genre_pd = pd.DataFrame.from_records(sorted(genre_dict.items(), key=lambda x:x[1], reverse=True), columns=['genre', 'count'])
上面的代码给了我一个所有流派的字典,以及它们在整个语料库中的总数。让我们进入剧情。
plot_data = [
go.Bar(
x=genre_pd[‘genre’],
y=genre_pd[‘count’]
)
]
plot_layout = go.Layout(
title=’Distribution for all Genres’,
yaxis= {‘title’: “Count”},
xaxis= {‘title’: “Genre”}
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

看那些数量很少的类型是不实际的,因为它对我们来说没有什么价值。我们只想查看代表数据集的顶级独特流派,因此让我们挑选 50 个顶级流派来查看!

如果我们看一下 genre_list 这一栏,如果“小说”至少被列为一种类型,那么这本书就被归类为小说。通过观察,如果一本书在其流派列表中至少有小说,同一列表中的所有其他流派也将与小说密切相关。由此,我可以比较我的数据集中小说和非小说书籍的数量,并将其转化为二元分类问题!
def determine_fiction(x):
lower_list = [genre.lower() for genre in x]
if 'fiction' in lower_list:
return 'fiction'
elif 'nonfiction' in lower_list:
return 'nonfiction'
else:
return 'others'
book['label'] = book['genre_list'].apply(determine_fiction)
test['label'] = test['genre_list'].apply(determine_fiction)
4.清理文本
下面是我的函数,可以删除任何非 Ascii 字符和标点符号。
def _removeNonAscii(s):
return "".join(i for i in s if ord(i)<128)def clean_text(text):
text = text.lower()
text = re.sub(r"what's", "what is ", text)
text = text.replace('(ap)', '')
text = re.sub(r"\'s", " is ", text)
text = re.sub(r"\'ve", " have ", text)
text = re.sub(r"can't", "cannot ", text)
text = re.sub(r"n't", " not ", text)
text = re.sub(r"i'm", "i am ", text)
text = re.sub(r"\'re", " are ", text)
text = re.sub(r"\'d", " would ", text)
text = re.sub(r"\'ll", " will ", text)
text = re.sub(r'\W+', ' ', text)
text = re.sub(r'\s+', ' ', text)
text = re.sub(r"\\", "", text)
text = re.sub(r"\'", "", text)
text = re.sub(r"\"", "", text)
text = re.sub('[^a-zA-Z ?!]+', '', text)
text = _removeNonAscii(text)
text = text.strip()
return textdef cleaner(df):
df = df[df['label'] != 'others']
df = df[df['language'] != 'nil']
df['clean_desc'] = df['book_desc'].apply(clean_text)return df
只需拨打:
clean_book = cleaner(book)
clean_test = cleaner(test)
我们现在对每本书都有了一个“干净”的描述!
“胜利会让你出名。输了就意味着必死无疑。”成为
“胜利会让你出名,失败意味着死亡”
为模型准备我们的数据
现在有趣的部分来了。书籍描述是我们的预测器,所以我们必须特别注意!我们需要确保每个描述都是相同的格式和长度。
使用固定输入长度可以提高模型训练期间的性能,因为这样可以创建固定形状的张量,从而获得更稳定的权重。因此,我们将进行裁剪和填充——如果原始描述长度比最佳长度短,则将描述裁剪到最佳长度并用空值填充的过程。
我们如何确定最佳长度?
绘制描述长度的分布图,并观察最“常见”的描述长度。

哇,这是一个非常倾斜的分布!但是我们知道大多数书的描述长度小于 500。我想画出累积分布函数(CDF ),来观察每一级描述长度的“图书数量”。
len_df_bins=clean_book.desc_len.value_counts(bins=100, normalize=True).reset_index().sort_values(by=['index'])len_df_bins['cumulative']=len_df_bins.desc_len.cumsum()len_df_bins['index']=len_df_bins['index'].astype('str')len_df_bins.iplot(kind='bar', x='index', y='cumulative')

约 92.7%的记录字数在 277 字以下。因此,我决定将我的最大阈值设置为 250 个单词。我们还需要一个最小阈值,我将把它设置为 6,因为任何少于 5 个单词的描述都不太可能足以确定类型。
1.剪辑和填充
对于描述少于 250 个单词的记录,我们将用空值填充它们,而对于描述多于 250 个单词的记录,我们将对它们进行裁剪,只包含前 250 个单词。
RNN 从左到右读取令牌序列,并输出一个预测书是小说还是非小说。这些标记的内存被一个接一个地传递给最终的标记,因此,对序列进行预填充而不是后填充是很重要的。这意味着零添加在令牌序列之前,而不是之后。存在后填充可能更有效的情况,例如在双向网络中。
min_desc_length=6
max_desc_length=250clean_book=clean_book[(clean_book.clean_desc.str.split().apply(len)>min_desc_length)].reset_index(drop=True)
上面的代码过滤掉了所有少于 6 个单词的描述。
vocabulary=set() #unique list of all words from all descriptiondef add_to_vocab(df, vocabulary):
for i in df.clean_desc:
for word in i.split():
vocabulary.add(word)
return vocabularyvocabulary=add_to_vocab(clean_book, vocabulary)#This dictionary represents the mapping from word to token. Using token+1 to skip 0, since 0 will be used for padding descriptions with less than 200 words
vocab_dict={word: token+1 for token, word in enumerate(list(vocabulary))}#This dictionary represents the mapping from token to word
token_dict={token+1: word for token, word in enumerate(list(vocabulary))}assert token_dict[1]==token_dict[vocab_dict[token_dict[1]]]def tokenizer(desc, vocab_dict, max_desc_length):
'''
Function to tokenize descriptions
Inputs:
- desc, description
- vocab_dict, dictionary mapping words to their corresponding tokens
- max_desc_length, used for pre-padding the descriptions where the no. of words is less than this number
Returns:
List of length max_desc_length, pre-padded with zeroes if the desc length was less than max_desc_length
'''
a=[vocab_dict[i] if i in vocab_dict else 0 for i in desc.split()]
b=[0] * max_desc_length
if len(a)<max_desc_length:
return np.asarray(b[:max_desc_length-len(a)]+a).squeeze()
else:
return np.asarray(a[:max_desc_length]).squeeze()len(vocabulary)
85616
我们有 85616 个独特的单词。最后,裁剪和填充步骤的最后一步,标记每个描述。
clean_test['desc_tokens']=clean_test['clean_desc'].apply(tokenizer, args=(vocab_dict, max_desc_length))
2.列车测试分离
当数据集不平衡时,即目标变量(虚构/非虚构)的分布不均匀时,我们应该确保训练-验证分裂是分层的。这确保了目标变量的分布在训练和验证数据集中得到保留。
我们也可以尝试随机欠采样来减少虚构样本的数量,但是,在这种情况下,我将使用分层采样。原因如下。
分层随机样本用于可以很容易分成不同的子群或子集的人群,在我们的例子中,是虚构或非虚构的。我将从每个标签中随机选择与群体规模和人口数量成比例的记录。每个记录必须只属于一个阶层(标签),我确信每个记录是互斥的,因为一本书只能是小说或非小说。重叠的地层会增加某些数据被包括在内的可能性,从而扭曲样本。
分层抽样优于随机欠抽样的一个优点是,因为它使用特定的特征,所以它可以根据用于划分不同子集的内容来提供更准确的图书表示,而且我们不必删除任何可能对我们的模型有用的记录。
def stratified_split(df, target, val_percent=0.2):
'''
Function to split a dataframe into train and validation sets, while preserving the ratio of the labels in the target variable
Inputs:
- df, the dataframe
- target, the target variable
- val_percent, the percentage of validation samples, default 0.2
Outputs:
- train_idxs, the indices of the training dataset
- val_idxs, the indices of the validation dataset
'''
classes=list(df[target].unique())
train_idxs, val_idxs = [], []
for c in classes:
idx=list(df[df[target]==c].index)
np.random.shuffle(idx)
val_size=int(len(idx)*val_percent)
val_idxs+=idx[:val_size]
train_idxs+=idx[val_size:]
return train_idxs, val_idxs_, sample_idxs = stratified_split(clean_book, 'label', 0.1)train_idxs, val_idxs = stratified_split(clean_book, 'label', val_percent=0.2)
sample_train_idxs, sample_val_idxs = stratified_split(clean_book[clean_book.index.isin(sample_idxs)], 'label', val_percent=0.2)classes=list(clean_book.label.unique())sampling=Falsex_train=np.stack(clean_book[clean_book.index.isin(sample_train_idxs if sampling else train_idxs)]['desc_tokens'])
y_train=clean_book[clean_book.index.isin(sample_train_idxs if sampling else train_idxs)]['label'].apply(lambda x:classes.index(x))x_val=np.stack(clean_book[clean_book.index.isin(sample_val_idxs if sampling else val_idxs)]['desc_tokens'])
y_val=clean_book[clean_book.index.isin(sample_val_idxs if sampling else val_idxs)]['label'].apply(lambda x:classes.index(x))x_test=np.stack(clean_test['desc_tokens'])
y_test=clean_test['label'].apply(lambda x:classes.index(x))
x_train 和 y_train 将用于训练我们的模型,而 x_val 和 y_val 用于检查我们模型的验证准确性。我们的目标是适度的高训练精度和高验证精度,以确保我们不会过度拟合。
过度拟合是指我们的模型在对他们接受训练的数据进行预测时表现良好,但未能对看不见的数据(验证数据)进行归纳。另一方面,当我们的模型甚至在训练数据上表现糟糕时,就会出现欠拟合。
过度拟合的模型将具有高方差和低偏差,而欠拟合的模型将具有高偏差和低方差。
误差=偏差+方差
我们的主要目标是减少误差,而不是偏差或方差,因此最佳复杂度是中间值。
模型结构
在这一步,我们的训练数据只是一个数字矩阵,它是我们模型的必要输入。至于我们的 y 标签,现在是 1(虚构)或者 0(非虚构)。
重述
概括一下,我们有一堆书籍描述,它们被转换成由整数表示的单词向量,还有一个二元情感分类可供学习。RNN 病会很快发作,为了让事情在我们的小电脑上易于管理,我们将描述限制在它们的前 250 个单词。不要忘记,这也有助于提高我们的模型训练的性能!
初始化我们的模型
现在让我们建立我们的神经网络模型!考虑到 LSTM 递归神经网络是多么复杂,用 Keras 做到这一点是多么容易,这真的令人惊讶。
我们将从嵌入层开始,这只是将输入数据转换为更适合神经网络的固定大小的密集向量的一个步骤。您通常会看到这与我们这里的基于索引的文本数据结合在一起。嵌入层帮助我们降低问题的维度。如果我们对词汇表中的单词进行一次性编码,每个单词将由一个向量表示,这个向量的大小等于词汇表本身的大小,在本例中是 85643。由于每个样本将是一个大小为(词汇×记号数量)的张量,即(85643×250),该层的大小对于 LSTM 来说将太大而不能消耗,并且对于训练过程来说将是非常资源密集和耗时的。如果我使用嵌入,我的张量大小将只有 250 x 250!WAYYY 小一点!
一个热编码将导致一个巨大的稀疏矩阵,而嵌入给我们一个密集的矩阵表示。嵌入长度越高,我们的模型可以学习的表示就越复杂,因为我们的嵌入层学习每个单词的固定长度的“表示”。
接下来,我们只需为 RNN 本身设置一个 LSTM 图层。就这么简单。我们指定 200 来匹配嵌入层的输出大小,并删除项以避免过度拟合,这是 RNN 特别容易发生的。顺便说一下,你可以选择 200 以外的任何数字,它只指定了该层中隐藏神经元的数量。
最后,我们只需要用 sigmoid 激活函数将它归结为最后一层中的单个神经元,以选择我们的二元情感分类 0 或 1。
我将解释为什么我为模型选择了超参数,但是如果你想跳到代码,请随意跳过这一部分!
我们应该使用多少 LSTM 层?速度-复杂度权衡
通常 1 层足以发现简单问题的趋势,2 层足以发现相当复杂的特征。对于一系列选择(层数),我们可以在固定的时期数之后比较我们的模型的准确性,如果我们发现即使在添加更多层之后验证准确性也没有显著变化,我们可以选择最小层数。
我们应该添加多少隐藏节点到我们的 LSTM 层?
Ns:训练数据中样本的数量
Ni:输入神经元的数量
No:输出神经元的数量
alpha:缩放因子(指示您希望您的模型有多通用,或者您希望防止过度拟合的程度)
通式:Ns / [alpha * (Ni + No)]
添加脱落层。精度-防过拟合权衡
通过在训练期间忽略随机选择的神经元来防止过度拟合,并降低对单个神经元的特定权重的敏感性。这迫使我们的模型展开 it 学习。
添加密集层
因为我们有 1 个输出标签来表示小说或非小说,所以我们将有 1 维输出。
添加激活层
有许多激活功能可供选择,所以这取决于我们的目标。
在这种情况下,我们希望输出是虚构/非虚构的,因此 Softmax 或 Sigmoid 函数会很好。
Sigmoid 函数基本上输出概率,我们通常会使用 sigmoid 进行二值分类。
Softmax 函数输出介于 0 和 1 之间的值,使得所有输出值的总和等于 1。基本上你得到了每一类的概率,它们的和必然是 1。这使得 Softmax 非常适合多类问题。
您可以使用 Sigmoid 和 Softmax 函数调整激活层超参数,并比较验证精度!我们也可以尝试 reLU,它被广泛使用,因为它计算速度快,效果好。
选择损失函数、优化器和判断标准
由于我们面临的是二进制分类问题,二进制交叉熵将与 sigmoid 一起很好地工作,因为交叉熵函数抵消了 Sigmoid 函数两端的平稳段,因此加快了学习过程。
对于优化器,自适应矩估计(adam)已被证明在大多数实际应用中工作良好,并且仅在超参数变化很小的情况下工作良好。r
从整体准确性的角度来判断模型的性能是最容易解释最终模型性能的。
现在我们将实际训练我们的模型。像 CNN 一样,RNN 的资源非常丰富。保持相对较小的批量是让它在你的电脑上运行的关键。当然,在现实世界中,您可以利用安装在集群上的许多计算机上的 GPU 来大大提高这一规模。
代号
parameters = {'vocab': vocabulary,
'eval_batch_size': 30,
'batch_size': 20,
'epochs': 5,
'dropout': 0.2,
'optimizer': 'Adam',
'loss': 'binary_crossentropy',
'activation':'sigmoid'}
**def** bookLSTM(x_train, y_train, x_val, y_val, params):
model = Sequential()
model.name="Book Model"
model.add(Embedding(len(params['vocab'])+1, output_dim=x_train.shape[1], input_length=x_train.shape[1]))
model.add(LSTM(200, return_sequences=**True**))
model.add(Dropout(params['dropout']))
model.add(LSTM(200))
model.add(Dense(1, activation=params['activation']))
model.compile(loss=params['loss'],
optimizer=params['optimizer'],
metrics=['accuracy'])
print(model.summary())
model.fit(x_train,
y_train,
validation_data=(x_val, y_val),
batch_size=params['batch_size'],
epochs=params['epochs'])
results = model.evaluate(x_test, y_test, batch_size=params['eval_batch_size'])
**return** model
BookModel1 = bookLSTM(x_train, y_train, x_val, y_val, parameters)------ Model Summary ------Model: "Book Model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_2 (Embedding) (None, 200, 200) 17123400
_________________________________________________________________
lstm_1 (LSTM) (None, 200, 200) 320800
_________________________________________________________________
dropout_1 (Dropout) (None, 200, 200) 0
_________________________________________________________________
lstm_2 (LSTM) (None, 200) 320800
_________________________________________________________________
dense_1 (Dense) (None, 1) 201
=================================================================
Total params: 17,765,201
Trainable params: 17,765,201
Non-trainable params: 0
_________________________________________________________________Train on 23387 samples, validate on 5845 samples
Epoch 1/5
23387/23387 [==============================] - 270s 12ms/step - loss: 0.3686 - accuracy: 0.8447 - val_loss: 0.2129 - val_accuracy: 0.9129
Epoch 2/5
23387/23387 [==============================] - 282s 12ms/step - loss: 0.1535 - accuracy: 0.9476 - val_loss: 0.2410 - val_accuracy: 0.9013
Epoch 3/5
23387/23387 [==============================] - 279s 12ms/step - loss: 0.0735 - accuracy: 0.9771 - val_loss: 0.2077 - val_accuracy: 0.9357
Epoch 4/5
23387/23387 [==============================] - 280s 12ms/step - loss: 0.0284 - accuracy: 0.9924 - val_loss: 0.2512 - val_accuracy: 0.9334
Epoch 5/5
23387/23387 [==============================] - 293s 13ms/step - loss: 0.0161 - accuracy: 0.9957 - val_loss: 0.2815 - val_accuracy: 0.9290
657/657 [==============================] - 3s 5ms/step
我注意到,随着我的纪元从 3 增加到 5,测试精度增加了,但是验证精度降低了。这意味着模型更好地拟合了训练集,但它失去了对新数据进行预测的能力,这表明我的模型开始拟合噪声,并开始过度拟合。让我们改变参数!
parameters = {'vocab': vocabulary,
'eval_batch_size': 30,
'batch_size': 20,
'epochs': 2,
'dropout': 0.2,
'optimizer': 'Adam',
'loss': 'binary_crossentropy',
'activation':'sigmoid'}
**def** bookLSTM(x_train, y_train, x_val, y_val, params):
model = Sequential()
model.name="Book Model2"
model.add(Embedding(len(params['vocab'])+1, output_dim=x_train.shape[1], input_length=x_train.shape[1]))
model.add(LSTM(200, return_sequences=**True**))
model.add(Dropout(params['dropout']))
model.add(LSTM(200))
model.add(Dense(1, activation=params['activation']))
model.compile(loss=params['loss'],
optimizer=params['optimizer'],
metrics=['accuracy'])
print(model.summary())
model.fit(x_train,
y_train,
validation_data=(x_val, y_val),
batch_size=params['batch_size'],
epochs=params['epochs'])
results = model.evaluate(x_test, y_test, batch_size=params['eval_batch_size'])
**return** model
BookModel2 = bookLSTM(x_train, y_train, x_val, y_val, parameters)------ Model Summary ------Model: "Book Model2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_3 (Embedding) (None, 200, 200) 17123400
_________________________________________________________________
lstm_3 (LSTM) (None, 200, 200) 320800
_________________________________________________________________
dropout_2 (Dropout) (None, 200, 200) 0
_________________________________________________________________
lstm_4 (LSTM) (None, 200) 320800
_________________________________________________________________
dense_2 (Dense) (None, 1) 201
=================================================================
Total params: 17,765,201
Trainable params: 17,765,201
Non-trainable params: 0
_________________________________________________________________Train on 23387 samples, validate on 5845 samples
Epoch 1/2
23387/23387 [==============================] - 337s 14ms/step - loss: 0.3136 - accuracy: 0.8690 - val_loss: 0.1937 - val_accuracy: 0.9305
Epoch 2/2
23387/23387 [==============================] - 332s 14ms/step - loss: 0.1099 - accuracy: 0.9636 - val_loss: 0.1774 - val_accuracy: 0.9341
657/657 [==============================] - 3s 4ms/step
我们仅在两个时期内就实现了 96.4%的训练准确率和 93.4%的验证准确率!对于 2 次运行来说,这已经很不错了。我尝试了许多不同的超参数,仅运行 10 个纪元就花了我一个小时,所以…
你自己试试,让我知道你选择了什么参数来获得比我更高的验证准确率!
测试我们模型的简单函数
在这部引人入胜的《纽约时报》畅销书《纸与火的女孩》续集中,雷和雷恩逃离了他们在隐秘宫殿中的压抑生活,但很快发现自由需要付出可怕的代价。雷,一个天真的乡下女孩,成为了一名皇家妓女,现在被称为月嫂,一个成功地做了别人做不到的事情的平民。但是杀死残忍的魔王并不是计划的结束——这只是开始。现在,雷和她的战士爱人雷恩必须前往王国,以获得来自遥远的反叛氏族的支持。旅途变得更加险恶,因为有人悬赏要得到雷的人头,还有阴险的怀疑威胁着要把雷和雷恩从内部分开。与此同时,在黑魔法和复仇的推动下,一个消灭叛军起义的邪恶阴谋正在成形。雷会成功地推翻帝制并保护她对任的爱情吗?还是她会成为邪恶魔法的牺牲品?
def reviewBook(model,text):
labels = [‘fiction’, ‘nonfiction’]
a = clean_text(fantasy)
a = tokenizer(a, vocab_dict, max_desc_length)
a = np.reshape(a, (1,max_desc_length))
output = model.predict(a, batch_size=1)
score = (output>0.5)*1
pred = score.item()
return labels[pred]
让我们传入我们的最终模型和样本文本,看看我们的模型是否能够仅仅根据一本书的描述准确地预测它的类型。你觉得上面这本书属于哪种流派?
reviewBook(BookModel2,fantasy)
小说
很明显在描述中有“恶魔之王”和“黑魔法”!
结论
请注意,在第二或第三个时期之后,我们训练时的验证准确性从未真正提高;我们可能只是过度适应了。在这种情况下,早期停止将是有益的。
但是再一次——停下来想想我们刚刚在这里做了什么!一种神经网络,可以“阅读”描述,并根据文本推断这本书是否是小说。它考虑了每个单词的上下文及其在评论中的位置——建立模型本身只需要几行代码!你可以用 Keras 做的事情真是不可思议。
伙计们,希望你们在阅读我的第一篇媒体文章时过得愉快。cheerrrrrrssssssssssssss
Python 中从头开始的内核回归
大家都知道线性回归,但是你知道核回归吗?
机器学习的初学者都是从学习回归的含义和线性回归算法的工作原理开始的。事实上,线性回归的易理解性、可解释性和大量有效的真实世界用例是该算法如此著名的原因。然而,有些情况下线性回归并不适合。在本文中,我们将看到这些情况是什么,什么是内核回归算法,以及它如何适应这种情况。最后,我们将从头开始编写带有高斯核的核回归算法。要阅读本文,需要具备 Python 和 numpy 的基础知识。

由 Clarisse Croset 在 Unsplash 上拍摄的照片
简单回顾一下线性回归
给定形式为 N 特征向量 x =[ x ₁、 x ₂、… ,x ₙ]的数据,该数据由 n 个特征和相应的标签向量 y 组成,线性回归试图拟合出最佳描述数据的直线。为此,它试图找到直线方程的最优系数 c ᵢ, i ∈{0,…,n}y=c₀+c₁x₁+c₂x₂+…+cₙxₙ然后,获得的方程被用于预测新的看不见的输入向量 x ₜ.的目标 y ₜ
线性回归是一种简单的算法,不能模拟特征之间非常复杂的关系。从数学上来说,这是因为它是线性的,方程的次数为 1,这意味着线性回归总是模拟一条直线。事实上,这种线性是线性回归算法的弱点。为什么?
好吧,让我们考虑一种情况,其中我们的数据不具有直线的形式:让我们使用函数 f(x) = x 生成数据。如果我们使用线性回归来拟合该数据的模型,我们将永远不会接近真正的三次函数,因为我们正在寻找系数的方程没有三次项!因此,对于任何不是使用线性函数生成的数据,线性回归都很可能不足。那么,我们该怎么办?
我们可以使用另一种类型的回归,称为多项式回归,它试图找到(顾名思义)多项式方程的最佳系数,该方程的次数为 n , n ⪈1.然而,多项式回归带来了另一个问题:作为一名数据分析师,您无法知道方程的次数应该是多少,才能使结果方程最适合数据。这只能通过反复试验来确定,由于在 3 阶以上,使用多项式回归建立的模型难以可视化,所以这变得更加困难。
这就是内核回归的用武之地!
什么是内核回归?
看到名字,你可能会问,如果线性回归中的‘linear’是指线性函数,多项式回归中的‘多项式’是指多项式函数,那么‘核’是什么意思?原来,它的意思是一个内核函数!那么,是什么内核函数呢?简单地说,它是一个相似性函数,接受两个输入,并指出它们有多相似。我们将很快看到在核回归中如何使用核函数。
现在谈谈内核回归。与需要学习最优参数向量 c =[ c ₁、 c ₂、… ,c ₙ]的线性和多项式回归不同,核回归是非参数回归,这意味着它通过直接对输入 x ₜ.执行计算来计算目标 y ₜ
怎么会?
给定数据点( x ᵢ, y ᵢ),内核回归通过首先为每个数据点 x ᵢ.构建一个内核 k 来进行预测然后,对于给定的新输入 x ₜ,它使用内核计算每个 x ᵢ(由 x ᵢ- x ₜ给出)的相似性得分;相似性分数充当权重 w ᵢ,其表示在预测目标 y ₜ.时该内核(以及相应的标签 y ᵢ)的重要性然后通过将权重向量 w= [ w ₁、 w ₂、… 、w ₙ]乘以标签向量 y= [ y ₁、 y ₂、… ,yₙ】来获得预测。

作者图片:方程中的核回归
现在,可以有不同的核函数,它们产生不同类型的核回归。一种这样的类型是高斯核回归,其中构造的核的形状是高斯曲线,也称为钟形曲线。在高斯核回归的背景下,每个构建的核也可以被视为具有平均值 x ᵢ和标准偏差b的正态分布。这里,b 是控制曲线形状(特别是高斯核中的高斯曲线的宽度)的超参数。高斯内核 k 的方程式如下所示。注意这个等式和高斯(也称为正态)分布的等式之间的相似性。

图片作者:高斯核方程
接下来我们将编写这种类型的内核回归。
编码高斯核回归
我们将首先查看一维特征向量的情况,然后将其扩展到 n 维。
from scipy.stats import norm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import mathclass GKR:
def __init__(self, x, y, b):
self.x = x
self.y = y
self.b = b
'''Implement the Gaussian Kernel'''
def gaussian_kernel(self, z):
return (1/math.sqrt(2*math.pi))*math.exp(-0.5*z**2)
'''Calculate weights and return prediction'''
def predict(self, X):
kernels = [self.gaussian_kernel((xi-X)/self.b) for xi in self.x]
weights = [len(self.x) * (kernel/np.sum(kernels)) for kernel in kernels]
return np.dot(weights, self.y)/len(self.x)
我们为高斯核回归定义了一个类,它在初始化期间接受特征向量 x、标签向量 y 和超参数 b 。在类内部,我们定义了一个函数 gaussian_kernel() 来实现高斯内核。你可以看到我们只是把数学方程写成代码。接下来,我们定义函数 predict() ,该函数接收目标值需要预测的特征向量 x ₜ(代码中称为 X )。在函数内部,我们为每个 x ᵢ构造内核,计算权重并返回预测,同样通过将数学方程插入代码中。

作者图片:可视化不同的构造内核
现在,让我们传入一些虚拟数据,并查看输出的预测。我们预测 x ₜ = 50 的值(出于演示目的,忽略它已经存在于训练数据中)
gkr = GKR([10,20,30,40,50,60,70,80,90,100,110,120], [2337,2750,2301,2500,1700,2100,1100,1750,1000,1642, 2000,1932], 10)
gkr.predict(50)
这给了我们 1995.285 的输出

作者图片:从图形上,我们可以观察到 x_t = 50 的权重 w_i 是不同核之间的交点的垂线和虚线与 y 轴相交的点
现在,让我们针对 n 维特征向量的情况扩展代码。我们需要做的唯一修改是相似性得分计算。我们不是获得 x ᵢ和 x ₜ之间的差异,而是将 n 维情况下的相似性得分计算为它们之间的欧氏距离|| x ᵢ- x ₜ||。注意,为了处理 n 维向量,我们在需要的地方使用 numpy。
from scipy.stats import multivariate_normal
'''Class for Gaussian Kernel Regression'''
class GKR:
def __init__(self, x, y, b):
self.x = np.array(x)
self.y = np.array(y)
self.b = b
'''Implement the Gaussian Kernel'''
def gaussian_kernel(self, z):
return (1/np.sqrt(2*np.pi))*np.exp(-0.5*z**2)
'''Calculate weights and return prediction'''
def predict(self, X):
kernels = np.array([self.gaussian_kernel((np.linalg.norm(xi-X))/self.b) for xi in self.x])
weights = np.array([len(self.x) * (kernel/np.sum(kernels)) for kernel in kernels])
return np.dot(weights.T, self.y)/len(self.x)

作者图片:可视化构建的 3D 高斯核
同样,让我们传入一些 2D 虚拟数据并预测 x ₜ = [20,40]。
gkr = GKR([[11,15],[22,30],[33,45],[44,60],[50,52],[67,92],[78,107],[89,123],[100,137]], [2337,2750,2301,2500,1700,1100,1000,1642, 1932], 10)
gkr.predict([20,40])
我们得到 y ₜ = 2563.086。
本文的扩展代码(包括可视化代码)可以在 GitHub 和 Kaggle 上找到。
结论
我们看到了线性回归和多项式回归不能使用的地方和原因,并在此背景下理解了内核回归背后的直觉和工作原理,以及如何将其用作替代方法。我们研究了高斯核回归的细节,并通过简单地插入数学方程来编码,用 Python 从头开始编码。
我很乐意在 Linkedin 上与你联系!
参考
1 A .布尔科夫,《百页机器学习书》 (2019),安德烈·布尔科夫出版。
现代强化学习的关键概念
强化学习导论
强化学习设置的基本层次包括一个在反馈回路中与环境交互的主体。代理基于在时间s_{t-1}从处于前一状态的环境接收的响应,在时间s_t为环境的每个状态选择动作。从这个基本设置中,我们已经可以确定强化学习设置中的两个主要组件,即代理和环境。

代理-环境接口的递归表示。在时间步骤t,代理接收环境状态的实例s_t。然后,代理从状态s_t的可用动作集中选择一个动作a_t。在下一次迭代中,代理收到一个新的状态实例s_{t+1}和一个基于在前一个状态s_t中采取的动作a_t的即时奖励r_{t+1}。
当代理与环境交互时,它学习一个策略。策略是一种“习得的策略”,它控制着代理在环境的特定时间t选择动作的行为。策略可以被视为从环境的状态到在那些状态中采取的动作的映射。
强化代理的目标是在反馈配置中与环境交互时最大化其长期回报。代理从每个状态-动作循环中得到的响应(代理在环境的每个状态下从一组动作中选择一个动作)被称为奖励函数。奖励函数(或简称奖励)是基于代理所做的动作的该状态的合意性的信号。
“有利的”奖励可以指示代理的良好的即时事件(即,状态-动作对)。另一方面,“不利的”奖励可能对代理人来说是一个坏事件。奖励函数对于强化代理所面临的问题是唯一的,并且影响代理所做的最优策略的选择。奖励函数在很大程度上定义了强化学习任务。
另一个关键的部分是一个值函数(或者简单的值)的概念。当代理在环境的特定状态下采取行动时,奖励函数向代理传达该状态的直接和内在的合意性。然而,结果可能是,一个有即时高回报的状态可能会导致其他非常不受欢迎的状态。这并不好,因为 RL 代理的目标是最大化长期回报。状态的价值函数是通过考虑可能的未来状态和它们的回报函数而得到的当前状态的预期长期合意性。
归根结底,虽然 RL 代理的目标是最大化价值,但奖励是代理在与环境交互时收到的主要信号。评估价值的想法是在代理人与环境相互作用的每个状态下提高奖励的质量。因此,当代理在一个状态中采取行动时,它基于价值估计来这样做,以便它可以转移到具有高价值的新状态,从而导致长期回报。
奖励很容易获得,因为它们本质上是直接从环境中获得的反馈。另一方面,当主体反复与环境交互并收集更多信息时,必须不断地评估值。寻找一种有效的技术来估计值的任务是设计现代强化学习算法的核心。
然而,重要的是要注意,虽然估计值函数已经影响了现代 RL 文献中的许多想法,但强化学习问题仍然可以在不估计值的情况下解决。但是当然,这种方法的效率、适用性和可伸缩性是另外一个讨论。
最后,我们需要一个环境模型来学习强化学习代理的最优策略。环境模型必须以某种方式表示环境的随机性质,并在采取行动时向代理返回下一个状态和响应。拥有一个环境模型在计划中是有用的,在计划中,代理在采取行动之前考虑可能的未来结果。在任何情况下,强化学习系统也可以是初步的试错学习器,正如在学习自动机理论中看到的那样。通过反复试验学习的代理也可以学习环境的模型,并在以后使用它进行计算规划。
文献学
- 纳伦德拉,K. S .,& Thathachar,硕士(2012)。学习自动机:导论。快递公司。
- 萨顿和巴尔托(1998 年)。强化学习:导论。麻省理工出版社。
【https://ekababisong.org】最初发表于。
用 python 做按键驱动分析
实践教程
回答“是什么驱动了糖果的魅力?”这个问题的指南

图片由作者提供,仪表盘可用此处
在几年前的一次数据科学采访中,我被要求使用来自我们在 FiveThirtyEight 的朋友的一个小数据集来建议如何最好地设计一款畅销的糖果。“根据你在这里看到的‘市场调查’,”提示示意道,“建议产品设计团队一种糖果的最佳特性,我们可以和品牌糖果一起销售。”

FiveThirtyEight 的原始数据集,可在线获取点击
作为应用和商业领域的数据科学家,最好的这个词总是用来测试你的商业意识。更环保的数据科学家的一个典型标志是,他们是否在考虑最佳业务成果与最佳机器学习模型。“最佳”是“哪些糖果元素带来最高的满意度/享受度?”的平衡以及“哪些糖果元素推动了最高价格?”我们基本上是在努力寻找平衡
- 一种保证能取悦消费者的糖果
- 占据足够的空间,不仅仅是“山寨、打折 M & Ms”
- 还经过成本优化,比 M & M 更便宜,从而提高了利润率。
我们在 FiveThirtyEight 的朋友在试图解决#1 时犯了一个严重的统计错误(或两个)。
本教程通过使用适当的统计工具在 python 中进行“关键驱动因素”分析,脱离了 FiveThirtyEight 方法。在这个过程中,我解释了 1)为什么数据科学家和产品策略师应该更加信任我的数据,以及 2)如何以一种赢得信任的方式传达这些结果(参见我的糖果仪表盘)。
下面是本文的路线图:
- 方法:线性回归不正确,使用相对权重分析
- 实现:在 python 中进行 RWA 以获得糖果的味道和价格
- 三角测量:为什么企业应该通过三角测量信任 RWA
统计第一,ML 第二
让我们通过理解为什么线性回归不是正确的答案…或者至少不是正确的答案来开始我们的统计方法。
FiveThirtyEight 建立了一个多元回归,包括在他们的数据集中捕获的糖果的所有可能特征。重要性是从线性回归的系数中提取的,使用维度的 P 值来定义我们是否可以将其视为可靠。

多元回归方程
然而,看看线性回归的方程,我们看到一个非常重要的问题。记住:OLS 回归系数告诉我们自变量的增加是否与因变量均值的增加相关(反之亦然,为负)。但这是衡量数量的标准。
在我们的糖果问题中,如果我们建立一个 OLS 回归来预测糖果棒的中奖情况,并将单位从克改为磅,我们将得到一个高得多的系数。体积除了单位没有改变任何东西。这里的论点可能是你可以标准化你的变量,比如标准化到 0 均值和单位方差。然而,通过归一化,您可能会遇到共线性问题-如果预测值是线性相关的或高度相关的,则 OLS 会变得不稳定,即使对自变量进行了标准化也是如此。
所以我们的工具箱里还需要一个工具。一些可以帮助我们避开关于系数的坏假设的东西。虽然 ML 可能没有答案,但统计学有。
相对权重分析和为什么 R2 是真正的绝地
这里,我们将实现代码,告诉我们每个特征/自变量对标准方差(R2)的贡献有多大。在其原始形式中,相对权重分析返回原始重要性分数,其总和等于模型的总体 R2;它的规范化形式允许我们说“特征 X 解释了目标变量 Y 中方差的 Z% 或者,更具体地说,
“假设让一种糖果受欢迎的关键驱动力在这里被抓住,坚果巧克力是最受欢迎的口味组合。”
相对权重分析依赖于 R2 分解来分配每个预测值的重要性。当独立变量之间的相互关联使得几乎不可能将标准化回归权重作为重要性的衡量标准时,RWA 通过创建相互正交的预测值并在没有多重共线性影响的情况下对其进行回归来解决这一问题。然后,它们被转换回原始预测值的度量。

从到的三特征 RWA 示例
我们涉及到多个步骤,我将通过一个 python 脚本来演示,而不是用符号来演示,您将能够使用这个脚本(如果您一字不差地使用这个脚本或派生出您自己的版本,请相信这篇文章!)我假设此时您已经完成了构建逻辑和数学上合理的模型所需的 EDA 和操作。
用 Python 实现 RWA
第一步:获得所有因变量和自变量之间的相关性。
步骤 2 :使用相关矩阵上的特征向量和特征值创建正交预测器,创建特征值平方根的对角矩阵。这避免了多重共线性的问题。注意获取对角线索引的 python 技巧。
第三步:乘特征向量矩阵及其转置(在 python 中,我们可以用@作为运算符,称为 matmul)。这允许我们将 X 视为因变量的集合,将 X 回归到矩阵 Z 上——矩阵 Z 本身是 X 的正交对应物,具有最小的平方误差。为了得到每个独立变量的部分效应,我们将矩阵乘法应用于逆矩阵和相关矩阵。
注 :如前所述,上面 coef_yz 的平方和应该加起来就是总 R2!这在下一步中将很重要!
步骤 4 :然后我们计算相对权重,作为步骤 2 和步骤 3 中矩阵的乘积。标准化后的版本就是 r2 的百分比!
现在,您只需拉上您的功能和这两个列表的拉链,就可以获得每个功能的相对权重,因为它“驱动”(或者,更数学地说,解释与增加相关的差异)了糖果对偶的获胜百分比。

预测胜率的原始和正常相对权重
巧克力和坚果赢得了口味,但我们还没完。我们还必须通过从我们创造的糖果中创造价值来赚钱,以收入减去成本来衡量。使用表中的价格百分位数,我们还可以看看是什么推动了糖果的价格。

价格百分位预测的原始和正常相对权重
向企业传达结果
我们在这里有两个责任:提出建议,并让利益相关者乐于执行这些建议。

plt 总是一个很好的动态可视化事物的科学方法。对许多利益相关者来说,好的科学和坏的可视化是密切相关的。
建议 1 :巧克力占了糖果成功的 38%,而花生占了 15%。我们可以通过观察样本中巧克力和花生糖的相对成功率来证实这一点。

建议 2 :相对于其他形式,Pluribus 糖果的成本最低(相对重量 3%),这有助于抵消我们的巧克力和坚果成本。

推荐 3: 根据我们的数据,美味的 pluribus chocolatey peanutyalmondy 糖果尽管性能更高,但并不容易获得。在我们的数据集中只有 2 个被捕获。
通过分析亚马逊杂货数据中的糖果,这些建议可以得到进一步的支持,该数据有 290 万条糖果评论。
虽然在亚马逊的数据中,水果在味道/评论得分上超过了坚果,但它仍然排在前三名。

风味在预测亚马逊杂货店约 3M 糖果评论分数中的重要性的相对权重分析
此外,从高销量(>第 50 个百分点)、高排名(> 3 星)的亚马逊巧克力和坚果评论构建的主题模型进一步表明,我们的风味特征是一个成功的决定。

这是洞察交付幻灯片的一个示例。我的幻灯片的最终版本有 5 张幻灯片:首先是建议,然后是 RWA 可视化,然后是确认结果,最后是“这是风险/不确定性所在,以及我们如何试图将其最小化”的幻灯片。
结论
事实上,我们可能会认为关键驱动因素分析有点像寻找圣杯,因为有如此多不同的可能混淆的变量,以至于知道拉什么杠杆来驱动我们的目标变量是一种无中生有的尝试。但是我们可以通过放弃传统的(尽管是错误的)线性回归系数的使用,并转向相对权重分析来获得更好的信心。而且,可以肯定的是,这个版本有一些改进——如果你关注 R2 风味概况,并亲自尝试定价,你会发现通过各种数学优化还有改进的空间。
隐藏在这里的是一个关于数据科学家必须精通降低商业风险和最大化决策潜力背后的统计学和数学的故事。否则,我们只是解决输入/输出问题的廉价软件开发人员/工程师,这些问题会给企业带来巨大的成本。
对于那些 DS 领导者和经理读者来说,这个例子表明,建立一个不同时拥有面向统计和技术的数据科学家的数据科学团队是一个灾难。为什么?那么,在这种情况下,“我们如何做出最好的糖果?”,是一个统计问题和业务领域问题,不容易用 sklearn API 调用解决。
通过使用 Tidyverse 挖掘性别平等数据获得的关键见解
确定关键绩效指标,以评估妇女对国家和全球一级决策的贡献。

萨曼莎·索菲亚在 Unsplash 上的照片
性别不平等是最受关注的领域之一,这促使联合国(UN)制定了可持续发展目标 5 — 实现性别平等并赋予所有妇女和女童权力。为了评估当今世界的情况,最好的评估标准之一是根据妇女在领导和决策方面的贡献对国家进行排名。为了在同样的基础上形成见解,可以将妇女在国家议会中所占席位的比例(%) 视为基石(数据)。其背后的原因是,在当今世界,许多地区的歧视性法律和制度性做法限制了妇女竞选政治职务的能力。系统性不平等、缺乏受教育机会、参与劳动力的选择有限以及对个人自由的许多其他限制,限制了妇女获得追求政治生涯的资源和机会。
关于数据
数据来源是改头换面星期一挑战(2020W30) 的一部分,并由世界银行整理,作为其世界发展指标数据库的一部分。数据揭示了全国妇女在国家议会中所占席位的比例(%)(1997-2019 年)。这些数据是可视化性别平等——viz 5计划的一部分。
探索性数据分析
从数据中获得洞察力的第一步是探索数据。对于这个场景,使用了 Tidyverse ,这是在 r 中进行 EDA 的一个关键要素。以下是数据的一瞥:
head(Female_Political_Representation)Country.Name Country.Code Year Proportion of Seats
1 Albania ALB 1997 NA
2 Albania ALB 1998 NA
3 Albania ALB 1999 0.05161290
4 Albania ALB 2000 0.05161290
5 Albania ALB 2001 0.05714286
6 Albania ALB 2002 0.05714286
对于每个国家,我们都有国家代码、年份(1997-2019)和女性所占席位的比例。从这一瞥中,我们可以看到我们缺少价值观。
让我们检查缺失值是在初始年份还是在随机地点。
missing_data <- filter(Female_Political_Representation, is.na(`Proportion of Seats`)) %>% # Filter only Missing values
group_by(Year) %>% # Group by Year
summarise(count = n()) %>% # Count the instances
arrange(desc(count)) # Arrange in descending order> missing_data
# A tibble: 20 x 2
Year count
<int> <int>
1 1999 31
2 1997 23
3 2000 22
4 2002 17
5 1998 16
6 2001 13
7 2003 6
8 2013 4
9 2014 4
10 2017 3
正如我们所见,缺失数据是随机分布的。因此,对于插补,我们可以遵循两种方法:
- 捕捉单个国家的趋势,并将其用于估算该国的缺失年份。
- 在国家级别使用向前填充|向后填充方法估算缺失值。
我更喜欢后一种方法,并通过给出方向“向下来使用填充的方法
Imputed_data <- Female_Political_Representation %>%
group_by(Country.Name,Country.Code) %>% # Group at Country Level
fill(`Proportion of Seats`, .direction = "downup") # Missing Value Imputation
colSums(is.na(Imputed_data)) # check for completeness
识别 KPI
插补后的关键目标是确定特定国家如何有效实施对性别问题有敏感认识的议会——妇女有充分参与的自由。可以通过计算妇女席位比例的年同比变化来评估。以下是可以创建的两个指标:
- 与前一年的差异:通过用前一年的值减去特定年份的值来获得。它可以被视为计算提升的一种手段——差异越积极,国家就越有可能提高对性别平等的认识。此外,我们可以根据这一指标对国家进行排名。
- 差额 vs 起点:计算当年比例与起点的差额。公式:比例(2019)-比例(1997)。差异越大,国家在权力结构和组织中实现性别均衡代表性的进展就越好。
生成见解
使用 tidyverse ,我们可以通过使用 lag 函数轻松计算出 ***与一年前*** * 的差异。*
# difference vs Year Ago Compute (At Country Level) ----KPI1 <- Imputed_data %>%
group_by(Country.Name,Country.Code) %>%mutate(Diff_vs_Year_Ago =
`Proportion of Seats` - lag(`Proportion of Seats`)) %>%
#Difference vs Year Ago fill(Diff_vs_Year_Ago, .direction = "downup") %>%
# Missing Value Imputation mutate(`Proportion of Seats` = round(`Proportion of Seats` *100,2),
Diff_vs_Year_Ago = round(Diff_vs_Year_Ago*100,2)
# Data Standardization)
我们可以对国家进行排名,以查看年度水平,哪个国家的进步最大/最小。
# Rank the differences at Yearly level ----
Rank1 <- KPI1 %>%
group_by(Year) %>%
mutate(rank = rank( - Diff_vs_Year_Ago, ties.method = "first"))
对于 2019 年(最近一年),我们可以借助 ggplot2 和 plotly 来可视化前 10/后 10 个国家:
library(plotly)
# Plot Top 10 Countries
top_10_plot <- Rank1 %>%
filter(Year == 2019 & rank < 11) %>%
ggplot(aes(x=reorder(Country.Name, `Proportion of Seats`), y= `Proportion of Seats`,fill = Country.Code)) +
geom_bar(stat="identity")+
theme_minimal() +
theme(legend.position = "none") +
xlab("Country") +
coord_flip()# Convert to plotly
ggplotly(top_10_plot)

十大国家(2019 年与 2018 年)
故事要点:与去年相比,排名前 3 位的国家表明他们增加了超过 10%的席位比例,其中阿联酋以 27.50%的比例高居榜首
# Plot Bottom 10 Countries ----
bottom_10_plot <- Rank1 %>%
filter(Year == 2019 & rank >205) %>%
ggplot(aes(x=reorder(Country.Name, - Diff_vs_Year_Ago), y= Diff_vs_Year_Ago,fill = Country.Code)) +
geom_bar(stat="identity")+
theme_minimal() +
theme(legend.position = "none") +
xlab("Country") +
coord_flip()# Convert to plotly
ggplotly(bottom_10_plot)

垫底的 10 个国家(2019 年与 2018 年)
故事要点:与去年相比,所有排名后 10 位的国家都显示出了不到 0%的下降率,其中突尼斯以-8.7 %的下降率高居榜首
我们可以执行顶部/底部分析的另一个角度是查看国家如何随着时间的推移而演变(‘差异 _ 对比 _ 起点’)。我们可以在国家级别进行分组,并使用‘first’方法计算每个实例与起始年份的差异。
# Difference vs start Compute ----
KPI1 <- KPI1 %>%
arrange(Year) %>%
group_by(Country.Name) %>%
mutate(Diff_vs_Start = `Proportion of Seats` - first(`Proportion of Seats`))# Compute Rank basis at Yearly Basis
Rank2 <- KPI1 %>%
group_by(Year) %>%
mutate(rank_Diff_vs_Start = rank( - Diff_vs_Start, ties.method = "first"))
对于 2019 年(最近一年),我们可以将前 10 名/后 10 名国家定位如下:
top_10_plot1 <- Rank2 %>%
filter(Year == 2019 & rank_Diff_vs_Start < 11) %>%
ggplot(aes(x=reorder(Country.Name, Diff_vs_Start), y= Diff_vs_Start,fill = Country.Code)) +
geom_bar(stat="identity")+
theme_minimal() +
theme(legend.position = "none") +
xlab("Country") +
coord_flip()# Convert to plotly
ggplotly(top_10_plot1)

前 10 个国家(历史上有所改善)
故事要点:历史上排名前三的国家,如阿联酋、卢旺达和玻利维亚,表明它们的席位比例增加了 40 %以上,其中阿联酋以 50%的比例高居榜首。

垫底的 10 个国家(历史上有所改善)
故事要点:与起点相比,历史上所有垫底的 10 个国家的增长率都呈下降趋势,低于 0%,其中塞舌尔以-6.2 %的增长率高居榜首
**全球层面的见解—
从全球绩效的角度来看,我们可以忽略国家/地区,按年度对数据进行分组,并获得修订的 KPI,如下所示:
# Global Level Trend ----
Global_Insight <- KPI1 %>%
group_by(Year) %>%
summarize(
Avg_Proportion_of_Seats = mean(`Proportion of Seats`),
Avg_Diff_vs_Year_Ago = mean(Diff_vs_Year_Ago),
Avg_Diff_vs_Start = mean(Diff_vs_Start)
)> mean(Global_Insight$Avg_Diff_vs_Year_Ago) # Compute Average Lift
0.5781982##########################################################Year Avg_Proportion_of_Seats
<int> <dbl>
1 1997 10.4
2 1998 10.8
3 1999 11.2
----------------------------------
4 2017 21.9
5 2018 22.5
6 2019 23.3
##########################################################
此外,我们可以使用这些数据来创建一个面积图,它将展示全球趋势,如下面的代码所示:
# Area plot ----# Plot 1
Avg_Proportion_of_Seats_plot <- ggplot(Global_Insight, aes(x = Year, y = Avg_Proportion_of_Seats)) +
geom_area(fill ="#00AFBB", alpha = 0.5, position = position_dodge(0.8))ggplotly(Avg_Proportion_of_Seats_plot)# Plot 2
Avg_Diff_vs_Year_Ago_plot <- ggplot(Global_Insight, aes(x = Year, y = Avg_Diff_vs_Year_Ago)) +
geom_area(fill ="#ff7a00", alpha = 0.5, position = position_dodge(0.8))ggplotly(Avg_Diff_vs_Year_Ago_plot)# Plot 3
Avg_Diff_vs_Start_plot <- ggplot(Global_Insight, aes(x = Year, y = Avg_Diff_vs_Start)) +
geom_area(fill ="#0dff00", alpha = 0.5, position = position_dodge(0.8))ggplotly(Avg_Diff_vs_Start_plot)# Combine 3 plots ----
library(ggpubr)
theme_set(theme_pubr())figure <- ggarrange(Avg_Proportion_of_Seats_plot, Avg_Diff_vs_Year_Ago_plot, Avg_Diff_vs_Start_plot,
labels = c("Avg_Proportion_of_Seats", "Avg_Diff_vs_Year_Ago", "Avg_Diff_vs_Start"),
ncol = 1, nrow = 3)figure

环球之旅(1997- 2019)
故事要点:我们可以看到,全球级别的席位比例从 10.4% (1997 年)上升到 23.3% (2019 年),平均每年增长 0.57%。此外,Diff_vs_Year_Ago 经历了高峰和低谷,2007 年涨幅最大,2010 年跌幅最小
结束注释
这一洞察生成之旅始于探索和清理数据、标准化数据(缺失值插补)、识别 KPI、创建有效的视觉效果来回答问题,并从中讲述一个有意义的故事。此外, tidyverse 可以快速方便地从数据中挖掘见解,这些数据稍后可以集成到 tableau public 中,以创建快速的视觉效果和故事线,如下所示:

Tableau 公共仪表板(https://public.tableau.com/profile/gaurav.chavan#!/viz home/改头换面 Monday 2020 w30 _ 15961721926540/global journey?发布=是
上图预测表明,到 2030 年,妇女在政治角色中的比例仅为27.67%,而不是联合国达到 50%的目标。****
链接到Tableau 公共仪表盘: 链接****
链接到代码和视觉效果:链接
熊猫初学者的关键编程概念

照片由 PhotoMIX 公司从 Pexels 拍摄
如果你刚刚开始使用 Python 或熊猫,欢迎使用。
让我先简短地说几句鼓励的话。
学习编码在开始时可能会感到有点令人生畏,因为有很多未知的东西。
除此之外,有时你周围的人会让你泄气: 你没有合适的背景……如果你不知道 x,你就做不了 y……开始接触技术的唯一正当途径是获得学位。
他们错了。
与任何学科一样,编程是一种技能组合,存在于一个范围内。不要相信任何循环论证,如果你不知道如何写代码,你就不能写代码。你唯一需要的是坚持。
你属于。
事实是有很多东西需要学习。这并不总是容易的,需要持续的努力才能达到这个技能范围。
在这篇文章中,我将提供一些基本编程概念的概述,以便当您开始编写 Pandas 代码时,您对正在发生的事情有一个更好的了解。
我会试着把每个概念都带回熊猫图书馆,以便尽可能地让它变得有形。
语言与图书馆
简而言之,编程语言是一套规则和惯例,控制我们如何指示计算机做我们想让它做的事情。
不同的编程语言使用不同的词汇或“语法”。
在 python 中,我们可以通过编写以下内容让计算机返回单词“hello world ”:
print(“hello world”)
在 Java(另一种编程语言)中,我们写道:
System.out.println("hello world");
在幕后,编程语言从高级词汇,如“print”,一直向下转换到 1 和 0。
我们的计算机可以“理解”1 和 0,因为我们可以用物理状态来表示这些值。
例如,我们可以使用电灯开关。当它打开时,我们可以说它代表数字 1,当它关闭时,它代表 0。

伊莎贝拉和路易莎·菲舍尔的照片
电脑有数十亿个被称为晶体管的微小开关,它们以同样的方式工作。结合在一起,它们编码了你需要的所有数据。
“高级”语言离那些 1 和 0 更远,这意味着从语言到硬件状态需要更多的转换。
“低级”语言更接近于 1 和 0,需要较少的翻译。
这里有一个自然的折衷——高级语言往往更慢,但更容易使用。低级语言往往更快,但更难使用。
另一方面,库(又名包)是其他人用编程语言编写的代码,然后整齐地捆绑起来,以便其他程序员可以借用。
Python 是一种编程语言。Pandas 是一个开源软件(即免费的、公开可用的)用 python 编写的数据分析库。

Python 成为数据分析如此受欢迎的选择的原因之一是因为它的开发人员社区已经创建了大量有用的库,包括 Pandas、Numpy、Matplotlib、Scikit-learn 等等。
当我们想要利用这些库中的一个时,我们需要安装代码(一次)并将其导入到我们的文件中(每次我们想要使用它时)。
数据类型/类
就其核心而言,编程就是转换数据;将输入转换成输出。
但并不是所有的数据都一样。我们有不同的数据类型,可以用不同的方式使用。
为了进一步说明这一点,让我们比较两种最常用的数据类型——字符串(也称为文本)和整数。
整数可以整除。字符串不能。

4/2=2.但是“你好”/“再见”并不代表什么。
相反,可以大写字符串,但不能大写整数。
因此,区分数据类型的主要因素是与它们相关联的功能。
在 Python 这样的面向对象语言中,我们可以创建自己的数据类型,通常称为类。
类是一个蓝图,它告诉我们可以用我们的数据类型(方法)做什么,以及我们可以存储关于它们的什么信息(属性)。
一个类的单个实例称为对象。
从上面的例子中,我们可以对字符串运行资本化方法:

但不是 int:

Python 有一些内置的数据类型(类),如 int、string、boolean、list 等。
Pandas 也有自己的类,使得数据分析工作成为可能。
Pandas 中最流行的类是 DataFrame,它存储表格数据(像 excel 电子表格)。
设计 DataFrame 类的开发人员编写代码来赋予它所拥有的功能。
例如,我们可以使用“to_csv”方法用数据帧中的数据创建一个 csv 文件:
dataframe.to_csv(‘my_df.csv’)
同样,这个功能与 DataFrame 类相关联,data frame 类是 Pandas 库的一部分。
通俗地说:别人写了很多代码让你不用。
这就是术语抽象的含义——也是编程中最令人敬畏的事情之一。
其他人写了数百万行代码,从 1 和 0,到 python 语言,到 Pandas 库,到 DataFrame 类,到 to_csv 方法。
但是你所要做的就是写一行代码。
变量
变量是存储值的容器。
在一些语言中,你需要给一个变量分配一个特定的数据类型(这些被称为静态类型语言)。
在其他语言中,您可以将数据存储在变量中,而无需分配特定的类型(动态类型语言)。
Python 是动态类型的。因此,我们可以直接在变量中存储一个值:
my_variable = 5
Java 是静态类型的,所以如果我们想将整数 5 直接放入变量中,我们必须声明该变量是整数的容器,而不是任何其他数据类型的容器:
Int myVariable = 10
我们的变量可以“存储”python 中的任何类。
功能
功能是将输入转换为输出的过程。
如果这听起来很熟悉,那应该是。
我们已经讨论过“方法”,它是函数的一种类型。所有的方法都是函数,不是所有的函数都是方法。
关键的区别在于方法被绑定到特定的数据类型/类,而一般的函数没有。
如果这令人困惑,一个例子应该可以澄清事情。
当我们想要大写一个字符串时,我们可以调用 capital 方法。这个方法是显式绑定到字符串的。
另一方面,我们可以创建自己的函数,不依赖于特定的类。
假设我们想写一个将数字 5 加到字符串末尾的函数:

现在我们有一些功能不是由 对象调用 ,而是由 用户自定义输入(input_string)调用 。
理论上,字符串可以拥有这个方法。但是期望 python 在 string 类的定义中考虑这种任意的任务是荒谬的。
在真正的意义上,函数帮助我们创建可重用的代码,这些代码还没有被我们正在使用的语言或库所考虑。
Pandas 用户最常犯的一个错误是在使用数据执行分析任务时没有利用函数。
这导致了混乱和重复的代码。
混乱和重复的代码更容易出错,也更难维护。
无论是在实践中还是在理论上,当您想要重用您正在编写的代码时,使用函数是最佳实践。
将功能限制在一定范围内也是最佳实践,这样每个功能都执行一个独特且独立的任务。
函数通常有输入,称为“参数”。这些是你的函数代码的组成部分。它们通常会以某种方式用于产生输出。
直到用户(通常是您自己)通过传入值来代替这些参数来运行该函数,否则什么都不会发生。
您传入的值在技术上称为“参数”。
这里有很多单词需要记录,所以让我们以一些示例代码结束,这些代码涵盖了上面讨论的大多数概念:

结束语
在这篇文章中,我们介绍了一些最重要的编程概念,以及它们如何应用于 Pandas 库。
如果你想了解更多关于如何开始接触熊猫的知识,请查看我的一些直观指南,并确保在下面订阅。编码快乐!
数据科学中的关键统计概念

丹·法雷尔在 Unsplash 上的照片
一些必须知道的统计概念的汇编
如果你在处理数据,你可能经常会遇到术语,比如“测试”、“分数”、“值”等等。以字母开头,如‘F’,‘P’,‘R’,‘T’,‘Z’等。这篇文章是关于一些在数据科学领域经常遇到的统计术语/概念的通俗解释。
免责声明:这篇文章不是关于什么?
本文不是关于提供全面的解释,而是对一些关键统计指标的 简明和高层次的汇编。下面的每个概念都有几篇专门的文章。我将提供几篇这样的文章的链接供你参考。
将涵盖以下主题:
1) H_0 和 H_a —假设检验
2) P 值
3) Z 分数
4) t 检验
5) F 检验
6) R 平方
1) H_0 和 H_a —假设检验
简单地说,假设是你想要测试(或验证)的想法(或前提或主张)。例如,喝着咖啡,你开始思考,“纽约州人的平均身高与加利福尼亚州人的平均身高相比如何?”这是你的想法。

Franki Chamaki 在 Unsplash 上拍摄的照片
现在,为了测试你的想法/主张,你需要一些数据。此外,你需要构建一个问题陈述——一个假设,为了检验这个假设,你需要一个假设检验。更具体地说,你需要设计两个场景——一个支持你的主张,另一个是备选场景。
一个零假设基本上是现状(或者默认的建立或普遍接受的价值,正如这个视频很好地解释的那样)。例如,现状可能是两个州的人的平均身高是相等的。这将形成你的零假设, 记为 H_0 。在法庭上,你有起诉和辩护。同样,对于每一个零假设,你都有一个备选(或替代)假设(为了测试你的想法/主张),记为 H_a (又名研究假设,因为你需要做一些研究/采样来挑战 H_0)。
阐明了你的无效假设和替代假设后,你现在需要一些数据。当然,测量纽约和加州完整人口的身高是不切实际的。因此,你会为一些人(比如 50 或 100 或更高)收集样本数据来测试你的说法。有了样本数据,您将执行一些统计测试,这将在接下来的部分中解释(使用其他等效的示例)。
更多资料:
2) P 值
该术语主要用于在假设检验中测量 结果的统计显著性。这里, P 代表“概率”。所以,它是一个介于 0 和 1 之间的概率值。你用它来拒绝或支持零假设。****

与P-值密切相关的是显著性水平(由希腊字母 alpha 表示),通常为 0.05(或 5%)。基本就是 100%减去的置信水平。较高的α水平意味着较低的置信区间,反之亦然。
如果 P 值小于该显著性水平,则拒绝零假设。如果P-值大于显著性水平,则支持替代假设的支持度不那么强,因此,零假设为未被拒绝,即替代假设为未被接受。
我个人觉得,当“重要性”的意义与“偶然性”定量相关时,P 值更直观。例如,0.01 的P-值(实际上是一个很小的值)表示有仅仅 1%的机会(概率)您对样本进行的实验结果是“偶然”获得的,或者是由于某种采样误差而“随机”发生的。换句话说,你可以庆幸你获得的结果确实 非常显著。简单地说,P-值越小,你的结果就越有意义,随机或偶然发生(获得)的可能性就越小。按照这个逻辑,一个高的 P 值,比如 0.7,意味着你的结果有 70%的概率是偶然得到的,这与你进行实验的方式无关。所以,你现在的发现没那么重要了。
我的显著性水平(alpha)是太严格还是太宽松?
回答:要看手头的问题。想象一下,通过拒绝零假设,你做出了一个错误的决定,也就是说,尽管现在你选择了另一个假设,你拒绝零假设的选择不是一个好的选择。你只是拒绝了它,因为你的 P 值低于 alpha 值。您只是遵循规则(基于您在研究之前设置的 alpha 值)。但是,并不是所有的规则都是好的。
现在,如果你正在对球员踢点球的平均速度进行假设测试,你必须对 95%的置信区间感到满意,也就是说,为拒绝零假设留出 5%的宽窗口(可以认为是 5%的宽松),或者为做出错误决定留出 5%的窗口。那很好。 这只是踢腿的速度。 然而,如果你正在研究一些关键的东西,比如说非侵入性治疗对患者肿瘤的影响,你肯定会想要一个高置信区间,可能是 99.9%,留下 0.1%的显著性水平,即 0.001(把它想象成只有 0.1%宽松;非常非常严格地与肿瘤分析妥协。现在你有一个只有 0.1%的小得多的窗口来做出错误的决定(假设这里的“错误”是指拒绝零假设,接受替代假设)。
关于 P 的更多文章-值:
- 关于数据科学的 p 值,你应该从头开始了解的一切
- 数据科学家解释的 P 值
- 为数据科学家简单解释 P 值
- P 值的圣杯以及它们如何帮助我们进行假设检验
- P 值,以及何时不用它们
- 假设检验和 P 值的直观解释
- 统计显著性解释
3) Z 分数

照片由марьянблан| @ marjanblan在 Unsplash 上拍摄
a【Z】-score(又名标准分数)告诉你距离(下方/左侧或上方/右侧)多少个标准差,一个观察值是正态分布的平均值。它既可以取正值,也可以取负值。负的Z-分数意味着数据点是均值左侧的 Z 标准差,正的Z-分数意味着数据点是正态分布均值右侧的 Z 标准差,该数据点属于正态分布。
在哪里使用 Z -score?
一个重要的应用是计算与给定数据点相关的正态曲线下的(概率)面积。 什么都没听懂?继续读!

迪伦·吉利斯在 Unsplash 上的照片
下面举一个改编自这个精彩视频的例子。假设你的瑜伽班参与者的年龄遵循正态分布(下图中的左曲线),平均值为 50(岁),标准差为 10(岁)。我知道,当你接近退休的时候,你需要瑜伽!
现在,你被问及 35 岁以下参与者的比例(曲线下的红色阴影区域)。要回答这个问题,您必须首先使用下面的公式将标准化正态分布,即均值= 0,标准差= 1 的正态分布。标准化分布中 x 轴上的值以偏离平均值(0)的标准偏差表示,代表Z-分数。35 年的值现在偏离平均值-1.5 个标准偏差,即Z-得分为-1.5。根据定义,Z-分数是无单位的。

正态和标准正态分布示意图(未按比例绘制)。
于是,求 35 岁以下参与者比例的问题转化为求 Z < -1.5 的比例。现在你要做的就是,查Z-评分表得到 Z = -1.5 对应的数值。该值为 0.0668。这是所需的比例(红色阴影区域的面积,其中黑色曲线下的总面积为 1) — 6.68%的参与者。
Z 分数的一些进一步应用
同样,您可以使用 Z -score 来比较两个或更多数据具有不同刻度的情况。例如,寻找前 10%的学生,他们参加了两种不同的考试(不同的分数系统),如 GMAT 和 SAT。
另一个应用是检测人群/数据集中的异常值。如何?标准化人口分布(如果是正态的)并标记位于Z-分数-3 以下和Z-分数+3 以上的数据点,因为这些点将超过平均值的标准偏差的 3 倍,即概率为 0.003(99.7%的区域位于正负 3 个标准偏差内)。
进一步材料:
4) t 检验
这是一个假设检验(又名学生的t-检验)允许您确定两个研究组/样本之间是否存在显著的统计差异,其数据点假定为正态分布。

乔纳森·法伯在 Unsplash 上拍摄的照片
一个例子:
假设你想比较两个不同大陆的人的身高。你取两个独立/不成对的样本,每个大洲的人口各取一个,假设他们是正态分布的。虽然你可以简单地说,你可以比较两个样本的平均值,并说平均值较大的大陆有较高的人。但是样本分布中的方差/分布呢?可以是样本在上有显著差异。
这就是 t 值发挥作用的地方。正如这个视频很好地解释的那样,它基本上是信号(均值差异)和噪声(两个样本内的变化),如下图所示。两个平均值之间的差值越大,则 t 值越高。变化越大, t 值越低。

解释 t 值计算的草图(改编自这段视频)
现在你可以使用这个t-假设中的值t-测试,你的零假设可能会说两个样本之间没有统计学上的显著差异。如果t-值高于临界t-值(类似于显著性水平α,在p-值的情况下),则零假设被拒绝(即两个样本在统计上不同),而支持替代假设。如果 t 值低于临界 t 值,则不拒绝零假设。
如何选择临界t-值?
可以使用t-表找到临界值。要使用t-表,您需要一个预定义的p-值和自由度 f ,它就是 n -2,其中 n 是两个样本中数据点的总数(总样本大小)。使用这两个值( p 和 f ,可以查找临界t-值。
进一步材料:
- 使用 Python 和 Numpy 进行 T-test
- 统计测试——何时使用哪一种?
- 为初学者和专家讲解的统计分析 t 检验
5) F 检验

为什么 F ?这项测试以 R. A. Fischer 的名字命名,他发展了这个概念。 F 测试广泛用于比较适合数据集的统计模型,以确定哪一个更好地解释或捕捉了独立/目标变量的方差。
测试的一个关键应用是在回归问题的背景下。具体来说,给定一个带有一些参数 p_ 1 的回归模型(称为限制模型),它允许您确定一个更复杂(更多回归者)的带有 p_ 2 参数(p _2>p _1)的回归模型(称为非限制模型)是否是为您的数据建模的更好选择。**
注意: 不要把 P1 和 p2 与前面介绍的 p 值混淆。
最简单的(最简单的/基本的)受限模型可以是一个简单的、仅截距的模型(例如,你的目标数据的平均值),具有 p _1 = 1。在仅截距模型中,所有回归系数都为零。紧接的下一个有竞争力的、不受限制的模型可以是除截距之外仅具有一个独立特征的模型,即 p _2 = 2。同样,您可以将 p _1 和 p _2 推广到任何值。
使用 f 检验
您可以在假设测试的上下文中使用F-测试,方法是制定一个空假设 H _0,声明“非限制模型的 并不比限制模型的 好很多。”相应的替代假设 H_a ,将是无限制模型 明显优于限制模型 。
在下面的公式中,下标 1 和 2 分别对应于受限和非受限模型,RSS_1 和 RSS_2 作为它们各自的残差平方和。显然,分子表明与无限制模型(模型 2)** 相比,限制模型(模型 1)仍然无法解释多少方差。**

F 统计量的定义。术语(p2—P1)和(n_p2)代表自由度,其中 n 是样本中数据点的数量。
有了 F 统计量的计算值,你需要一个预定义的显著性水平 p** (就像上面的 t 测试一样;通常 0.05 表示在 95%的置信区间评估 F 统计值)。现在,在零假设的假设下,F-统计量遵循一个F-分布,该分布具有两个自由度作为其两个特征参数。最后,为了测试你的假设(要求),你查阅F-分配表,其中 df_1 将是你的第一个自由度, df _ 2 是第二个自由度。对于您预定义的p-值,F-分配表中 df _1 和 df _2 的交点将是临界值。**如果你计算的F-统计值大于临界值,你拒绝零假设,反之亦然。****
直观地说,F-统计公式中分子的巨大差异意味着非限制模型(模型 2)比限制/简单模型(模型 1)解释了更大的数据方差。因此,F-统计值越高,模型 2 越好,拒绝零假设的机会越大。****
F 测试的另一个关键应用是对一组样本进行方差分析(ANOVA ),以确定它们在统计上是否不同。
延伸阅读:
6) R 平方
注意:这是而不是任何称为 r 的变量的平方。

它被称为决定系数,通常表示为 R ,读作R-平方。它表明与目标变量平均值的简单基线猜测相比,您的模型拟合得有多好。更准确地说,它测量的是目标(响应/相关)变量的变化有多大比例是由您的模型确定(捕捉、解释或预测)的。
下面的定义 R 的就说清楚了。

解释 R 计算的草图(重绘自 Wiki )。

公式中的两个彩色项是什么?
这两项都是方差。所以,第二项基本上是两个方差的比值。
- 蓝色项是残差平方和****
- 洋红色项是总平方和(根据定义,与数据的方差成比例)
****如果你的模型是一个完美的拟合,你右边图中的黑色直线将穿过每个数据点,公式中的蓝色项将为零,导致 R = 1 。如果您的模型 f 只是目标变量 y 的平均值,即基准模型,您将得到蓝色项等于品红色项,从而得到 R = 0。
例如, R 值为 0.85 意味着您的模型捕捉到了您预测的目标变量中 85%的方差。r 越高预测越好。然而,更好的预测并不总是意味着更好的模型。你也可以过度拟合。所以要小心!
****流言终结者:这篇文章着眼于 R 平方,解释了为什么低 R 平方并不总是坏事,高 R 平方也不总是好事。
注意: A 负 R 平方仅仅意味着你的模型比一个简单的平均基线模型更差。 是时候检查你的模型了!
调整后的 R 平方
如果你不断地给你的模型增加新的特性,R 的值将总是增加。这样,虽然你会得到越来越好的分数,但你最终可能会过度拟合你的数据。为了避免这种情况,有时使用调整的 R 平方的。它包括一个依赖于特征(变量/回归量)数量 p 和数据点数量 n 的惩罚项。

计算调整后的 R 平方的公式
关于 R 的更多文章-平方:
结论:
这篇文章的目的是让读者对数据科学中最常用的统计方法有一个基本的了解。本文中讨论的测试/概念并不局限于任何特定的领域,而是在它们的框架中是通用的。
这就把我带到了这篇文章的结尾。要了解我的文章,请关注我这里的。如果你想让我给这篇文章补充些什么,请随意评论相关的消息来源。
采用现有数据科学项目的成功关键
软件开发
代码本来可能不是你的,但现在是你的了。那么接下来呢?

我最近收集了大量笔记本,这些笔记本有助于创建分析。这听起来像是一个令人生畏的项目,但我对代码了解得越多,我就越意识到它并不那么糟糕。笔记本看起来让人不知所措,但是当分解成更小、更易管理的块时,代码相对简单。
采用代码
当我采用这套笔记本时,我做的第一件事就是阅读它。我花了半周时间浏览每一个笔记本,每一行代码都至少读了三遍,并分解了一个笔记本如何过渡到另一个笔记本的流程。我想确保我理解了创建代码所需的输入、代码生成的预期输出以及代码库的整体架构。
由于大多数最初的开发人员都走了,我只能依靠一个人尽可能多地问一些问题。这些问题和答案打破了我的任何误解或困惑,并允许我在头脑中更好地设计代码的未来状态。我开始看到代码的更广阔的图景,以及如何利用它向前发展。
当您采用其他人的项目时,最好记住他们在最初开发代码时可能只有一个用例。了解这个初始用例可以帮助您理解如何将代码转换成更通用的解决方案,从而允许代码重用和扩展。你可能不是软件开发人员,但你可以开始像软件开发人员一样思考。坐下来,考虑一下在代码中可能出现多次的区域。你能从中创建一个函数或类吗?当你设计代码的时候,记录所有的东西。这有时可能看起来很乏味,但是文档可能是让新队友加入并确保他们能够快速学会并使用任何代码的关键。
确定价值
当我开始清理和重新利用我所采用的代码时,很明显这项工作有一些已知的用例,但是代码从笔记本到 Python 库的迁移可能会导致工具不被使用。人们不使用代码是你需要考虑的风险。如果项目需要一周的时间来阅读、清理和迁移到它的新位置,如果项目成为一个死胡同,您的团队能负担得起迁移吗?
在我移植了该工具的代码之后,在几次使用之后,很明显它可能在库中处于休眠状态,没有人使用它。有几次,这个工具被用来推动对其他工作的见解,但很快就失去了它的魅力。几个月后,当我开始从事其他项目时,我正坐在一个 sprint 回顾会上,这时有人带来了他们工作的演示。当他们开始展示他们的分析时,我意识到他们使用了这个工具!在休眠了这么长时间之后,这个工具又变得与一个不期望的用例相关了。努力的程度变得值得了,现在新的用例正在出现;随着人们更多地使用代码,代码也在更新,它提供了价值。
当你采用别人的项目时,理解清理、改进和扩展工作的商业理由是至关重要的。你需要知道团队或客户将如何使用这些代码,以及你所做的工作是否有意义。我们经常会陷入一个很酷的想法,即我们错过了为什么我们在这个项目上工作的商业理由。如果没有客户要求这项工作,没有理由展开或重新运行分析,那么你在做什么?坐下来,确保你看到了一条清晰的代码移植之路。了解如何使用这项工作,并向客户提供价值。当您继续构建数据科学项目并向他人展示您的工作时,培养这方面的技能以了解业务合理性和附加值可能是有益的。
执行迁移
知道您已经通读了代码,并确定了迁移和清理代码的工作量是否值得。假设这个问题的答案是肯定的,你如何开始?
我喜欢的第一个出发点是尽早制定一个策略,告诉我如何将代码移植到它的新家。如果您将代码从一个笔记本移动到另一个笔记本,清理工作可能不同于将代码集成到软件库中。当您迁移您的代码时,考虑您将来如何扩展工作,以及需要为大量工作开放的领域。当您决定创建类或函数时,这可能会有所帮助。
当我在移植代码时,我也喜欢关注测试。您希望确保获得与最初采用代码时相同的输出。如果同时更新代码,则可能得不到相同的结果;因此,功能可能相似,但输出可能不同。我喜欢在多次迁移代码时验证我的代码输出,以确保在添加会改变结果的更改之前它看起来是相同的。它还可以帮助开发单元测试来验证代码是否按预期运行,或者让团队中的其他人测试您的代码。他们的反馈对于理解您在继续迁移时需要进行的任何更改至关重要。
在过去的一年里,我采纳了两个项目,都放在他们自己的一套笔记本里,并把它们移植到他们的图书馆里。当我与其他数据科学家和开发人员一起工作时,很明显可以将这些功能合并到一个软件库中,允许这两个工具共享相似的功能或类。当我移植代码时,这些反馈对于理解我应该如何继续工作很有价值。这些对话和其他对话将帮助您确定您正在进行的工作的后续步骤,这些工作涉及代码的改进或扩展领域。
需要记住的要点
一开始,采用别人的数据科学项目可能看起来很麻烦或有压力,但它可以带来许多好处。当您采用这个项目时,您可以帮助提高您在审查代码和理解功能方面的技能,掌握代码迁移和改进的业务合理性,并在清理您已经获得的工作时继续学习编码实践。
采用代码
- 读,读,读。你想要理解你正在处理的代码。
- 理解最初的用例以及未来的期望。
- 代码重用和可扩展性设计。
- 记录一切。原始评论可能会产生误导;更新并记录所有变更。
确定数值
- 如果采用和清理代码没有价值,为什么还要这样做?
- 理解项目对团队的增值。
- 你的商业理由是什么?
执行迁移
- 尽早开发您的代码迁移策略。
- 确定如何构建代码。
- 测试,测试,测试,甚至更多的测试!您希望确保代码按预期运行。
- 开发您的单元测试来验证代码是否按预期运行。
- 确定接下来的步骤。这项工作已经完成了吗,或者您已经识别出代码中可能需要改进或扩展的地方了吗?
如果你想阅读更多,看看我下面的其他文章吧!
在从事数据科学项目时,请一位主题专家来审查您的工作可能会有所帮助。
towardsdatascience.com](/stop-wasting-your-time-and-consult-a-subject-matter-expert-f6ee9bffd0fe) [## 每位数据科学工程师的前三本书
我放在书架上的伟大资源,我喜欢介绍给软件工程师和数据科学家。
towardsdatascience.com](/top-3-books-for-every-data-science-engineer-e1180ab041f1) [## 在数据科学中我们需要面向对象编程吗?
让我们讨论一下作为一名数据科学家转向面向对象编程的利弊。
towardsdatascience.com](/do-we-need-object-orientated-programming-in-data-science-b4a7c431644f) [## 关于寻找数据科学项目的思考
有时候你需要在工作中把一个项目交给别人,这没什么。
towardsdatascience.com](/thoughts-on-finding-a-data-science-project-d4b74893f50)
用 BERT 提取关键词
入门,NLP
一种提取关键词和关键短语的最小方法

由 Wokandapix 创作
当我们想要从特定文档中理解关键信息时,我们通常转向关键词提取。关键词提取是提取与输入文本最相关的单词和短语的自动化过程。
用耙和雅克等方法!我们已经有了易于使用的软件包,可以用来提取关键字和关键短语。然而,这些模型通常基于文本的统计属性工作,而不是基于语义相似性。
伯特进来了。BERT 是一个双向转换器模型,它允许我们将短语和文档转换为捕捉其含义的向量。
如果我们用 BERT 代替统计模型会怎么样?
尽管有许多优秀的论文和解决方案使用了 BERT 嵌入(例如, 1 、 2 、 3 ),但我找不到一个简单易用的基于 BERT 的解决方案。相反,我决定创建 KeyBERT 一种利用 BERT 嵌入的简单易用的关键字提取技术。
现在,这篇文章的主要话题将不是使用 KeyBERT 而是一个关于如何使用 BERT 创建你自己的关键词提取模型的教程。
1.数据
对于本教程,我们将使用一个关于监督机器学习的文档:
doc = """
Supervised learning is the machine learning task of
learning a function that maps an input to an output based
on example input-output pairs.[1] It infers a function
from labeled training data consisting of a set of
training examples.[2] In supervised learning, each
example is a pair consisting of an input object
(typically a vector) and a desired output value (also
called the supervisory signal). A supervised learning
algorithm analyzes the training data and produces an
inferred function, which can be used for mapping new
examples. An optimal scenario will allow for the algorithm
to correctly determine the class labels for unseen
instances. This requires the learning algorithm to
generalize from the training data to unseen situations
in a 'reasonable' way (see inductive bias).
"""
我相信,使用一个读者相当了解的主题的文档有助于你理解产生的关键短语是否有质量。
2.候选关键词/关键短语
我们首先从文档中创建候选关键字或关键短语的列表。虽然很多都集中在名词短语上,但是我们将通过使用 Scikit-Learns CountVectorizer来保持它的简单性。这允许我们指定关键字的长度,并使它们成为关键短语。这也是一个快速删除停用词的好方法。
我们可以使用n_gram_range来改变候选结果的大小。例如,如果我们将它设置为(3, 3),那么得到的候选词将是包含 3 个关键字的短语。
然后,变量candidates只是一个包含候选关键字/关键短语的字符串列表。
注意:你可以用n_gram_range创造不同长度的关键短语。然后,您可能不想删除停用词,因为它们会将较长的关键短语连接在一起。
3.嵌入
接下来,我们将文档和候选关键字/关键短语都转换成数字数据。我们使用 BERT 来达到这个目的,因为它在相似性和释义任务上都显示出了很好的结果。
生成 BERT 嵌入的方法有很多,比如 Flair , Hugginface Transformers ,现在甚至还有 spaCy 的 3.0 版本!然而,我更喜欢使用sentence-transformers包,因为它允许我快速创建高质量的嵌入,这对于句子和文档级的嵌入非常有效。
我们用pip install sentence-transformers安装包。如果你在安装这个包时遇到问题,那么先安装 Pytorch 可能会有帮助。
现在,我们将运行以下代码,将我们的文档和候选项转换为向量:
我们是 Distilbert ,因为它在相似性任务中表现出了出色的性能,这就是我们对关键词/关键短语提取的目标!
因为 transformer 模型有令牌限制,所以在输入大文档时可能会遇到一些错误。在这种情况下,你可以考虑把你的文档分成几个段落,然后把得到的向量放在一起(取平均值)。
注意:有很多预先训练好的基于 BERT 的模型可以用于关键词提取。不过,我会建议你使用distilbert — base-nli-stsb-mean-tokens 或xlm-r-distilroberta-base-paraphase-v1 ,因为它们分别在语义相似度和释义识别中表现出色。
4.余弦相似性
在最后一步,我们希望找到与文档最相似的候选项。我们假设与文档最相似的候选项是表示文档的好的关键字/关键短语。
为了计算候选项和文档之间的相似度,我们将使用向量之间的余弦相似度,因为它在高维度中表现得相当好:
就这样了!我们将与输入文档最相似的前 5 个候选项作为结果关键字:

图片由作者提供。
结果看起来棒极了!这些术语看起来肯定像是描述了一个关于监督机器学习的文档。
现在,让我们看看如果将n_gram_range改为(3,3)会发生什么:

图片由作者提供。
似乎我们现在得到的是关键词而不是关键词!这些关键短语本身似乎很好地代表了文档。然而,我不高兴的是,所有的关键短语都如此相似。
为了解决这个问题,让我们看看我们的结果的多样化。
5.多样化
返回相似的结果是有原因的…它们最能代表文档!如果我们将关键字/关键短语多样化,那么它们就不太可能很好地代表整个文档。
因此,我们结果的多样化需要在关键词/关键短语的准确性和多样性之间取得微妙的平衡。
我们将使用两种算法来使我们的结果多样化:
- 最大和相似度
- 最大边际关联
最大和相似度
数据对之间的最大总距离定义为数据对之间的距离最大化。在我们的例子中,我们希望最大化候选项与文档的相似性,同时最小化候选项之间的相似性。
为此,我们选择前 20 个关键词/关键短语,并从这 20 个关键词/关键短语中选择彼此最不相似的 5 个:
如果我们将设为低 nr_candidates,那么我们的结果似乎与我们最初的余弦相似度方法非常相似:

图片由作者提供。
然而,相对较高的nr_candidates将创建更多不同的关键短语:

图片由作者提供。
如前所述,您必须牢记准确性和多样性之间的权衡。如果你增加了nr_candidates,那么很有可能你会得到非常多样化的关键词,但是这些关键词并不能很好的代表文档。
我建议你保持nr_candidates少于你文档中独特单词总数的 20%。
最大边际关联
使我们的结果多样化的最后一个方法是最大边际相关性** (MMR)。在文本摘要任务中,MMR 试图最小化冗余并最大化结果的多样性。幸运的是,一个名为embe beed的关键词提取算法已经实现了一个版本的 MMR,允许我们使用它来多样化我们的关键词/关键短语。**
我们首先选择与文档最相似的关键字/关键短语。然后,我们迭代地选择既与文档相似又与已经选择的关键词/关键短语不相似的新候选:
如果我们设置一个相对较低的多样性,那么我们的结果似乎与我们最初的余弦相似性方法非常相似:

图片由作者提供。
然而,相对较高的多样性分数将创建非常多样化的关键短语:

图片由作者提供。
感谢您的阅读!
如果你像我一样,对人工智能、数据科学或心理学充满热情,请随时在 LinkedIn 上添加我,或者在 Twitter 上关注我。
本文中的所有示例和代码都可以在这里找到:
KeyBERT 是一种简单易用的关键字提取技术,它利用 BERT 嵌入来创建关键字和…
github.com](https://github.com/MaartenGr/KeyBERT)**
如何在手臂皮层上实现咳嗽检测-M0
小型微控制器中的关键字定位
超低功耗 MCU 的挑战
深度神经网络(DNNs)具有无与伦比的提取高级信息的能力(比如,“一个病人在过去的一个小时里咳嗽了几次?”)来自原始传感器数据。
但是 dnn 通常在云中实现,因为它们对于嵌入式微控制器来说太耗费资源了。这让嵌入式系统工程师面临一个令人不安的选择:要么(1)将数据从传感器传输到基于云的神经网络,并付出电池寿命短、延迟差和数据隐私威胁的代价,要么(2)放弃深度神经网络的强大推理能力。
目前针对这一问题的“edge AI”解决方案依赖于重型微处理器和 DSP,但这些器件可能会消耗 0.5 W 至 30 W 的功率。对于一个重量轻、不显眼的用于咳嗽计数的可穿戴设备来说,它们是不切实际的,因为它只有 10 毫瓦的备用功率。
在本文中,我们描述了一些将深度神经网络压缩到资源受限平台中的技巧,如超低功耗 ARM Cortex-M0+微控制器。
嵌入式门控循环单元
我们的方法基于嵌入式门控递归单元(eGRU),它利用了一些修改(见图 1 ),我们现在将依次考虑这些修改。

图 1:示出了(a) GRU 和(b) eGRU 的小区架构的框图。与 GRU 相比,eGRU 省略了重置门 r,并且不需要权重 wr。此外,它用 softsign 变体替代 sigmoid 和 tanh 激活功能。
单门机构
eGRU 有一个更新门,但没有复位门。这将模型的占地面积减少了三分之一。现在,如果没有复位门,当出现某些大输入时,eGRU 容易闩锁。这一挑战在反向传播训练期间得到缓解:在每次迭代的正向传递期间,eGRU 状态从均匀随机分布初始化。这迫使 eGRU 在任何新的相关数据出现时丢弃过去的记忆。
软设计激活功能
Cortex-M0+没有专用的浮点单元,这使得软设计成为传统 GRUtanh和 sigmoid 激活功能的理想替代品。校正线性单元(ReLU)是更有效的激活函数,但是将 ReLU 与大量量化的权重相结合会破坏网络的性能。因此, softsign 是一个很好的妥协:它的饱和属性有助于保持网络性能,它的运行速度比 M0+上的 tanh 或 sigmoid 快 10 倍以上。
重量量化
eGRU 使用 3 位指数量化码存储其权重,从而将网络占用空间减少了 10 倍。
Q15 定点运算
为了符合 M0+ 32 位架构,eGRU 使用 Q15 16 位定点格式执行所有运算。由于指数权重量化,权重乘法(最常见的运算)被实现为右移运算。这使得速度提高了 20 倍。
评估 eGRU
已经在不同复杂度的三个声学事件检测(AED)任务上评估了 eGRU:咳嗽检测、口语数字识别和城市声音识别(见图 2)。
与在工作站上实现的传统 GRU 相比,在 ARM Cortex-M0+上实现的 eGRU 在咳嗽检测上表现相当好,在语音数字任务上稍差。eGRU 在城市声音任务上的表现比传统的 GRU 差得多(见图 3)。
目前,eGRU 对于嵌入在低功率微控制器单元上的短声音事件检测或关键词识别任务是有效的。

图 2: (a)在实验中调查的三个音频事件检测(AED)数据集和任务的总结。咳嗽检测是最容易的,因为样本相对较短,并且它是一个 3 类问题。城市音长 10 倍,由 10 个不同的类别组成。(b)说明用于所有任务的神经网络结构。前两层中的重复单位是 RNN、eGRU 或 GRU 细胞。输入是 FFT 向量序列

图 3:显示嵌入 ARM Cortex-M0+处理器的 eGRU 模型性能的结果。(a)在不同的任务中,M0+上的 eGRU 模型与其在计算机上的完全精确的 GRU 模型相比,表现良好。然而,嵌入式 eGRU 模型是高效的,仅占用 GRU 的 10%大小,并且只需要廉价的整数运算。(eGRU 和 GRU 模型在所有任务中的验证精度曲线。eGRU 比 GRU 需要更长的历元来训练。(c)相应的验证损失曲线。eGRU 模型在短期任务中接近类似的损失
对来源感兴趣?查看我们的原创研究 论文 。
对茶感兴趣?这件物品与伯爵茶很相配。
带有 MLOps 的 Kickstarter
使用 PySpark 和 TensorFlow 对 kickstarter 项目的成功进行分类。
介绍
对我来说,在 99 %的情况下,在 Kickstarter 上支持发明者会导致多年等待一个永远不会出现在我家门口的产品。因此,让我们用一个惊人的 kickstarter 成功分类器来彻底解决这个问题。我们将使用 MLOps 平台来获取我们的数据源(您可以在 Kaggle 上找到它),然后使用 SDK 在本地开发我们的预处理和建模脚本,最后将整个包提交到我们的 AWS 帐户,以对其进行版本控制并为生产做好准备。毕竟,这可能是一个真正的赚钱机器。
使用 PySpark 进行预处理
有些人可能会认为对 50 MB 的数据集使用 Spark 可能有点大材小用。但我喜欢一致性和改进。毕竟,它对 MB 和 TB 一样有效。
让我们从定义我们的主要功能开始:
像往常一样,我使用 MLOps 平台生成脚本模板,从 S3 读取数据源。MLOps SDK 为我们不想考虑的所有事情提供了一个很好的包装——比如读、写和版本控制转换,这样我就可以专注于my_transformations中发生的事情。
接下来,让我们定义我将使用的 PySpark 类:
这里没有什么特别的,普通的 Spark 预处理类以及导入的 MLOps SDK 。
我们还需要我最喜欢的 PySpark 辅助函数,它将 PySpark 向量转换成列:
一旦我们完成了这些,我们就可以转到 main 函数了,它获取原始输入数据帧,执行所有转换,然后将其返回给 main 函数进行磁盘写入。我们从稍微清理一下数据帧开始,断言所有值都有正确的类型:
我们还通过减去项目的开始和结束时间来计算活动的总“在线”时间,并过滤掉一些小的子类,如非美元的货币(约 10 %的数据)和非成功或失败的州(约 6 %的数据)。
完成后,我们可以继续将所有分类字符串列转换为整数:
完成后,我们可以继续缩放所有列。这是深度学习的重要一步,因为我们不想让我们的权重失控。我将使用StandardScaler,一旦完成,我还将使用OneHotEncoder将我的项目状态列(成功/失败)转换成一个 hot 编码表示,因为这是 TensorFlow 需要的格式:
需要注意的一件重要事情是OneHotEncoder的dropLast=False论点,你只能通过痛苦的经历来了解这一点。我知道他们有理由默认这个给True,但是我真的认为有人在喝醉的时候决定的。
最后,我们可以将一个热编码向量分解成列,然后返回 main:
当我开发这个脚本时,我通过做pip install mlops-local来使用平台内部可用的 MLOps 本地测试环境,这样我可以快速迭代数据的子集,直到我对我的转换满意为止:

然后,我可以在数据集视图中查看计算出的指标的最终结果:

使用 TensorFlow 训练
和往常一样,训练和预处理的设置是一样的。与预处理一样,我在 main 函数中有一点模板生成的代码,用于处理数据的读取、写入和发送回控制台。
除此之外,我有一个my_network函数,在那里我定义了我的架构。在控制台中,我为脚本提供我的超参数,在这种情况下是batch_size、learning_rate和epochs,然后在mlops.hyperparameters下连同数据矩阵一起用于训练、验证和测试。我将运行 20 个时期,这可能会超出数据量:

正如所料,我们看到一个快速上升到几乎 96 %的准确性,然后停滞不前,损失变得疯狂。严重过度训练。但话说回来,它在测试集上获得了稳定的 96 %的分数,这只是我玩玩而已。
投入生产
既然我们对我们的模型如此满意,是时候利用它赚钱了,把它公之于众(其实不是,它藏在一个 VPC 里,可以从你的云服务中访问)。我将创建一个活动端点,这意味着一个 24/7 全天候运行的托管 API,根据推理机的 CPU 利用率水平扩展实例。
我还将设置 10 %的数据采样百分比,这意味着对于每 10 个请求,MLOps 平台将保存来自推理的输入和输出,并对数据漂移、模式正确性等进行分析。在这一点上,我可以稍后设置一个警报,通知我的 DevOps 团队,如果大便击中风扇:

所以,对你来说这是一个端到端的魔术。希望很快在 Slack 社区与您见面,在这里我们将从数据工程、数据科学和 DevOps 的角度讨论机器学习和操作,以及它们如何融合在一起!
伯特在计算 2019 年城市幸福指数
随着时间的推移,非洲充满了负面含义。我没有立场来捍卫或支持这样的主张,因为在大多数情况下,我认为这样的观点只是支持者的观点。除此之外,我选择从数据的角度来看待非洲大陆的积极因素,更多的是整体公民的幸福感。在此之前,我深入分析了一下,请花点时间通读一下根据 BBC 报道的 2019 年非洲大陆五大正面故事。老师 塔比奇 必须在那里,可能是我太肯尼亚化了。如果我不提我最喜欢的合唱团在 AGT 的表演,恩德洛武青年合唱团以及跳羚队获得世界橄榄球冠军,非洲众神会不高兴的。
为了解开这个幸福理论,我写下了几个“研究问题”,我相信这些问题会引导我找到最终结果
1。有可能获得关于非洲国家的重要数据来确定他们的幸福吗?
2。对于同样的问题,最好的计算方法是什么?
3。这些结果可以通过任何方式验证吗?有验证集吗?
大多数国家都有关于幸福指数的数据,但通常涉及几个指标的组合,我不愿意走这条路,至少目前是这样。但愿这将在未来形成验证集,但愿如此。我训练过许多分析模型,所以使用正确的数据,这种方法并不难。
按人口统计的最大城市的数据
我最终收到了来自非洲不同城市的随机推文,这些推文是基于这些城市的人口数量和个人喜好。因此,预计数据和个人偏好会有一点偏差,但是结果仍然是确定的。这里列出了人口最多的城市。我最终融入了几个东非城市,尽管它们的人口规模很大。阿比让、亚的斯亚贝巴、布琼布拉、开罗、达累斯萨拉姆、约翰内斯堡、坎帕拉、基加利、金沙萨、拉各斯、罗安达、摩加迪沙和内罗毕在分析中受到关注。
推文收藏
地理定位在收集从这些城市传播的推文中至关重要。Twitter 有一个高级搜索功能,因此这个集合可以使用关键字“附近”。看看杰斐逊的 GetOldTweets repo 来深入搜索和收集过去的推文。你以后会感谢我的。收集来自内罗毕的推文就像下面的 Python 命令一样简单。
通过上面的命令,你将能够收集来自/靠近肯尼亚内罗毕的 2019 年传播的多达1000 万条推文。
我感兴趣的是来自城市的一小部分推文,因此最终收集了 16942 条随机和独特的推文。挑战在于推文使用不同的语言,这与我的训练数据和选择的方法的要求相反。
推文预处理和翻译
与传统的英语文本不同,推特是独特的,因为它们被缩短以适应字符限制,并且在大多数情况下表达的语言是非传统的。因此,预处理同样是不同的。我用 Pandas 将 CSV 转换成数据帧,以便于操作。
令人感兴趣的是推文本身的“text”栏。因此,我删除了所有其他的专栏,删除了重复的,停用的词以及空的推文。这在推特上经常发生。下面的代码将处理所有这些过程。
不幸的是,这个过程将再次留下几条短推,如下所示。

解决方法是再次删除空值,如下所示,因为在空字段上训练模型是浪费资源。
上述过程的输出如下。

这是有道理的。不幸的是,我们的模型是在英语文本上训练的,因此需要将这些推文翻译成英语,尤其是来自阿比让和金沙萨等法语城市的推文。我使用了 GoogleTranslate API 键将所有推文翻译成英语。这需要一些时间,但将使用下面的代码完成工作:
与城市字段连接后的输出如下。

伯特在训练我们的模特
来自变形金刚的双向编码器表示(BERT) 是 Google 基于变形金刚开发的自然语言处理(NLP)技术。来自谷歌博客、的消息称,这一突破是谷歌对变形金刚研究的结果:模型将单词与句子中的所有其他单词联系起来处理,而不是一个接一个地按顺序处理。因此,BERT 模型可以通过查看单词前后的单词来考虑单词的完整上下文,这对理解搜索查询背后的意图特别有用。”
由于 BERT 模型已经在数百万个句子和特征上被训练过,它们在许多开箱即用的 NLP 任务上表现得相当好。我使用了 Fast-Bert ,这是 PyTorch BERT 模块的一个优秀的简单包装器,用于在 tweets 的数据集上训练模型,以文本作为特征,以情感类别(0 到 4)作为标签。该模型随后在我们翻译的推文中进行了测试。
先决条件
不幸的是,BERT 模型非常庞大,有数百万个特征,因此运行模型的计算能力对我来说是个大问题。我选择了几个云选项,下面是我对我尝试过的几个选项的想法。
- Kaggle —有 GPU 支持的免费平台,但内存分配对我不利。由于内存相关问题,培训过程被终止。
- 谷歌的 Colab——运行良好,但在经过数小时的训练后,它也分别关闭了,尽管与 Kaggle 的平台相比,它更适合这项任务。没有尝试 TPU 功能,因为 Pytorch 还不被支持。
- 谷歌云平台——我最终选择了这个平台,因为我可以使用他们提供的 300 美元免费积分。我使用了相同的一小部分,所以这是任何有兴趣训练这样一个模型的人的最佳平台。首先,不要为 GCP 买单。因为您将使用虚拟机(VM ),所以只要满足于 CPU 和内存高的虚拟机就可以了。不要用付费的 GPU。我试过这个,结果除了支付 68 美元之外,什么也没训练。只需按照这篇文章在 GCP 上设置你的笔记本。你会节省很多时间。
附加工具:
Python 3
Fast-Bert 如果使用 CPU,请忽略此选项。
Ubuntu
我选择了 DistilBERT ,一个更小、更快、更便宜的模型来训练和设置 CPU 版本,因为我无法使用谷歌积分访问 GPU。下面的代码除了对训练集和验证集进行分段之外,还导入了模型训练所需的所有包。
数据束
建模的第一步是创建数据束。这只是一个对象,它接受训练、验证和测试 CSV 文件,并将它们转换为 BERT 及其变体(如 DistilBERT)的内部表示。它还根据设备配置文件、batch_size 和 max_sequence_length 实例化正确的数据加载器。
学习者
学习步骤以数据分组和相关参数作为输入。下面是 Python 中相同内容的表示,其中学习者封装了模型生命周期的关键逻辑,如训练、验证和推理。
然后模型被训练如下。
考虑到训练时间和资源,我只是将纪元的数量设置为 1。如果您有足够的资源,您可以更改这个数字以获得更好的准确性(不保证)。使用 16 个 vCPUs 和 64GB 内存,培训需要大约 19 个小时。建议保存模型,这样就不会进行重新训练。下面的预测器对象将模型和标签作为输入。
对测试集进行情感分析
使用下面的代码可以选择批量情绪预测。
如下所示的输出将是该推文属于情感类别的标签和概率。每条推文情感输出的概率总和应该等于 1。

因此,具有最高概率的标签是选择的预测标签。根据上面的输出,第一个 tweet 情感预测标签是 0,概率为 25%。为了选择列表中概率最高的标签,下面代码中的第一行起作用了。然后,输出被转换成第二行中的数据帧。
原始测试集和每条 tweet 的预测的串联产生了以下结果:-

酸甜苦辣的时刻
到现在为止,你一定已经对快乐在输出中意味着什么有了一个概念。与其余的相比,情绪标签 4 显示了更大程度的满足。另一方面,标签 0 表示不满,因此被解释为悲伤的感觉。因此,获得情绪得分的平均值,按城市分组,是计算一个城市总体幸福感的一个简单但似乎合理的答案。下面的代码表明。
卢旺达基加利 摘得 13 个最幸福城市的桂冠。令人惊讶的是, 摩加迪沙,索马里 位居第二,尽管我们读到过关于索马里这个国家的负面报道。 肯尼亚内罗毕 我的首都是继 乌干达坎帕拉 之后东非第二不快乐的城市。
结论
当使用数据驱动的解决方案来获得某些国家或城市的人们的幸福时,上述结果在某种程度上令人大开眼界。几点作为我的结论:—
- 城市的选择纯粹是基于人口和个人喜好,特别是东非城市的选择。这是我讲述非洲故事的最好/唯一方式。随着时间和更多的资源,我将能够从非洲大多数国家的首都获得更多的推文,并进行更好的比较。
- 20 万条随机推文的训练集(虽然在类中是平衡的)有点偏低。DistilBERT 模型也具有较少的特征( 66M ),这在很小程度上损害了准确性。我计划用一个多语言的完整模型(110 万功能)和整个 160 万 tweets 训练集实现同样的功能。希望会有一些显著的不同。
- 翻译是一项挑战,尤其是对推文中的缩写词和有语境挑战的词。原始上下文可能会丢失,但翻译者在人类评估者查看的几个样本上工作得相当好。
- 验证我们的结果。这是一个棘手的部分。我们的数据基于社交数据,尤其是推特。推文描述了各个城市的日常聊天,因此最适合衡量传播者的总体幸福感。然而,目前使用的方法考虑了其他几个决定幸福感的因素。例如,联合国世界幸福报告就是其中之一,因此如果模型中包含其他因素,将其作为基础事实将是有效的。这是可以讨论的。
杀死汽车保险商
正如我们所知,人工智能正在如何改变汽车保险

戴维·沃特基斯在 Unsplash 上的照片
在黎明降临这座城市之前,约翰起床去上班。这对他来说是重要的一天,因为他要向董事会做报告。由于他非常紧张,而且这一天似乎相当愉快,他决定开车去上班,而不是让自动驾驶汽车载他。约翰已经通过他的移动设备订阅了智能保险计划。这基本上意味着保险费率根据他的情况而变化。事实上,他决定关闭汽车的自动驾驶仪,这导致他的驾驶保险费略微增加了几美分。但这对他来说很好,因为他需要从演示中转移注意力。
每年,全世界有 125 万人死于车祸,另有 200 万人受伤。这些事故中有 94%是由于人为错误造成的,但随着每辆驾驶经验超过 60 年的自动驾驶汽车的扩散,死亡和受伤的数量下降了。安全性的提高最终导致全球保险费的下降。

由 Samuele Errico Piccarini 在 Unsplash 拍摄的照片
约翰一坐到驾驶座上,他的虚拟助手凯蒂就查看了他的日记,并给汽车的导航仪设置了程序。这条路线不仅考虑到了当时的交通状况加上驾驶时间,这将使他能够及时到达目的地,而且还考虑到了安全因素。由于所有汽车都与中央智能交通系统(ITS)实时连接,人工智能(AI)每天都会收集数百万辆汽车的数据。然后计算基本统计数据,如交通和事故热点、事故可能性等。该系统优化了整个道路网络,以减少交通和事故。
然而,John 决定不走这条路线,而是选择了一条风景更好但系统不推荐的路线。这一选择导致他的每日保险费进一步增加,因为风险稍高。这些增加的费用通过他的银行账户用微支付系统自动支付。

尤金·特里古巴在 Unsplash 上的照片
一路上,一个疯狂的司机开着一辆这样的车(没有撞坏传感器)径直撞上了他。这辆车有一个内部诊断系统,可以自动判断受损程度。约翰的虚拟助手凯蒂对事故进行了统计分析,将其归类为轻微事故,因此没有派出救护车。然而,它与约翰互动,以确保他感觉良好。此外,意识到约翰的演示要迟到了,凯蒂叫了一辆替换车尽快把他送到办公室。
与此同时,智能交通系统派出无人驾驶飞机用视频记录事故。凯蒂已经向在线保险公司提出了索赔,并上传了所有记录在案的证据。在这种情况下,事故相当简单,人工智能法官查明了另一名人类司机的过错。由于汽车仍在运行,因此不需要自动驾驶拖车,汽车会自动驾驶到附近的一家钣金厂进行维修。根据人工智能法官做出的决定,所有发生的费用都自动向另一名人类司机收取。当钣金工完成修理后,汽车自己开回了约翰的家。与此同时,凯蒂让约翰了解维修的最新情况。

当然,这是一个未来的场景,但它可能比我们想象的要近得多。
- 无人驾驶汽车已经在美国的一些州出现并广泛使用。
- 从 SIRI 到 Cortana,虚拟助手几乎可以在任何手机中找到。这些助手已经在导航方面提供了帮助,并考虑到了实时交通、约会等因素。
- 许多国家都有智能交通系统,配备了大量摄像机和其他传感器,能够监测道路网络,并在必要时提供援助。
- 无人机越来越普及,越来越普及。他们在监视偏远地区和运送轻型货物方面已经非常成功。
- 人工智能法官已经做出了一些小的决定。例如,爱沙尼亚目前正在试行一种可以裁决小额索赔纠纷的“机器人法官”。
不同的组件是可用的。仍然缺少的是将它们连接在一起的粘合剂。然而,我们开始生活在上面提到的场景中只是时间问题。当我们做到了,我们的生活将永远改变。我们将会有更少的车祸和死亡。我们将能够专注于最重要的事情,而不会被驾驶压力所困扰。对于无聊的部分,总有我们的虚拟助手不知疲倦地工作,让我们的生活变得轻松。
本文原载于【https://www.businesstoday.com.mt】
Alexei DingliProf 是马耳他大学的 AI 教授。二十多年来,他一直在人工智能领域进行研究和工作,协助不同的公司实施人工智能解决方案。他的工作被国际专家评为世界级,并赢得了几个当地和国际奖项(如欧洲航天局、世界知识产权组织和联合国等)。他已经出版了几本同行评审的出版物,并且是马耳他的成员。由马耳他政府成立的人工智能工作组,旨在使马耳他成为世界上人工智能水平最高的国家之一。
20 年代金融创新的动力知识

埃里克·达尔林普尔在 Unsplash 上拍摄的照片
社会&商业正在加速变革,这在很大程度上要归功于技术!
人们总是很容易说这个十年将与之前的十年有很大不同。直觉上,我们都知道这一点,然而,有时我们没有认识到变化的指数性质。技术可能是社会和商业变革的最大驱动力,作为一个例子,如果你研究美国家庭对技术的采用,你会发现变化的速度惊人。随着新技术以更快的速度传播,S 曲线变得越来越陡峭!从某种程度上来说,未来十年我们将经历比过去整个世纪更多的技术变革。

伟大的未来学家、《未来的冲击》一书的作者阿尔文·托夫勒早在 1970 年就对此做了很好的总结。如果人类的存在已经大约。50,000 年(800 世),相比之前 798 世的总和,我们在过去两世经历了更多的变化。直到 150 世以前,我们一直住在洞穴里,然而,在未来的 80 年里,世界人口的 85%将是城市人口!
20 年代:金融服务领域的技术十年=变革步伐加快=颠覆?
近 700 年来,金融机构一直相当有弹性,并保持了其作为经济支柱的角色。从本质上讲,金融机构并没有发生太大变化,它们提供的是同样的服务:金融咨询、金融投资、存款/贷款/交易、流动性和信用管理以及风险管理,还有价值主张:专业知识、经验、规模、关系管理和市场理解。
当然,这并不是说没有发生变化。随着经济、监管、全球化、信息技术、企业和消费者的发展,银行也发生了重大转变。然而,当我们仔细观察时,这些变化大部分发生在过去的 100 年里,其中大部分发生在过去的 50 年里。拉古拉姆·拉扬在他的论文中也提到了这一点,他的论文是《透过不完全契约的视角看商业银行的过去和未来。他写道,这种变化(至少在企业银行业)有三个关键因素——技术、信息处理和产权环境。
这也是有意义的。如果将银行视为处理信息以提供金融解决方案的大型数据存储,那么随着多种技术(区块链、人工智能、加密、云等)的入侵,银行似乎已经成熟。
2018 年,埃森哲研究了 10,000 家公司的 62 个参数,以确定各行业的中断状态。尽管金融服务业迄今仍有弹性,但它似乎最容易在未来受到冲击。

来源:埃森哲
金融服务的中断有时被认为是一种激进的观点,尽管人们普遍承认,银行业已经出现了加速变革和更新的破坏性力量。过去十年,金融机构在某些领域已经在解决这一问题上取得了进展。例如,在财富管理领域(如下图),由于市场力量,数字化采用和服务创新变得咄咄逼人。同样,由于 MIFID 导致新的创新模型,我们正在见证买方和卖方的重大长期变化。

来源:ThomasBrand
也就是说,对金融机构进化的总体关注,以及由此带来的绩效和效率方面的结果,充其量只是适度的,并回避了一个问题——从更广泛的意义上讲,在颠覆性力量和技术进步的推动下,金融机构如何为加速变革的时代做好准备?
引领金融行业的加速变革——动态知识可能是关键!
Thomas Ricketts 在他的文章中,在创新前沿发现机遇 描述了知识如何在数字时代的行业创新中发挥关键作用,这些行业更加关注知识资本/无形资产/知识资本(下图)。据估计,现在标准普尔 500 指数 80%的企业价值是无形资产。

资料来源:托马斯·里基茨
对于金融服务来说,知识的作用变得更加突出,因为它具有最高的无形强度(无形资产占总资产的百分比)以及跨行业产品和流程中最高的信息强度。

资料来源:没有资本的资本主义:理解我们新的“知识”经济;迈克尔·波特的 HBR 文章
此外,还有几个影响金融服务的破坏性驱动因素,使得确定优先级和重点变得异常困难。

来源:世界经济论坛
因此,金融服务领域的知识是创新和效率的强大驱动力。在数据、信息和人工智能的数字时代,不仅仅是一个拥有智能人工智能的被动系统。
为了更全面更全面地利用知识的力量,我们需要一个新的框架,叫做运动知识。动能知识(很像动能——质量&速度)着眼于知识的两个维度(1)资本(2)速度:
(1)知识型资本(KBC)一般指无形形式的资本,包括一系列资产。经合组织为知识资本创建了一个框架,使这种资本的衡量更加科学:

资料来源:基于知识的资本、创新和资源分配经合组织
(2)第二个维度,即知识的速度或应用,虽然研究得不太科学,但却是创新前沿过程中缺失的一个关键方面。由于缺乏适用性,知识资本并没有产生预期的产出,适用性主要体现在四个方面:

我在之前的文章中也有详细介绍:工业 4.0:向知识型企业演进
理解和应用 动态知识框架 极大地增加了产品、流程和主张(3P)演变的机会,从而带来结构和客户创新。

资料来源:Amit Shanker
在过去的十年中,以技术、“决策工厂”和“创新实验室”的形式对知识资本进行了更大的投资,以开发尖端创新。然而,随着技术变得更加普及,所产生的知识的传播仍然薄弱,这些投资的效果可能会相对较快地消失。这就要求银行从根本上更加关注他们的运营模式和技术之间的平衡,以在整个 3P 生态系统中部署动态知识。金融机构需要创造新的“知识”角色,专注于知识的学习和传播方法,如应用不同学习理论开发智力资本的认知主义者和连接主义者。
举例说明 KMeans 超参数

图片来源:失眠症患者/索尼
如今,任何高中学历的人都可以实现机器学习算法,这是一件好事。大多数人都能接触到的东西总是一件好事。有很多公共库可以用来简化算法部分。但是权力越大,责任越大。从头开始编写库所节省的时间应该用来微调您的模型,这样您就可以获得不错的结果。
今天我们来看看 Scikit KMeans 模型的调校。KMeans 是一种广泛使用的数据聚类算法:如果您希望根据客户的购买行为将大量客户聚类到相似的组中,您可以使用 KMeans。如果希望根据人口统计和兴趣对所有加拿大人进行聚类,可以使用 KMeans。如果你想根据植物或葡萄酒的特征对它们进行分类,你可以使用 KMeans。所有这些问题都需要无监督聚类,也就是说,我们事先不知道聚类看起来是什么样子。还有其他无监督聚类的方法,如 DBScan、层次聚类等,它们各有优点,但在这篇文章中,我将讨论 KMeans,因为它是一种计算量很小的聚类方法,你可以经常在笔记本电脑上运行,特别是使用迷你批处理 KMeans 。
完整代码的链接在最后。
示例的样本数据
我们生成 3 个具有 2 个特征的聚类(0,1,2)(xx和 yy )。聚类由以下 3 对 x,y 值生成:
mu1 = 3.0
sigma1 = 0.5
mu2 = 20.0
sigma2 = 5.5
mu3a = 1.0
sigma3a = 0.8
mu3b = 5.0
sigma3b = 0.4
numpoints = 1000
np.random.seed(1234)
x1 = np.random.normal(mu1, sigma1, numpoints)
y1 = np.random.normal(mu1, sigma1, numpoints)
x2 = np.random.normal(mu2, sigma2, numpoints)
y2 = np.random.normal(mu2, sigma2, numpoints)
x3 = np.random.normal(mu3a, sigma3a, numpoints)
y3 = np.random.normal(mu3b, sigma3b, numpoints)

我们有三组蓝色、栗色和红色的数据。左图显示了所有数据。右图显示了一个放大的版本,因此我们可以清楚地看到有两个集群。
超参数
超参数来自 Scikit 的 KMeans :
*class* sklearn.cluster.**KMeans**(*n_clusters=8*, *init='k-means++'*, *n_init=10*, *max_iter=300*, *tol=0.0001*, *precompute_distances='auto'*, *verbose=0*, *random_state=None*, *copy_x=True*, *n_jobs=None*, *algorithm='auto'*)
随机状态
这是设置一个随机种子。如果我们想要一次又一次地复制精确的集群,这是很有用的。我们可以把它设置成任何我们想要的数字。下面我设置为 random_state=1234 。
n _ 簇
我们需要为算法提供我们想要的聚类数。标准文献建议我们使用肘方法来确定我们需要多少个集群,并且它对于 Scikits 的干净的理论数据集很有效。实际上,这只是一个初步的猜测。在这个例子中,我们知道我们有 3 个集群。所以让我们用 n_clusters=3 试试:
km = KMeans(n_clusters=3, random_state=1234).fit(dftmp.loc[:, dftmp.columns != ‘group’])

这是怎么回事?我们预测了 3 个簇,但是它们不在我们最初的 3 个簇附近。
我们确实得到了 3 个集群,但是它们与我们最初的集群非常不同。最初,我们在左下角有两个集群,但它们都被归入一个集群,黄色的圆圈。这是因为 KMeans 随机指定初始聚类质心,然后根据点到质心的距离尝试对尽可能多的点进行分组。当然,它重复这个过程直到收敛,但是没有什么能阻止它陷入局部最小值。事实上,众所周知,KMeans 依赖于质心初始化。这是我们的第一个线索,我们不能盲目地使用知识手段。如果我们要求 3 个聚类,那么我们需要有一些概念,我们期望聚类中心在所有特征中的位置。
初始化
这是您可以设置初始簇质心的地方。在我们的例子中,我们有 3 个集群,所以我们需要 3 个质心阵列。因为我们有两个特征,每个数组的长度都是 2。所以在我们的例子中,我们必须有 3 对聚类中心。因为这是一个模拟,所以我们知道准确的聚类中心,所以让我们试试。
centroids = np.asarray([[mu1,mu1],[mu2,mu2], [mu3a,mu3b]])
km = KMeans(n_clusters=3, init=centroids, random_state=1234).fit(dftmp.loc[:, dftmp.columns != 'group'])

最后,我们有了最初的 3 个集群!(通过将我们的聚类中心初始化为原始值)
啊!我们走吧。对于大多数数据点,我们都有原始的 3 个聚类!
但是等等!那是作弊!我们永远不会知道我们星团的精确质心。没错。我们只能推测我们的聚类中心大概是什么。所以你不必知道精确的中心,但是近似值会有帮助。
如果我们只有近似的聚类中心,我们还能做什么来改进我们的聚类?接下来,我们将看看另一种方法,我们可以得到我们的原始集群。
更改群集的数量
我知道!你想,但是,但是,但是,我们最初有 3 个集群,我们将集群的数量设置为 3。我们还能做什么?不如我们把集群的数量设为预期的两倍。什么?我知道,请原谅我。
km = KMeans(n_clusters=numclusters, random_state=1234).fit(dftmp.loc[:, dftmp.columns != 'group'])

啊!左下方有两个分开的集群,如底部一行图所示。我们不需要给出初始的聚类中心。
请看右下方显示的原始群集 0 和 2,它们或多或少被很好地分开了。所以这是一件好事。但是原来的集群 1(右上)现在被分成 4 个集群。但是我们知道这只是我们模拟的一个集群。因此,接下来我们只需将这些集群整合在一起。类似集群(紫色、棕色、深绿色和浅绿色)的东西将成为单个集群。
因此,如果我们不知道我们的聚类中心在哪里,这可能是许多特征的情况,那么我们可以使用这个技巧-高估我们的聚类数量。有人可能会说这是过度拟合——这对于右上的簇来说是正确的,但这是在没有好的质心的情况下,我们可以让左下的簇分离的唯一方法。即使我们有近似的质心,这种方法也能更好地增强聚类分离。
标准化数据
你说:“但是等等!我知道你必须对你的数据进行标准化。事实上这是真的。无论何时进行任何涉及欧几里得空间的操作,您都必须对数据进行归一化,以便所有的特征都在相同的范围内,KMeans 就是这样做的。在这种情况下,我能够逃脱,因为我的原始数据的 x 和 y 范围看起来差不多:0–30(参见上面样本数据部分的第一个图表)。但是让我们将数据标准化,看看是否有所不同。
scl = StandardScaler()
dftmparray = (dftmp.loc[:, dftmp.columns != 'group']).values
dfnorm = scl.fit_transform(dftmparray)
dfnorm = pd.DataFrame(dfnorm)
km = KMeans(n_clusters=3, random_state=1234).fit(dfnorm)

我们不能预测底部坐标较低的独立星团。右上角显示了原始空间中两个聚类的分离,但右下角显示这两个聚类在预测中没有很好地分离。
我们看到,即使我们对数据进行了归一化,我们仍然没有成功地分离原始聚类 0 和 2(在原始数据的左下方)。
其他人
还有其他超参数,如 tol、max_iter,有助于缩短计算时间。这些参数在一个更复杂的问题中变得比这个例子中显示的更重要,所以我不会试图通过例子来展示它们。
但是让我们看看它们的含义:
n_init =默认为 10,因此算法将初始化质心 10 次,并将选择最收敛的值作为最佳拟合。增加该值以扫描整个特征空间。注意,如果我们提供了质心,那么算法将只运行一次;事实上,它会在运行时警告我们这一点。如果我们设置了初始质心,或者如果我们设置的聚类数比我们预期的要多(为了以后合并一些聚类,如上所述),那么我们可以保留默认值。
tol =如果我们将它设置为一个更高的值,那么它意味着在我们宣布收敛之前,我们愿意容忍惯性的更大变化,或损失的变化(有点像我们收敛的速度)。因此,如果惯性的变化小于 tol 指定的值,那么算法将停止迭代,并宣布收敛,即使它已经完成了少于 max_iter 轮次。将其保持在较低的值,以扫描整个特征空间。
max_iter =通常有 n_init 次运行,并且每次运行迭代 max_iter 次,即,在一次运行中,点将被分配给不同的簇,并且针对 max_iter 次计算损失。如果将 max_iter 保持在一个较高的值,那么可以保证您已经探索了整个特征空间,但这通常是以收益递减为代价的。
其他变量决定计算效率,因此如果您有一个非常大的数据集,最好保持默认值。
结论
仅仅运行一个肘方法、确定集群的数量以及仅仅运行标准的 KMeans 通常是不够的。一般来说,我们必须研究数据,并获得主题专家对必须有多少个群集以及它们的近似质心应该是多少的意见。一旦我们有了这些,我们就可以将它们放在一起调整 KMeans:
- 通过提供初始聚类中心
- 通过要求更多的集群,以便我们可以在事后整合一些集群。
- 我们还可以通过增加一些特征的权重来增加它们的贡献,试图用 Mahlanobis 距离来代替欧几里德距离。例如,在上面的例子中,如果我们认为 xx 在分离中比 yy、重要 10 倍,那么我们将在归一化步骤后将 xx 乘以 10。虽然这并不总是可取的——还有其他方法来处理这个问题,例如 PCA。
重现上述情节的完整 python 代码可以在这里找到。Jupyter 笔记本的 pdf 版本可以在这里找到。
KNN 算法:何时?为什么?怎么会?
KNN: K 近邻算法是机器学习的基本算法之一。机器学习模型使用一组输入值来预测输出值。KNN 是最简单形式的机器学习算法之一,主要用于分类。它根据相邻数据点的分类方式对数据点进行分类。

图片由 Aditya 提供
KNN 根据先前存储的数据点的相似性度量对新数据点进行分类。例如,如果我们有一个西红柿和香蕉的数据集。KNN 将存储类似的措施,如形状和颜色。当一个新的物体出现时,它会检查颜色(红色或黄色)和形状的相似性。
KNN 的 k 代表我们用来分类新数据点的最近邻的数量。

图片由 Aditya 提供
我该如何选择 K?
在我们有很多点的实际问题中,问题是如何选择 K 的值?
选择正确的 K 值称为参数调整,这是获得更好结果的必要条件。通过选择 K 的值,我们对数据集中可用的数据点的总数求平方根。
a.K = sqrt(数据点总数)。
b.总是选择 K 的奇数值,以避免两个类之间的混淆。
KNN 是什么时候?
a.我们有正确标记的数据。例如,如果我们预测某人是否患有糖尿病,最终标签可以是 1 或 0。它不能是 NaN 或-1。
b.数据无噪声。对于糖尿病数据集,我们不能将葡萄糖水平设为 0 或 10000。这几乎是不可能的。
c.小数据集。
KNN 是如何工作的?
我们通常用欧氏距离来计算最近邻。如果我们有两点(x,y)和(a,b)。欧几里德距离(d)的公式为
d = sqrt((x-a) +(y-b))

图片由 Aditya 提供
我们试图获得最小的欧几里德距离,并基于较小距离的数量来执行我们的计算。
让我们在一个数据库上尝试 KNN,看看它是如何工作的。数据可以从https://github . com/adityakumar 529/Coursera _ Capstone/blob/master/diabetes . CSV中提取。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
pd 和 np 是熊猫和 NumPy 图书馆的。最后 3 行(混淆矩阵、准确度分数和 f1 分数)用于检查模型的准确度。train_test_split 就是对数据进行拆分和训练。KNeighborsClassifier 代表 K 个最近邻。数据集的标准化是许多机器学习评估器的共同要求:如果单个特征看起来不像标准的正态分布数据,它们可能表现得很差。
data = pd.read_csv("../input/diabetes.csv")
data.head()


我们已经通过 pd.read_csv 读取了 CSV 文件。通过头部()我们可以看到前 5 行。有些因素的值不能为零。例如,对于人类来说,葡萄糖值不能为 0。同样,人类的血压、皮肤厚度、胰岛素和身体质量指数也不能为零。
non_zero = ['Glucose','BloodPressure','SkinThickness','Insulin','BMI']
for coloumn **in** non_zero:
data[coloumn] = data[coloumn].replace(0,np.NaN)
mean = int(data[coloumn].mean(skipna = True))
data[coloumn] = data[coloumn].replace(np.NaN, mean)
print(data[coloumn])0 148.0
1 85.0
2 183.0
3 89.0
4 137.0
...
763 101.0
764 122.0
765 121.0
766 126.0
767 93.0
Name: Glucose, Length: 768, dtype: float64
0 72.0
1 66.0
2 64.0
3 66.0
4 40.0
...
763 76.0
764 70.0
765 72.0
766 60.0
767 70.0
Name: BloodPressure, Length: 768, dtype: float64
0 35.0
1 29.0
2 29.0
3 23.0
4 35.0
...
763 48.0
764 27.0
765 23.0
766 29.0
767 31.0
Name: SkinThickness, Length: 768, dtype: float64
0 155.0
1 155.0
2 155.0
3 94.0
4 168.0
...
763 180.0
764 155.0
765 112.0
766 155.0
767 155.0
Name: Insulin, Length: 768, dtype: float64
0 33.6
1 26.6
2 23.3
3 28.1
4 43.1
...
763 32.9
764 36.8
765 26.2
766 30.1
767 30.4
Name: BMI, Length: 768, dtype: float64
我们创建了非零值,该值包含预测结果值所需的所有列。我们需要确保这些列没有任何与零或 NaN 值相关的值。如果我们有 0,我们将替换为 NaN。然后用列的平均值替换 NaN。让我们绘制糖尿病数据的细节图。
import seaborn as sns
p=sns.pairplot(data, hue = 'Outcome')

我们用值不能为零的列定义了非零值。在每一列中,我们将首先检查是否有 0 个值。然后我们用 NaN 替换它。稍后,我们将创建该列的含义,并用 mean 替换前面的含义。
既然我们已经准备好了数据。是时候训练和测试数据了。
X =data.iloc[:,0:8]
y =data.iloc[:,8]
X_train,X_test,y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=0, stratify=y)
对于数据 X,我们取范围从 0 到 7 的所有行和列。同样,对于 y,我们取第 8 列的所有行。
我们有在程序开始时导入的 train_test_split,我们将测试大小定义为 0.2,这意味着在所有数据中,20%将被保留下来,以便在稍后阶段测试数据。
*#feature Scaling*
sc_X = StandardScaler()
X_train = sc_X.fit_transform(X_train)
X_test = sc_X.transform(X_test)
标准缩放器执行标准化任务。通常,数据集包含不同规模的变量。例如,数据集将包含一个值范围为 20–70 的胰岛素列和一个值范围为 80–200 的葡萄糖列。由于这两个列的规模不同,因此在构建机器学习模型时,它们被标准化为具有共同的规模。
import math
math.sqrt(len(y_test))
外出:
12.409673645990857
我们用这个值得到 K 的值。我们需要 K 的一个奇数值,所以我们将它设为 12–1 或 12+1。
classifier = KNeighborsClassifier(n_neighbors=13,p=2,metric='euclidean')classifier.fit(X_train,y_train)
外出:
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='euclidean',
metric_params=None, n_jobs=None, n_neighbors=13, p=2,
weights='uniform')
让我们用分类器预测来预测我们的数据。
y_pred = classifier.predict(X_test)
y_pred
外出:
array([0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1,
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0])
我们有一系列数据,但我们需要评估我们的模型来检查准确性。让我们从一个混淆矩阵开始。
cm= confusion_matrix(y_test,y_pred)
cm
外出:
array([[86, 14],
[24, 30]])
我们有一个混淆矩阵,其中 86 和 30 的对角线表示正确的值,14,24 表示我们错过的预测。
我们会检查 f1 的成绩。
print(f1_score(y_test,y_pred))
在外
0.6122448979591836print(accuracy_score(y_test,y_pred))
外出:
0.7532467532467533
我们的 f1 评分为 0.61,准确率为 0.75
让我们绘制实际数据和预测值的图表。
import matplotlib.pyplot as plt
plt.figure(figsize=(5, 7)) ax = sns.distplot(data['Outcome'], hist=False, color="r", label="Actual Value")
sns.distplot(y_pred, hist=False, color="b", label="Predicted Values", ax=ax) plt.title('Actual vs Precited value for outcome')
plt.show()
plt.close()

可在以下位置查看实际代码:
使用 Kaggle 笔记本探索并运行机器学习代码|使用来自[私人数据源]的数据
www.kaggle.com](https://www.kaggle.com/adityakumar529/knn-algorithm)
https://git hub . com/aditykumar 529/Coursera _ Capstone/blob/master/KNN . ipynb。
变压器并没有你想象的那么难理解
破解注意事项—为了解最新的 SOTA 自然语言处理模型打下基础。

Ttransformer 的架构已经成为许多最新 SOTA NLP 模型开发的基石。它主要依靠一种叫做注意力的机制。与之前的其他成功模型不同,它不涉及卷积或递归层。
如果你是这个模型的新手,你可能不会发现这个架构是最容易理解的。如果是这样的话,希望这篇文章能有所帮助。
我们将从常规编码器-解码器网络如何工作以及它可能会遇到哪些困难开始解释,常规编码器-解码器架构中使用的注意 机制是什么,最后,它如何用于变压器。
用于神经机器翻译的编码器-解码器网络

编码器-解码器架构。图片来源。
左边的图像显示了一个编码器-解码器架构,两个组件都由递归层组成。
在左边,编码器接收输入句子,每个单词由它们的嵌入表示,并期望为输入句子输出良好的摘要。这个概要被称为上下文 向量(连接二者的箭头),并作为其初始 状态被馈送给解码器。
右边的解码器负责输出翻译,每步一个单词。在训练期间,它将目标 句子作为输入。在进行预测时,它用来自最后一个 步骤的输出进行自我反馈(如此处所示)。
这种架构优于更简单的序列到序列 RNN,因为来自编码器的上下文 向量整体上提供了对输入语句的更多直接 访问。因此,解码器在输出单个翻译之前可以通过上下文向量查看整个句子,而常规的序列到序列 RNN 只能访问位于当前时间步长之前的单词。
在所有递归层中,信息通过隐藏 状态从一个时间步传递到另一个时间步,随着更多时间步的执行,它们逐渐被遗忘。当编码一个长的序列时,输出上下文向量很可能已经忘记了关于句子的第一个成分的许多信息。这同样适用于解码器,如果序列太长,包含在上下文向量中的信息不会 传递 向下到最后几个时间步。
注意事项
为了解决这个内存 问题并提高模型性能,引入了注意 机制、双向递归层,以及对模型结构的一些修改。
编码器现在由双向 LSTM/GRU 组成,因此输入句子在两个 方向被读取。除了上下文 向量之外,编码器现在还输出由来自每个编码步骤的每个输入字的编码组成的序列。在每个时间步,编码序列在被完全传递给解码器。由于解码器每次输出一个字,所以注意 机制用于选择要处理的编码序列的正确部分,以及编码器自己的输入。****
下图说明,尽管使用了相同的编码器输出,但不同的时间步长对编码器序列的不同部分给予不同程度的关注。

编码器输出的加权和。为了翻译每个单词,这个序列的不同部分被赋予不同的重要性。图片来源。
这种选择是通过用一组注意 权重对编码器 序列执行加权 求和来完成的,所述权重由求和为 1 的浮点组成。对于给定的时间步长,编码序列中只有少数部分值得关注,并且每一步使用不同的权重集。
Say that we have only one input sentence X = [x1, x2, ..., xn] in our batch, it has *N* words and each is represented by its embedding vector of length *M*. The input sentence is then a sequence with a shape of *N* x *M*.The encoder is used to output a good summary of the input sentence by transforming X into its encodings Z = [z1, z2, ..., zn], with zi being the encoding of the word in the i-th position.The dimension of each encoding vector z is determined by the number of neurons from the encoder's the last layer.A set of attention weights ⍺ = [⍺1, ⍺2, ..., ⍺n], at a given time step *t*, is a *N*-dimensional vector. Each element multiples one word encoding from Z, outputting a weighted sum, ∑⍺i x zi.
这些注意力权重是可学习的参数,通过测量编码器序列S****与解码器的最后* 隐藏 状态 h 中每个元素的兼容性来确定。来自编码器序列的向量与该隐藏状态越相似,其对应的注意力权重就越大。*

乘法/点积注意力。
h 和 S 之间的点* 积测量 S 中的每个向量与 h 的相似度,通过应用 softmax 我们将结果转化为分布。整个过程可以看做是模型在使用隐藏 状态 h 作为查询来寻找中最相似的元素。T* 要检索它们,用获得的注意力权重乘以 S 。
**But why attentions are determined using the previous hidden state, and why is this similarity important?Say that we are using this model to translate a sentence from one language to another and we’ve just finished translating one word and we’re working on the next output.The hidden state of the decoder from the previous step contains information regarding the last output. Since the model is trained to predict the next word, this hidden state can be seen as something related to what the model wants to predict as the next word. It’s then logical to search for information similar to the hidden state from the encoder sequence to produce the next translation.**
自我关注
到目前为止,解码器使用注意力来映射其隐藏状态,编码器输出用来找到需要注意的相关部分。在一个转换器中,这个机制也被它的编码器用来从一个句子中找到与句子本身相关的信息。换句话说,对于一个句子中的一个给定单词,在产生它的编码时要考虑更多的上下文。这叫自我关注。

对单词“it”的编码器自我注意分布从第 5 层到第 6 层的转换器被训练用于英语到法语的翻译。图片来源。
这张图片以一种形象的方式展示了自我关注。每个单词与单词【it】的相关性由连接它们的线的强度来表示。
在这种情况下,并不是所有的单词都与单词'' it'具有相同的相关性,句子中的不同单词对该单词具有不同程度的重要性,包括非常 'it' 。****
这就是自我关注所做的,每个单词的编码包含了它的关系和其他关于一个句子中所有单词的信息。这可以为编码器提供更好地理解单词的潜在句法和语义含义的能力。
用于执行自我关注的等式与上面所示的等式相同,只是现在不是使用隐藏** 状态h,而是使用句子** 本身作为查询,并且 softmax 内的值被缩放以避免 softmax 具有可忽略的 梯度。****

成比例的点积注意力。图片来自原纸。
在引擎盖下,注意力只是模型执行查找的工具,将带有一组键值对的查询映射到输出。仅当相应的关键字与查询匹配时,才检索来自值的组件。
早期情况下, Q 为隐藏** 状态hK和 V 均为编码器输出 S* 。 S 和 h 用于查找注意 权重⍺ ,然后通过执行 ⍺ ⋅ S 从 S 中检索匹配组件。***
由于循环层的顺序性质,我们无法将所有隐藏状态打包在一个矩阵中,并一次性找到所有注意力权重。在每个时间步骤找到注意力权重。****
为了执行自我关注,所有的值 Q 、 K 和 V 都是来自输入** 句子的同一个单词列表,因此对单词和本身进行比较。与之前的情况不同,现在所有单词的所有注意力权重都可以在一个镜头中处理,因为它不受循环层的顺序性质的限制。**
现在,让我们来看看变压器架构,还有更多值得挖掘的地方。
变压器和多头注意
该模型再次由一个编码器-解码器结构组成,每个编码器-解码器又由 N(=6)个编码器/解码器模块相互堆叠组成。

全变压器架构。图片来自原创论文
每个编码器/解码器块将其输出传递给下一个编码块,并且来自最后一个编码块的输出被传递给 N 个解码块中的每个编码块。****
每个编解码块中有不同的子层:与层归一化层跳过连接,一个由两个** 密集 层组成的“前馈模块,最后一个是多头关注模块。在每个解码器块的底部增加了一个屏蔽的多头注意力,行为略有不同。这里的主要目标是理解多头注意力是如何运作的,以及注意力是如何在其中执行的。**
如你所见,在这个模型中没有卷积或递归层,整个架构完全依赖于注意机制。
多头警示模块

多头注意力模式示意图
本质上,一个多头注意力模块只是一些规模的点积注意力并行工作。对于每个注意力,输入 Q 、 K 和 V 首先被投影到不同的子空间,使用不同的权重矩阵 、Wk 和 Wv 。通过这种方式,每个注意力开始处理输入的不同方面。它们的输出然后被线性组合。
它在编码器中的行为非常简单,它执行自我关注,其中 Q 、 K 、 V 都是输入**语句中的单词的相同 l ist。每个编码器模块将其输出传递给下一个,最后一个输出馈给所有解码器模块。**

多头关注。
对于解码器来说,屏蔽多头注意力将自我注意力应用于目标** 句子(在训练期间),其中未来单词被屏蔽 排除,防止任何单词将其自身与位于其后的单词进行比较。在推断时间,解码器只能访问其最后的输出,因此不需要屏蔽。该模块的输出作为 Q 传递给上方的多头注意力,多头注意力从编码器接收编码,并将其作为 K 和 V 。它的输出与来自掩蔽注意模块的输出**重新组合,并被传递以供进一步处理。****
最后,解码器输出被传递到一个密集层,最后的 softmax 输出当前步骤的翻译。
最后的话

这是一个关于变形金刚的绝妙类比!
本文到此为止。如果你喜欢它的内容,可以看看我的其他作品。如果有任何错误,最好能在评论中看到。
PS:阿尔弗雷多有一门关于深度学习的免费课程。有兴趣就去看看,告诉我有多差!
讨论自然语言处理中三种最常用的输入类型。
towardsdatascience.com](/an-overview-for-text-representations-in-nlp-311253730af1) [## 从零开始的集成学习
引入集成学习,这是一种通过组合训练好的模型来提高性能的强大工具。
towardsdatascience.com](/ensemble-learning-from-scratch-20672123e6ca)**
有效学习机器学习算法的诀窍
机器学习
我希望我在开始自学时就知道这一点。

多兰·埃里克森在 Unsplash 上的照片
B ackdrop:
几天前,我的一个朋友过来嘲笑我,说“你怎么花了这么长时间才学会机器学习?只是几个型号,我一个星期就学会了”。这是他的原话。我只是对他笑笑,询问他学到了什么。他说出了几个机器学习算法的名字。我问他到底学到了什么,然后得到的明显回答是使用 Sklearn 的 fit 和 predict 方法,以及该算法如何工作的简要概述。
我脸上带着邪恶的笑容,问他为了得到最好的参数,他会怎么做?模型如何学习最佳权重?当我们有低延迟要求时,我们该怎么做?虽然这些都不是什么复杂的问题,他坐在那里默默地看着我的脸,我笑到了最后。
这个故事的要点是,机器学习不仅仅是简单的拟合和预测方法。
我们大多数人只是在 youtube 上看了几个视频,然后声称我们知道机器学习,结果很快就意识到我们的错误。对所有自学的人,只要记住有成千上万像你我一样的人在学习机器学习/数据科学。请记住,我们将与拥有数据科学相关领域硕士/博士学位的人竞争。因此,要想与他们竞争,我们需要在基本面上非常强大。
随着围绕机器学习的大量讨论,每天都有新的课程冒出来,目前有比实际工作更多的课程。面对如此巨大的资源,选择正确的道路是一个难题。
说实话,这些课程大多很平庸,没有深入覆盖。嗯,有一些好的课程,但他们都提供不同的课程。很少有人深入研究数学部分,很少有人擅长编码部分等等。所以今天我不会特别提到任何课程。我将分享我在故事中遵循并建议给同一个朋友的方法。我相信它也会对您的数据科学之旅有所帮助。
简介:
在我们进入算法部分之前,让我告诉你我们在机器学习项目中的确切位置。完成机器学习项目涉及许多阶段,每个阶段都同等重要。

机器学习项目的关键阶段
建模是我们的机器学习算法进入的阶段,它只是 ML 生命周期中的重要阶段之一。
好了,让我们进入机器学习算法的主题。
对于每一个算法,我们需要注意一些重要的事情。

学习 ML 算法的流水线
1.算法背后的直觉是什么
最初,我习惯于学习一个算法,过一段时间后就会忘记,每当我回去修改它时,我会发现很难理解我当时已经学过的内容。随着时间的推移,我意识到我们人类无法真正记住太理论化的东西,如果通过可视化来学习,我们更有可能记住很长时间。这就是几何学帮助我们以最简单的方式形象化算法核心的地方。如果我们有一些关于这些算法的很酷的现实生活中的例子,我们会更倾向于理解它。
一旦你从你选择的任何课程中完成了一个算法的学习,打开一个新的标签,开始寻找那个算法的直觉。相信我,网上有很多很酷的解释。首先,Quora 和 Medium 是最好的起点。
2.算法是如何工作的?
一旦你对它有了直觉,试着观察算法实际上是如何工作的。你需要检查的另一件事是算法如何处理各种形式的数据,比如文本/分类/数字。
在这个阶段,用多个因素进行实验,看看算法是如何工作的,你可以参考 Scikit-Learn 中现成的算法。检查算法的参数,并尝试使用它们,看看它们如何影响模型的性能。
3.哪里可以用/哪里不能用
这是大多数人经常忽略的最重要的因素,而他们更关注它是什么和如何工作的。为什么行得通,或者为什么行不通,这对于深入理解算法非常重要。
尝试体验并理解它是如何处理大型数据集和高维数据的。如果它倾向于离群值或不平衡的数据集。
在面试中,最棘手的问题不是什么和怎样,而是为什么。假设明天你在学习算法后做了一个个人项目,你用了一个特定的 X 算法来解决它,面试官很可能会回答为什么是 X 算法为什么不是 Y 算法?让我们假设你想出了准确性作为理由,然后是最困难的问题为什么你认为它比其他的更好。
哦,好家伙!这就是为什么你应该知道它在哪里工作,在哪里不工作。
例如,你需要给出这样的回答,因为我们的数据是高维的,本质上是非线性的,由于种种原因,算法 X 在处理非线性数据时往往比 Y 做得更好。
4.为什么算法的可解释性很重要
这是关键步骤之一,之所以重要,是因为作为一名数据科学家,你可能需要向完全没有技术知识的客户展示模型。在此期间,你可能需要让他们相信你的模型预测的是正确的结果,你需要提供一些他们应该适应它的好理由。你不能简单地把准确性扔给他们。如果你的算法是可解释的,那么你可以向他们展示为什么这个模型能预测一些东西。可解释性只意味着算法的特性重要性。
例如:如果你正在做一个医疗保健项目,你的模型预测一个人的疾病是阳性还是阴性。这是一个非常敏感的问题,他们不能犯错误,这就需要可解释性。如果你的模型向你展示了预测这个人积极/消极的原因(因为 X 特征(身体的某些水平)大于 X 值或其他什么),这将变得更加容易和有意义。
5.为什么要学习算法的时间/空间复杂度?
当我们实时工作时,我们可能必须处理大量数据,如果需要低延迟,时间和空间复杂性可以帮助您选择正确的算法。
如果您的模型占用更多内存,那么实时运行它会非常昂贵,尤其是如果您使用云基础架构来运行模型。有时,一些业务问题伴随着低延迟要求,其中一些算法提供了良好的准确性,但由于其时间/空间复杂性的限制而无法满足要求。
Wikipedia 是一个很好的资源,可以获得每个算法的所有相关信息。
6.为什么我们需要理解算法背后的数学?
又是数学?是的,是的,我明白了。我们甚至可以通过简单地从 Scikit learn 导入来使用算法,即使不理解数学,但是让我告诉你,从长远来看,这是完全不推荐的。好吧,不管我们接受与否,我们肯定需要数学来更好地理解在引擎盖下到底发生了什么。这可能会让一些人失望,但我得到了好消息,我们不能避免数学,但我们可以简化它,避免严格的数学。
简单地说,大多数机器学习算法的工作是最小化实际输出和预测输出之间的差异(损失)。
算法=最小化(损失)+正则化项
例如,我们应该最小化逻辑回归的对数损失和 SVM 等的铰链损失。
注意:并不是每个 ML 算法都是这样,这只对少数算法有效。
为了最大限度地减少这种损失,在内部这些算法使用优化技术,如梯度下降和其他涉及一点数学的味道。因此,如果你不太擅长数学,那么就试着理解每个算法的损失函数及其梯度下降,这样你就可以避免所有其他严格的数学,并保持目标不变。一旦你对此感到满意,你就可以深入研究更多的数学知识。
7.为什么要从头开始实施(可选):
如果假设你正在学习吉他,你会先从基础开始,然后慢慢地尝试复制别人已经创作的音乐,在这个阶段,如果你明白他们是如何创作音乐和曲调的,那么下一步就是创作你自己的音乐,对吗?
同样,我们可以通过复制现有算法来从头实现它们,从而更清楚地理解现有算法。您将学到一些要点,这些要点可以帮助您在将来构建更好的模型。请记住,由于一些问题,我们可能无法在我们的项目中始终使用 Scikit learn 版本的算法。在这种情况下,您必须准备好以满足您需求的方式优化或修改算法。
这说起来容易做起来难,这将花费你大量的时间来达到这一点,这就是为什么我把它标记为可选的。至少尝试实现一个算法来理解它实际上是如何工作的。如果你觉得很难编码,把算法分解成几个部分,先写伪代码,然后试着把它转换成实际代码。
塞巴斯蒂安·拉什卡的《Python 机器学习是一本真正的好书,可以指导你从零开始开发算法。
结论:
不要急于求成,慢慢来,用最好的方式学习,而不是学了一半又回来多次,每次都要参考。记住,目标不是完美,而是一个强大的基础,相信我,我们永远不能完美的事情,目标总是每天都变得更好。如果你能理解算法的要点,并且清楚算法是如何工作的,那么从长远来看,你肯定会感谢你自己。
在这个过程中,如果你不明白某件事或卡住了,把它放在一边,继续其他话题。不要一味的坚持,浪费自己宝贵的时间。稍后带着一个全新的想法回来,再次检查一下,相信我,你会感到惊讶的。万一你仍然不能理解某件事,寻找其他能以更简单的方式解释它的资源。
最后一步,将您的所有知识应用于不同数据类型和大小的多个数据集。要获得真正的知识,实践就是一切。比起单纯的阅读,你会学到很多东西,所以准备好动手吧。
如果你读到这里,你肯定有学习 ML 的热情,这是学习任何技能最重要的因素。不断学习,不要放弃。
如果您有任何建议或疑问,请随时在评论中告诉我,或者您可以通过我的 Linkedin 与我联系。
编码快乐!回头见!!
了解雇主对 2020 年数据科学家的期望
数据科学就业市场趋势
该分析是从 1000 多份最近的数据科学家工作中完成的,这些工作是使用网络搜集从工作门户中提取的。

最近,我开始积极地寻找一份数据科学方面的工作,我没有任何像人工智能/机器学习方面的硕士或博士背景的正规教育。我开始学完全是出于自己的兴趣(不仅仅是因为炒作)。这是一个具有挑战性的选择加入的轨道,尤其是如果你同时从事其他一些技术。我通过参加许多 MOOCs(大规模开放在线课程)开始了我的旅程,并开始阅读多个博客。最初,它没有意义,最终在阅读了其他人的代码并接触了实时数据集之后。慢慢开始有意义了。
当我开始找工作时,一个有趣的新故事开始了。我在印度打开了一个顶级工作门户网站,开始搜索工作,我发现很少有工作与我正在寻找的相关,但当我打开其中一个时,令我惊讶的是,他们提到的要求对我来说是新的。抛开传统的数据分析、机器学习、深度学习不谈,一些 ETL 工具和多种大数据技术被提到是必备技能。我认为这没什么,因为如今每个公司都有自己对数据科学家的定义,并开设了另一个职位。这一次,它提出了对 AWS、Azure 和 Power BI 等其他技术的需求。
请记住,所有这些空缺职位都标有“仅数据科学家”字样。所有这些空缺都有共同的要求,如机器学习算法,统计学,数据分析,数据清洗和深度学习技术。除了这些技能,一些公司还希望候选人具备云知识(AWS、Azure 或 GCP)和数据可视化工具,如 Tableau、Power BI 和 ETL 工具,如 SSIS。通常,这些技术更多地与数据分析师/数据工程师角色有关,但数据科学家角色仍在不断发展,并没有真正坚持特定的技能组合。
我确实理解这样一个事实,即公司寻找一个符合他们职位空缺的申请人,并且拥有他们所寻求的技术技能。这肯定会为公司节省时间和金钱,而不是重新提供培训。
因此,我有了一个有趣的想法,来了解 IT 行业对实时数据科学家角色的确切期望,而不是 MOOCs 中通常教授的内容。
目标:我们将努力找出目前业内最热门的技能和趋势。为此,我们将从工作门户获取数据。
注意:这整个分析是为印度市场的数据科学家角色而做的。
在本文中,我们将尝试找到几个重要问题的答案,这些问题是每个数据科学求职者都会想到的。
- 公司寻找的顶尖技能有哪些?
- 业内最期望的经验水平是什么?
- 在这个领域积极提供工作机会的公司有哪些?
- 空缺较多的位置有哪些?
注:你可以在结论部分找到完整代码的链接。
1.网页抓取:
我从印度顶级求职门户网站-Naukri.com收集了所有相关的工作信息,如今几乎每个求职者和招聘人员都在使用这个网站。我使用 selenium-python 进行 web 抓取,因为传统的 BeautifulSoap 方法在这个站点上不太好用。

来自 Naukri.com 的工作列表示例
免责声明:网络搜集纯粹出于教育目的。
我们将为每份工作收集这五个要素:角色、公司名称、经验、地点和关键技能。
刮削代码:
2。预处理:
在开始之前,让我们做一些基本的预处理。
2.1.处理缺失值:
执行了基本的清理,找到丢失的值并删除它们。

2.2.处理重复数据:
我们在处理重复数据时需要非常小心,因为一家公司可能会多次发布相同的要求,因为该职位仍然空缺或另一方面,该公司可能会寻找一个具有相同要求的全新职位。为了简单起见,我没有丢失任何数据。
2.3.标记位置和技能列
将所有字符串转换为小写以避免冗余,并将位置和技能列标记化,因为这些列中有多个值。
这是预处理后的样子。

3.分析:
现在,我们有一切可以开始了。
3.1.哪个位置提供更多的机会?:
注意:如果你不是印度人,可以跳过这个位置部分。

- 如果我们观察上面的图,几乎有 38% 的工作岗位位于孟加拉鲁鲁。
- 排名前四的城市,即孟加拉鲁鲁、孟买、海德拉巴和浦那构成了该国数据科学工作岗位总数的近 72 % 。
- 因此,如果你来自这些城市中的任何一个,你获得数据科学家工作的机会可能会比其他城市多。
3.2.有哪些公司在积极招聘?:

- 分析 Vidhya educon 以几乎占总职位列表 21%的比例高居榜首。
- 名单上还有许多咨询公司。这些咨询公司通常为他们的客户进行招聘。
- 一般来说,求职网站的竞争会非常激烈。由于收到的申请数量巨大,大多数时候招聘人员甚至不会看到你的简介。有些情况下,即使是一个空缺职位,你也必须与数百名其他申请人竞争。最好了解那些正在积极招聘的公司,这样我们可以通过他们的官方网站直接申请,这增加了获得面试机会的概率。
3.3.最渴望的体验是什么?:

不同经验层次的工作机会。
- 我们可以观察到,公司显然在寻找有经验的候选人。有 5-10 年工作经验的候选人似乎有更多的空缺。这很有意义因为数据科学家的工作涉及关键的决策技能,这些技能来自经验。
- 至少有两年工作经验的候选人有相当好的机会。
- 这并不意味着新生进不去,只是有经验的候选人比新生有更多的机会。公司通常不会从这些招聘门户网站上招聘应届生,他们会直接从校园招聘中招聘。大一新生总是可以选择为创业公司工作,以获得必要的经验。
3.4.需求中的角色有哪些:
这是调查的重要一步,因为在几个结果之后,工作门户通常会开始显示一些与我们正在搜索的工作无关的其他工作。为了确保我们寻找的是正确的角色,让我们来看看最常提到的 10 个角色。

- 如果我们在上一节中观察到,有更多的职位空缺给有更多经验的人,这给我们留下了一个基于角色的空缺问题。
- 大部分空缺仍然被称为数据科学家。其次是高级数据科学家和首席数据科学家,这当然需要良好的经验。
3.5.公司寻找的技能:
终于,我们到了。你读这篇文章的主要原因。

- 看起来很复杂,别担心,我会在后面的部分分解它。我之所以在这个情节中包含了许多技能,是因为数据科学涉及的领域非常广泛。
- 虽然我们能够在上面的情节中描绘出一些顶级技能,但它仍然不能服务于这个分析的目的。
让我们深入研究一下,以便更清楚地了解这些趋势。
3.5.1.必备技能?:
- 机器学习,作为数据科学家最重要的技能,这并不奇怪。
- 数据挖掘和数据分析是每个数据科学家必须经历的关键活动。

3.强大的统计建模是成为更好的数据科学家所需要的。
4.公司希望对深度学习有很好的了解,因为它提供了最先进的技术来解决一些有趣的实时问题,如 NLP 和计算机视觉。
5.由于每天记录的数据量大幅增加,雇主希望候选人具备大数据技术的知识。实际上,我们可能正在处理大型数据集,这些技能肯定会派上用场。
3.5.2.编程语言吃香?:
- 如果您开始学习数据科学,在开始时,您肯定会发现很难选择正确的编程语言。虽然有许多语言,但竞争总是在 Python 和 R 本身之间进行。让我们看看数据告诉我们什么。

2.业界仍然支持 Python,因为它有丰富的库,随后是 R 语言。
- SQL 是每个数据科学家的必备。虽然它不适合被当作编程语言,但我还是碰运气把它包含在这里:)。
4.在 python 和 R 之后,对 SAS T21 和 C++语言的需求似乎很大。
3.5.3.深度学习框架可供选择?:
- 由于深度学习的突然兴起,许多深度学习框架从谷歌和脸书这样的巨头进入市场。

2.业界更赞成 Tensorflow 而不是 PyTorch 。
3.Keras 在市场上有很好的份额,人们喜欢它,因为它简单易用。
4.虽然有许多其他框架,如 Caffe,Maxnet,但似乎没有太多的机会。即使不在世界上,至少在印度。
3.5.4.哪种大数据技术具有优势?

- 火花高居榜首。你可以选择 python 版本的 spark -Pyspark。
- Hadoop 与 spark 几乎拥有相同的机会,只是略有不同。
- 蜂巢也有相当多的空缺。
3.5.5。哪家云提供商需要 ML?

- 训练模型涉及大量的计算,很容易变得非常昂贵。公司正在寻找更便宜的方式来完成工作,这就是这些云平台出现的原因。
- AWS 高居榜首,其次是 Azure 。
- 企业正在迅速转向云选项。这些技术有更多的机会在未来的数据科学中发挥重要作用。
3.5.6。数据可视化工具有需求吗?

- 雇主们对数据可视化的表格表现出了更大的兴趣。
- 而微软的 Power BI 依然落后。
结论:
为了得到一份工作,你真的必须具备这篇文章中提到的所有技能吗?
也不尽然,如果你对自己的基础知识很在行,列表中没有什么工具是你在工作中容易掌握的。话虽如此,如果你只是在找工作,在简历上写下这些技能可能会帮助你获得面试机会。
如果你擅长所有提到的数据科学家必备技能,那么最好的方法应该是开始参加面试,同时尝试填补你理解中的空白,并学习你认为会让你比其他候选人更有优势的工具/技术。
如果你觉得这很有帮助或者有任何问题,请在评论中告诉我。
回头见。快乐编码..!
参考文献:
- https://medium . com/@ krishnakumar/donut-chart-with-python-matplotlib-d 411033 c 960 b
- https://stack overflow . com/questions/51389377/unfolding-bag-of-words-in-pandas-column-python
- https://www.naukri.com
知道你不知道的:当对预测不确定时,获得可靠的信心分数
接触样本外的例子,作为获得更有意义的预测分数的一种方式。

Artem Sapegin 在 Unsplash 上拍摄的照片
Softmax 预测分数通常用作多类分类设置中的置信度分数。在本帖中,我们将展示在通过梯度下降进行常规经验风险最小化时,softmax 分数可能是没有意义的。我们还将应用异常值暴露深度异常检测中介绍的方法来缓解这一问题,并为 softmax 分数添加更多含义。
判别分类器(试图从数据中估计 P(y|x)的模型)往往在预测中过于自信,即使输入样本看起来与他们在训练阶段看到的任何东西都不一样。这使得这种模型的输出分数不能被可靠地用作置信度分数,因为该模型经常在它不应该有置信度的地方有置信度。
示例:
在这个合成示例中,我们有一个类别 0 的大聚类和另一个类别 1 的大聚类,外加两组较小的训练集中不存在的离群点。

玩具示例
如果我们对此应用常规分类器,我们会得到如下结果:

置信度得分基线
我们看到分类器在任何地方都过于自信,即使是离群样本也有很高的分数。使用热图显示置信度得分。
这使得直接使用 softmax 分数作为置信度分数不是一个好主意,如果分类器在训练中没有看到任何证据来支持它,那么它可能意味着置信度分数是错误的。
但是,如果我们使用异常值暴露深度异常检测中提出的方法,我们可以获得更合理的 Softmax 分数:

异常暴露
这个得分图更加合理,有助于了解模型在哪些地方有足够的信心,在哪些地方没有。异常区域具有非常低的置信度~0.5(相当于在两类设置中完全没有置信度)。
方法的描述
异常值暴露的深度异常检测中提出的想法是使用与您的训练/测试数据大不相同的外部数据,并强制模型预测该外部数据的均匀分布。
例如,如果您试图构建一个分类器来预测图像中的猫和狗,您可以获得一组熊和鲨鱼图像,并强制模型在这些图像上预测[0.5,0.5]。
数据和模型
我们将使用 102 朵花作为分布内数据集,使用 OpenImage 数据集的子集作为分布外数据集。在引言中引用的论文中,他们表明,对一组非分布样本的训练可以很好地推广到其他非分布样本。
我们使用 MobilenetV2 作为我们的分类架构,并用 Imagenet 初始化权重。
**def** get_model_classification(
input_shape=(**None**, **None**, 3),
weights=**"imagenet"**,
n_classes=102,
):
inputs = Input(input_shape)
base_model = MobileNetV2(
include_top=**False**, input_shape=input_shape, weights=weights
) x = base_model(inputs)
x = Dropout(0.5)(x)
out1 = GlobalMaxPooling2D()(x)
out2 = GlobalAveragePooling2D()(x)
out = Concatenate(axis=-1)([out1, out2])
out = Dropout(0.5)(out)
out = Dense(n_classes, activation=**"softmax"**)(out)
model = Model(inputs, out)
model.compile(
optimizer=Adam(0.0001), loss=categorical_crossentropy, metrics=[**"acc"**]
) **return** model
我们将使用生成器从硬盘上一批一批地加载图像。在基线中,我们仅加载分布内图像,而在异常曝光模型中,我们从具有正确标签的分布内图像中加载一半,从具有统一目标的分布外图像中加载另一半= >:
target = [1 / n_label **for** _ **in** range(n_label)]
结果
两种训练配置对分布样本的准确率都略高于 90%。如果 softmax max 得分低于 0.15,我们选择预测“不知道”,从而放弃进行类别预测。
现在让我们看看每个模型是如何工作的!
常规培训:
您可以通过以下方式运行 web 应用程序:
streamlit run main.py


来自 Unsplash 的第一张鸟图像/来自 102 种花数据集的第二张花图像
我们训练了一个花卉分类,然后尝试对一张鸟的图片进行分类,该模型预测仙客来类具有相当高的置信度" 0.72 ",这不是我们想要的。
异常风险:
您可以通过以下方式运行 web 应用程序:
streamlit run ood_main.py


来自 Unsplash 的第一张鸟图像/来自 102 朵花数据集的第二张花图像
好多了!因为最大 softmax 分数是 0.01,所以鸟图片被分类为“不知道”。在两个模型之间,分布内花图像(右)的预测保持不变。
接下来是对来自维基百科的图像的预测,第一个(左)是 102 朵花数据集中的一朵花,第二个是分布中不存在的一种食肉植物。异常暴露模型表现如预期,分布内图像被正确分类,而模型避免对食肉植物进行分类预测。


修改第一张花图由 aftabnoori—Own work,CC BY-SA 4.0,【https://commons.wikimedia.org/w/index.php?curid=41960730】T2/修改第二张植物图:https://commons . wikimedia . org/wiki/File:Venus _ fly trap _ showing _ trigger _ hairs . jpg
结论
在这篇文章中,我们展示了 softmax 分数作为信心的衡量标准是多么的有缺陷。然后,我们应用了一种基于离群值暴露的方法来解决这个问题,并获得更有意义的置信度得分。这使我们能够在需要时可靠地避免做出预测,这在许多商业/研究应用中是一个至关重要的特性,在这些应用中,不做任何预测比做出明显错误的预测要好。
参考资料:
代码:
[## cvx tz/learning _ to _ absent
知道自己不知道的。通过在 GitHub 上创建一个帐户,为 CVxTz/learning _ to _ absent 开发做贡献。
github.com](https://github.com/CVxTz/learning_to_abstain)
了解你的受众。如何展示你的数据科学项目!

史蒂文·洛艾扎在 Instagram 上的照片
如何定义和调用将您的冗长代码隐藏在别处的函数。
介绍
你是否展示过一个项目,并开始一行一行地滚动代码,只是为了找到你想要展示的情节?
这从你打算展示的有价值的信息中拿走了。
你们中有人有像这样或者更长的 Jupyter 笔记本吗?
如果你这样做了,请记住几件事:
如果你的听众精通技术,他们不会在乎你能使用 pandas 来操作数据或者知道如何使用 matplotlib 上的选项。
而商业利益相关者真正做的是 而不是 的关心。
这条建议特别适用于你必须向上级展示你的发现的工作环境。
更好的方法
你可以从 Github 下载 jupyter 笔记本和 python 脚本来跟进。
开发工具来展示我们的机器学习模型和预测。-StevenLoaiza/演示
github.com](https://github.com/StevenLoaiza/presentation) 
下面,我们在笔记本上运行一个 Python 脚本。该脚本包含一些函数,这些函数将用于执行与上述示例完全相同的任务,但是代码行更少。
这段代码是可展示的,并没有把注意力从真正重要的东西上转移开,在这个例子中,就是图表。
我们如何做到这一点?
定义函数
要做的主要事情是定义一些函数。我知道我需要过滤数据,创建一个新列,更改列名并绘制数据图表。
我创建了几个函数来完成这些任务。下面是其中一个函数的例子— create_yr() 。
*我假设您已经知道如何用 python 编写函数 *
我建议你把所有的功能都写在笔记本上,这样你就可以验证它们是否有效。一旦你对它们感到满意,我们就要把它们从视线中移除!

保存\运行脚本
将上面编写的函数复制并粘贴到记事本中。当您转到“另存为”时,将其从 *更改为。txt 文件到一个 *。py 文件。(我一般保存在笔记本的同一个目录下)

现在,您可以将脚本调用到您正在处理的数据科学笔记本中。这将允许您使用保存在 *中的所有功能。py 文件。

如果不在同一个目录中,您可以将其更改为"Path**/function _ call . py " *

哦不!什么是 create_yr()
想象一下,你必须在几个月后重新访问这个项目。
当你阅读它的时候,你会看到许多用户定义的函数,但是你不记得它们是什么。
加载脚本
可以加载脚本了!这将把脚本的全部内容放在笔记本单元格中供您查看。
结论
我希望这些想法能在你的下一个项目中很好地为你服务。编码是一门艺术,在开始时有一些额外的步骤,你可以在将来为调试或重组笔记本节省无数的时间。
感谢您的阅读!
附加说明
熊猫。DataFrame.pipe:这是我在上面使用的操作符之一。这是一个很好的工具,可以用来创建像样的代码。从上面的例子中,您可以遵循对代码执行操作的逻辑顺序。
[## 熊猫。DataFrame.pipe - pandas 1.0.3 文档
应用于系列/数据框架的函数。、和被传递到。或者,数据关键字是字符串的元组…
pandas.pydata.org](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.pipe.html)
了解你的偏见
你在收集数据时应该注意什么
在统计学中,你可能在每一步都会犯错误。你可能会问一个与你的问题无关的问题,错误地定义感兴趣的人群,在你的分析中犯一个错误,等等。
最脆弱的时刻之一是数据收集。因为你在这一步得到的是你最终决定的基础。今天,让我们来讨论几个常见的陷阱,它们会让你的完美数据收集过程大打折扣。
首先让我们介绍一下我们的主要敌人——偏见。在统计学中,偏差指的是数据的系统性失真(与方差相反,方差是混乱的)。你可以想象一个弓箭手射击一个目标,并一直击中正下方的中心。同样的,例如,由于设备故障,你的大学生身高数据可能会高估测量值。

虽然高方差意味着射手射遍所有地方,但高偏差会让他们朝同一个方向射失目标。[图片由 Grzegorz jurdzinski 提供]
问题是你并不总是知道你的数据是否以及如何被歪曲。这就是为什么意识到即将打破你的分析的危险是很重要的。
远程办公
由于持续的新冠肺炎疫情,许多公司被迫关闭办公室。只要有可能,工人们就在家工作。一些 IT 公司,如 Twitter 或脸书,甚至决定允许员工无限期在家工作。许多人怀疑这是否是一个好决定。毕竟,那时人们的工作效率不是更低吗?想象一下,你是一家科技公司的董事,正在考虑这样的举动。你可能想知道在这个行业工作的人对此感觉如何,以及他们这样工作是否有任何问题。

在家工作似乎是个不错的选择。但是有那么好吗?[图片由 Dillon 在 Unsplash 上摇动
假设你准备了一张表格,上面有你感兴趣的问题,并把它发给人。我们来讨论一些场景。
覆盖不足偏差
场景一:你向所有员工发送了一封带有问题的电子邮件。
这很方便——你有所有的地址,也许你甚至相信你的员工不会说谎(下面会有更多关于这个问题的内容)。但是首先你想了解 IT 行业的所有人,而不仅仅是你的公司。你的同事很可能不会成为人口样本的代表。也许你有一个很酷的办公室,每个人都想回去?还是你的员工都是积极性很高的人,在家里没有注意力集中的问题?你不知道。
你收集数据的方法从样本中排除了一部分人口。因此它不具有代表性——这种偏差被称为覆盖不足偏差。
选择偏差
场景二:为了接触更多的人,你将表格发布在公司的公共博客上。
现在每个人都包括在内了——每个有互联网接入的人都可以访问您的表单(并且您假设所有 IT 人员都有互联网),因此您不会遗漏任何人。但是每个人回答你的问题的可能性都一样吗?由于文章发布在你公司的博客上,你的员工更有可能阅读它,从而填写你的表格(即使他们不是唯一这样做的人)。
你的取样方法更喜欢某些人,导致了选择偏差。
无反应偏差
场景三:你雇佣了一家专门从事民意调查的公司来寻找 IT 行业员工的代表性样本,并向你提供他们的电子邮件地址。
看起来很完美,对吧?你设法联系了你感兴趣的人群的代表性样本。还有一个问题——不是所有人都会回复。不回答你问题的人不会只是一些随机的人,他们可能有一些不回答的共同原因。
这就是为什么你可能会以无反应偏差而告终。仅仅接触一个代表性的样本是不够的——你的答案是你最终感兴趣的数据。
反应偏差
场景四:厌倦了失败,你雇佣了一名黑客来封锁 IT 行业典型员工的电脑,直到他们填写了你的表格。
这次一定要成功,对吧?没有人会为了避免填写一些简短的表格而扔掉他们的电脑。但是你得到了答案并不意味着他们是诚实的。毕竟,人们现在很愤怒,他们可能会撒谎。他们也知道你会以某种方式利用他们,所以他们可能会欺骗你相信适合他们的东西。也许他们害怕数据不会被适当地匿名化,他们不想承认他们没有生产力?或者也许他们想让你认为 WFH 很棒,他们会说他们喜欢它,只是因为他们想有这个选择?
这可能是最难防范的情况之一——你得到了答案,但你不知道它们是否是真的——我们称之为反应偏差。
不止如此
请注意,有更多种类的偏见可能会潜入您的数据中,您应该始终考虑什么可能是错误的。它们包括但不限于观察者偏差、损耗偏差、回忆偏差等。维基百科描述了其中一些。还有一部关于生存偏见的伟大的 xkcd 漫画。

总是分析你是如何收集数据的,错误就在等待着你去犯。[图片由艾米丽·莫特在 Unsplash 上拍摄]
结束语
你的数据可能看起来非常完美,但它可能会让你得出错误的结论,即使它与现实略有出入。很难保护自己不受偏见的影响,但是意识到什么可能出错会帮助你避免许多错误。
如果你有兴趣看看现实生活中犯的一些错误,我们推荐你看一下最近由 Cassie Kozykov 写的关于纽约市新冠肺炎感染研究的文章。
本文与 托马什·韦索斯基 共同撰写。请看他的新 篇 ,在那里他描述了推断和预测的区别。
用 RFM 了解你的客户
最后更新于 2020 年 6 月
了解如何仅用三个数据点来细分你的客户:新近性、频率和货币价值。

来源:( @annadziubinska )转自 Unsplash
在这篇文章中,我们将向你展示如何通过几个简单的步骤创建一个 RFM 模型。您还将学习如何用几行 Python 代码实现该模型。无论你是有技术背景的人还是非编码人员,我都强烈鼓励大家跟随我,去感受开发一个有价值的 RFM 模型是多么容易。在后续的博客文章中,我们将扩展 RFM 模型,并介绍来自统计学和机器学习领域的更先进的技术。
为什么你应该做 RFM 细分
RFM 细分将使您能够更好地了解您的客户群,并作为您的数据之旅和更高级的客户模型的良好起点。您将能够为您的企业的关键问题提供更准确的答案,例如:
- 谁是你最好的客户?
- 哪些客户处于流失的边缘?
- 谁有潜力转化为更有利可图的客户
- 哪些客户流失/不活跃?
- 留住哪些客户至关重要?
- 谁是你的忠实客户?
- 哪一组客户最有可能对您当前的活动做出回应?
RFM —基础知识
RMF 是一种简单的统计方法,根据顾客的购买行为对他们进行分类。仅通过使用三个客户数据点来识别行为:购买的最近度(R)、购买的频率(F)和每次购买的平均货币价值(M)。在对 RFM 数据进行一些计算后,我们可以创建可操作且易于理解的客户细分,如下所示:
- 冠军:最近买的,经常买,花的最多
- 忠诚客户:定期购买。对促销有反应。
- 潜在忠诚者:平均频率的近期客户。
- 最近客户:最近购买,但不经常购买。
- 前景看好:最近有购物者,但还没花多少钱。
- 需要关注:高于平均新近度、频率和货币值。可能不是最近才买的。
- 即将入睡:低于平均新近度和频率。如果不重新激活,将会丢失它们。
- 面临风险:他们购买后已经有一段时间了。需要把他们带回来!
- 不能丢了它们:以前经常购买但很久没回过。
- 冬眠:上一次采购是长退,订单数少。可能会丢失。
上述细分市场和标签经常被用作一个起点,但你可以想出更适合你的客户群和商业模式的你自己的细分市场和标签。
对于每个细分市场,您可以设计适当的操作,例如:
- 冠军:奖励他们。他们可以成为新产品的传播者和早期采用者。
- 忠诚客户:追加销售更高价值的产品。与他们交战。求点评。
- 潜在忠臣:推荐其他产品。参与忠诚度计划。
- 最近/新客户:提供良好的入职流程。开始建立关系。
- 有前途:创造更多的品牌知名度。提供免费试用。
- 需要注意:重新激活它们。提供限时优惠。根据购买历史推荐新产品。
- 即将睡眠:重新激活它们。分享宝贵的资源。推荐热门产品。提供折扣。
- 有风险:发送个性化电子邮件或其他信息以重新建立联系。提供优惠并分享宝贵的资源。
- 不能失去他们:把他们赢回来。和他们谈谈。给他们特别优惠。让他们觉得自己有价值。
- 冬眠:再造品牌价值。提供相关产品和优惠。
准备我们的数据
在本帖中,我们将使用在线零售数据集——在互联网上广泛用于不同的分析。看起来是这样的:

交易数据的起始表
经过一些调查,我们发现数据需要一些清理,所以我们做了一些过滤以获得更好的输出——记住:垃圾输入,垃圾输出。以下是我们所做的:
- 仅选择英国事务以获得不太复杂的组。不同国家的行为会受到不同活动、折扣、运费等的影响。我们也避免了不同货币可能带来的困难。
- 过滤掉所有没有正确 CustomerID 的交易。
- 筛选出数量或单价为零或更低的交易。
- 创建了一个 sum 列,我们通过将数量乘以单价来计算每个订单行的收入。然后,我们将 InvoiceNo 上的交易分组,并创建 InvoiceSum 列来保存每张发票的收入。
我们现在已经拥有了创建 RFM 模型所需要的一切。我们的事务表现在看起来像这样:

我们清理的交易表按发票号分组
从交易数据中创建 RFM 模型
为了使创建模型的过程更容易理解,我们将在进行过程中展示数据清单。
步骤#1 计算 RFM 值
为了创建 RFM 分数,我们必须获得每个客户的新近度、频率和货币价值的数据点。它们的定义如下:
最近:客户最后一次交易的年龄。这与香草 RFM 略有不同,在香草中,新近度是根据自上次购买后的天数来计算的。
频率:客户生命周期内的购买次数
货币价值:客户交易的平均货币价值。
这一步之后的结果应该是一个 RFM 汇总表,其中包含一个唯一的客户 id 以及最近、频率和平均货币值的数据。它应该是这样的:

我们的开始摘要 RFM 表
分割时,我们将只使用频率、新近度和货币值列。 T 列(客户的年龄)仅在内部用于计算 recency 的值,不会用于将来的计算。
首先,我们将快速检查一下我们的数据,看看它们是如何分布的。
最近分布

频率分布
正如我们所见,频率数字是高度倾斜的,因为大量的非重复交易。事实上,多达 85,3% 的顾客都是非回头客。为了创造更合理的细分市场,我们选择过滤掉非回头客。现在分布看起来像这样:

不考虑回头客的频率分布。
新近分布

回头客的新近分布
在过滤掉非回头客之后,新近数据也具有更好的分布。如果没有过滤器,图会严重偏向零。
货币分配

回头客的货币价值分布
这是具有挑战性的数据。正如我们所看到的,大多数客户的平均货币价值在 0 到 500 之间,但我们也有一些客户超过 2000,甚至超过 16000。这些顾客看起来像是局外人。对此的一个假设是,他们的行为更像是做生意,买了再卖。我们决定移除“异常值”并将阈值设置为 2k,这给出了以下分布:

没有“异常值”的货币价值分布
请注意,我们应该进一步调查异常值,而不仅仅是抛弃它们。
步骤 2:获得个人 RFM 分数
获得个人 RFM 分数有几种方法。你可以利用你自己的商业专长和启发,做出适合你的客户群的排名。在这种情况下,我们将走统计路线,使用四分位数对我们的客户进行排名。
通过将每个 RFM 值分成四分位数,创建四个或多或少相等的桶,来对各个 RFM 分数进行排名。然后,我们将每个桶从一到四进行排序;四是最好的。我们的汇总表现在应该看起来像这样:

RFM 个人得分表
得分最低的 A recency (R)为 1,表示已经有一段时间没有活动的客户。频率为 4,得分最高,是你最频繁的买家,以此类推。
第 3 步:计算总体 RFM 分数
这一步可以通过两种方式完成:
- 连接——创建片段 这里我们只是像字符串一样连接(而不是添加)单个的 RFM 乐谱,并得到带标签的片段作为回报。我们最好的部分将是 444 分,最差的部分将是 111 分,这意味着在所有三个 RFM 类别中的最低分。
- 加法—创建一个分数 在这里,我们将各个 RFM 分数(如数字)相加,并得到一个指示客户分数的数字作为回报。分数范围从 3 到 12,我们可以用它来创建更加人性化的标签类别。
如果我们选择同时进行串联和加法,我们的汇总表将如下所示:

包含 RFM 片段和分数的表格
步骤#4 用人类友好的名字分组和标记
即使像 411 和 243 这样的片段可以被人类理解,它们也不是对人类最友好的标签。但正如帖子开头所承诺的,为 RFM 片段和 RFM 分数创建更多可用的标签是可能的。对于 RFM 部分,我们将使用最常见的命名方案,如上所述。我们的汇总表现在将如下所示:

带有 RFM 线段的表格
如你所见,我们现在有冠军和冬眠者等等。就位。
如果您更喜欢附加方案,我们可以创建客户标签,如:青铜、白银、黄金和白金。

RFM 表与人类友好的分数标签。
看起来怎么样?
为了鸟瞰您的总体客户群,我们可以绘制一个简单的条形图,显示每个类别中有多少客户:

RFM 段计数
不幸的是,看起来我们的大多数客户都在冬眠,所以我们最好走了。好的一面是:我们有一些冠军、以及一些有前途的和新类别的客户。我们最好好好照顾他们。
我们可以对 RFM 分数做同样的绘图,看看它如何比较。

RFM 分数计数
自然,我们看到了相同的模式:少数最有价值的客户和大量需要关注和重新激活的客户。最好开始工作。我们学到了什么
我们学到了什么
如果 OnlineRetail 数据集中的客户是我们的客户,我们可以说我们已经了解了以下内容:
- 我们 85%以上的客户都不是回头客——我们需要制定一个如何提高保留率的计划。
- 我们的数据包含大量需要清理的垃圾——我们需要了解数据是如何生成的,并改进我们的数据验证。
- 我们的数据包含离群值,离群值应该被调查,并可能被标记或删除。
- 清理数据后,我们的 RFM 模型可用于为每个客户群创建更精确的行动计划。这可以对营销支出、转化率和客户保持率产生积极影响。
结论
如您所见,我们只需使用三个客户数据点就可以获得可操作的客户细分。如果您刚刚开始您的数据之旅,RFM 模型是一个有用的起点,它既快速又易于理解和实施。
Python 代码的完整示例
准备数据
创建 RFM 模式
从你的 WhatsApp 聊天记录中了解自己
使用 python 对聊天数据进行简单的数据探索以发现新事物

由于新冠肺炎疫情,我被建议在家做远程工作。已经一个星期了,整天呆在家里让我厌烦,所以我随意地想,也许是时候做自我反省了。幸运的是,我记得不久前我导出了我的 WhatsApp 聊天。所以我一头扎进去,决定做快速的数据探索,以更多地了解我自己和我的对话者。让数据说话。
数据准备
WhatsApp 导出的聊天格式为.txt。消息的每一行都由<timestamp> — <sender> : <message>组成。在消息有多行的一些情况下,第二行和随后的行将仅用<message>表示,而没有<timestamp> — <sender>。结构见下例。

将数据转换成数据帧让我可以做更多的事情。这个任务的美妙之处在于它需要模式匹配来区分timestamp、sender和message。正则表达式将使工作变得容易得多。我将 Python 的re模块与其f-string字符串格式结合起来,发现这是一个很好的组合,尤其是在更复杂的模式上。下面是我将.txt文件转换成dataframe文件的代码。
够不够?不。我们可以检索更多的信息来帮助未来的分析。因此,我在下面的代码中做了更多的特性工程,并返回下面的dataframe。

探索性数据分析
现在数据已经准备好了,让我们从回答几个问题开始
1.最活跃的对话发生在什么时候
了解聊天行为是必须的。我认为调查谈话发生最多的时间将会很好地描述它。所以,在小时频率中,我取了平均值:
- 字数(
word), - 字符数(
char), - 被认为是一个回复 (
seq)的行的顺序号 - 行数(
seq_line)。
万一你把seq和seq_line搞混了,假设 A 和 B 之间有一段对话
- A-A-B-B-B 将有 2 个序列和 5 个
seq_line - A-B-A-B 将有 4 个序列和 4 个
seq_line
从上面的图表中,我至少知道:
- 在工作日,我们倾向于在休息时间(12 点)停止聊天,而在周末,则是在下午 3 点。我能理解为什么我们在工作日的中午停止聊天。现在是休息时间。我吃午饭,快速休息,这让我远离我的手机。但是,我从没想过周末下午 3 点会那么低。
- 在工作日,seq 和 seq_line 之间的差距在中午变得更小,这意味着在这个时间每个回复包含的行数非常少。总体差距在周末要高得多,这意味着我们经常在周末回复更多的行。
- 如果我们放大到晚上 7-10 点,即使工作日和周末之间的行数(
seq_line)相对相同,周末的字数(word)也要高得多。这意味着每一行在周末包含的单词比工作日多。我想这是“故事时间”。如果我必须讨论什么,我想我会在那个时候做。
我可以说,平均而言,我在下午 6 点开始积极聊天,每天晚上 10-11 点达到高峰,直到早上 6 点才停止聊天。
2.谁反应更快
我想知道,谁回复短信的时间更长。知道谁有反应,谁没有反应是非常重要的。我不想在没有任何证据的情况下,被人笼统地以“你回复晚了”来评判。所以,这又是关键时刻了。
我计算了甲方和乙方所有文本的平均值。我计算了甲方最后一次聊天和乙方第一次回复之间的差异(反之亦然),进行了一些数据辩论,结果如下:
看起来甲方和乙方差不多。他们花了大约 10 分钟回复一条信息。然而,在乙方方面,差异更大,这意味着乙方有更大的机会需要更长的时间来回复。我想我知道乙方是谁了*哎。
3.最快的响应时间是什么时候
与前一个问题类似,但现在我想看看最快的反应发生在什么时候。从平均值来看,在工作日(周一至 Fri),甲方和乙方的响应时间分别为凌晨 1 点和晚上 11 点。周末,甲方凌晨 0 点最快,乙方还在晚上 11 点。
你可以看到甲方和乙方的几个不同的峰值,但我想强调的是,这个事实支持了我之前的说法,即谈话在深夜更激烈。
4.谁写得更长或更快
我已经告诉你谁回答得更快了。但是如果用更长时间回复的一方用了更多的词呢?我对每个聚会的文本中使用的行、词和字符进行了简要总结。请注意,文本或回复可以包含多行。
如果我们仔细观察,就行数而言,乙方回复的行数比甲方多。这可能会导致一个结论,即甲方倾向于用一整行来总结回复,而乙方倾向于用不同的行来发送。
乙方在每次回复中发送的字数和字符数相对低于甲方,这意味着甲方比乙方写得更长。这也得到持续时间变量的支持,其中甲方比乙方写回复的持续时间更长。因此,甲方比乙方写得更长
在前面的问题中,我们知道乙方需要更长的时间来响应。我假设那是因为 B 写的比 A 长,实际上 A 写的更长。而且 B 写的甚至比 a 还快所以 B 没有借口哈哈。
5.词频
检查单词数据的一种最流行的方法是使用单词云可视化其词频。
我删除了几个停用词,以去除无意义的常用词。因为我在聊天中使用印度尼西亚语,所以我使用 Elang 来删除印度尼西亚语的停用词。现在,使用单词云,看看这些单词

有很多“哈哈”和“wkwk”,印度尼西亚人认为是笑的词。使用正则表达式,我删除了笑的单词,这是最后的单词云。

如果你听不懂的话我很抱歉,这是印尼语,而且多是非正式用语(反正谁在聊天中用正式用语)。
6.我们多久笑一次
之前我发现笑的单词占据了我的单词云很多空间。我们笑得那么频繁吗(通过短信)?为了找出答案,我提取了所有笑的单词,并将其数量与行数进行比较,以获得概率。

21.7%概率一句台词有笑点?太搞笑了。我没期望那么多。但事实就是如此。也许我在短信里是个有趣的人。我是吗?
摘要
我们在深夜进行了一次激烈的谈话,可能是在谈论彼此的经历。我们经常笑。甲方写的很多但是写的时间比较长,乙方写的比较短但是回复的时间比较长。
未来的工作
这些数据有许多应用。在未来的工作中,我想对聊天进行情感分析,看看我是否可以使用数据来预测对话的数量,并使用多个对话(多人)进行聚类
如果你认为我在这篇文章中遗漏了什么,请在下面留下评论。我也希望听到任何形式的问题/建议。
我的 git 库上有完整的代码
谢谢你。
用深度神经网络知道已知的未知
深度神经网络中随机和认知不确定性的定义和量化
深度神经网络 (DNNs)是易于实现的通用机器学习模型,可以在许多领域实现最先进的性能(例如,计算机视觉、自然语言处理、语音识别、推荐系统)。然而,DNNs 并不完美。你可以阅读 文章博文书籍中的任意号 讨论有监督深度学习的各种问题。在本文中,我们将关注一个(相对)狭窄但重要的问题:标准 DNN 无法可靠地显示何时预测不确定。对于一个拉姆斯费尔德式的来说:DNNs 没有能力知道“已知的未知”
作为 DNNs 中这种故障模式的一个简单例子,考虑为二进制分类任务训练 DNN。您可能会合理地假设 DNN 的 softmax(或 sigmoid)输出可用于测量 DNN 在其预测中的确定性或不确定性;您可能会认为,看到接近 0 或 1 的 softmax 输出表示确定性,接近 0.5 的输出表示不确定性。实际上,soft max 输出很少接近 0.5 ,并且通常接近 0 或 1,不管 DNN 是否做出正确的预测。不幸的是,这个事实使得天真的不确定性估计变得不可靠(例如,softmax 输出上的熵)。
公平地说,不确定性估计并不是 DNN 的所有应用都需要的。如果一家社交媒体公司使用 DNN 来检测图像中的人脸,以便其用户可以更容易地标记他们的朋友,而 DNN 失败了,那么这种方法的失败几乎无关紧要。用户可能会稍感不便,但在社交媒体或广告等低风险环境中,不确定性评估对于从 DNN 中创造价值并不重要。
然而,在高风险环境中,如自动驾驶汽车、医疗保健或军事应用,衡量 DNN 预测的不确定性可能至关重要。不确定性度量可以降低部署模型的风险,因为它们可以提醒用户这样一个事实,即某个场景本身很难进行预测,或者该场景以前没有被模型看到过。
在自动驾驶汽车中,由于信噪比较低,DNN 在夜间的预测更不确定(至少在光学相机的测量中),这似乎是合理的。在医疗保健领域,如果向诊断皮肤癌的 DNN 显示一幅特别模糊的图像,尤其是如果模型在训练集中没有看到如此模糊的例子,那么它应该更加不确定。在分割卫星图像的模型中,如果对手改变了他们伪装某些军事设施的方式,DNN 应该更加不确定。如果这些情况中固有的不确定性被传达给用户,该信息可以用于以更安全的方式改变系统的行为。
在本文中,我们探讨了如何估计两种类型的统计不确定性以及在 DNN 的预测。我们首先讨论这两种类型的不确定性的定义,然后我们强调一种流行的和易于实现的技术来估计这些类型的不确定性。最后,我们展示并实现了一些利用这些不确定性估计的分类和回归的例子。
对于那些对代码示例最感兴趣的人来说,这里有两个 Jupyter 笔记本,一个有玩具回归示例,另一个有玩具分类示例。在下面的“示例和应用”一节中也有基于 PyTorch 的代码片段。
我们所说的“不确定性”是什么意思?
剑桥词典将不确定性定义为:“某事未知的情况。”有些事情可能不为人知有几个原因,从统计学的角度来看,我们将讨论两种类型的不确定性,称为偶然(有时也称为偶然)和认知不确定性。
偶然不确定性与不确定性的客观或物理概念有关,它是数据生成过程中固有的一种不确定性。由于偶然的不确定性与数据的内在质量有关,我们假设它不能通过收集更多的数据来减少;即它是不可约的。
一个简单的例子可以很好地解释随机不确定性:假设我们有一个硬币,它有正面或反面的正概率。那么,即使硬币有偏差,我们也无法确定地预测下一次投掷会是什么,不管我们做了多少次观察。(例如,如果硬币有偏向,正面朝上的概率为 0.9,我们可能合理地猜测正面将在下一次投掷中出现,但我们不能确定它会发生。)
认知不确定性与主观或个人的不确定性概念有关——这是一种由于对真实数据生成过程的了解或无知而产生的不确定性。由于这种类型的不确定性与知识有关,我们假设它可以减少(例如,当更多的数据被收集并用于训练时);也就是说,它是可约的。
认知的不确定性可以用回归的例子来解释。假设我们正在拟合一个线性回归模型,我们有-1 和 1 之间的自变量 x ,以及所有 x 的对应因变量 y 。假设我们选择了线性模型,因为我们相信当 x 在-1 和 1 之间时,模型是线性的。然而,我们不知道当一个测试样本 **x *** 远远超出这个范围时会发生什么;说是在 x * = 100。因此,在这种情况下,模型规格存在不确定性(例如,真实函数可能是二次的),并且存在不确定性是因为模型没有看到测试样本范围内的数据。这些不确定性可以捆绑成关于真实数据生成分布的知识的不确定性,这是认知的不确定性。
关于概率和不确定性的术语偶然性和认知性,似乎是由伊恩·哈金在他的书《概率的出现】中引入现代词典的,该书讨论了 1600 年至 1750 年的概率历史。对于外行读者来说,这些术语并不清楚,但它们的定义与概率和统计基础中最深层的问题有关:概率意味着什么?如果你熟悉术语频率主义者和贝叶斯,那么你会看到随机(客观)和认知(主观)不确定性之间各自的关系。我不打算在这篇博文中解决这个哲学问题,但我知道,运气和认知不确定性的定义是微妙的,什么属于哪一类是有争议的。为了更全面(但仍然适用)地回顾这些术语,请看文章:“偶然性还是认知性?有关系吗?
为什么区分偶然的和认知的不确定性很重要?假设我们正在开发一辆自动驾驶汽车,我们拿出一辆在普通道路上训练过的原型车,让它驶过蒙扎赛道,这条赛道有着极其倾斜的弯道。

图 1 :蒙扎赛道上的倾斜转弯
由于汽车之前没有见过这种情况,我们会认为自动驾驶汽车中的图像分割 DNN 是不确定的,因为它从未见过接近地面左侧的天空。在这种情况下,不确定性将被归类为认知性的,因为 DNN 人不了解这样的道路。
相反,假设我们乘坐同一辆自动驾驶汽车,在下雨天开车出去兜风;假设 DNN 已经在多种雨天条件下接受过训练。在这种情况下,仅仅由于较低的能见度,对道路上的物体有更多的不确定性。在这种情况下,不确定性将被归类为偶然的,因为数据中固有的随机性更大。
这两种情况应该区别对待。在赛道上,不确定性可能会告诉开发人员,他们需要收集特定类型的训练数据,以使模型更加鲁棒,或者不确定性可能会告诉汽车可以尝试安全地机动到一个位置,在那里它可以将控制权移交给司机。在雨天的情况下,这种不确定性可能会提醒系统简单地减速或启用某些安全功能。
估计 DNNs 中的不确定性
近年来出现了聚宝盆的提出的方法来估计 DNNS 中的不确定性。一般来说,不确定性估计是在贝叶斯统计的背景下制定的。在用于分类的标准 DNN 中,我们隐式地训练了一个判别模型,在该模型中,我们获得了神经网络权重的最大似然估计(取决于选择用于训练网络的损失函数)。这种对网络权重的点估计不利于理解模型知道什么和不知道什么。相反,如果我们找到权重的分布,而不是点估计,我们可以对网络权重进行采样,并以此计算相应的输出。
直观地说,这种网络权重的采样就像创建一个网络集合来完成任务:我们对一组“专家”进行采样来进行预测。如果专家意见不一致,认知的不确定性就会很高。如果专家认为做出准确的预测太困难,那么就有很高的偶然性不确定性。
在这篇文章中,我们将看看一个流行的和易于实施的方法来估计不确定性的 DNNs 由亚林加尔和邹斌 Ghahramani 。他们表明辍学可以用来学习 DNN 体重的近似分布(如前所述)。然后,在预测过程中,dropout 用于从拟合的近似分布中对权重进行采样,类似于创建专家集合。
认知不确定性是通过从样本权重中提取预测的样本方差来估计的。将样本方差与认知不确定性联系起来的直觉是,当模型预测几乎相同的输出时,样本方差将会很低,而当模型做出不一致的预测时,样本方差将会很高;这分别类似于当一组专家一致地做出预测时和当他们没有做出预测时。
同时,通过修改 DNN 以获得第二个输出,以及使用修改的损失函数来估计随机不确定性。随机不确定性将对应于输出的估计方差 。这个预测的方差与数据的内在数量有关,这就是为什么它与偶然的不确定性有关;这类似于一群专家判断形势太难做出预测。
总的来说,最终的网络结构如图 2 所示。有一个输入 x 被馈送到 DNN,在每一层之后都有丢失(每一层之后的丢失是最初指定的,但是在实践中,每一层之后的丢失常常使训练变得太困难)。该 DNN 的输出是估计的目标 ŷ 和估计的方差或比例参数 σ̂ 。

图 2:DNN 架构的例子,能够估计随机和认知的不确定性
这个 DNN 用一个损失函数来训练,比如:

或者

如果网络被训练用于回归任务。上面显示的第一个损失函数是具有不确定性的 MSE 变量,而第二个是 L1 变量。这些分别通过假设似然的高斯和拉普拉斯分布得出,其中每个分量都是独立的,方差(或标度参数)由网络估计和拟合。
如上所述,这些损失函数有数学推导,但我们可以直观地理解为什么这个方差参数捕捉一种类型的不确定性:方差参数提供了方差和 MSE 或 L1 损失项之间的权衡。如果 DNN 可以容易地估计目标的真实值(即,使接近真实值 y ),那么 DNN 应该在此基础上估计一个低方差项,以使损失最小化。然而,如果 DNN 不能估计目标的真实值(例如,信噪比低),那么网络可以通过估计高方差来最小化损失。这将减少 MSE 或 L1 损失项,因为该项将除以方差;然而,网络不应该总是这样做,因为对数方差项不利于高方差估计。
如果网络正在接受分类(或分段)任务的训练,损失将类似于这个两部分损失函数:
**
这种损失函数的直觉是:当 DNN 可以容易地估计组件的正确类别时,该类别的值将会很高,并且 DNN 应该估计低的方差,以便最小化添加的噪声(以便所有样本将集中在正确的类别周围)。然而,如果 DNN 不能容易地估计组件的类别,则 ŷ 值应该较低,并且添加噪声可能会增加对正确类别的猜测,这可能会总体上最小化损失函数。(参见第。Alex Kendall 的论文的第 41 章,以获得关于这个损失函数的更多讨论。)**
最后,在测试中,网络被采样 T 次以创建 T 估计目标和 T 估计方差输出。这些 T 输出然后以各种方式组合,以产生最终的估计目标和不确定性估计,如图 3 所示。

图 3 : DNN 输出到最终估计目标和不确定性估计
数学上,认知和偶然的不确定性是(对于 MSE 回归变量):
****
对于分类案例,认知不确定性有多种解释:熵,样本方差,互信息。每一种都被证明是有用的,选择哪种类型取决于应用。
示例和应用
为了使理论更加具体,我们将在 PyTorch 的回归和分类任务中通过两个玩具示例来评估 DNNs 的不确定性。下面的代码摘自 Jupyter 笔记本中提供的完整实现(在接下来的两个小节的开头会提到)。最后,我们将讨论在医学图像的真实世界数据示例中计算不确定性。
回归示例
在回归笔记本中,我们将一个非常简单的神经网络——由两个完全连接的层组成,在隐藏层上有漏失——拟合到具有不确定性损失的 MSE 变量的一维输入和输出数据(在下面实现)。
注意,我们不是直接拟合方差项,而是拟合方差项的对数以获得数值稳定性。
在回归场景中,我们也可以使用不确定性损失的 L1 变量,该变量在笔记本中并在下面实现。
有时使用 L1 损失而不是 MSE 损失会为回归任务带来更好的性能,尽管这取决于应用。
在这个场景中,随机的和认知的不确定性估计值是按照下面的实现来计算的(更多的上下文请看笔记本)。
在图 4 中,我们将拟合函数和不确定性结果可视化。在最右边的图中,我们展示了阈值认知不确定性,它展示了不确定性估计检测非分布数据的能力(至少在这个玩具场景中)。
****
图 4 :回归实例的各种不确定性。橙色的原始训练数据。左边的两个图用蓝色显示了神经网络拟合的函数,第一个图和第二个图中分别具有偶然性和认知不确定性。最右边的图显示了临界的认知不确定性。完整实现见 Jupyter 笔记本。
分类示例
在分类笔记本中,我们再次拟合了一个由两个完全连接的层组成的神经网络,在隐藏层上有脱落。在这种情况下,我们尝试进行二元分类。因此,损失函数实现如下。
在这种情况下,我们可以计算许多不确定性估计值。在下面的实现中,我们计算认知、熵和偶然的不确定性。熵可以被合理地认为是属于一个偶然的和认知的不确定性,但下面它被分离出来,所以偶然的和认知的不确定性计算如前所述。
在图 5 中,我们可视化了训练数据上产生的认知和偶然的不确定性,以及熵。正如我们可以看到的,训练数据类重叠接近零,不确定性度量在那里达到峰值。在这个玩具的例子中,所有三个不确定性的测量都是高度相关的。在笔记本中为感兴趣的读者提供了关于原因的讨论。

图 5 :二元分类示例的各种不确定性度量。参见 Jupyter 笔记本了解完整实现。
医学图像示例
在最后一个例子中,我将展示作为会议论文发表的真实世界例子中不确定性的一些结果和应用(此处预印)。探索的任务是一个图像到图像的翻译任务,类似于著名的 pix2pix 的例子,但是使用的是医学图像。在这种情况下,我们希望使大脑的计算机断层扫描(CT)图像看起来像大脑的相应磁共振(MR)图像。这是一个回归损失,我们使用不确定性损失的 MSE 变量来训练一个 U-Net ,它被修改为在每一层之后具有空间丢失(关于为什么空间丢失的讨论,请参见此处的),并且输出两幅图像而不是一幅图像;一个输出是估计的 MR 图像,另一个是像素方差。
图 6 示出了输入和输出的例子。最左边的 CT 图像在枕叶的左半球有一个异常(图像中大脑的左下方;它在右边相应的 MR 图像中更容易被可视化)。DNN 只在健康图像上训练,因此 DNN 应该不知道这种异常数据,并且它应该通过在该区域中具有高样本方差(即,高认知不确定性)来反映这一点-根据前面讨论的认知不确定性理论。

图 6 :从左到右——CT 图像输入网络,MR 图像为训练目标(此处显示是因为在左半球枕叶可见异常),像素认知不确定性、像素认知随机不确定性以及认知与随机的像素比显示在标题“Scibilic”下,该标题清楚地突出了异常区域。
当这个图像被输入到网络中时,我们计算了认知和偶然的不确定性。这种异常在认知不确定性中得到了明确的强调,但还有许多其他区域也被预测具有高度的认知不确定性。如果我们采用认知和偶然不确定性的像素比例,我们会得到最右边显示的图像,标记为“Scibilic”(在预印本中有更多讨论)。该图像很容易被阈值化以预测异常(图像的分布外区域)。
这种异常检测方法绝非万无一失。实际上,这是相当易变的,但是它展示了一种将这种类型的不确定性估计应用于真实世界数据的方法。
外卖食品
机器学习中的不确定性估计有可能降低在高风险场景中部署模型的风险。随机和认知的不确定性估计可以向用户或开发人员显示有关 DNN 性能的不同信息,并可用于修改系统以提高安全性。我们讨论并实现了一种不确定性估计的方法。这种方法并不完美,基于辍学的不确定性提供了一种获得某种(通常是合理的)不确定性度量的方法。该度量是否足够可信以用于部署是另一回事。实践者在实现这种方法时应该问自己的问题是,得到的具有不确定性估计的模型是否比没有不确定性估计的模型更有用——例如,更安全。
了解火花和卡夫卡:一亿个事件用例
电子商务市场中典型的一天,每分钟处理 10,000 个事件,并选择正确的工具来处理这些事件

Flaunter.com在 Unsplash 上拍照
本文将帮助您重新创建一个场景,其中有大量数据流入,您不仅要存储这些数据,还要执行一些实时分析!
这只是系统设计的一个例子,在这里你必须开发一个高度可用和可伸缩的数据管道。虽然对于像电子商务这样的用例,可能有许多其他因素需要考虑,但为了本文的目的,我们将把它分成 3 个主要部分:
- 摄取
- 处理
- 输出
简而言之,这是几乎所有系统设计的鸟瞰图,也是可能出错的地方。
摄入层
在开始使用我们的工具之前,让我们后退一步,看看我们在这里试图解决什么样的用例或问题。要了解我们的输入或摄取层,首先要了解我们的输出层。一般来说,你可以通过两种方式展示你的发现:
- 批处理:如果您的分析只是一次性的,或者可能只是每日报告更新,或者只是团队中的随机演示,您可以选择批量接收数据。这可能意味着从您的数据库中取出一个小的数据转储,并用它进行一些分析。
- 实时处理:也称为流数据是一种在新数据分析至关重要时可以采用的方法。最常见于 B2C 场景,在这种场景中,您可以即时执行操作。
批处理的好处是,它消除了构建实时管道的开销,并且您永远不会处理完整的数据集。不过,这并不适用于 B2C 环境,尤其是电子商务,在电子商务中,你必须推荐新产品、跟踪用户行程或设计实时仪表板。
既然我们知道我们的输出层将是实时的,我们将相应地选择我们的摄取工具。当然,有成千上万的工具可供你从中获取数据,但根据受欢迎程度、社区实力和各种用例的实现情况,我们将挑选 【卡夫卡】 和Spark Streaming。
这里再次强调,了解您的业务需求以决定执行相同工作的几个工具是很重要的。在像 e-comm 这样的场景中,我们已经知道我们想要实时输出,但是我们在这里谈论的数字是什么?
1-2 秒相当实时!是的,但对一个电子商务网站来说不是这样,在那里你的用户不会等待超过一秒来执行下一次点击。这让我们想到了延迟的概念。这是我们用来选择摄取工具的指标。这两个工具有很多不同之处,但是卡夫卡提供了毫秒级的延迟!
处理层
在我们的用例中,我们将分别检查 Spark 和 Kafka 的处理机制。我们将看到 spark 如何使底层硬件实际上不应该保存的数据处理成为可能。另一方面,我们将看到使用 Kafka 消费数据是多么容易,以及它如何在数百万的规模上实现这一点。
我将使用下面来自 Kaggle 的数据集,它有超过 1 亿行
https://www . ka ggle . com/mkechinov/ecommerce-behavior-data-from-multi-category-store
除非您拥有一台非常高端的机器,否则不可能将整个数据集加载到您本地机器的内存中,甚至不可能将它拆分成批处理,当然除非您对每个传入的批处理执行处理,但这就是为什么我们使用类似于 Spark 的东西。
基础设施
设置 spark 有其复杂性,因此,为了加快速度,我们将在 数据块 ,上启动 Spark 集群,让您可以在数据驻留的 AWS S3 的数据支持下快速启动集群。
Spark 遵循典型的主从架构,概括来说,这意味着主服务器负责所有的作业调度工作以及其他一些事情,另一方面,从服务器负责执行实际操作或将数据保存在内存中。

Spark 架构,1 个主节点+ 2 个工作/从节点
当我们在数据上实现 Spark 时,我们将对其进行更详细的介绍。目前,我已经在 databricks 上构建了一个 1 工作节点+ 1 个主节点集群,总共有 2 个内核和 8 GB 内存,尽管完整的配置应该是 4 个内核和 16 GB 内存。
它是 2 和 8,因为我们所有的 spark 操作都只发生在 worker 节点上,而我们只有 1 个 worker 节点。内核的数量(即 2 个)将在这里发挥关键作用,因为所有并行化工作都将在这里进行。
读取 8 GB 内存上的 14 GB 数据
在比内存本身更大的内存中存储数据是不切实际的,因此,spark 所做的是,只有当你想对数据进行一些操作时,它才会将数据加载到内存中。例如,以下代码行将并行读取我们的数据集,即利用 2 个内核读取我们的数据。
ecomm_df = sparkSession.read.csv("/mnt/%s/ecomm.csv" % MOUNT_NAME, header=True
我们的 14 GB 文件将被分成大约 112 个小块,由于我们有 2 个内核,因此将被分成 2 个块,每次 128 MB
虽然,spark 不会在你提交这个命令的时候开始读取文件,因为有一个完全不同的概念懒惰求值,这使得它不会以传统的 pythonic 方式读取它!但是我们仍然可以通过快速转换成 RDD 来检查这个文件的分区/块的数量
ecomm_df.rdd.getNumPartitions()
OUTPUT: **110 #Number of partitions**
这与我们的计算非常接近。看看这个知道我是如何从 14 GB 的文件大小计算出 112 个分区的。
现在,不要太专业,让我们快速浏览一下我们的数据
**# A SAMPLE RECORD OF OUR DATA**Row(event_time='2019-11-01 00:00:00 UTC', event_type='view', product_id='1003461', category_id='2053013555631882655', category_code='electronics.smartphone', brand='xiaomi', price='489.07', user_id='520088904', user_session='4d3b30da-a5e4-49df-b1a8-ba5943f1dd33')

过滤掉只购买了 Xiamoi 智能手机的人,然后执行左连接。查看如何将每个命令分解为 110 个任务,并且 2 个任务总是并行运行

按品牌分析有多少百分比的用户只是查看和添加到购物车,以及购买特定商品
现在您已经了解了 spark 的功能,它是一种非常可扩展的方法,可以在有限的资源集上训练/分析几乎任何规模的数据
模拟实时数据摄取
我们之前已经讨论了很多关于 Kafka 的要点,所以不需要太深入,让我们看看我们在真实场景中摄取这种数据的 Kafka 管道是什么样子的!
当我们谈论任何给定时间的 1 亿个事件这样的数字时,可伸缩性成为优先考虑的问题,对分区和消费者群体的理解也是如此。在这种摄入水平下,这两种成分可以成就或破坏我们的系统。看看这个架构,对 Kafka 系统有个大概的了解

这个模型的真实世界复制品将是你的邮箱。
- 邮递员:这个人是制作人,他的工作只是收集数据,然后把它放进你的邮箱
- 邮箱/信箱:这是你的经纪人,如果没人来收,信件会一直堆积。
- 你的地址:这是你的题目,邮递员怎么知道要把这些数据发到哪里?
- 你:你是消费者,收集这些数据并进一步处理是你的责任
这是 Kafka 数据流机制的一个非常简单的解释,足以进一步理解本文,而分区和消费者组的概念也将帮助您理解代码片段

主题是保存您的数据的内容,可以划分为 n 个分区供并行使用
在这种规模下,您希望并行化数据消费。为此,可以将传入的数据分成不同的分区,当这种情况发生时,我们可以建立消费者组,这意味着多个消费者希望从同一个源读取数据。
参考上面的体系结构,两个使用者从同一个源读取数据,因此,同时读取更多的数据,但读取的数据不同。如果消费者 1 已经读取了行 1 和行 2,消费者 2 将永远看不到这些数据,因为这种隔离已经在分区级别发生了!
这是我在使用分区和消费者组大规模接收这种数据时做的一个小实现
**# 4 Partitions Made
# Topic Name : ecomm_test**./kafka_2.11-2.3.1/bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 4 --topic ecomm_test**# Send data to ecomm_test topic**
producer.send(topic='ecomm_test', value=line)**# Start 2 consumers and assign it to the group "ecommGroup"** consumer = KafkaConsumer('ecomm_test', group_id='ecommGroup')
consumer = KafkaConsumer('ecomm_test', group_id='ecommGroup')**# Output of how consumer 1 reads data, only reading from 2 partitions i.e. 0 & 1**ConsumerRecord(topic=u'ecomm_test', partition=1, value='2019-11-01 00:00:01 UTC,view,17302664,2053013553853497655,,creed,28.31,561587266,755422e7-9040-477b-9bd2-6a6e8fd97387\n')ConsumerRecord(topic=u'ecomm_test', partition=0, value='2019-11-01 00:00:01 UTC,view,3601530,2053013563810775923,appliances.kitchen.washer,lg,712.87,518085591,3bfb58cd-7892-48cc-8020-2f17e6de6e7f\n')**# Output of how consumer 2 reads data, only reading from 2 partitions i.e. 2 & 3**ConsumerRecord(topic=u'ecomm_test', partition=3, value='2019-11-01 00:00:05 UTC,view,4600658,2053013563944993659,appliances.kitchen.dishwasher,samsung,411.83,526595547,aab33a9a-29c3-4d50-84c1-8a2bc9256104\n')ConsumerRecord(topic=u'ecomm_test', partition=2, value='2019-11-01 00:00:01 UTC,view,1306421,2053013558920217191,computers.notebook,hp,514.56,514028527,df8184cc-3694-4549-8c8c-6b5171877376\n')
一吻制作架构:输出
我们只需要确保我们与以下概念保持一致:
- 吻:保持简单愚蠢:尽可能保持架构简单
- 微服务:分离组件以避免一连串的故障
- CAP 定理:一致性,可用性,划分容差。选择两个对你来说最重要的
最后,我们将介绍可以在生产系统中实施的最终体系结构,尽管还涉及许多其他组件,如可用性区域、存储系统、故障切换计划,但这只是生产中最终处理层的概述

包含数据流的完整架构图
正如你所看到的,图表是不言自明的,没有一个正确的架构/系统设计适合所有的用例,你只需要在给定的资源下构建可以工作的东西。
欢迎联系或在此发布您的问题/反馈
干杯!
了解这 5 个 HCI 原则会让你的数据可视化看起来很神奇
入门,设计心理学。
人机交互(HCI)研究中使用的原则

图片来自视觉肉桂。
一年前,我有机会在大学里阅读人机交互(HCI)。在那里,我开始了解这个领域中的各种人类心理原则。从数据可视化的角度探索多个这样的原则让我非常兴奋。数据可视化是计算机系统上的数据和人类大脑之间的高带宽连接,通过理解不同的心理学原理如何影响人类行为,由视觉通信来促进;我们可以设计我们的产品(即,图形,用户界面/UX,等等)。)从我们的用户那里引出具体的反应和行动。我们可以通过更具同理心和以用户为中心来产生重大影响。
在这里,我将分享五种不同的人机交互原则如何帮助我们创建有影响力的可视化。
- 米勒定律 -别说了
- 雅各布定律——用户喜欢知名的东西
- 冯·雷斯托夫效应——还记得那个独特的
- F 模式 -设计用于扫描,而非读取
- 希克斯定律 -更多信息;要花更长时间才能抓到一个
米勒定律
如果你想理解某事,你首先要想象你所听到或读到的是真的,并从那里开始。—乔治·米勒
乔治·米勒提出的米勒定律告诉我们,我们只能在工作记忆中保留大约七项内容。除此之外的任何事情都很难回忆起来。多于七个元素会使用户产生困惑和注意力分散,用户不再记得他/她现在正在寻找的信息。
创建一个包含超过七个不同的客观元素的仪表板是不好的。相反,如果我们有十个图表要合并到一个仪表板中,我们可以将它们分块并制作两个仪表板。简单来说,我们可以说米勒定律试图说明我们应该减少信息过载(认知负荷)和可视化的复杂性。


图片由作者提供。J 的数据存在于 Kaggle 的 Mostipak。
你觉得哪一个容易读和记,A 还是 B?
我确定葡萄牙 763,199 比葡萄牙 763199 更容易记住,所以在 B 中,我们用了米勒定律。实现米勒定律的一个直接方法是分块,因为分块形式似乎更容易扫描,完成起来也不那么令人生畏。

由作者设计。来自未画的插图。
雅各布定律
为用户习惯的模式设计。——雅各布·尼尔森
世界上最有影响力的设计师之一雅各布·尼尔森(Jakob Nielsen)提出了雅各布定律。它指出用户喜欢熟悉的体验。他们倾向于喜欢与他们已经探索过的相似的可视化/图表。他们已经知道这些图表代表什么/如何,因为他们不需要太多的努力就能理解。所以我们可以说熟悉是安全的,用户喜欢知名的东西。

图片由作者提供。
请记住这张图表和它想要表达的意思。
这是否意味着我们应该复制一个流行的可视化?不完全是。相反,我们应该通过进行深度分析,并关注专家如何为类似的需求进行设计,来研究我们为之设计的社区中如此伟大的设计。
我们的目标是在我们设计的行业中找出著名的风格。以已知的方式倾斜将帮助我们建立正确的用户期望,创造熟悉的体验。

图片由作者提供。
我希望你还记得我向你要的图表。现在,你发现图表和它的目标有什么不同吗?
我敢打赌,你有。是的,因为我们已经看到了学生人数的条形图,我们的大脑已经捕捉到了它,每当我们看到标题学生人数时,我们立即用它倾斜条形图,但在这里我把条形图放在学生表现上,这样就给用户创造了很少的时间来考虑用新信息进行调整。利用这个规律,我们可以追求用户在享受可视化的同时不要多想。
冯·雷斯托夫效应
如果你想让人们记住某件事,那就让它突出来。——海德薇·冯·雷斯托夫
八七年前,德国精神病学家海德薇格·冯·雷斯托夫进行了一项记忆实验。她给了人们一份相似但不同的物品清单。清单上的一个项目是一种不同于其他事物的独特颜色。当海德薇格要求她的研究参与者记住这个清单时,她发现颜色独特的物品的回忆率明显高于其他物品。因此,Von Restorff 效应或隔离效应或特定编码表明,当我们看到一组相似的物体时,我们通常会记住与其他物体最不同的那个。

图片由作者提供。欧盟统计局的数据。
在这里,我们强调了相关的(基本方面)国家,荷兰,只有这样才能吸引用户的注意力。当我们试图帮助用户记忆时,这个原则非常重要。大多数情况下,尺寸、颜色和形状都是用来应用这一原则的。
f 型
在注意力经济中,任何试图与观众建立联系的人都必须将用户的时间视为终极资源。——雅各布·尼尔森
Jakob Nielsen ( 想起了这个名字!?),全球最具影响力的设计师之一,发现了 F-Pattern,这是设计界被引用最多、最有用的眼球追踪资源。F 模式代表观察者通常关注的地点/可视化,跟随字母 F(“F”表示快)。这份报告表明:
- F 上的两个横条是最重要的信息。
- 竖线表示读者倾向于阅读页面的左侧,并且只阅读前几个单词。
- 人们不在网上阅读。他们扫描。

NNGroup 展示了眼球追踪研究如何揭示用户(在从左向右阅读的文化中)通常以看起来像字母 f 的模式扫描大量内容。用户看得最多的区域是红色的;黄色区域表示视图较少,其次是蓝色区域。
我们的可视化应该为扫描而设计,而不是阅读,所以最好的内容应该锚定在左上角优先。这个位置肯定会引起注意,因为使用它会使阅读体验更有吸引力。然而,我们也应该以这样一种方式思考,如果有人在浏览我们的 viz 时发现它有吸引力,他们会阅读,这样我们也可以将信息放在 F 之外的地方。


在可视化中创建 F 模式。图片由作者提供。数据由宏观趋势提供。
这里我们看到在 A 上,居中的内容在设计中产生了一点空隙;因此,它消耗了用户的探索时间;然而,在 B 上,我们将文本放在左边,这样用户就可以立即开始吸收内容(我们中的一些人可能不同意这一点,但我这样做只是为了便于理解。)这样就有了 f 的模式。

由作者设计。来自展开图的插图。事实来源于 NNgroup 。
确保坚持 F 模式将确保我们的可视化给我们的观众留下有意义的印象。如果你想更多地了解这种模式,这里有一些值得一查的:古腾堡图、分层饼模式、斑点模式和承诺模式等。,
希克定律
减少刺激次数,获得更快的决策过程。—威廉·埃德蒙·希克
由英国和美国心理学家威廉·埃德蒙·希克和雷·海曼团队提出的希克定律或希克-海曼定律或信息增益率告诉我们,一个人做出决定所需的时间是他或她可能做出的选择的结果:增加选项的数量将对数地增加决策时间。
通俗地说:可供选择的东西越多,我们选择的时间就越长。你觉得这类似于 K.I.S.S(保持简洁)的设计方法吗?
是的,K.I.S.S .呼应了乡巴佬定律。K.I.S.S .(保持简单愚蠢或保持简短简单)源自希克定律,导致其设计和开发简单。希克斯定律的目标是试图简化决策过程,而不是消除这一过程。我们可以说,这完全是关于我们如何安排我们的信息体系结构。
所以在可视化中,提供大量的信息会产生更多的选择(信息),用户会花更长的时间来选择一个。(请记住,我们不会以隔离的方式使用希克斯定律。我们总是把它和其他 HCI 的原则结合起来。)
我们视觉中的信息过载直接影响了希克定律的原理,因为我们“可能”从试图决定下一步要抓什么开始。不过,很快我们就要,呃…

图片由作者提供。
在 A 上,我们有许多选项可供选择,我们的用户将花一些时间来决定选择哪一个。关于 B,我们有三个选择,所以没有那么多需要决策时间。因此,在 B 中,我们使用了希克定律。缩短长长的列表,减少可能的选项数量,是实现希克定律的一种简单方法。在长列表不可避免的情况下,我们应该限制用户一次可以查看的选项数量,以使浏览更加舒适和快速。
因此,如果你做到了这一步,我们可以看到,以一种有效的方式正确使用上述原则将使我们的可视化达到一个新的水平。利用这些原则,我们将以尽可能好的方式呈现数据,以满足受众的需求。下一次当你开始设计的时候,想想在哪里以及如何应用这些原则。
最后引用梅顿·戈拉瑟的话:
对一件设计有三种反应——是,不是,哇!哇是一个目标。
如果你对这篇文章有任何疑问,或者想在你的下一个数据可视化项目中合作,请在 LinkedIn 上 ping 我。
本文由 vizartpandey.com自愿投稿至博客。
推荐读物
知道了这些,你就可以覆盖 Python 中 99%的文件操作
提高您处理文件的效率

Maksym Kaharlytskyi 在 Unsplash 上拍摄的照片
处理文件是我们每天最常见的任务之一。Python 有几个内置模块,用于执行文件操作,比如读取文件、移动文件、获取文件属性等。本文总结了许多您需要了解的函数,以涵盖 Python 中最常见的文件操作和良好实践。
这是您将在本文中看到的模块/函数的图表。要了解每个操作的更多信息,请继续阅读。

作者:高
打开和关闭文件
当你想读或写一个文件时,首先要做的是打开文件。Python 有一个内置函数open,它打开文件并返回一个 file 对象。文件对象的类型取决于打开文件的模式。它可以是文本文件对象、原始二进制文件和缓冲二进制文件。每个文件对象都有像read()和write()这样的方法。
这个代码块有问题,能认出来吗?我们以后再讨论。
file = open("test_file.txt","w+")
file.read()
file.write("a new line")
Python 文档列出了所有可能的文件模式。下表列出了最常见的模式。一个重要的规则是,任何 **w** 相关的模式都会先截断文件(如果存在的话),然后创建一个新文件。如果你不想覆盖文件,小心使用这种模式,如果可能的话,使用a追加模式。
前面代码块中的问题是我们只打开了文件,而没有关闭它。处理文件时,务必关闭文件。拥有一个打开的文件对象会导致不可预知的行为,比如资源泄漏。有两种方法可以确保文件被正确关闭。
- 使用
第一种方式是显式使用close()。一个好的做法是将它放在finally中,这样我们可以确保文件在任何情况下都会被关闭。它使代码更加清晰,但另一方面,开发人员应该负起责任,不要忘记关闭它。
try:
file = open("test_file.txt","w+")
file.write("a new line")
exception Exception as e:
logging.exception(e)
finally:
file.close()
2。使用上下文管理器 **with open(...) as f**
第二种方法是使用上下文管理器。如果你不熟悉上下文管理器,那么看看 Dan Bader 的上下文管理器和 Python 中的“with”语句。with open() as f语句实现了__enter__和__exit__方法来打开和关闭文件。此外,它在上下文管理器中封装了 try/finally 语句,这意味着我们永远不会忘记关闭文件。
with open("test_file","w+") as file:
file.write("a new line")
这个上下文管理器解决方案总是比close()好吗?看你用在什么地方了。以下示例实现了将 50,000 条记录写入文件的 3 种不同方式。正如您从输出中看到的,use_context_manager_2()函数与其他函数相比性能极低。这是因为with语句是在一个单独的函数中,它基本上为每条记录打开和关闭文件。如此昂贵的 I/O 操作会极大地影响性能。
比较with语句和 close()方法
读取和写入文件
打开文件后,您必须想读取或写入该文件。file 对象提供了 3 个方法来读取一个文件,分别是read()、readline()和readlines()。
默认情况下,read(size=-1)返回文件的全部内容。如果文件大于内存,可选参数size可以帮助您限制返回字符(文本模式)或字节(二进制模式)的大小。
readline(size=-1)返回一整行,末尾包含字符\n。如果size大于 0,将返回该行的最大size字符数。
readlines(hint=-1)返回列表中文件的所有行。可选参数hint表示如果返回的字符数超过hint,将不再返回更多的行。
在这 3 种方法中,read()和readlines()的内存效率较低,因为默认情况下,它们以字符串或列表的形式返回完整的文件。一种更节省内存的方法是使用readline(),让它停止读取,直到返回一个空字符串。空字符串""意味着指针到达了文件的末尾。
以节省内存的方式读取文件
就写作而言,有两种方法write()和writelines()。顾名思义,write()是写字符串,writelines()是写字符串列表。开发人员负责在末尾加上 **\n** 。
将行写入文件
如果您将文本写入特殊的文件类型,如 JSON 或 csv,那么您应该在 file 对象之上使用 Python 内置模块json或csv。
在文件内移动指针
当我们打开一个文件时,我们得到一个指向某个位置的文件处理程序。在r和w模式下,处理程序指向文件的开头。在a模式下,处理程序指向文件的结尾。
***tell()******seek()***
当我们从文件中读取时,指针移动到下一次读取将开始的地方,除非我们告诉指针四处移动。您可以使用两种方法完成此操作:tell()和seek()。
tell()从文件开始以字节/字符数的形式返回指针的当前位置。seek(offset,whence=0)将处理器移动到距离whence有offset个字符的位置。whence可以是:
- 0:从文件的开头开始
- 1:从当前位置
- 2:从文件末尾开始
在文本模式下,whence只能为 0,offset应≥0。
讲述()和寻找()
了解文件状态
操作系统上的文件系统可以告诉你许多关于文件的实用信息。例如,文件的大小、创建和修改时间。要在 Python 中获得这些信息,可以使用os或pathlib模块。其实os和pathlib.之间有很多共同点pathlib是一个比os更面向对象的模块。
os
获得完整状态的一种方法是使用os.stat("test.txt")。它返回一个结果对象,带有许多统计信息,如st_size(文件的大小,以字节为单位)st_atime(最近一次访问的时间戳)st_mtime(最近一次修改的时间戳)等。
*print(os.stat("text.txt"))>>> os.stat_result(st_mode=33188, st_ino=8618932538, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=16, st_atime=1597527409, st_mtime=1597527409, st_ctime=1597527409)*
您也可以使用os.path单独获取统计数据。
*os.path.getatime()
os.path.getctime()
os.path.getmtime()
os.path.getsize()*
Pathlib
获得完整状态的另一种方法是使用pathlib.Path("text.txt").stat()。它返回与os.stat()相同的对象。
*print(pathlib.Path("text.txt").stat())>>> os.stat_result(st_mode=33188, st_ino=8618932538, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=16, st_atime=1597528703, st_mtime=1597528703, st_ctime=1597528703)*
我们将在以下章节中比较os和pathlib的更多方面。
复制、移动和删除文件
Python 有许多处理文件移动的内置模块。在你相信 Google 返回的第一个答案之前,你要意识到模块的不同选择会导致不同的表现。有些模块会阻塞线程,直到文件移动完成,而其他模块可能会异步执行。
shutil是最著名的移动、复制和删除文件和文件夹的模块。它提供了 4 种方法来复制一个文件。copy()、copy2()和copyfile()。
**copy()** v.s. **copy2()** : copy2()和copy()很像。不同的是,copy2()还会复制文件的元数据,比如最近的访问时间、最近的修改时间。但是根据的 Python 文档,由于操作系统的限制,即使copy2()也无法复制所有的元数据。
副本()与副本 2()
**copy()** v.s. **copyfile()** : copy()设置新文件的权限与原文件相同,但copyfile()不复制其权限模式。其次,copy()的目的地可以是一个目录。如果存在同名文件,它将被覆盖,否则,将创建一个新文件。但是,copyfile()的目的地必须是目标文件名。
copy() v.s. copyfile()
os
os模块有一个功能system(),允许你在子外壳中执行命令。您需要将命令作为参数传递给system()。这与在操作系统上执行的命令具有相同的效果。对于移动和删除文件,您也可以使用os模块中的专用功能。
操作系统移动 _ 复制
异步复制/移动文件
到目前为止,解决方案总是同步的,这意味着如果文件很大并且需要更多时间移动,程序可能会被阻塞。如果想让程序异步,可以使用threading、multiprocessing或者subprocess模块,让文件操作在单独的线程或者单独的进程中运行。
异步方式的文件操作
搜索文件
复制和移动文件后,您可能希望搜索与特定模式匹配的文件名。Python 提供了许多内置函数供您选择。
全球
[glob](https://docs.python.org/3.8/library/glob.html#module-glob)模块根据 Unix shell 使用的规则找到所有匹配指定模式的路径名。它支持通配符,如*?[].
glob.glob("*.csv")在当前目录中搜索所有扩展名为csv的文件。glob模块也可以搜索子目录中的文件。
搜索文件名—全局
os
os模块功能强大,基本上可以做一切与文件有关的操作。我们可以简单地使用os.listdir()列出目录中的所有文件,并使用file.endswith()和file.startswith()来检测模式。如果你想遍历目录,那么使用os.walk()。
搜索文件名—操作系统
pathlib
pathlib具有与glob模块相似的功能。也可以递归搜索文件名。与之前基于os的解决方案相比,pathlib拥有更少的代码,提供了更面向对象的解决方案。
搜索文件名—路径库
摆弄文件路径
使用文件路径是我们做的另一项常见任务。它可以得到一个文件的相对路径和绝对路径。它也可以是连接多个路径和寻找父目录等。
相对和绝对路径
os和pathlib都提供了获取文件或目录的相对路径和绝对路径的函数。
文件的相对和绝对路径
加入路径
这就是我们如何独立于环境连接os和pathlib中的路径。pathlib使用斜杠创建子路径。
连接文件路径
获取父目录
dirname()是在os中获取父目录的功能,而在pathlib中,你只需使用Path().parent就可以获取父文件夹。
获取父文件夹
os 对 s. pathlib
最后,我想简单说一下os和pathlib。正如 Python 文档所说,pathlib比os更面向对象。它将每个文件路径表示为适当的对象,而不是字符串。这给开发者带来了很多好处,比如更容易连接多个路径,在不同的操作系统上更加一致,方法可以直接从对象中访问。
我希望这篇文章能提高你处理文件的效率。
参考:
** [## 用 Python 读写文件(指南)-真正的 Python
在本教程中,您将学习如何在 Python 中读写文件。您将涵盖从文件是什么…
realpython.com](https://realpython.com/read-write-files-python/#buffered-binary-file-types) [## 为什么应该使用 pathlib
几年前当我发现 Python 的新 pathlib 模块时,我最初认为它是一个稍微更…
treyhunner.com](https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/#:~:text=The os module is a,nested string-iful function calls.)**
知道什么和为什么?—解释图像分类器预测
数据科学工具包

测试库提供的解释的比较
介绍
事实上,每年机器学习(ML)都在成为我们生活中越来越重要的一部分。ML 帮助我们完成简单的日常任务,比如找到回家的最佳路线,用手机准确扫描文件或将文本翻译成不同的语言。然而,它也被用作许多高度负责的系统中的一个关键要素,在这些系统中,人的生命和福祉受到威胁。
- 人工智能(AI)被用于司法系统,以评估被定罪的人再次违法的可能性有多大。
- 一些公司正在研发能够帮助甚至完全免除医生在医学图像上定位肿瘤的系统
随着我们实施类似于上面提到的那些系统,越来越清楚的是我们不仅要提供预测,还要提供解释什么影响了我们的决策。在这篇文章中,我将比较和测试最常用的库,用于解释图像分类 — Eli5、LIME 和 SHAP 领域的模型预测。我们将调查他们利用的算法,以及比较所提供的解释的效率和质量。
注意:因为我不想让你厌烦滚动巨大的代码片段,所以我只在文章中放了一小部分。然而,如果你想创建类似的可视化,或者学习如何解释你的分类器的预测,我鼓励你访问我的 GitHub 。
权衡取舍
在我们开始之前,让我们先回答一个最基本但同时也是最重要的问题。为什么我们甚至需要解释?难道我们不能解释模型的预测来了解是什么影响了它们吗?不幸的是,在很多情况下,答案是否定的

模型的潜在准确性和可解释性之间的权衡
我们可以说在模型的复杂性和它的可解释性之间有一个权衡。由于一些问题——尤其是在计算机视觉领域——非常复杂,我们必须使用强大而复杂的模型来解决它们。这些类型的模型通常被称为黑盒,因为我们不知道或不理解它们内部发生了什么。因此,我们经常为了模型的准确性而牺牲可解释性。
图像分类
正如我在第一段提到的,在这个项目中,我们将处理图像分类模型。这是最古老和最受认可的计算机视觉(CV)任务之一,它涉及到给照片分配一个带有对象类别名称的标签。尽管看起来很简单,但这是一项多年来给研究人员带来巨大问题的任务。突破性的想法是 AlexNet —卷积神经网络(CNN),在 2012 年的 ImageNet 比赛中首次使用。AlexNet 以大约低 10 个百分点的误差击败了其他参与者。这个解决方案彻底改变了计算机视觉。从那时起,CNN 就成了这个研究分支中所有任务的默认答案。不幸的是,CNN 是黑盒的一个例子——尽管我们知道黑盒内部发生的变化,但即使对于该领域的专家来说,对它们的全面解释也是一个问题。
注:如果你想更深入地探索 CNN,我强烈建议你阅读我的另一篇文章——深入了解卷积神经网络背后的数学。
ELI5
我们将研究的第一个库是Eli 5——这是一个简单但可靠的工具,旨在可视化、检查和调试 ML 模型。该库允许解释用 Keras 编写的图像分类器的预测。为此,Eli5 利用了梯度加权类激活映射(Grad-CAM)算法。值得注意的是,这不是一个通用的方法,它仅适用于 CNN 解决方案。
Grad-CAM
Grad-CAM 是 CAM 的下一个迭代,这是将 CNN 的预测可视化的最初想法之一。它使用激活图的值以及反向传播来理解预测的来源。

ResNet34 激活在六个不同网络深度的可视化。随着层深度的增加,激活分辨率降低。
过滤图(或激活图)是将一个卷积核应用于层输入的结果。根据过滤器中的值,它们对不同的模式做出反应。重要的是,位于 CNN 不同深度的卷积层对它们所观察的物体的不同细节水平做出反应。浅层次对简单的形状有反应——不同角度的线条,相同亮度的表面。另一方面,深层的 CNN 会随着特定的复杂模式的出现而发光。此外,在大多数情况下,深层 CNN 层中的激活图的分辨率比图形开始处的低。
Grad-CAM 解释是通过执行前向激活图的线性加权组合,然后执行 ReLU 来获得的。相对于特征图激活,通过对给定类别(在 Softmax 之前)获得的分数梯度进行平均来计算线性方程的系数。


例子
允许使用 Eli5 解释任何基于 Keras 的 CNN 预测的代码片段— 完整示例

使用 Eli5 为 ResNet34 型号获得的解释
摘要
- [+]Eli 5 背后的思想很简单,计算量也很小,因此,该算法既容易理解,又能很快执行。
- [―] 该方法仅用于解释 CNN 预测。
- [―] 目前库**只支持基于 Keras 的模型。**
- [―] 该方法的精度有限——取决于激活图分辨率。

显示 CNN 激活的分辨率如何影响解释的精确度的可视化
石灰
我为什么要相信你?:解释任何分类器的预测是一篇文章,是旨在解释 ML 模型的整个研究分支的基础。本文中包含的思想成为了最流行的解释库——本地可解释模型不可知解释(LIME)的基础。这种算法与 Grad-CAM 完全不同,它试图通过扰动输入数据来理解模型,并理解这些变化如何影响预测。
代理模型
这一次,我们的目标是用简单、可理解的线性模型取代复杂的黑盒模型。当然,新模型只是原模型的近似,但经过选择,它忠实地代表了当地的情况。这个方向的第一步是将图像分成超像素——颜色和亮度相似的相邻像素组。这种方法是有意义的,因为照片的分类可能是由许多像素决定的,所以单个像素的扰动对预测的影响很小。然后,我们创建一个人工照片集合,通过用灰色替换原始照片的随机超像素来创建。

石灰算法
我们还定义了一个函数,它将允许我们确定原始图像和样本之间的相似程度,其中 D 是图像之间的余弦距离,而【σ是图像的宽度。为了计算这个度量,我们将数码照片展平,并将其视为一个矢量。然后,我们计算代表被比较的两幅图像的向量之间的角度的余弦。

现在你需要做的就是找到原始模型对输入图像 f(x) 的预测,以及线性模型对扰动图像g(z’)的预测,并求解由 L 定义的加权回归。

稳健性
我们当然期望从梦的解释库中得到的一个关键特征是健壮性。我们想要两张几乎相同的图像来给出非常接近的解释。然而,事实证明石灰在这方面高度不稳定。**
为了验证这一点,我进行了一个实验——我解释了图像分类器对两幅几乎相同的图像的预测。第二张图片是通过在原始图片中添加少量高斯噪声创建的——如此之小,以至于从模型中获得的概率几乎不会改变,图像对于肉眼来说是无法区分的。然而,解释上的差异却是显著的。
例子
允许使用 LIME 解释任何图像分类器预测的代码片段— 完整示例

使用 ResNet34 型号的石灰获得的解释
摘要
- [+]模型不可知方法 —完全独立于 ML 模型的类或架构。
- [+] 库有现成的实现,可以让你解释任何图像分类器的预测。
- [―]耗时的计算,取决于所选的超参数,对于单个图像可能会持续几分钟。
- [―]稳定性问题——即使是图像的微小变化,也会导致截然不同的解释
SHAP
Hapley 加法解释(SHAP)和 LIME 非常相似——两者都是解释个体预测的加法和模型不可知的方法。然而,SHAP 的目的是通过计算每个特征对预测的贡献来解释给定输入的模型预测。为了实现这个目标,SHAP 使用了沙普利值,它最初来自博弈论。
沙普利值
首先,为了更好地理解所分析的算法,我们来解释一下什么是 Shapley 值。这是 Shapley (1953)描述的一种方法,根据游戏玩家对总收益的贡献来分配奖励。这个想法已经被转移到 SHAP,作为评估哪个特征对模型的最终预测贡献最大的一种方式。它被描述为一个特征值在所有可能的联合中的平均边际贡献。联盟向量z’为每个特征分配值 0 或 1,定义它是否出现在联盟中。使用函数 h 将这些向量映射到特征空间——对于图像,该函数填充灰色超像素,对应的向量值为 0。
KernelSHAP 这是一个想法的组合,从 LIME 开始就知道了,但是使用了 Shapley 值。类似地,与石灰一样,我们使用超像素来限制特征的数量,将相似颜色和亮度的像素组合起来。我们还使用加权回归来建立线性模型,其中每个超像素代表我们模型的单个特征。
关键区别在于回归模型权重的选择。对于 LIME,它是原始图像和扰动图像之间的余弦度量,而对于 KernelSHAP,使用以下公式来确定权重,其中 M 是最大联合,| z’|是所考虑的联合中的特征数量。

例子
允许使用 SHAP 解释任何图像分类器预测的代码片段— 完整示例

从 ResNet34 型号的 SHAP 获得的解释
摘要
- [+]源于博弈论的坚实数学基础,使其具有很强的可解释性。
- [+]模型不可知方法
- [―]极其缓慢,因为它需要计算许多沙普利值
- [―] KernelSHAP 是一个通用算法,如果我们想用它来解释 CV 模型的预测,我们需要定义我们的函数 h 将联盟映射到图像特征。
基准
我们将使用执行模型解释所必需的墙时间,作为我们库性能的度量。为了避免与预测解释无关的因素的影响,我们将依赖于 100 个单独案例的平均时间。获得的值如下所示。测试是在没有 GPU 的计算机上进行的,该计算机配备了英特尔酷睿 i7–7700 HQ CPU 处理器(2.80GHz)

测试图书馆的平均讲解时间
结论
如果你设法来到这里,祝贺你。非常感谢你花时间阅读这篇文章。如果你喜欢这篇文章,考虑把它分享给你的朋友,或者两个或五个朋友。我希望这篇文章是有帮助的,现在你知道如何解释你的图像分类器的预测。
本文是“数据科学工具包”系列的另一部分,如果您还没有机会,请阅读其他文章。此外,如果你喜欢我目前的工作,请在 Twitter 和 Medium 上关注我,并在 GitHub 和 Kaggle 上查看我正在进行的其他项目。保持好奇!
知道何时停止
你应该在什么时候停止追逐百分点,给你的模型贴上“完成”的标签?

约翰·马特丘克在 Unsplash 上拍摄的照片
在预测分析中,知道何时停止可能是一件棘手的事情。
不像生活中的许多活动,没有明确的终点线,之后你可以说“滴答,我完成了”。多做一点工作就能改进你的模型的可能性总是存在的。有如此多的变量需要调整,很容易最终沉迷于 0.1 个百分点,在抬起头来想“时间都去哪里了”之前,在细节上倾注了巨大的努力。
通过特征工程、模型选择和超参数调整迭代您的模型是任何数据科学家的关键技能。但是知道何时停止是很少解决的事情,并且可以极大地改变模型开发的成本和数据科学项目的 ROI。
我不是在这里谈论过度与欠适应。过度拟合是指模型与训练数据过于接近,可以通过将训练集错误与验证集错误进行比较来检测。在 Medium 和其他地方有许多 伟大的 教程更详细地解释了这一切。
我指的是你在整个建模过程中花费的时间,以及你如何量化回报和证明成本的合理性。
战略
一些可以帮助你决定何时结束的策略可能是:
- 设定最后期限— 帕金森定律指出“工作扩大是为了填满完成它的时间”。拥有一个开放式的时间框架会让你拖延时间,把时间花在那些最终不会给最终结果带来多少价值的事情上。给自己设定一个截止日期是一个保持低成本和可预测的好方法,它迫使你有效地进行优先排序。当然,不利的一面是,如果您过于激进地设定截止日期,您可能会交付一个质量很差的模型。
- 可接受的错误率— 你可以事先决定一个可接受的错误率,一旦达到就停止。例如,自动驾驶汽车可能会以 99.99%的准确率识别骑自行车的人。这种方法的困难在于,在你开始实验之前,很难设定你的模型有多精确的期望值。鉴于不可减少的误差水平,你想要的准确率可能是不可能的。另一方面,您可能会过早地停止,而仍然有空间来轻松地改进您的模型。
- 价值梯度法— 通过在您的模型中绘制真实世界的错误成本与增强模型所需的努力,您可以了解每次增量改进的投资回报。这允许您继续开发您的模型,只有当额外调整的预测值低于您的时间值时才停止。

收益递减法则
当你投入时间调整你的模型时,你可能会发现你的进展在开始时很快,但很快就停滞了。你可能会先取得最明显的进步,但随着时间的推移,你会越来越努力地工作以获得更小的收益。在数据本身中,可减少误差和不可减少误差之间的平衡为模型所能达到的精确度设置了上限。
在学习练习或纸牌游戏比赛中,你可以随心所欲地重复,追求那些越来越小的进步。
然而,对于一个商业项目来说,调整这个模型的成本随着您投入的时间的增加而线性攀升。这意味着,到了某个时候,再多掏 0.1%就不值得投资了。
这因项目而异。如果您正在处理超市数据,考虑到每天的大量购买,额外的百分之一个百分点的准确性可能值很多钱。这为继续努力改进您的模型带来了丰厚的投资回报。但是对于规模更小的项目,你可能需要更早地划清界限。

模型误差的真实成本
在调优模型时,您可能要关注的值本质上是统计的。MSE、%精度、R 和 AIC 是由它们的数学公式定义的,与你试图解决的现实世界的问题无关。
不要只考虑准确性和误差的统计测量,这些应该被转换成可以与你正在进行的时间投资相权衡的东西,即金钱。
假设我们经营一个冰淇淋亭,我们试图使用天气、星期几、一年中的时间等变量来预测我们每天会卖出多少冰淇淋。
我们创建的模型没有一个是完美的,在任何一天,它通常都不是完美的;
- 高估——意思是我们买的配料比卖出的冰淇淋数量需要的多。
- 低估——意味着我们缺货,失去了潜在的业务。
这两种类型的错误都会给企业带来货币成本。如果我们中午就缺货,我们就失去了半天销售的利润。如果我们估计过高,我们可能会把钱花在最终被扔掉的原料上。
我们可以在我们的模型之上引入业务规则来帮助减少一些损失。损失 1 个冰淇淋销售额的成本可能高于扔掉 1 个冰淇淋过期牛奶的成本(假设我们有希望获利)。因此,我们会倾向于过量储存,例如,比模型预测的多储存 20%的原料。这将大大降低库存中断的频率和成本,代价是不得不扔掉几瓶过期的牛奶。
优化这 20%的规则,属于规定性分析的范畴。使用训练集,我们可以调整这一规则,直到模型中误差的平均估计真实成本达到最低。

价值梯度法
既然我们已经估算了模型准确性的真实成本,我们就知道我们在模型上投资的时间值多少了。随着每一次迭代,我们从先前版本的成本中减去真实世界的成本,以计算出我们额外努力所增加的价值。从那里,我们可以推断出一个投资回报窗口。
例如,您的验证集可能包含 1,000 行,并且您的最新模型比前一次迭代节省了 40 美元。如果您预计每年收集 100,000 个数据点,那么您可以将附加值乘以 100 来获得年增长率。因此,你为生产该模型的最新版本而投入的工作每年可获得 4000 美元的回报。
将此与我们的时间成本相比较,我们可以获得预期的投资回报。例如,如果上述改进需要一个每天收入 400 美元的人工作一天,那么它很快就收回了成本。
然而,随着收益递减规律侵蚀我们的改进速度,我们的利润将开始下降。当它接近零时,是时候接受我们所拥有的,并进入我们项目的下一个阶段。
当然,这是一门不精确的科学。它假设对我们模型的改进将以平稳和可预测的方式发生,并且未来的收益将小于以前的改进。无论何时你收工,都有可能会有重大突破。
但是,从商业角度关注你在一个模型上投资的时间总是一个好主意,通过降低成本和腾出时间花在最重要的事情上,你可以做更有价值的工作。
即将推出:一个 Python 模块,它获取预测、实际值和成本函数,并输出任何模型的预期 ROI 允许您将上述决策集成到您的模型调整过程中。
知识蒸馏——穿越时间的调查
通过这个博客,你将回顾知识蒸馏(KD)和六篇后续论文。
历史
2012 年,AlexNet 在 ImageNet 数据上的表现超过了现有的所有模型。神经网络即将被广泛采用。到 2015 年,许多先进技术被打破。趋势是在你能找到的任何用例上使用神经网络。VGG 网的成功进一步肯定了使用更深层次的模型或模型集合来获得性能提升。
(模特合奏只是一个花哨的名词。这意味着对多个模型的输出进行平均。例如,如果有三个模型,其中两个模型预测“A”,而一个模型预测“B”,那么将最后的预测作为“A”(两票对一票)
但是这些更深层次的模型和这些模型的集合在推理过程中运行的成本太高。(3 个模型的集合使用 3 倍于单个模型的计算量)。
意念
Geoffrey Hinton、Oriol Vinyals 和 Jeff Dean 提出了一种在这些预先训练的集合的指导下训练浅层模型的策略。他们称之为知识提取,因为你从一个预先训练好的模型中提取知识到一个新的模型中。因为这看起来像是一个老师在指导一个学生,所以这也被称为师生学习。https://arxiv.org/abs/1503.02531

(图片来自https://nerv anasystems . github . io/distiller/knowledge _ distillation . html))
在知识蒸馏,他们使用预训练模型的输出概率作为新浅层模型的标签。通过这个博客,你可以了解这项技术的改进。
Fitnets
2015 年出现了 FitNets:薄而深的网的提示(发表于 ICLR 2015 年)
FitNets 在 KD 损失之外又增加了一项。它们从两个网络的中点获取制图表达,并在这些点的要素制图表达之间添加均方损失。
经过训练的网络正在提供新网络正在模仿的经过学习的中间表征。这些表征帮助学生有效地学习,被称为暗示。

FitNet 能够压缩模型,同时保持几乎相同的性能
回过头来看,这种使用单点给出提示的选择是次优的。许多后续论文试图改进这些提示。
更加关注注意力
更加关注注意力:通过注意力转移提高卷积神经网络的性能在 2017 年 ICLR 上发表

图片来自报纸
他们与 FitNets 有相似的动机,但是他们使用注意力地图作为提示,而不是从网络中的一个点来表示。(MSE 超过学生和教师的注意力地图)。他们还使用网络中的多个点来给出提示,而不是 FitNets 中的一点提示
来自知识蒸馏的礼物
同年,在 CVPR 2017 上发表了《知识蒸馏的礼物:快速优化、网络最小化和迁移学习。
这也类似于 FitNets 和注意力转移纸。但是他们用 Gram 矩阵给出了提示,而不是表示和注意力地图。
他们在论文中对此进行了类比:
“在人的情况下,老师解释问题的解决过程,学生学习解决过程的流程。当输入特定问题时,学生 DNN 不必学习中间输出,但是当遇到特定类型的问题时,可以学习解决方法。通过这种方式,我们相信演示问题的解决过程比教授中间结果提供了更好的概括。”

图片来自报纸
为了测量这个“解决方案流程”,他们在两层的特征图之间使用了一个 gram 矩阵。因此,代替 FitNets 中作为提示的中间特征表示,这使用特征表示之间的 Gram 矩阵作为提示。
解释复杂网络
随后在 2018 年,发表在 NeurIPS 2018 上,解释复杂网络:通过因子转移的网络压缩

图片来自报纸
他们在模型中增加了另一个模块,他们称之为释义器。它基本上是一个自动编码器,不会减少尺寸。从最后一层,他们分叉出另一层训练重建损失。
该学生还有另一个名为 translator 的模块。它将学生最后一层的输出嵌入到教师解释的维度中。他们利用老师潜在的转述表述作为暗示。
TL;学生应该能够从教师网络构建一个输入的自动编码表示。
一次全面检修的特色蒸馏
2019 年,全面检修的特色蒸馏在 ICCV 2019 发布。

图片来自报纸
他们声称我们接受暗示的位置不是最佳的。输出通过 ReLU 细化,在转换过程中会丢失一些信息。他们提出了 marginReLU 激活(移位 ReLU)。“在我们的利润率 ReLU 中,正面(有利)信息未经任何转换就被使用,而负面(不利)信息被抑制。因此,所提出的方法可以在不丢失有益信息的情况下进行蒸馏”
他们使用了部分 L2 距离函数,该函数被设计为跳过关于负区域的信息的提取。(如果来自该位置的学生和教师的特征向量都是负的,则没有损失)
对比表征蒸馏在 ICLR 2020 出版。在这里,学生也从老师的中间陈述中学习,但是他们使用对比损失来代替 MSE 损失。
总之,这些不同的模型采用了不同的方法来
- 增加蒸馏过程中传递的信息量。
(特征表征,Gram 矩阵,注意力图,转述表征,预 ReLU 特征) - 通过调整损失函数
(对比,部分 L2 距离)来提高蒸馏过程的效率
看待这些想法的另一个有趣的方式是,新想法是旧想法的矢量和。
- KD 的 Gram 矩阵=神经类型转移+ KD
- 注意力地图=你所需要的就是注意力+ KD
- KD =自动编码器+ KD 的解释表示
- 对比表征提炼= InfoNCE + KD
其他向量和是什么?
- KD 的 GAN(也就是用特征表示之间的 GAN 损失来改变对比损失),
- 弱监督 KD ( 对吵闹学生的自我训练提高了 ImageNet 分类
这篇博客的灵感来自于 https://twitter.com/nishantiam/status/1295076936469762048 在知识蒸馏的推特风暴
[知识蒸馏] FitNets:薄深网的提示

注意——YouTube 上还有一段视频解释了这篇论文
解决的问题
本文首先提出了一个案例,即宽而深的模型通常需要大量的乘法运算,这会导致很高的内存和计算需求。正因为如此,即使该网络在准确性方面是一个最高性能的模型,它在现实世界中的应用也是有限的。
为了解决这种问题,我们需要执行模型压缩(也称为知识蒸馏),将知识从一个繁琐的模型转移到一个参数较少的简单模型。
这篇论文背后的主要驱动力是,到目前为止,知识提炼方案已经考虑了与教师网络规模相同或更小的学生网络。
他们提请注意这样一个事实,即迄今为止,学生网络的深度还没有被考虑。
比教师网络层数多但每层神经元数量少的学生网络称为薄深度网络。
现有技术及其局限性
现有技术可以从两个不同的角度来看。
第一个视角是知识提炼的技术。自从这篇论文问世几个月后的 在神经网络中提炼知识的 论文它是唯一的现有技术。
知识蒸馏研究领域起步论文的关键见解
towardsdatascience.com](/paper-summary-distilling-the-knowledge-in-a-neural-network-dc8efd9813cc)
作者在这里提出了一个例子,当更平滑的 softmax 技术起作用时;迄今为止,还没有人注意到学生网络的深度。
他们认为
深度是表征学习的一个基本方面,它导致更抽象和不变的表征,因此我们应该考虑深而薄的学生网络
然而,他们也意识到更深层次网络(尤其是更细的更深层次网络)的训练可能非常具有挑战性。这个挑战是关于优化问题(例如,消失梯度),因此第二个现有技术观点来自于过去在解决深层网络的优化问题上所做的工作。
也就是说,这篇论文以及推而广之,所有被引用的论文都是 Resnet 时代之前的!
Resnet 架构在解决消失梯度等问题上发挥了重要作用,并为创建更深层次的模型铺平了道路。因此,对我们来说,试图理解这里过去引用的作品并不重要。
接下来,我们将讨论本文如何试图规避训练更深但更薄的学生网络的挑战
关键见解
因此,第一个也是最主要的景象就是我们已经讨论过的,也就是说,建立一个更薄但更深入的学生网络是一个好主意。
本文的重点转移到解决他们在一个更薄更深的学生网络中可能面临的优化问题。
由于初始层的学习是有帮助的,他们决定通过使学生网络的一部分模仿教师网络的一部分来帮助学生网络。例如,如果我们在学生模型中有一层学习预测教师模型中一层的输出,那么我们可能会缓解与培训相关的问题。

来源:从报纸上剪下
学生应该学会预测教师输出的那一层被称为“提示层
来自学习的学生网络的层被称为“引导的层。
你现在可以考虑有一个目标函数,它接受提示和引导层的输出,并最小化损失。
然而,这导致了一个有趣的问题,即在教师模型中选择哪些层作为提示层,同样地,在学生模型中哪一层应该作为引导层。
作者指出,如果导向层更靠近输出层,则可能会过度正则化。为什么这种特殊的安排导致过度正规化是没有解释的!
然后他们提到,他们最终选择了学生的中间层作为引导层,暗示层也是如此,即教师的中间层
这个决定很可能是他们实验的结果。
它是如何工作的?
如上所述,您可以选择教师模型的中间层作为提示层,选择学生模型的中间层作为引导层,这样可以最大限度地减少预测中的损失。
这基本上是一个 2 阶段的培训过程。在第一阶段,使用预先训练的教师模型来训练网络直到引导层。
也就是说,这创造了一个有趣的情况。由于学生模型应该更薄,引导层的神经元数量将少于提示层。因此,我们无法真正比较这两层的输出
为了解决这个问题,他们在引导层前面放了一个回归量,使维度与提示层的维度相同。下图显示了这一点。

来源—作者
作者随后在多个数据集(CIFAR 10、CIFAR 100 和 SVHN)上进行了实验,获得了显著的结果。

来源—摘自论文
以上结果基于 CIFAR 10 数据集。教师模型有 5 层,900 万个参数。他们用不同的层数训练了 4 个不同的学生网络(称为 FitNet)。从表中可以看出,FitNet 1 只有 250K 参数,精度下降了 1%多一点。
FitNet 2、3 和 4 比教师网络具有更好的准确性,从而证明深度和提示训练都有效。
以下是这篇论文的一些见解/观察-
- 基于提示的机制确实简化了训练过程
- 由于阶段式设置,学生可以更好地进行初始化
- 暗示训练似乎也有助于正规化。结果表明了这一点
各种链接和详细信息
论文有开源实现吗?
Github 上有多种实现。这里我提供了这篇论文的第一作者 https://github.com/adri-romsor/FitNets 的实现链接
这篇论文是在一次会议上发表的吗?
是的。这篇论文被 2015 年 ICLR 会议接受,被引用了 1000 多次
论文链接—【https://arxiv.org/abs/1412.6550
有解释论文的视频吗?
是的。我为这篇论文制作了 YouTube 视频。
我的观点、问题和要点
- 一篇写得非常好的论文强调(并证明)了深度在学生网络中的重要性。
- 对提示和引导层的选择可以进行更详细的研究。
- 我认为 Resnet 应该关注优化问题(消失梯度等),但该技术对学生网络的初始化仍然有用。这至少有助于加快收敛速度!
希望你喜欢这个摘要,我可能误解/曲解了论文的某些部分,因此,如果有的话,错误是我的,而不是原论文作者的。
知识图在零售业中的应用

TL;博士 : 知识图表在科技领域变得越来越流行。我们探索如何在零售行业中使用它们来丰富数据、扩大搜索结果并为零售公司增加价值。
编辑以一年一度的黑客周结束了 2019 年,这是一个以最小风险测试新想法的绝佳机会,同时促进了团队和专业之间的合作。我的团队致力于一个我去年一直热衷于探索的研究领域:知识图表。如何在零售业中利用和优化它们?

一个谷歌知识面板的例子
知识的兴起
在科技行业,知识图表正在爆炸。它们被语音助手、在线零售推荐者和搜索引擎所使用,脸书、谷歌和网飞等科技巨头是它们最大的拥护者。你最有可能每天看到它们以一个盒子或者“知识面板”的形式出现,当你用谷歌搜索的时候。谷歌使用从维基百科等网站收集的数据,这些网站使用一个 JSON-LD 模式来声明页面的结构化数据,以及它自己对用户行为的理解来扩展你的搜索结果。以搜索大卫·鲍依(左)为例。谷歌从维基百科返回出生地、出生日期和配偶等汇总信息,以及流行歌曲和电影以及用户定义的“人们也搜索”。这产生了一个更具信息性的信息面板,其中数据是以实体为中心的,也就是“事物而不是字符串”

作为图形的大卫·鲍依
如果我们以图表的形式查看大卫·鲍依的电影数据,它看起来会像上面这样:大卫·鲍依(用红色表示的人节点)通过 ACTED_IN 关系连接到各种电影(蓝色的电影节点)。我们可以使用与这些节点相关的数据(例如电影中的其他演员)或与人物节点相关的数据(例如黄色的出生年份)来进一步扩展这一点。
这个简单的图形能够以一种直观的方式存储数据,允许一种传统 RDBMS 难以实现的查询(比如跟踪链接)。我们可以看到这样的关系,其中来自一个节点的每条路径都有一个相关联的含义,如“参与”。这形成了一个本体,其中我们将特定领域的知识表示为实体、概念和数据之间的属性、连接和关系。
零售产品图
大量的数据适合本体,零售也不例外。让我们来看看如何将来自 EDITED 的产品作为产品图来查看。为方便起见,我们只包含了产品数据和字段的子集。有很多软件包可以用来构建图形,我们使用流行的 Neo4j 平台。

使用 Neo4j 将产品编辑成图形
这里我们有一个用惟一标识符命名的产品节点(橙色)。从这个产品节点,我们有几个指向其他节点的关系,包括:HAS_ATTR(绿色),颜色(蓝色),护理(粉红色),品牌(红色)和类别(米色)。HAS_ATTR 指的是一个属性,例如,该产品包含一个紧固件,以及使用简单的 TF-IDF 单词提取(使用权重来隔离重要属性的单词)在产品的名称、描述和护理上发现的护理。品牌是在抓取的时候直接取的。而其他关系,类别和颜色,是使用基于文本和图像的机器学习找到的。
以这种格式存储零售数据创建了一个可解析的数据结构,突出了与一个产品以及其他产品的关系。例如,其他具有“ruffle”特性的产品也会指向“ruffle”节点,如下所示。这种结构还允许在我们爬行时从管道中不断获取数据,因为图能够适应。通过将数据存储为图形,我们还可以应用使用图论制定的算法,例如利用最近邻居的最短路径(这可能有助于产品匹配)和链接预测,我们可以预测节点之间的关系。

提取与我们的产品具有“皱褶”特征的其他产品
陷入语义学
到目前为止,我们已经谈论了很多关于用图表表示数据的内容,但是我们一直在讨论知识图表吗?关于这个话题有一些不同的观点,但我更喜欢将知识图定义为添加了特定领域知识的本体(例如,参见 Ehrlinger et al 2016 )。虽然我们的产品数据使用机器学习来提取我们用作图中节点的产品属性,但对我来说,知识图使用外部数据或对零售的理解来构建本体。
例如,EDITED 使用博柏利作为我们产品图中的品牌节点。如果它存在于一个知识图中,它将在节点中存储信息,如公司成立的时间和地点,以及与品牌相关的某些属性,如遗产、印刷品、奢侈品、Riccardo Tisci(首席创意官)等。这需要零售专家的协调和深入研究。为了使这个知识图与我们的产品图明显分开,节点用黄色标出。

使用博柏利相关词汇的零售知识图的示例子集。节点类型包括年份、公司、国家、人员和关联词语。
查询扩展—增强搜索引擎
现在我们有了一个零售知识图(其中黄色节点是零售行业中具有语义连接的实体)和一个经过编辑的产品图(颜色和品牌等产品数据的多色节点),我们可以利用这两个图进行一些高级查询扩展。
我们使用知识图中的语义信息来获取与文化背景相关的单词。以上述与博柏利相关的单词为例,特别是通过“BRAND_FROM”连接到“Britain”的节点。我们可以使用知识图的这个集群返回英国品牌,如博柏利和保罗·史密斯。
在下面的产品图中,我们有一个博柏利产品和一个保罗·史密斯产品,它们通过在知识图中的连接而相互关联。它们在产品图中还通过一些共享节点(例如,服装、衬衫、印花等)相互关联。因此,如果我们要搜索“英国设计师衬衫式连衣裙”,我们的知识图表将返回基于英国品牌的结果,简单的搜索(如 fuzzy)可以确保我们专注于衬衫式连衣裙。

通过品牌的原产国来关联产品
语义搜索在零售业中很常见,特别是像“时髦的连衣裙”或“跳舞的连衣裙”这样的搜索,会比搜索像“黑色不对称亮片迷你连衣裙”这样的特定产品名称更常见。我们还可以使用基于产品属性和语义实体的知识图将单词关联在一起,与其说是本体,不如说是关键字关联,以构建简单的基于规则的分类,从而实现快速扩展。同样,行业专家在这个过程中根据他们对零售的了解来选择这些词是至关重要的。下面是我们知识图表的一个子集——与“party”相关的精选单词列表。我们可以利用这一点扩大客户的搜索范围。

零售知识图的子集,带有与 party 相关的单词
通过搜索“时髦服装”,我们从知识图中返回两个“路径长度”(即箭头)内与“时髦”相关的所有精选单词。我们还可以将其扩展到路径长度> 2,以进一步挖掘知识图连接,例如,返回具有这些属性的品牌。这将返回一个“party”聚类来查询我们的产品图,返回所有以 party 相关的词作为属性的产品(即通过 HAS_ATTR 关系),从而扩展我们的原始查询。我们可以使用我们的知识图的任何部分重复这个过程,例如,“皮夹克”使用一个织物本体(如皮革和麂皮),“可持续”使用一个可持续本体(链接品牌、材料、关联词等)。

使用零售知识图通过查询扩展来查询我们的产品图
这种将知识图连接到产品图的方法还允许我们进一步探索我们的零售数据。通过观察与某些词的联系增加,我们可以开始看到趋势集群的形成,以及品牌之间共享节点数量增加的品牌集群。
最后的想法
事实证明,知识图谱是未来科技的一大贡献者,也将很快成为零售业的下一场大革命。在几天的时间里,我们只涉及了他们零售潜力的一小部分。然而,它们可以为零售公司增加重要的价值,这些公司正在寻求改善搜索扩展、个性化在线推荐、预测趋势、产品匹配等等。我们期待在 EDITED 探索所有这些可能性。
知识图表一览
KGs 洞察
利用语义图视角,将人类知识融入智能系统
知识图(KGs)已经成为将人类知识整合到智能系统中的核心抽象。这种知识被编码在基于图的结构中,该结构的节点表示真实世界的实体,而边定义这些实体之间的多种关系。KGs 正受到工业界和学术界的关注,因为它们提供了一种灵活的方式来捕获、组织和查询大量的多关系数据。
这篇文章的目标是介绍 KG 特有的双重视角:
- 基于图形的视角,它允许我们在 kg 上执行图形算法和归纳推理技术;
- 基于语义的视角,它为数据的语义解释提供了一个正式的框架,这对于执行演绎推理是必不可少的。
然后,这篇文章将重点关注与语义视角相关的技术和语言,这些技术和语言支持演绎学习。支持归纳技术的图形视角将在致力于图形表示学习的系列文章中讨论:https://towardsdatascience.com/tagged/grl-series。

哲学领域中 KG 的例子
KGs 的正式定义
F 通常,一公斤可以定义为G= {E, R ,T},其中 G 为 a
每个三元组形式化为 ( u , e ,v)∊t,其中u∊e在语义体系中,三元组被形式化为一个事实,其中(, e ,v)对应于 ( 其中 s 和 o 是两个实体,分别是事实的主体和客体,而 r 是连接s和 o 的关系
为了阐明这一方面,请考虑下面的例子陈述:“苏格拉底影响了柏拉图。”从图的角度来看,三元组包括“苏格拉底”和“柏拉图”作为图的两个节点,而“受影响”是这两个节点之间的一条边。从语义上看,简单的说法包括“苏格拉底”和“柏拉图”两个实体,而“受影响”是这两个实体之间的关系。实体和关系也可以定义为语句的术语。
KG 数据模型
资源描述框架(RDF)是语义网(SW)的核心技术,用于实现知识的双重表示。SW 的目的是实现机器可读和可理解的网络级数据基础设施。为了实现这一仅部分实现的愿景,采用了统一资源标识符(URIs)和超文本传输协议(HTTP)等 Web 技术。
RDF 反映了一个简单的基于图的数据模型,利用了 Web 技术,并提供了一个正式的意义概念(语义),为有根据的演绎建立了基础。RDF 图可以用不同的格式序列化,包括 N-Triples、N3、Turtle、JSON 和 XML。例子“苏格拉底影响了柏拉图”可以翻译成 RDF,并按 N-Triples 连载如下:
*<[http://dbpedia.org/resource/Socrates](http://dbpedia.org/resource/Socrates)>
<[http://dbpedia.org/ontology/influenced](http://dbpedia.org/ontology/influenced)>
<[http://dbpedia.org/resource/Plato](http://dbpedia.org/resource/Plato)> .*
其他类型的序列化,比如 Turtle,支持使用所谓的前缀对 RDF 事实进行更紧凑的声明。该示例可以重写如下:
*[@prefix](http://twitter.com/prefix) dbo: <[http://dbpedia.org/ontology/](http://dbpedia.org/ontology/)> .
[@prefix](http://twitter.com/prefix) dbr: <[http://dbpedia.org/resource/](http://dbpedia.org/resource/)> .
dbr:Socrates dbo:influenced dbr:Plato .*
从软件的角度来看,术语 dbr:Socrates ,dbo:infected,和 dbr:Plato 也被称为资源,两个不同资源之间的关系——在本例中为dbo:infected——也被称为谓词或这个例子直接来自一个名为 DBpedia 的现有开放 KG,它的目标是以 RDF 三元组集合的形式提供包含在维基百科信息框中的信息。这个集合也可以表示为 RDF 图。**
运行实例表明,URIs 可以作为实体 s 和 o 以及关系 r 的唯一标识。RDF 允许我们表示实体之间的关系,也可以表示与单个实体相关的特定信息。在 RDF 语句中
*dbr:Socrates dbo:birthDate -469-0-0^^xsd:date .*
该对象不是一个实体,而是一个文字值,具有使用 XML 模式数据类型(XSD)定义的特定数据类型。从图的角度来看,一个文字值被认为是 KG 的一个叶节点。从 RDF 表示开始,增加了量化的语句来表示实体和关系的语义。
语义模式和本体
DF 模式(RDFS)和 OWL(网络本体语言)是两种不同的语言模型,能够以 RDF 图的形式构建量化的语句。RDFS 是定义 RDF 图语义模式的最重要的标准之一。OWL 是在实际案例中使用的最流行的本体语言,合并和扩展了 RDFs。RDFS 和 OWL 指定了大量的词汇表来表示使用 RDF 节点和边的特殊条件,引入了一致性和特定的数据类型来支持逻辑推理。此外,它们表明术语是如何相互关联的,并强加了一个结构来定义语义解释的约束。
DFS 提供了为聚集具有相似特征的实体定义类的机制。为了定义阶级,RDFS 提供了两个不同的术语:
- rdf:type 属性定义了一个主题节点的“类型”;此属性的对象必须是类。在 RDF 中, rdf:type 也可以替换为a;
- rdfs:Class 用于聚合相似的实体。
在运行的示例中,可以定义以下语句来扩展与 Socrates 相关的信息:
*ex:Human rdf:type rdfs:Class .
dbr:Socrates rdf:type ex:Human .*
RDFS 还允许用rdfs:subclass of属性定义类层次结构。因此,事实的收集可以扩展如下:
*ex:Human rdf:type rdfs:Class .
dbr:Socrates rdf:type ex:Human .
ex:Mortal rdf:type rdfs:Class .
ex:Human rdfs:subClassOf ex:Mortal .*
RDFS 还定义了特定的术语来扩展属性的语义。这些术语包括:
- rdf:Property→它是将 rdf:type 中的任何一个术语用作谓词;
- rdfs:domain 和rdfs:range→它们定义属性的域和范围。域和范围被分类为rdfs:Class;
- rdfs:sub property of→它指定了属性的层次结构。
因此,与dbo:affected属性相关的信息可以表示如下:
*dbo:influenced rdf:type rdf:Property ;
rdfs:range ex:Human ;
rdfs:domain ex:Human .*
WL 是一种描述本体的语言模型。OWL 文档,被称为本体,包含了 RDFS 定义的术语,并添加了进一步的结构来解决其局限性。例如,OWL 明确了不同实体之间的相同或不同的关系。它支持更具表达性的类定义,包括并集、补集、不合集,指定基数限制。此外,它还包括更具表达性的属性定义,支持区分对象和数据类型属性。OWL 还允许我们定义传递的、函数的、对称的和反向的属性,表示值的限制。描述类和属性之间关系的陈述也被称为公理。这些陈述在参考领域被归类为真,并且是实现演绎推理的基础。
运行示例可以用 OWL 扩展如下:
*[@prefix](http://twitter.com/prefix) rdf: <[http://www.w3.org/1999/02/22-rdf-syntax-ns#](http://www.w3.org/1999/02/22-rdf-syntax-ns#)> .
[@prefix](http://twitter.com/prefix) rdfs: <[http://www.w3.org/2000/01/rdf-schema#](http://www.w3.org/2000/01/rdf-schema#)> .
[@prefix](http://twitter.com/prefix) owl: <[http://www.w3.org/2002/07/owl#](http://www.w3.org/2002/07/owl#)> .
[@prefix](http://twitter.com/prefix) ex: <[http://example.com/](http://example.com/)> .
[@prefix](http://twitter.com/prefix) dbr: <[http://dbpedia.org/resource/](http://dbpedia.org/resource/)> .
[@prefix](http://twitter.com/prefix) dbo: <[http://dbpedia.org/ontology/](http://dbpedia.org/ontology/)> .
[@prefic](http://twitter.com/prefic) wkd: <[https://www.wikidata.org/wiki/](https://www.wikidata.org/wiki/)> .# RDF
dbr:Socrates dbo:influenced dbr:Plato ;
dbo:birthDate -469-0-0^^xsd:date .# RDFS
dbr:Socrates rdf:type ex:Human .
ex:Human rdf:type rdfs:Class ;
rdfs:subClassOf ex:Mortal .dbo:influenced rdf:type rdf:Property ;
rdfs:range ex:Human ;
rdfs:domain ex:Human .# OWL
dbr:Socrates owl:sameAs wkd:Q913 .
dbo:influenced rdf:type owl:ObjectProperty .
dbo:birthDate rdf:type owl:DatatypeProperty .
rdfs:subClassOf rdf:type owl:TransitiveProperty .*
这个例子建立了量化的陈述,例如“所有人都会死”从而也让我们通过演绎推理推断出一个新的事实:“苏格拉底是凡人”来源于 ex:人类 是 ex:凡人 的子类。在同一个例子中,OWL 语句允许我们声明dbo:infected和dbo:birth date是两种不同类型的属性,分别是对象属性和数据属性。此外,使用 OWL 可以定义这样一个公理,根据这个公理,rdfs:subclass of是一个传递属性。
查询千克
一种被称为 SPARQL (SPARQL 协议和 RDF 查询语言)的实用语言已经在软件环境中开发出来,用于在 kg 上执行查询。这种结构化查询语言的核心是基于图形模式的,它遵循相同的 RDF 图形模型。此外,SPARQL 引入了变量作为有效术语。所以图模式分为常量,用 dbr:Socrates 等资源表示,用 等变量表示?哲学家 ,用问号标识。在查询过程中,根据 RDF 图评估图模式。这个过程在图模式的变量和 RDF 图中的资源之间生成一个映射。然后,这些变量被满足查询中包含的图形模式的 RDF 资源替换。下面是 SPARQL 查询的一个例子:
*[@prefix](http://twitter.com/prefix) dbr: <[http://dbpedia.org/resource/](http://dbpedia.org/resource/)> .
[@prefix](http://twitter.com/prefix) dbo: <[http://dbpedia.org/ontology/](http://dbpedia.org/ontology/)> .SELECT ?philosopher
WHERE {
dbr:Socrates dbo:influenced ?philosopher .*
考虑到我们运行的例子, ?哲学家 变量替换为资源 dbr:柏拉图 。
下一步是什么
在下一篇文章中,我描述了从结构化的数据源构建知识库的概念性方法,将这些数据源的本地模式映射到由领域本体定义的全局模式。
关于集成异构数据所采用的映射方法的说明
towardsdatascience.com](/building-knowledge-graphs-from-structured-sources-346c56c9d40e)
如果你喜欢我的文章,你可以支持我使用这个链接https://medium.com/@giuseppefutia/membership*成为中等会员。**
可解释人工智能的知识图
KGs 洞察
将语义技术和符号系统整合到深度学习模型中,以实现更易于理解的人工智能

一个可解释的人工智能系统的示意图,该系统将语义技术集成到深度学习模型中。人工智能系统的传统管道用蓝色表示。深度学习组件与知识图(kg)和本体的知识匹配过程用橙色描绘。由查询和推理机制实现的跨学科和交互式解释用红色表示。
D eep 学习模型有助于在人工智能(AI)系统的预测和分类任务中取得前所未有的成果。然而,在取得这一显著进步的同时,它们并没有提供人类可以理解的关于具体结果是如何实现的见解。在人工智能对人类生活的影响相关的背景下(例如,招聘工具、医疗诊断等。),可解释性不仅是一个可取的属性,而且是——或者,在某些情况下,很快将是——一个法律要求。
大多数实现可解释人工智能(XAI) 的可用方法都专注于只有能够操纵深度学习算法中数学函数的专家才能使用的技术解决方案。一种互补的方法由符号人工智能代表,其中符号是人类和深度学习之间通用语言的元素。在这种背景下,知识图(KGs) 及其底层语义技术是符号人工智能的现代实现——虽然与深度学习模型相比,KGs 不太灵活,对噪声也不太鲁棒,但 KGs 天生就被开发为可解释的。
当前 XAI 的局限与 KGs 的机遇
XAI 是数学家、计算机科学家和软件工程师设计、开发和测试技术的研究领域,旨在使人工智能系统更加透明,更容易被利益相关者理解。在该领域开发的大多数方法需要非常具体的技术专业知识来操纵算法,这些算法在深度学习的基础上实现数学功能。此外,理解这种数学支架不足以洞察内部工作模型。事实上,为了更容易理解,基于深度学习的系统应该能够发出和操纵符号,使用户能够解释如何实现特定的结果。
在符号系统的背景下,KGs 及其底层语义技术是解决可理解性问题的一个有希望的解决方案。事实上,这些语义实体和关系的大型网络为几个推理机制提供了有用的主干,从一致性检查到因果推理。这些推理过程由本体实现,它提供了与特定知识领域相关的语义实体和关系的正式表示。
KGs 在建设美好 XAI 中的作用
基于语义技术的符号系统的实现适合于改进对非内部人员的解释。深度学习模型的输入特征、隐含层和计算单元、预测输出可以映射成 KGs 的实体或本体的概念和关系( 知识匹配 )。传统上,这些本体工件是来自不同学科的专家采用的概念化和实践的结果,例如生物学、金融和法律。因此,即使他们没有人工智能技术方面的技能,他们也非常容易被具有特定领域专业知识的人理解( 跨学科解释 )。此外,在语义技术的上下文中,知识和本体是为查询而生的,因此它们能够为用户请求提供答案( 交互式解释 )并提供符号级别来解释深度学习模型的行为和结果。
从这些点出发,XAI 的未来工作有具体的轨迹,包括利用符号技术来设计新颖的深层神经架构,以本地编码解释;多模态解释模型的开发,该模型能够从不同的角度提供洞察力,结合视觉和文本人工制品;定义一个通用解释框架,用于深度学习模型比较,基于知识和本体,以实现适当的验证策略。
参考
关于这个主题的更多信息可以在我们的期刊文章中找到,标题为“关于将知识图整合到深度学习模型中以获得更容易理解的人工智能——未来研究的三个挑战”。
社会公益知识图表讲习班:帮助联合国实现可持续发展目标

2015 年制定的联合国可持续发展目标(SDGs)是 17 个全球共同目标的集合,旨在到 2030 年改善全球人民的健康和福祉。17 个目标有 169 个具体目标。每个目标有 1 至 3 个指标,用于衡量实现目标的进展情况。联合国与来自 70 个国家的代表进行了一系列“全球对话”,以决定 SDG。
埃森哲实验室与联合国合作,正在组织社会公益知识图表研讨会,以帮助联合国利用知识图表创建和探索技术,深入了解可持续发展目标。我们正在以合作构思练习的形式汇集参与者的专业知识,为联合国提出建议,并确定未来可能的研究方向。
当前为实现可持续发展目标所做的努力
联合国内部有许多与可持续发展目标相关的令人兴奋的工作。为此,联合国成立的组织全球脉动实验室(Global Pulse Lab)目前正在研究实时分析大数据的手段和方法。这意味着联合国可以利用人工智能和人工智能来发现数据中的模式,推断数据内容,并迅速获得洞察力,毫不延迟地采取行动。示例项目包括(但不限于):
通勤统计—针对 SDG 11,可持续发展城市和社区,该项目使用地理定位和社交媒体标签来了解市民的通勤模式。这一分析得出的见解正被用来填补官方通勤统计数据的空白。
气候异常——针对 SDG 13“气候行动”,该项目使用卫星图像跟踪气候异常,为决策者提供早期气候预警。
Pulse Labs 的其他细节和项目包括 SDG 2——零饥饿、SDG 4——质量行动和 SDG 5——性别平等。
联合国正在开展的工作得到了其他机构的补充,这些机构正在采取措施确定可能与多个可持续发展目标相关的共同主题。比如,2016 EAT Stockholm 食品论坛的主题演讲认为,所有的可持续发展目标都可以直接或间接地与食品联系起来。还说明了如何将可持续发展目标分成更广泛的类别,例如:生物圈、社会和经济。
当今世界比以往任何时候都更加相互关联,实现目标指标所定义的可持续发展目标的进展反映了这种相互关联。如果表示和连接 SDG 的解决方案的开发取得进展,更大的洞察力就在掌握之中。这项工作将为我们提供探索联系和数据背景以及衡量一个 SDG 对另一个 SDG 的影响的能力。
为什么是知识图表?
图表用关系映射数据,而 SDG 则有个人在健康、贫困、社会和经济等方面的数据。因此,当他们测量相同的人群时,从一个 SDG 到另一个 SDG 开始提供数据上下文和数据的语义理解是一个自然的过渡。知识图可以提供带有语义上下文的数据覆盖,同时表示来自非结构化和结构化来源的概念。随着数据量的增长,对领域的语义理解会加深和拓宽。
NLP 的最新进展是从非结构化数据中提取知识,在语义上连接它们,并预测缺失的链接,这有助于构建全面的知识图。将知识图与这些先进的 NLP 技术结合使用,为研究 SDG 提供了一个令人兴奋的机会。此外,这一方法允许研究人员和决策者衡量干预和全球事件在可持续发展目标内部和之间的影响。知识图表将让我们深入了解:
- 来自一个或多个可用数据集的每个 SDG 的语义表示
- 在 SDG 内部和之间包含新的或现有关系的广泛表示
- 通过识别或预测领域空间内或跨领域空间的干预效果,实现可持续发展目标内部和之间的数据连接
知识图将各个数据仓库之间的点连接起来,可以在语义上表示非结构化和结构化数据。它是一种粘合剂,可以将数据、概念、关系和属性结合在一起。
本次研讨会将展示使用知识图对可持续发展目标的影响,也将有助于为各种其他领域设定类似的方向。
更多关于社会公益知识图表研讨会的详细信息
本次研讨会将探讨如何利用知识图表来实现联合国的 17 项可持续发展目标(SDGs),涵盖的主题包括贫困、医疗保健、教育、可持续发展等。在知识图创建、数据填充和应用的新的可扩展技术的背景下。
它将汇聚一群实践者和决策者,讨论可以解决可持续发展目标的正在进行的行业工作和学术研究成果。
此外,它将基于已提交的论文(请参见“征集论文”了解更多详细信息),并建立一个社区和论坛来公开讨论解决方案。
我们将提供杰出演讲者、联合国数据和专家的访问权限。会议将在协作构思练习中达到高潮,旨在促进关于可持续发展目标的现场小组集思广益会议,并讨论有助于联合国利用知识图表解决方案实现这些目标的潜在解决方案。
参考
https://medium . com/pulse-lab-Jakarta/tracking-the-sdgs-using-big-data-dad 0ad 351 f2e
https://medium . com/@ OECD/where-to-start-the-the-sdgs-FD 825 f 256 CCE
https://medium . com/@ OneYoungWorld _/what-the-business-case for-the-sdgs-4a 8402 f 9 ffd 7
https://medium . com/@ UNDP/stopping-the-leak-boosting-sdgs-40c 96026 aa 89
自然语言处理中的知识图@ ACL 2020
2020 年中期的技术水平
这篇文章是为了纪念我们研究 NLP 和 Graph ML 在知识图驱动下的进步的系列文章发表一周年!🎂1️⃣
观众的反馈驱使我继续,所以系好安全带(也许在这一集酿造一些☕️):,我们正在看 KG 相关的 ACL 2020 进程!

ACL 2020 今年实现了完全虚拟化,我无法想象主席们组织如此庞大的在线活动以满足多个时区和 700 多份已接受论文的需求有多困难。感谢所有参与者以及发言者和与会者,鉴于会议的规模,会议进行得很顺利👏
那么与 ACL 2019 相比,KG & NLP 领域有什么变化吗?是啊!
我将今年的贡献总结为:
知识图展示了在非结构化数据中揭示高阶相关性的更好能力
今天我们的议程是:
结构化数据上的问题回答
在这种情况下,问题是针对结构化数据源发送的,比如基于 SPARQL 的 kg 或 SQL 数据库(其他查询语言并不那么突出)。
今年,我们可以观察到越来越多的人加入了复杂(也称为多跳)问题。
例如, Saxena 等人 在他们的 EmbedKGQA 中解决了复杂 KGQA 耦合 KG 嵌入与问题嵌入向量的问题。 1️⃣首先,一个底层的 KG 嵌入了某种算法(作者选择 ComplEx ),这样每个实体和关系都与一个特定的向量相关联。在某些情况下,作者冻结它们,或者根据 KG 大小保持微调。2️⃣输入的问题通过 RoBERTA(来自最后一层的[CLS]令牌)编码,并通过 4 个 FC 层(如果你问为什么是 4,我没有答案,看起来像一个幻数🧙♂️)传递,这些层应该将问题投影到复空间。3️⃣关键部分发生在评分中,作者采用 KG 嵌入框架并构建了一个三元组 (头实体、问题、候选实体)。评分功能与 ComplEx 中的相同。这里,头部是问题中的主要实体,问题本身被认为是一个关系(虽然看起来有点牵强),候选实体要么是 KG 中的所有实体(如果很小),要么是头部周围的 2 跳子图(当需要修剪时)。是的,它确实类似于用于训练 KGE 算法的典型的 1-N 评分机制。✂️通过计算问题嵌入h_q和每个关系嵌入h_r之间的点积(h_q, h_r)并对其进行阈值处理,可以进一步修剪候选空间。
🧪在 MetaQA 和 WebQuestionsSP 上进行的实验中,作者探索了一个不完整 KG 随机删除 50%边的附加场景,因此系统必须学会推断这种丢失的链接。在完整的场景中, EmbedKGQA 的表现与 PullNet 不相上下(在 3 跳问题上略胜一筹),当不使用额外的文本来增加 KG 时,绝对命中@1 分数比基线高 10–40%。👏
尽管如此,检查 EmbedKGQA 如何处理需要聚合或有几个基础实体的问题还是很有趣的🤔。

EmbedKGQA。来源: Saxena 等人
另一方面, 兰等人 提出使用迭代的基于 RL 的查询生成方法(KG-free😉 ).基于主题实体(通过一些实体链接器获得,作者借助 Google KG API 链接到 Freebase),有一组 3 个操作,即扩展、连接和聚集,它们被应用于构建查询模式的种子实体。自然,这些操作允许具有最小/最大聚合的复杂多跳模式。🔦在每一步,作者使用波束搜索来保留 K 个最佳模式,并通过导出一个 7d 特征向量,然后是一个带有 softmax 的前馈网络来对它们进行排序。🤨你会问:“等等,伯特在哪里?现在每个人都在用伯特!”。好了,不要惊慌,开始吧:参与查询图的实体和关系的表面形式被线性化,与输入问题连接,并馈入 BERT,以获得最后一层的[CLS]表示(这是 7d 特性之一)。
🌡作者在 ComplexWebQuestions、WebQuestionsSP 和 ComplexQuestions(看起来有点像是为 Freebase 量身定制的,不是吗?),并发现比基线有明显的改进。进一步的消融显示了 3 个选择的操作者的重要性。这里有一个悬念:这是一篇简短的论文!👀我推荐这篇论文作为一篇短文的范例,它传达了主要思想,展示了实验,并证明了消融方法的有效性👍

来源: 兰等人
📑结构化问答还包括对 SQL 表的语义解析,许多新的复杂数据集推动了 SQLandia 的研究。

来源: 王等人
在其他人当中,我将概述 王等人 和他们的 RAT-SQL(关系感知转换器,不🐀)中,它们定义了列和表之间的显式边缘,以对数据库模式进行编码。作者还定义了一个初始模式和值链接来获得候选列和表。此外,列、表和问题标记通过修改后的自我关注层共同传递。➡️最后,树形结构的解码器构建一个 SQL 查询。
RAT-SQL 在 Spider 中表现出了巨大的改进,在使用 BERT 进行令牌的初始嵌入时获得了更大的收益📈

来源: 埃尔戈哈里等人
通常,在与语义解析系统交互时,您会希望即时解决一些小问题🔴解析器出错了。 Elgohary 等人 正是针对这个问题,提出了 SPLASH ,一个用自然语言反馈纠正 SQL 语法分析的数据集。纠正场景不同于对话式 text2SQL 任务,因此,即使是最近的 SOTA 模型,如 EditSQL,与人工注释者相比,在纠正任务中也存在很大差距,即 25%对 81%。那是相当大的差距👀。
曾等人 开发了 Photon 这是一个成熟的文本到 SQL 的系统,也能够执行一些查询修正😉
KG 嵌入:双曲线和超关系
双曲空间是 ML 最近的热门话题之一。克制🤯简单来说,在双曲空间中🔮(由于它的属性)您可以更有效地表示层次结构和树状结构,同时使用更少的维度!

来源: 横山雅美等人
出于这种动机, 横山雅美等人 提出了 AttH ,一种双曲 KG 嵌入算法,使用旋转、反射和平移来模拟 KG 中的逻辑和层次模式。 Att 来自应用于旋转和反射向量的双曲线注意。🎩绕过不稳定的黎曼优化的诀窍是使用切空间,可以将 d 维庞加莱球的每个点映射到切空间。在这个明显不平凡的设置中,每个关系不仅与一个向量相关,还与描述特定于关系的反射和旋转的参数相关。尽管如此,在现实世界的 KGs R << V中,开销并不是很大。
⚖️在实验中, AttH 在 WN18RR 和 yago 3–10 上表现特别好,表现出一些层次结构,在 FB15k-237 上的余量较小。更重要的是,仅仅 32 维 AttH 在真实和复杂的平面中显示出与 32-d 模型相比的巨大余量。此外,在 WN18RR 和 FB15k-237 上,32-d 分数仅比 SOTA 500-d 嵌入模型小 0.02-0.03 个 MRR 点。消融研究证明了具有可学习曲率的重要性,而其最接近的匹配 MurP 将曲率固定。

来源:罗索等人。发布于 WebConf 2020。
图表示学习中的另一个增长趋势是超越由三元组组成的简单 kg,学习更复杂的、超关系kg(如 Rosso 等人 的工作中所创造的)的表示,此时每个三元组可能有一组键-值属性对,这些属性对给出了关于三元组在各种上下文中的有效性的细粒度细节。事实上,Wikidata 在其 Wikidata 语句模型中采用了超关系模型,其中属性被称为限定符。重要的是而不是将模型与 n 元事实(生成冗余谓词)和超图混合在一起。也就是说,如果你只在三个层次上使用维基数据,你会丢失一半的内容😃
关等人 不想失去大半个维基数据,提出了 NeuInfer ,一种学习超关系 kg 嵌入的方法(他们之前的工作 NaLP ,更适合 n 元事实)。

来源: 关等人
NeuInfer 的想法是计算一个超相关事实的有效性和兼容性得分(参见图示)。首先,(h,r,t)嵌入被输入到一个完全连接的网络(FCN)中,以估计这个三元组的可能性(有效性)。其次,对于每个键值对,构建一个五元组(h,r,t,k,v),并通过另一组 fcn 传递。有了 m 个对, m 个向量被最小池化,结果表示兼容性得分,即那些限定词与主三元组相处得有多好。最后,作者使用两个分数的加权和得到最终分数。
作者在标准基准 JF17K(提取自 Freebase)和 WikiPeople(来自 Wikidata)上评估了 NeuInfer ,并报告了 JF17K 与 NaLP 相比在预测头部、尾部和属性值时的显著改进。📈我鼓励作者将他们的数字与 HINGE(来自 Rosso 等人 )进行比较,因为这两种方法在概念上是相似的。
💡现在我们需要谈谈。我们需要谈谈甚至在 ACL 2019 这样的顶级会议上发表的 KG 嵌入算法的再现性。此外,他们表明,他们的性能指标得分(如命中@K 和 MRR)取决于有效三元组在采样否定中的位置(这实际上不应该发生)。另一方面,现有的强基线表现完全一样,不管任何位置。要点是使用评估协议,将有效的三元组放在否定中的随机位置。

来源: 孙、瓦希思特、桑亚尔等人
[开始一场无耻的自我推销😊]嗯,我们的团队对这个问题也有话要说:在我们的新论文 “将光明带入黑暗:统一框架下知识图嵌入模型的大规模评估” 中,我们进行了 65K+实验,并花费了 21K+ GPU 小时评估了 19 个模型,从 2011 年首次发表的 RESCAL 到 2019 年末的 RotatE 和 TuckER,5 个损失函数,各种带/不带负采样的训练策略,以及更多的超参数我们还为你们和我们亲爱的社区发布了所有模型的最佳超参数🤗。此外,我们正在发布 PyKEEN 1.0 ,这是一个 PyTorch 库,用于训练和基准测试 KG 嵌入模型![自我推销结束]
🔥我鼓励你通读其他几部作品: 萨昌 通过离散化研究 KG 实体嵌入的压缩问题,例如,“巴拉克·奥巴马”而不是 200d float32 向量将被编码为“2–1–3–3”,而“米歇尔·奥巴马”将被编码为“2–1–3–2”。

使用(液压)压缩节省 CD 空间的示例
也就是你只需要一个 K 值的 D 长向量(这里 D=4,K=3)。对于离散化,发现回火的 softmax 效果更好。作为从 KD 代码到 N 维浮点向量的反函数,作者建议使用简单的双 LSTM。实验结果令人吃惊👀—FB15k-237 和 WN18RR 的压缩率达到100–1000 x,推理时(当 KD 代码必须被解码回来时)性能下降和计算开销可以忽略不计(最大 2% MRR)。🤔我建议我们都坐下来,重新思考我们的 KGE 管道(特别是在生产场景中)。例如,通过 PyTorch-BigGraph 获得的 7800 万维基数据实体的 200d 嵌入需要👉110 GB👈空间。想象一下,轻轻的 100 倍压缩会是什么样子😏。
还有一系列工作改进了流行的 KGE 模型:
- 唐等人 将旋转从 2D 旋转推广到高维空间,其中正交关系变换对于 1-N 和 N-N 关系更有效。
- 徐等 通过将密集向量分块为 K 个部分,将双线性模型推广为多线性。然后表明,如果 K=1,该方法等于 DistMult ,如果 K=2,该方法简化为复和孔,作者对 K=4 和 K=8 进行了实验。谢等人通过用计算机视觉领域著名的 Inception 网络中的滤波器替换标准的 conv 滤波器来扩展 ConvE。
- Nguyen 等人 应用自关注式编码器和 CNN 解码器进行三重分类和搜索个性化任务。
数据到文本 NLG:准备好你的变压器

WebNLG 2017 的 RDF 转文本任务示例。来源: 赵等人
随着 KGs(以及一般的结构化数据)在 NLP 中被广泛采用,在 2020 年,我们可以观察到自然语言生成(NLG)方法的激增,这些方法采用一组 RDF 三元组/一个 AMR 图/一组表格单元,并产生连贯的人类可读文本,如描述或问题。
顺便说一下,目前的 RDF-to-text 方法仅在 WebNLG 2017 数据上进行评估,但有一个新的挑战, WebNLG 2020 !🎉如果你喜欢 NLG,一定要参加😉
一条推文详尽总结了今年的 NLG 趋势:
自然语言处理中的 SOTA 算法综述
老练的策划者和执行者?一些结构排列?不😅。只要旋转你最喜欢的预先训练的 LM。
🤔事实上,插入一个预先训练好的 LM 并给它一些例子确实有效。陈等人在配有 2 解码器的实验台上演示了这一现象。也就是说,表格单元首先通过可学习的 LSTM 编码器来获得复制机制的隐藏状态。另一方面,文本以冻结的重量进入 GPT-2。顶部的✍️The 复制机制有助于保留表格单元格中的稀有标记。WikiBio 上的实验表明,少至 200 个训练样本就足以生成比复杂的强基线好得多的文本。猜猜 GPT 3 号需要多少😏

来源: 陈等人

来源: 陈等人
继续使用表格,陈等人 构建一个新的数据集, LogicNLG ,这需要在标准文本生成的基础上使用额外的逻辑。例如(参见插图),需要一些比较和计数操作来包含像“多一枚金牌”或“最多金牌”这样的部分,使文本更加自然和生动🌼。数据集的基线模型使用预训练的 GPT-2 和 BERT,但看起来 LMs 仍有一些改进的空间。
在图形到文本的领域中, 宋等人 应用了稍微修改的变换器编码器,该编码器显式地处理关系表面形式。输入只是一个线性化的图(可以用 DFS 来构建)。但是解码器保持不变。🎩该方法的关键部分是添加(连同标准 LM 损失)两个自动编码损失,这两个损失被设计成更好地捕捉动词化图形的结构。第一个损失重建三重关系,而另一个损失重建线性化输入图的节点和边标签。在 AMR 和 RDF 图(WebNLG)上进行的🧪实验表明,仅仅将这两个损失相加就可以产生大约 2 个 BLEU 点。

辅助损失试图重建视图 1 和视图 2。来源: 宋等人

不要隐藏你的痛苦,退休吧!
🗒在这一点上,我应该做一个小小的评论每个人都应该停止使用 BLEU 来评估 NLG 质量(ACL 20 篇论文的最佳提名之一,我相信他们)。WebNLG 2020 的组织者非常赞同这一观点,因为他们除了经典(或者我们应该说过时了?)度量。此外,在 ACL'20 上,提出了一种新的度量标准, BLEURT ,并证明它与人类的判断更相关。让我们投资于这些新的评估指标,让 ol' BLEU 休息一下吧🏖

来源: 赵等人
最后,让我们从数据到文本再到总结。在抽象概括领域 黄等人****在他们的 ASGARD 方法中采用从文档构建的 kg 来增强生成过程。

具体来说,编码器由两部分组成。1️⃣·罗伯塔用于对输入段落进行编码。最终的层嵌入被馈入 BiLSTM 以获得隐藏状态。2️⃣ OpenIE 用于从输入文档中提取三元组并归纳出一个图。关系的令牌被转换成类似于 DualEnc 的显式节点,初始节点状态取自步骤 1 的 BiLSTM。然后,使用图注意网(GAT)通过一个读出函数来更新节点状态,从而得到一个图上下文向量。3️⃣:生成过程受步骤 1 和 2 中获得的两个向量的制约。
🧙♂️Some 魔法在训练中发生: ASGARD 求助于强化学习,其中奖励函数取决于胭脂和完形填空分数。完形填空部分包括从人类书写的摘要中提取开放图形,并基于它们生成完形填空式问题,以便系统更好地学习摘要文档的含义。📦所以你在里面有一个质量保证模型!作者为 CNN 和 NYT 数据集生成了 1M+的完形填空题。📏实验报告比以前的基线有所改进!然而,一致的赢家是一个预先训练好的 BART,它在目标数据集上进行了微调😅好吧,看起来“TPUs go brrr”策略在这里也行得通。
对话式人工智能:改进面向目标的机器人
在 ConvAI 领域,我有点偏向于面向目标的系统,因为 KGs 和结构化数据自然地扩展了它们的功能。

来源: 坎帕尼亚等人
🔥首先, Campagna 等人 提出了一种合成面向目标的对话的方法,作为对话状态跟踪(DST)任务的附加训练数据。作者创建了一个抽象模型(人们也可以将其命名为本体,它定义了基本状态、动作和转换。为什么这很酷:1️⃣该模型可以应用于各种领域,如餐厅预订或火车连接搜索与任何插槽和价值;2️⃣合成数据允许在监督数据非常有限的领域进行零发射传输。3️⃣事实上,实验表明,仅使用和合成的语料库进行训练(并在真实的 MultiWoz 2.1 测试上进行评估)达到了原始完整训练集的大约 2/3 的准确度💪
我相信这种方法可以作为一种通用的数据扩充实践,用于开发特定领域的对话系统,或者用于有限的带注释的训练数据。

当新的基于朋友的数据集到达时
针对对话中的关系抽取, 于等人 开发了dialoge,一个新的数据集,由来自朋友的约 2k 个对话中的 36 个关系组成。虽然这些关系没有用维基百科或 URIs 数据库进行注释,但即使对伯特来说,数据集仍然是一个相当大的挑战。此外,作者提出了一个新的度量标准,它显示了一个系统需要多少回合来提取某个关系。
OpenDialKG 是 ACL 2019 年最佳论文奖提名者之一,因为他在新的数据集中促进了对话系统中基于图形的推理。 周等人 在他们新的适合中国人的 KdConv 数据集上很好地采用了 OpenDialKG 的主要思想👏
还有一系列研究如何将外部知识融入端到端对话系统的作品。如果你的背景知识表示为文本三元组或表格单元格(甚至是纯文本),那么 林等人 建议使用 Transformer 作为知识编码器,而 秦等人 则依靠记忆网络式编码器。如果你有像 ConceptNet 这样的常识 KG, 张等人 从话语中提取概念构建局部图,然后采用编码器对对话的“中心概念”进行编码,这将影响解码器。如果你对更近期的康威产品感兴趣,一定要查看康威工厂的 NLP 会议记录,该工厂与 ACL 位于同一地点(实际上)!
信息抽取:OpenIE 和链接预测
如果您的工作恰好是从原始文本文档构建 kg,那么您可能已经知道 OpenIE 是一个事实上的标准。正如我们在前面章节中看到的,像 OpenIE4 或 OpenIE 5 这样的基于规则的框架仍然在被积极地使用。也就是说,提高 OpenIE 提取的质量可以缓解 KG 构建中的许多问题。小注意:打开 IE 后获得的 kg 也叫打开 kg。
**Kolluru 等人 提出生成式 OpenIE 方法, IMoJIE(基于迭代记忆的联合信息提取)。受 CopyAttention 范式的启发,作者提出了一种迭代生成 seq2seq IE 算法:在每次迭代中,原始序列与先前提取的序列连接,并通过 BERT 获得最终嵌入。然后,具有复制和注意机制的 LSTM 解码器负责生成新的提取(例如,包含三元组的记号)。🤖为了进一步改进训练集,作者将 OpenIE 3、OpenIE 4 和其他系统的输出汇总并排序为“银标签”以供生成。
虽然架构看起来非常简单,但是确实带来了显著的改进📈与现有基线相比。消融研究报告称,BERT 对整体质量至关重要,因此我假设可以通过插入更大的变压器或使用特定领域的预训练 LM 来进一步提高质量,例如,如果您的文本来自法律或生物医学领域。**

来源: Kolluru 等人
虽然在类似 RDF 的 kg 上的链接预测(LP)已经有了良好的记录和几个里程碑,但我们不能说开放 kg 上的 LP 也是如此。

来源:
但是现在我们可以了!🤩 Broscheit 等人 定义了开放链接预测的任务,给出了开放 kg 的挑战:
- 给定一个('主题文本','关系文本',?)查询,系统必须预测真实的、新的、不能被平凡解释的事实。
- 然而,没有实体或关系 URIs 可用,将许多表面形式绑定到一个表示。
- 尽管如此,同一实体或关系的各种表面形式可能构成测试集泄漏,因此必须仔细构建和清理测试集。
作者提出了如何构建和清理数据集的方法、评估协议和基准本身。 OLPBench 是具有 KG 嵌入的 LP 的最大数据集之一:它包含 3000 万个三元组,100 万个不同的开放关系,以及 80 万个唯一实体的 250 万个提及👀。在实验中,作者使用了 ComplEx,其中多标记提及通过 LSTM 进行聚合。公开 LP 任务结果是非常困难😯:即使强大的 768d 复合体也仅产生 3.6 个 MRR,1 时 2 次命中,10 时 6.6 次命中。
显然,这是一个非常具有挑战性的数据集:非常有趣的是,看到这些方法不仅可以扩展到如此大的图形,还可以将性能提高到类似 FB15k-237 的数字(仅供参考,目前大约是 35 个 MRR 点和 55 次点击@10)。
顺便说一句,如果你对从文本中构建知识更感兴趣,我鼓励你查看最近的 AKBC 2020 会议的记录,这次会议吸引了一大批演讲者和出版物👏
结论
今年在 ACL'20 上,我们看到了更少的 KG 增强语言模型(但我们确实看到了设计用于表格的 TaPas 和 TABERT ),可能 NER 也少了一些。另一方面,图形到文本的 NLG 正在崛起!亲爱的读者,你还是坚持到了最后,你应该得到一些掌声:)

请在评论中让我知道你喜欢什么,哪些地方需要改进。感谢阅读,敬请关注更多出版物😌
基于回答集编程的知识表示和推理
..或者为什么企鹅不应该飞。
阅读声明式编程和命令式编程的区别,并从代码示例(答案集编程、Python 和 C)中学习。

企鹅“罗杰”——有点无聊,因为他不会飞。(图片由 Unsplash 上的 66 北拍摄)
介绍
在工业和科学领域,计算问题的数量似乎是无限的。对来自大量可用数据的新见解有着巨大的需求。为了获得这些知识,专门的人使用各种编程语言来设计和实现算法。
然而,当前现实世界中的许多问题都是复杂的(组合)搜索问题,我们试图用这些问题来自动化和优化流程,并支持人们的决策。这不涉及算法的编码,而是给定知识的编码。换句话说,给定关于所有要考虑的规则和约束的知识,什么才算解决方案。声明性编程表达其逻辑,而不是编写描述计算控制流的语句。我们想要实现什么,而不是关于我们如何实现它的陈述。
这被称为声明式编程。
为什么是声明式编程?
使用一种有前途的声明性编程范例,即回答集编程(ASP,有时也称为回答集 Prolog),比流行的命令式编程方法提供了意想不到的优势,例如:
- 简短解决方案(以代码行数衡量)
- 透明度(包括可读性)
- 可靠性
还有很多。一旦你把问题分解成最小的部分,写下所有必要的知识,你不仅解决了计算的挑战。一个很大的优势是,你已经将知识数字化,可以用它来解决进一步的问题,或者以其他方式利用它。
E 经验和知识可持续地获得并防止损失(例如,通过员工退休或解雇)。
此外,它加强了“业务人员”和程序员之间的合作。人工智能的整合得到支持,各个层面的接受度都会提高。这是一个基本的过程,只有在公司所有部门的合作下才能实现。
什么是 ASP,它是如何工作的?
答案集程序由以事实、规则(head(X) :- body(X).)或约束形式表达的给定知识组成。该程序由求解器加载,并返回一个“稳定模型”。这个所谓的答案集由所有可以使用给定的规则和约束导出的事实组成。生成有限数量的稳定模型作为解,最终选择其中的一个。
注意: 接地及解决问题不在本文讨论范围内。
让我们从逻辑学的角度考虑一个关于鸟类和企鹅的著名例子。众所周知,鸟会飞。这可以编码为 answert 集合规则:
canFly(X) :- bird(X).
规则读作“如果 *X* 是鸟,那么 *X* 可以飞”。现在我们来补充更多的知识!例如,事实告诉无条件的真理,就像海鸥'马尔文'是一只鸟,但企鹅'罗杰'也是一只。
canFly(X) :- bird(X).
bird(malvin).
bird(roger).== MODEL OUTPUT ==
Anwer: 1
bird(malvin) bird(roger) canFly(malvin) canFly(roger)
SATISFIABLE
因此,答案集告诉我们已知的事实,马尔文和罗杰是鸟类,但也得出结论,他们能够飞行。我们当中的生物学爱好者知道,企鹅不会飞,因此模型是错误的!

海鸥‘马尔文’——稍微炫耀一下,因为他会飞。(照片由菲尔·博塔在 Unsplash 上拍摄)
为了得到可接受的结果,我们需要以事实和完整性约束的形式向程序添加更多的知识。在这里,模型需要知道罗杰不仅是一只鸟,也是一只企鹅,而且没有一只企鹅会飞。
canFly(X) :- bird(X).
bird(malvin).
bird(roger).
seagull(malvin).
penguin(roger).
:- canFly(X), penguin(X).== MODEL OUTPUT ==
UNSATISFIABLE
这并没有带来预期的结果,并显示了彻底和非常仔细地思考问题以及解决方案是多么重要。这个模型告诉我们,就像程序员所说的,一只鸟可以飞,但是对于企鹅家族的鸟却没有任何建议。为了避免这一点,我们可以补充说,只有不是企鹅的鸟才能飞。
canFly(X) :- bird(X), not penguin(X).
bird(malvin).
bird(roger).
seagull(malvin).
penguin(roger).
:- canFly(X), penguin(X).== MODEL OUTPUT ==
Answer: 1
bird(malvin) bird(roger) seagull(malvin) penguin(roger) canFly(malvin)
SATISFIABLE
在第1行中添加这个 knwoledge,稳定模型由预期结果组成。
命令式编程与声明式编程
..解决数独游戏
让我们看另一个例子来突出上面提到的 ASP 的优点。数独是一个众所周知的益智游戏,流行解释搜索问题。给定一个包含 1 到 9 之间的数字或空格的初始 9x9 网格,所有空格都必须用数字填充。如果您找到所有的值,使得每一行、每一列和每一个 3×3 的子方块都包含数字 1-9,并且每个数字只出现一次,那么您就赢得了 Sudoko。

典型的数独游戏(摘自 Potassco.org)。
Python(命令式)
下面的代码片段将展示如何用 Python 解决数独问题。
用 Python 解数独。
c(命令式)
用 C 解决数独游戏看起来和 Python 很像。方法上没有明显的区别。
用 c 语言解数独。
Python 和 C 都显示了描述计算的控制流的书面语句,因此,'如何求解',以及如何为即将到来的步骤改变状态。
ASP(声明性)
最后但同样重要的是,让我们看看 ASP 代码片段——初始化后,我们能够用不到 10 行代码解决的数独游戏!
% Initialize the game (given numbers)
sudoku(1, 1, 5).
sudoku(1, 2, 3).
sudoku(1, 5, 7).
sudoku(2, 1, 6).
sudoku(2, 4, 1).
sudoku(2, 5, 9).
sudoku(2, 6, 5).
sudoku(3, 2, 9).
sudoku(3, 3, 8).
sudoku(3, 8, 6).
sudoku(4, 1, 8).
sudoku(4, 5, 6).
sudoku(4, 9, 3).
sudoku(5, 1, 4).
sudoku(5, 4, 8).
sudoku(5, 6, 3).
sudoku(5, 9, 1).
sudoku(6, 1, 7).
sudoku(6, 5, 2).
sudoku(6, 9, 6).
sudoku(7, 2, 6).
sudoku(7, 7, 2).
sudoku(7, 8, 8).
sudoku(8, 4, 4).
sudoku(8, 5, 1).
sudoku(8, 6, 9).
sudoku(8, 9, 5).
sudoku(9, 5, 8).
sudoku(9, 8, 7).
sudoku(9, 9, 9). % define the grid
n(1..9).
x(1..9).
y(1..9).% each field contains exactly one number from 1 to 9
{sudoku(X,Y,N): n(N)} = 1 :- x(X) ,y(Y).% helper
subgrid(X,Y,A,B) :- x(X), x(A), y(Y), y(B),(X-1)/3 == (A-1)/3, (Y-1)/3 == (B-1)/3.% constraints
:- sudoku(X,Y,N), sudoku(A,Y,N), X!=A.
:- sudoku(X,Y,N), sudoku(X,B,N), Y!=B.
:- sudoku(X,Y,V), sudoku(A,B,V), subgrid(X,Y,A,B), X != A, Y != B.#show sudoku/3.== MODEL OUTPUT ==
Answer: 1
('sudoku', (2, 1, 6)), ('sudoku', (1, 2, 3)), ('sudoku', (9, 4, 2)), ('sudoku', (7, 2, 6)), ('sudoku', (7, 3, 1)), ('sudoku', (1, 9, 2)), ('sudoku', (5, 1, 4)), ('sudoku', (7, 4, 5)), ('sudoku', (4, 3, 9)), ('sudoku', (9, 1, 3)), ('sudoku', (4, 5, 6)), ('sudoku', (5, 6, 3)), ('sudoku', (2, 4, 1)), ('sudoku', (8, 1, 2)), ('sudoku', (8, 8, 3)), ('sudoku', (7, 9, 4)), ('sudoku', (8, 7, 6)), ('sudoku', (5, 4, 8)), ('sudoku', (7, 6, 7)), ('sudoku', (8, 6, 9)), ('sudoku', (6, 5, 2)), ('sudoku', (9, 7, 1)), ('sudoku', (3, 4, 3)), ('sudoku', (4, 7, 4)), ('sudoku', (3, 3, 8)), ('sudoku', (4, 8, 2)), ('sudoku', (1, 7, 9)), ('sudoku', (9, 9, 9)), ('sudoku', (9, 8, 7)), ('sudoku', (5, 9, 1)), ('sudoku', (4, 4, 7)), ('sudoku', (6, 9, 6)), ('sudoku', (7, 7, 2)), ('sudoku', (2, 7, 3)), ('sudoku', (5, 5, 5)), ('sudoku', (1, 5, 7)), ('sudoku', (1, 1, 5)), ('sudoku', (6, 3, 3)), ('sudoku', (2, 6, 5)), ('sudoku', (2, 9, 8)), ('sudoku', (8, 3, 7)), ('sudoku', (3, 6, 2)), ('sudoku', (3, 8, 6)), ('sudoku', (2, 8, 4)), ('sudoku', (1, 3, 4)), ('sudoku', (8, 2, 8)), ('sudoku', (3, 7, 5)), ('sudoku', (9, 5, 8)), ('sudoku', (4, 9, 3)), ('sudoku', (6, 4, 9)), ('sudoku', (7, 5, 3)), ('sudoku', (2, 5, 9)), ('sudoku', (8, 5, 1)), ('sudoku', (5, 3, 6)), ('sudoku', (4, 6, 1)), ('sudoku', (3, 9, 7)), ('sudoku', (1, 4, 6)), ('sudoku', (9, 2, 4)), ('sudoku', (5, 8, 9)), ('sudoku', (1, 8, 1)), ('sudoku', (6, 6, 4)), ('sudoku', (5, 7, 7)), ('sudoku', (7, 1, 9)), ('sudoku', (3, 5, 4)), ('sudoku', (6, 8, 5)), ('sudoku', (5, 2, 2)), ('sudoku', (2, 3, 2)), ('sudoku', (8, 9, 5)), ('sudoku', (9, 6, 6)), ('sudoku', (9, 3, 5)), ('sudoku', (6, 2, 1)), ('sudoku', (3, 1, 1)), ('sudoku', (4, 2, 5)), ('sudoku', (6, 1, 7)), ('sudoku', (4, 1, 8)), ('sudoku', (8, 4, 4)), ('sudoku', (2, 2, 7)), ('sudoku', (3, 2, 9)), ('sudoku', (1, 6, 8)), ('sudoku', (6, 7, 8)), ('sudoku', (7, 8, 8))}
SATISFIABLE
注意 :例如,使用一个 ASP 的 Python 包装器,结果看起来就像上面的代码示例一样方便。
与 Python 和 C 语言相比,这完全是关于“是什么”而不是“怎么做”——这是两种方法之间的根本区别。
在最开始,我们定义数独板是 9x9 的单元(或区域),我们使用数字 1 到 9 作为填充值。遵循每个字段只能填写 1 到 9 之间的一个数字的基本规则,我们定义了一个小助手。它说明哪些字段引用同一个子网格。最后,我们只需要约束来告诉求解器什么是可能的,什么是不可能的。第一行检查选择的数字在列中是否唯一,而第二个约束检查行的规则。第三个约束完善了游戏规则,根据该规则,一个数字在子网格中也必须是唯一的。
就这样。我承认语法需要时间来适应。但是一旦你熟悉了它,你就能创造出非常易读的程序,为我们解决高度复杂的问题。
摘要
在知识表示和推理领域,ASP 是一个非常有前途的知识保存和声明性问题解决工具。
简短的解决方案 —除了最初绘制数独游戏的努力之外,ASP 还提供了迄今为止最短的解决方案(以代码行数衡量)。
—无需创建用户不清楚的规则,也无需创建与程序状态相关的规则。只有游戏的基本条件和三个规则必须被编码,才能得到正确的结果。
这在给出的例子中可能并不重要,但在许多工业应用中却是一个主要问题。
仅举几个现实世界的例子,美国国家航空航天局的航天飞机决策支持、瑞士的火车调度(世界上最密集的火车网络之一)或地中海沿岸最大的转运站的团队建设都是其潜力的证明。
结果
人工智能在工业界的接受度还是很低的。此外,许多公司被现有的海量数据淹没了。
将运营主题专家的知识与人工智能的优势结合在一起。
ASP 为数字化和保护现有知识提供了独特的机会。由于良好的可读性和对流程以及要解决的问题的必要理解,IT 和业务走得更近,从而获得更好和更可持续的成功。
你喜欢这个故事吗?
我很欣赏这篇文章的点赞和转发——很快会有更多关于这个话题的内容!您还可以在此处找到执行摘要。
自我监督学习中的知识转移
自我监督学习是一个有趣的研究领域,其目标是在没有任何人工注释的情况下从无标签数据中学习丰富的表示。
这可以通过创造性地公式化一个问题来实现,比如你使用数据本身的一部分作为标签,并试图预测它。这样的公式被称为借口任务。
例如,您可以设置一个托词任务,在给定灰度版本的情况下预测图像的彩色版本。同样,您可以移除图像的一部分,并训练一个模型从周围环境中预测该部分。还有很多这样的借口任务。

作者图片
通过在借口任务上的预训练,希望模型将学习有用的表示。然后,我们可以对模型进行微调,以完成下游任务,如图像分类、对象检测和语义分割,只需一小组已标记的训练数据。
评估表示的挑战
所以借口任务可以帮助我们学习表征。但是,这提出了一个问题:
如何确定一个有学问的表征有多好?
目前,衡量表示的标准方法是在一组标准任务和基准数据集上进行评估。
- 线性分类:使用冻结特征的图像网络分类
- 低数据状态:仅使用 1%到 10%数据的 ImageNet 分类
- 迁移学习:PASCAL VOC 上的对象分类、对象检测和语义分割
我们可以看到,上述评估方法要求我们对借口任务和目标任务使用相同的模型架构。

作者图片
这带来了一些有趣的挑战:
- 对于借口任务,我们的目标是在大规模的未标记数据集上学习,因此更深的模型(例如 ResNet)将帮助我们学习更好的表示。
- 但是,对于下游任务,我们更喜欢实际应用的浅层模型(例如 AlexNet)。因此,我们目前在设计借口任务时必须考虑这一限制。
- 如果一些方法使用更简单的架构,而另一些方法使用更深入的架构,那么就很难公平地比较哪种前文本任务更好。
- 我们无法将从托词任务中学到的表征与手工制作的特征(如 HOG)进行比较。
- 我们可能希望在借口任务中利用几个数据域,如声音、文本和视频,但目标任务可能会限制我们的设计选择。
- 在托词任务上训练模型可能学到对一般视觉识别没有用的额外知识。目前,最终的特定于任务的层被忽略,并且仅取特定卷积层的权重或特征。
知识转移
Noroozi 等人在 2018 年的论文“通过知识转移促进自我监督学习”中提出了一个简单的想法来解决这些问题。
直觉
作者观察到,在一个好的表示空间中,语义相似的数据点应该靠得很近。

作者图片
在常规的监督分类中,图像语义相似的信息通过由人标注的标签来编码。在这种标签上训练的模型将具有对语义相似的图像进行分组的表示空间。
因此,对于自我监督学习中的文本前任务,目标是隐含地学习使相同类别图像相似而不同类别图像不相似的度量。因此,如果我们能够以某种方式将语义相关的图像编码到相同的标签,我们可以提供对所学习的表示的鲁棒估计。
总体框架
作者提出了一个新的框架,将知识从深度自我监督模型转移到一个独立的浅层下游模型。您可以为借口任务和下游任务使用不同的模型架构。
关键创意:
对来自托词任务的特征进行聚类,并分配聚类中心作为未标记图像的伪标记。然后,在伪标签上重新训练具有目标任务架构的小网络,以预测伪标签并学习新颖的表示。
端到端流程描述如下:
1.借口任务

照片来自诺鲁齐等人
在这里,我们选择一些深度网络架构,并在一些数据集上根据我们选择的一些借口任务来训练它。在模型被训练之后,我们可以从一些中间层提取特征。
2.k 均值聚类

照片来自诺鲁齐等人
对于数据集中所有未标记的图像,我们从借口任务模型计算特征向量。然后,我们运行 K-means 聚类来分组语义相似的图像。其想法是,聚类中心将与 ImageNet 中的类别保持一致。
在论文中,作者在一个 Titan X GPU 上运行 K-means 4 小时,将 130 万张图像聚类成 2000 个类别。
3.伪标记

照片来自诺鲁齐等人
聚类中心被视为伪标签。我们可以使用与上述步骤相同的数据集,也可以使用不同的数据集本身。然后,我们计算这些图像的特征向量,并为每个图像找到最近的聚类中心。该聚类中心被用作伪标签。
4.伪标签训练

照片来自诺鲁齐等人
我们采用将用于下游任务的模型架构,并训练它将未标记的图像分类到伪标记中。因此,目标架构将学习新的表示,使得它将在预训练的特征空间中最初接近的图像映射到接近点。
知识转移的优势
我们看到了如何通过对特征进行聚类,然后使用伪标签,我们可以将来自任何借口任务表示的知识带入像 AlexNet 这样的公共参考模型。
因此,我们现在可以轻松地比较不同的托辞任务,即使它们使用不同的体系结构和不同的数据域进行培训。这也允许我们通过使用深度模型和挑战借口任务来改进自我监督的方法。
这个框架的效果如何?
为了定量评估这一想法,作者进行了如下实验:
a.增加借口任务的复杂性(Jigsaw++)
为了评估他们的方法,作者进行了一项名为“拼图”的古老的类似拼图的借口任务,其中我们需要预测用于随机洗牌 3*3 正方形图像网格的排列。

照片来自诺鲁齐等人
他们通过在一些随机位置用另一张随机图像的瓷砖随机替换 0 到 2 个瓷砖来扩展这项任务。这增加了难度,因为现在我们需要仅使用剩余的补丁来解决问题。新的托辞任务被称为“Jigsaw++”。

照片来自诺鲁齐等人
在论文中,他们使用了 701 个最小汉明距离为 3 的排列。它们在每个图像块上独立地应用平均值和标准偏差归一化。他们还使图像在 70%的时间内灰度化,以防止网络用低级统计数据作弊。
b.使用更深层次的网络来解决借口任务
作者使用 VGG-16 解决借口任务和学习表征。随着 VGG-16 的容量增加,它可以更好地处理“拼图++”任务的复杂性增加,从而提取更好的表示。
c.将知识传回 AlexNet
来自 VGG-16 的代表被聚类,聚类中心被转换成伪标签。然后,训练 AlexNet 对伪标签进行分类。
d.在评估数据集上微调 AlexNet
对于下游任务,用来自伪标签分类的权重初始化 AlexNet 模型的卷积层,并且随机初始化完全连接的层。然后,预训练的 AlexNet 在各种基准数据集上进行微调。
e.结果
使用像 VGG-16 这样的更深层次的网络会导致更好的表示和伪标签,也会在基准测试任务中产生更好的结果。它在 2018 年的几个基准测试中获得了最先进的结果,并进一步缩小了监督和自我监督方法之间的差距。
1.PASCAL VOC 的迁移学习
作者在 PASCAL VOC 2007 数据集上测试了他们的方法,并在 PASCAL VOC 2012 数据集上测试了他们的方法。
洞察力
- 用 VGG16 训练 Jigsaw++并使用 AlexNet 预测聚类给出了最好的性能。
- 切换到具有挑战性的托词任务“Jigsaw++”比“Jigsaw”提高了性能。
- 在 Jigsaw++和下游任务中使用相同架构 AlexNet 时,知识转移不会产生显著影响。
2.ImageNet 上的线性分类
在这种情况下,线性分类器在不同的卷积层上根据从 AlexNet 提取的特征进行训练。对于 ImageNet,使用 VGG-16 并使用聚类将知识转移到 AlexNet 会带来 2%的大幅提升。

照片来自诺鲁齐等人
3.ImageNet 上的非线性分类
对于非线性分类器,使用 VGG-16 并使用聚类将知识转移到 AlexNet 会在 ImageNet 上给出最佳性能。

照片来自诺鲁齐等人
论文中的其他见解
1.集群数量如何影响性能?
网络不会受到集群数量的显著影响。作者测试了 AlexNet 在对象检测任务中对来自不同数量集群的伪标签进行的训练。

照片来自诺鲁齐等人
2.这和知识蒸馏有什么不同?
知识转移与知识升华有着本质的不同。这里,目标是只保留来自表示的图像的聚类关联,并将其转移到目标模型。不像蒸馏,我们不对老师的确切输出做任何回归。
3.你能在聚类和预测伪标签中使用不同的数据集吗?
是的,这种方法很灵活,你可以在一个数据集上进行预训练,在另一个数据集上进行聚类,并为第三个数据集获取伪标签。
作者做了一个实验,他们在 ImageNet 的表示上训练聚类,然后在“位置”数据集上计算聚类中心,以获得伪标签。对象分类的性能仅略有下降(-1.5%)。

照片来自诺鲁齐等人
结论
因此,知识转移是一种简单而有效的方式来将表示从深层模型映射到浅层模型。
参考
- Mehdi Noroozi 等人,“通过知识转移促进自我监督学习”
- Mehdi Noroozi 等人,“通过解决拼图游戏对视觉表征的无监督学习”
- 景岛乐·冈野原等,“一个带有伪否定样本的判别性语言模型”
原载于 2020 年 10 月 4 日 https://amitness.com**。
已知操作员学习—第 1 部分
FAU 讲座笔记关于深度学习
不要重新发明轮子

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行
欢迎回到深度学习,所以今天,我想和你们谈谈关于我们如何重用先前的知识并将其整合到深度网络中的想法。这实际上是我们在一个由欧洲研究委员会资助的大型研究项目中一直在做的事情,我想这些想法也会让你感兴趣。

什么是已知算子学习?来源;推特。图像在下 CC 乘 4.0
所以,我决定把他们包括在讲座中。这就把我们带到了已知算子学习的话题。已知算子学习是一种非常不同的方法,因为我们试图重用我们已经拥有的关于问题的知识。因此,我们必须学习更少的参数。这与我们从传统深度学习中了解的情况形成了鲜明对比。如果你说这么传统的深度学习,那么我们往往试图从数据中学习一切。现在,我们想从数据中了解一切的原因当然是因为我们对网络实际上应该是什么样子知之甚少。因此,我们试图从数据中学习一切,以消除偏见。特别是对于感知任务来说,我们对人类如何解决问题知之甚少。对我们来说,人脑在很大程度上是一个黑盒,我们试图找到一个匹配的黑盒来解决问题。

强化学习允许类似放射科医生的标志检测。图片由 Florin Ghesu 提供。
我从 Florin Ghesu 那里拿来了这个例子,你记得,我已经在简介中展示过了。这里,我们有这种强化学习类型的方法,然后我们通过强化学习来激励我们对身体器官的搜索。我们查看图像中的小块,然后决定下一步移动到哪里,以接近特定的地标。因此,我们可以在这里介绍我们如何解读图像,或者放射科医师如何解读图像,以及他将如何走向某个标志。当然,我们有这种多尺度的方法。当然,我们这样做的主要原因是,因为我们不知道大脑实际上是如何工作的,也不知道放射科医生实际上在想什么。但是我们至少可以模仿他的工作方式来处理这个问题。嗯,但是一般来说并不是所有的问题都是这样。深度学习如此受欢迎,以至于它被应用于许多许多不同的问题,而不是感知任务。

在图像重建中,我们有很多关于这个问题的先验知识。来自深度学习讲座的 CC BY 4.0 下的图片。
例如,人们一直用它来模拟 CT 重建。因此,这里的问题是,你有一组投影数据显示在左边,你想重建切片数据显示在右手边。

CT 还能让书不打开就可读。使用 gifify 创建的图像。来源: YouTube 。
这个问题已经研究得很透彻了。自 1917 年以来,我们已经知道这个问题的解决方案,但是,当然,还有伪像和图像质量等问题,动力学使这个问题变得困难。因此,我们希望找到改进的重建方法。

U-net 也会解决图像重建吗?来自深度学习讲座的 CC BY 4.0 下的图片。
例如,有一个问题叫做有限角度问题。如果我们只旋转比如说 120 度,而不是完全旋转,你会得到像左边这样的切片图像。它们充满了伪像,你几乎看不到图像上显示的内容。我们在右边有匹配的切片图像。如果你看右边的图片,你可以看到这是一个贯穿躯干的切口。它展示了肺,展示了心脏,展示了脊柱,以及前面的肋骨。我们在左边的图像中几乎看不到肋骨和脊柱,但是我们有方法可以完成图像到图像的转换。我们已经看到,我们甚至可以用它来修补图像中缺失的信息。那么为什么不直接用它来完成重建呢?这实际上已经做到了。

初步结果令人印象深刻。 CC 下的图片来自深度学习讲座的 4.0 。
我可以给你看一个结果。所以,这确实有效。这是为一个看不见的人做的。所以,这是用另外 10 个人的切片训练的,在第 11 个人的切片上进行评估。所以,这个人从来没有被见过,你可以看到它很好地重建了肋骨,躯干,胸壁在输入图像中几乎看不到。我们在这里也可以看到一个非常好看的外观。所以,这很酷。但是说实话:这是医学图像。人们在这上面做诊断。

让我们尝试在数据中隐藏一个模拟病变(红色箭头)。左图显示全扫描,右图显示网络输入。 CC 下的图片来自深度学习讲座的 4.0 。
所以,让我们来测试一下,隐藏一个损伤。所以,我们把它放在胸壁这里,这有点意思,因为这正是我们图像质量最差的地方。我还在右下角展示了一个放大的视图,所以你可以看到病变就在那里,它的对比度比周围的组织要高得多。现在,如果我给你看这个,你可以看到我们将在右边显示给 U-net 的输入。所以,你可以看到病变在放大的视图中几乎看不见。你可以看到它,但是它有很多人造物品。现在,问题是它会被保留还是会从图像中删除?

病变被正确重建(红色箭头),但也在心脏中引入了一个奇怪的孔(蓝色箭头)。来自深度学习讲座的 CC BY 4.0 下的图片。
嗯,就在那里!你可以看到病变在这里。这很酷,但是你也可以看到蓝色的箭头。以前没有一个洞。所以不知何故,这也有点令人不安。因此,正如你在[4]中看到的,我们实际上研究了更多的细节和鲁棒性。

噪音使整个系统失去平衡,并使胸壁移动约 1 厘米。 CC 下的图片来自深度学习讲座的 4.0 。
我们对这类网络进行了对抗性攻击。最令人惊讶的对抗性攻击实际上是如果你提供泊松噪声,这种噪声实际上会出现在投影数据中。然后,你得到这个。如果我现在前后移动一点,你可以看到胸壁移动了大约 1 厘米。这仍然是一个吸引人的图像,但病变完全消失了,我们所做的唯一的事情是我们在输入数据中添加了一点噪声。当然,它之所以中断这么多,是因为我们从未用噪声进行过训练,网络也从未见过这些噪声模式。这就是它坏掉的原因。

噪音增强有帮助。 CC 下的图片来自深度学习讲座的 4.0 。
因此,如果我们将泊松噪声添加到输入数据中,您也可以看到我们得到了更好的结果。胸壁在它应该在的地方,但是我们的损伤不像以前那么清楚了。老实说,如果你在这上面做医学诊断,那会非常困难,因为你根本不知道文物在哪里,因为文物看起来不再是人造的了。所以你不能很好的认出他们。

局部最小值可以在适当的重建算法中产生。来自深度学习讲座的 CC BY 4.0 下的图片。
顺便说一下,你记得我们在优化过程中必须处理局部极小值。在一次训练中,我们得到了一个可以产生像这样的图像的网络。所以,我们现在调整到病人的背景。你可以看到这种网络开始在病人旁边的空气中画出像肝脏和肾脏这样的器官形状。所以,你可能要考虑一下,在图像重建上进行完全黑盒学习是否是一个好主意。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。
这就是为什么我们下次会谈到一些想法,将先前的知识整合到我们的深层网络中。所以,我希望你喜欢这个视频,我希望能在下一个视频中见到你。拜拜。
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
谢谢
非常感谢 Fu、Florin Ghesu、Yixing Huang Christopher Syben、Marc Aubreville 和 Tobias Würfl 对制作这些幻灯片的支持。
参考
1 Florin Ghesu 等人,《不完整 3D-CT 数据中的鲁棒多尺度解剖标志检测》。医学图像计算和计算机辅助干预 MICCAI 2017 (MICCAI),加拿大魁北克省,2017 年第 194–202 页— MICCAI 青年研究员奖
2 Florin Ghesu 等人,用于 CT 扫描中实时 3D-Landmark 检测的多尺度深度强化学习。IEEE 模式分析与机器智能汇刊。印刷前的 ePub。2018
[3] Bastian Bier 等,用于骨盆创伤手术的 X 射线变换不变解剖标志检测。MICCAI 2018 — MICCAI 青年研究员奖
[4]黄宜兴等.深度学习在有限角度层析成像中鲁棒性的一些研究。MICCAI 2018。
[5] Andreas Maier 等《精确学习:神经网络中已知算子的使用》。ICPR 2018。
[6]托比亚斯·维尔福尔、弗罗林·盖苏、文森特·克里斯特莱因、安德烈亚斯·迈尔。深度学习计算机断层扫描。MICCAI 2016。
[7] Hammernik,Kerstin 等,“一种用于有限角度计算机断层成像重建的深度学习架构。”2017 年医学杂志。施普林格观景台,柏林,海德堡,2017。92–97.
[8] Aubreville,Marc 等,“助听器应用的深度去噪”2018 第 16 届声信号增强国际研讨会(IWAENC)。IEEE,2018。
【9】克里斯托弗·赛本、伯恩哈德·史汀普、乔纳森·洛门、托比亚斯·维尔福、阿恩德·德夫勒、安德烈亚斯·迈尔。使用精确学习导出神经网络结构:平行到扇形波束转换。GCPR 2018。
【10】傅、等.《弗兰基网》2018 年医学杂志。施普林格观景台,柏林,海德堡,2018。341–346.
[11]傅、、伦纳特·胡斯沃格特和斯特凡·普洛纳·詹姆斯·g·迈尔。"经验教训:深度网络的模块化允许跨模态重用."arXiv 预印本 arXiv:1911.02080 (2019)。
已知操作员学习—第 2 部分
FAU 讲座笔记关于深度学习
学习的界限

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行
欢迎回到深度学习!所以,今天我想继续和大家聊聊已知的运营商。特别是,我想向你们展示如何将这些已知的运算嵌入到网络中,以及由此产生了什么样的理论含义。因此,关键词将是“让我们不要重新发明轮子。”

我们已经在这节课的开始讨论了普适近似。 CC 下的图片来自深度学习讲座的 4.0 。
我们一直追溯到我们的通用近似定理。通用逼近定理告诉我们,我们可以找到一个隐藏层表示,它用逼近 U( x )来逼近任何连续函数 u( x ),并且它应该是非常接近的。它被计算为 sigmoid 函数的叠加线性组合。我们知道有一个界限ε下标 u,ε下标 u 告诉我们原始函数和近似函数之间的最大差值,这正好是网络中的一个隐藏层。

能否将普适近似与已知运算结合起来?来自深度学习讲座的 4.0CC 下的图片。
这很好,但是我们对一个隐藏层的神经网络并不感兴趣,对吗?我们会对我们创造的精确学习方法感兴趣。因此,这里的想法是,我们希望将近似器与已知操作混合,并将它们嵌入到网络中。具体来说,我这里的配置对于理论分析来说有点大。所以,我们来看一个稍微简单一点的问题。在这里,我们只是说,好吧,我们有一个两层网络,其中我们有一个从 x 使用 u ( x )的转换。这是一个矢量到矢量的变换。这就是为什么它是黑体的原因。然后,我们有一些变换 g( x )。它接受 u ( x )的输出,并产生一个标量值。这实质上就是 f 的定义( x )。所以在这里,我们知道 f( x )由两个不同的函数组成。所以,这已经是我们研究已知算符学习所需要的第一个假设。

让我们看看这个更简单的例子。 CC 下的图片来自深度学习讲座的 4.0 。
我们现在想近似复合函数。如果我看 f,我们可以看到,有三种方法可以近似它。我们能近似的只有 U ( x )。那么,这会给我们 F 下标 u,我们只能近似 G( x )。这将导致 F 下标 g,或者我们可以近似两者。那就是 G( U ( x ))使用我们的两种近似。现在,对于任何一个近似,我都会引入一个误差。误差可以描述为 e 下标 U,如果我逼近 U ( x )和 e 下标 G,如果我逼近 G( x ),和 e 下标 f,如果我逼近两者。

非线性使我们无法将误差从各自的层中分离出来。来自深度学习讲座的 4.0CC 下的图片。
所以,让我们看看数学,看看我们可以用这些定义做什么。当然,我们可以从 f( x )开始。我们用 f 的定义( x )。然后,定义给我们 g( u ( x ))。我们可以开始逼近 G( x )。现在,如果你在逼近它,我们会引入一些误差,例如,这个误差必须被加回去。这将在下一行显示。我们可以看到,我们也可以使用 G( x )的定义,它是 sigmoid 函数的线性组合。这里,我们使用原始函数 u 下标 j,因为它是一个矢量函数。当然,我们有不同的权重 g 下标 j,偏差 g 下标 0,以及通过逼近 g( x )引入的误差。因此,我们现在也可以按组件来近似 u ( x )。然后,我们引入一个近似,这个近似当然也引入了一个误差。这很好,但我们在这里有点卡住了,因为对 u ( x )的近似误差在 sigmoid 函数内部。其他错误都在外面。那么,我们能做些什么呢?好吧,至少我们可以看看误差范围。

不过,我们可以研究误差范围。 CC 下的图片来自深度学习讲座的 4.0 。
那么,让我们来看看我们的界限。这里的关键思想是,我们使用 sigmoid 函数的性质,它有一个 Lipschitz 界限。这个函数有一个最大斜率,用 l 下标 s 表示,意思是,如果我在位置 x,向 e 方向移动,那么我总能找到一个上界,用 e 的大小乘以函数中的最大斜率,再加上原始函数值。所以,这是一个线性外推,你可以在这个动画中看到。我们实际上有两个白色的圆锥体,它们总是在函数的上方或下方。显然,我们也可以用 Lipschitz 性质构造一个下界。好吧,现在我们能做些什么呢?我们现在可以继续使用它来达到我们的目的,但是我们会遇到下一个问题。我们的 Lipschitz 界限不适用于线性组合。所以,你看到我们实际上感兴趣的是,用这个乘以某个权重,g 下标 j,一旦我取了一个负的 g 下标 j,那么这就意味着我们的不等式翻转了。所以,这并不酷,但我们可以找到一个替代的公式,就像下面这个。因此,当我们乘以 Lipschitz 常数时,我们只需使用绝对值,以便始终保持在函数之上。在这里浏览证明有点乏味。这就是为什么我给你们带来了这两张图片。因此,我们重新表述了这一点,我们把右边的所有项减去,然后把它们移到左边,这意味着所有这些项的组合必须小于零。如果你对正的和负的 g 下标 j 这样做,你可以在两个图中看到,独立于 e 和 x 的选择,I 总是小于零。如果你对这个[5]的正式证明感兴趣,你也可以查阅原始参考文献。

新的界限允许我们将错误提取到同一层。来自深度学习讲座的 CC BY 4.0 下的图片。
现在,让我们利用这个不等式。我们现在可以看到,我们终于可以把 e 下标 uj 从括号中取出来,从 sigmoid 函数中取出来。我们通过使用这种近似得到一个上界。然后,我们可以看到,如果我们正确排列项,前几项只是 F( x )的定义。所以,这是用 G( x )和 U ( x )的近似值。这可以简化为只写下 F( x )。再加上 G( x )的分量之和乘以 Lipschitz 乘以误差的绝对值再加上 G 引入的误差。现在,我们基本上可以减去 F( x ),如果这样做,我们可以看到 f( x ) — F( x )只不过是进行近似时引入的误差。这就是 e 下标 f,我们有 e 下标 f 的误差上界,它是由右边的和组成的。我们仍然可以用ε下标 g 代替 e 下标 g,ε下标 g 是 e 下标 g 的上界,它仍然是 e 下标 f 的上界,现在,这些都是上界。

这个新的误差界限提供了层相关的因素。 CC 下的图片来自深度学习讲座的 4.0 。
同样的想法也可以用来得到一个下界。你会看到,然后我们有这个负和。这永远是一个下限。现在,如果我们有了上限和下限, 然后我们可以看到 e 下标 f 的幅度由分量 G 下标 j 乘以 Lipschitz 常数乘以误差加上ε下标 G 之和决定。这很有趣,因为在这里我们看到这本质上是用 G( x )的结构放大的 U ( x )的误差加上 G 引入的误差。因此, 如果我们知道 u ( x )误差 u 抵消,如果我们知道 g( x )误差 g 抵消,当然,如果我们知道两者,就没有误差,因为我们没有什么要学的。

我们新的误差界符合经典理论。 CC 下的图片来自深度学习讲座的 4.0 。
所以,我们可以看到这个界有这些非常好的性质。如果我们现在将这与经典模式识别联系起来,那么我们可以将 u ( x )解释为特征提取器,将 g( x )解释为分类器。因此,你可以看到,如果我们在 u ( x )中出错,它们可能会被 g( x )放大。这也给了我们一些提示,为什么在经典的模式识别中,人们非常关注特征提取。任何你没有正确提取的特征,都是缺失的。这也是我们深度学习方法的一大优势。我们还可以针对分类优化特征提取。注意,当推导所有这些时,我们需要 Lipschitz 连续性。

也可以找到 deep networks 的版本。来自深度学习讲座的 4.0CC 下的图片。
好吧。现在,你可能会说“这只是两层!”。我们还将此扩展到深层网络。所以,你可以这样做。一旦你有了两层星座,你可以通过递归找到一个证明,也有一个深度网络的界限。然后,你基本上得到了各层的总和,找到了这个上限。它仍然认为是由相应层引入的误差以附加的方式对总误差界限做出了贡献。同样,如果我知道了一层,那部分误差就消失了,总的上界也减小了。我们设法在《自然机器智能》上发表了这篇文章。因此,对于其他研究人员来说,这似乎也是一个有趣的结果。好吧。现在,我们讨论了为什么将已知操作包含到深度网络中是有意义的理论。所以,我们想要重用这些先验知识,这不仅仅是常识,我们实际上可以正式表明,我们正在减少误差范围。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座的 4.0CC 下的图片。
所以在下节课中,我们想看几个例子。然后,您还会看到有多少不同的应用程序实际上使用了它。非常感谢大家的收听,下期视频再见。拜拜。
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
谢谢
非常感谢 Fu、Florin Ghesu、Yixing Huang Christopher Syben、Marc Aubreville 和 Tobias Würfl 对制作这些幻灯片的支持。
参考
1 Florin Ghesu 等人,《不完整 3D-CT 数据中的鲁棒多尺度解剖标志检测》。医学图像计算和计算机辅助干预 MICCAI 2017 (MICCAI),加拿大魁北克省,2017 年第 194–202 页— MICCAI 青年研究员奖
2 Florin Ghesu 等人,用于 CT 扫描中实时 3D-Landmark 检测的多尺度深度强化学习。IEEE 模式分析与机器智能汇刊。印刷前的 ePub。2018
[3] Bastian Bier 等,用于骨盆创伤手术的 X 射线变换不变解剖标志检测。MICCAI 2018 — MICCAI 青年研究员奖
[4]黄宜兴等.深度学习在有限角度层析成像中鲁棒性的一些研究。MICCAI 2018。
[5] Andreas Maier 等《精确学习:神经网络中已知算子的使用》。ICPR 2018。
[6]托比亚斯·维尔福尔、弗罗林·盖苏、文森特·克里斯特莱因、安德烈亚斯·迈尔。深度学习计算机断层扫描。MICCAI 2016。
[7] Hammernik,Kerstin 等,“一种用于有限角度计算机断层成像重建的深度学习架构。”2017 年医学杂志。施普林格观景台,柏林,海德堡,2017。92–97.
[8] Aubreville,Marc 等,“助听器应用的深度去噪”2018 第 16 届声信号增强国际研讨会(IWAENC)。IEEE,2018。
【9】克里斯托弗·赛本、伯恩哈德·史汀普、乔纳森·洛门、托比亚斯·维尔福、阿恩德·德夫勒、安德烈亚斯·迈尔。使用精确学习导出神经网络结构:平行到扇形波束转换。GCPR 2018。
【10】傅、等.《弗兰基网》2018 年医学杂志。施普林格观景台,柏林,海德堡,2018。341–346.
[11]傅、、伦纳特·胡斯沃格特和斯特凡·普洛纳·詹姆斯·g·迈尔。"经验教训:深度网络的模块化允许跨模态重用."arXiv 预印本 arXiv:1911.02080 (2019)。
已知操作员学习—第 3 部分
FAU 讲座笔记关于深度学习
CT 重建再探

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行

我们还能重建四维血流吗?使用 gifify 创建的图像。来源: YouTube 。
欢迎回到深度学习!所以今天,我们想看看已知算子学习的应用,我今天想展示的一个特别的应用是 CT 重建。

CT 重建就是用非常大的稀疏矩阵进行矩阵乘法。 CC 下的图片来自深度学习讲座的 4.0 。
这里,你可以看到 CT 重建问题的正式解决方案。这就是所谓的滤波反投影或 Radon 逆投影。这正是我之前提到的,在 1917 年已经解决的方程。但你可能知道,CT 扫描仪是在 1971 年才实现的。所以实际上,发现这个非常好的解决方案的 Radon 从未见过它付诸实践。那么,他是如何解决 CT 重建问题的呢?CT 重建是一个投影过程。它本质上是一个可以求解的线性方程组。这个解本质上是用卷积和求和来描述的。因此,它是沿检测器方向 s 的卷积,然后是旋转角度θ的反投影。在整个过程中,我们抑制负面价值。因此,我们还会在系统中引入非线性。这些都可以用矩阵符号来表示。因此,我们知道投影操作可以简单地描述为一个矩阵一个,它描述了光线如何与体积相交。有了这个矩阵,你可以简单地将体积乘以 A,这就给出了你在扫描仪中观察到的投影 p。现在,得到重建是你得到投影 p,你需要 A 的某种逆或伪逆来计算它。我们可以看到,有一个解与我们在上面的连续方程中看到的非常相似。所以,我们这里有一个本质上的伪逆,那就是 A 转置次数AA 转置反转次数 p 。现在,你可能会说,你在 a 中看到的反转实际上是滤波器。所以,对于这个特殊的问题,我们知道 A 的逆转置会形成卷积。

为什么不把它映射到神经网络上呢? CC 下的图片来自深度学习讲座的 4.0 。
这很好,因为我们知道如何在深度网络中实现卷积,对吗?矩阵乘法!这就是我们所做的。我们可以将一切映射到神经网络中。我们从左手边开始。我们放入正弦图,也就是所有的投影。我们有一个卷积层来计算过滤后的投影。然后,我们有一个反投影,这是一个完全连接的层,本质上是这个大矩阵 A 。最后,我们有非负约束。所以本质上,我们可以定义一个神经网络,它可以进行精确的滤波反投影。现在,这实际上并不那么超级有趣,因为没什么可学的。我们知道所有这些重量,顺便说一下,矩阵 A 真的很大。对于三维问题,它可以接近高达 65,000 万亿字节的浮点精度内存。所以,你不想实例化这个矩阵。你不想做那件事的原因是它太稀疏了。所以,在 A 中,只有很小一部分元素是真正的连接。这对于 CT 重建来说非常好,因为这样你通常不会实例化 A ,而是简单地使用光线跟踪器计算 A 和 A 转置。这通常在图形板上完成。现在,我们为什么要谈论这些?我们已经看到了 CT 重建不充分的情况,我们基本上可以进行可训练的 CT 重建。

许多关于 CT 的教科书忽略了滤波器离散化和正确填充的主题。来自深度学习讲座的 4.0CC 下的图片。
如果你看一本 CT 书,你已经遇到了第一个问题。如果你按常规实现它,你只是想重建一个圆柱体,仅仅显示这个圆形区域内 1 的值,那么你会想要一个像这样的图像,其中圆柱体内的一切都是 1,圆柱体外的一切都是 0。所以,我们沿着原始切片图像中的蓝线显示这个线图。现在,如果你实现滤波反投影,就像你在教科书上找到的,你会得到一个像这样的重建。典型的错误是你把傅立叶变换的长度选得太短,另一个错误是你没有恰当地考虑离散化。现在,您可以使用它并修复离散化中的问题。所以你现在能做的就是用学习技巧训练正确的过滤器。因此,在经典 CT 课程中,你要做的是运行从连续积分到离散形式的所有数学运算,以计算出正确的滤波器系数。

我们能使用学习技术找到正确的离散化吗?来自深度学习讲座的 CC BY 4.0 下的图片。
相反,我们在这里表明,通过知道它采取卷积的形式,我们可以简单地将我们的逆表示为 p 乘以傅里叶变换,这也是一个矩阵乘法 F 。然后, K 是保存频谱权重的对角矩阵,之后是傅里叶逆变换,这里表示为 F 埃尔米特变换。最后,你反向投影。我们可以简单地把它写成一组矩阵,顺便说一下,这也定义了网络架构。现在,我们实际上可以优化正确的滤波器权重。我们要做的是解决相关的优化问题。这只是让右手边等于左手边,我们选择一个 L2 损失。

反向传播可以自动计算这个梯度。来自深度学习讲座的 4.0CC 下的图片。
你们已经在这门课的很多场合见过了。现在,如果我们这样做,我们也可以手动计算。如果你使用矩阵食谱,然后,你得到以下关于层 K 的梯度。这将是 F 乘以 A 乘以然后在括号中 A 转置 F 埃尔米特我们的对角滤波器矩阵 K 乘以傅立叶变换乘以 p 减去 x 然后乘以 F 乘以 p 转置。所以如果你看看这个,你可以看到这实际上是重建。这是我们网络的前进通道。这是引入的误差。所以,这是我们的灵敏度,如果我们应用我们的损失,我们在网络的末端得到。我们计算灵敏度,然后反向传播到我们实际需要它的层。这是层 K 。然后,我们乘以这个特定层中的激活。如果你还记得我们关于前馈网络的讲座,这就是各自的层梯度。我们仍然可以重复使用很早以前在这节课中学到的数学知识。所以实际上,我们不必经历计算这个梯度的痛苦。我们的深度学习框架将为我们做到这一点。因此,使用反向传播算法可以节省大量时间。

学习的滤波器与正确离散的权重相同。 CC 下的图片来自深度学习讲座的 4.0 。
如果你这么做了会发生什么?当然,在得知神器不见了之后。所以,你可以拿走这件艺术品。这是一个学术上的例子。我们还有一些。

更复杂的 CT 几何形状也可以映射到神经网络。 CC 下的图片来自深度学习讲座的 4.0 。
你可以看到,你也可以用类似的矩阵方程来近似扇束重建。我们现在有了一个额外的矩阵。因此, W 是乘以输入图像中每个像素的逐点权重。 C 现在直接就是我们的卷积矩阵。因此,我们可以用这个方程简单地描述一个扇形束重建公式,当然,我们可以由此产生一个结果网络。

学习 CT 有助于有限的角度伪影。来自深度学习讲座的 4.0CC 下的图片。
现在让我们看看如果我们回到这个有限角度层析成像问题会发生什么。所以,如果你有一个完整的扫描,它看起来像这样。让我们进行一次只有 180 度旋转的扫描。这里,扫描的最小设置实际上是 200 度。所以,我们少了 20 度的旋转。没有我在已知算子学习的介绍中展示的有限角度问题那么强,但这里仍然出现了显著的伪像。现在,让我们将传统的滤波反投影算法作为预训练,并调整权重和卷积。如果你这样做,你会得到这个重建。因此,您可以看到图像质量得到了显著提高。很多藏物都不见了。右手边仍有一些伪像,但图像质量明显更好。现在,你可能会说“好吧,你又在使用黑盒了!”。

学习到的权重可以映射回它们的原始解释,并与其他解决方案进行比较。来自深度学习讲座的 4.0CC 下的图片。
但这实际上并不正确,因为我们的权重可以被映射回原来的解释。我们还有一个滤波反投影算法。这意味着我们可以从我们的网络中读出训练过的权重,并将它们与最先进的进行比较。如果你看这里,我们用所谓的 Parker 权重进行初始化,这是短扫描的解决方案。这里的想法是,相对的射线被分配一个权重,使得测量完全相同的线积分的射线基本上总和为 1。这显示在左手边。在右手边,你找到了我们的神经网络在 2016 年找到的解决方案。所以这是数据最优解。你可以看到它对我们的 Parker weights 产生了重大影响。现在,2017 年 Schä fer 等人发表了一篇如何修复这些有限角度伪影的启发式文章。他们建议增加穿过我们没有观测到的区域的射线的重量。他们只是增加重量,以固定确定性的质量损失。他们的发现看起来更好,但只是一个启发。我们可以看到,我们的神经网络找到了一个非常相似的解决方案,我们可以证明这是数据最优的。所以,你可以在最左边和最右边看到明显的不同。如果你看这里,如果你看这里,你可以看到这些重量,一直到这里和这里。这实际上是探测器的终点。所以,这里和这里是探测器的边界,也是这里和这里。这意味着这里和这里的这些区域没有任何变化。其原因是我们在训练数据中从来没有一个对象可以填满整个检测器。因此,我们也不能在这里反向传播梯度。这就是为什么我们基本上仍然在这些位置进行初始初始化。那很酷。这才是真正的诠释网络。这是真正了解培训过程中发生的事情,对吗?

此外,迭代压缩感知解决方案可以使用深度学习技术来解决。 CC 下的图片来自深度学习讲座的 4.0 。
那么,我们能做得更多吗?是的,甚至还有其他东西,比如所谓的变分网络。这是 Kobler,Pock 和 Hammernik 的工作,他们基本上表明任何类型的能量最小化都可以映射成一种展开的前馈问题。因此,本质上能量最小化可以通过梯度下降来解决。所以,你最终会得到一个你想要最小化的最优化问题。如果你想有效地做到这一点,你可以把它表述为一个递归神经网络。我们是如何处理递归神经网络的?我们打开它们。因此,如果固定迭代次数,任何类型的能量最小化都可以映射到一个前馈神经网络中。这样,你就可以像这里的迭代重建公式或这里的迭代去噪公式一样,进行能量最小化,并计算其梯度。如果你这样做,你将基本上与先前的图像配置减去负梯度方向结束。你这样做,一步一步地重复。

迭代和解析解也可以根据神经网络结合起来。 CC 下的图片来自深度学习讲座的 4.0 。
这里,我们有一个特殊的解决方案,因为我们将它与我们的神经网络重建相结合。我们只是想学习一个图像增强步骤。所以我们所做的是,我们进行神经网络重建,然后连接到前面的层。有 T 条纹或降噪步骤是可训练的。他们使用压缩传感理论。所以,如果你想在这里看到更多的细节,我推荐你参加的一个图像重建课程。如果你仔细观察,你会发现这是一个在稀疏域中压缩图像的想法。这里,我们表明,我们实际上可以学习在稀疏域中表达图像内容的变换,这意味着我们也可以获得这种新的稀疏变换,并在传统的信号处理意义上解释它。

额外的迭代处理在图像质量方面产生了进一步的好处。来自深度学习讲座的 4.0CC 下的图片。
我们来看一些结果。在这里,你可以看到,如果我们采取全扫描参考,我们得到一个真正的无伪影图像。我们的神经网络输出有了我之前展示的这个重建网络的改进,但是它仍然有这些条纹伪影,你可以在右上角看到。在左下方,您可以看到去噪算法的输出,它是三维的。因此,它可以去噪,但仍有条纹问题。你可以看到,在右下角的变分网络中,条纹被抑制了很多。因此,我们实际上学习了一种基于压缩感知思想的变换,以消除这些条纹。一个非常好的神经网络,在数学上精确地模拟了压缩感知重建方法。这太令人兴奋了!

实际上,所有的能量最小化方法都可以映射到神经网络。它们总是产生 ResNet 类型的架构。那么,ResNets 在学习优化未知的能量函数吗? CC 下的图片来自深度学习讲座的 4.0 。
顺便说一下,如果你想到这种能量最小化的想法,那么你也会发现下面的解释:能量最小化和这种展开总是导致一个 ResNet,因为你采取以前的配置减去负梯度方向,这意味着它是以前的层输出加上新层的配置。所以,这实质上意味着 ResNets 也可以用这种方式来表达。它们总是任何能量最小化问题的结果。也可能是最大化。在任何情况下,我们甚至不必知道它是最大化还是最小化,但一般来说,如果你有一个函数优化,那么你总是可以通过一个 ResNet 找到这个优化过程的解。因此,你可以说 ResNets 也适合于为一个完全未知的误差函数寻找优化策略。

在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座的 CC BY 4.0 下的图片。
很有趣,不是吗?关于已知算子学习的这些想法,我还想告诉你一些事情。此外,我们希望看到更多我们可以应用它的应用,也许还希望看到一些关于深度学习和机器学习领域在未来几个月和几年内将如何发展的想法。非常感谢大家的收听,我们在下一段也是最后一段视频中再见。拜拜。
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
谢谢
非常感谢 Fu、Florin Ghesu、Yixing Huang Christopher Syben、Marc Aubreville 和 Tobias Würfl 对制作这些幻灯片的支持。
参考
1 Florin Ghesu 等人,《不完整 3D-CT 数据中的鲁棒多尺度解剖标志检测》。医学图像计算和计算机辅助干预 MICCAI 2017 (MICCAI),加拿大魁北克省,2017 年第 194–202 页— MICCAI 青年研究员奖
2 Florin Ghesu 等人,用于 CT 扫描中实时 3D-Landmark 检测的多尺度深度强化学习。IEEE 模式分析与机器智能汇刊。印刷前的 ePub。2018
[3] Bastian Bier 等,用于骨盆创伤手术的 X 射线变换不变解剖标志检测。MICCAI 2018 — MICCAI 青年研究员奖
[4]黄宜兴等.深度学习在有限角度层析成像中鲁棒性的一些研究。MICCAI 2018。
[5] Andreas Maier 等《精确学习:神经网络中已知算子的使用》。ICPR 2018。
[6]托比亚斯·维尔福尔、弗罗林·盖苏、文森特·克里斯特莱因、安德烈亚斯·迈尔。深度学习计算机断层扫描。MICCAI 2016。
[7] Hammernik,Kerstin 等,“一种用于有限角度计算机断层成像重建的深度学习架构。”2017 年医学杂志。施普林格观景台,柏林,海德堡,2017。92–97.
[8] Aubreville,Marc 等,“助听器应用的深度去噪”2018 第 16 届声信号增强国际研讨会(IWAENC)。IEEE,2018。
【9】克里斯托弗·赛本、伯恩哈德·史汀普、乔纳森·洛门、托比亚斯·维尔福、阿恩德·德夫勒、安德烈亚斯·迈尔。使用精确学习导出神经网络结构:平行到扇形波束转换。GCPR 2018。
【10】傅、等.《弗兰基网》2018 年医学杂志。施普林格观景台,柏林,海德堡,2018。341–346.
[11]傅、、伦纳特·胡斯沃格特和斯特凡·普洛纳·詹姆斯·g·迈尔。"经验教训:深度网络的模块化允许跨模态重用."arXiv 预印本 arXiv:1911.02080 (2019)。
已知操作员学习—第 4 部分
FAU 讲座笔记关于深度学习
深层设计模式

FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。 自己试试吧!如果您发现错误,请告诉我们!
航行

现代听力仪器信号处理管道的简化版本。 CC 下的图片来自深度学习讲座的 4.0 。
欢迎回到深度学习!这就是了。这是最后一堂课。所以今天,我想向你们展示这种已知算子范式的几个更多的应用,以及我认为未来的研究实际上可以去的一些想法。让我们看看我为你准备了什么。我想展示的一件事是简化的现代助听器管道。这是与一家生产助听器的公司的合作,他们通常有一个信号处理管道,其中有两个麦克风。他们收集一些语音信号。然后,通过分析滤波器组运行。这本质上是一个短期傅里叶变换。然后通过定向麦克风来聚焦你面前的事物。然后,您使用降噪来为佩戴助听器的人获得更好的清晰度。随后是自动增益控制,使用增益控制,您可以将频率分析合成为语音信号,然后在助听器内的扬声器上播放。所以,还有一个循环连接,因为你想抑制反馈循环。这种管道,你可以在各种制造商的现代助听器中找到。这里,您可以看到一些例子,所有这些处理的关键问题是降噪。这是困难的部分。所有其他的事情,我们都知道如何用传统的信号处理来解决。但是减少噪音是一个巨大的问题。

整个流水线可以用已知的操作符来表示。这样,我们可以嵌入一个 DNN 来减少噪音。 CC 下的图片来自深度学习讲座的 4.0 。
那么,我们能做什么呢?我们可以将整个助听器管道映射到一个深层网络上。所有这些步骤都可以用微分运算来表示。

实际去噪 DNN 的设置。来自深度学习讲座的 CC BY 4.0 下的图片。
如果我们这样做,我们建立以下大纲。实际上,我们这里的网络并不深,因为我们只有三个隐藏层,但是有 2024 个隐藏节点和 ReLUs。然后,这被用于预测维纳滤波器增益的系数,以便抑制具有特定噪声的信道。这就是设计。我们有来自归一化光谱的 7714 个节点的输入。然后,这是通过三个隐藏层运行。它们与 ReLUs 完全连接,最后,我们有一些 48 通道输出,由产生维纳增益的 sigmoid 产生。

训练数据库概要。 CC 下的图片来自深度学习讲座的 4.0 。
我们在一些数据集上进行了评估,这里我们有 259 个干净的语音信号。然后我们基本上有 48 个非平稳噪声信号,我们混合它们。所以,你可以说我们在这里训练的是一种循环自动编码器。实际上,这是一个去噪自动编码器,因为我们将干净的语音信号加上噪声作为输入,在输出端,我们希望产生干净的语音信号。这是一个例子。

助听器输出的一个例子。音频示例也可以在这里听。来自深度学习讲座的 4.0CC 下的图片。
让我们尝试一个非平稳的噪声模式,这是一个电子钻。另外,请注意,网络之前从未听说过电子演习。这通常会损坏您的助听器,让我们来听听输出。因此,您可以听到非平稳噪声也得到很好的抑制。哇哦。这很酷,当然还有更多应用。

已知的算子也可以用于 X 射线材料分解。使用 gifify 创建的图像。来源: YouTube 。
让我们再考虑一个想法。我们能衍生出网络吗?这里,假设您有一个场景,您以不喜欢的格式收集数据,但您知道数据和投影之间的正式等式。

衍生深度神经网络架构的示例。 CC 下的图片来自深度学习讲座的 4.0 。
我在这里展示的例子是锥束采集。这简直就是典型的 x 射线几何。所以,你拿一个 X 射线,这是典型的锥束几何图形。现在,对于锥束几何,我们可以完全使用这个线性算子来描述它,正如我们在前面的视频中已经看到的。所以,我们可以表达物体 x 我们的几何图形 A 下标 CB 和我们的投影 p 下标 CB 之间的关系。现在,锥束采集不是很好,因为你有放大倍数。所以如果你有一个靠近光源的东西,它会比靠近探测器的物体放大更多。所以,这对于诊断来说不是很好。在 othopedics 中,他们更喜欢平行投影,因为如果你有东西,它会被正交投影,不会被放大。这对诊断非常有用。你会有公制投影,你可以简单地测量投影,它会有和体内一样的大小。因此,这对于诊断来说非常好,但通常我们无法用现有的系统来测量。因此,为了创建这个,你必须创建一个物体的完整重建,从各个角度进行完整的 ct 扫描,然后重建物体并再次投影。通常在整形外科,人们不喜欢切片卷,因为它们太复杂了,难以阅读。但是投影图像看起来更好。我们能做什么?我们知道这里连接两个方程的因子是 x 。所以我们可以简单地求解这个方程,得到关于 x 的解。曾经,我们有 x 和这里的矩阵逆 A 下标 CB 乘以 p 下标 CB。然后,我们只需将其乘以我们的生产映像。但是我们对重建不感兴趣。我们对这张投影图感兴趣。那么,让我们把它代入我们的方程,然后我们可以看到,通过应用这一系列矩阵,我们可以把锥束投影转换成平行束投影。不需要真正的重建。只需要一种中间重建。当然,在这里你不仅仅获得一个单一的投影。你可能想获得一些这样的投影。让我们说三个或四个投影,而不是像 CT 扫描那样的几千个。现在,如果你看这组方程,我们知道所有的运算。所以,这很酷。但是我们这里有这个逆,注意,这又是一种重构问题,一个大矩阵的逆,在很大程度上是稀疏的。所以,我们对这个人的评估还是有问题。这是非常昂贵的,但我们在深度学习的世界里,我们可以假设一些事情。所以,让我们假设这个逆只是一个卷积。所以,我们可以用傅立叶变换,对角矩阵 K 和傅立叶逆变换来代替它。突然,我只估计一个对角矩阵的参数,这使得问题变得简单了一些。我们可以在这个域中解决它,我们可以再次使用我们的技巧,我们已经在这里定义了一个已知的运营商网络拓扑。我们可以简单地用我们的神经网络方法来使用它。我们使用反向传播算法来优化这个家伙。我们只是用其他层作为固定层。顺便说一下,这也可以在非线性公式中实现。记住,一旦我们能够计算出次梯度,我们就可以把它插入我们的网络。所以你也可以做一些非常复杂的事情,比如中值滤波。

迭代的训练过程。 CC 下的图片来自深度学习讲座的 4.0 。
我们来看一个例子。在这种情况下,我们对 MR 投影进行重新归类。我们将在 k 空间中进行采集,这些通常只是平行投影。现在,我们感兴趣的是生成 X 射线和 X 射线的叠加,我们需要来波束几何。所以,我们取几个投影,然后重新组合它们,使之与入射光束的几何形状完全匹配。这里很酷的一点是,我们可以将 MR 和 X 射线的对比结合在一幅图像中。这并不简单。如果您只使用 Ram-Lak 过滤器进行初始化,您将得到以下结果。所以在这个图中,你可以看到绿色的预测和基础事实之间的差异,基础事实或标签显示为蓝色,我们的预测显示为橙色。我们在这里只训练几何图元。所以,我们用圆柱体和一些高斯噪声的叠加来训练,等等。在训练数据集中从来没有任何东西看起来甚至有点像人类,但我们把它应用到拟人化的幻影上。这是为了向您展示该方法的通用性。我们在这里估计很少的系数。这使我们能够非常非常好地概括在训练数据集中从未见过的东西。那么,让我们看看迭代过程中会发生什么。你可以看到过滤器变形,我们正在接近,当然,正确的标签图像在这里。你可以看到的另一件事是,右边的这张图片明显变好了。如果我再进行几次迭代,你可以看到我们真的可以得到清晰锐利的图像。显然,我们也可以不只是查看单个过滤器,而是查看不同平行投影的各个过滤器。

迭代中的多过滤器版本。来自深度学习讲座的 CC BY 4.0 下的图片。
我们现在还可以训练视图相关的过滤器。这就是你在这里看到的。现在,我们为获得的每个不同视图设置了一个过滤器。我们仍然可以显示预测图像和标签图像之间的差异,并再次直接应用于我们的拟人化模型。你也可以看到,在这种情况下,我们得到了很好的收敛。我们训练过滤器,这些过滤器可以联合起来,以产生非常好的影像。

诸如 Frangi 滤波器之类的经典方法也适用于已知的算子学习。 CC 下的图片来自深度学习讲座的 4.0 。
很好,还有其他的东西,我们可以用来作为一种先验知识。在这项工作中,我们基本上采用了一种启发式方法,即 Frangi 提出的所谓的血管性过滤器。你可以看到它所做的处理本质上是卷积。有一个特征值计算。但是如果你看看特征值计算,你可以看到这个中心方程。它也可以表示为一个层,这样我们可以将 Frangi 过滤器的整个计算映射到一个专门的层中。然后,这可以在多尺度方法中训练,并给你一个可训练版本的 Frangi 滤波器。现在,如果你这样做,你可以产生血管分割,它们基本上是受 Frangi 滤波器的启发,但因为它们是可训练的,所以它们产生更好的结果。

通过适当的损耗,我们可以使网络块服务于特定的属性。来自深度学习讲座的 CC BY 4.0 下的图片。
这有点有趣,但你很快就会意识到弗兰基滤波器失败的一个原因是预处理不充分。因此,我们也可以将它与一种预处理网络结合起来。这里的想法是,假设你采用一个 U 型网络或导向过滤网络。同样,引导滤波器或联合双边滤波器可以映射到神经网络层。你可以在这里包括他们,你设计一个特殊的损失。这种特殊的损失不仅仅是优化分段输出,而是将它与某种自动编码器损失结合在一起。因此,在这一层中,您希望预处理后的图像仍然与输入图像相似,但其属性使得使用 8 尺度 Frankie 滤波器的血管分割效果更好。所以,我们可以把它放入我们的网络并训练它。结果,我们得到了血管检测,并且这种血管检测与 U 网相当。现在,U-Net 本质上是一个黑盒方法,但在这里我们可以说“好的,我们有一种预处理网。”顺便说一下,使用导向过滤器,它真的很好。所以,不一定是 U 网。这是一种神经网络调试方法。你可以证明我们现在可以一个模块接一个模块地替换我们的 U-net。在上一个版本中,我们根本没有 U 网,但我们有一个导向滤波器网络和 Frangi 滤波器。这与 U-net 的性能基本相同。所以,这样我们就能模块化我们的网络。为什么要创建模块?原因是模块是可重用的。这里,您可以看到眼科数据的眼部成像数据输出。这是典型的眼底图像。所以这是眼睛背景的 RGB 图像。它显示了血管都穿透视网膜的盲点。视网膜中央凹是视网膜上分辨率最高的地方。现在,通常如果你想分析这些图像,你只需要绿色通道,因为它是对比度最高的通道。我们的预处理网络的结果可以在这里显示。因此,我们获得了显著的噪音降低,但同时,我们也获得了对船只的重视。所以,这在某种程度上改善了血管的显示方式,也保存了精细的血管。

学习的预处理滤波器可以与其他模态一起使用,而不需要微调。 CC 下的图片来自深度学习讲座的 4.0 。
好吧,这很好,但它只对眼底数据有效,对吧?不,我们的模块化表明,如果我们采用这种建模方式,我们能够将滤波器转换为完全不同的模态。这就是现在的光学相干断层血管造影术(OCTA),一种提取眼睛背景的无对比度血管图像的专业模式。您现在可以证明,我们的预处理过滤器可以应用于这些数据,而不需要任何额外的微调、学习或诸如此类的东西。你把这个过滤器应用到人脸图像上,当然,这些图像显示了相似的解剖结构。但是你根本不需要任何关于 OCTA 数据的培训。这是左边的 OCTA 输入图像。中间是我们滤波器的输出,右边是两者的 50%混合。这里是放大的区域,大家可以清楚地看到,看起来像噪声的东西实际上在滤波器的输出中变成了血管。这些是定性的结果。顺便说一下,到目前为止,我们终于也有了定量结果,我们实际上很高兴我们的预处理网络真的能够在正确的位置生产容器。所以,这是一个非常有趣的结果,这向我们展示了我们可以将网络模块化,使它们可以重复使用,而不必训练它们。因此,我们现在可能可以生成无需额外调整和微调即可重组到新网络中的数据块。这真的很酷。

经典的模式识别管道演变成了深度学习。我们能从经典理论中得到启发,并以这种方式创建可重用的模块吗? CC 下的图片来自深度学习讲座的 4.0 。

已知操作员学习的总结。来自深度学习讲座的 CC BY 4.0 下的图片。
我想向你们展示这个概念,因为我认为已知算子学习非常酷。这也意味着你不必扔掉所有你已经学过的经典理论:傅立叶变换和所有处理信号的巧妙方法。他们仍然是非常有用的,他们可以嵌入到你的网络中,而不仅仅是使用正则化和损失。我们已经看到,当我们谈到这个偏差-方差权衡时,这基本上是一种你可以同时减少方差和偏差的方法:你结合了关于这个问题的先验知识。所以,这很酷。然后,你可以创建算法,学习权重,减少参数的数量。现在,我们有了一个很好的理论,它也向我们展示了我们在这里所做的事情是合理的,并且几乎所有最先进的方法都可以被整合。很少有运算找不到次梯度近似。如果你找不到次梯度近似,可能还有其他方法,这样你仍然可以使用它。这使得方法非常有效,可解释,并且您还可以使用模块。所以,那很酷,不是吗?

多棒的一个学期啊! CC 下的图片来自深度学习讲座的 4.0 。
这是我们最后一个视频。所以,我也要感谢你这个令人兴奋的学期。这是我第一次完全以视频的形式来教授这门课。到目前为止,据我所知,反馈普遍非常积极。因此,非常感谢您在途中提供反馈。这也是非常重要的,你可以看到我们在各种场合对讲座进行了改进,包括硬件和内容等等。为此非常感谢你。我从中获得了很多乐趣,我想我将来还会继续做很多事情。所以,我认为这些视频讲座是一种非常酷的方式,特别是,如果你在教一个大班的话。在非电晕的情况下,这门课会有 300 名观众,我认为,如果我们使用像这些录音这样的东西,我们也可以获得一种非常个性化的交流方式。我也可以利用我不在演讲厅的时间安排一些事情,比如问答环节。所以,这很酷。另一件很酷的事情是我们甚至可以做课堂笔记。你们中的许多人一直在抱怨,这门课没有课堂笔记,我说“看,我们让这门课跟上时代。我们包括最新和最酷的话题。制作课堂笔记非常困难。”但实际上,深度学习帮助我们制作课堂笔记,因为有视频记录。我们可以在音轨上使用语音识别,并生成课堂笔记。所以你可以看到我已经开始这样做了,如果你回到旧的录音,你可以看到我已经把链接放到了完整的文字记录中。它们以博客文章的形式发布,你也可以访问它们。顺便说一下,像视频一样,博客帖子和你在这里看到的一切都是使用 4.0 版的知识共享许可的,这意味着你可以自由地重用其中的任何部分,并重新分发和共享它。所以总的来说,我认为这个机器学习领域,特别是深度学习方法,我们现在正在快速发展。我们仍在前进。因此,我认为这些事情和发展不会很快停止,这个领域仍然非常令人兴奋。我也很兴奋,我可以在像这样的讲座中向你们展示最新的东西。因此,我认为仍有令人兴奋的新突破即将到来,这意味着我们将在未来调整讲座,制作新的讲座视频,以便能够融入最新和最伟大的方法。

当然,在研究中你永远不会独行。当今的研究是全球性的! CC 下的图片来自深度学习讲座的 4.0 。
顺便说一下,我在这堂课上给你们展示的东西当然不仅仅是我们小组的。我们吸收了世界各地其他小组的许多不同成果,当然也包括我们在埃尔兰根取得的成果,我们并不孤单,但我们正在一个庞大的国际合作伙伴网络中工作。我认为这是科学需要进行的方式,现在和将来都是如此。我有一些额外的参考。好吧。这学期就这样了。非常感谢您收听所有这些视频。我希望你和他们玩得很开心。嗯,让我想想,我很确定下学期我还会教一个班。所以,如果你喜欢这门课,将来你可能会想加入我们的其他班级。非常感谢,再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。如果你有兴趣从视频讲座中获得文字记录,试试自动博客。
谢谢
非常感谢 Fu、Florin Ghesu、Yixing Huang Christopher Syben、Marc Aubreville 和 Tobias Würfl 对制作这些幻灯片的支持。
参考
1 Florin Ghesu 等人,《不完整 3D-CT 数据中的鲁棒多尺度解剖标志检测》。医学图像计算和计算机辅助干预 MICCAI 2017 (MICCAI),加拿大魁北克省,2017 年第 194–202 页— MICCAI 青年研究员奖
2 Florin Ghesu 等人,用于 CT 扫描中实时 3D-Landmark 检测的多尺度深度强化学习。IEEE 模式分析与机器智能汇刊。印刷前的 ePub。2018
[3] Bastian Bier 等,用于骨盆创伤手术的 X 射线变换不变解剖标志检测。MICCAI 2018 — MICCAI 青年研究员奖
[4]黄宜兴等.深度学习在有限角度层析成像中鲁棒性的一些研究。MICCAI 2018。
[5] Andreas Maier 等《精确学习:神经网络中已知算子的使用》。ICPR 2018。
[6]托比亚斯·维尔福尔、弗罗林·盖苏、文森特·克里斯特莱因、安德烈亚斯·迈尔。深度学习计算机断层扫描。MICCAI 2016。
[7] Hammernik,Kerstin 等,“一种用于有限角度计算机断层成像重建的深度学习架构。”2017 年医学杂志。施普林格观景台,柏林,海德堡,2017。92–97.
[8] Aubreville,Marc 等,“助听器应用的深度去噪”2018 第 16 届声信号增强国际研讨会(IWAENC)。IEEE,2018。
【9】克里斯托弗·赛本、伯恩哈德·史汀普、乔纳森·洛门、托比亚斯·维尔福、阿恩德·德夫勒、安德烈亚斯·迈尔。使用精确学习导出神经网络结构:平行到扇形波束转换。GCPR 2018。
【10】傅、等.《弗兰基网》2018 年医学杂志。施普林格观景台,柏林,海德堡,2018。341–346.
[11]傅、、伦纳特·胡斯沃格特和斯特凡·普洛纳·詹姆斯·g·迈尔。"经验教训:深度网络的模块化允许跨模态重用."arXiv 预印本 arXiv:1911.02080 (2019)。
用考拉和火花进行机器学习
实用指南
有火花后端的熊猫
andas 被认为是用 python 编写的事实上的数据分析库。大多数数据科学家或机器学习工程师在转到其他库之前都是从 Pandas 和 Numpy 开始的。没有一次可以围绕使用 Pandas 作为标准数据处理库展开辩论。使用 Pandas 有很多好处,但是 Pandas API 适应分布式处理的一个关键瓶颈是。像摩丁和达斯克这样的解决方案在一定程度上解决了这个问题。

作者使用 Canva.com 的图片
说到使用分布式处理框架,Spark 是专业人员和大型数据处理中心事实上的选择。最近,Databricks 的团队开源了一个名为考拉的库,用 spark 后端实现了熊猫 API。这个库正在积极开发中,覆盖了超过 60%的熊猫 API。要阅读更多关于使用考拉的内容,请参考我之前的文章激发熊猫的火花:数据布里克的考拉与谷歌实验室。
在本教程中,我将带领您使用 Koalas 和 PySpark 执行探索性数据分析,并使用 Spark 分布式框架构建回归模型。在处理大型数据集时,使用考拉而不是熊猫 API 有很多好处。一些关键点是
- 大数据处理变得简单
- 从熊猫到考拉的快速转变
- 与 PySpark 无缝集成
本教程的目标是利用 Spark 后端,使用考拉完成一个完整的机器学习开发周期。工作中的谷歌合作实验室将被嵌入。
在 Google 联合实验室中设置 Spark 3.0.1
作为第一步,我用 spark 安装配置 google colab 运行时。详细内容,读者可以在 Google Colab om medium 阅读我的文章入门 Spark 3.0.0。
我们将安装以下程序
- Java 8
- 火花-3.0.1
- Hadoop3.2
- Findspark
您可以使用下面的命令集安装最新版本的 Spark。
# Run below commands
!apt-get install openjdk-8-jdk-headless -qq > /dev/null
!wget -q http://apache.osuosl.org/spark/spark-3.0.1/spark-3.0.1-bin-hadoop3.2.tgz
!tar xf spark-3.0.1-bin-hadoop3.2.tgz
!pip install -q findspark
环境变量
安装完 spark 和 Java 之后,设置安装 Spark 和 Java 的环境变量。
import os
os.environ["JAVA_HOME"] = "/usr/lib/jvm/java-8-openjdk-amd64"
os.environ["SPARK_HOME"] = "/content/spark-3.0.1-bin-hadoop3.2"
火花安装试验
让我们在 google colab 环境中测试 spark 的安装。
import findspark
findspark.init()
from pyspark.sql import SparkSession
spark = SparkSession.builder.master("local[*]").getOrCreate()
# Test the spark
df = spark.createDataFrame([{"hello": "world"} for x in range(1000)])
df.show(3, False)/content/spark-3.0.1-bin-hadoop3.2/python/pyspark/sql/session.py:381: UserWarning: inferring schema from dict is deprecated,please use pyspark.sql.Row instead
warnings.warn("inferring schema from dict is deprecated,"
+-----+
|hello|
+-----+
|world|
|world|
|world|
+-----+
only showing top 3 rows
安装考拉
在安装 spark 并确保它正常工作后,我们现在可以使用 pip 安装 databrick 的考拉了。
! pip install koalasRequirement already satisfied: koalas in /usr/local/lib/python3.6/dist-packages (1.2.0)
Requirement already satisfied: numpy<1.19.0,>=1.14 in /usr/local/lib/python3.6/dist-packages (from koalas) (1.18.5)
Requirement already satisfied: matplotlib<3.3.0,>=3.0.0 in /usr/local/lib/python3.6/dist-packages (from koalas) (3.2.2)
Requirement already satisfied: pyarrow>=0.10 in /usr/local/lib/python3.6/dist-packages (from koalas) (0.14.1)
Requirement already satisfied: pandas<1.1.0,>=0.23.2 in /usr/local/lib/python3.6/dist-packages (from koalas) (1.0.5)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib<3.3.0,>=3.0.0->koalas) (2.4.7)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.6/dist-packages (from matplotlib<3.3.0,>=3.0.0->koalas) (0.10.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib<3.3.0,>=3.0.0->koalas) (1.2.0)
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib<3.3.0,>=3.0.0->koalas) (2.8.1)
Requirement already satisfied: six>=1.0.0 in /usr/local/lib/python3.6/dist-packages (from pyarrow>=0.10->koalas) (1.15.0)
Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.6/dist-packages (from pandas<1.1.0,>=0.23.2->koalas) (2018.9)
Requirement already satisfied: pyarrow in /usr/local/lib/python3.6/dist-packages (0.14.1)
Requirement already satisfied: numpy>=1.14 in /usr/local/lib/python3.6/dist-packages (from pyarrow) (1.18.5)
Requirement already satisfied: six>=1.0.0 in /usr/local/lib/python3.6/dist-packages (from pyarrow) (1.15.0)# Install compatible version of pyarrow
! pip install pyarrowimport seaborn as sns/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
import pandas.util.testing as tmimport databricks.koalas as ks
机器学习开发周期
开发机器学习模型的标准做法是执行探索性数据分析,执行特征工程,并建立模型。我将试着用考拉来接触上述观点的基础。我相信大多数 ML 工程师/科学家都使用 Pandas API 来执行 EDA 和特征工程。我演示了如何使用考拉来完成这项工作,并使用 PySpark 来构建模型。
我将使用联合循环发电厂数据集来预测每小时净电力输出(EP)。我已经把数据上传到我的 GitHub 上,这样用户就可以重现结果了。
使用考拉进行探索性数据分析
作为第一步,我想使用考拉 API 探索给定的数据、它的分布和依赖性。我将包括一个简单的例子来演示这个想法,用户可以针对手头的问题扩展它。
下载数据并保存在本地
# Downloading the clustering dataset
!wget -q 'https://raw.githubusercontent.com/amjadraza/blogs-data/master/spark_ml/ccpp.csv'
使用考拉read_csv方法读取数据。要阅读更多关于 API 的内容,请关注考拉官方文档
# Read the iris data
kdf_ccpp = ks.read_csv("ccpp.csv")kdf_ccpp.columnsIndex(['AT', 'V', 'AP', 'RH', 'PE'], dtype='object')kdf_ccpp.head()

就像熊猫一样,考拉也有绘制数据以理解变量的功能。在下面的例子中,我绘制了原始数据和它的平滑版本。这个例子演示了plot和rolling窗口方法的使用
kdf_ccpp['AT'].plot(figsize=(12,6))
kdf_ccpp['AT'].rolling(window=20).mean().plot()
kdf_ccpp['AT'].rolling(window=200).mean().plot()<matplotlib.axes._subplots.AxesSubplot at 0x7f9992f63320>

作者图片:更平滑版本的 AT 特性图
就像上面的绘图一样,用户可以绘制所有的列。参见下面的命令
kdf_ccpp.plot(figsize=(12,6))<matplotlib.axes._subplots.AxesSubplot at 0x7f9993b7e668>

作者图像:原始数据图
使用 20 个数据点的移动平均值绘制所有列。
kdf_ccpp.rolling(window=20).mean().plot(figsize=(12,6))<matplotlib.axes._subplots.AxesSubplot at 0x7f99939bd358>

作者图片:平滑数据图
下面的命令演示了describe的使用,这是一种类似于 Pandas API 中的方法。
kdf_ccpp.describe()

作者图片
特征工程
特征工程步骤通常与 EDA 结合在一起。用户准备特性的目的是获得最具预测性和分布良好的特性集。在本文中,我将演示如何使用考拉来执行特征工程。
为了理解不同变量之间的关系,paiprplot函数seaborn被广泛使用。使用 below 命令绘制数据集中变量的 pairplot。由于 Seaborn 不支持考拉数据帧,用户必须在调用 pairplot 之前将其转换为熊猫数据帧。
sns.pairplot(kdf_ccpp.to_pandas())<seaborn.axisgrid.PairGrid at 0x7f99989459e8>

作者提供的图片:原始要素和目标的配对图
通过查看上图,我们可以看到很多离群值,对于一些变量与目标的关系并不清楚。为了去除异常值,最简单的解决方案是计算移动平均值,我用考拉来演示。
sns.pairplot(kdf_ccpp.rolling(window=20).mean().to_pandas())<seaborn.axisgrid.PairGrid at 0x7f9993a5ada0>

作者提供的图像:平滑特征和目标的配对图
看起来 20 天移动平均线与目标变量有更好的关系,因此使用 20 天平均线更有意义。
使用 PySpark 建模
一旦 EDA 和特性工程完成,就该建立预测模型了。使用考拉数据框架的好处之一是用户可以无缝地创建 Spark 数据框架。在下一节中,我将演示如何使用 PySpark API 来构建和训练梯度推进机器(GBM)。
# Create the moving average features
kdf = kdf_ccpp.rolling(window=20, min_periods=1).mean()# Convert the Koalas DataFrame into Spark DataFrame
sdf = kdf.to_spark()sdf.show(5,False)+------------------+------+------------------+-----------------+-----------------+
|AT |V |AP |RH |PE |
+------------------+------+------------------+-----------------+-----------------+
|14.96 |41.76 |1024.07 |73.17 |463.26 |
|20.07 |52.36 |1022.055 |66.125 |453.815 |
|15.083333333333334|48.04 |1018.7566666666667|74.79666666666667|465.3966666666667|
|16.5275 |50.36 |1016.6275 |75.2575 |460.6675 |
|15.386000000000001|47.788|1015.1479999999999|79.53 |463.314 |
+------------------+------+------------------+-----------------+-----------------+
only showing top 5 rows
现在,使用 PySpark API 构建模型。关于使用 PySpark 构建模型的更多细节,请参考我的文章使用 Spark 进行机器学习。
from pyspark.ml.regression import LinearRegression
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.evaluation import RegressionEvaluator
from pyspark.ml.regression import GBTRegressor
准备与 PySpark 型号兼容的功能
# Create the feature column using VectorAssembler class
vectorAssembler = VectorAssembler(inputCols =["AT", "V", "AP", "RH"], outputCol = "features")
vpp_sdf = vectorAssembler.transform(sdf)vpp_sdf.show(2, False)+-----+-----+--------+------+-------+-----------------------------+
|AT |V |AP |RH |PE |features |
+-----+-----+--------+------+-------+-----------------------------+
|14.96|41.76|1024.07 |73.17 |463.26 |[14.96,41.76,1024.07,73.17] |
|20.07|52.36|1022.055|66.125|453.815|[20.07,52.36,1022.055,66.125]|
+-----+-----+--------+------+-------+-----------------------------+
only showing top 2 rows
创建 tarin 并测试拆分
# Define train and test data split
splits = vpp_sdf.randomSplit([0.7,0.3])
train_df = splits[0]
test_df = splits[1]
建立和训练模型
# Define the GBT Model
gbt = GBTRegressor(featuresCol="features", labelCol="PE")
gbt_model = gbt.fit(train_df)
gbt_predictions = gbt_model.transform(test_df)
评估模型准确性
# Evaluate the GBT Model
gbt_evaluator = RegressionEvaluator(labelCol="PE", predictionCol="prediction", metricName="rmse")
gbt_rmse = gbt_evaluator.evaluate(gbt_predictions)
print("The RMSE of GBT Tree regression Model is {}".format(gbt_rmse))The RMSE of GBT Tree regression Model is 1.077464978110743
将预测转换回考拉数据框架
kdf_predictions = ks.DataFrame(gbt_predictions)kdf_predictions.head()

让我们从模型中画出实际值和预测值。
kdf_predictions[['PE', 'prediction']].plot(figsize=(12,8))<matplotlib.axes._subplots.AxesSubplot at 0x7f9992ba4828>

作者图片:实际 PE 与预测 PE 图
一个有效的 Google Colab
下面是工作谷歌 colab 笔记本重新创建教程。试试看,在可能的情况下,在目前用考拉代替熊猫的基础上开发机器学习算法。
结论
在本教程中,我演示了使用考拉来执行探索性数据分析和特征工程。对于熊猫用户来说,使用 Spark 后端进行分布式计算的好处是,切换到考拉是直接的。在讨论的要点下面
- 考拉过去常常表演 EDA
- 使用考拉的特征工程
- PySpark 与考拉的整合
参考资料/阅读/链接
- 【https://spark.apache.org/docs/latest/ml-features.html 号
- 【https://koalas.readthedocs.io/en/latest/?badge=latest
- https://towards data science . com/machine-learning-with-spark-f1dbc 1363986
- https://medium . com/analytics-vid hya/getting-started-spark 3-0-0-with-Google-colab-9796d 350d 78
- https://medium . com/analytics-vid hya/spark-ifying-pandas-data bricks-koala-with-Google-colab-93028890 db5
Python 中的朝鲜语自然语言处理
利用“KoNLPy”模块进行词法分析和词性标注

通过阅读这篇文章,您将学会使用 Python 为朝鲜语执行简单的自然语言处理任务,如词法分析和词性标注。我们将使用一个名为KoNLPy的 Python 模块。基于官方文档,KoNLPy(读作为 *ko en el PIE* ):
“…是一个用于朝鲜语自然语言处理(NLP)的 Python 包。”
该模块基于以下理念:
- 保持简单。
- 让它变得简单。对人类来说。
- 网络民主让每个人都可以贡献自己的想法和建议,
本教程有 3 个部分:
- 设置
- 履行
- 结论
让我们继续下一部分,开始安装必要的模块。
1.设置
Windows 操作系统
安装有点复杂,因为您需要确保您已经安装了 Java 版本 1.7。进入以下链接为您的电脑下载必要的 JDK。
从 Python 访问 Java 类库需要JPype。您需要根据您的操作系统和 Python 版本安装正确的JPype。用下面的代码检查它
python --version
前往下面的链接并下载相应的文件。我将使用下面的文件,因为我在 64 位 Windows 机器上运行 Python3.7.4。
JPype1-0.7.2-cp37-cp37m-win_amd64.whl
将文件放在一个目录中,然后打开一个终端。强烈建议您事先设置一个虚拟环境。将目录更改为 wheel 文件所在的根文件夹。运行以下命令来安装它。根据您下载的内容相应地修改名称。
pip install JPype1-0.5.7-cp27-none-win_amd64.whl
通过pip install命令继续安装koNLPy。
pip install konlpy
其他操作系统
如果你正在使用其他种类的操作系统,请查看官方的文档,因为我还没有亲自测试过。它支持 Linux 和 MacOS,并且安装更加简单。
让我们继续下一节,开始写一些 Python 代码。
2.履行
这个模块为我们提供了几个不同的类来执行词法分析和词性标注。它们中的每一个在最终结果和性能上都是不同的。查看下面的链接,了解更多关于时间和性能分析的信息。
[Kkma](https://konlpy.org/en/latest/api/konlpy.tag/#konlpy.tag._kkma.Kkma)[Komoran](https://konlpy.org/en/latest/api/konlpy.tag/#konlpy.tag._komoran.Komoran)[Hannanum](https://konlpy.org/en/latest/api/konlpy.tag/#konlpy.tag._hannanum.Hannanum)[Okt](https://konlpy.org/en/latest/api/konlpy.tag/#konlpy.tag._okt.Okt)[Mecab](https://konlpy.org/en/latest/api/konlpy.tag/#konlpy.tag._mecab.Mecab)—Windows 不支持
在本教程中,我将使用 Okt 来保持事情简单和容易。让我们从在 Python 文件上添加以下导入声明开始。
from konlpy.tag import Okt
from konlpy.utils import pprint
我将使用以下文本作为输入。在韩语里是I am eating an apple的意思。希望我没弄错。
text = '나는 사과를 먹고있다'
将类初始化为对象
okt = Okt()
之后,我们可以调用其中的函数,并使用pprint utils 类将结果打印出来。
名词
让我们尝试使用nouns函数从句子中提取名词
pprint(okt.nouns(text))
您应该会得到以下结果。
['나', '사과']
나—我사과—苹果
改变
如果你想对句子进行分词,你可以使用morphs功能。它接受三个输入参数。
phrase—输入文本norm—一个布尔值表示是否规范化句子stem—布尔值表示是否对句子进行词干处理。词干化是将句子中的单词缩减成基本形式或词根形式的过程。
它可以被称为如下:
pprint(okt.morphs(text, norm=True, stem=True))
您应该在控制台上看到以下输出。
['나', '는', '사과', '를', '먹다']
你可以注意到먹고있다(吃)这个词正在被简化为먹다(吃)。
나—我는—粒子사과—苹果公司를—粒子먹다—吃
词性标签
pos如果您在标记化过程后寻找词性标签,此功能非常有用。与前面的函数不同,这个函数中的参数根据您使用的类而有所不同。有些类有flatten参数,如果设置为 False,它会保留 eojeols。Okt 类有以下输入参数。
phrase—输入文本norm—一个布尔值表示是否规范化句子stem—布尔值表示是否对句子进行词干处理。词干化是将句子中的单词缩减成基本形式或词根形式的过程。join—一个布尔值表示是否返回由/符号分隔的变形和标签的联合集合。
让我们用下面的代码来测试一下
pprint(okt.pos(text, norm=True, stem=True))
控制台将显示以下结果。
[('나', 'Noun'), ('는', 'Josa'), ('사과', 'Noun'), ('를', 'Josa'), ('먹다', 'Verb')]
修改前一行并将join参数设置为True
pprint(okt.pos(text,norm=True, stem=True, join=True))
结果现在被捆绑在一起,作为一个由/符号分隔的元素。
['나/Noun', '는/Josa', '사과/Noun', '를/Josa', '먹다/Verb']
3.结论
让我们回顾一下今天所学的内容。
我们开始安装必要的模块和库。如果您是 Windows 用户,设置会稍微复杂一些。
接下来,我们深入探讨了koNLPy模块提供的功能。它可以用来从输入的句子中提取名词。此外,你还可以把它标记成单个的单词。您可以对它进行微调,只获得单词的基本形式作为输出。
此外,我们还测试了pos函数,该函数允许我们识别朝鲜语的词性标签。
感谢你阅读这篇文章。希望在下一篇文章中再见到你!
参考
kot Lin——用代码片段控制流程(2020 年 3 月)
初学者的 kot Lin—# 2:控制流
如果,当,为,而,当,中断并继续…

约翰·洛克伍德在 Unsplash 上拍摄的照片
C控制流运算符可用于在计算中从两条或多条可能的路径中选择一条合适的路径。
在本文中,我们将介绍 Kotlin 中的以下控制流:
if表情when表情for循环while和do...while循环break操作员continue操作员
if表情
if语句的传统用法:
val num1 = 10
val num2 = 20
**if** (num1 > num2) {
print("num1 > num2)
} **else if** (num1 < num2) {
print("num1 < num2")
} **else** {
print("num1 == num2")
}// Output: num1 < num2
2.而不是三元运算符(在 Java 中— condition?val1 : val2):
val num = 0
val isZero = **if** (num == 0) true **else** false
仅供参考:kotlin 中没有三元运算符。
3.在 Kotlin 中,if也可以返回值(我们在上面一点中已经看到)。因此,它也可以用在函数的返回语句中。
fun getMinValue(a: Int, b: Int): Int {
return if (a <= b) {
a
} else {
b
}
}
参考:当使用
if操作符返回值时,if和else块的最后一行应该是你想要返回的结果值。
when表情
when是 switch case 的替代品(java 中)。你可以说,when表情是有超能力的开关格。when表达式可以用来返回值,类似于if表达式。when的传统用法(类似于开关盒):
val color = "RED"
when(color) {
"RED" -> print("Color is RED")
"GREEN" -> print("Color is GREEN")
"BLUE" -> print("Color is BLUE")
else -> print("Color is Unknown")
}// Output: Color is RED
3.when表情的超能力能力:
fun getValue(input: Any): String {
return when (input) {
**is String ->** "Input is a String"
**in 'A'..'Z' ->** "Input is between A to Z"
**0 ->** "Input is 0"
**1, 2 ->** "Input is either 1 or 2"
**in 3..10 ->** "Input is between 3 to 10"
**!in 11..100 ->** "Input is not between 11 to 100"
**else ->** "Inside else case"
}
}
getValue("Any String"):输出将是Input is a String。getValue('D'):输出为input is between A to Z。getValue(0):输出将为Input is 0。getValue(5):输出将为Input is between 3 to 10。getValue(256):输出将为Input is not between 11 to 100。getValue(55):输出将是Inside else case。
参考消息:
is或!is可用于检查输入的类型。in或!in将用于检查范围。
for循环
*for*循环迭代可迭代的任何东西(具有提供*Iterator*对象的*iterator()*函数的任何东西),或者本身是*Iterator*的任何东西。
in—最简单的 for 循环,遍历列表中的每个元素
*val fruits = listOf("Apple", "Banana", "Cherries", "Guava")
for (fruit **in** fruits) {
println(fruit)
}// Output: Apple, Banana, Cherries, Guava*
2... —迭代 0(含)到 5(含)之间的范围
*for (number in 0..5) {
println(number)
}// Output: 0 through 5*
3.withIndex() —使用当前项目的索引遍历列表。
*val fruits = listOf("Apple", "Banana", "Cherries", "Guava")
for ((index, fruit) in fruits.**withIndex**()) {
println("$index - $fruit")
}// Output: 0 - Apple, 1 - Banana, 2 - Cherries, 3 - Guava*
注:查看关于在 Kotlin 中使用 for 循环的 8 种不同方法的详细文章。如果你想知道如何使用
for循环来迭代Map,那么别忘了看看那篇文章的第 8 点。
while和 do…while 循环
- 类似于
while循环的传统用例(基于它将循环通过语句块的条件):
*var i = 5
while (i > 0) {
println(i)
i--
}// Ouput: 5 through 1*
2.在do...while中,首先执行程序块,然后检查条件:
*var i = 5
do {
println(i)
i--
} while (i > 0)// Ouput: 5 through 1*
break操作员
break运算符(默认,即无任何标签)用于终止最近的封闭循环:
*for (y in 0..5) {
if (y > 5) break
println("y: $y")
}// Output:
y: 0
y: 1
y: 2
y: 3*
2.一个循环在另一个循环中的例子,其中break操作符仅终止最近的循环:
*for (x in 0..2) {
for (y in 0..2) {
if (y > 0) break
println("x:$x - y:$y")
}
}// Output:
x:0 - y:0
x:1 - y:0
x:2 - y:0*
3.break带有标签的操作器不仅可用于终止最近的回路,也可用于终止外部回路:
*outer@ for (x in 0..2) {
for (y in 0..2) {
if (y > 0) break@outer
println("x:$x - y:$y")
}
}// Output:
x:0 - y:0*
continue操作员
continue运算符终止以下语句的执行,并跳转到封闭循环中的第一条语句:
*for (i in 0..10) {
if (i%2 == 0) continue
print("$i ")
}// Output: 1 3 5 7 9*
2.continue带标签的操作员:
*outer@ for (x in 0..3) {
for (y in 0..3) {
if (y > 1) continue@outer
println("x:$x - y:$y")
}
}// Ouput:
x:0 - y:0
x:0 - y:1
x:1 - y:0
x:1 - y:1
x:2 - y:0
x:2 - y:1
x:3 - y:0
x:3 - y:1*
注:如果你想要一篇关于
return, break and continue(即 Kotlin 中的跳转表达式)的带有标签和代码片段的详细文章,那么请在评论中提及“是的,我感兴趣……”*。当我发布相同的文章时,我会特别回复你。*
您的机会…
加入我的部落后,获得我的个人 Java 收藏清单作为免费的欢迎礼物。 马上获取!
关于作者
Anand K Parmar 是一名软件工程师,热爱设计和开发移动应用程序。他是一名作家,发表关于计算机科学、编程和个人理财的文章。在 LinkedIn 或 Twitter 上与他联系。下面是他的最新文章。
关于 Kotlin 中的“for”循环,您只需要知道
medium.com](https://medium.com/quick-code/all-you-need-to-know-about-kotlin-for-loop-144dc950271d) [## 每个初学者都应该知道数据结构和算法之间的区别
理解计算机科学基础的简单指南
medium.com](https://medium.com/swlh/differences-between-data-structures-and-algorithms-eed2c1872cfc)*
Kubeflow 比以往任何时候都更容易接近
10 分钟内开始使用 Kubernetes 的最佳机器学习平台

由 Unsplash 上的 Pietro Jeng 拍摄
机器学习项目通常由多个相互关联的步骤组成:数据采集、数据处理、数据建模、微调、测试等。这些步骤中的每一步都可以是一个独立的过程,以自己的节奏运行,具有明确定义的输入和输出。因此,数据科学家和 ML 工程师倾向于认为这些项目像管道。
库巴流管道,库巴流的一个组件,就是为了解决这个设计模式。此外,Kubeflow 将在您的 ML 项目的整个生命周期中为您提供帮助:实验和元数据跟踪、与框架无关的培训、Jupyter 服务器、模型服务等等。
但是我们如何部署一个 Kubeflow 实例来开始使用它呢?我们应该创建和维护一个 Kubernetes 集群吗?
嗯,有更好的入门方式: MiniKF 。就像 minikube , MiniKF 提供了一个单节点 Kubernetes 集群,上面部署了 Kubeflow。所以,我们来看看怎么设置吧!
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
KubeFlow 简介
Kubeflow 是一个开源项目,致力于使 ML 项目的部署更加简单、可移植和可伸缩。来自文档:
kube flow 项目致力于使在 Kubernetes 上部署机器学习(ML)工作流变得简单、可移植和可扩展。我们的目标不是重新创建其他服务,而是提供一种简单的方法来将 ML 的最佳开源系统部署到不同的基础设施上。无论你在哪里运行 Kubernetes,你都应该能够运行 Kubeflow。
但是我们如何开始呢?我们需要 Kubernetes 集群吗?我们应该自己部署整个系统吗?我的意思是,你有没有看过 Kubeflow 的清单回购?
不要慌;最终,在 Kubeflow 上运行笔记本所需要的只是一个谷歌云平台(GCP)账户和你的旧笔记本文件!
MiniKF
我将保持简单,不使它变得愚蠢。事实是,只需几分钟就可以轻松运行 Kubeflow 的单节点实例。我们需要的只是一个 GCP 帐户和从市场部署应用程序的能力。我们要用 MiniKF!

MiniKF 部署—作者图片
- 去你的 GCP 控制台
- 搜索市场然后找到 MiniKF
- 点击它并选择启动
- 设置 VM 配置,(由于我的配额,我通常将数据磁盘更改为标准持久磁盘)并单击 deploy。
就是这样!部署最多需要十分钟,您可以按照屏幕上的说明观看进度;ssh 进入机器,在终端上运行minikf,等待直到您的端点和凭证准备好。

MiniKF 的提供已完成—图片由作者提供
现在,我们准备访问 Kubeflow 仪表板。点击网址,输入你的凭证,你就可以开始了!

Kubeflow 仪表板—按作者分类的图像
运行 Jupyter 服务器
为了运行我们的实验,我们需要一个 Jupyter 笔记本实例。在 Kubeflow 中创建一个 Jupyter 笔记本相对容易。我们首先需要创建一个 Jupyter 服务器并连接到它。让我们这样做:
- 从左侧面板中选择笔记本
- 选择
New Server按钮 - 填写服务器的名称,并请求您需要的 CPU 和 RAM 数量
- 保持 Jupyter 笔记本图像不变(
jupyter-kale:v0.5.0-47-g2427cc9—注意图像标签可能不同)

创建 Jupyter 服务器—作者图片
完成这四个步骤后,等待笔记本服务器准备好并连接。你将被转移到你熟悉的 JupyterLab 工作区。如果您想要一个关于如何在不编写任何代码的情况下将您的笔记本转变为 Kubeflow 管道的端到端教程,请参见此处:
无需编写一行代码,即可将您的笔记本草稿转化为生产就绪的 Kubeflow 管道。
towardsdatascience.com](/jupyter-is-ready-for-production-as-is-b36f1d1ca8f8)
结论
在这个故事中,我们看到了如何在 10 分钟内启动并运行 Kubeflow 实例。开始使用这个强大的工具很容易;运行您的笔记本电脑,使用 Katib 启动超参数调整实验,并使用 KFServing 为您的模型提供服务。
我们已经看到了如何在不编写任何代码的情况下将您的 Jupyter 笔记本转换成 Kubeflow 管道。在未来的帖子中加入我们,了解更多:超参数调优、版本控制、调试等等!
关于作者
我叫迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲中央银行、经合组织和宜家等主要客户设计和实施人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请在 twitter 上关注我的媒体、 LinkedIn 或 @james2pl 。
所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。
Kubeflow:简化、扩展和可操作化

来源:shutterstock
公司的成功和发展与他们在技术堆栈中使用的技术紧密相关。这一点在开发 ML 管道时表现得最为明显。
将健壮的 ML 模型和数据管道交付给生产是一件复杂的事情。无论给定项目的范围如何,每个数据科学团队都面临相同的限制和约束:
- 大规模的特征分析和准备是困难的
- 运行许多 ML 训练任务,每个任务具有不同的参数或算法,花费太多时间并且需要昂贵的资源
- 跟踪和复制实验,以及代码、数据和结果的正确版本是复杂的
- 将数据科学笔记本代码转移到生产管道需要付出大量努力
- 生产管道需要处理许多可伸缩性、可用性、自动化模型漂移检测、与实时数据集成、安全性等操作任务。
建立模型远不是旅程的终点。为了将支持人工智能的应用部署到生产中,你需要一群开发人员、数据工程师、DevOps 实践者和数据科学家,他们最好在一个平台上协作和工作。
在这个新兴领域中,没有多少解决方案能够覆盖这个特殊的领域,而 Kubeflow 在过去几年中作为开源领导者的势头越来越大。 Kubeflow 是在 Kubernetes 上编排复杂工作流的绝佳工具,但它也带来了挑战,尤其是对于不习惯使用这类解决方案的数据科学家来说。许多 ML 从业者发现它使用起来很复杂,遇到各种各样的可用性问题,并对功能差距感到沮丧。
幸运的是,可以扩展 Kubeflow 的功能,并将其转变为一个全面、易于使用的 MLOps 平台。在 Iguazio ,我们已经做到了。我们已经接受了库伯流。我们的方法是将它添加到我们的托管服务目录中,弥补现有的功能差距,用我们开发的新开源框架包装和扩展它的功能。
为什么我们需要 MLOps 解决方案?
数据科学家的生活:工具辩论者
数据科学家在开发模型时通常会经历以下过程:
- 从 CSV 或密集格式(如拼花地板)收集数据,需要从外部来源手动提取。使用的工具:ETL 和数据导出工具。
- 数据标记,探索和丰富,以确定潜在的模式和特征。使用的工具:用于数据标记、探索和模型开发的交互式工具;用于大规模聚合、连接和透视数据的分析工具/数据库。
- 模型训练和验证。使用的工具:并行模型培训框架。
- 使用自动化和/或可视化工具进行模型评估。使用的工具:CI/CD 框架,可视化库。
- 回到第 1 步并重复,直到达到预期的结果。
这导致大量耗时且复杂的跑腿工作。如果数据科学团队想要让一个模型走出实验室,那么他们必须引入一些方法。
这只是开始
但是这个漫长的过程只是第一步!您仍然需要操作模型,将它与应用程序联系起来,并自动化您的功能工程过程。这可能需要一年或更长的时间,并且需要一大批 ML 从业者用蛮力来解决这个问题。

来源:推特
一旦我们有了一个模型,我们需要检查所有的许多步骤,以便将基于 AI/ML 的应用程序交付到生产中。这包括:封装、扩展、性能调整、仪器和自动化。
Kubeflow 是 Kubernetes 的 ML 工具包
Kubeflow 是由 Google 发起的一个开源项目,它将领先的 ML 框架集合在 Kubernetes 之上。它提供了通用的安装工具和交叉验证,但是它的工具也可以独立部署。它充当模型开发的砖块和灰泥,专注于 Kubernetes 上 ML 模型开发管道的自动化、缩放和跟踪。
值得注意的 Kubeflow 组件:
集装箱式 Jupyter 笔记本
Kubeflow 在 Kubernetes 上提供了一个 Jupyter 笔记本服务,因此用户可以创建一个具有给定资源需求的 Jupyter 服务器,并获得预配的容器。
库伯弗洛管道公司(KFP)
什么是 Kubeflow 管道?简单地说,它是一个 ML 工作流及其所有组件的描述。一个组件可以负责 ML 过程中的不同步骤,如数据处理、转换、模型训练、验证等。
KFP 使您能够通过 Python SDK 描述具有单个步骤的工作流(其中每个步骤都是容器微服务或无服务器功能),在集群上执行该工作流,并跟踪进度和实验结果。
KFP 使用户能够自动化 ML 管道,而不是手动运行单个作业。
可扩展培训操作员
Kubernetes 中的应用生命周期和伸缩可以通过一个操作符来管理。Kubeflow 项目托管各种运营商,使用不同的 ML 框架( TensorFlow 、 PyTourch 、 Horovod 、 MXNet 、 Chainer )运行可扩展的 ML 训练任务。
模型服务解决方案
Kubeflow 项目托管一个基本的模型服务框架(KFServing)并支持外部服务框架(Seldon、Triton 和 Nuclio-serving )。Iguazio 领先的开源项目 Nuclio 是一个用于实时 API、ML 和数据工程任务的无服务器引擎,它有一个模型,提供风格的快速性能和大量功能(自动模型部署、金丝雀、模型监控、漂移和异常值检测、集成和实时管道等)。) .
实施 Kubeflow:主要挑战
Kubeflow 本身就是一个更广泛的 ML 操作系统的组成部分。Kubeflow 包含一些强大的组件,使其成为该领域的领跑者——它是 Kubernetes 原生的、高度可定制的、开源的和松散耦合的。但是它有一些关键的限制,需要由 ML 团队来解决。
挑战 1:复杂性
Kubeflow 是一个工具生态系统,而不是一个整体或集成的解决方案,它依赖于许多底层平台服务和工具(Kubernetes、用户管理、数据服务、数据版本、监控、日志、API 网关等。).如果没有托管解决方案,公司需要一个由开发人员、开发人员和 ML 工程师组成的团队,他们将致力于将各种 Kubeflow 和附加组件集成到一个具有统一门户和安全性的完整服务中,管理部署,支持内部用户,升级每个子服务,构建用于故障排除的工具和专业知识,并持续跟踪社区工作。如果您已经有一个大型的 DevOps 组织和廉价的资源,这可能是有意义的,但对于许多想要专注于他们的业务应用程序的精简组织来说就没有意义了。
让我们假设您想要使用 Katib 之类的工具运行超参数作业,使用 Kubeflow Pipelines、MPIJob 之类的分布式 ML 操作符,并跟踪或比较结果。您需要手动将所有这些工具缝合在一起,即使它们都是 Kubeflow 下的子项目。
正确安装 Kubeflow 意味着运行和管理十几个单独的服务,其中一些不是生产级的。喜欢 Kubernetes 上的单一 AI/ML 框架概念的 ML 从业者发现他们正在努力部署、管理和保护它。一旦他们这样做了,他们注意到他们的内部用户由于可用性和集成问题而不愿意使用它。
挑战 2: Kubeflow 说的是工程师的语言,而不是科学家的语言
Kubeflow 的核心焦点是使用 Kubernetes 的高级 ML 工程。它最初是由 Kubernetes 社区成员为 DevOps 和 MLOps 工程师设计的,而不是为数据科学家设计的。
像 Kubernetes 的其他功能一样,这一切都始于 Docker 容器、YAML 文件和脚本。数据科学家是数据科学平台的主要消费者。他们不想管理 YAML 文件——他们宁愿使用简单的用户界面和数据工程,或者 Python 中的 ML 逻辑,让一些东西在集群上为他们运行,然后收集结果,希望以可扩展和可管理的方式。
虽然在分布式管道中运行 ML 任务非常强大,但数据科学家通常从使用本地 IDE 开始,如 Jupyter、PyCharm 或 VSCode。他们希望在本地开发、调试、运行和跟踪工作,而不创建 Kubernetes 资源或复杂的管道,并且只有在他们成功完成单独运行后,他们(或团队中的 ML 工程师)才希望过渡到在可扩展的集群上运行或使用多级管道。不幸的是,这在 Kubeflow 中是不可能的,因为每个被跟踪的执行都需要构建完整的管道和 Kubernetes 资源。
数据科学团队希望基于逻辑 ML 项目来组织和管理他们的工作,具有清晰的项目级别成员关系、项目特定的资源和计费、隔离项目之间的资源和安全凭证的能力等。在 Kubeflow 中,用户可以使用提升的权限创建作业,在用户或项目级别没有隔离、监控或跟踪。
同样,许多任务是复杂的手动任务。例如,如果您想要查看管道运行的结果,您必须编写代码来存储和可视化运行工件,大多数商业工具或托管工具可以为您做到这一点。
数据科学团队应该能够使用熟悉的工具和简单的 UI 门户,并在幕后为他们调配和监控资源。
挑战 3: Kubeflow 是部分 MLOps 解决方案
Kubeflow 工具包主要应用于模型开发阶段,这意味着团队需要其他几个强制服务,这进一步增加了开销。为了快速(或完全)实现商业价值,团队需要将 Kubeflow 功能扩展到数据科学管道的其余部分,并手动与外部数据和身份管理系统集成。

MLOps 堆栈和 Kubeflow(图片由作者提供)
Kubeflow 专注于运行和跟踪 ML 实验的模型开发管道,然而大多数用户需要如上图所述的附加服务,可扩展数据和特征工程、模型管理、生产/实时管道、版本化和管理的数据仓库、管理的运行时、认证/安全等服务。
Iguazio 开发了开源框架(如 Nuclio 、 MLRun )和额外的数据服务和管理层,将 Kubeflow 补充和扩展为一个功能齐全的托管数据科学平台。这将在下一节中进一步描述。
交付端到端数据科学平台 Kubeflow Inside
将基于数据科学的产品交付到生产环境的大部分复杂性在于不同组织和技术孤岛之间的集成,采用单个“同类最佳”组件并手动集成它们需要大量资源,维护组织孤岛,并导致巨大的技术债务,因为您需要维护所有集成和粘合层。
我们认为,组织应该部署一个涵盖数据工程、数据科学、ML 工程和 DevOps 领域的数据科学解决方案。我们需要抽象掉大部分复杂性,同时实现一个高性能、可扩展且安全的平台,该平台可以部署在任何云中或内部。
以下是 Iguazio 平台上的附加功能列表(大部分是开源的):
具有用户友好的门户、API 和自动化的集成解决方案
可用性是 Kubeflow 的主要挑战之一,加上 Kubeflow 只解决了解决方案的一部分(没有离线开发、数据工程或生产部署)。用户发现自己在与多个门户和用户界面对抗,并添加了大量粘合代码。
假设所有数据科学元素和元数据由一个服务管理,您可以使用要素存储创建一个要素集对象,将其作为对象传递给培训、验证或模型服务逻辑,使用它来验证您的模型行为和概念漂移,并直接从生产管道更新它和相应的标记数据。使用粘合逻辑和脚本来实现这一点几乎是不可能的,并且会导致大量额外的开发和 ML 工程工作。
名为 MLRun 的开源框架控制着从数据摄取到生产管道的整个功能,它提供了全面的 Web UI、CLI、API/SDK,并且与 underline Kubeflow 组件(操作符、管道等)紧密集成。)
通过 MLRun ,用户可以在任何地方使用他们的原生 IDE (Jupyter、PyCharm、VSCode 等)通过 SDK 和 IDE 插件工作。),不需要在 Kubernetes 集群上运行,只需要几个简单的命令就可以运行单个任务或者完成批处理和实时管道。
执行、实验、数据、模型跟踪和自动化部署通过 MLRun 无服务器运行时引擎自动完成。MLRun 通过严格的成员关系和跨团队协作来维护项目层次结构(而不是像 Kubeflow 那样使用平面名称空间)。

示例:MLRun 项目仪表板屏幕(图片由作者提供)
您可以按照 MLRun 文档中所述部署各种组件,或者您也可以使用 Iguazio 的托管产品,该产品在 MLRun 和 Kubeflow 以及其他数据和管理服务的基础上增加了端到端安全性和完全托管的服务体验。
功能商店
特征工程可能是构建 ML 管道中最耗时的任务之一。如果没有所有特性的共享目录,团队就有浪费时间进行重新开发以及跨团队和项目重复工作的风险。需要使用数据工程框架(如 Spark、Presto、Dask 等)定期计算这些特征。)和流处理引擎(Flink、Nuclio 等。)并使用用于训练的离线/批处理 API 和用于服务的实时 API 和数据库来交付。特征存储的一个主要优点是为训练和服务层提供了一致的特征集,确保训练好的模型在生产中保持其性能。
此外,要素存储是存储版本化要素元数据和统计数据的关键元素,这对于进行模型监控、验证、概念漂移检测和持续再训练至关重要。
建立自己的功能商店是一种奢侈,通常只保留给一线网络公司,因为它需要复杂的堆栈。没有特性存储的选择意味着团队将投入大量的手工数据工程工作来构建和维护特性。
实时管道、模型管理和监控
一旦模型准备就绪,它们需要转变为运行的微服务,这些微服务通过 API 或数据流接受特征向量,并产生预测结果,这些结果需要在生产业务应用中使用。实际上,生产流水线比简单的服务端点复杂得多,它们可能包括特征检索、转换、验证、异常值检测、集合或更复杂图形下的多个模型服务、警报等步骤。
Nuclio 和 MLRun-serving 开源框架使团队能够在几分钟内根据训练结果和实时特征存储中的数据构建复杂的实时数据处理和模型服务管道,并通过单个 API/UI 命令部署或升级到生产。
将模型投入生产只是其生命周期的开始。必须记录模型的预测和行为,必须监控它们的概念漂移,有时在变化的环境下根据新数据进行重新训练。数据需要治理和审计。如果没有一个集中的系统,模型维护会很快变得难以管理并且过于昂贵。
托管服务和无服务器运行时
大量工作投入到创建和管理各种软件包,并将它们转化为具有自动扩展、配置管理、升级和安全性的生产服务。典型的数据科学堆栈可以由数十种服务组成,如数据分析工具、ML/AI 框架、开发工具、仪表盘、安全和授权服务以及日志记录。您可以雇佣一个大型团队来手动构建一个堆栈,或者您可以使用一个带有托管服务的平台,允许用户选择服务、指定参数并单击部署。
此外,将代码转化为产品服务是一个耗时的项目,涉及许多团队成员(见下图)。您需要将代码打包到容器中,针对弹性、可伸缩性、性能、强化安全性、添加工具等对其进行重新设计。许多数据科学家不精通软件开发和 DevOps,因此这些任务对他们来说更具挑战性。无服务器技术的使用使团队能够自动完成所有这些任务。
MLRun runtimes 和 Nuclio 可以获取一段代码,并自动将它转换为一个灵活的、完全托管的服务,这可以通过 UI 或在您的开发环境(如 Jupyter)中使用一行代码来完成。
无服务器功能可以独立运行,也可以作为步骤插入到更大的 Kubeflow 管道中,无需任何额外的开发。MLRun 项目支持自动化 CI/CD 管道。每次代码、数据或配置更改时,都可以通过 Git 挂钩触发工作流,项目成员可以查看结果并批准自动部署到测试或生产系统中。

从开发迁移到生产的努力(图片由作者提供)
功能市场和汽车
您可以开发自己的功能,或者使用市场上的一组预烘焙功能,然后将它们插入到您的管道中,无需任何开发工作。ML run 函数市场提供了一套用于特征分析、检测和自动化 ML 训练的 AutoML 函数。这些功能是为规模、性能而设计的,并可通过仪器和可视化报告进行生产。
团队可以实现本地功能市场/存储库,最大化协作和重用。一个成员可以构建一个可以在另一个项目中使用的功能,或者由另一个团队成员改进并返回到市场(使用不同的版本标签)。
生产就绪的托管数据服务
每一个数据科学解决方案都处理数据,数据可以以多种形式出现(文件、表格、流、时间序列等。),这需要与几个底层数据服务集成。应控制数据访问,将每个作业或用户限制在特定的数据集内,并具有特定的访问权限,此外,必须对数据进行版本控制以实现可再现性。
您可以从不同的云提供商那里获得并集成托管数据服务。Iguazio 拥有业界领先的高性能多模式数据库和低延迟分布式文件系统,采用独特的技术,使用闪存/SSD 存储,但性能类似于内存中的数据库,成本仅为其一小部分,而且规模更大。这些因素有助于加快部署、提高性能、扩大规模和降低成本。
端到端安全性
数据科学平台可能包含从多个用户聚合的非常敏感的数据。必须实施多层安全方法,包括:
- 身份验证和身份管理:使用行业标准协议,如 LDAP、OAuth2 和 OIDC,确定哪个用户或服务正在访问一段数据或另一项服务。
- 基于角色的访问控制(RBAC):强制每个用户、任务或角色的访问权限,他们可以访问哪些资源,他们可以执行哪些操作。
- 数据安全:控制数据资产的访问和隐私。
- 机密管理:保护机密和访问凭证,避免将这些机密存储在代码或数据资产中,而是在执行时将它们提供给特定的用户和作业。
MLRun 支持与安全服务的集成。您可以自己部署和集成它们,也可以使用 Iguazio 托管平台,为您提供所有固化和全面的管理。
摘要
在 Iguazio ,我们坚信 Kubeflow 的潜力,这就是我们选择将其包装并扩展为完整的端到端 MLOps 解决方案的原因。我们还相信打破数据工程、数据科学和 DevOps 从业者之间的孤岛,这样就可以抽象出复杂性,组织就不会背负沉重的技术债务。通过一些额外的服务和功能,Kubeflow 可以成为应对操作化机器学习挑战的正确解决方案,为数据科学家提供高性能、可扩展和安全的技术,可以部署在任何云、本地或混合环境中。
Kubernetes 和亚马逊 SageMaker 的机器学习——两全其美
使用 Amazon SageMaker 为机器学习工作负载扩展 Kubernetes 集群的容量和功能

Kubernetes 和亚马逊 SageMaker——两全其美
如果你是一个经常训练和部署机器学习模型的团队的一员,你可能有一个集群设置来帮助协调和管理你的机器学习工作负载。你使用 Kubernetes(和 KubeFlow)或亚马逊 SageMaker 的机会。
到目前为止,你必须选择你的编排系统,并坚持下去。您要么(1)根据数据科学团队的预期工作负载调配 Kubernetes 集群,要么(2)完全由 Amazon SageMaker 管理,根据需要自动调配和拆除资源。
如果能两全其美岂不是很好?
- 使用 Kubernetes 管理您的工作流,并使用 Amazon SageMaker 获得大规模分布式培训的爆发容量?
- 用 Kubeflow Jupyter 笔记本开发算法和模型,用亚马逊 SageMaker 大规模运行超参数实验?
- 使用 Kubeflow 训练模型,并托管一个推理端点 Amazon SageMaker,可以弹性扩展到数百万用户?
有了针对 Kubernetes 的亚马逊 SageMaker 运营商,你就可以做到这一点!您可以使用它来训练机器学习模型,优化超参数,运行批量转换作业,并使用 Amazon SageMaker 设置推理端点,而无需离开您的 Kubernetes 集群。

使用 Amazon SageMaker Operators for Kubernetes 来运行培训作业、模型调优作业、批量转换作业,并使用 Kubernetes 配置文件和 kubectl 在 Amazon sage maker 上设置推理端点
用于 Kubernetes 的 Amazon SageMaker Operators 是 Kubernetes 中的一个定制资源,它支持使用 Kubernetes CLI 和配置文件调用 Amazon SageMaker 功能。事实上,Kubernetes 的许多核心功能都是作为定制资源构建的,这种模块化使得 Kubernetes 非常具有可扩展性。对于 Kubernetes 用户来说,Amazon SageMaker Operators 使您能够以一种一致的方式与 Kubernetes 和 Amazon SageMaker 进行交互。
在这篇博文中,我将概述 Amazon sage maker Operators for Kubernetes,为什么它很重要,以及常见的使用模式,以便您可以决定这是否适合您。这篇博文中引用的所有代码、配置文件和演示 Jupyter 笔记本都可以在 GitHub 上获得:
https://github . com/shashankprasanna/kubernetes-sage maker-demos . git
要深入了解如何使用 Amazon SageMaker Operators for Kubernetes 实现分布式培训、模型调优和模型托管示例,请查看随附的帖子:
云中的一对
Kubernetes 和 Kubeflow 项目享有强大的用户社区,是机器学习领域发展最快的开源项目之一。只要您拥有设置、管理和排除 Kubernetes 集群故障的内部专业知识,您就可以获得作为数据科学家或机器学习研究人员所需的一切——Jupyter 笔记本和对 KubeFlow 分布式培训的支持,KubeFlow 和 Katib 的超参数调整,以及 KFServing 的轻松推理部署。作为 Kubernetes 用户,您可以完全灵活地选择在哪里运行它(本地或云),以及在什么系统上运行它。这也意味着您要负责保持群集的高利用率,以降低运营成本,鉴于突发性或峰值机器学习工作负载的性质,这可能是一项挑战。
亚马逊 SageMaker 采取了不同的方法。首先,它为机器学习工作流程的几乎每个部分提供了一套完全托管的服务,从数据标记、托管 Jupyter 笔记本开发环境、使用后自动供应和拆除的托管培训集群、超参数优化、托管模型托管服务等等。作为 Amazon SageMaker 用户,您不必关注基础设施管理和集群利用率之类的事情。
作为一名机器学习实践者,你应该能够利用两者的优势。例如,您应该能够将持续运行的(或多或少)固定容量自我管理的 Kubernetes 基础架构与按需、完全管理的弹性 Amazon SageMaker 基础架构配对,后者仅在您需要时供应。这是一个强大的想法——数据科学家团队可以让他们的想法自由驰骋,随心所欲地进行实验,而不受现有 Kubernetes 设置的限制。
您现在已经可以做到这一点,但是必须在这两个系统之间来回切换。有了 Amazon sage maker Operators for Kubernetes,您现在无需离开您可能已经熟悉的 Kubernetes 环境就可以做到这一点。
场景和用例
借助 Amazon SageMaker Operators for Kubernetes,您可以将单节点培训、分布式或多节点培训、大规模超参数调整和托管推理部署等工作负载卸载到 Amazon sage maker 的完全托管基础设施中。因此,问题就变成了,什么时候把工作负载转移到 Amazon SageMaker 上比在 Kubernetes 集群上运行更有意义?
让我们通过几个假设的场景来探讨这个问题。
场景#1 —大规模培训能力过剩

使用 Amazon sage maker Operators for Kubernetes 通过 kubectl 提交培训工作。Amazon SageMaker 提供所需的容量并运行培训作业。
假设您目前正在本地数据中心或使用亚马逊 EKS 的 AWS 上运行 Kubernetes 集群。在设置时,您根据当时的工作负载对数据中心的 CPU、GPU 和存储数量进行了预算和选择。现在,您的团队已经壮大,或者您拥有更多数据,需要更多计算能力。如果您有 128 个 GPU,您可以在一天内完成一个机器学习训练实验的快速截止日期,但在您的 Kubernetes 集群上,他们都在忙于其他项目。你只需要短时间的额外突发容量。
你的选择是
- 扩展您现有的 Kubernetes 集群并添加所需的资源
- 使用所需的资源启动另一个 Kubernetes 集群
- 使用 Amazon SageMaker 进行按需供应
(1)和(2)是您没有参与的额外基础设施工作。(3)是一个很好的选择,但是要求您离开您熟悉的 Kubernetes 环境,并且它没有集成到您已经设置的任何 CI/CD 自动化中。
还有第四种选择。使用 Amazon SageMaker Operators for Kubernetes 通过kubectl提交 Amazon sage maker 作业,就像提交其他 Kubernetes 作业一样。在后台,将自动为您提供一个 Amazon SageMaker 托管集群,其中包含指定数量的实例。然后,培训作业将在 Amazon SageMaker 管理的集群上执行,一旦培训完成,该集群将自动关闭,您将看到培训的确切持续时间,这是您将支付的费用。
场景#2 —托管可伸缩的推理端点

使用 Amazon sage maker Operators for Kubernetes 通过 kubectl 托管推理端点。Amazon SageMaker 提供所需的实例并运行模型服务器。
让我们考虑另一种情况。您拥有针对 Kubernetes 的培训、验证和部署的 CI/CD 自动化设置。您使用 Kubernetes 托管的模型由您的客户通过终端、移动应用程序或网站使用。该模型托管在 GPU 实例上,因为延迟和性能对于您的客户体验至关重要。您希望释放 GPU 资源用于培训,并且需要能够自动扩展和执行实时模型监控。Amazon SageMaker 主机服务已经提供了这些功能,但是您希望在不中断现有 CI/CD 工作流的情况下利用这些功能。使用 Amazon SageMaker Operators for Kubernetes,您可以直接从 Kubernetes 部署一个经过训练的模型,以同样的声明方式使用 YAML 的配置文件,它可以轻松集成到您现有的设置中,并且仍然允许您获得 Amazon sage maker 托管的好处。
现在让我们来看看 Kubernetes 和 Amazon SageMaker 一起使用的一些常见使用模式。
使用案例#1 —利用 TensorFlow、PyTorch、MXNet 和其他框架进行分布式培训

工作流程:用户上传培训代码到亚马逊 S3。Amazon SageMaker 下载训练代码,拉出指定的框架容器,并在其中运行训练脚本。用户不必处理构建和推动容器。
借助分布式多节点训练,您可以通过在多个 GPU 之间分配工作负载来大幅减少训练模型的时间。当 Kubernetes 集群中的 GPU 容量不足时,可以配置一个分布式培训作业,在 Amazon SageMaker 管理的集群上运行。除了快速访问 AWS 上的多余容量之外,您还可以获得 Amazon SageMaker 的其他好处,如利用 Spot Instance 大幅降低培训成本的能力,在 AWS 控制台上或使用 AWS CLI 监控和跟踪培训工作的能力,以及通过几次点击托管培训模型的能力。
如果您正在使用广泛使用的框架,如 TensorFlow、PyTorch、MXNet、XGboost 等,您所要做的就是将您的培训脚本作为 tar.gz 文件上传到亚马逊 S3,并通过在 YAML 编写的 Kubernetes 配置文件向亚马逊 SageMaker 提交培训作业。看看 GitHub 存储库中的示例代码和配置文件。以下是您需要做出的更改,以便通过 Kubernetes 的 kubectl 提交您的 Amazon SageMaker 培训工作
下面是这篇博文的 GitHub 资源库中的[k8s-sm-dist-training-script.y](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/1-tf-dist-training-training-script/k8s-sm-dist-training-script.yaml)aml文件摘录。
apiVersion: sagemaker.aws.amazon.com/v1
kind: TrainingJob
metadata:
name: k8s-sm-dist-training-script
spec:
hyperParameters:
- name: learning-rate
value: "0.001"
- name: batch-size
value: "256"
…
- name: sagemaker_program
value: 'cifar10-multi-gpu-horovod-sagemaker.py'
- name: sagemaker_submit_directory
value: 's3://sagemaker-jobs/training-scripts/sourcedir.tar.gz'
...
algorithmSpecification:
trainingImage: 763104351884.dkr.ecr.us-west-2.amazonaws.com/tensorflow-training:1.15.2-gpu-py27-cu100-ubuntu18.04
trainingInputMode: File
...
resourceConfig:
instanceCount: 128
instanceType: "ml.p3.2xlarge"
volumeSizeInGB: 50
...
这读起来像任何其他 Kubernetes 配置写在 YAML。对于培训工作,你会注意到顶部的kind: TrainingJob
以下是几个关键部分,您可以在其中指定培训工作的各个方面:
**hyperParameters**—这些在 YAML 规范中指定,因此您可以通过更改和提交培训作业来自动运行不同的实验**sagemaker_submit_directory**—您上传培训脚本的 S3 地点。与使用 Kubernetes 提交培训相比,这是独一无二的,因为您不必构建自定义容器!Amazon SageMaker 会自动将您的培训脚本下载到现有的 TensorFlow 容器中,然后为您运行培训。没有乱搞 Docker 文件和自定义容器。**resourceConfig**—您需要多少个什么类型的实例。该配置将要求 128 个 V100 GPUs 来运行分布式培训。**trainingImage**— 从预先构建的容器中挑选用于 TensorFlow、PyTorch、MXNet,用于训练或推理,用于 Python2 或 Python 3,用于 CPU 或 GPU。
像提交任何其他 Kubernetes 配置文件一样提交作业。
kubectl apply -f k8s-sm-dist-training-script.yaml
用例 2 —使用定制容器的分布式培训

工作流:用户在本地构建一个自定义容器,并将其推送到 Amazon ECR。Amazon SageMaker 提取定制容器,并在完全管理的训练集群上运行它。
如果您正在使用定制的专有算法并构建自己的 Docker 容器,那么您更愿意指定容器映像,而不是 TensorFlow、PyTorch、MXNet 等框架培训脚本。与用例 1 不同,您必须经历额外的步骤,首先在本地构建一个自定义 docker 容器,并将其推送到 Amazon Elastic Container Registry(ECR ),并在 trainingImage 下指定其 URI。如果您没有需要构建定制容器的定制算法,我推荐使用用例 1 中的方法。
apiVersion: sagemaker.aws.amazon.com/v1
kind: TrainingJob
metadata:
name: k8s-sm-dist-custom-container
spec:
hyperParameters:
- name: learning-rate
value: "0.001"
- name: weight-decay
value: "0.0002"
...
algorithmSpecification:
trainingImage: <ACCOUNT_ID>.dkr.ecr.us-west-2.amazonaws.com/<IMAGE>:latest
trainingInputMode: File
metricDefinitions:
- name: val_acc
- regex: 'val_acc: ([0-9\\.]+)'
GitHub 存储库中的代码也包括重复这些步骤的 Jupyter 笔记本。
提交作业:
kubectl apply -f k8s-sm-dist-custom-container.yaml
用例 3——大规模超参数优化
机器学习模型的超参数是在训练阶段没有优化或学习的选项。Amazon SageMaker 提供超参数优化功能,并实现贝叶斯和随机搜索。这与 KubeFlow 的 Katib 项目所提供的功能没有什么不同。要在 Amazon SageMaker 上运行大规模的超参数调优作业,需要创建一个 Kubernetes 配置文件。这里您将指定超参数范围,而不是固定的超参数。这指示亚马逊 SageMaker 尝试不同的选项,以达到最佳模式。maxNumberOfTrainingJobs 指定您希望使用不同超参数组合运行的作业总数,maxParallelTrainingJobs 指定您希望在任何给定时间对多少个实例运行此操作。
apiVersion: sagemaker.aws.amazon.com/v1
kind: HyperparameterTuningJob
metadata:
name: k8s-sm-hyperopt-training-script
spec:
hyperParameterTuningJobConfig:
resourceLimits:
maxNumberOfTrainingJobs: 32
maxParallelTrainingJobs: 8
strategy: "Bayesian"
trainingJobEarlyStoppingType: Auto
hyperParameterTuningJobObjective:
type: Maximize
metricName: 'val_acc'
parameterRanges:
continuousParameterRanges:
- name: learning-rate
minValue: '0.0001'
maxValue: '0.1'
scalingType: Logarithmic
...
categoricalParameterRanges:
- name: optimizer
values:
- 'sgd'
- 'adam'
...
提交作业:
kubectl apply -f k8s-sm-dist-custom-container.yaml
用例 4——用 BYO 模型托管一个推理端点

工作流程:用户上传一个训练有素的模型作为 tar.gz 文件到亚马逊 S3。如果模型是使用亚马逊 SageMaker 训练的,那么 model.tar.gz 将已经在亚马逊 S3 上可用。Amazon SageMaker 下载模型文件,提取服务容器,并在完全托管的实例上托管端点。
一旦模型经过训练,您就可以使用 Amazon SageMaker 托管来托管它,而不是在您的 Kubernetes 集群上托管它。使用 Amazon SageMaker,您可以利用额外的功能和节省成本的特性进行推理部署。要进行部署,您需要创建一个配置文件:HostingDeployment。在这里,您将指定实例的类型,如果您托管多个模型,则提供 A/B 测试的权重,以及经过训练的模型在亚马逊 S3 上的位置,如下所示。
apiVersion: sagemaker.aws.amazon.com/v1
kind: HostingDeployment
metadata:
name: k8s-sm-inference-host-endpoint
spec:
region: us-west-2
productionVariants:
- variantName: AllTraffic
modelName: tf-cifar10-resnet-model
initialInstanceCount: 1
instanceType: ml.c5.large
initialVariantWeight: 1
models:
- name: tf-cifar10-resnet-model
executionRoleArn: arn:aws:iam::<ACCOUNT_ID>:role/service-role/AmazonSageMaker-ExecutionRole-20190820T113591
containers:
- containerHostname: tensorflow
modelDataUrl: s3://sagemaker-jobs/trained-tf-model/model.tar.gz
image: 763104351884.dkr.ecr.us-west-2.amazonaws.com/tensorflow-inference:1.15.2-cpu-py36-ubuntu18.04
准备实施!
在这篇文章中,我简要介绍了 Amazon sage maker Operator for Kubernetes,以及如何在现有的 Kubernetes 集群中使用它。我展示了 2 个场景和 4 个不同的用例来利用 Amazon SageMaker 的优势,而无需离开您的 Kubernetes 环境。
关于如何实现这篇博文中给出的例子的分步说明,请查看这篇附带的文章:
要运行这些示例,请前往 GitHub:
https://GitHub . com/shashankprasanna/kubernetes-sage maker-demos . git
如果你有问题,请在 twitter (@shshnkp)、LinkedIn 联系我或者在下面留言。
用于 Kubernetes 的 Amazon SageMaker 操作员—分布式培训、超参数调整和模型托管的示例
了解如何编写自己的 YAML 配置文件来使用 Amazon SageMaker 操作符

使用 Amazon SageMaker Operators for Kubernetes 来运行培训作业、模型调优作业、批量转换作业,并使用 Kubernetes 配置文件和 kubectl 在 Amazon sage maker 上设置推理端点
在 re:invent 2019 上,AWS 宣布了用于 Kubernetes 、的 亚马逊 SageMaker 操作符,使 Kubernetes 用户能够训练机器学习模型,优化超参数,运行批量转换作业,并使用亚马逊 SageMaker 设置推理端点——而无需离开您的 Kubernetes 集群。您可以通过在 YAML 编写熟悉的 Kubernetes 配置文件并使用kubectl CLI 工具将它们应用到您的 Kubernetes 集群来调用 Amazon SageMaker 功能。
这使您可以通过将训练和推理工作负载卸载到 Amazon SageMaker 来扩展 Kubernetes 集群的容量和机器学习能力。关于亚马逊 sage maker Operators for Kubernetes 的更多介绍,请阅读以下博客文章:
在这篇博文中,我将一步一步地介绍如何创建 Kubernetes 配置文件来运行分布式训练作业、超参数调优作业以及使用 Amazon SageMaker 托管可伸缩模型推理端点。
本指南的目标读者是对 Kubernetes 有基本了解的开发人员、研究人员或 DevOps 专业人员。即使您不熟悉 Kubernetes 和 Amazon SageMaker,我也会介绍提交培训作业和托管推理端点所需的所有必要步骤。
所有代码、配置文件和演示 Jupyter 笔记本都可以在 GitHub 上获得:https://GitHub . com/shashankprasanna/kubernetes-sage maker-demos . git
用于 Kubernetes 的 Amazon SageMaker 操作符及其使用方法
Amazon SageMaker Operators for Kubernetes 是作为 Kubernetes 中的一个定制资源实现的,它使 Kubernetes 能够调用 Amazon sage maker 功能。下面,我将提供实现每个用例的逐步说明:
- 用例 1: 利用 TensorFlow、PyTorch、MXNet 等框架进行分布式训练
- 用例 2: 使用定制容器的分布式培训
- 用例 3: 使用 TensorFlow 进行大规模超参数优化
- 用例 4: 用 BYO 模型托管一个推理端点
接下来,我假设您有一个 AWS 帐户,并且在您的主机上安装了 AWS CLI 工具。
所有代码、配置文件和演示 Jupyter 笔记本都可以在 GitHub 上获得:https://GitHub . com/shashankprasanna/kubernetes-sage maker-demos . git
设置
让我们从构建一个 Kubernetes 集群开始。使用 eksctl CLI 工具,只需一个简单的命令和 15 分钟的时间,就可以构建一个包含几个节点的非常简单的集群。
按照 AWS 文档中的说明安装 eksctl CLI 工具。然后运行下面的命令,去喝杯咖啡。这个命令启动一个单节点 Amazon Elastic Kubernetes 服务(EKS)集群,这对于本文中的例子来说已经足够了。请注意,您仍然可以使用 Amazon SageMaker Operators for Kubernetes 在 Amazon sage maker 上的数百个节点上运行大规模分布式培训和超参数调优作业。
创建一个 Kubernetes 集群
eksctl create cluster \
--name sm-operator-demo \
--version 1.14 \
--region us-west-2 \
--nodegroup-name test-nodes \
--node-type c5.xlarge \
--nodes 1 \
--node-volume-size 50 \
--node-zones us-west-2a \
--timeout=40m \
--auto-kubeconfig
为 Kubernetes 安装 Amazon SageMaker 操作员
一旦集群启动并运行,按照用户指南中的说明为 Kubernetes 安装 Amazon SageMaker 操作器。你也可以参考这篇有帮助的博客文章来指导你的安装过程:为 Kubernetes 介绍 Amazon SageMaker 操作员
验证安装运行
kubectl get crd | grep sagemaker
您应该得到如下所示的输出:
batchtransformjobs.sagemaker.aws.amazon.com 2020-02-29T21:21:24Z
endpointconfigs.sagemaker.aws.amazon.com 2020-02-29T21:21:24Z
hostingdeployments.sagemaker.aws.amazon.com 2020-02-29T21:21:24Z
hyperparametertuningjobs.sagemaker.aws.amazon.com 2020-02-29T21:21:24Z
models.sagemaker.aws.amazon.com 2020-02-29T21:21:24Z
trainingjobs.sagemaker.aws.amazon.com 2020-02-29T21:21:24Z
这些都是您可以使用 Amazon SageMaker Operators for Kubernetes 在 Amazon SageMaker 上执行的任务,我们将进一步了解(1)培训作业(2)超参数调优作业(3)托管部署。
从 GitHub 下载示例
将培训脚本、配置文件和 Jupyter 笔记本下载到您的主机上。
git clone [https://github.com/shashankprasanna/kubernetes-sagemaker-demos.git](https://github.com/shashankprasanna/kubernetes-sagemaker-demos.git)
下载训练数据集并上传至亚马逊 S3
cd kubernetes-sagemaker-demos/0-upload-dataset-s3
注意: TensorFlow 必须安装在主机上才能下载数据集并转换为 TFRecord 格式
浏览[upload_dataset_s3.ipynb](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/0-upload-dataset-s3/upload_dataset_s3.ipynb)将你的训练数据集上传到亚马逊

用例 1:使用 TensorFlow、PyTorch、MXNet 等框架的分布式培训
如果您是 Amazon SageMaker 的新手,那么在使用 TensorFlow、PyTorch、MXNet、XGBoost 等流行框架时,它的一个很好的特性是,您不必担心构建包含代码的自定义容器并将其推送到容器注册中心。Amazon SageMaker 可以自动将任何培训脚本和依赖项下载到一个框架容器中,并为您大规模运行它。所以你只需要版本化和管理你的训练脚本,根本不用处理容器。有了 Amazon sage maker Operators for Kubernetes,你仍然可以获得同样的体验。
导航到包含第一个示例的目录:
cd kubernetes-sagemaker-demos/1-tf-dist-training-training-script/
ls -1
输出:
cifar10-multi-gpu-horovod-sagemaker.py
k8s-sm-dist-training-script.yaml
model_def.py
upload_source_to_s3.ipynb
这个目录下的两个 python 文件cifar10-multi-gpu-horovod-sagemaker.py和model_def.py是 TensorFlow 训练脚本,实现了分布式训练的 Horovod API。
运行[upload_source_to_s3.ipynb](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/1-tf-dist-training-training-script/upload_source_to_s3.ipynb),用训练脚本创建一个 tar 文件,并上传到指定的亚马逊 S3 桶。

[k8s-sm-dist-training-script.yaml](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/1-tf-dist-training-training-script/k8s-sm-dist-training-script.yaml)一个配置文件,当使用分布式培训任务的kubectl kicks 应用时。在您最喜欢的文本编辑器中打开它,仔细查看。

首先你会注意到kind: TrainingJob。这表明你将提交一份亚马逊 SageMaker 培训工作。

在超参数下,指定cifar10-multi-gpu-horovod-sagemaker.py可以接受作为输入的超参数。
为分布式培训指定附加参数:
sagemaker_program—cifar 10-multi-GPU-horo VOD-sage maker . py tensor flow 培训脚本,实现用于分布式培训的 Horovod APIsagemaker_submit_directory—亚马逊 S3 上培训脚本所在的位置sagemaker_mpi_enabled和sagemaker_mpi_custom_mpi_options—为分布式培训启用 MPI 通信sagemaker_mpi_num_of_processes_per_host—设置为请求实例上的 GPU 数量。对于有 8 个 GPU 的p3dn.24xlarge实例,将该值设置为 8。

通过从这里选择适当的容器来指定深度学习框架容器:
https://docs . AWS . Amazon . com/dlami/latest/dev guide/deep-learning-containers-images . html
Amazon SageMaker 会自动将sagemaker_submit_directory下指定的训练脚本下载到从 trainingImage 实例化的容器中。
要跟踪性能,您还可以指定一个指标定义。

在“资源配置”下,指定要在多少个实例或节点上运行此多节点培训。上面的配置文件指定它将在 32 个 GPU 上运行分布式训练。

最后,指定亚马逊 S3 上的数据集位置。这应该与您在运行upload _ source _ to _ S3 . ipynbJupyter notebook 以上传训练数据集时选择的存储桶名称相同。
要开始分布式培训,请运行:
kubectl apply -f k8s-sm-dist-training-script.yaml
输出:
trainingjob.sagemaker.aws.amazon.com/k8s-sm-dist-training-script created
要运行培训职务信息,请执行以下操作:
kubectl get trainingjob
输出:
NAME STATUS SECONDARY-STATUS CREATION-TIME SAGEMAKER-JOB-NAME
k8s-sm-dist-training-script InProgress Starting 2020-03-03T08:25:40Z k8s-sm-dist-training-script-91027b685d2811ea97a20e30c8d9dadc
现在导航到AWS Console > Amazon SageMaker > Training jobs
您将看到一个与kubectl get trainingjob的输出同名的新培训作业

要查看培训日志,请单击控制台中的培训作业,然后单击监视器部分下的“查看日志”。这将带您到 CloudWatch,您可以在那里查看培训日志。
或者,如果您安装了 smlogs 插件,那么您可以使用kubectl运行以下命令来查看日志:
kubectl smlogs trainingjob k8s-sm-dist-training-script
用例 2:使用定制容器的分布式培训
如果你正在使用定制的专有算法,那么你必须构建自己的 Docker 容器。要提交一个带有自定义容器的训练作业,首先要在本地构建容器映像,并将其推送到 Amazon Elastic Container Registry(ECR)。将映像推送到 ECR 后,您将使用 ECR 路径更新 Kubernetes 作业配置文件,而不是我们在前面的示例中提供的 TensorFlow 容器路径。
导航到第二个示例的目录:
cd kubernetes-sagemaker-demos/2-tf-dist-training-custom-container/docker
ls -1
输出:
build_docker_push_to_ecr.ipynb
cifar10-multi-gpu-horovod-sagemaker.py
Dockerfile
model_def.py
运行[build_docker_push_to_ecr.ipynb](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/2-tf-dist-training-custom-container/docker/build_docker_push_to_ecr.ipynb)来构建 docker 文件,并将其推送到 ECR 注册表。

导航至AWS Console > Amazon ECR。您应该会在这里看到新推出的 Docker 容器:

导航到
cd kubernetes-sagemaker-demos/2-tf-dist-training-custom-container/
在你最喜欢的文本编辑器中打开[k8s-sm-dist-custom-container.yaml](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/2-tf-dist-training-custom-container/k8s-sm-dist-custom-container.yaml)配置文件仔细看看。
您需要做的惟一更改是 trainingImage 部分,在这里您需要提供 ECR 注册中心中您将自定义容器推送到的位置。

要使用自定义容器启动分布式培训,请运行:
kubectl apply -f k8s-sm-dist-custom-container.yaml
输出:
trainingjob.sagemaker.aws.amazon.com/k8s-sm-dist-custom-container created
用例 3:利用 TensorFlow 进行大规模超参数优化
机器学习模型的超参数是在训练阶段没有优化或学习的选项,但是影响模型的性能。要提交 Amazon SageMaker 超参数调优作业,您需要创建一个 Kubernetes 配置文件kind: hyperparameterTuningJob,而不是前面两个例子中的trainingJob。
另一个区别是,这里您将指定超参数的范围,而不是固定的超参数,这样 Amazon SageMaker 可以尝试不同的选项来获得最佳模型。
导航到第三个示例的目录:
cd kubernetes-sagemaker-demos/3-tf-hyperopt-training-script
ls -1
输出
cifar10-training-script-sagemaker.py
inference.py
k8s-sm-hyperopt-training-script.yaml
requirements.txt
upload_source_to_s3.ipynb
运行[upload_source_to_s3.ipynb](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/3-tf-hyperopt-training-script/upload_source_to_s3.ipynb)将培训脚本上传至亚马逊 S3。

在您最喜欢的文本编辑器中打开[k8s-sm-hyperopt-training-script.yaml](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/3-tf-hyperopt-training-script/k8s-sm-hyperopt-training-script.yaml)配置文件仔细查看。

kind: HyperParameterTuningJob表明这是一项 Amazon SageMaker 模型调优工作。
在 resourceLimits 下,指定希望 hyperparameter tuner 运行多少训练作业,以便探索和找到最佳的 hyperparameter 集。maxNumberOfTrainingJobs 指定您希望使用不同超参数组合运行的作业总数,maxParallelTrainingJobs 指定您希望在任何给定时间对多少个实例运行此操作。策略可以是贝叶斯或随机的。

超参数可以是 integerParameterRanges、continuousParameterRanges 或 categoricalParameterRanges。在上面的例子中,优化器和批量大小是分类的,这意味着 Amazon SageMaker 将随机选择一个指定的值。对于学习速率和动量,Amazon SageMaker 会在指定范围内随机选取一个连续值。
要启动超参数优化作业,请运行:
kubectl apply -f k8s-sm-hyperopt-training-script.yaml
输出:
hyperparametertuningjob.sagemaker.aws.amazon.com/k8s-sm-hyperopt-training-script created
要获得有关超参数优化作业的更多详细信息,请运行:
kubectl get hyperparametertuningjob
输出
NAME STATUS CREATION-TIME COMPLETED INPROGRESS ERRORS STOPPED BEST-TRAINING-JOB SAGEMAKER-JOB-NAME
k8s-sm-hyperopt-training-script InProgress 2020-03-03T09:13:58Z 0 2 0 0 50d11d175d2f11ea89ac02f05b3bb36a
超参数调优作业产生了多个训练作业,您可以通过请求 kubectl 获得训练作业的列表来查看这些作业
kubectl get trainingjob
输出
NAME STATUS SECONDARY-STATUS CREATION-TIME SAGEMAKER-JOB-NAME
50d11d175d2f11ea89ac02f05b3bb36a-001-673da61b InProgress Starting 2020-03-03T09:14:11Z 50d11d175d2f11ea89ac02f05b3bb36a-001-673da61b
50d11d175d2f11ea89ac02f05b3bb36a-002-7952d388 InProgress Downloading 2020-03-03T09:14:11Z 50d11d175d2f11ea89ac02f05b3bb36a-002-7952d388
导航至AWS Console > Amazon SageMaker > Hyperparameter tuning jobs
您应该看到超参数调优工作正在进行中

用例 4:用 BYO 模型托管一个推理端点
要在 Amazon SageMaker 托管服务中部署模型,您只需将自己的模型放在压缩的 tar 文件中。如果您想要托管在 Amazon SageMaker 上训练的模型,那么输出将已经是所需的格式。
如果您运行上面的例子,只需导航到保存培训工作结果的亚马逊 S3 存储区AmazonS3 > YOUR_BUCKET > JOB_NAME > output。在这里,您应该可以找到一个名为model.tar.gz的文件,其中包含了培训模型。
导航到第四个示例的目录:
cd kubernetes-sagemaker-demos/3-tf-hyperopt-training-script
ls -1
输出
k8s-sm-inference-host-endpoint.yaml
在您喜欢的文本编辑器中打开[k8s-sm-inference-host-endpoint.yaml](https://github.com/shashankprasanna/kubernetes-sagemaker-demos/blob/master/4-tf-inference-host-endpoint/k8s-sm-inference-host-endpoint.yaml)配置文件,仔细查看。

在instanceType下指定托管的实例类型,如果您托管多个模型,请提供 A/B 测试的权重。在modelDataUrl下,指定受训模特在亚马逊 S3 上的位置。
要部署模型,请运行:
kubectl apply -f k8s-sm-inference-host-endpoint.yaml
输出:
hostingdeployment.sagemaker.aws.amazon.com/k8s-sm-inference-host-endpoint created
要查看有关托管部署的详细信息,请运行:
kubectl get hostingdeployments
输出:
NAME STATUS SAGEMAKER-ENDPOINT-NAME
k8s-sm-inference-host-endpoint Creating k8s-sm-inference-host-endpoint-cdbb6db95d3111ea97a20e30c8d9dadc
导航至AWS Console > Amazon SageMaker > Endpoints
您应该能够看到服务中的 Amazon SageMaker 端点,并准备好接受请求。

结论
在这篇博文中,我介绍了如何将 Kubernetes 和 Amazon SageMaker 结合起来,在运行机器学习工作负载时发挥两者的优势。
我简要介绍了用于 Kubernetes 的 Amazon SageMaker 操作符,以及如何使用它来利用 Amazon SageMaker 的功能,如分布式培训、超参数优化和托管可弹性伸缩的推理端点。之后,我向您展示了使用 Kubernetes CLI kubect提交培训和部署请求的一步一步的过程。
我在 GitHub 上提供了所有的配置文件,所以你可以随意使用它,修改它,让它成为你自己的。感谢阅读,所有代码和示例在 GitHub 上都有:
https://GitHub . com/shashankprasanna/kubernetes-sage maker-demos . git
如果你有问题,请在推特( @shshnkp ), LinkedIn 联系我或者在下面留言。尽情享受吧!
使用 AWS EKS 和 ECR 部署 Kubernetes 应用程序
使用 AWS EKS 和 AWS ECR 映像将应用程序部署到 Kubernetes。

库伯内特斯
Kubernetes 是 Google 在 2014 年创建的一个容器编排平台。它是一个开源平台,目前许多组织广泛用于容器部署和管理。尽管社区中有其他容器编排工具可用,如 Docker Swarm,但 Kubernetes 仍因其特性和灵活的可用性而保持容器编排的领先地位。
AWS EKS
亚马逊弹性 Kubernetes 服务是在 AWS 基础设施上为 Kubernetes 提供的服务。像 AWS 提供的任何其他服务一样,Kubernetes 资源将完全由 AWS 自己管理,这减少了开发人员维护它们的负担。AWS 还确保这些资源每次都高度可用和可靠。
AWS ECR
Amazon Elastic Container Registry 是 AWS 提供的一个完全托管的 Docker 注册表。就像流行的 docker 注册表 Dockerhub 一样,ECR 也支持非常安全的私有和公共存储库。我们可以使用 AWS CLI 将图像推送或拉入 ECR。

在本文中,我们将探讨如何使用 AWS EKS 和 ECR 服务部署 Kubernetes 应用程序。在深入了解我们将如何实施我们的 Kubernetes 解决方案的复杂细节之前,下面是我们将执行的任务的摘要。
- 使用 Node.js 创建一个简单的 web 应用程序
- 创建 web 应用程序的 docker 映像
- 将我们的 docker 图像推送到 AWS ECR
- 为我们的 EKS 集群创建一个包含公共和私有子网的 VPC
- 创建一个 Kubernetes 集群
- 创建 Kubernetes 工人(公共和私人工人)
- 在 Kubernetes 上部署我们的 web 应用程序
现在我希望你至少对我们将在这篇文章中涉及的内容有一点点概念。在我们开始实现之前,我们需要在我们的开发机器中具备以下先决条件。
先决条件
- Kubectl —我们将用来在我们的 Kubernetes 集群和我们的机器之间进行通信的通信工具。安装说明可从https://kubernetes.io/docs/tasks/tools/install-kubectl/获得
- AWS CLI — AWS 工具,我们将使用它发布与 AWS 配置相关的命令。要安装,请遵循https://docs . AWS . Amazon . com/CLI/latest/user guide/CLI-chap-configure . html
- Aws iam 认证者 —授予 iam 角色访问我们的 Kubernetes 集群的权限。用于安装https://docs . AWS . Amazon . com/eks/latest/user guide/install-AWS-iam-authenticator . html
- eks CTL—AWS EKS 官方 CLI 工具。对于安装 https://github . com/weave works/eks CTL
在满足我们的先决条件后,第一个任务将是创建一个简单的服务器。我使用 Node.js 和 express 来创建一个非常简单的 web 应用程序,它将在端口 3000 上进行侦听。
接下来,让我们对我们的 web 应用程序进行 dockerize。创建 docker 文件并发出 docker 构建命令。
docker build -t webapp .
现在,如果您发布 docker 图像,我们将看到我们的 webapp 图像。下一个任务是将我们的图像推送到 AWS ECR。
创建 ECR 存储库
在推送映像之前,我们需要在 ECR 上创建一个存储库。为此,转到 ECR 仪表板并点击创建存储库。

现在,我们有了一个存储库来推送我们的图像。但在此之前,我们需要验证我们的 AWS CLI,以便将图像推送到我们的存储库。对于下面的问题命令。
(Get-ECRLoginCommand).Password | docker login --username AWS --password-stdin 628640267234.dkr.ecr.ap-southeast-1.amazonaws.com
之后,用我们的库名标记图像。在这里作为版本,你可以给任何版本,但在这种情况下,我将使版本作为最新的。
docker tag webapp:latest 628640267234.dkr.ecr.ap-southeast-1.amazonaws.com/eks-demo:latest
现在是最后一步,将我们的映像推送到 ECR 存储库。
docker push 628640267234.dkr.ecr.ap-southeast-1.amazonaws.com/eks-demo:latest

如果您遇到任何权限问题,请确保您的 AWS CLI 角色拥有权限amazonec 2 containerregistryfull access。

现在转到我们的存储库,我们推送的图像应该在那里可用。
正在创建 AWS EKS 集群
下一步是创建我们的 EKS 集群。创建集群时,我们需要指定集群要使用的 VPC 子网。亚马逊 EKS 需要至少两个可用区域中的子网。创建 VPC 时,我们有两个选择。
- 创建公共和私有子网
- 仅创建公共子网
在本文中,我们将创建公共子网和私有子网的组合。在这种情况下,可以使用公共子网从外部访问我们的 web 应用程序,此外,如果我们需要部署数据库之类的东西,我们可以将它们设为私有,只有我们的 web 应用程序和 VPC 内的任何其他应用程序可以访问它们。
创造 VPC
如果需要,可以手动为我们的集群创建 VPC。但是让我们使用 AWS Cloudformation 创建我们的 VPC,因为 AWS 已经有了一个创建公共和私有子网 VPC 的模板。
- 转到 CloudFormation dashboard 并选择创建堆栈
- 在这里选择模板源作为亚马逊 S3 网址,并提供以下模板已经由 AWS 创建。
[https://amazon-eks.s3.us-west-2.amazonaws.com/cloudformation/2020-06-10/amazon-eks-vpc-private-subnets.yaml](https://amazon-eks.s3.us-west-2.amazonaws.com/cloudformation/2020-06-10/amazon-eks-vpc-private-subnets.yaml)

- VPC 的 CIDR 地址将是 192.168.0.0/16
- 使用 CIDR 地址块 192.168.0.0/18 和 192.168.64.0/18 创建两个公共子网
- 使用 CIDR 地址块 192.168.128.0/18 和 192.168.192.0/18 创建两个私有子网

最后,选择 Create 并等待直到栈被创建。在堆栈创建的最后,它将给出 3 个输出。

- SecurityGroups —这是为我们的 VPC 创建的安全组。
- SubnetIds —我们创建的 4 个子网的 id。A
- VpcId —创建的 VPC 的 Id。
用工人创建 EKS 集群
我们可以通过给出 eksctl create cluster 命令来轻松创建集群。但是让我们用下面的附加配置创建一个 YAML 文件。
在上面的 cluster.yaml 文件中,我们为集群定义了以下配置。
- 集群名称将为 EKS 演示集群
- 在 vpc 部分,我们提供了之前已经创建的 VPC
- 在节点组中,我们使用 t2.meduim 实例创建 3 个 workers。三个工人中有两个将被创建为公共工人,而一个将被创建为私有工人。
现在发出下面的命令,在 EKS 上创建我们的集群。
eksctl create cluster -f cluster.yaml **--kubeconfig**=C:\Users\{user}\.kube\config

之后,eksctl 将根据我们的 YAML 文件开始创建我们的集群。创建群集和节点将需要几分钟时间。在 get issue 下面的命令检查我们的集群是否已经部署。
kubectl get svc

当您发出 kubectl 命令时,有时可能会得到以下错误。这可能意味着在我们的 kubectl 配置文件中,没有定义访问集群所需的凭证和用户。
error: no configuration has been provided, try setting KUBERNETES_MASTER environment variable
要将这些配置详细信息写入配置文件,请发出以下命令。
aws eks --region {region} update-kubeconfig --name EKS-Demo-Cluster
创建部署清单
现在让我们开始在创建的 Kubernetes 集群上部署我们的应用程序。首先,要在 pods 上部署我们的应用程序,我们需要创建一个部署。下面是将用于部署的部署清单。
- 我们的应用标签将是 app:web
- 在规格:模板:规格:容器中为我们推送的 AWS ECR 图像设置图像
- 应用程序的副本数量为 2
发出以下命令来创建我们的部署。
kubectl apply -f deployment.yaml
要检查我们的部署是否已创建,请发出以下命令。
kubectl get deployments


现在,我们可以看到我们的部署已经创建并运行在两个 pod 上。
创建服务清单
现在要访问我们的应用程序,我们需要创建一个服务。我们的服务类型将是节点端口,因为我们需要我们的应用程序从外部访问。
- 服务类型为节点端口
- targetPort 是 3000 ,因为这是我们的集装箱暴露端口
- 选择器将是 app:web ,因为这是我们在部署中定义的标签
根据命令创建我们的服务问题
kubectl apply -f service.yaml
要检查我们的服务是否已创建,请发出以下命令。
kubectl get services

现在让我们尝试从外部访问我们的 web 应用程序。从服务中,我们知道我们的应用程序正在侦听端口 31479。接下来,我们需要获取应用程序节点的公共 IP 地址。让我们首先尝试确定我们的应用程序在哪里运行。
kubectl get pods -o wide
由此,我们可以识别我们的应用程序正在运行的 pod 的节点。要获取这些节点的外部 IP 地址,请发出 get nodes 命令。

kubectl get nodes -o wide

在上面的节点列表中,我们可以看到两个节点有外部 IP,而一个没有,因为我们将其配置为私有工作节点。现在我们有了我们的 IP 地址以及它正在监听的端口。下一个任务是将此端口添加到节点的安全组中,以允许流量进入。并添加入站规则以允许端口 31479 中流量。

之后,我们可以获得一个公共节点 IP 地址,并使用端口 31479 调用它。

我们也可以对其他 IP 地址做同样的事情,结果应该是一样的。
下一个任务是将数据库部署到我们的 Kubernetes 集群中。但是我会把这个任务留给你去尝试。之后,确保通过发出以下命令删除集群,以避免对我们创建的 EC2 实例收费。
eksctl delete cluster --region=ap-southeast-1 --name=EKS-Demo-Cluster

这就是如何使用 AWS EKS 和 ECR 创建和部署应用程序到 Kubernetes。在 Kubernetes 和 EKS 上还有很多其他的概念值得我们学习。因此,一定要不断学习,直到你有信心部署和管理应用程序。谢谢你。
Kubernetes 开发:超越配置文件
关注你的代码,而不是基础设施!

图片来自皮克斯拜
许多故事称赞 Kubernetes 是自动化部署、扩展和管理容器化应用程序的优秀工具。我支持这一点;Kubernetes 正在努力减轻微服务架构的痛苦并应对其挑战。
然而,Kubernetes 上的当地发展可能是一个痛点。典型的工作流程由几个步骤组成;在本地测试您的应用程序,构建并标记 docker 映像,创建部署配置,最后在 Kubernetes 上运行您的应用程序。如果有一个 bug 或者一个新的特性需要集成,开发者需要从头开始遵循同样的过程。在他们的 Next’19 演示中,谷歌工程师称之为痛苦和折磨的无限循环。
在之前的故事中,我们介绍了 Skaffold,这是 Google 的一个轻量级开源项目,它促进了本地 Kubernetes 的开发。你可以在这里了解更多信息:
在 Kubernetes 上开发时,痛苦和苦难的无限循环已经成为过去。
towardsdatascience.com](/kubernetes-local-development-the-correct-way-1bc4b11570d8)
但是,有没有更自然的方法来解决当地 Kubernetes 发展的挑战呢?我们能不能只关注我们的代码,而把基础设施排除在我们的逻辑之外?嗯,输入云码!

云代码(Cloud Code)是 Google 云平台的一套开发工具,包括 Visual Studio 代码和几个 JetBrains 产品的 IDE 扩展。它促进了本地或远程 Kubernetes 集群上的开发、部署和调试。它使用 Skaffold,所以让我们更深入地了解为什么以及如何使用它!
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
你可能需要的一切
云代码是一个 IDE 扩展,它支持迭代开发,并使本地和远程集群上的调试变得轻而易举。该工具提供了几个功能,让您专注于工作中有趣的部分。
- 帮助处理 Kubernetes 配置文件;云代码提供了完成建议、林挺、内联文档和代码片段。编写 Kubernetes 配置文件从来没有那么容易。
- 自动化部署流程;云代码自动化了我们在序言中看到的工作流程步骤。只需一个命令,我们就可以构建、推送和部署我们的应用程序,并在发生任何变化时自动重新部署它。此外,在远程集群上调试就像在笔记本电脑上调试代码一样。
- 提供一个公用事业的世界;云代码为调试配置端口转发和入口点,并提供图形用户界面与部署进行交互。
装置
要安装云代码,只需将其作为扩展添加到您最喜欢的 IDE 中。例如,我更喜欢使用 Visual Studio 代码。因此,要将它添加到 VS 代码中,请在扩展面板中搜索它,然后单击 install。它会在你的工具条上添加一个或多个新图标。
简单的例子
在本节中,我们将使用一个简单的 Flask 应用程序,它将" Hello World" 打印到屏幕上。我们将使用通过云代码提供的模板。选择的 IDE 是 VS 代码,因此,从屏幕底部选择Cloud Code,然后选择New Application。然后,选择Kubernetes Application、Python (Flask): Hello World模板和路径来初始化你的项目。

使用云代码创建新的应用程序
该模板已经有一个包含我们的应用程序逻辑的src文件夹,一个包含部署和服务 YAML 配置文件的kubernetes-manifests文件夹,以及一个设置 Skaffold 配置的skaffold.yaml文件。
接下来,我们可以从底部的菜单中选择Cloud Code菜单项,选择Run on Kubernetes。接下来,您应该选择要部署到的集群和要推送容器映像的注册表。我正在本地 docker 集群上部署应用程序;因此,不需要选择注册表。云代码将构建您的图像,标记它并将其推送到注册表。然后,它会将它部署在您选择的集群上。如果这是您第一次执行循环,可能需要一段时间!

使用云代码运行您的应用
只要该过程成功完成,就会为您提供一个链接来查看结果。然后,如果您更改了某些内容,只要您保存了文件,就可以观看它的实时更新!
最后,您可以轻松地调试代码。从 VS 代码的调试视图中选择Debug on Kubernetes,然后按按钮!接下来,设置一个断点,从浏览器刷新应用程序,观察调试器的神奇之处。

使用云代码调试应用程序
要更深入地研究云代码,请查看它的文档,尤其是您选择的 IDE 的快速入门指南。例如,这里的是 VS 代码的向导。
结论
在这个故事中,我们看到了如何打破每个试图在 Kubernetes 上进行本地开发的开发人员所面临的痛苦和折磨的无限循环。我们引入了云代码,这是一个强大的 IDE 扩展,可用于 Visual Studio 代码和几个 JetBrains 产品。
云代码通过提供一组丰富的特性来优化开发工作流,这些特性可以自动化映像构建、标记和部署的过程。此外,它支持在本地和远程 Kubernetes 集群上进行调试,并完全支持编写 Kubernetes 配置文件。
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
关于作者
我叫迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
Kubernetes HPA 采用来自 Prometheus 的定制指标
当需要基于自定义指标的 K8s pod 自动扩展时,可以使用一个有用的示例和分步指南。
我决定编写这些步骤,因为我最近参与了将一个复杂的应用程序从 AWS 迁移到 GCP 的工作,与其他此类系统一样,我们不能仅仅依靠 CPU 或内存使用指标来满足它们的 SLA。
自动扩展是一种根据资源使用情况自动扩大或缩小工作负载的方法。K8s 水平 Pod 自动缩放器:
- 被实现为一个控制循环,它通过 metrics.k8s.io API 定期查询资源指标 API 以获取核心指标、,如 CPU/内存和自定义指标 API 以获取应用特定指标 (external.metrics.k8s.io 或 custom.metrics.k8s.io API)。它们由 metrics 解决方案供应商提供的“适配器”API 服务器提供。有一些已知的解决方案,但是这些实现都不是 Kubernetes 的正式部分
- 根据观察到的指标,自动调整部署或副本集中的单元数量。
在下文中,我们将重点关注自定义指标,因为自定义指标 API 使得像 Prometheus 这样的监控系统能够向 HPA 控制器公开特定于应用的指标。
为了基于自定义指标进行扩展,我们需要两个组件:
- 一个从我们的应用程序中收集指标,并将它们存储到 Prometheus 时间序列数据库中。
- 第二个扩展了 Kubernetes 定制度量 API,使用收集器提供的度量,即 k8s-prometheus-adapter 。这是一个自定义指标 API 的实现,它试图支持任意指标。

配置 HPA 的分步指南
- 让我们假设我们有以下两个应用程序(名为 myapplication )特定的指标发布给 Prometheus,它正在我们的集群中监听 http://Prometheus-server . Prometheus:
**myapplication_api_response_time_count**{endpoint="api/users",environment="test",environment_type="development",instance="10.4.66.85:9102",job="myapplication-pods",namespace="myapplication",pod="myapplication-85cfb49cf6-kvl2v",status_code="2xx",verb="GET"}
和
**myapplication_api_response_time_sum**{endpoint="api/users",environment="test",environment_type="development",instance="10.4.66.85:9102",job="myapplication-pods",namespace="myapplication",pod="myapplication-85cfb49cf6-kvl2v",status_code="2xx",verb="GET"}
我们希望根据端点延迟来扩展我们的应用单元。
2.既然我们已经有了 Prometheus metrics,使用 Prometheus 适配器从 Prometheus 提供 metrics 是有意义的。Kubeapps Hub 上列出了一个舵图,名为stable/Prometheus-adapter,可用于安装适配器:
helm install --name my-release-name stable/prometheus-adapter
3.使用my application _ API _ response _ time _ avg自定义指标配置适配器:
prometheus-adapter:
prometheus:
url: http://prometheus-server.prometheus
port: 80
rules:
custom:
- seriesQuery: '{__name__=~"myapplication_api_response_time_.*",namespace!="",pod!=""}'
resources:
overrides:
namespace:
resource: namespace
pod:
resource: pod
name:
matches: ^(.*)
as: "myapplication_api_response_time_avg"
metricsQuery: 1000 * (sum(rate(myapplication_api_response_time_sum[5m]) > 0) by (<<.GroupBy>>) / sum(rate(myapplication_api_response_time_count[5m]) > 0) by (<<.GroupBy>>))
我们公开了my application _ API _ response _ time _ avg,这将被 HPA 查询。每个规则必须指定一些资源覆盖,并且 metricsQuery 告诉适配器在检索数据时应该执行哪个 Prometheus 查询。
4.使用以下命令检查指标的值,该命令向 Kubernetes API 服务器发送一个原始的 GET 请求:
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/myapplication/pods/*/myapplication_api_response_time_avg" | jq .
响应:
{
"kind":"MetricValueList",
"apiVersion":"custom.metrics.k8s.io/v1beta1",
"metadata":{
"selfLink":"/apis/custom.metrics.k8s.io/v1beta1/namespaces/myapplication/pods/*/myapplication_api_response_time_avg"
},
"items":[
{
"describedObject":{
"kind":"Pod",
"namespace":"myapplication",
"name":"myapplication-85cfb49cf6-54hhf",
"apiVersion":"/v1"
},
"metricName":"myapplication_api_response_time_avg",
"timestamp":"2020-06-24T07:24:13Z",
"value":"10750m",
"selector":null
},
{
"describedObject":{
"kind":"Pod",
"namespace":"myapplication",
"name":"myapplication-85cfb49cf6-kvl2v",
"apiVersion":"/v1"
},
"metricName":"myapplication_api_response_time_avg",
"timestamp":"2020-06-24T07:24:13Z",
"value":"12",
"selector":null
}
]
}
注意,API 使用 Kubernetes 风格的数量来描述度量值。在 metrics API 中最常见的是m后缀,这意味着毫单位,或一个单位的千分之一。如果度量正好是单位的整数,我们可能看不到后缀。
例如,在这里,10750m将是 10,75 毫秒,12将是 12 毫秒
5.创建一个 HPA,如果my application _ API _ response _ time _ avg暴露的延迟超过 500 ms,该 HPA 将按比例增加my application-deployment,几秒钟后,HPA 从 metrics API 中获取my application _ API _ response _ time _ avg值。
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: myapplication-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapplication-deployment
minReplicas: 3
maxReplicas: 15
metrics:
- type: Pods
pods:
metricName: myapplication_api_response_time_avg
targetAverageValue: "500"
6.检查新创建的 HPA。我们可能会注意到,自动缩放器不会立即对延迟峰值做出反应。默认情况下,指标同步每 30 秒发生一次,只有在过去 3-5 分钟内没有重新缩放的情况下,才会发生缩放。通过这种方式,HPA 可以防止冲突决策的快速执行,并为集群自动伸缩提供时间。
kubectl describe hpa myapplication-hpa -n myapplication
结论
处理自动伸缩基本上是每个生产就绪系统中的一项常见任务,我在引言中提到的应用程序也是如此,例如,为了处理突发流量,我们必须根据延迟进行自动伸缩。通过检测该应用程序,并通过 Prometheus 公开正确的指标进行自动扩展,我们可以对其进行微调,以更好地处理突发事件并确保高可用性。
Kubernetes 地方发展:正确的道路
在 Kubernetes 上开发时,痛苦和苦难的无限循环已经成为过去。

图片来自皮克斯拜

Kubernetes 是自动化部署、扩展和管理容器化应用程序的优秀工具。然而,Kubernetes 上的当地发展可能是一个痛苦的过程。典型的工作流程由几个不同的步骤组成;在本地检查代码的功能,构建并标记 docker 映像,创建部署配置并在 Kubernetes 上部署。如果有 bug 或需要升级,开发人员需要从头开始遵循相同的过程。在他们的 Next’19 演示中,谷歌工程师称这是痛苦和折磨的无限循环,那么,有没有一种方法可以自动化降低生产力的部分,让开发人员专注于他们代码的逻辑?介绍斯卡福德;
Skaffold 是 Google 的一个轻量级开源项目,它促进了本地 Kubernetes 的开发。它跨环境运行,通过提供一组丰富的特性来优化开发过程,这些特性对于原生 Kubernetes 开发是必不可少的,包括图像标记、资源端口转发和日志记录、文件同步等等。
学习率是为那些对 AI 和 MLOps 的世界感到好奇的人准备的时事通讯。你会在每周五收到我关于最新人工智能新闻和文章的更新和想法。在这里订阅!
斯卡福德来救援了!
Skaffold 提供了一个 CLI(命令行界面),可以在本地和远程集群上进行迭代开发。该工具提供了几个特性,使得在 Kubernetes 上进行本地开发成为一种乐趣。
- 轻量级开源 CLI 工具。Skaffold 没有服务器端组件,因此您在集群上没有开销或维护负担。
- 检测源代码中的变化,并自动构建/推送/部署。ska fold 会在源代码发生变化时检测到变化(只要您保存了文件),自动启动管道来构建、标记、推送和部署您的应用程序。此外,Skaffold 聚合来自运行中的容器的日志,并将容器端口转发到主机。
- 增加项目的可移植性。斯卡福德让项目共享小菜一碟;您团队中的任何开发人员现在都可以
git clone和skaffold run项目,并在几秒钟内运行应用程序。此外,让新成员加入您的团队比以往任何时候都容易;不再需要安装指南和配置更改。 - 开发与生产。Skaffold 配置文件、用户级配置语句和环境标志可以描述如何在不同的环境中部署应用程序,甚至可以描述应用程序的哪个部分将被部署,从而实现细粒度的功能和集成测试。
装置
要安装 Skaffold,请遵循文档中提供的说明,或者访问 GitHub 发布页面获取特定版本。Skaffold 提供 Linux、OSX 和微软 Windows 的安装选项,以及 docker 镜像。例如,在 Linux 上安装 Skaffold CLI 就像执行以下命令一样简单:
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
sudo install skaffold /usr/local/bin/
该命令安装 Skaffold 的最新稳定版本。如果您想要特定的版本(例如版本 1.10.1 ),只需将命令更改为以下内容:
curl -Lo skaffold [https://storage.googleapis.com/skaffold/releases/v1.10.1/skaffold-linux-amd64](https://storage.googleapis.com/skaffold/releases/v1.10.1/skaffold-linux-amd64) && chmod +x skaffold && sudo mv skaffold /usr/local/bin
简单的例子
在本节中,我们将使用 Skaffold GitHub 页面上提供的简单的 Go 应用程序示例。因此,有一个简单的 Go 应用程序可以打印" Hello world!“每秒钟:
现在我们需要一个 docker 文件来封装应用程序,并为 Kubernetes 部署做好准备:
FROM golang:1.12.9-alpine3.10 as builder
COPY main.go .
RUN go build -o /app main.goFROM alpine:3.10
ENV GOTRACEBACK=single
CMD ["./app"]
COPY --from=builder /app .
现在您可能会注意到这个 Dockerfile 文件的一些奇怪之处:它有两行FROM。这种技术被称为构建器模式,用于生成较小的容器。在这种情况下,我们使用第一个容器来编译代码,因为golang:1.12.9-alpine3.1映像为这项工作提供了所有必要的工具,而第二个映像只复制已编译的二进制文件并运行应用程序。因此,我们可以将集装箱的占地面积减少几个数量级。
现在我们有了 Dockerfile 文件,我们需要部署 YAML 配置文件:
apiVersion: v1
kind: Pod
metadata:
name: getting-started
spec:
containers:
- name: getting-started
image: skaffold-example
该文件获取图像getting-started并将其部署在 pod 中。这就是痛苦停止的地方。我们现在可以运行skaffold init并让工具检测我们的资源并生成斯卡福德 YAML 配置文件。
apiVersion: skaffold/v2beta4
kind: Config
metadata:
name: skaffold
build:
artifacts:
- image: skaffold-example
deploy:
kubectl:
manifests:
- pod.yaml
我们现在可以运行skaffold run,Skaffold 将构建我们的映像并将其部署到我们本地的 Kubernetes 集群。如果这还不够,尝试运行skaffold dev。这条语句将完全执行前面的命令,而且还会聚合容器的日志并打印出来。现在,如果您进行了更改并保存了文件,请注意,它会立即检测到更改并再次开始构建/标记/部署周期。

Kubernetes 与 Skaffold 的互动地方发展
默认情况下,Skaffold 使用 Git 标签来管理你的图片,因此如果你运行docker image ls,你会看到类似这样的内容:

斯卡福德 git 标签
要深入了解,请查看 Skaffold 的文档示例或该工具的 GitHub 页面。最后但同样重要的是,Skaffold 与其他 Kubernetes 工具配合得很好,例如 Kustomize 和 Jib ,因此,您不必改变当前的工作流程。
结论
在这个故事中,我们介绍了每个试图在 Kubernetes 上进行本地开发的开发人员所经历的痛苦和折磨的无限循环。然后,我们介绍了 Skaffold,这是一个开源 CLI,它通过提供一组丰富的特性来优化开发工作流,这些特性对于原生 Kubernetes 开发来说是必不可少的,包括图像标记、资源端口转发和日志记录、文件同步等等。
在以后的文章中,我们将通过为 Skaffold 引入一种图形用户界面来使事情变得更简单,在这里你只需按一个按钮就可以做同样的事情。敬请期待!
编辑:新的故事现在出版了!点击下面的链接…
关注你的代码,而不是基础设施!
towardsdatascience.com](/kubernetes-development-beyond-configuration-files-f78d7ab9a43)
关于作者
我叫迪米特里斯·波罗普洛斯,我是一名为阿里克托工作的机器学习工程师。我曾为欧洲委员会、欧盟统计局、国际货币基金组织、欧洲央行、经合组织和宜家等主要客户设计和实施过人工智能和软件解决方案。
如果你有兴趣阅读更多关于机器学习、深度学习、数据科学和数据运算的帖子,请关注我的 Medium 、 LinkedIn 或 Twitter 上的 @james2pl 。此外,请访问我的网站上的资源页面,这里有很多好书和顶级课程,开始构建您自己的数据科学课程吧!
具有外部环境配置的应用程序的 Kubernetes 模式
实践教程
通过使用 git-sync、Kubernetes init-containers、配置映射和卷,将配置生命周期与应用程序生命周期分离

将配置生命周期与应用程序生命周期分离。(图片由作者提供)
每个应用程序都需要配置,我们需要在不重新创建应用程序工件或映像的情况下灵活地适应这种配置。这构成了连续交付方法的模式。
问题
在一个容器化的世界中,我们如何让应用适应不同的开发、试运行、沙盒和生产环境?答案是使用外部配置数据,这对于每个环境都是不同的。
通常,最好将所有配置数据保存在一个地方,而不是分散在不同的资源定义文件中。例如,一个这样的地方可以是具有以下两个主要优点的 Git 存储库:
- 您可以免费获得版本控制配置数据和审计。
- 所有工程师都有权限更改不同环境的配置,包括生产环境
坏处呢?您已经弄清楚了:围绕敏感配置数据的安全问题。在那里保存任何凭证是一种反模式,因此一个想法是使用占位符。
解决办法
Kubernetes 为常规和机密数据提供本地配置资源。这些是分别用于通用目的和敏感数据的配置图和秘密对象。我们可以以同样的方式使用这两者,因为它们都提供了键值对的存储和管理。除了实际的数据编码(对于机密来说是 Base64)之外,配置映射和机密的使用在技术上没有区别。
简单地说,我们问题的解决方案在于在应用程序启动之前使用 Git 存储库。占位符被替换为来自 Secrets 的值,Secrets 可以通过 Terraform 或任何用于 Kubernetes 的 GitOps 连续交付工具创建。
让我们来看一个例子:
假设您有一个 Git 存储库,其中包含为每个环境分组的文件,工程师可以在其中更改任何内容,安全凭证是不可见的,而是用占位符替换。
database . properties就是这样一个既有简单配置数据又有凭证的文件
connectionHost=${mysql_hostname}
connectionUserName=${mysql_username}
connectionPassword=${mysql_password}
connectionPort=3306connectionPool.maxIdle=90
connectionPool.maxActive=100
connectionPool.maxWait=20000
connectionPool.testSQL=SELECT 1
我们上面提到了用于替换占位符的秘密。一旦创建了秘密并保存了数据,我们就可以使用秘密的密钥作为映射到 Pod 中装载的卷的文件。一个秘密备份的卷包含与条目一样多的文件,映射的关键字作为文件名,映射的值作为文件内容。
当通过 Kubernetes API 更新密码时,安装的密码卷中的文件也会更新。因此,如果应用程序支持配置文件的热重新加载,它可以立即从这样的更新中受益。在我们的例子中,我们保持这个例子简单,我们将考虑一次性配置加载,而不是热重新加载。
输入-占位符-文件-秘密 内容:
apiVersion: v1data:input-placeholders.properties: bXlzcWxfaG9zdG5hbWU9bG9jYWxob3N0Cm15c3FsX3VzZXJuYW1lPXJvb3QKbXlzcWxfcGFzc3dvcmQ9cGFzc3dvcmQ=kind: Secretmetadata:creationTimestamp: "2020-09-27T10:04:01Z"name: input-placeholders-files-secretnamespace: my-main-applicationresourceVersion: "45565287"selfLink: /api/v1/namespaces/my-main-application/secrets/input-placeholders-files-secretuid: 818229c3-b986-44a9-a8a5-e235557f98a7type: Opaque
现在我们有了秘密和属性项目,让我们把它们粘在一起。
Kubernetes 有另一个资源: init 容器。它通过为与初始化相关的任务提供独立的生命周期来分离关注点,与主应用程序容器不同。这允许保持容器的单一目的,并且应用程序容器可以由只关注应用程序逻辑的工程师创建。通常,init 容器应该很小,运行迅速,并成功完成。
Kubernetes 中的 Init 容器是 Pod 定义的一部分,它们按顺序一个接一个地执行,在应用程序容器启动之前,所有这些容器都必须成功终止。从这个意义上说,init 容器就像 Java 类中帮助对象初始化的构造函数指令。
除了 Kubernetes 中的 init 容器和秘密之外,Pod 中的卷共享非常适合这种配置和应用程序容器的链接。容器可以共享(外部)卷,但是它们还不能直接共享位于容器内的目录。
在我们的示例中,我们使用了一个init 容器(properties-sync),它提供了 Git 客户端功能,其唯一目的是克隆一个 Git 存储库。在 Pod 上安装一个空目录,并在 git-sync 的帮助下将 Git 存储库克隆到其中:****
- 一个简单的命令将 Git 存储库放入本地目录。
- 可以一次或定期从分支的头、git 标签或特定的 git 散列中提取。
- 可以通过认证或不认证的 HTTP 或 SSH。
另一个init 容器( 属性-占位符-替换)用于占位符替换使用包含克隆项目的共享卷,并将最终结果移动到主应用程序容器使用这些文件的新文件夹中。
然而,对于属性-占位符-替换 init 容器,我们需要一些来自基本映像的帮助来将配置数据复制到共享 Pod 卷。 busybox 是一个不错的选择,它仍然很小,但是允许我们使用普通的 Unix cp 命令来完成这个任务。**
因为两个 init 容器都是同一个 Pod 的一部分,所以它们可以访问同一个卷来共享数据。我们使用相同的机制将克隆的文件从 init 容器共享到主应用程序容器。
替换-占位符-后缀-挂钩 ConfigMap 是用于占位符替换的实际脚本
**kind: ConfigMap
apiVersion: v1
metadata:
name: "replace-placeholders-poststart-hook"
labels:
app: "my-main-application"
data:
replace-placeholders.sh: |
replace() {
local placeholders_input_files_location=$1
local files_to_update_location=$2
local input_file=merged-secret-files.properties
rm $input_file
echo "--- Starting to merge all the secret files."
for properties_file in $placeholders_input_files_location/*.properties; do
(cat "${properties_file}"; echo) >> $input_file;
done
echo "--- Finished to merge all the secret files."
if [ -f "$input_file" ]
then
echo "--- $input_file will be used to replace the placeholders."
while IFS='=' read -r placeholder_key placeholder_value
do
local placeholder_prefix='${'
local placeholder_suffix='}'
local placeholder_to_replace="${placeholder_prefix}${placeholder_key}${placeholder_suffix}"
find $files_to_update_location -type f -exec sed -i "s+${placeholder_to_replace}+${placeholder_value}+g" {} \;
done < "$input_file"
echo "--- Copy properties files to correct location /properties"
cp -R $files_to_update_location/* /properties
else
echo "--- No input file found to replace the placeholders: $input_file."
fi
}
replace "$INPUT_PLACEHOLDERS" "$GIT_SYNC_ROOT/sync/environments/$ENVIRONMENT_TYPE"**
在主应用程序的以下部署中,它作为卷被引用和装载:
**apiVersion: apps/v1
kind: Deployment
metadata:
name: my-main-application
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
app: my-main-application
template:
metadata:
labels:
app: my-main-application
spec:
imagePullSecrets:
- name: gitlab-registry
initContainers:
- name: properties-sync
image: "jlowin/git-sync"
imagePullPolicy: Always
volumeMounts:
- name: gitconfig-project
mountPath: /opt/properties_from_git
env:
- name: GIT_SYNC_REPO
value: "https://gitlab.com/my-domain/properties-project.git"
- name: GIT_SYNC_BRANCH
value: "master"
- name: GIT_SYNC_WAIT
value: "30"
- name: GIT_SYNC_USERNAME
value: "<some-username>"
- name: GIT_SYNC_PASSWORD
value: "<some-password>"
- name: GIT_SYNC_ROOT
value: /opt/properties_from_git
- name: GIT_SYNC_DEST
value: sync
- name: GIT_SYNC_ONE_TIME
value: "true"
- name: properties-placeholders-replacement
image: busybox
env:
- name: ENVIRONMENT_TYPE
value: "development"
- name: INPUT_PLACEHOLDERS
value: /opt/placeholders_from_secrets
- name: GIT_SYNC_ROOT
value: /opt/properties_from_git
volumeMounts:
- name: input-placeholders-files
mountPath: /opt/placeholders_from_secrets/input-placeholders.properties
subPath: input-placeholders.properties
- name: replace-placeholders-script-volume
mountPath: /opt/replace-placeholders.sh
subPath: replace-placeholders.sh
- name: gitconfig-project
mountPath: /opt/properties_from_git
- name: properties
mountPath: /properties
command: ['/bin/sh', '-c', '/opt/replace-placeholders.sh; echo finished;']
containers:
- name: my-main-application
image: "registry.gitlab.com/my-domain/my-main-application-image-tag:v1"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
protocol: TCP
volumeMounts:
- name: properties
mountPath: /properties
volumes:
- name: input-placeholders-files
secret:
secretName: input-placeholders-files-secret
- name: gitconfig-project
emptyDir: {}
- name: properties
emptyDir: {}
- name: replace-placeholders-script-volume
configMap:
defaultMode: 0755
name: "replace-placeholders-poststart-hook"**
部署的 Pod 模板规范包含以下内容:
- 输入-占位符-文件-包含秘密存储的输入-占位符.属性
- gitconfig-project —类型为 emptyDir,它在托管此 Pod 的节点上创建为一个空目录;这里克隆了 Git 项目。
- 属性 —配置数据的最终目的地,占位符替换为 Secret 中的值,由主应用程序容器使用
- **replace-placeholders-script-volume—包含用于替换 Git 项目中占位符的脚本,从 config mapreplace-placeholders-poststart-hook挂载
正如您所注意到的,部署包含两个 init 容器属性-同步和属性-占位符-替换 和主应用程序容器my-main-application。****
属性-同步:
- 在启动时被调用,并从映像jlowin/git-sync构建。
- GIT_SYNC_ONE_TIME 告诉它只同步一次,这只是为了保持示例的简单,并且不使用 sidecar。
- 从 gitconfig-project 挂载的 GIT_SYNC_ROOT 是 GIT 文件的目标文件夹。
- 与下一个 init 容器共享 gitconfig-project 卷。
属性-占位符-替换:
- 在 properties-sync 之后立即启动,并安装上述 4 个卷:输入-占位符-文件、git config-项目、属性、替换-占位符-脚本-卷**
- 最后是运行从 config mapreplace-placeholders-post start-hook挂载的/opt/replace-placeholders . sh脚本****
我的主应用:
- 正在挂载卷属性以访问由属性-占位符-替换初始化容器复制的配置。****
使用这种模式,我们不仅可以使用版本化的配置数据,还可以克服存储在环境变量、配置映射或机密中的配置数据的大小限制。Kubernetes 配置资源有其局限性:由于 Secrets/ConfigMaps 的大小限制为 1 MB,它们不能存储任意大的数据,并且不太适合所有的配置应用程序数据。真实世界的 Kubernetes 集群还对每个名称空间或项目可以使用的 ConfigMap 的数量设置了单独的配额,因此 config map 并不是一个金锤。
我希望您喜欢阅读本分步指南,并理解如何使用不同的 Kubernetes 对象来定义配置模式,以便使应用程序适应云上不同的配置需求。
无服务器是 Kubernetes 的末日吗?
对两种技术进行比较,以结束孰优孰劣的争论。

总部,我又做了一次。我用了这个醒目的标题,是为了一定要引起你的注意,对此表示抱歉。我需要你们的注意来介绍这个大主题,以供思考。你认为 Kubernetes 是 DevOps 世界上最后一个最好的广告技术吗?今天,技术比以往任何时候都更短暂,你必须为变化做好准备。我喜欢 Kubernetes,我很高兴再次谈论它。这是在 DevOps 场景中最热门的流行语。阅读这篇文章你会找到这个大问题的答案:
这是基础设施管理的最终解决方案,还是我们需要把赌注压在无服务器上,让我们的心远离运营团队?记住, NoOps 来了。
我认为技术上的变化是正常的。我们的祖先乘马车旅行,我们乘飞机。这是进步的一部分。
在过去的几年中,有一场小革命,将越来越多的应用程序从虚拟机带到了容器中,这主要归功于使用 Kubernetes 进行部署的机会。
当这场革命发生时,有一个小而有力的流行词。是“无服务器”。大多数人认为它是邪恶的,其他人喜欢白马王子,可以将开发商从噩梦中拯救出来。好吧,让我们来看看有哪些问题和机会——安静,没有威胁即将出现!
Kubernetes 和 serverless 有什么区别?
无服务器是一种云模型,在这种模型中,您希望摆脱服务器和基础架构。目标是避免固定成本,减少上市时间和团队(运营和开发)之间的摩擦。具体来说,想象有一个层可以接收你的代码并负责执行。无服务器差不多就是这样。
你提供代码,供应商提供所有其他的。
最常见的无服务器实现具有带 SDK 的无状态容器,允许您的代码集成到系统中,并根据资源的使用情况向您开具发票。在大多数情况下,我们可以将我们的功能上传到云中(“FaaS”,功能即服务),该功能由 HTTP 调用激活。主要的云提供商提供类似的云体验:
- 亚马逊: AWS Lambda
- 微软 Azure: Azure 功能
- 谷歌云:云功能
当然,服务器并没有灭绝。你看不到它们,因为它们被供应商隐藏了,供应商使用它们来提供服务。服务器仍然存在,但你看不到任何内存、CPU 或磁盘空间。你只需要专注于代码。你可以把精力放在真正需要的地方。
还有什么是 Kubernetes?将 Kubernetes 视为一个框架,从简单的 docker 映像开始运行分布式系统。它可以满足您的扩展需求、部署和负载平衡。所有这些东西都可以很容易地用普通的 YAML 文件描述和重用,通过设计创建一个可复制的环境。
Kubernetes 是你手上的基础设施。
只需更改一些配置文件,您就可以完全控制容器实例(服务和容器)、网络和部署。Kubernetes 可以满足您的扩展需求、故障转移、部署模式等等。对于 Kubernetes 的新手,我在 Kubernetes 上写了一篇很好的介绍文章。

图片来自"到底什么是 Kubernetes "
Kubernetes 和 serverless 一样,只需要系统管理员很少的努力就可以实现复杂的架构。这种技术将人力密集型的传统部署转变为智能和快速的部署。嘿伙计们,诺普斯来了!
Kubernetes 有哪些优点?
使用 Kubernetes 的最大优势是,您可以像处理常规服务器场一样处理您的集群,但没有物理管理的成本。从逻辑上讲,您可以在服务器和集群组件之间重新创建并行性。您可以像实例化虚拟机一样实例化 pod 和服务。你有网络,存储等等。这意味着通过对集群的低级别访问,可以更深入地控制所有单个组件。
因此,我列出了使用 Kubernetes 而不是无服务器平台的优势:
- 与过去的兼容性很好。如果你在使用容器,那么迁移是很容易的,如果不是,那么只是容器化你的应用组件的成本。
- 对发生的事情有很大的控制力
- 更少的供应商锁定。Kubernetes 就是 Kubernetes,Docker 容器就是 Docker 容器。在纸面上,您只需点击一下鼠标就可以移动基础架构
- 微调每个组件的能力
- 也可以在本地运行(对于开发人员,或者极端情况,或者如果你只是疯了)
- 成本预测。您为群集的资源付费,这比无服务器方法更容易预测。
无服务器的优点是什么?
Kubernetes 在减少系统管理员工作量方面向前迈出了一大步,但并没有减少到零。基本上,无服务器方法避免了任何 sysadmin 组件,因为您唯一需要关心的是源代码。就像挑一套乐高积木,把它们拼在一起。每块砖都是独立工作的。你只需要让他们正常交流。就这样。FaaS 的解决方案似乎太难实施,因为它们需要思维方式的转变。在这种情况下,您可能会采用一些更软的无服务器解决方案,直接托管您的应用程序,无需更改。这种解决方案的一个很好的例子是 Heroku,它从服务器和传统 DevOps 中抽象出来,提供了一种 NoOps 无服务器体验,可以促进您的应用程序开发,减少所有托管摩擦(您还有一个免费层)。
无服务器是 Kubernetes 的末日吗?
如今,甚至无服务器似乎也是新事物,AWS Lambda 的首次发布是在 2014 年。那一年,Docker 正在迈出第一步(第一次正式发布是在 2013 年,我不确定在发布时它何时准备好用于生产场景)。Kubernetes 出生于 2014 年。因此,我们可以说,无服务器的出现与集装箱时代差不多。从这个角度来看,无服务器并没有紧随 Kubernetes 之后,我们也不能认为无服务器是容器的替代品。它们只是在 web 应用程序中实现托管部分的两种不同方法。也许在某些情况下,你可能更喜欢这个或那个。当一个和另一个。正确的答案是“视情况而定”,就像许多类似的问题一样。咨询师和优秀咨询师的区别在于,知道很多互补的解决方案,并根据场景找到最佳方案。
带什么回家
我们已经讨论了这两种解决方案的优点,然后我们可以说,仅仅通过了解技术,您就可以找到适合您的场景的最佳解决方案。使用像谷歌云或其他大型云服务,你将准备好实施任何解决方案。只是时间来试验他提供的工具,并了解利弊。
觉得这篇文章有用?在 Medium 上关注我(丹尼尔·方塔尼),看看我在下面 DevOps 上最受欢迎的文章!不要忘记👏这篇文章分享一下吧!
进军深度学习:从零开始的字符识别
使用自定义 CNN 分析汉字。
注意:对于本系列中的所有文章,我都遵循 fast.ai 关于实用深度学习的课程,并听从杰瑞米·霍华德的建议:做项目并写下它们。
这是一篇关于我参加 Kuzujishi 识别卡格竞赛的经历的文章。虽然目标是最终向竞赛提交参赛作品,但我使用了竞赛中的数据从头开始构建了一个字符识别网络。该数据集看起来像是常规 MNIST 数据集的一个不错的大胆扭曲 twist(修改后的国家标准与技术研究所)是一个包含超过 60,000 个用于识别任务的手写字符的数据库。
在这里,我讨论项目的第一部分:创建一个 Kuzushiji 字符识别模型。我跳过了数据的设置,因为这需要特定于数据最初是如何呈现的工作。尽管如此,在我的 GitHub repo 中仍然可以找到代码,链接在文章的末尾。
酷族世纪人物
当我开始这个项目时,我首先想知道的是“我需要识别多少个字符?”提供了每个字符及其 Unicode 表示的 csv,所以我加载了它并查看了一下:
unicodes = pd.read_csv(unicode_csv_path)
unicodes.shape(4781, 2)
有 4781 个字符!进一步检查发现,这些字符中有许多是与汉字字符集无关的符号。在创建数据集时过滤掉这些符号后,我剩下了 4213 个子文件夹。每个文件夹包含一个在数据集中至少出现过一次的字符样本。
在开始之前,让我们看一下我必须处理的一些图像:

从数据集中提取带有 unicode 标签的 Kuzushiji 字符(图片由作者提供)
这就是我保存图像的方式,但这里有一个原始图像的例子,没有改变:

单个 Kuzushiji 字符(图片由作者提供)
唯一的区别是前后图像之间的灰度变换。
加载数据
加载数据是一个挑战,但不是以我预期的方式。下面是使用data_block api 创建 databunch 的完整实现:
db = ImageList.from_folder('./char_images') \
.filter_by_func(filter_too_many) \
.use_partial_data(0.3) \
.split_by_rand_pct(0.3) \
.label_from_folder() \
.transform([[binarize()], [binarize()]], size=(32,32)) \
.databunch(bs=16)
我将一次剖析这一行。
首先,我从char_images文件夹中创建了一个ImageList。接下来,我使用一个定制函数filter_by_func(filter_too_many)过滤数据,这个函数有一个简短的实现:
def filter_too_many(filename):
num = filename.parts[-1].split('_')[-1].split('.')[0]
return int(num) < 500
来回答“你为什么这么做?”我们需要看一下现有的数据。这是每个角色数量分布的直方图。

当我绘制这个图时,问题变得很明显。大约有 100 个字符,样本超过 1000 个。其他的 3212 个字符要少得多。事实上,很多只有 1 或 2 个样本。我很清楚这是一个非常不平衡的数据集。
为了客观地看待这个问题,这里有一个链接,链接到一个 40,000 单词的数据集中的英语字符的分布。这里有一个链接,链接到中文中的汉字频率。在英语中,E 和 Z 的比例是 171 比 1。中文字符集的链接显示至少有 9000 个字符。Kuzushiji 有一半的字符计数。综上所述,Kuzushiji 并不特殊,在处理字符样本时,这种分布是可以预期的。
不平衡数据
不平衡数据是数据科学生态系统中一个研究得很好的问题。高质量、平衡的数据对于训练和验证模型至关重要。
在处理不平衡数据集时,您需要实施过采样和欠采样策略。您对少数数据进行过采样,以满足多数数据的数量。欠采样不太常见,因为这等同于丢弃数据。为了简化我的问题,我创建了 500 个少数民族字符的副本,对它们进行了过采样。然后,对于较大的标签,我也将这些字符类欠采样到 500。那是filter_too_many函数的责任。它会根据文件名过滤掉 500 份以上的副本。
关于我所采用的方法,有一个小小的警告:对于有一两个样本的角色,我每个都创建了 500 个副本,没有任何改动。在这之后,我把这些数据当作完美的。正如我从这篇关于主题的文章中了解到的,这并不理想。这些拷贝同时出现在训练和验证数据中。这可能提高了模型的准确性,因为该角色的训练集和验证集中的图像是相同的。像数据扩充这样的技术可以大大降低这种危险,因为每个角色都以某种微妙的方式变得不同。
处理大型数据集
与其他数据集相比,我的实际上并没有那么大。然而,在我自己的机器上,用 NVIDIA GeForce GTX 1080,训练有点烦人。因此,对于我的最后一次迭代,我只使用了 30%的数据,通过use_partial_data(0.3)实现。为了达到这个阶段,我经历了我的 databunch 和 model 的各种版本,我将在本文的后面讨论。就目前而言,知道我试图训练模型并等待看到结果的耐心正在变得稀薄就足够了,所以我坚持 30%。现在我可以离开模型训练一夜,第二天早上在我的桌面上看到结果。
转换
接下来的两行很简单——我将数据分成 70%的训练数据和 30%的验证数据,并根据每个文件所在的文件夹对它们进行标记。下一条线transform([[binarize()],[binarize()]], size=(32,32))是我花了一些时间的地方。我想了解 fastai 的转换 api 是如何工作的,看看我是否可以为自己的数据集创建一个。
Kaggle 竞赛网站指出,一些页面的另一面显示出模糊的字符轮廓。该模型只需要识别最前面的字符,而不是下面字符的模糊标记。我决定,对于每个字符,必须有一个像素阈值来区分背景和字符。事实证明,这个想法效果很好,去除了模糊的背景轮廓,使人物轮廓清晰。有时会有伪像,但这取决于角色图像的原始质量。下面是一个之前和之后的例子:

之前的示例图像,二值化。注意右上角和右下角的工件
当我为此编写代码时,有一些我没有预料到的复杂性。查看该函数的代码,并再次与调用它的代码行进行比较:
我首先创建了一个转换函数_binarize。它的实现包括使用 opencv 函数将张量转换成 numpy 数组,然后重新创建 torch 张量。在充分测试了这个函数之后,我用它实例化了一个TfmPixel。最后,我在一个列表中传递被调用的值,并重复这个过程两次。看来TfmPixel和Transform类有一个已定义的 call 函数。这也允许类作为一个函数,这就是为什么binarize()是有效的。除此之外,fastai 期望,对于定制转换,一个转换列表应用于训练集,一个转换列表应用于验证集。这就是为什么在代码中,我把binarize()放在两个列表中。这是 fastai api 中少数几个对我来说不太直观的部分之一。
批量大小和标准化
最后,我通过传递批量大小为 16 的数据并对数据进行规范化,完成了 databunch 的创建。就像我上面说的,这些也是我用来提高训练速度的变量,我会在后面提到。
创建 CNN
对我来说,将我在之前的文章中所做的应用迁移学习来解决这个问题是相当容易的,但是我没有。我从头开始构建我的模型有两个原因。首先,我可以学习如何正确地写出模型中的层次和交互。第二,理解模型的变化如何影响最终结果的变化。这是我最终模型的样子:
卷积、ReLU、BatchNorm
这三层包含了我在网络中使用的大部分魔法。但是我的模型并不像上面的代码那样。相反,我从小处着手,只有一两层,然后一步一步往上爬。其实我是先完全用 PyTorch 写的小网络,然后用 fastai 重写的。这迫使我钻研简单事情的源代码,例如“卷积滤波器的默认步长是多少”或“fastai 的conv_layer如何将所有这些层合并为一个层,它传递了哪些默认值?”
我编写了函数_conv2d_layer,让我可以快速决定要从多少个通道开始,而不用担心中间层的通道数。在每一步 2 回旋之后,我的网络在频道上加倍。我在查看 ResNet18 后做出了这个决定,因为我不想偏离那些经过良好测试的架构。这同样适用于我使用的频道数量。但是,即使在我写这篇文章的时候,我也反复地改变这个模型,因为新的想法不断涌现。在最终模型中,该架构在通过自适应池层之前在 512 个通道处截止。这是最终的架构,通过输出的镜头完全展开:

在他的 fast.ai 课程中,Jeremy 讨论了使用卷积的具体顺序,然后是校正线性单元(简称 ReLU),最后是批量归一化层。ReLU 选择并清除负激活。在数学上,只是max(0,x)其中 x 是激活。批量标准化有很多工作要做,我不认为我可以用数学来解释,但根据 Jeremy 的说法,它的要点可以归结为定义类似于y=ax+b的东西,其中批量标准化添加了a和b项,以将均值和方差转移到我们想要的位置。顺序问题,直观地说,ReLU 之后的批量范数层意味着试图移动均值和方差的工作不会浪费,因为激活不会被 ReLU 归零。
非常重要的是要注意,如果你正在阅读 fastai v1 文档,它说自定义conv_layer "返回 nn 的序列。Conv2D,BatchNorm 和一个 ReLU" 。这意味着批处理规范化在 ReLU 之前完成。但是,源代码讲述了一个不同的故事,一个 ReLU before batch norm。我发现这一点是因为我很困扰,因为医生暗示的序列与我的直觉告诉我的不同。直觉和一点“信任但核实”大有帮助。
头部
在将卷积层定制为我认为最有效的层之后,剩下的简单任务就是将这些激活映射到 1-hot 向量的 4212 个输出,我的网络将使用这些输出来预测结果。这被称为网络的“头”。例如,当使用预先训练的模型时,通常希望将模型的头部换成一组更特定于任务的层。网络卷积层的权重仍然存在,但最终层需要一点训练。
我保持我的最终层简单明了,应用一个池层,然后是批量标准化,下降,和完全连接的线性层。上面的代码使用了PoolFlatten和bn_drop_lin,都是 fastai 函数。
PoolFlatten先创建一个AdaptiveAvgPool2d 图层。然后,它加上一个 flatten 来创建大小为 512 的秩 1 张量。请记住,在此之前,该架构演示了卷积如何在增加通道数量的同时减少输入的宽度和高度。激活范围从 128x16x16 到 256x8x8 到 512x4x4。然后汇集发生,创建大小为 512 的秩一张量。我仍在学习自适应平均池的细节,包括何时使用它与最大池或两者都用。无论如何,在 CNN 的结尾,建议使用某种池来将激活转换为最后一层的正确输出形状。
bn_drop_lin是另一个 fastai treat,通过源代码比文字更好地解释。我要补充的唯一一点是,dropout 层减少了过度拟合,我知道我的模型可能会因为数据集中只有一个样本的字符而受到影响。
虽然您看不到它,但最终的 softmax 层也存在于网络中。Fastai 足够聪明,知道模型最终想要一个 softmax 层来创建一个合适的概率分布。它知道这是由于输出的性质,一个热码编码向量,和损失函数,交叉熵,用于分类任务。
训练 CNN
这是一个非常耗时的过程。我将回顾我所做的一切实验,但不幸的是,这是我记忆中的日志,而不是记事本或日志。下一次我准备这样做的时候,我需要把它写在一个单独的地方,这样我就可以查看我尝试过的所有变量。
优化 GPU 的使用
最初,我的训练需要两个小时或更长时间,使用 NVIDIA GeForce GTX 1080,我知道我会留下一些东西。果然,在查看gpustat -cp -i时,我只看到了 3–10%的 GPU 使用率。最初,我使用 128 或 256 的批处理大小,因为我没有用完内存。在阅读了大量论坛帖子后,我意识到,在这一点上,也许我的内存不是瓶颈,但通过我的binarize转换器的图像才是。许多作者建议使用优化的图像库,但是我认为这对于我的简单任务来说太难了。相反,我首先从我的数据中提取了一小部分。然后,我大幅减少了批量。最后,我不断地热然一个fit_one_cycle,不在乎最后的结果。我只是运行它,观察速度,内存使用,GPU 使用,然后停止它,重复。

GPU 处于最大使用率(是的,我已经将我的桌面命名为 smallrig)
对于 64x64 的图像,我开始看到批量大小为 4 的 GPU 得到了很好的利用。对于 32x32 的图像,一批 16 个似乎就可以了,而且速度快得多。
起初,我认为在将它们映射到一个 4212 独热编码张量之前,我需要更多的最终激活,所以我将最终通道大小强制增加到 1024。但是没有足够的通道起始数量,图像太小,以至于模型开始在 1×1 像素上进行步长 1 卷积。那没有任何意义。我必须提高我的通道的初始数量,以便输入激活不会减少到 1x1,直到最后的步幅 2 卷积。但是另一个问题突然出现了。训练后,错误率在 3%左右,训练损失为 0.02,验证损失为 0.15。策划损失并不愉快;验证损失并没有以任何稳定的方式减少,即使训练损失在减少。显然,我是过度拟合,即使与辍学层。因此,我退出了通道,并让激活设置为 512x4x4 张量,然后通过头部获得字符概率。这个模型经过训练后表现良好。
因此,我坚持使用 32x32 的图像,模型的批量大小为 16,512 个最终通道,以及最终的 512x4x4 激活张量,然后通过头部输入以获得字符概率。这个模型经过训练后表现良好。
实际训练
这里没有太多描述,只是一点点代码和图片。首先,我试图找到最佳的学习速度:
learn.lr_find()
learn.recorder.plot(skip_end=20)

一个很棒的图表。最初,我感到气馁,因为我的初始图形看起来非常平坦,在非常大的峰值之前,只有一个小的波谷。然而,正如我从论坛上了解到的,我需要切掉图的尾端。如果没有这一点,损失爆炸使 y 轴气球,这反过来使图表的其余部分变得无足轻重。用skip_end=20参数重试效果非常好。事实上,我忍不住创造了这个迷因:

我也可以这样初始化权重。或者当一个难懂的概念最终实现时。不要让我开始。
然后,我拟合了一段时间的模型
learn.fit_one_cycle(7, slice(1e-3), callbacks=[SaveModelCallback(learn,every='epoch', name='30pct32sz16bsN_model')])

看到 0.017 的错误率,我非常激动。看一下损失图表:
learn.recorder.plot_losses()

训练和验证的最终损失分别为 0.003 和 0.084。请记住,与验证相比,培训的损失较低是预期的,也是健康的,只要差异不是很大,并且两者仍呈下降趋势。当我查看纪元表时,我惊讶地发现错误率、验证损失和训练损失都在下降,因此可能有更多纪元的空间。不过在这一点上,我对结果很满意。
我也试着看看最高亏损,但是,每当我跑的时候
interp = ClassificationInterpretation.from_learner(learn)
我以这个结尾:
RuntimeError: [enforce fail at CPUAllocator.cpp:64] . DefaultCPUAllocator: can't allocate memory: you tried to allocate 3870777456 bytes. Error code 12 (Cannot allocate memory)
果然,我的 RAM 看起来总是这样,post 尝试:

内存不足(内存接近 100%)
我还没有调查我需要做什么才能得到这份工作。也许我需要删除对象,停止运行不和谐,等等。任何能找回额外记忆的东西。或者只做简单的事情,买更多的内存。
热图和挂钩
杰里米在他的一堂课中做了一件很酷的事情,他看了看最终卷积的热图,并将其叠加在一只猫的图像上,他的模型预测这只猫是一只缅因猫。我决定也尝试一下,因为这是对 fastai 提供的回调功能的一个非常温和的介绍。这篇文章变得相当长,所以我将省去代码(在我的 GitHub 上总是可以找到)并提供一张图片来代替。

它负责识别的字符的最终卷积的热图
热图很好地勾勒出了角色的细节。它错过了人物的右上部分,但仅此而已。请记住,此热图是由最终卷积生成的。因此,它只是通过对 512x4x4 张量的 512 个通道进行平均而产生的 4x4 图像。然后对该图像进行插值以适合 32×32 的图像。
结束:吸取的教训
创建 CNN 实际上是这个字符识别练习中最简单的部分。PyTorch 和 fastai 的 API 都非常容易使用。在我想了解更多的情况下,我通常只需要查看 fastai 源代码。我喜欢用 PyTorch 写代码,然后用 fastai 重写,同时理解我写的所有东西。当然,对于像PoolFlatten这样的一些层,我需要回去确保我理解了更好的细节,但是我仍然对它是什么以及为什么它适合有一个直观的理解。
实验是艰苦的工作。我应该遵守纪律,跟踪每一个变化的变量,了解它对网络性能的影响。我希望在决定采用最大化速度的方法之前,我已经在自述文件中写下了我尝试的每种组合。这还没有开始考虑网络的变化,以了解模型的错误率是如何受到影响的,因为我需要几个时期才能看到这一点。唯一有帮助的是能够快速旋转笔记本,测试一两个功能,并将其复制到我的主笔记本上进行应用。
这很有趣,也很有收获。MNIST 变得无聊。Kuzushiji 的角色是我所期待的——有点挑战性。我花了大约三周时间浏览视频、阅读文档、查看数据等。在我的上一篇文章中,我提到了数据准备和培训之间的 80/20 分割。由于培训的时间,这个项目是 40/60 分裂。操纵模型的参数,看看什么可行,什么不可行,这占用了我大部分时间。
和往常一样,我的代码可以在我的 github repo 中找到。如果你真的看了代码,我恳求你,请浏览一下自述文件,这样你就不会被我的几个笔记本完全弄糊涂了。
谢谢你坚持到最后!欢迎评论和提问。
L1 和 L2 正则化-解释
如何控制模型的复杂性

克里斯·莱佩尔特在 Unsplash 上的照片
过拟合是数据科学领域中的一个重要问题,需要小心处理,以便建立一个健壮和准确的模型。当模型试图很好地拟合训练数据,以至于不能推广到新的观察结果时,就会出现过度拟合。过度拟合模型捕捉训练数据中的细节和噪声,而不是总体趋势。因此,即使是特征的微小变化也会极大地改变模型的结果。过度拟合模型似乎在训练数据上表现突出,但在新的、以前看不到的观察上表现不佳。
过拟合的主要原因是模型复杂。因此,我们可以通过控制复杂性来防止模型过度拟合,这正是正则化所做的。正则化通过惩罚模型中较高的项来控制模型的复杂性。如果增加一个正则项,该模型试图最小化损失和模型的复杂性。

在这篇文章中,我将介绍两种常用的正则化技术,分别是 L1 和 L2 正则化。导致模型复杂的两个主要原因是:
- 特征总数(由 L1 正则化处理),或
- 特征的权重(由 L2 正则化处理)
L1 正规化
它也被称为针对稀疏性的正则化。顾名思义,它用于处理主要由零组成的稀疏向量。稀疏向量通常导致非常高维的特征向量空间。因此,模型变得很难处理。
L1 正则化通过在每次迭代中从权重中减去一个小的量来强制无信息特征的权重为零,从而最终使权重为零。
L1 正则化惩罚|权重|。
L2 正规化
为了简单起见,它也被称为正则化。如果我们把模型的复杂度作为权重的函数,那么特征的复杂度与它的权重的绝对值成正比。

L2 正则化迫使权重趋向于零,但并不使它们完全为零。L2 正则化就像在每次迭代中去除一小部分权重的力。因此,权重永远不会等于零。
L2 正则化惩罚(权重)
有一个额外的参数来调整 L2 正则项,称为正则化率(λ)。正则化率是一个标量并乘以 L2 正则化项。

注意:为λ选择一个最佳值很重要。如果 lambda 太高,模型就会变得太简单,而且往往会不符合要求。另一方面,如果λ太低,调节的效果变得可以忽略不计,模型可能会过拟合。如果 lambda 设置为零,那么正则化将被完全移除(过度拟合的高风险!).

注: 岭回归使用 L2 正则化,而套索回归使用 L1 正则化。弹性网回归结合了 L1 和 L2 正则化。
结论
过度拟合是机器学习模型的一个关键问题,需要小心处理。我们建立机器学习模型来预测未知。我们希望模型能够学习训练数据中的趋势,并在评估新的观察结果时应用这些知识。因此,模型需要很好地概括底层结构,而不是过于关注训练点的细节。正则化有助于模型实现这个目标。
感谢您的阅读。如果您有任何反馈,请告诉我。
洛杉矶交通数据分析🚗
使用公开来源数据分析洛杉矶的碰撞模式

交通是一个几乎每个人都熟悉的问题。作为一名在洛杉矶生活了 7 年的居民,我经历过太多的交通堵塞,似乎不管一天中的什么时候或者一周中的哪一天。这就是为什么当我偶然发现由洛杉矶市维护的交通碰撞数据集时,我如此感兴趣。这个数据很酷,原因有几个。虽然它不直接测量流量,但它测量的是一个密切相关的代理。不难假设,更多的流量与更多的冲突相关,而更多的冲突直接导致更多的流量。
我希望像这样的数据集可以用来为每个人创造更安全、更高效的社区。本着这种精神,这个数据集(以及其他一些数据集)由洛杉矶市积极维护,并对公众免费开放。
浏览数据后,我决定尝试回答 3 个主要问题:
- 交通碰撞模式如何随一天中的时间、一周中的日期和一年中的时间而变化?
- 碰撞在地理上是如何分布的?有可能识别高风险区域或交叉路口吗?
- 有可能预测给定时间范围内的碰撞次数吗?
在进入上面的问题之前,让我们了解更多关于数据集的知识。
📈数据
数据从 2010 年 1 月开始,每周更新。在我的特殊情况下,我使用 2010 年 1 月至 2019 年 7 月的数据,结果是大约 50 万行。每行对应一次碰撞。这些数据是从原始的纸质交通报告中转录出来的,因此很有可能存在错误。以下是一些关键字段的示例:

从 LA 碰撞数据集中选择的字段
这些字段的可用性激发了上面列出的关键问题。
与任何数据集一样,这个数据集在开始任何分析之前都需要清理。有几列只有一个值,反映了该数据中的所有行都对应于流量冲突的事实。
还有多个字段具有冲突的近似街道名称(上面未显示)。这些文本字段需要清理,特别是删除多余的空格。同样,在上面的图片中,我们可以看到包含在一个字符串中的纬度/经度坐标。我将这些坐标提取在单独的列中以备后用。
下一步是检查空值或缺失值。约 16%的碰撞(78K)没有相关的受害者年龄。还有少量(400 个)碰撞没有有效的纬度/经度坐标,将从第 2 部分的绘图部分中排除。
💡数据探索
清洗之后,但在进入主要问题之前,我想做一些一般性的数据探索。这种分析通常是有用的。即使心中没有一个具体的目标,我也经常能找到有用的趋势或见解。我将从绘制数据中的几个变量开始。顺便说一下,所有这些工作都是用 R 语言完成的,代码链接在文章的底部!

按受害者年龄划分的碰撞次数。注意 99 岁时的峰值!
我想到了以下几点:
- 几乎没有 15 岁以下的受害者。
- 大多数受害者都是 20 多岁。每个年龄段的碰撞受害者数量一般在 30 岁以后会减少。
- 峰值最多为 5 的倍数(25、30、35 等)。这表明一些年龄是估计的,官方身份(如驾驶执照)并不总是在碰撞报告中使用。
- 99 岁似乎是一个包罗万象的水桶。实际上,99 岁以上的受害者不太可能有上面显示的那么多。
这一情节也引发了疑问:
- 如何处理与多个受害者的碰撞?
- 99 岁的高峰是怎么回事?
我就这些问题给数据所有者发了电子邮件,但不幸的是没有收到回复。如果我得到回应,我会添加更新。
接下来,我们按性别来看碰撞。

按性别划分的碰撞次数。“X”代表未知性别。
- 这幅图告诉我们,如果发生了碰撞,受害者更可能是男性而不是女性。
如果我有按性别划分的司机总数,考虑到人均碰撞量,这项工作会更有趣。这将是这一数据反复出现的缺点,也将是我对这一分析的主要延伸之一。
接下来我要做的是查看数据中最低和最高的碰撞天数。我只包括两端最高和最低的 0.5%,所以我可以手动查看结果。以下是最低碰撞天数:

碰撞次数最少的日子。“每日计数”是相应一天的碰撞次数。
- 大多数低碰撞日都在节假日前后。直觉上,这是有道理的,因为在(某些)假期开车的人可能会少一些。
- 大多数低碰撞日发生在 2014 年初之前。我们将在这篇文章的后面看到,每月的碰撞在 2014 年后开始上升。
这里是最高的碰撞日:

碰撞次数最多的日子。“每日计数”是相应一天的碰撞次数。
- 大多数高碰撞日是 2015 年后的星期五。
- 我们将在这篇文章的后面看到,星期五通常是一周中碰撞次数最多的一天。
这些结果引出了一些超出本分析范围的问题和想法。
- 为什么只有一些节假日与低碰撞日相关联?例如,MLK 日作为低碰撞日出现了两次,但独立日从来没有。
- 为什么像阵亡将士纪念日或劳动节这样的节日不会显示为低冲突日或高冲突日?
- 夏令时在任何一年都不会出现任何异常值。这让我很惊讶。
- 观察高碰撞日的天气情况会很有趣吗?
记住这些描述性的分析,我准备好解决我在这篇文章开始时提出的关键问题。第一个是关于分析碰撞随时间的变化。
🕒按时间碰撞
在这一节中,我分析了碰撞模式如何随着一天中的时间、一周中的日期和一年中的时间而变化。
首先,我绘制了 2018 年的每日碰撞。绘制从 2010 年开始的所有数据太混乱了,所以本节的许多部分我只关注 2018 年。除了碰撞日期,数据还有一个报告日期字段。这是事故实际报告给警方的日期。在大多数情况下,报告日期是碰撞日期的同一天或后一天。

2018 每日碰撞和碰撞报告。你能看出不同之处吗?
- 日常碰撞和报告的碰撞有明显的差异。看看四月中旬报告的碰撞高峰…在实际碰撞中没有类似的情况!
- 这些差异使我认为,关于冲突何时被报告或处理,可能存在管理动态。
- 数据中的异常值没有明显的模式。
让我们看一个类似的按月汇总的图。在这个层次上,我可以包括从 2010 年到 2019 年的整个时间框架。

每月冲突和报告的冲突
- 在月线级别,这两个量似乎比日线级别更紧密地相互跟踪。
- 2010 - 2014 年每月的碰撞次数大致恒定,2014 - 2017 年上升,2017 - 2019 年大致恒定。请记住,本次分析使用的数据截止到 2019 年 7 月。
那么,为什么上图中每月的碰撞会上升呢?2014 - 2017 年在洛杉矶生活和开车的人数上升了吗?会不会和拼车服务的兴起有关?从这些数据中还不清楚,但这些可能是一个单独帖子的起点。
接下来,我分析一天中碰撞的分布。

一天中不同时间的碰撞
碰撞是:
- 从凌晨 4 点到 8 点急剧增加
- 从上午 8 点减少到上午 9 点 30 分
- 通常从上午 9:30 到下午 6:00
- 从晚上 8 点到凌晨 4 点急剧下降
- 在他们每天的最小值[最大值]凌晨 4 点[~下午 5 点]
这些结果可能反映了道路上的车辆数量。凭直觉,许多碰撞发生在晚上高峰时间。正如我之前提到的,获得每小时道路上车辆总数的测量值将允许我计算人均碰撞数。报告冲突时没有可用的每小时时间戳,所以我不能按小时绘制该字段。
下一步是通过一周中的某一天来检查碰撞。

冲突和按星期报告的冲突
碰撞是:
- 周日至周五增加,周四至周五急剧增加
- 周日[周五]达到每周最低[最高]
工作周的结束是周五大量碰撞的明显假设。到目前为止我还没想出其他的!
对于报告的冲突:
- 周日[周五]的碰撞仍然最少[最多]
- 然而,每个工作日报告的冲突基本上是恒定的
最后,我按月绘制结果。

按月报告的碰撞和碰撞。在此分辨率下,这些字段是相似的。
碰撞是:
- 通常从 4 月到 8 月保持不变
- 一般 9 月至 2 月较低,尤其是 9 月至 12 月
- 三月最高
因此,在较冷的月份,碰撞往往会减少。对此一个可能的解释是,在寒冷的月份里,到洛杉矶旅游的游客较少。关于 3 月份的高碰撞次数,我最初的假设是夏令时。然而,没有一个最高的碰撞日是在这一天。或许这个结果源于春假游客?
这就结束了我对碰撞时间模式的分析。以下是我对以上结果的总结。
- 碰撞和报告的碰撞在每日水平上变化很大,但在每月水平上没有变化。
- 2010 - 2014 年每月的碰撞次数大致恒定,2014 - 2017 年上升,2017-2019 年年中(本次分析的结束日期)大致恒定。
- 碰撞次数在大约凌晨 4 点[~下午 5 点]最低[最高]。
- 周日[周五]碰撞次数最低[最高]。
- 9 月至 12 月(3 月)的碰撞次数最少[最多]。
- 获取特定时间道路上车辆总数的信息将有助于对上述结果进行有趣且有用的人均计算。
接下来是看地理碰撞。
🌎地理上的冲突
除了纬度/经度坐标,该数据还有多个描述碰撞发生地点的字段。我将从查看这些字段开始。首先,我将通过area绘制碰撞的分布。

由“区域”列计数的冲突
一些区域显然比其他区域有更多的碰撞。但是没有额外的信息,如大小或每area的交通密度,这个图表不能提供太多信息。
该数据还包括名为location和cross_street的字段。location是发生碰撞的主要街道,而cross_street是最近的十字路口。我将看看这些字段的 10 个最常见的值及其组合。

碰撞最多的“位置”
10 条最常见的location是洛杉矶最长、交通最繁忙的道路。这 10 条街道占总碰撞数的 10%。总共有>25Klocation,所以尾巴很长。现在,我来看看cross_street字段。

碰撞最多的“cross_street”
5%的冲突没有关联的cross_street。否则,这个列表与前面的列表有很多重叠。显而易见,下一步是通过结合这两个字段来查看最常见的碰撞交点。

碰撞最多的交叉口
最常见的碰撞交叉路口(location / cross_street组合)包含许多与之前列表中相同的街道。然而,也有例外:第 2 行(坦帕大道和诺德霍夫街)的组件既不出现在最常见的location中,也不出现在cross_street中。即使是最容易发生碰撞的交叉路口也只占全部碰撞的一小部分。
现在是时候利用数据中的地理坐标,开始绘制碰撞图了。提醒一下,有少量碰撞没有有效的纬度/经度数据,因此不包括在本节中。

整个洛杉矶的 2018 碰撞。每个点都是唯一的纬度/经度坐标。
- 点的空间分布显示了 LA 有趣的形状。
- 蓝色[红色]点表示纬度/经度坐标,2018 年的碰撞数较低[较高]。
- 即使在这张缩小的地图上,在山谷(地图的北部)和城市的中部和东部也可以看到高碰撞坐标。
这张地图相当混乱。为了更好地观看,我将放大一个窗口,显示洛杉矶市中心的大部分。

洛杉矶选定区域的 2018 年碰撞
- 许多中高碰撞坐标清晰可见。许多这些高碰撞点往往发生在同一条街道的不同十字路口。
之前的地图显示了整体碰撞。如果我加上一天中的时间,这个数据看起来怎么样?

2018 年洛杉矶选定地区最常见日间部分的碰撞
- 该图仅包括 5+次碰撞的坐标。每一个坐标都被分配到发生大部分碰撞的那一天。日部分之间带连线的坐标被删除。
- 大多数碰撞发生在
Early Morning时没有坐标。鉴于我通过时间分析在碰撞中的发现,这是有意义的。 - 许多坐标的大部分碰撞发生在
Afternoon和Evening。该结果也与“按时间划分的碰撞”部分的结果相匹配。 - 有趣的是,有一组坐标中
Late Night碰撞是常见的。
让我们看一个类似的按工作日/周末划分的地图。

2018 年洛杉矶选定地区最常见周部分的碰撞
- 该图仅包括 3+碰撞的坐标。每个坐标都被分配到发生大多数碰撞的星期几。周部分之间带连线的坐标被移除。
Weekday桶里显然有更多的日子和碰撞。- 这张地图标明了周末撞车事故多发的地区。将星期五的部分或全部包含在
Weekend桶中也可能很有趣。
为了结束这一节,我按一年中的时间绘制碰撞图。

洛杉矶选定地区最常见季节的 2018 年碰撞
- 该图仅包括 3+碰撞的坐标。每个坐标被分配给大多数碰撞发生的季节。季节间有联系的坐标被删除。
- 看起来更多的碰撞发生在夏季(3-8 月)。这将与“按时间划分的碰撞”部分中的结果一致。
- 考虑到洛杉矶没有像秋天或冬天这样明显的季节,可能有其他方式来划分这样一个地块的一年。
这些是我对“地理碰撞”部分的结论:
- 使用
location和cross_street字段,除了绘图之外,还可以确定洛杉矶最容易发生事故的坐标。 - 最常见的碰撞日部件是
Afternoon和Evening。 - 工作日发生的碰撞比周末多得多。按周部分绘制碰撞图显示了周末碰撞更常见的区域。
- 夏季发生的碰撞比冬季多。
🔮预测碰撞
最后一节讨论如何预测碰撞。我特别试着预测每月和area会发生的碰撞次数。
我先来看一个单个area的碰撞时间序列的例子:

区域 2(壁垒)的每月碰撞
area2 的趋势通常与整体每月冲突的趋势相匹配(这是在按时间分析的冲突中)。
让我们将这个时间序列分解成趋势、季节性和剩余部分。作为题外话,我将在这篇文章中关注分析结果,而不会深究我所使用的时间序列方法的理论。然而,如果你想了解更多,网上有很多资源可以利用!

“区域”2 的趋势、季节性和剩余部分(壁垒)
- 记住季节性曲线的形状。接下来,我将把它与每月碰撞总数的分解进行比较。
- 趋势看起来与我们在上图中看到的相似。
让我们比较一下area 2 分解和整体每月碰撞分解。

总体数据的趋势、季节性和剩余部分
- 与
area2 相比,整体数据的季节性曲线看起来非常不同!这表明不同的区域可以有不同的动态。
接下来,我将查看area 2 的自相关函数(ACF)和部分自相关函数(PACF)。ACF 分析碰撞的滞后值与当前值的相关程度。PACF 显示了每个滞后解释了多少以前无法解释的差异。

ACF 和 PACF 负责“区域”2(壁垒)
- 这些图表明
area2 碰撞值与其滞后相关。然而,在前两个滞后值之后,额外的滞后并不能解释太多无法解释的差异。 - 因此,任何预测
area2 碰撞的模型应该包括至少 2 个滞后项。
我尝试了几种不同的模型来预测碰撞:
- 3 个月和 6 个月移动平均线模型(MA)
- 自回归综合移动平均线(ARIMA)
- 先知图书馆
MA 模型平均过去的值来生成预测,是最简单的时间序列模型。ARIMA 模型可以使用过去的值、差异和以前的误差。Prophet 是一个附加预测模型,其中非线性趋势与年度和月度季节性相适应。
先知比和马的模型更新。你可以在这里找到更多信息:
Prophet 是一个用 R 和 Python 实现的预测程序。它速度很快,并提供完全自动化的预测…
facebook.github.io](https://facebook.github.io/prophet/)
我根据最后 12 个月(2018 年 8 月至 2019 年 7 月)的数据,使用以下指标评估每个模型:
- 平均绝对百分比误差(MAPE):预测值和实际值之间的平均绝对百分比差
- 偏差:预测值和实际值之间的平均百分比差异
MAPE 让我知道我的预测离实际碰撞值有多远,而偏差告诉我是否系统地高估或低估了数据。
我为每个area自动调整 ARIMA 模型。所以每一个都可以有不同的 p、d 和 q。我还测试了多个 Prophet 模型规格(并在下面显示了最佳结果)。以下是所有区域的平均模型 MAPE 和偏差结果:

数据中所有区域的多个平均模型结果
- 总的来说,我觉得这些成绩都不错!
- 3 个月和 6 个月 MA 模型的表现非常相似。
- ARIMA 模型与马模型有相似的 MAPE,但偏差更大。
- 到目前为止,Prophet 模型的结果最差(即使在调优之后)。
- 令我惊讶的是,MA 型号(最简单的型号)的性能最好!
让我们只看一下area 2 的模型预测。

“区域”2(壁垒)的模型预测与实际碰撞
- 在前 5 个月,Prophet 模型的预测值高于其他模型。
- 所有模型都错过了 2019 年 1 月的下降和 2019 年 4 月-2019 年 7 月的上升/下降模式。
- 6 个月 MA 模型预测变化不大。
- 马模型和 ARIMA 模型似乎做出了保守的预测,没有捕捉到数据的波动性。
接下来,我将查看每个型号每月的平均 MAPE。该图包括所有区域。

每个型号的平均月 MAPE(所有地区)
- 对于验证数据的前半部分,MA 和 ARIMA 模型的 MAPE 一起移动。
也值得看看每个模型每月的平均偏差。

每个模型的平均月偏差(所有地区)
- 对马模式和 ARIMA 模式的偏好一起移动。
- Prophet 模型对整个验证集有正偏差(过度预测)。
现在,我将根据area查看每个模型的平均 MAPE 和偏差。

每个“区域”每款车型的平均 MAPE
- MAPE 的平均表现因地区而异。例如,12 区[3]的模型性能相对较好[差]。

每个模型每个“区域”的平均偏差
- 平均偏差也因
area而大幅变化。 - 令人惊讶的是,大多数模型对大多数区域都有正偏差(这表明预测过度)!
接下来,我将看看每个模型的最差area/月预测。

area14 出现两次。2019 年 1 月和 2 月都出现。- 有趣的是,看到了所有模型都在挣扎的情况(2019 年 1 月
area2)与一个模型特别挣扎的情况(2018 年 9 月area14)。
基于最坏的预测,我将放大到area 14。

“区域”14(太平洋)的模型预测与实际碰撞
area14 的趋势与上述area2 完全不同。- 2019 年 7 月除了 Prophet 以外的所有车型都错过了秒杀。
以下是我对碰撞预测部分的结论:
- 总体月度表现还不错(MAPE < 10%,多数情况下有偏差)。
- 然而,MA 模型具有最好的性能,这表明长期滞后数据、差分和以前的误差不会提高误差率。这令人惊讶,但表明每月的碰撞次数在一定范围内是随机的。
- 趋势似乎因
area而异。这在理论上应该由 ARIMA 和预言家方法来解决,它们符合area的独立模型。 - 为了改进这些模型,我想深入挖掘一两个领域,并试图理解趋势。获得关于一辆
area的具体交通模式的数据肯定也会有所帮助。额外的数据源(如天气)也很有希望被探索。
🏁结论
我对洛杉矶碰撞数据的分析到此结束!如果你有解决这些问题的其他方法,请随时联系我们。
您可以在下面的 GitHub 资源库中找到我使用的所有代码:
这份报告包含围绕洛杉矶碰撞数据分析的材料。以下是对…的描述
github.com](https://github.com/jai-bansal/los-angeles-collision-analysis)
如果你喜欢这篇文章,看看我下面的其他作品吧!
这篇文章是关于机器过程中通常不会引起太多注意的一个方面:随机种子。
towardsdatascience.com](/how-to-use-random-seeds-effectively-54a4cd855a79) [## 为您的组织开发技术培训的 7 个技巧
将你的下一个培训课程想法变成现实的技巧
medium.com](https://medium.com/@jai_bansal/7-tips-for-developing-technical-trainings-for-your-organization-928cf7744d44)
感谢阅读!
Python 中的标签编码器和 OneHot 编码器
通过示例了解标签编码器、OneHot 编码器和 Pandas 虚拟变量

杰西卡在 Unsplash 上的
M 机器学习算法理解数字而不是文本。因此,所有“文本”列都必须转换为“数字”列,以便算法能够理解。
这是将标签或分类或 文本 值转换成数字或 数值 值的故事。简单来说,
编码是将单词转换成数字的过程
在 Python 中, OneHot 编码和勒贝尔编码是将分类列编码成数值列的两种方法。而这些都是最常用的 Python 库的一部分: Scikit-Learn
但是等等,你不会想在笔记本里导入 Scikit-Learn 吧??
没问题,⚡️熊猫会来帮你的。
让我们深入这个将分类变量转换成数字变量的故事,以便 ML 算法理解它。
分类数据
任何数据集都包含多个包含数值和分类值的列。

作者图像:分类列的数据类型
分类变量代表可以分组的数据类型。它有有限且通常固定数量的可能值,称为 类别 。性别、社会阶层、血型、国家代码等变量都是分类数据的例子。
但是,如果该数据被编码成数值,那么只有它可以在机器学习算法中被处理。
让我们考虑下面的例子,以简单的方式理解编码。
import pandas as pdcountries = ["Germany","India","UK","Egypt","Iran"]
continents = ["Europe","Asia","Europe","Africa","Asia"]
code = ["G","I","U","E","N"]
d={"country": countries, "continent":continents, "code":code}
df = pd.DataFrame(d)

作者图片:示例数据框架
将“代码”列的数据类型从对象转换为类别
df['code'] = df.code.astype('category')

按作者分类的图像:所有列的数据类型
通过这个例子让我们了解编码过程。
Python 中的标签编码
标签编码是一种简单直接的方法。这会将分类列中的每个值转换为数值。分类列中的每个值称为标签。
标签编码:根据字母顺序为每个标签分配一个唯一的整数
让我用上面的例子向您展示标签编码在 python 中是如何工作的,
from sklearn.preprocessing import LabelEncoderle = LabelEncoder()
df["labeled_continent"] = le.fit_transform(df["continent"])
df
列**continent**中的标签将被转换成数字,并存储在新列 **labeled_continent**中
输出将是,

作者图片:Python 中的标签编码
用更简单的话来说,标签按字母顺序排列,从 0 开始给每个标签分配一个唯一的索引。

作者图片:了解 Python 中的标签编码
一切正常吗??干得好,⁉️
这里涉及到标签编码的问题。它使用序列中的数字来引入标签之间的比较。在上面的例子中,列**continent**中的标签没有顺序或等级。但是标签编码后,这些标签是按字母顺序排列的。由于这些数字,机器学习模型可以将这种排序解释为Europe > Asia > Africa
为了解决标签编码的排序问题,OneHot 编码应运而生。
Python 中的 OneHot 编码
在 OneHot 编码中,为列中的每个标签创建一个二进制列。这里,每个标签都被转换为一个新列或新要素,并被赋予 1(热)或 0(冷)值。
让我先给你看一个例子来理解上面的陈述,
from sklearn.preprocessing import OneHotEncoderohe = OneHotEncoder()
df3 = pd.DataFrame(ohe.fit_transform(df[["continent"]]).toarray())
df_new=pd.concat([df,df3],axis=1)
df_new

作者图片:Python 中的 OneHot 编码
在这个场景中,最后三列是 OneHot 编码的结果。非洲、亚洲和欧洲的标签分别被编码为 0、1、2。OneHot 编码将这些标签转换成列。因此,查看最后 3 列,我们有3 labels → 3 columns
OneHot 编码:在一行中只有一个标签是热的
在特定的行中,只有一个标签的值为 1,所有其他标签的值为 0。在将这样的编码数据集输入到机器学习模型之前,可以进行更多的转换,如 OneHot Encoding 文档中所述。
快速浏览这篇文章,了解合并两个数据帧的更多选项
了解 Python pandas 中的 merge()和 concat()
towardsdatascience.com](/join-the-tables-ab7fd4fac26b)
Python 中的 pandas.get_dummies()
OneHot 编码可以以更简单的方式实现,无需导入 Scikit-Learn。
⚡️赞成!!熊猫是你的朋友。这个简单的函数pandas.get_dummies()会将指定列中的所有标签快速转换成单独的二进制列
df2=pd.get_dummies(df[["continent"]])
df_new=pd.concat([df,df2],axis=1)
df_new

图片作者:熊猫虚拟变量
上述数据帧的最后 3 列与 OneHot 编码中观察到的相同。
pandas.get_dummies()为列**continent**中的每个标签生成虚拟变量。因此,非洲大陆、亚洲大陆、和欧洲大陆分别是非洲、亚洲和欧洲标签的虚拟二元变量。
通过我的故事,
我向您介绍了将分类变量转换为数值变量的方法。每种方法都有自己的优点和局限性,因此理解所有的方法很重要。根据您想要实现的数据集和机器学习模型,您可以在 Python 中选择上述三种标签编码方法中的任意一种。
这里有一些资源可以帮助你解决这个问题:
喜欢我讲故事的方式吗??
这里有一个有趣的fun&learn活动供你创建自己的数据集。看一看。
从网页中提取数据并将其存储到 excel 中—只需 4 个简单的步骤
towardsdatascience.com](/web-scraping-make-your-own-dataset-cc973a9f0ee5)
感谢您的宝贵时间!
我总是乐于接受建议和新的机会。请随时添加您的反馈,并通过 LinkedIn 与我联系。
标签传播去神秘化
基于图的标签传播的简单介绍
社交媒体网络已经遍布全球,并且与日俱增。考虑一个社交媒体网络,你知道一些人的兴趣,你想预测其他人的兴趣,这样我们就可以有针对性地开展营销活动。为此,我们可以使用基于图的半监督机器学习技术,称为标签传播。在本文中,我将通过一些例子和样本代码来解释标签传播过程。
什么是标签传播?
标签传播算法(LPA) 是一种迭代算法,其中我们通过在数据集内传播标签来将标签分配给未标记的点。该算法由小金朱和邹斌·格拉马尼【1】于 2002 年首次提出。LPA 属于直推学习,因为我们想要预测已经给我们的未标记数据点的标签。
假设我们有一个如下所示的人的网络,有两个标签类别“对板球感兴趣”和“对板球不感兴趣”。那么问题来了,我们能预测剩下的人是否对板球感兴趣吗?

来自 Pixabay 的 Gordon Johnson 的原始图片。
对于 LPA 在这种情况下的工作,我们必须做一个假设;连接两个节点的边带有相似性的概念。即,如果两个人联系在一起,这意味着这两个人很可能有相同的兴趣。我们可以做出这样的假设,因为人们倾向于和其他有相似兴趣的人联系。
在图中随机行走
考虑图 1 中给出的示例图,其中我们有 2 个标签类(红色和绿色)和 4 个彩色节点(每个类 2 个)。我们想预测节点 4 的标签。

图一。样本图表 1
我们可以在图中随机行走,从节点 4 开始,直到我们遇到任何标记的节点。当我们碰到一个有标签的节点时,我们停止行走。因此,这些被标记的节点被称为吸收态。让我们考虑从节点 4 开始的所有可能的路径。在所有可能的遍历中,下面的遍历将以绿色节点结束。
- 4 → 9 → 15 → 16
- 4 → 9 → 13 → 14
- 4 → 9 → 13 → 15 → 16
- 4 → 9 → 15 → 13 → 14
下面的遍历将以红色节点结束。
- 4 → 7 → 8
- 4 → 7 → 6 → 5 → 1
- 4 → 5 → 1
- 4 → 5 → 6 → 7 → 8
- 4 → 2 → 1
基于从节点 4 开始的所有可能的随机行走,我们可以看到大多数行走都以红色节点结束。所以,我们可以把节点 4 涂成红色。这是 LPA 背后的基本直觉。
数学公式
设Xₗ为被标记节点的集合,Yₗ为被标记数据的独热标签(如果不了解独热编码,可以参考这个链接)。假设有{1,…,C}类标签。Xᵤ是未标注的顶点。我们不知道Yᵤ,因此Yᵤ将包含零。
我们可以将随机游走表示如下。

图二。随机漫步
在矩阵形式中,该方程将如下所示。

图三。矩阵形式的随机游动
如果我们可以计算概率转移矩阵 T ,我们就可以计算所有未标记节点的标记概率。
如何计算概率转移矩阵?

图 4。样本图表 2
考虑如图 4 所示的具有吸收态的样本图。对于每个节点,我们都要计算跳到其他节点的概率。当我们到达吸收状态时,行走结束,因为我们陷入吸收状态(在图中表示为自循环)。这是一个无向图,所以我们可以向任何方向移动。
假设从一个节点转移到其邻居的概率是相等的,我们可以将 T 写成如下。

图五。图 4 中样本图 2 的矩阵 T
从节点 1 到节点 1 的概率是 1,因为节点 1 处于吸收状态。从节点 1,我们无法到达任何其他节点。因此,从节点 1 到达其他节点的概率将是 0。同样的方法也适用于节点 2。
从节点 4,您可以转到节点 1、3 和 5。因此,从节点 4 移动到节点 1、3 和 5 是同样可能的,每个节点的概率为 0.33。类似地,从节点 5,我们可以移动到节点 4 和 6,每个节点的概率为 0.5。
注意,我们可以使用图的度矩阵(D)和邻接矩阵(A ),使用下面的等式来计算 T。
T = D⁻¹A
现在请注意,我们可以拆分矩阵 T,如图 6 所示。

图六。t 可以分成 4 块
- Tₗₗ —从标记节点到标记节点的概率
- Tₗᵤ —从标记节点到未标记节点的概率
- Tᵤₗ —从未标记节点到标记节点的概率
- Tᵤᵤ —从未标记节点到未标记节点的概率
注: Tₗₗ将是一个单位矩阵,而 Tₗᵤ将是一个零矩阵,因为我们不能从被标记的节点移出,因为它们是吸收态。
如果我们将矩阵 T 乘以 t 倍,然后将 t 送至无穷大(∞),会发生什么?你可以在 MATLAB 中输入这个矩阵,得到 T ⁰⁰.你会得到这样的结果。

图 7。t 在 MATLAB 上自乘 100 次
当你将 T 提高到更大的幂时,概率将停止变化(达到饱和)并导致稳定的转移概率。您现在可以看到,只有前两列包含非零值,其余列都为零。
我们可以用数学方法描述如下。

图 7。T 乘以自身无限倍的公式
获得最终答案
最后,带标签的矩阵看起来像这样,我们可以得到带标签节点的标签向量和不带标签节点的标签向量。

图 8。有标号和无标号节点的一键标号公式
现在让我们考虑图 4 中的示例图 2,我们希望预测未标记节点的标签。使用我们的 MATLAB 结果,我们可以得到如下标签。

图九。获取未标记节点的标签
对于每个未标记的节点,我们分配具有最大概率的类别标签。但是,你可以看到节点 5 有相等的概率是红色和绿色。因此,我们的最终标记图将如图 10 所示。

图 10。样本图的最终标记 2
示例代码
带有 LPA 简单实现的示例代码
你也可以阅读我以前的文章用 Python-igraph 可视化图形数据来学习如何用 Python 表示图形数据。
** [## 用 Python-igraph 可视化图形数据
使用 CiteSeer 数据集介绍 python-igraph 模块
towardsdatascience.com](/visualising-graph-data-with-python-igraph-b3cc81a495cf)
最后的想法
LPA 使用已标记节点的标签作为基础,并试图预测未标记节点的标签。然而,如果初始标记是错误的,这会影响标记传播过程,并且错误的标记可能被传播。为了克服这个问题,标签扩散被引入,其中我们在学习无标签节点的标签的同时也学习有标签节点的标签。这也应用了一些标签修正。你可以从周等人的文章学习本地和全球一致性中了解更多关于标签传播的信息。
希望你觉得这个解释有用。我很想听听你的想法。感谢您的阅读。
干杯!
参考
1朱小金和邹斌·格拉马尼。利用标签传播从有标签和无标签数据中学习。宾夕法尼亚州匹兹堡市卡内基梅隆大学计算机科学学院,技术报告。CMU CALD 2002 年 2 月 107 日。
2网络分析。第十七讲(第一部分)。列昂尼德·茹科夫(https://youtu.be/hmashUPJwSQ)教授的图的标号传播。**
主动学习导论
标签更聪明而不是更多。

从像素运行 4 个 FFWPU
介绍
想象一下你的学生时代为考试而学习。你是随机阅读笔记的某一部分,还是在书的后面随机做题?不要!好吧,至少我希望你没有像对待早餐一样严格对待你的学业。你可能做的是找出哪些话题对你来说很难掌握,并在这些话题上努力工作。只对你认为你理解的想法做一些小的更新。那么我们为什么要区别对待我们的机器学生呢?
我们需要更多的数据!这是我作为一名数据科学家经常听到的响亮号召,而且大多数时候都是如此。这通常是因为一些问题没有足够的数据来获得好的结果。一个经理问你需要多少数据。你多说。他们雇佣一些实习生或者众包一些贴标机,花上几千美元,你就能获得更多的性能。增加一个步骤,让您的模型告诉您它想要了解更多的内容,这可以大大提高您的性能,而只需要很少的数据和成本。我说的是做一些,为流行词做好准备,主动学习。
在本文中,我们将运行一些与主动学习和数据选择相关的基础实验。我们将在 IMDB 情感数据集的一个小子集上训练一个随机森林。然后,我们将通过随机采样,以及通过采样模型想要了解的数据点来增加训练集。我们将比较我们在数据增长方面的性能提升,并展示智能标记如何节省时间、金钱和提高性能。该项目的代码在这里的要点中,也包括在本文的底部。让我们开始吧。
TLDR
如果您的问题需要更多数据,请尝试在分类器的帮助下进行标注。为此,要么选择置信度最低的例子,要么选择最高和第二高概率最接近的例子。这在大多数情况下有效,但不是万灵药。我见过随机抽样和这些主动学习方法做得一样好。
数据
对于这个问题,我们将查看 IMDB 情感数据集,并尝试预测一部电影评论的情感。我们将为这个数据集获取整个测试集,以及一小部分训练数据。我们将基于不同的采样策略逐渐增加训练集的大小,并观察我们的性能提升。
在训练集中有大约 34,881 个示例,而在测试集中只有 15,119 个。我们首先将数据加载到熊猫数据框中。
df = pd.read_csv("IMDB_Dataset.csv")
df["split"] = np.random.choice(["train", "test"], df.shape[0], [.7, .3])
x_train = df[df["split"] == "train"]
y_train = x_train["sentiment"]
x_test = df[df["split"] == "test"]
y_test = x_test["sentiment"]
基本模型
对于本教程,我们将看一个简单的随机森林。你可以将这些技术应用到你能想到的任何模型上。这个模型只需要告诉你它对任何给定的预测有多大的信心。因为我们正在处理文本数据,所以我们的基本模型将使用原始文本中的 TF-IDF 特性。我知道,我知道,我们应该在这里使用深度变压器模型,但这是一个关于主动学习的教程,而不是关于 SOTA 的,所以请原谅我。如果你想知道如何使用像伯特检查我的其他教程在这里。
我们将我们的 RandomForest 模型定义为仅使用 unigram 特性的 SciKit-Learn 管道:
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import TfidfVectorizerclf = RandomForestClassifier(n_estimators=100, random_state=0)
model = Pipeline(
[
("tfidf", TfidfVectorizer(ngram_range=(1,1))),
("classifier", clf),
]
)
现在我们可以称之为。fit() 在一个文本输入列表上,管道将处理剩下的部分。让我们使用 5 个例子的初始训练集,看看我们在测试集上做得如何。
# Get five random examples for training.
rand_train_df = x_train.sample(5)
model.fit(rand_train_df["review"], rand_train_df["sentiment"])

测试集上 5 个示例随机森林的初始性能。
从这里,我们可以看到数据集是相当平衡的,因为预测所有的正数给了我们几乎 0.5 的精度。这个模型是相当蹩脚的,因为它只预测积极的。让我们看看我们是否可以使用主动学习来比随机采样新点更快地获得更好的性能。
选择好的数据点进行标注
所以我们现在有了一个分类器。最多是 meh,我们需要更多的数据。让我们使用分类器对我们的其他训练数据进行预测,并查看模型对哪些点最没有信心。对于大多数 Sci-Kit 学习评估者来说,这是非常容易。我们可以使用。 predict_proba() 函数获取每个类的概率。要手动完成这项工作,您还可以查看树的单个预测,并计算每个类的投票数。不过 predict_proba 就方便多了:)。
preds = model.predict_proba(x_test["review"])
这将给我们一个概率的 numpy 数组,其中每一列是一个类,每一行是一个例子。大概是这样的:
[[.1, .9],
[.5, .5],
[.2, .8]...
不确定抽样
挑选好的点进行标记的最简单的“智能”策略是使用模型最没有信心的点。在上面的例子中,这是第二点,因为任何类别的最大概率都是最小的。
def uncertainty_sampling(df, preds, n):
"""samples points for which we are least confident"""
df["preds"] = np.max(preds, axis=1)
return df.sort_values("preds").head(n).drop("preds", axis=1)
这里我们有一个函数,它接受训练示例的数据帧、相关的预测概率以及我们想要采样的点数。然后,它获取每行中的最大值,将数据点从最小到最大排序,并获取具有最小最大概率的n个示例。
如果我们将不确定性采样应用于上面的三个示例概率,我们会说我们应该首先标记[.5,. 5],因为最大概率小于所有其他最大概率。(. 8 和. 9)哪个直观上讲得通!
边际抽样
不确定性采样很好,但在多类设置中,它不能很好地捕捉不确定性。如果你有以下预测会怎样?
[[.01, .45, .46],
[.28, .28, .44],
[0.2, 0.0, .80]...
该模型似乎最不确定的数据点是第一个,因为它仅预测了 0.01 的类别 3!但是不确定性采样会说,示例 2 是标记的最佳点,因为 0.44 是最小的最大概率。他们都是很好的候选人,但第一个直觉上更有意义。边际抽样迎合了这种直觉;最好标记的点是那些预测之间具有最小差值的点。我们可以使用以下函数来执行边缘采样:
def margin_sampling(df, preds, n):
"""Samples points with greatest difference between most and second most probably classes"""
# Sort the predictions in increasing order
sorted_preds = np.sort(preds, axis=1)
# Subtract the second highest prediction from the highest
# We need to check if the classifier has more than one class
if sorted_preds.shape[1] == 1:
return df.sample(n)
else:
df["margin"] = sorted_preds[:, -1] - sorted_preds[:, -2]
return df.sort_values("margin").head(n).drop("margin", axis=1)
在这段代码中,我们对预测的概率进行排序。然后我们检查数组是否有多个维度。如果它只有一个概率,那么它只看到了一个类,而没有关于其他类存在的信息。在这种情况下,我们只需要随机抽样。否则,我们通过从最高概率中减去第二高的概率并对结果进行排序来找到余量。
实验
我进行了一个简单的实验,从五个随机采样点开始,然后应用每个采样策略再获得五个点。我重复这样做 100 次,直到我采样了大约 500 个点。我在每个时间点绘制测试集上的 f1 分数,并查看我们的性能如何随着每个采样策略而提高。

你可以看到,对于这个问题,边际抽样和不确定抽样都比随机抽样做得好。在二进制分类的情况下,它们是相同的。当我开始写这篇文章时,我没有想到这一点😅。我创建了一个叫做combined的额外抽样策略,它做了一点边际抽样、一点不确定性抽样和一点随机抽样。对于我的许多项目,我喜欢这种结合的方法,因为有时随机抽样确实有帮助。如果我们总是根据边际或不确定性进行采样,我们就不能从我们的数据集中均匀地采样,并且可能会错过一些重要的信息。有趣的是,我发现抽样中的一点随机通常会有回报。虽然不相信我,因为我还没有运行任何好的实验来证明这一点😅。
结论
主动学习可以通过选择向模型添加最多信息的新点,帮助您用更少的数据获得更好的性能。这种策略在大多数时候都很有效,但并不保证会做得更好。当您考虑标注一些附加数据时,这是一个很好的工具。
密码
用 Jupyter 笔记本电脑标记图像的有效方法

你可能会遇到这样的情况,你需要为你的图片添加标签。或者你已经做了。一种标记方法是手动查看每张图像,并将其标签写在文件中,这是一个痛苦的过程。
在这篇博文中,我将分享你如何让这个过程变得简单快捷。仅仅通过在 Jupyter 笔记本上写几行代码。先看演示吧。
演示
我的Image目录里有一些猫和狗的图片。我想给猫贴上0的标签,给狗贴上1的标签。我只需要通过传递图像目录来调用一个函数。我可以用互动的方式给我的图片贴标签,比如 following。

标记图像
一旦您标记了所有图像,一个标记。 csv 文件被创建并保存在您的计算机中,该文件包含所有图像名称和相应的标签。

下面是create_labels()函数的实现,它完成了上面显示的所有工作。
我将继续创造和发布更多这样的工具,让日常的 ML 任务变得简单。以下是该项目的 Git-Hub 链接。
让 ML 任务变得简单而轻松的工具。为 shivaverma/Easy-ML 开发贡献一份力量
github.com](https://github.com/shivaverma/Easy-ML)
用熊猫标注数据
熊猫数据标签简介

数据标注是将信息标签分配给数据子集的过程。有许多标记数据集的例子。包含癌性和健康肺的 x 射线图像以及它们各自的标签的数据是标记数据的一个例子。另一个例子是消费者信用数据,它指定消费者是否拖欠贷款。在获得标记的数据集后,机器学习模型可以在标记的数据上训练,并用于预测新的未标记的例子。拥有良好的标记数据对于构建高性能机器学习模型至关重要。在本帖中,我们将讨论使用 python 熊猫库生成有意义标签的过程。
我们开始吧!
我们将考虑标记数字数据的任务。出于我们的目的,我们将使用红酒质量数据集,它可以在这里找到。
首先,让我们将数据读入熊猫数据框:
import pandas as pd
df_wine = pd.read_csv("winequality-red.csv")
接下来,让我们使用。“head()”方法。
print(df_wine.head())

该数据对应于质量分数在 0 到 10 之间的葡萄酒。让我们看看数据中的值:
print("Quality values: ", set(df_wine['quality']))

假设我们对另一个分类问题感兴趣,而不是对葡萄酒质量进行分类。让我们考虑一下对一种酒的酒精含量是否在 10%以上进行分类的问题。让我们来看看酒精百分比的最小值和最大值:
print("Max Alcohol %: ", df_wine['alcohol'].max())
print("Min Alcohol %: ", df_wine['alcohol'].min())

让我们也画出分布图:
import matplotlib.pyplot as plt
plt.title("Distribution in Alcohol %")
df_wine['alcohol'].hist()

如果酒精百分比高于或等于 10%,我们将用“1”标记数据,否则用“0”标记数据:
import numpy as np
df_wine['alcohol_class'] = np.where(df_wine['alcohol']>=10.0, '1', '0')
我们现在可以用二进制标签来可视化分布:
from collections import Counter
plt.title("Distribution in Alcohol Class Labels")
plt.bar(dict(Counter(df_wine['alcohol_class'])).keys(), dict(Counter(df_wine['alcohol_class'])).values())

该数据被适当地标记用于训练二元分类模型。现在让我们考虑二进制分类以外的问题。如果我们看一下“固定酸度”的最小值和最大值,我们会发现这些值的范围比酒精%的范围更宽:
print("Max fixed acidity %: ", df_wine['fixed acidity'].max())
print("Min fixed acidity %: ", df_wine['fixed acidity'].min())

我们可以用熊猫的。loc[]'方法将三元标签分配给数据,这将把数据分成三组。标签“0”将被分配给值(4–7),“1”将被分配给值(7–9),“2”将被分配给值(9–16):
df_wine.loc[(df_wine['fixed acidity']>4.0) & (df_wine['fixed acidity']<=7.0), 'acidity_class'] = 0
df_wine.loc[(df_wine['fixed acidity']>7.0) & (df_wine['fixed acidity']<=9.0), 'acidity_class'] = 1
df_wine.loc[(df_wine['fixed acidity']>9.0) & (df_wine['fixed acidity']<=16.0), 'acidity_class'] = 2
我们现在可以直观地看到三元标签中的分布:
plt.title("Distribution in Alcohol Class Labels")
plt.bar(dict(Counter(df_wine['acidity_class'])).keys(), dict(Counter(df_wine['acidity_class'])).values())

数据现在被适当地标记,用于训练三元分类模型。这可以很容易地扩展到四进制、五进制等。我就讲到这里,但是我鼓励你自己动手处理数据和编写代码。
结论
总之,在这篇文章中,我们讨论了如何使用熊猫来标注数据。首先,我们考虑了为葡萄酒数据分配二进制标签的任务,该标签指示葡萄酒的酒精含量是否高于 10%。然后,我们看了看指定三元标签,表明葡萄酒中固定酸度的水平。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
用 Python 标记时间序列数据
用于监督机器学习

图片来源:Freepik
最近,我在进行一个研究项目,我必须标记 112,000 行时间序列数据,这样我就可以在监督机器学习中使用它。我需要数据中的行在事件发生时显示“1 ”,在事件没有发生时显示“0”。但是标签的信息被嵌入了 3 个小时的录音。
本质上我必须去…

作者创建的图像
本文解释了我为此创建的过程和代码。
简而言之,步骤如下:
- 将您的数据加载到脚本 ( 时间序列数据 & 事件标记)
- 将事件的起止时间分解为一列秒/十分之一秒
- 将列表转换成一列 1 和 0
- 将 1 和 0 列写入数据文件的“标签”列
您需要的所有代码都在本文中。您在脚本开始时输入了三个变量。之后,你只需点击运行,带标签的数据文件就会神奇地出现在你的目录中,随时可以用于 SVM、逻辑回归或你正在使用的任何机器学习算法。
注意:假设您已经以适合您的数据类型的方式预处理了您的时间序列数据,并且它与事件标记数据时间同步。
步骤 0:数据准备
开始之前,检查您的数据是否为脚本正确格式化。该脚本使用 2 个文件;您的时间序列数据和您的事件标记。每一个都有一个假设:
- 时间序列数据: 时间序列数据是事件发生时你所做的测量(例如,在 20 分钟的说话时间内所做的神经读数测量)。假设:您的时间列是 csv 文件的第一列(col[0])。
- 事件标记数据:事件标记是显示事件发生和未发生的持续时间。(例如,如果您正在使用神经数据来测量一个人说话时大脑活动的变化,则事件将在这个人说话时发生)。假设:你的事件标记是这样的开始和结束时间形式:

例如,这可以是显示该人每次开始说话和何时停止说话的几个事件。(图片由作者创作)。
注意:如果您的事件数据已经在您的首选采样率的一列中,您只需执行步骤 1、3 和 4。
提示:如果你用音频记录了你的活动,并把它们保存在. mp3 或。wav 文件,我建议使用 Audacity 软件。它可爱又免费,允许你在音频记录上标记事件,并且导出事件标记,就像上面显示的那样。
1。将您的数据载入脚本
现在,您可以加载(1)您的时间序列数据 , (2)您的事件标记数据,( 3)您的时间序列数据的采样率(即您是否以十秒、秒等为单位进行记录)。下面的代码块是唯一需要编辑的代码部分。
import pandas as pd
import numpy as np*# YOUR DATA FILE & NAME* data_file_name = 'data_time_series.csv' data = pd.read_csv(data_file_name, encoding='utf-8', skiprows=0)
*# YOUR EVENT MARKINGS FILE* events = pd.read_csv("event_durations.csv", encoding='utf-8', skiprows=1)
*# YOUR SAMPLE RATE (ie seconds, deciseconds)* sample_rate = 0.1 *#Deci-seconds*
从这一点开始,剩下的代码就可以运行了——不需要进一步的编辑。完成后,带标签的文件将出现在您的工作目录中。
2。将开始-结束时间分成一列秒/十分之一秒
该函数仅从您的事件标记数据帧中提取持续时间,并将其转换为一列秒/十分之一秒(取决于您在步骤 1 中输入的采样率)。
**def addRange (events):**
global events_split events_split = pd.DataFrame()
events = np.array(events)
row = 0
for _row in events:
x = round(events[row,0],1) *# Start time* y = round(events[row,1],1) *# End time* events_split = events_split.append(pd.DataFrame([x]))
while x < y:
x = round((x + sample_rate),1)
events_split = events_split.append(pd.DataFrame([x]))
row = row + 1
return events_splitaddRange(events)
接下来,我们将使用该函数的输出来创建一列标签。
3。将该列表转换为一列 1 和 0
对于这个函数,我们需要首先创建一个包含您的时间序列数据的“time”列的 iterable 变量:
data_time_col = pd.DataFrame([data.iloc[:,0]])
data_time_col = data_time_col.T
然后,下面的函数使用这个变量,以及新分解的事件标记数据,创建一列 1 和 0,与您的时间序列数据上的行完全匹配。
**def createLabels(data_time_col):**
global labels_01_df
labels_01_df = pd.DataFrame() for i in data_time_col.values:
if i in events_split.values:
labels_01_df = labels_01_df.append([1], ignore_index=True)
else:
labels_01_df = labels_01_df.append([0], ignore_index=True)
return labels_01_df
createLabels(data_time_col)
4。将 1 和 0 列写入数据文件的“标签”列
最后,我们需要将您的 0 和 1 列表插入到您的时间序列数据帧中,并将其导出到 csv。(新列将插入到索引[0]中,并推动其他列)。带有标签的新文件将出现在您的目录中,与原始文件同名,但末尾带有“标签”。
data.insert(loc=0, column="labels", value=labels_01_df)
data.to_csv(data_file_name + " - LABELLED.csv", index=False)
瞧,你的文件已经准备好了,可以用于 scikit-learn 或你选择的 ML 库:)
完整的脚本可以在我的 GitHub 页面上找到。
希望那有用!如果你有任何问题,请直接在 LinkedIn 上给我发消息。也可以邮箱 订阅我的帖子 这里。
最后,如果你想进一步支持 Medium 上的作者,你可以在这里注册成为会员。
劳动生产率和其他冒险

伯明翰博物馆信托基金会在 Unsplash 上拍摄的照片
劳动生产率被认为是衡量一个国家福祉的最重要指标之一。不过,我们对它了解的并不多,让我们试着弄清楚它是如何计算的,世界上的事情是如何与它(数据来源: 总经济数据库 )。

稍后我们会找到答案。
劳动生产率客观地反映了一个经济体的健康程度,它基于两个指标:该国的人均 GDP 和就业人口比例。同样的公式可以用另一种方式来写:

*注:本文使用国内生产总值数据(购买力平价)。数据来源总体经济数据库
我们来修正一下什么是 GDP 和人均 GDP。GDP 是国内生产总值,代表一个国家生产的所有最终商品和服务的总市场价值。人均 GDP 表示一个人平均生产多少国内生产总值(GDP /人口)。这两项指标每年都进行测量,并以同一种货币——美元——进行比较。

图表显示,高 GDP 并不意味着人均 GDP 也会高。例如,中国的国内生产总值排名第一,生产的商品和服务数量世界第一。但无论是人均 GDP 还是劳动生产率都没有进入前 10 名,它们分别排在第 61 位和第 78 位,与哥伦比亚和巴西处于同一水平(顺便提一下,这两个国家也是 GDP 排名前 10 的国家):

为什么会出现这种不匹配?首先,中国是人口最多的国家。当按每 14 亿人分配 250 亿 GDP 时,该值比大多数国家低几倍。其次,人们在那里工作很多-2019 年就业人口的比例为 55.6%,高于平均水平 10-12%。第三,中国有廉价或低技术含量的产品。
该国劳动生产率高的 3 个原因:
- 最终产品成本低,但生产量大+就业率低。这些条件适用于生产廉价石油的阿拉伯国家,并且不需要花费大量的精力和时间。
- 高人均国内生产总值+高或平均百分比的就业人口。这是美国和大多数西欧国家的典型模式——所有劳动适龄人口都工作并生产高价值产品。卡塔尔出人意料地成为这个群体的一员。它的高劳动生产率不是像其他产油国那样由低比例的就业人口保证的,而是由更高的成品成本和大量的生产保证的。
- 高人均 GDP 低就业率。这种情况很少见,但这是未来的趋势——有一小部分就业人口生产昂贵的产品。
俄罗斯
我们已经考察了主要经济指标中的领先者。现在我们会在这些评级中发现俄罗斯。就国内生产总值而言,俄罗斯领先于许多国家——新闻和经济书籍告诉我们这一点。事实上,在 2019 年,俄罗斯在世界 GDP 排名(PPP)中排名第 6。但并没有成为劳动生产率的领先者。
我们再来测试一下你的直觉。

我们在一个仪表板上收集了所有最重要的宏观经济指标。

仪表板显示什么?自 20 世纪 60 年代初以来,俄罗斯的劳动生产率(RSFSR)主要是积极的。苏联解体后,俄罗斯和独联体国家的生产率指数大幅下降,直到 2005 年才恢复到 1989 年的水平。劳动生产率的积极动态被 2008 年的危机所拖累,但在 2010 年开始再次增长,并在 2019 年达到最大值(人均 5.99 万美元)。
俄罗斯的劳动生产率随着 GDP 的变化而变化。当图线与柱顶不重合时,第二个因素(就业人数)会产生影响:图下方的柱顶表示就业人数百分比下降,图上方的柱顶表示工作人口百分比上升。

俄罗斯和世界
俄罗斯的劳动生产率从未在世界上处于领先地位。在苏联时期,它上升到了收视率的最高位置。历年最好成绩是 1968 年的第 32 名,最差成绩是 1997 年和 1998 年的第 61 名。之后俄罗斯一直没有升到评级 48 线以上。2019 年,俄罗斯排名世界第 55 位。

在世界平均指数和 GDP 领先的前 25 个国家的平均水平的背景下,观察俄罗斯劳动生产率的动态也很有趣。俄罗斯从未在后一项指标上表现出色。
现在是一些积极的时刻。自 1982 年以来,俄罗斯的劳动生产率超过了世界平均水平。苏联解体后,直到 2006 年,它再次低于平均指标,但在 2007 年赶上了平均指标,不再低于平均指标,并趋于赶上 GDP 领先国家。即使是 2008 年的危机也没有打破这一积极趋势。

我们来总结一下
劳动生产率是衡量一个国家福祉的一个重要而有趣的指标。观察它的动态就像观察 GDP 的动态一样令人着迷。
评分第一是一个相对的概念。你总是可以选择一个让图表看起来更积极的尺度。在我们的分析课程中,您可以学习如何避免数据操纵,并使数据清晰可见。欢迎给我写信,我们会讨论你所有的问题。
LaBSE:由 Google AI 嵌入语言不可知的 BERT 句子
谷歌人工智能如何将多语言句子嵌入的限制推向 109 种语言

通过谷歌人工智能博客的多语言嵌入空间
多语言嵌入模型是将多种语言的文本映射到共享向量空间(或嵌入空间)的模型。这意味着,在这个嵌入空间中,相关或相似的词将位于彼此更近的,而不相关的词将位于彼此更远的(参见上图)。
在这篇文章中,我们将讨论冯等人最近在 T18 提出的LaBSE:Language-AgnosticBERTSentenceEmbed ing。艾尔。这是句子嵌入的最新技术。
现有方法
现有的方法大多涉及在大量并行数据上训练模型。型号如 激光: L 语言-AgnosticSEtenceRpresentations和 m-USE: M 多语言 U 通用 S entence E 编码器它们在多种语言中表现得相当好。然而,它们的表现不如专用的双语建模方法,如翻译排名(我们即将讨论)。此外,由于有限的训练数据(尤其是低资源语言)和有限的模型容量,这些模型不再支持更多的语言。
NLP 的最新进展表明,在掩蔽语言建模(MLM)或类似的预训练目标上训练语言模型,然后在下游任务上对其进行微调。像 XLM 这样的模型是对 MLM 目标的扩展,但是是在跨语言环境下。这些对下游任务很有效,但是由于缺少句子级目标而产生了糟糕的句子级嵌入。
相反,与其他下游任务类似,从 MLMs 产生的句子嵌入必须通过微调来学习。
— LaBSE 论文
语言无关的 BERT 句子嵌入

双向双编码器,带附加余量 Softmax 和通过 LaBSE 纸共享的参数
所提出的架构是基于一个双向双编码器 (郭等。艾尔。 )与加性边距 Softmax ( )杨等人 ) 与改进。在接下来的几个小节中,我们将深入解读该模型:
翻译排名任务

通过谷歌人工智能博客的翻译排名任务
先事后人,郭等人。艾尔。使用翻译排序任务,本质上按照与源的兼容性对所有目标句子进行排序。这通常不是“所有”的句子,而是一些“ K - 1 ”的句子。目标是最大化源句子与其真实翻译之间的兼容性最小化与其他 ( 负采样)。
双向双编码器

双编码器架构经郭等人。艾尔。
双编码器架构本质上使用并行编码器对两个序列进行编码,然后使用点积获得两种编码之间的兼容性得分。郭等人的模特。艾尔。基本上是在一个平行语料库上训练的,用于上一节讨论的翻译分级任务。
就“双向”而言;它基本上在两个“方向”上获取兼容性得分,即从源到目标以及从目标到源。例如,如果从源 x 到目标 y 的兼容性由【y _ I)表示,则分数【ɸ(y_i,x_i)* 也被考虑在内,并且各个损失被求和。*
损耗= L+L′
最大附加利润(AMS)

嵌入空间有无加性余量 Softmax 经杨等
在向量空间中,分类边界可能非常窄,因此很难分离向量。AMS 建议在原 softmax loss 中引入一个参数 m 来增加向量之间的可分性。

AMS via LaBSE 论文
请注意参数 m 是如何从正样本中减去的,而不是负责分类边界的负样本。
如果你有兴趣更好地了解 AMS,你可以参考这个博客。
交叉加速器负采样

通过 LaBSE 纸进行交叉加速器负采样
翻译分级任务建议对“”K-1”和源句子的潜在不兼容翻译的其他句子使用负采样。这通常是通过从该批的其他人那里获取句子来完成的。这种批内负采样如上图所示(左)。然而,LaBSE 利用 BERT 作为其编码器网络。对于像这样的大型网络,批量大到足以为训练提供足够的负样本是不可行的。因此,提出的方法利用分布式训练方法在不同的加速器(GPU)之间共享批处理,并在最后广播它们。这里,所有的共享批次都被认为是负样本,只有本地批次中的句子被认为是正样本。如上图所示(右*)。*
预训练和参数共享
最后,如前所述,建议的架构使用 BERT 编码器,并在掩蔽语言模型(MLM)上进行预训练,如 Devlin 等人所述。艾尔。和翻译语言模型(TLM)目标如在 XLM(康诺和兰普尔)。此外,这些是使用 3 阶段渐进堆叠算法训练的,即首先针对 L / 4 层,然后针对 L / 2 层,最后针对 L 层,训练L/2层。
更多关于 BERT 前期训练的内容,你可以参考我的博客。
把所有的放在一起
LaBSE,
- 将所有现有方法(即预训练和微调策略)与双向双编码器翻译排序模型相结合。
- 是一个庞大的模型,支持 109 种语言。
结果

通过谷歌人工智能博客在 Tatoeba 数据集上的平均准确率(%)
LaBSE 在所有语言上的平均准确率达到 83.7%,明显优于其竞争对手。

通过谷歌人工智能博客进行零拍设置
LaBSE 还能够在没有训练数据的语言上产生不错的结果(零命中率)。
有趣的事实:该模型使用 500k 的词汇量来支持 109 种语言,并为甚至零命中率的情况提供跨语言支持。
结论
我们讨论了语言不可知的 BERT 句子嵌入模型,以及如何结合预训练方法来获得最先进的句子嵌入。
该模型在 TFHub 这里开源。
参考
*LaBSE 论文:【https://arxiv.org/abs/2007.01852 *
带 AMS 的双编码器:https://www.ijcai.org/Proceedings/2019/746
双编码器和翻译排名任务:https://www.aclweb.org/anthology/W18-6317/
https://arxiv.org/abs/1901.07291XLM 纸
了解基于变压器的自监督架构
medium.com](https://medium.com/swlh/bert-pre-training-of-transformers-for-language-understanding-5214fba4a9af) [## 附加边际软最大损失(AM-Softmax)
了解 L-Softmax、A-Softmax 和 AM-Softmax
towardsdatascience.com](/additive-margin-softmax-loss-am-softmax-912e11ce1c6b)*
女士品茶:贝叶斯方法
假设检验的贝叶斯方法和频率方法的介绍和比较
一位女士声称,她可以通过品尝来发现一杯奶茶是先加茶还是先加牛奶。我们如何评价她的主张?通过解决这个被称为女士品茶问题的问题,罗纳德·费雪先生首次引入了假设检验和 p 值的概念。
在本文中,我重温了 Fisher 的解决方案(即频率主义方法),使用贝叶斯方法解决女士品茶的问题,并比较他们的结果。
问题的正式陈述
给一杯奶茶,我们假设这位女士会以概率 p 猜出正确答案(即先加茶还是先加奶)。如果她随机猜测,我们预计 p 等于 0.5——也就是所谓的机会水平。如果她有某种神奇的技能,那么我们期望找到大于 0.5 的概率。
因此,要决定她是否说谎,我们应该测试是否 p=0.5 (称为零假设,通常用 H₀ 或 M₀ 或 p > 0.5 (称为替代假设,用 H₁ 或 M₁ 表示)。为此,我们请她品尝了 N 杯奶茶,并告诉我们她的猜测。我们用 n 表示她猜对的次数。
现在的问题是:我们如何利用这些信息(即 n 和 N )来决定她是否说谎?
常客方法
检验零假设的 frequentist 方法基于 p 值的计算。对于这位女士品茶的例子,p 值是假设这位女士在她的能力上撒了谎,在 N 个杯子中有超过或等于 n 个正确猜测的概率。如果这种概率非常小,那么很难相信她能做出这么多正确的选择仅仅是因为纯粹的偶然。因此,对于 p 值非常小的情况,我们将拒绝零假设。
因此,p 值有多小将是接受女士主张的标准(即替代假设, M₁ )。拒绝零假设有一些传统的阈值。下表提供了总结。

表 1。接受替代假设的阈值
现在的问题是:我们应该如何计算 p 值?
精确 p 值
对于一个任意的 p ,在 N 次猜测中有 m 次正确猜测的概率是

给定零假设,我们有 p=0.5 ,因此,我们可以计算 p 值为

近似 p 值
随着 N 增加,根据中心极限定理 ⁴.,具有 m 个正确猜测的分布收敛到具有均值 Np 和方差 Np(1-p) — 的高斯分布然后,p 值可以近似为 by⁵

其中第二项是值为 n 的高斯分布的累积密度函数(cdf),平均值为 N/2 ,方差为 N/4 。
贝叶斯方法
从贝叶斯的角度来看,无效假设和替代假设可以分别看作是两个不同的模型 M₀ 和 M₁ ,它们都是生成数据的候选对象。那么,贝叶斯假设检验就相当于贝叶斯模型选择:哪个模型更好地解释数据?
贝叶斯模型选择的思想是在给定观察数据的情况下计算每个模型的后验概率,例如在我们的设置中的 P(M₀|n) 。奇后验比定义为两个后验概率的比值,如下所示

其中右边第一项称为奇数先验比,第二项称为 【贝叶斯因子】 ⁶ 。如果两个模型之间没有先验偏好(即,当我们在模型上有一致的先验时),奇数后验比等于贝叶斯因子。
贝叶斯因子是贝叶斯假设检验和 selection⁷.模型中的核心概念贝叶斯因子的高值告诉我们,在给定观察值的情况下,替代模型比零模型更有可能。因此,贝叶斯因子有多大将是接受这位女士的说法的标准(即替代假设, M₁ )。类似于 p 值的情况,有一些传统的阈值用于拒绝零假设,总结在表 1 中。
现在的问题是:我们应该如何计算贝叶斯因子?
什么是 M₀和 M₁?
对于女士品茶的问题,每个模型都可以通过单次正确猜测的概率的先验分布来表征。零模型的特征是直接的,没有任何模糊: p 等于 0.5——先验是 0.5 处的δ分布。因此,条件概率 P(n|M₀) 可以使用上一节提到的公式轻松计算。
然而,替代车型 M₁ 的特性并不简单。我们知道先验分布必须使其整个质量在 p > 0.5 上,但是我们需要精确地指定先验的形式——这对于 P(n|M₁) 的计算是必要的。那么,什么是好的先验选择呢?
先验选择的精确贝叶斯因子
一个非常简单但直观的先验选择是在【0.5,1】的区间上均匀分布。使用此先验,对数贝叶斯因子可以计算为

我们用数值计算积分。
使用 BIC 的贝叶斯因子的先验独立近似
可以证明 that⁸,如果先验分布在参数 p 的最大似然(ML)估计的邻域内非零,那么随着 N 的增加,对数条件概率 log(p(n|m₁)可以通过(常数 times⁹) 贝叶斯信息准则 (BIC)来估计。令人惊讶但真实的是,随着 N 的增加,先验的影响消失了。因此,对于较大的 N ,贝叶斯因子可以近似为(无论何时 n > N/2 )

当 n ≤ N/2 时,我们有 logBF( n )≈-log(N)/2,但它可能不再是一个精确的近似值,因为 p 的 ML 估计超出了先验的支持——小于 0.5 。
对比:我们什么时候相信这位女士?
对于 N 和 n 的不同选择,我们计算了精确和近似的 p 值和贝叶斯因子。然后,对于每个显著性水平,根据表 1,我们计算正确猜测的临界比率(即 n/N ) ,超过该比率我们拒绝零假设。图 1 示出了“临界”、“中等”、“强”和“非常强”4 种不同水平的界限。

图一。对于每个 N,显示了表 1 中提到的不同显著性水平的拒绝零假设的比率决策阈值。绿线对应于贝叶斯方法,紫线对应于频率主义方法。虚线是近似版本,实线是精确版本。
这里有一些有趣的信息:
- 贝叶斯和频率主义方法有非常相似的拒绝零假设的标准,而贝叶斯方法更保守一些。
- 随着 N 的增加,近似值变得更好,同时即使对于 N 的小值,它们也相当精确。
- 当 N 小于大约 8 或 9 时,我们无法做出任何陈述,我们需要至少 17 到 19 个样本才能做出非常有力的陈述。
- 正如所料,随着 N 的增加,我们能够检测到相对于 p=0.5 的更小偏差。
与 frequentist 方法相反,用于假设检验的 Bayesian 方法也可以做出关于接受零假设的声明。逻辑是一样的,我们只需要看负的对数贝叶斯因子。可以找到一组相似的正确猜测的临界比率,在该比率以下,我们将接受零假设(女士说谎)。边界如图 2 所示。

图二。对于每个 N,对于表 1 中提到的不同显著性水平,显示了接受零假设的比率决定阈值。虚线是近似版本,实线是精确版本。
结果可以概括为三点:
- 近似版本和精确版本不再那么接近,原因是 p 的最大似然估计小于 0.5。
- 即使样本少于 5 个,我们也可以接受零假设。
- 少于 20 个样本不可能做出任何强有力的陈述,少于(至少!)60 个样本!
结论
我们从贝叶斯和频率论的角度研究了假设检验,以女性品茶为例。三个一般性结论是:
- 这些方法的决策界限非常相似。
- 正态分布和 BIC 的近似值相当准确,只要它们的假设得到满足。
- 贝叶斯假设检验在拒绝零假设方面稍微保守一些,但是它使得陈述也接受零假设是可行的。
承认
我非常感谢 Navid Ardeshir 、Kian Kalhor、Mohammad Tinati 和 Parnian Kassraie 在过去几年中就相关主题进行了许多有益且有趣的讨论。
代码:
分析的代码(用 Julia 语言编写)可以在这里找到。
脚注:
请参阅 A. C. Davison 的《统计模型》第七章或 l .乏色曼的《所有统计学》第十章,从频率主义者的角度进一步研究假设检验。
值得一提的是,frequentist 的假设检验方法的目的只是拒绝零假设,它不能对接受零假设做出任何声明。
该表由 B. Efron 和 T. Hastie 的“计算机时代统计推断”和 L. Held 和 M. Ott 的“关于 p 值和 Bayes 因子”的信息组合而成。
⁴ m 可以看作是概率为 1 的 N 伯努利随机变量求和的输出。因此,对于大的 N ,其分布收敛于高斯分布。
⁵:这相当于在这些 N 试验中使用单样本 t 检验。
⁶好奇的读者可以思考一下奈曼-皮尔逊引理中贝叶斯因子和似然比之间的关系。
⁷看到 A. Neath 和 J. Cavanaugh 的惊人文章“贝叶斯信息标准:背景、推导和应用”和 B. Efron 和 T. Hastie 的“计算机时代统计推断”的第 13 章,以获得进一步的研究。
⁸对贝叶斯模型选择的介绍见 B. Efron 和 T. Hastie 的“计算机时代统计推断”第 13 章,t 检验和回归检验的贝叶斯替代方法见 Rouder 等人(2009) 和 Rouder 等人(2012) 。
⁹常数取决于 BIC 的定义。如果我们取“计算机时代统计推断”中提到的定义,常数为 1,但如果我们取维基百科中的定义,我们需要常数为 -0.5 。
附录!
几周前我发现了这首歌。这是非常可爱和有趣的,而深深的黑暗和悲伤。我真的很喜欢它,所以我决定利用它的封面显示两位女士喝茶(咖啡?)并将其链接放在本文末尾!
莱拉:Ekho 集体的想法
Ekho 集体:超越系列的歌剧
我们如何创造我们的视听沉浸式体验,让游客与人工智能互动
在我之前关于我们项目的博文中,我研究了我们在 T2 的 Ekho 集体在新冠肺炎期间如何改变建造我们的沉浸式装置 Laila 的过程。现在我们的项目已经接近尾声,2020 年 8 月在赫尔辛基的门票已经开始发售。在这里,我收集了我们集体成员对建设莱拉过程的想法。
莱拉的机器人(人工智能代理)蜂拥在游客周围。解释如下!
尤纳斯·尼斯宁
Joonas Nissinen 是我们的创意技术专家,拥有计算机图形和人工智能背景。他认为莱拉是一个数字世界,它平衡了人类可以理解的戏剧弧线和程序生成技术:

尤纳斯·尼斯宁,我们的创意技术专家
当创造一个歌剧体验时,我们需要有一个传统的情节和叙事。通过在莱拉使用人工智能,我们给了技术自己的机构。引入代理意味着不能保证直截了当的叙述。目前,我们正致力于平衡一个混乱的系统,它有自己的意愿以某种特定的方式运行,并编排该系统的部分以适应我们的叙述。这很难。
我们在 Laila 中以 boids 的形式使用人工智能,boids 是一种计算代理,可以根据一组简单的规则做出决定。Boids(又名鸟形生物)是仿生的。它们表现出群集行为,这在自然界中以鱼群、蚁群,当然还有鸟类群集的形式存在。在莱拉,机器人实际上构成了一个超个体:它们是一种群体智能,表现出涌现的特性。根据简单规则局部互动的代理人的协同作用导致一个更高层次的整体,其行为比每个单独的代理人复杂得多。通过这一点,莱拉变成了一个复杂的系统:没有人能够预测将要发生的一切。
为了解决设计机器人的问题,我创造了一个系统,允许我们在一个尺度上切换机器人的动机:它们对分离的敏感程度,它们排列的容易程度,以及它们运动的凝聚力。此外,boids 的环境由使用各种伪随机噪声函数生成的不断变化的矢量场组成。磁场的作用有点像河流中的水流——朝某个方向流动比较容易,朝另一个方向流动就比较困难。这些向量场也可以用来增强戏剧性,例如通过鼓励 boids 在体验中的某一点以螺旋方式移动。

莱拉内部
因此,我们的机器人遵循各种各样的行为模型,并对他们世界的几种力量(例如重力)做出反应。然后,我们通过激光雷达跟踪莱拉的游客,将他们引入机器人的世界。有了追踪,访问者就有了自己的代理和影响范围。机器人被指定以特定的方式对“自己的”访客做出反应。游客们还介绍了世界矢量场的变化,创造了其电流流动的变化。
当我们的机器人穿越莱拉的时间线并对这种影响的聚合做出反应时,蝴蝶效应就产生了。这意味着最初由 boids 的相互作用产生的系统中的小变化可能会累积成以后更大的变化。这给莱拉带来了不可预测性和神秘感。
奥利·基尔皮
奥利·基尔皮是我们的动作设计师和视觉艺术家,图中他正在评估莱拉的投影的清晰程度。他分享了他在建造 Laila 期间学到的东西,以及他对该项目目前阶段的感受:

奥利·基尔皮,动作设计师和视觉艺术家
在这个项目的这一点上,接近完成时,我们正在努力平衡体验的确定性和它自己产生的程度。我们想给游客自由和故事中的角色。我们也想向游客讲述我们自己的故事。我们正在寻找这两件事之间的平衡——用户将如何互动,以及他们能在多大程度上影响他们的体验。
我以前做过虚拟现实和美术,但是设计一个 360 度的穹顶带来了全新的挑战。在 VR 中,像素更多,精度更高。然而,在 360°我们有一个人的全视野作为我们的舞台——而不是大多数 VR 护目镜提供的有限的隧道视野。在虚拟现实中,用户的视角随着他们一起移动,因为他们独自在体验中。在这里,我为我们所有的参观者同时建立了视觉效果,因为空间和视角是共享的。
关于这个项目一个有趣的事情是,由于这是一个新的设计领域,没有现有的规则。我意识到,在 360°的背景下,平面页面上存在的传统构图规则并不适用。这种环境更加自然,就像在大自然中行走一样——它不是一个环境的快照,或通过某个镜头看到的环境,而是一个环境本身。
Saara-henrikka m kinen
我们的体验和视觉设计师saara-henrikka mkinen 讲述了她在用户测试中对 Laila 的了解:

saara-henrikka m kinen,体验和视觉设计师
由于我们精心制作了 Laila 来对它的访客做出反应,所以看看我们的访客给作品带来了多少层次的重塑是很有趣的。每个人都有自己的个性、记忆和先入之见,这些都会影响他们对作品的解读。这些事情也会影响他们如何互动——既与作品互动,也与各自的访客群体成员互动。例如,我们的一个测试访问者评论说“我没有动,因为其他人也没有动”。另一个人评论道,“我是那种想解散团队的人——我想独立行动。”显然,一些人将莱拉视为一个游戏场:他们开始控制甚至主导这一体验。话又说回来,有些来访者不想被注意,宁愿消失在作品内部。
因为他们包含不同类型的人,每个群体都有独特的经历——在精神和具体层面上。例如,如果两个朋友加入不同的小组,然后讨论 Laila,他们可能不会认可对方谈论的所有内容。由于群体动力影响视觉和声音的产生,其他群体的访问者可能没有体验过特定的部分。
通过 Laila,我们希望为人们一起提供对作品的见解的可能性。他们通过观察彼此来了解莱拉是如何互动的。从这个意义上说,莱拉既是一次个人的旅程,也是一次共同的旅程。
明娅·阿克塞尔松(这篇博客的作者)
我是一名体验设计师和机器人研究员。下面是我对《莱拉》中含义的一些看法:

Minja Axelsson(作者),体验设计师和机器人研究员
莱拉是我们未来的幻想——反乌托邦、乌托邦和现实主义。我们的游客体验所有这些可能性,并参与它们的创造。我希望通过这一点,参观者可以获得一些作品的所有权。即使参观者决定将莱拉作为一个被动的接受者来体验,他们的存在仍然会影响作品的展开。这与现实世界有相似之处:被动也是一种会带来后果的选择。我是一个有点激进的人,所以我通过这个镜头来解释这个作品:我们做出的选择很重要。
在莱拉,没有人能自己选择将会发生什么。这是一个复杂的系统,通过人工智能和访客的互动建立起来。Laila 背后的想法受到了混沌理论和蝴蝶效应的启发:一个系统初始状态的小变化如何能够在后来的状态中产生大的影响(即几周前一只遥远的蝴蝶扇动翅膀影响了龙卷风的路径),以及一个看似随机的系统如何具有潜在的模式和相互联系。Laila 有很多参数,理论上有无限多的事情可以发生,在一定的框架内。当参观者进入作品时,一个特定的现实被创造出来,机会打开又关闭。这与哥本哈根的解释有关——当某种现实被衡量时,它就被创造出来,而其他的选择就从潜在的存在中消失了。
虽然莱拉是一个传统意义上的故事情节,但我认为这种哲学仍然存在于作品中。人们在进入莱拉之前贡献了一段自己的录音,通过这段录音,他们积极参与了莱拉世界的建设。我希望这能给人们一种感觉,他们的声音是重要的,他们正在把自己融入一个复杂的整体。我很高兴听到参观者说他们把这项工作当成了冥想。我认为这证明了它给了他们停下来思考的空间。我很想知道它对我们的人性、技术、它们之间的关系以及我们将共同建设什么样的未来引发了什么样的思考。
埃西·霍塔里
我们的人工智能交互设计师 Essi Huotari 讨论了讲故事在为 Laila 设计人工智能交互中的作用:

Essi Huotari,人工智能交互设计师
我认为 Laila 有三个基本要素:故事、人工智能和访客互动。我最大的设计挑战是平衡我们对莱拉故事的控制和赋予人工智能和游客影响这个故事的权力。在拥有和失去控制之间交替是我们工作的动力。
我认为定义讲故事的是时间的意义:一个时间线,即使是一个抽象的时间线,构建一个故事,并赋予它意图。某些事情发生在其他事情之后。由于莱拉有一个故事情节,我们有时需要从访客和人工智能那里掌握控制权,以推动故事向前发展。这将 Laila 与许多其他交互式装置区分开来,这些装置的功能更像是一个游戏场,有一套始终有效的给定规则。找到合适的地方进行干预是真正的挑战。我认为讲故事和给访问者完全的控制权是一个光谱的两端。莱拉在故事情节中沿着这个光谱移动。
我认为设计过程中最有趣的部分是为实验创造空间,并利用快乐的意外。设计一个拥有自己代理的人工智能代理的体验是很有趣的。我不得不在 Laila 中寻找参数、目标和物理定律的正确组合,而不是选择预先确定的动作,从而产生我们正在寻找的人工智能行为。作为一名设计师,我习惯于决定成品的具体外观和感觉。在这里,我必须放弃一些控制权。作为回报,我们发现了令人愉快的人工智能行为和互动,这是我们事先无法想象的。
伊娜·泰琼拉蒂
我们的编舞 Iina Taijonlahti 对游客如何在 Laila 中移动很感兴趣,并谈到了它在作品中的意义:

编舞伊娜·泰琼拉蒂
从本质上说,社交舞蹈是由莱拉内部的游客创造的。莱拉和外面的世界有着同样的习俗。即使在杂货店里,人们也在不知不觉中创造舞蹈动作。人们移动的方式取决于大量的参数:你是否认识某人,你来自哪种文化,你带着什么设备移动。另一件有趣的事情是,根据参观者的视角,他们可以作为观众的一员,或者是作品中的表演者。这很有趣:我是被观察,还是我是观察者?在某种程度上,参观者进入 Laila 的窗帘就像一个舞台的入口。
我认为莱拉所在的空间技术非常先进。莱拉的球体是非传统的,令人身临其境,这是一直 360 度看东西的结果。游客们评论说他们失去了时间和地点感。
关于 Laila 的一件有趣的事情是,我们给了非人类的 actants 代理权。这是通过莱拉的人工智能代理——它的群体智能——来完成的。这样,莱拉就与后人文主义的概念相关联,因为它关注的是非人类的视角。我一直在思考的问题是:我们如何才能放弃理性主义和人文主义的理想,在那里人类的智慧是至关重要的?我们如何给其他感官空间,以及体验和分配力量的新方式?
海基·海斯卡宁
我们的媒体技术工程师 Heikki Heiskanen 回顾了他创作《莱拉》的经历:

Heikki Heiskanen,媒体技术工程师
与这么多来自不同领域的有才华的人一起工作——比如软件开发、视觉艺术、声音设计和歌剧——令人着迷。由于莱拉是一种新型的艺术概念,它需要不同领域的知识。随着我们将新的信息和知识整合到 Laila 中,它的概念也在不断发展。在这种工作过程中,来自多种观点的观点汇集在一起,并被整合成一个连贯的整体,这种工作过程包括其自身独特的挑战和成功。
随着我们准备向游客开放莱拉,我希望它将被视为沉浸式互动技术讲故事能力的一个例子。声景令人惊叹,视觉效果极具想象力——我会把莱拉描述为一次神奇的经历。
Python 中的 Lambda 表达式
如何用 Python 编写 lambda(或匿名)函数

马库斯·斯皮斯克在 Unsplash 上的照片
介绍
假设我们正在编码,需要编写一个简单的函数。然而,我们只会使用这个函数一次,因此似乎没有必要为这个任务创建一个带有 def 关键字的完整函数。这就是 lambda 表达式的用武之地。
什么是 lambda 表达式?
λ表达式用于创建匿名函数,或者没有名字的函数。当我们需要创建一个只需要使用一次的函数(一次性函数)并且可以用一行代码编写时,它们非常有用。Lambda 函数可以有任意数量的参数,但只能有一个表达式。它们通常具有产生函数对象的这种格式:
lambda 参数:表达式
使用 def 关键字创建函数
假设我们想写一个函数,它接受一个数作为输入,并返回这个数的平方。我们可以通过使用 def 关键字来做到这一点:
我们使用 def 关键字来定义这个函数。我们将这个函数命名为平方。这个函数有一个参数, num ,它使用**运算符返回这个数的平方。
带有一个参数的 Lambda 表达式
现在让我们把这个函数写成一个 lambda 表达式:
就是这样!我们首先从 lambda 关键字开始,然后是参数 num ,一个冒号,以及您希望该函数返回的内容,即 num**2。
注意,这个函数是匿名的,或者没有名字。所以我们不能在以后调用这个函数。另外,我们没有写退货。冒号后的所有内容都是将被返回的表达式的一部分。
如果我们想将 lambda 函数赋给一个变量,以便以后可以调用它,我们可以通过使用赋值运算符来实现:
然后,我们可以调用这个函数,就像调用用 def 关键字定义的函数一样。例如:
square(3) # will return 9 as the output
了解如何有效解决 Python 编码问题!
towardsdatascience.com](/best-way-to-solve-python-coding-questions-376539450dd2)
具有多个参数的 Lambda 表达式
让我们做一个 lambda 函数,它有两个参数,而不是只有一个。首先,我们将使用 def 关键字创建一个返回两个数之和的函数,然后我们将把它写成一个 lambda 表达式:
正如我们所见,如果我们希望我们的函数在一个 lambda 表达式中有多个参数,我们只需用逗号分隔这些参数。
就像使用 def 关键字创建的表达式一样,lambda 表达式不需要任何参数。例如,如果我们想要一个 lambda 表达式,它不接受任何参数,并且总是返回 True,我们可以这样写:
Lambda 表达式中的条件语句
我们也可以在 lambda 表达式中包含 if else 语句。我们只需要确保它们都在一行上。例如,让我们创建一个函数,它接受两个数字并返回其中较大的一个:
我们的 lambda 表达式接受两个数字, num1 和 num2 ,如果 num1 大于 num2 ,则返回 num2 。显然,这个函数不考虑数字是否相等,因为在这种情况下,它将只返回 num2 ,然而,我们只是说明如何在 lambda 表达式中使用条件语句。
[## 在 Python 中压缩和解压缩 Iterables
如何在 Python 中压缩和解压缩可迭代对象
towardsdatascience.com](/zip-function-in-python-da91c248385d)
那其他如果呢?
从技术上讲,我们不能在 lambda 表达式中使用 elif 语句。但是,我们可以将 if else 语句嵌套在 else 语句中,以获得与 elif 语句相同的结果。例如,如果我们还想检查 num1 是否大于 num2 ,如果 num2 大于 num1 ,或者(意味着它们是否相等),我们可以使用下面的 lambda 表达式:
所以如果我们的 lambda 表达式发现num 1>num 2,就会返回 num1 。如果这个条件为假,它将继续执行 else 语句。在这个 else 语句中(在括号内),它首先检查num 1<num 2是否为真。如果条件为真,它将返回 num2 。如果条件为假,它将返回 else 语句之后的内容,在本例中是字符串“它们相等”。
最后一个音符
Lambda 表达式在接受另一个函数作为参数的函数中非常有用。例如,在 map、filter 和 reduce 函数中,我们可以传入一个 lambda 表达式作为函数。
映射、过滤和减少功能的详细概述:
如何使用 python 中内置的地图和过滤功能
towardsdatascience.com](/using-map-and-filter-in-python-ffdfa8b97520) [## 在 Python 中使用 Reduce
如何使用 python 中的 reduce 函数
towardsdatascience.com](/using-reduce-in-python-a9c2f0dede54)
如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 报名,我就赚一小笔佣金。
阅读卢艾·马塔尔卡的每一个故事(以及媒体上成千上万的其他作家)。您的会员费直接支持…
lmatalka90.medium.com](https://lmatalka90.medium.com/membership)
结论
在本教程中,我们学习了什么是 lambda 表达式,如何用零参数、单参数和多参数来编写它们。我们还学习了如何在 lambda 表达式中使用 if else 语句。
Lambda 函数示例和错误处理

Lambda 函数和错误处理。照片由 Pexels 的克里斯蒂娜·莫里洛拍摄
给 PYTHON 开发者的提示
用肮脏的方式编写即时函数。不建议在所有情况下都这样做,但是这样很方便
先决条件
在经历这些之前,你需要熟悉在 Python 中定义自己的函数;否则,你会迷失在中间。下面的文章将会给你更多关于如何定义你自己的函数的信息。
数据科学家需要具有特定功能的函数
towardsdatascience.com](/writing-your-own-functions-40d381bd679) [## 变量范围和 LEGB 规则
变量的作用域指的是你可以看到或访问变量的地方
towardsdatascience.com](/scope-of-variable-and-legb-rule-4d44d4576df5) [## 函数参数:默认值、关键字和任意值
定义一个接受可变数量参数的函数
towardsdatascience.com](/function-arguments-default-keyword-and-arbitrary-9588b5eaaef3) 
Lambda 函数语法。图片由作者
有一种更灵活的方式来动态编写函数,这种方式被称为 lambda 函数。这是因为我们使用了关键字lambda。例如,我们编写一个名为raise_number_to_power的函数作为 lambda 函数。在关键字 lambda 之后,我们指定参数的名称,即x和y。然后,我们使用一个冒号,后面是定义我们希望函数返回什么的表达式。
Lambda 函数允许你以肮脏的方式编写即时函数,所以我不建议你一直使用它们,但是在某些情况下它们会非常有用。例如,map 函数有两个参数。一个函数和一个序列,比如一个列表,以及这个函数对序列中所有元素的作用。

映射函数中的λ。图片作者作者
我们甚至可以不命名 lambda 函数来映射,在这种情况下,我们称它们为匿名函数。例如,我们在一个 lambda 函数上使用一个 map,它对一个列表中的所有元素进行平方运算,你将把结果存储在一个square变量中。在打印square变量的同时,揭示了它是一个 map 对象。为了查看它包含的内容,我们使用函数列表将其转换为列表并打印结果。正如所料,这是一个包含原始列表中元素的方块的列表。
错误处理
当你误用一个函数时,它会抛出一个错误。例如,检查从数字或字符串返回浮点的函数 float。当您向函数 float 传递一个整数值时,会返回相应的 float。类似地,如果你给它一个字符串8.7,它将返回浮点值。

不正确地使用函数将返回错误。图片作者作者
但是,如果您向它传递字符串hello,Python 将抛出一个错误,告诉您它无法将字符串转换为 float。在这种情况下,它抛出了一个ValueError,并且有许多类型的错误。当我们编写函数时,我们可能希望发现特定的问题并编写特定的错误消息。让我们来看看计算数字平方根的用户定义函数。它像预期的那样处理整数。如果我们给它传递一个字符串,比如hello,会有什么结果?它会抛出一个错误,对应于函数定义中的一行代码。

将字符串转换为浮点错误。图片作者作者
这个错误说它是一些TypeError,但是这个消息可能对我们函数的用户不是特别有帮助,所以我们应该尝试为我们编写的函数提供有用的错误消息。
捕捉此类异常的主要方法是 try-except 子句,在该子句中,Python 尝试在尝试之后运行代码,如果可以,一切正常。如果由于异常而无法工作,它将运行异常代码。现在让我们重写我们的square_root函数,但是这一次捕捉任何引发的异常。在这个例子中,我们试图执行x的0.5次方。使用 except,在出现异常的情况下,我们打印x must be an int or float。我们看到,结果函数对于整型和浮点型都工作得很好,并且打印出了我们想要的字符串。

用消息捕获 TypeError。图片作者作者
我们也可能只希望捕获TypeError并让其他错误通过,在这种情况下,我们将使用 except TypeError。可以检测到许多不同类型的异常,您可以查看在线提供的 Python 文档。您将希望通过使用关键字raise来引发一个错误,而不是简单地打印一个错误消息。

使用条件提高 ValueError。图片作者作者
例如,square_root函数在应用于负数时做了一些我们可能不想要的事情。它返回一个我们可能不想要的复数。假设我们不希望我们的函数适用于负数。使用 if 子句,我们可以在用户向函数传递一个负数的情况下引发一个ValueError。如果我们给我们的新函数一个负数,看它返回规定的ValueError。
**Other Interesting Articles**#1 [Function Arguments: Default, Keyword, and Arbitrary](/function-arguments-default-keyword-and-arbitrary-9588b5eaaef3)#2 [Scope of Variable and LEGB Rule](/scope-of-variable-and-legb-rule-4d44d4576df5)#3 [Writing Your Own Functions](/writing-your-own-functions-40d381bd679)#4 [Python: Procedural or Object-Oriented Programming?](/python-procedural-or-object-oriented-programming-42c66a008676)#5 [Data Science with Python: How to Use NumPy Library](/data-science-with-python-how-to-use-numpy-library-5885aa83be6b)#6 [Do you have the Software Engineer and Data Scientist skills?](/do-you-have-the-software-engineer-and-data-scientist-skills-probably-not-7e8fb069e067)
关于作者
魏江是一名研究员,负责收集、组织和分析意见和数据,以解决问题、探索问题和预测趋势。
他几乎在机器学习和深度学习的每个领域工作。他正在一系列领域进行实验和研究,包括卷积神经网络、自然语言处理和递归神经网络。
连接上 LinkedIn
获得你的第一份数据科学工作
关于如何在毕业后立即成为数据科学家的 10 个实用技巧。

图片由 StartupStockPhotos 来自 Pixabay
你辛辛苦苦学了几个月统计学和编程的【来龙去脉】,把所有基本的机器学习算法都背下来了。你也许可以解释神经网络如何工作,什么是反向传播,以及模型中的权重如何更新。
你最好的朋友忘记了你的存在,因为你已经有一段时间没有看到他了,因为你正忙着试图将你最新的随机森林模型改进到小数点后的另一个分数(经过几天的反复试验,你终于成功了)。
但后者并不重要…
如果你想,你可以在几个小时内完成所有这些。所以你终于有信心成为数据科学大师了!或者至少认为自己是一个体面的早期内行。
干得好!但是现在呢?
现在你需要让其他人相信你确实是一名数据科学家,这可能比学习技能本身更难。
因此,我将与你分享一些帮助我寻找数据科学工作的技巧,所以如果你感兴趣,请耐心等待…

- 确定你想要什么类型的工作。
有数以千计的数据科学家职位可供选择,但它们可能并不都适合你想要做的工作。你知道你在数据科学方面最强的部分是什么,你对什么感兴趣。你可能对传统的机器学习感兴趣,或者喜欢深度学习,并且已经完成了几个专注于神经网络的项目。
你是一个更喜欢动手的人,喜欢实现算法,对创建生产就绪代码感觉良好吗?
或者你宁愿阅读最新的研究并尝试实现最新的神经网络架构?
你想去大公司还是中型公司工作?或者你更愿意为创业公司工作?
公司文化对你来说重要吗?
你愿意搬迁吗?如果愿意,距离有多远?或者你可能只接受远程位置。
这些都是有效的选择,但我建议,对于第一个数据科学职位,你应该找一个不仅仅是公司中唯一的数据科学家的职位。
在你开始申请任何工作之前,你需要有这些答案,因为这会节省你的时间和精力。
2。申请尽可能多的相关职位。
一旦你想好了你想要的工作类型,你就可以开始申请这些职位了。重要的是,你要坚持你为自己的工作列出的规则,并把它应用到唯一相关的职位上。
我要再重复一遍:
这一点极其重要,只适用于相关职位。
数据科学家角色的职责差异很大,根据角色定义的不同,您最终可能会完成完全不同的任务。你想确定你会成为你所了解的并让你保持兴趣的人。
此外,在你不熟悉或根本不感兴趣的领域找到工作也很难。即使你在面试过程中取得了成功,在接下来的几个月或一年里,你也将被迫这样做,可能会感到痛苦。
你的完美工作还在外面。
3。创建一个电子表格来跟踪应用程序。
你不需要准备任何花哨的东西。谷歌电子表格就够了。你需要记录公司名称、你申请的职位、招聘广告的链接、申请日期、你是否得到回复,以及你是否描述了回复的内容,如被拒、电话面试邀请等。
这足以让你有条理,你会知道你申请了多少份工作,在什么时间跨度内,这基本上会帮助你在这个过程中保持理智。
有时你可能会觉得你已经申请了数百份工作,而当你看着电子表格时,你会发现实际上是很多,但没有你想象的那么多。

4。看看小一点的求职板和公司网站。
因此,有一些显而易见的我们都知道的通用求职平台,比如 Monster,实际上还有 Craigslist,它们都是很好的起点。一定要将申请发送到广告中的职位,但是公司通过这些网站收到的申请数量会很高,可能很难脱颖而出。
试着找一些与数据科学相关的,或者你想工作的特定领域的小职位。数据科学家找工作的好地方是
我个人已经远程工作好几年了,并且一直在面试上面页面上发布的工作。
此外,对于远程员工来说,寻找数据科学工作的好地方是:
- 我们远程工作
- 远程确认
5。查看公司网站寻找数据科学工作。
除了招聘信息,我还鼓励你搜索当地公司的网站,看看他们是否在招聘数据科学家。公司的政策可能是先在网站上做广告,然后转向更广泛的招聘广告。
正如你所想象的,公司网站上的申请人应该更少,所以你获得面试的机会会更高。
同样,你不仅可以查看当地公司,还可以找到其他方法来识别可能寻找数据科学家的企业。
好方法是查看你的朋友数据科学家毕业生工作的公司。有可能他们现在正在招聘,你甚至会被公司里的人推荐。
6。参加聚会和数据科学活动,并积极参与其中。
求职的另一个重要方面是参加当地的数据科学会议和其他数据科学相关活动。参加这些活动的都是对这个领域感兴趣的人或者是在这个领域工作的人。尝试与他们联系可以让你获得他们工作的公司的推荐,并最终获得一份工作。
积极参加这类活动很重要。
听一个小时关于优化梯度提升算法的讲座,然后看一个人回答公众的问题,你不会从中受益。
只有当你是活动的积极参与者时,你才会受益。也就是向正在演示、交谈并与其他参与者互动的人提问。你永远不知道你旁边的人什么时候会成为另一个工作领导。

图片由 uh_yeah_20101995 发自 Pixabay
7。清理 GitHub 账号,上传好项目。
对于任何一个数据科学家的角色来说,发送一个到你的 GitHub 个人资料的链接和你的简历和求职信几乎是一个要求。虽然更有经验的数据科学家可以用一个几乎空无一物的 GitHub 档案逃脱,但对于该领域的新手来说却很难。最后,你试图证明你可以成为一名数据科学家,这是一个很好的机会。
因此清理你的 github 账号,添加你引以为豪的优秀项目。
后者也意味着去除所有不相关的、不展示你技能的垃圾。在顶部展示你最好的项目,这样招聘人员打开你的 GitHub 档案时就会看到这些项目。
我推荐一些可视化效果很好的项目。我们是人,我们更喜欢吸引人的视觉效果而不是代码。
此外,一些招聘人员可能不太懂技术,可能不了解代码的细节,所以用漂亮的视觉效果吸引他们的眼球通常会奏效。
数据科学家的最佳生产力工具,如果您还没有使用它,您应该使用它…
towardsdatascience.com](/jupyter-notebook-autocompletion-f291008c66c)
8。有一个投资组合的网站。
这并不是任何求职申请的必备条件,但在试图让别人相信我们擅长某事时,这可能是一个不错的加分项。有如此多的在线编辑器允许你创建网站,所以你可以选择任何免费和受欢迎的网站或者使用 GitHub 页面。网上有很多教程教你怎么做。
确保你的网站有吸引力,并描述五个你引以为豪的项目。再一次,漂亮的视觉效果是加分项。
你希望你的网站引人注目,并显示你是你所做的专业人士。
在你的描述中不要使用技术术语,要像对待商业或产品专家一样对待访问者。你需要说服他们为什么你做的项目对世界有价值。如果他们对技术实现感兴趣,他们可以看看你的 GitHub 页面,所以一定要把你的项目链接到那里。
同样,有些人没有自己的网站(包括我),他们被雇佣了。然而,这些人依赖于他们以前的经验,所以他们不必努力工作来证明他们能胜任这份工作。
然而,作为这个领域的新人,你需要努力在各个层面给人留下深刻印象。你给人的印象越好,你获得面试的机会就越多。因此,花几个小时创建网站真的是值得的。

图片由 StartupStockPhotos 来自 Pixabay
9。记住三个你参与过的项目,并能围绕它们讲述故事。
所以这是面试准备的建议,这意味着你已经给某人留下了足够深刻的印象,以至于他会给你打电话,甚至亲自面试。您现在需要用您的数据科学知识给他们留下更深刻的印象。
我建议你修改你做过的三个项目,修改代码,记住项目的设定,以及所有关于它的小细节。
你是独自工作还是在团队中工作?
你一直在使用什么工具?
你用了什么算法?
结果如何?
你用什么标准来评估结果?
你有什么挑战吗?
如果你要重做这个项目,你会有什么不同的做法?
你需要能够回答所有这些问题以及其中三个项目的类似问题。为什么我说三个?一个不够?
你想要准备三个项目,这样当面试官问你关于体验的时候,你可以拿出其中的任何一个。可能会问你几个问题,所以你要准备好各种场景,不要看起来像你只是在一个大项目上工作。
即使问题不完全是上面提到的那个,通常准备上面的答案和重读项目代码会让你为面试官的问题做好准备。
此外,请注意,面试官的一些问题不是问项目本身,而是你应该用项目参考来回答。例如像‘你知道什么分类算法?’使用项目参考比只提供算法列表更好。
您可以通过实际找到包含数据科学面试问题的网站来练习,并尝试使用您选择的三个项目参考来回答这些问题。这应该让你为面试官可能会有的大量经验和技术问题做好准备。
10。了解公司和将要面试你的人。
为面试做好准备至关重要。你不知道公司的每一个细节,但是知道公司的概况总是一个好主意。
访问他们的页面,看看他们提供什么?
他们的潜在客户是谁?
他们的商业策略是什么?
他们的数据科学团队是什么?
公司价值观是什么?
这些信息通常可以在 LinkedIn、Glassdoor 或该公司的网站上找到。了解公司的一些细节是你的优势,会让你和面试官的对话更加流畅。
在面试之前了解一下面试官自己也是一个好主意。平时查查他们的 LinkedIn 应该就够了。你也可以看看他们是否有博客或者有什么有趣的在线信息。
了解这一点不会让你通过面试,但会让谈话变得更愉快,并可能帮助你不那么紧张。和你了解一点背景的人交谈比和完全陌生的人交谈更容易。至少这是对我的帮助!
总结
这些是我的十个建议,应该有助于获得你的第一份数据科学工作。显然,在面试和求职准备中,你还可以做更多的事情,但我相信,遵循这简单的十个步骤将会大大增加你获得工作的机会。
我希望这些信息对你有所帮助,祝你好运!
最初发布于 aboutdatablog . com:2020 年 4 月 2 日登陆你的第一份数据科学工作,。
PS:我正在 Medium 和aboutdatablog.com上写文章,深入浅出地解释基本的数据科学概念。你可以订阅我的 邮件列表 在我每次写新文章的时候得到通知。如果你还不是中等会员,你可以在这里加入。
下面还有一些你可能喜欢的帖子
解释一些乍一看不那么明显的东西…
towardsdatascience.com](/7-practical-pandas-tips-when-you-start-working-with-the-library-e4a9205eb443) [## 对熊猫中的数据框进行排序
如何快速有效地排序数据帧
towardsdatascience.com](/sorting-data-frames-in-pandas-a5a3af6f346a)*
登录代码:将登录页面应用到 Jupyter 笔记本中

图一。登陆代码亮点(图片作者, Unsplash , IRA 设计,多像素)
数据可视化
引入交互式 Python 编程的新概念
编译 Python 代码有很多选择。可以在终端、IPython、Spyder、Jupyter 笔记本等运行。如果你想要一个交互式编译器,也许你会选择 Jupyter 笔记本。但是,IPython(交互式 Python 的简称)是一个不错的选择。
有两种类型的 IPython 可以选择,IPython Shell 和 IPython Notebook。要打开 IPython Shell,只需在终端中写 ipython ,输入ipython notebook即可打开 IPython Notebook。那么,IPython 笔记本和 Jupyter 笔记本有什么区别呢?我没有把握回答它。但是,如果你通过终端启动 IPython 笔记本,会被建议输入 jupyter 笔记本 ,而不是 ipython 笔记本 ,如图 2 所示。我觉得 IPython 笔记本在和 Jupyter 笔记本迁移融合。

图二。终端中的 IPython 笔记本(图片由作者提供)
新的替代方案是 Jupyter 实验室,但我不熟悉它。我用 Jupyter 笔记本更方便。也许,我将来会写一个关于它的故事。
主要目标
在这个故事中,我将与你分享一个用 Python 进行交互式编码的新概念。我给大家介绍 登陆代码 ,一个将网站框架中的登陆页面应用到 Jupyter 笔记本中。您可以在图 1 中看到我制作的登录代码的突出部分。
Yups,我将分享如何在你的 Jupyter 笔记本(以下简称 Jupyter)中建立一个登陆代码。它将给你一个交互式 Python 编码的新体验,并以一种新的方式呈现你的代码,感受一种新的氛围。
在我们建立一个登陆代码之前,我想告诉你建立它的概念。着陆代码建立在 Jupyter 单元中,采用 Markdown 类型。我已经在 Jupyter 中解释了一些细胞类型;你可以在下面的链接中查看。
一个关于自定义 Jupyter 笔记本主题和轻松调整 Maptlotlib 参数的故事
medium.com](https://medium.com/@rizman18/how-can-i-customize-jupyter-notebook-into-dark-mode-7985ce780f38)
问题和解决方案
我们将在构建登陆代码时面临一些问题。当然,我会给你另外的解决方法。首先,我们不能在 Jupyter 单元格中运行 CSS,只能运行 HTML (Markdown)。我认为这是一个大问题。但是没关系。我们将用简单的图形设计技巧来介绍它。因为我们不能使用 CSS,所以我们不能建立一个像登陆页面响应登陆代码。同样,我们将使用一个奇特的 HTML 和图形设计范例来解决它,比如使用渐变、阴影效果、空白、统一概念等。
准备元素
我们将建立一个登陆代码和一些在登陆代码页提供的参考页面。登录代码由页眉、主图像、正文和页脚组成,而引用页面由页眉、主图像和一些代码单元格类型组成。要实现它,我们需要一些元素。图 3 显示了我们构建登陆代码所需的标题和主要图像元素。

图 3。登陆代码中的页眉(红框)和主图片(灰框)元素(图片由作者和 IRA 设计)。
我使用 HTML(包括超链接)创建标题文本(徽标、主页、数据科学、机器学习、编程)元素,并使用 Inkscape(像 Adobe Illustrator 这样的矢量图形软件)在主页中创建圆形蓝色按钮。主图像元素中的文本由 HTML 生成,图像从 IRADesigns 下载。感谢 IRADesigns,它提供了许多免费的插图。
主体元素由 6 篇文章及其标题、图片和副标题构成,如图 4 所示。每篇文章 6 张图片,从 Unsplash 下载,关键字“数据”。

图 4。登陆代码中的主体元素(图片由作者和 Unsplash 带关键字“数据”)组成。
我使用简单的 HTML 为我的登录代码创建了一个简单的页脚,如图 5 所示。

图 5。登陆代码和页脚元素中主体的某个部分(图片由作者和 Unsplash 带关键字“数据”)。
我创建了三个页面,数据科学页面,机器学习页面,以及参考页面的编程页面。它们的标题和主要图像元素如图 6 所示。



图 6。登陆码中每个引用页面的页眉和主图(图片作者和多像素)。
每个引用页面的标题和主图像都由登录代码页中的相同概念构成。我从多像素下载图片。感谢多像素。在 Header 和 Main Image 之后,被引用的页面后面是代码单元,如图 7 所示。


图 7。数据科学页面中的编码单元类型(图片由作者和多像素提供)。
程序
构建登陆代码的第一步是定制你的 Jupyter,使用 CSS 格式,而不是 jupyterthemes 库。您需要在 Jupyter CSS 文件中添加一些代码,命名为 custom.css 。可以在目录~/中获得。如果你找不到目录。朱庇特,也许它被你的背景隐藏了。可以通过按 Ctrl + H 查看隐藏的文件和目录,前缀来解决。(圆点)。如果您没有找到目录 custom 和文件 custom.css,您可以创建它们。custom.css 中包含的代码如图 8 所示。

图 8。用 CSS 定制 Jupyter(图片由作者提供)。
如图 8 所示,custom.css 文件包含 Jupyter 页面的任何手动 css。我们只是在这里写附加的或者更新样式。在这一步的开始,我们将在 Jupyter 中隐藏 ln 容器,如图 9 所示。


图九。在 Jupyter 中隐藏 ln 容器(图片由作者提供)
通过在 custom.css 中添加以下代码,可以隐藏 ln 容器并保存。
div.prompt,
div.tooltiptext pre {
display:none
}
因此,更新后的 custom.css 如图 10 所示。

图 10。custom . CSS 中的附加样式(图片由作者提供)
保存后,请刷新您的 Jupyter 页面。你会得到 ln 容器现在是隐藏的,如图 9 的左面板所示。
下一步是使单元格容器适合显示器的宽度。您可以通过在 custom.css 中添加以下代码来实现
.container {
width: 100% !important;
}
要使 Jupyter 中的 Notebook-container、Notebook_app 和 Body Header 变成白色(与背景相同),可以添加以下代码
#notebook-container {
padding: 0px;
background-color: white;
}.notebook_app {
background-color: white;
}body #header{
background-color:white;
}
添加这些代码后,您将获得 Jupyter 的新显示,如图 11 所示。

图 11。用 CSS 定制 Jupyter(图片由作者提供)。
接下来,通过添加以下代码来删除单元格之间的边框
#notebook {
padding-top:0px !important;
padding-bottom:0px !important;
}.container {
width:100% !important;
}.end_space {
min-height:0px !important;
}
应用它之后,您将获得如图 12 所示的新外观。请将其与图 10 和图 11 进行比较。

图 12。用 CSS 定制 Jupyter(图片由作者提供)。
修改 custom.css 的下一步是使图形结果与显示居中对齐。您可以看到图 12 中生成的图形是左对齐的。您可以通过添加以下代码来更改它
.output_png {
display: table-cell;
text-align: center;
vertical-align: middle;
}
保存 custom.css 并刷新 Jupyter 页面后,您将得到结果,如图 13 所示。

图十三。用 CSS 定制 Jupyter(图片由作者提供)。
接下来,您可以通过按 View(在左上角面板)隐藏切换标题和切换工具栏。然后按切换标题和切换工具栏。完成后,您将看到 Jupyter,如图 14 所示。

图 14。隐藏 Jupyter 中的切换标题和切换工具栏(图片由作者提供)。
下面是 custom.css 中的完整样式
在接下来的步骤中,我们将更多地讨论 HTML 框架。在登录代码页中,我在一个 div 标签中设置了页眉、主图像、主体和页脚。要创建 div,可以使用下面的代码
<div>
Content of Your Div
</div>
所有的元素背景都是在 Inkscape 中设计的。图 15 显示了登录代码的主板。

图 15。登陆代码设计(图片由作者和 IRADesign 提供)
你明白了吗?Yups,图 15 中没有显示的每个元素,都是用 HTML 创建的。例如,我通过组合按钮和超链接标签来创建标题文本。您可以使用这段代码来创建它
如果你只想使用一个超链接标签,这是没问题的。标签&emsp; 用于插入制表符。我们为什么需要它?答案是我们不能在 Jupyter 单元格中使用 CSS。只有 HTML 😄 .您需要通过按单元格- >单元格类型- > Markdown 来复制具有 Markdown 类型的 Jupyter 单元格代码。结果如图 16 所示。

图 16。登陆代码中的标题元素(图片由作者提供)
我在后添加了一些中断标签
以使其更加清晰。如果您看到更多细节,在图 16 中看不到文本 Home。你看不到它,因为文本 Home 的颜色是白色的。您需要使用此代码在单元格中插入主板设计(图 15)。
您可以看到我在第 13 行插入了许多 break 标记。原因和前面一样,我们不能在 Jupyter 单元格中使用 CSS。尤普斯,着陆代码的概念是一个棘手的问题。如果您运行它,您将得到如图 17 所示的结果。

图 17。登陆代码中的头元素(图片由作者提供)
之后,您需要用这段代码创建欢迎文本。
结果如图 18 所示。

图 18。登陆代码中的标题和主要图片元素(图片由作者和 IRADesign 提供)
接下来,如何创建主体(图 4)?我使用一个表格标签来创建它。我创建了两个表。对于每个表,它由 1 行和 3 列组成。您可以使用这段代码来创建它。
您可以将代码添加到前面的代码中,在 break 标记之后和 div 的结束标记之前。结果如图 19 所示。我会在下一段给你提供完整的版本。

图 19。登陆代码中的主体元素(图片由作者和 IRADesign 提供)
您可以用相同的代码创建下一个表。之后,您需要使用这段代码创建一个简单的页脚
<span style="color: white"> Copyright © 2020\. Allrights reserved. </span>
以下是创建登录页面的完整代码
运行之后,您将得到如图 20 所示的结果。

图 20。登录代码页面 1(图片由作者、IRADesign 和 Unsplash 提供)
接下来你需要创建引用的页面,分别命名为 data_science.ipynb、machine_learning.ipynb、programming.ipnyb,这里我只和你分享一页的代码。它在这里
所有的材料,包括网页设计,图片,和。ipynb 文件上传在我的 GitHub 里。您可以通过此链接访问
该代码创建登陆代码,一个应用程序的登陆页面到您的 Jupyter 笔记本 GitHub 是超过 50…
github.com](https://github.com/rizman18/landing_code)
你可以在 YouTube 上观看集锦预览
结论
登陆代码是交互式编程(Python 或 R)中的新概念。这是我们建设未来准备的一部分,因为技术总是在发展。它不够有效,因为我们不能在 Jupyter 单元格中运行 CSS。在这个故事中,使用 Jupyter Notebook 进行更多的交互式编程是一个小小的努力。
有兴趣看我其他的故事吗?你可以点击访问我的简介。如果你对创建登陆代码感兴趣但没有时间,你可以通过 Fiverr 联系我。
如果你喜欢这篇文章,这里有一些你可能喜欢的其他文章:
[## 使用 Matplotlib 实现 Python 数据可视化—第 1 部分
完成了从基础到高级的 Python 绘图的 Matplotlib 教程,包含 90 多个示例
towardsdatascience.com](/visualizations-with-matplotlib-part-1-c9651008b6b8) [## 使用 Matplotlib 可视化数据的 5 个强大技巧
如何使用 LaTeX 字体,创建缩放效果,发件箱图例,连续错误,以及调整框填充边距
towardsdatascience.com](/5-powerful-tricks-to-visualize-your-data-with-matplotlib-16bc33747e05) [## 用于科学绘图的 Matplotlib 样式
为您的科学数据可视化定制 Matplotlib
towardsdatascience.com](/matplotlib-styles-for-scientific-plotting-d023f74515b4) [## 在 Matplotlib 中创建色彩映射表
从颜色列表中创建和定制自己的色彩映射表的指南
towardsdatascience.com](/creating-colormaps-in-matplotlib-4d4de78a04b8) [## 在 Matplotlib 中自定义多个子情节
使用 subplot、add_subplot 和 GridSpec 在 Matplotlib 中创建复杂 subplot 的指南
towardsdatascience.com](/customizing-multiple-subplots-in-matplotlib-a3e1c2e099bc)
仅此而已。感谢您阅读这个故事。喜欢就评论分享。我还建议您关注我的帐户,以便在我发布新故事时收到通知。
城市房产数据中的房东定位
没有人应该被驱逐,句号。Python & React 可以帮助阻止它。

诺亚科特 2020
介绍
驱逐(Eviction)是一种根据法院命令,合法地将房客从他们的住所强行驱逐出去的过程,尽管通常是由自己动手的房东非法实施的。通常情况下,驱逐是一个滚动的过程,市政房东-房客法院处理大量案件,最后由警长敲你的门,但我们不是在正常时期。大多数人都很幸运,他们的房东遵守了法律,一直等到法院重新开庭审理因持续的新冠肺炎危机而关闭了几个月的驱逐案。那些有幸拥有一个守法房东的人并不幸运;他们现在知道,在一段不可描述的时间内,他们将面临无家可归的问题。
许多处理房东-房客问题的法院一开始就无法处理驱逐案件,更不用说在当前的经济衰退时期了。这些都不足为奇。法院不是为了帮助房客而设立的;它们是保护资本的堡垒,帮助土地所有者获得意外利润。租户通常准备不足,得不到政府机构的支持,在一个专为奸商建立的系统中无法获得足够的代表权。这种不公正留给了当地组织去对抗,包括租户联盟和同情的法律团体/服务,他们缺乏反击所需的工具和数据。很明显,租户组织是一门独立的科学,大多数这样的团体都做得很好。拥有更多信息和工具来筛选这些数据,将使租户组织者能够更准确、更深入地锁定社区和房东。
动机
作为费城租户联盟和德雷克塞尔学生租户联盟的租户组织者,我对其挑战有第一手的经验。第一步总是要弄清楚自己面对的是什么,这通常包括使用城市数据工具,如费城地图。

费城地图集
图集工具绝不是无用的;它提供了相当多的洞察力,但仅针对单个属性。关于该房产的信息往往已经过时,或者缺少所有者的实际邮寄地址。这种数据的缺乏使得研究人员/组织者很难得出有意义的结论,除非进入一个可能空空如也的兔子洞,在谷歌上搜索附加了城市的名字。
我可以写一整篇关于土地所有者如何隐藏在系统生成的数据背后的文章。不过,现在,我将只解释一个相关的策略。房东,尤其是有问题的房东,会躲在看似无止境的空壳公司后面,这些公司几乎不知道谁拥有他们。这些空壳公司、有限责任公司和合伙企业这样做也带来了另一个问题,你怎么知道“123 Street Road APT 3 LLC”拥有什么?虽然大多数这些非常明确命名的公司只拥有他们描述的财产,但有时数据会暴露他们拥有多少和在哪里。费城地图集工具不会轻易为您提供这些信息。系统仅基于属性进行过滤。

费城阿特拉斯酒店视图
只有按单个地址过滤才是呈现属性数据的个人主义方法。这种方法描绘了这样一种情况:在一个有数百万人口的城市中,只有一个房客在一套公寓中遇到问题,而这个房客却独自承担责任。在没有足够的知识、支持和/或代理的情况下,创建一种类似于进入房东-房客法庭的感觉,我们可以开始假设这是同一系统的一部分。人们意识到法院不是为房客设立的。他们是遍布我们城市的中产阶级化发展机器的一部分,城市的工具也不能不受其影响。
我出发去看看我能做些什么来改变这一切。我想使用城市在地图集工具中使用的相同数据集,opa _ properties _ public . CSV,并以一种更加民主化和集体化的方式呈现它。这是居住在费城的人们的数据,而不仅仅是土地所有者留下的痕迹。随着可以与大萧条相媲美的驱逐危机的逼近,我们需要迅速创造工具,阻止土地所有者隐藏在混乱、不准确的数据中,并暴露他们拥有的一切,给租户和租户倡导者一个战斗的机会。

诺亚科特 2019
数据源和描述
几个月前,我被安排在德雷克塞尔大学开始我教育的最后一个合作模块。尽管如此,当新冠肺炎关闭一切,我的合作社被取消。由于找不到替代合作社,也没有资格参加整个学期的课程,我决定做点什么来弥补我从上一个合作社中获得的发展经验。通过我与费城租户联盟的合作,我知道该市有很多数据可供我们联盟中的租户和我们倡导的租户利用。
费城开放数据包含费城地区可用的数据集目录,确切地说是 379 个数据集。我很快浏览了他们的目录,找到了 Atlas 工具使用的城市房地产评估数据。这个数据集创建于 2015 年,包含数十万套房产,但这些是如何在费城的业主之间分配的?在该集合中的 581,456 个资产中,只有 429,983 个唯一拥有实体。

直方图 1
房东拥有多少房产的分布相当有趣。在直方图 1 中,我绘制了这个分布的直方图。直方图记录在 y 轴上,以便更好地显示数据。尽管如此,x 轴在这里看起来更有趣。右边尾巴上的条形之间的间隔,显示了财富差距是如何快速增长的。

直方图 2
起初,我很惊讶左边的拖尾有多严重,这表明这个数据集中的大多数拥有实体只拥有一个属性,但这是有意义的。根据调查城市中谁单独拥有财产的经验,我可以说这种分布是严重拖尾的,因为存在大量不稳定的专门命名的公司、有限责任公司和合伙企业,它们的存在仅仅是为了“拥有”这些财产。假设大多数人不拥有大量财产也是公平的,美国消费者新闻与商业频道声称大多数人拥有 1 到 10 处财产,这是这个柱状图所描述的。
从 Python 开始
为了开始解释这个数据集,我需要从对数据进行排序和搜索开始。我选择使用 Python 3,我知道这种语言可以处理数据集中的 500,00 多个条目,并开始工作。我首先想知道的是:
这个集合中有多少个唯一的拥有实体?
他们拥有多少房产?
这个分布看起来像什么?
将它分解成更小的步骤,我开始创建一个只包含每个拥有实体一次的对象。如果它们出现不止一次,我需要更新那个拥有实体的计数。这些步骤转化为下面的 Python 3 代码。
意识到拥有大量实体并希望将这些数据用于 web 应用程序,我意识到我需要将这些数据分开。为此,我写了一个函数,为我认为的重要房东设置了一个下限。
我还编写了一些函数来编译来自原始 CSV 文件的仅包含房东和属性的 JSON 对象。
在这一点上,我开始考虑如何构建 React 使用的数据。JS 前端。我决定创建一个对象,通过房东和房产信息的子结构来组织数据。这段代码很大程度上受到我在前端呈现数据的方式的影响。尽管如此,这段代码应该提供其结构的一般要点。
如果你想更详细的看看我的数据处理或者想叉一下,这里是 GitHub 的资源库。
创建节点/快速 API
在处理完数据并创建了分割数据集的 JSON 文件后,我开始工作。我开始构建一个 node.js 服务器,它利用 Express 来创建 API 端点。(如果你想了解更多这方面的信息,点击这里)。我意识到列出 400,000 多个拥有实体会使浏览器崩溃或速度极慢,所以我为不同的 JSON 文件创建了端点。
为了抑制呈现所有实体的数量,我创建了一个只服务于重要房东的端点。
然后,我编写了一个端点来侦听特定的房东,在更大的数据集中找到它,并返回一个只包含房东请求的数据的对象。
出于篇幅和表述的考虑,我已经截断了运行 node/express 服务器所需的代码量。如果你想看到完整的服务器代码,这里有 GitHub 库。
建立一个反应堆。JS 前端
小楼一座反应过来。JS frontend 是这个项目的自然发展。在被我的前两个 Drexel 合作伙伴启动后,我在过去几年里一直在学习并越来越擅长编写 React 应用程序。我知道这不是一个编程教程,所以我将描述和解释这个项目产生的屏幕。如果你对我的代码感兴趣,你可以点击查看。
为了可视化拥有实体的属性,我为 React 搜索了一个地图库,并选定了 react-map-gl 。这个库允许我使用 MapBox maps,这是一个由优步创建的高度可定制的地图界面。使用来自字体牛逼的记号笔,我开始在地图上绘制房产数据。
对于较大的自有实体,尤其是费城住房管理局(Philadelphia Housing Authority)来说,绘制单个房产的效果并不太好,该机构拥有约 4000 多处房产。我想我必须使用聚类算法来解决缓慢的标记渲染。幸运的是,MapBox 已经花时间为 react-map-gl 开发了这个。别人开发了一个库来使用这个带有 反应钩子的 。这两个库分别是 超级集群 和 用途-超级集群 。按照一个很棒的教程关于如何一起使用所有这些,我制作了如下所示的屏幕。

费城房东观察员
聚类使我能够将更多的信息打包到地图上的标记中。每一个标记都提供了关于该房产的信息,如街道地址、类别、共有人、登记日期、销售日期、销售价格、和建造年份。通过在地图上提供这些信息,用户可以了解附近发生了什么,以及如何最好地解决与特定所有实体相关的租户问题。
屏幕右侧的地主选择器就没那么让人印象深刻了。目前,我只显示拥有超过 50 个属性的所有实体。这主要是因为在浏览器中呈现冗长的列表需要很长时间,我正在积极寻找解决方案。
项目演进
我只是开始触及租户或租户维权者在费城房地产评估数据的不同表述中所能发现的皮毛。我一直在做一个列表,列出我和其他人认为可能有用或有趣的未来发展。
1.彩色涂层标记,显示何时建造的属性和描述每个时间段的关键。
2.更多特定于所有实体的统计数据,如平均房龄和平均销售年份。
3.交叉引用购买力平价数据。(工资保护程序)
4.交叉引用费城驱逐文件数据。
5.将这个项目打包成一种其他城市可以开始以适合他们的方式可视化他们的数据的方式。

诺亚科特 2019
结论
在技术世界里,人们开始或创建项目,这些项目起初看起来有用,但最终不再有用或多余。我希望费城地主检举人 不属于这两类。很快,包括家庭在内的大量人口将被合法驱逐出他们的家园,在大多数情况下,他们无处可去。避难所要么已满,要么已被新冠肺炎摧毁,这是不可接受的。每个人都应该有一个称之为家的安全地方,如果他们目前没有,他们需要得到一个,如果他们有,他们需要留在那里。租户比以往任何时候都更需要团结起来,形成或加入租户联盟,以建立租户权力,并提供社区驱逐防御。
如果你在费城,我强烈推荐你加入费城租户联盟。PTU 为费城的租户争取权益,包括提供驱逐辩护。如果你有需要,不要犹豫,向他们伸出援手!
在费城之外,有一个租户联盟网络被恰当地称为 自治租户联盟网络 。他们能够给你指出正确的方向,并且有一个他们与租户联盟合作的城市列表。
对于任何对这个项目的编程方面更感兴趣的人,有适合这个项目范围的想法,或者如果你只是想聊聊,我的电子邮件是noah.cote3@gmail.com。
不然就看看我的 Github 在 Twitter 上关注我: @n_cote3。
三十年来冠状病毒研究的概况
语义之旅
2 月 10 日, STAT+ 发表了一篇关于冠状病毒研究中波动的兴趣和资助的有趣文章。阅读这篇文章激励我进一步调查冠状病毒研究的状况,特别是为了了解截至 2019 年底的冠状病毒研究状况,就在新冠肺炎疫情在全球爆发之前。
在这篇文章中,我将分享我所做的一些初步探索,以获得该研究领域的概况,使用文本挖掘方法。
对于那些不熟悉文本挖掘的人来说,这个网站提供了这项技术的简单介绍。文本挖掘的目的是将非结构化的文本数据转化为有价值的信息。在这项调查中, VOS 浏览器应用程序使用的算法扫描了数千份摘要,并将常用术语(单词)放在二维地图上进行可视化,其中两个术语之间的距离表明了术语之间的相关程度。如果术语经常一起出现在同一摘要中,它们之间的距离会变小,最终,可能会看到术语簇。
这种技术是理解领域内话语的一种强有力的方法,因为词的聚类表明了该领域内讨论或研究的主题。这样,可以从数据中发现研究主题。如果没有这样的计算方法,很难(如果不是不可能的话)从现代研究产生的海量信息中获得一个结构。
构建冠状病毒研究术语图
使用从 1990 年 1 月 1 日到 2019 年 12 月 31 日的冠状病毒搜索词组合,从Lens.org下载的 11,224 篇文章的元数据首先用于在 VOS 浏览器中生成术语网络图。随后使用 OpenRefine 和 Gephi 进一步优化数据和网络。进行多次迭代,直到最终网络确定下来。
在图 1 的术语图中,已经生成了五个不同的集群;我认为这个模块级别对于早期的探索是合理的。同样有趣的是网络的结构,它揭示了与另一个相反的集群,在两侧之间有一个桥接集群。
可以根据各种参数设置节点(彩色圆圈)的大小。对于图 1 中的可视化,强调了最常用的术语,其中较大的节点表示该词出现的频率较高。只显示语料库(文章集合中的词的主体)中使用最频繁的术语的标签,以避免视觉过载。

图 1:1990-2019 年冠状病毒研究文章标题和摘要的术语共现图。在对重复的术语进行协调并对不同的模数和截止值进行实验后,450 个节点和 3036 条边被选定用于最终的可视化。节点的大小设置为术语出现的数量,节点越大,术语出现的频率越高。只有出现最少 20 次(即在至少 20 篇文章中)的单词被包括在分析中。使用二进制计数,基于摘要中是否存在术语,而不是摘要中出现的全部数量。数据:。
除了频率,我们还可以问网络中是否有特别重要的术语。引用计数通常被用来衡量研究工作的重要性。因此,可以假设来自高引用计数的文章的单词来自该领域其他研究人员认为重要的文章。

图 2:比较基于术语出现的术语图(A)和平均标准化引用(B)。数据:Lens.org。
在图 2 中,基于出现的术语图(左,A)和基于引用的术语图(右,B)之间的差异可以相互比较。请注意,当在引用图(B)中查看时,许多出现频率高的词(A)的大小显著减小,而以前在出现频率图(A)中不常见的新术语在引用图(B)中变得突出,如节点大小的变化所示。在描述下面的主题时,我们将更深入地研究这些不同术语图视图的使用,并揭示每个集群内的洞察力。
冠状病毒研究的主题
为了确定主题,我检查了每个集群中流行的术语,并做了一些额外的研究来扩展一些术语,以展示如何使用这种方法来产生见解。以我的经验,给一个话题贴标签并不是一门精确的科学,需要一些该领域的知识才有意义。在这个过程中,我依靠我在临床传染病和疫苗研究方面的背景来帮助我,尽管来自冠状病毒研究领域专家的输入将有助于使标记更加准确。
第一组:冠状病毒的分子和细胞生物学
图 3A 显示了组 1 中最常用的术语。这些术语中有许多涉及冠状病毒生物学的基础研究,如刺突蛋白、复制、机制、结构、基因组和 rna 。

图 3:基于术语出现(A)或平均标准化引用(B)可视化聚类 1 中最高排名的术语。数据:Lens.org。
一个有趣的术语, mhv 也可以在这组最频繁出现的术语中找到。什么是 mhv ?
在发现 SARS 冠状病毒之前,许多关于冠状病毒的研究都是使用小鼠肝炎病毒* (MHV)进行的,这是一种鼠冠状病毒,根据其嗜性,它可以感染呼吸道、胃肠道或神经系统(见本文综述)。由于亲神经 MHV 菌株能够引发脱髓鞘,因此已将其用于建立多发性硬化症的小鼠模型。因此,MHV 模型是我们今天理解冠状病毒感染生物学的基础。鉴于最近发现 SARS-COV-2 病毒会引起嗅觉丧失(嗅觉丧失),重温一些关于 MHV 及其对中枢神经系统影响的旧文献可能是值得的。*
将视图改为平均标准化引用计数(图 3B),导致新术语如组织蛋白酶 L 和同步形成脱颖而出,表明这些术语存在于高被引文章中。
深入研究发现,组织蛋白酶 L 是一种重要的分子,因为它是 SARS 病毒利用其刺突蛋白激活其融合到宿主细胞中的宿主酶(见本文)。组织蛋白酶 L 的抑制剂已经被证明可以阻止 SARS 冠状病毒的进入(文章),尽管据我所知,这种治疗策略目前还没有被考虑用于新冠肺炎的治疗。
Synctium 的形成揭示了冠状病毒的一个特殊特征,如那些导致 SARS 和 MERS 的冠状病毒能够介导邻近的感染和未感染细胞之间的细胞融合,这种策略使病毒能够直接在细胞之间传播,并避免中和抗体(文章)。
第二组:冠状病毒爆发的公共卫生和临床研究
与第一组不同,这里倾向于将涉及临床和公共卫生研究的词聚集在一起(图 4A)。传播、实验室、监测和流行病学等词汇暗示了一种调查冠状病毒爆发的公共卫生方法。其他术语如肺炎、发烧、症状和疾病建议采用临床方法。到目前为止,许多人已经熟悉了术语 mers ,它代表中东呼吸综合征,这是最近在人类中爆发的冠状病毒。

图 4:基于术语出现(A)或平均标准化引用(B)可视化聚类 2 中最高排名的术语。数据:【Lens.org】。
为了找出这个集群中最重要的术语,使用了标准化引用视图(图 4B)。蝙蝠冠状病毒由于其与 SARS 和 MERS 冠状病毒的相似性以及随后的高度临床重要性,现在在这一群中表现突出。它与术语蝙蝠物种和自然宿主关系密切,这两个术语共同指向了解野生蝙蝠冠状病毒生态的研究。
另一个重要术语肾衰竭引发了进一步的调查。在 SARS 患者中,急性肾衰竭被发现是非常不利的结果,尽管相对不常见,为 6.7% ( 文章)。令人关注的是,根据两篇来自中国的预印文章(这篇文章和这篇文章,现在已经在新冠肺炎患者身上观察到了肾脏异常。这个例子强调了这样一个基于引用的术语图是如何将我们的注意力引向洞见的,否则这些洞见可能会迷失在信息的海洋中。
第 3 组:动物冠状病毒感染
这个有趣的集群位于基础科学和临床研究集群之间,连接着两个群体(图 1)。仔细观察,这一分组丰富了关于动物冠状病毒疾病的术语,如牛冠状病毒和猫冠状病毒以及 tgev ,这是一种感染猪的冠状病毒(图 5A)。 ibv 是指传染性支气管炎病毒,一种在鸡群中高度传染性的冠状病毒疾病。在当前视图中不可见,但在较低算法阈值下存在于该集群中的其他术语,如马冠状病毒和犬冠状病毒,揭示了冠状病毒适应的动物宿主的惊人多样性。这也给公众带来了一个鲜为人知的事实,即所有冠状病毒都源于动物,最终适应人类并导致疾病。

图 5:基于术语出现(A)或平均标准化引用(B)可视化聚类 3 中最高排名的术语。资料:Lens.org。
诸如 pcr 和样本等高度流行的词反映了用于识别和表征这些病毒的方法,但由于其无处不在的特性,可能不一定是该群的特定特征。这可以在标准化引用视图(图 5B)中看到,其中这些术语的大小大大减少。
在这种观点中,术语 pedv 感染和猪 delta cov 脱颖而出。在 2013 年第一次爆发期间,这些冠状病毒在新生小猪中导致严重疾病,导致高死亡率和农民的重大经济损失,估计达 10 亿美元(文章)。
第 4 组:病毒性呼吸道感染
描述其他呼吸道病毒如流感、腺病毒、 rsv 和鼻病毒的术语群表明冠状病毒也在病毒性呼吸道感染的背景下进行研究(图 6A)。常见和非特定术语,如年和月建议描述这些感染的时间。不太常见的术语如 nl63 、 hku1 和 oc43 原来是人类的冠状病毒感染,通常导致上呼吸道感染,表现为普通感冒。有趣的是,HKU1 冠状病毒来源于受感染的小鼠,而 OC43 被认为是从牛身上转移到人类身上的。

图 6:基于术语出现(A)或平均标准化引用(B)可视化聚类 4 中最高排名的术语。资料:Lens.org。
在图 6B 中,标准化引用视图允许我们观察到诸如临床数据、鼻咽抽吸物、病毒原因和优势比等术语变得突出。这表明,在这个集群的研究围绕临床研究,以确定和监测呼吸道病毒感染。
聚类 5:小鼠模型中的免疫反应和病毒发病机理
这个小星团,看起来像是星团 1 的分支,通过更仔细的研究揭示了许多洞见。鼠标是一个主要术语,这表明鼠标模型是这个主题的核心。在小鼠模型中,似乎要研究各种角度,例如以诸如 ifn (干扰素) t 细胞、巨噬细胞、表位、亚单位疫苗和促炎细胞因子为特征的免疫反应,以及通过肺病理学和中枢神经系统所看到的其后果(图 7A)。受体结合域暗示了与冠状病毒进入研究相关的另一个方向,当我们使用图 7B 中的标准化引用视图查找高引用文章中出现的术语时,这一点变得更加明显。

图 7:基于术语出现(A)或平均标准化引用(B)可视化聚类 5 中最高排名的术语。资料:【Lens.org】。****
在图 7B 中,词语 mers cov spike 、二肽基肽酶、 dpp4 和 hdpp4 变得更加突出,表明这些术语已在被多次引用的论文中使用。 dpp4 ,又称二肽基肽酶 4,是一种人类蛋白质,被发现是 MERS 冠状病毒刺突蛋白用来感染宿主细胞的受体(文章)。将这些点连接起来,我们可以拼凑出或许 mers cov spike 与其受体 dpp4 结合,正在小鼠模型的背景下进行研究。事实上,这一点已被描述表达人类 dpp4 基因的转基因小鼠的发展的研究所证实,该转基因小鼠完全允许 MERS 冠状病毒感染(文章)。术语 hdpp4 (人 dpp4)的出现,现在可以用小鼠 dpp4 不能很好地结合 mers cov spike 蛋白的事实来解释,这就需要开发一种表达人类版本 dpp4 基因的小鼠品系。
术语什么时候最常用?
作为最后的探索,我想获得一个场随时间演变的潜在动力的概念。为了探索这一点,修改了图 1 中基于出现次数的术语映射,其中节点根据平均使用年份进行着色(图 8)。

图 8:根据平均年份可视化研究文章中的术语频率。红色=最新,蓝色=最早。数据:。**
视觉为我们提供了这些术语最流行时的快照。看这张图,在颜色上似乎有一个总的渐变,最新的术语用红色表示,而最老的术语用蓝色表示。我们可以看到,网络左侧和中间的基础科学和动物研究聚类中的大多数术语都用蓝色阴影表示,而网络右侧的临床聚类中的术语则用红色表示。
这表明该领域最近的许多研究都倾向于临床研究,而不是基础科学和动物冠状病毒研究。
虽然不在本文的范围之内,但是追踪近年来流行的术语(例如红色的)可能是值得做的,并且可能揭示新兴的研究领域。
最后的想法
术语“图谱探索”揭示了过去三十年冠状病毒研究领域的结构。我们了解到冠状病毒研究大致分为三个主要领域:基础科学研究、临床/公共卫生研究和动物冠状病毒研究。还观察到基础科学和临床研究中的细分,例如专注于小鼠模型和病毒性呼吸道感染的细分。使用基于出现或引用的不同观点揭示了不同术语的重要性,这取决于它们的常用程度,如小鼠,或它们的重要性,如蝙蝠冠状病毒。
数据还表明,在过去的几年里,临床和公共卫生研究比基础科学更受关注。同样,除了猪δ冠状病毒和猪流行性腹泻病毒最近死灰复燃之外,动物冠状病毒研究的近期活动似乎较少。这种印象可以使用引文分析进行跟踪,引文分析可以更清楚地揭示该领域的发展。
这些初步发现指出了未来几年在基础科学和动物健康研究领域可以填补的知识空白。鉴于动物冠状病毒在自然界中无处不在,并且由于生态破坏以及可能由于密集的动物养殖,从动物到人类的跳跃总是有可能的,这可能是特别重要的。这将是一个有趣的调查线索。
此外,考虑到我们对新疫苗的迫切需求,我注意到与该领域的疫苗和免疫学研究相关的术语很少。这是一个简单的印象还是一个真实的事实,需要通过进一步的分析来确定,因为它可能对新冠状病毒疫苗的实际开发速度产生影响。
术语图谱分析使研究领域的结构能够以“自下而上”的方式从数据中展现出来。尽管这种方法很强大,但它也有局限性。
首先,构建当前地图依赖于 VOS 浏览器应用程序中产生的算法,其中用于计算术语之间的链接的固定标准已经在程序中制定。为了更深入地探索术语之间的联系,将需要进一步试验替代的链接计算,这些计算可能揭示本术语图分析中不存在的关系。
其次,本文中提出的见解只是可从地图中获得的潜在信息的一小部分,因此不能被视为该领域的完整描述。地图的显示依赖于各种分界点和参数,这意味着数据可以以不同的方式切片和切块,以揭示新的见解。这既是新发现的机会,也是主观解释的可能来源。
考虑到这一点,重要的是要认识到,这种方法并不意味着替代对该主题的深入研究,而是作为一种在相对较短的时间内“增加智力”的方式。将这种方法与阅读斯坦利·帕尔曼等顶尖专家的深度评论结合起来,是我快速了解该领域的方法。
在疫情的掌控下,许多研究都集中在新疫苗和治疗方法的研发上。然而,为了在短时间内设计出这些解决方案,我们需要建立一个知识体系,避免重复发明轮子。如果使用得当,来自数据科学和人工智能的新工具可以帮助我们构建信息,并将我们的资源导向最重要的地方。将更多的这些见解带到前沿将是我随后关于这个主题的探索的重点。
鸣谢:感谢 MA3X 对数据处理的协助。
卫星图像滑坡尺度预测
滑坡是一种自然灾害,被定义为斜坡上的大量岩石、碎片或泥土。滑坡是指土壤和岩石在重力的直接影响下向下倾斜的运动。术语“滑坡”包括五种斜坡运动模式:跌落、倾倒、滑动、蔓延和流动1[3]。

图一。菲律宾的一个城镇遭到山体滑坡袭击——图片来自皮克斯拜的大卫·马克

近年来,卫星技术和遥感技术发展迅速。应用卫星遥感捕捉地球的数量和图像质量正在迅速提高。它在地球表面监测中发挥着重要作用。

图 3。卫星图像中的滑坡区域—图像来源于[4]
我们的主要目标是理解和实现从卫星图像检测滑坡的方法。根据在不同时间检测到的滑坡区域,给出了滑坡标度(滑坡正在发展或减少)。本文是我题为“卫星架构中滑坡识别的深度学习”的公开论文的解释版本如何做的细节和实现我的论文的第二部分介绍。此外,我还分享了我的出版物的分步源代码。我希望我能把一个从研究论文到现实世界实施的解决方案。本着这个目的,如果你打算发表一篇研究论文,请分享我的文章或参考我的出版物。
T.A. Bui,P. J. Lee,K. Y. Lum,C. Loh 和 K. Tan,“卫星体系结构中滑坡识别的深度学习”, IEEE Access ,第 8 卷,第 143665–143678 页,2020 年,doi:10.1109/Access . 200205。2006.868636060003

图 4。卫星架构中用于滑坡识别的深度学习—图形摘要[4]
图 4 示出了通过引入 CNN 模型和 H-BEMD 算法之间的组合的滑坡检测的简短过程。从不同时间(2013 年 9 月 15 日和 2014 年 9 月 18 日)捕获的卫星图像,我们可以宣布滑坡发生了更显著的变化,并且易于检测滑坡规模(滑坡方向)。
1。基于 H-BEMD 的滑坡区域检测
色调——二维经验模式分解(H-BEMD)是文献[4]中介绍的一种算法。
1.1。为什么在卫星图像中使用色调通道来检测物体?
HSV 将亮度从色度中分离出来,也称为图像强度。卫星图像受天气影响,尤其是每次拍摄的光照条件不同。图 5 显示了同一地点在其他光照条件下的 RGB 卫星图像。

图 5。RGB、直方图和色调通道[4]
虽然三个图像(a、d、g)之间的直方图值不同,但是色调通道是相同的。因此,选择色调图像通道来检测卫星图像中的滑坡目标。
要将 RGB 图像转换为色调通道图像,OpenCV 是一个很好的简单方法。基本上,OpenCV 以 8 位/值(np.uint8 —从 0 到 255)改变 RGB 到 HSV 通道。但是,色调值由一个圆圈表示(从 0 度到 360 度)。因此,下面的代码显示了将 RGB 转换为 HSV 的方法,并给出了完整的取值范围。在这种情况下,无符号整数 16 位应用于全色调值。
用全值把 RGB 换成 HSV。
1.2。 H-BEMD 流程图及源代码
在这一部分,我将介绍详细的 H-BEMD 算法。首先,图 6 显示了如何通过 H-BEMD 获得变换图像的过程。

图 6。H-BEMD 流程图[4]
什么是 H-BEMD?
H-BEMD 是 BEMD 算法的改进版本。原始 BEMD [5]应用于来自 RGB 的灰色图像,其具有从 0 到 255 的值范围(以 8 位/值计)。然而,为了应用于色调通道,BEMD 没有得到校正的结果(滑坡区域),因为 BEMD 的主要重要关键点是检测图像信号的极值。因此,色调的正弦和余弦值应用于色调值。然后,检测正弦和余弦的极值。最后,使用反正切 2 合并正弦和余弦极值。它是色调通道的极值。
BEMD 源代码
接下来,我将详细介绍 H-BEMD 如何获得 imfs_cos_hue 和 imf_sin_hue 。
BEMD 的细节是什么?
sin(色调)和 cos(色调)值分别用θ和φ表示。H-BEMD 通过 H-BEMD 筛选过程自适应分解色调图像的正弦和余弦(θ和φ),流程如下:
- 第一步:通过形态学算法检测θ的极值(最大值和最小值)点。
- 步骤 2: 用径向基函数(RBF)[23]分别连接θ的最大值和最小值点,以生成新的 2D 包络
- 步骤 3: 如第 2.2.2 节所示,将 2D‘包络线’标准化。
- 步骤 3: 通过对两个包络求平均值来确定局部均值 mθ。
- 第四步:从图像中减去均值:ϑi=θ−mθ;
- 步骤 5: 对φ,ωI =φmφ,遵循步骤 1 至 4
- 步骤 6: 用θ=ϑi 和φ=ωi 重复筛选过程,i:=i+1
BEMD 源代码
图 7 是上述源代码的结果。

图 7。通过 H-BEMD 检测滑坡区域[4]
2。滑坡区域分割
首先,我们集中于色调通道的简短回顾。图 8 显示了色调值的架构。

图 8。色调通道[4]
本文介绍用 330° ~ 90°的数值范围来定义滑坡区。python 代码定义滑坡的细节是:
3。滑坡大小和方向检测
在不同时间拍摄的两幅卫星图像用于显示本节中的测试流程图。

图 9。从卫星图像滑坡物体。(a)2013 年 9 月 15 日拍摄到的尼泊尔 Jure 滑坡——t1 时间。(b)2014 年 9 月 18 日拍摄的尼泊尔 Jure 滑坡——时间 t2 [4]
图 10 是图 9 的 H-BEMD 结果。

图 10。H-BEMD 结果[4]

图 11。图 10 的滑坡标记[4]

图 12。滑坡区域位置。[4]
从图 12 中,定义了每个滑坡区域的质心点。图 13 和下面的源代码详细显示了质心点以及如何在 python 代码中获得质心点。
源代码:质心点和滑坡缩放方向

图 13。滑坡区域的质心。[4]
滑坡缩放的方向由绿点和红点定义。下面是详细的源代码。图 14 显示了源代码的结果。
滑坡方向

图 14。滑坡方向[4]
根据滑坡方向,我们可以很容易地确定什么区域是危险的,容易受到其影响。由此可以准确预测生活在受影响地区的人们。
我希望这篇文章能对你有所帮助,并对卫星数据在生活中的应用做一个简要的介绍。
参考资料:
【1】https://www . USGS . gov/FAQs/what-a-slide-and-what-causes-one
【2】https://www.taiwannews.com.tw/en/news/1238060
【3】https://vov . VN/en/society/massive-slides-bury-residents-and-houses-in-lai-chau-377950 . vov
【4】t . a . Bui,p
【5】j . c . nu nes,Y. Bouaoune,E. Delechelle,O. Niang 和 P. Bunel,“二维经验模式分解的图像分析”,图像 Vis。计算机。,第 21 卷,第 12 期,第 1019-1026 页,2003 年 11 月。
车道变换检测——下一阶段的计算机视觉
OpenCV 和图像处理领域的领先创新

计算机视觉(图片由来自 Pixabay 的奥莰·卡里斯坎提供)
嘿,伙计们,兴奋起来吧,因为在本教程中,我们将了解如何使用计算机视觉和图像处理来检测汽车是否在道路上变道,所以不再拖延,让我们开始-
你一定听说过使用 OpenCV haar cascade 文件检测人脸、眼睛或汽车、公共汽车等物体。可以做到,但接下来呢?所以让我们用这个简单的检测方法来建立一些很酷的东西。
1.资料组
在本教程中,道路上汽车的视频文件被用作数据集。此外,我们可以使用图像数据集检测图像中的汽车,但在这里,当汽车改变车道时,我们会通过弹出窗口发出警告,因此对于这些动态,视频输入更可行。
2.投入
第一步是给出教程中使用的输入 OpenCV 的 haar 级联文件,用于检测汽车的坐标,道路上汽车的视频文件
接受输入
cv2。VideoCapture()方法用于捕捉输入的视频,一段视频一般为每秒 25 幅图像/帧(fps)。在捕获输入后,使用循环提取帧,并使用汽车的 haar 级联文件检测到的坐标,我们在循环中围绕汽车绘制一个矩形,以在对捕获的帧执行其他操作时获得一致性。
检测汽车
在 OpenCV 中使用 BGR 而不是 RGB,所以(0,0,255)将在汽车上绘制一个红色矩形,而不是蓝色。

框架(图片由作者提供)
3.图像处理
我们使用该帧,但是如果该帧具有非常高的分辨率,它将减慢所执行的操作,此外,该帧包括可以使用模糊来减少的噪声,这里使用高斯模糊。
现在,让我们来看看一些图像处理的概念
3.1 HSV 框架
在这里,我们使用从 cv2 捕获的帧中获得的 HSV 帧。VideoCapture()仅突出显示汽车转弯的点,并封锁其余道路&汽车在道路上直行。设置上限和下限阈值来定义 HSV 中的颜色范围,以查看汽车改变车道的点,并用作帧的遮罩。下面是用来获得这个的代码片段-
3.2 侵蚀和膨胀
腐蚀和膨胀是图像处理中使用的两种基本形态学操作。侵蚀算子在核的区域上具有局部最小值的效果,核是模板或遮罩。腐蚀用于减少图像中的散斑噪声,散斑是从图像中的物体边界被腐蚀掉的。膨胀是图像和内核的卷积,它具有局部最大值算子的效果。当添加像素以平滑图像中对象的边界时,应用膨胀来重新获得一些丢失的区域。
从 HSV 帧中的第一步生成的遮罩现在用基本的形态学操作(腐蚀和膨胀)来处理。通过将帧和遮罩之间的按位 AND 运算应用于获取 ROI(感兴趣区域)来生成结果帧。
3.3 车道检测
canny 边缘检测器与 Hough 线变换一起用于车道检测。

Canny 边缘检测(图片作者提供)
4.轮廓
canny edge detector 之类的算法用于查找分隔图像边缘的边缘像素,但它没有告诉如何查找对象或实体,因为我们无法组合/组装一些点和边缘,这里我们可以使用 OpenCV 中实现的轮廓概念,如 cv2.findContours()。
定义—“轮廓是代表图像中曲线的点的列表。”轮廓由序列表示(序列是一个链表结构),每个序列都编码了下一个点的位置信息。我们在 ROI 中多次运行 cv2.findContours()来获取实体,然后使用 cv2.drawContours()来绘制轮廓区域。轮廓可以是点、边、多边形等。所以在画等高线的时候,我们做多边形近似,找出一个区域的边长和面积。函数 cv2.drawContours()的工作原理是从根节点开始绘制一棵树(数据结构),然后连接后续的点、边界框和 freeman 链码。
找到轮廓后的另一个重要任务是匹配它们。匹配轮廓意味着我们有两个单独的计算轮廓来相互比较,或者有一个轮廓来与抽象模板比较。
5.朋友圈
我们可以通过计算轮廓矩来比较两个轮廓。"矩是轮廓的总特征,通过将轮廓的所有像素相加来计算."

(图片来自图书参考 1《学习 OpenCV》)
力矩类型-
空间矩: m00,m10,m01,m20,m11,m02,m30,m21,m12,m03。
中心矩: mu20,mu11,mu02,mu30,mu21,mu12,mu03。
胡矩:有七个胡矩(h0 — h6)或(h1 — h7),两个符号都用。
我们计算力矩并使用 cv2.fitEllipse()在点上拟合椭圆。该角度是从轮廓和力矩中找到的,因为改变车道需要 45 度旋转,这被认为是汽车转弯角度的阈值。

拟合椭圆(图片来自参考书籍 1“学习 OpenCV”)
现在,我们可以使用 Tkinter 作为一个简单的弹出窗口来提醒变化,而不仅仅是打印变化车道的检测。

(图片由作者提供)
用画在车架上的矩形用绿线测量角度

弹出警告(图片由作者提供)

输出(图片由作者提供)
6.总结和未来范围
在本教程中,使用车道变换检测方法探索了智能汽车导航的一个小演示。
计算机视觉正在快速发展,其应用不仅在汽车的局部导航方面,而且在火星导航和产品检测领域都在进步,甚至正在开发医疗应用,并用于在早期阶段检测 X 射线图像中的癌症和肿瘤。
万岁,你坚持到了最后。太棒了。点击这里获取我的 GitHub 账户的源代码。
请随意询问任何疑问,因为我们正在学习与机器一样的东西 Hitesh Valecha …
参考文献—
- Bradski,Gary 和 Kaehler,Adrian ,学习 OpenCV:使用 OpenCV 库在 C++中进行计算机视觉,O'Reilly Media,in C .第二版,2013 年,@10.5555/2523356,ISBN-1449314651。
- Laganiere,Robert,OpenCV 计算机视觉应用编程食谱,Packt 出版社,2014 年第 2 版,@10.5555/2692691,ISBN — 1782161481。
好吧,由于创新从未停止,我邀请您阅读另一篇关于 耳朵生物识别 的创新博客。
语言本地化:数据科学和 FIFA 20 的端到端项目
使用 Python 和 Plotly 可视化进行探索性数据分析和 Twitter 情感分析。

JESHOOTS.COM在 Unsplash 上拍照
“什么是语言本地化?”你可能会问。
L 语言本地化是将产品翻译适应特定国家或地区的过程。这是一个更大的产品翻译和文化适应过程(针对特定国家、地区、文化或群体)的第二阶段,以说明不同市场的差异,该过程称为国际化和本地化。如这里的所解释的:
本地化流程通常与软件、视频游戏和网站以及音频/画外音、视频或其他多媒体内容的文化适应和翻译相关,较少涉及任何书面翻译(也可能涉及文化适应流程)。本地化可以在人们讲不同语言或讲同一种语言的地区或国家进行。
所以在某个时候,我被提到了这个项目:想象一下 电子艺界(EA) 想知道什么是翻译未来版本的FIFA视频游戏的好语言。这个任务依次分配给你,数据科学家,你没有资源,只有一个 Kaggle 数据集,里面有游戏中所有玩家的属性。
在没有官方数据或任何先前研究的情况下,我们不得不利用玩家的数据集,或许收集我们自己的数据。但是没什么好害怕的,这是数据科学家在几乎每个新项目中必须处理的事情。
TL;在这个过程中,我们使用了游戏中玩家的属性和技能的完整数据集。这个数据集包含一个名为国际声誉(IR) 的属性,它告诉我们一个球员在国际上的知名度。我们得出的结论是基于这样一个假设,即大量相同国籍、高 IR 的玩家可能会影响游戏在他们国家的可玩性。
除此之外,我们收集并使用了一系列提到游戏的 Twitter 消息。通过计算推文文本的情绪得分,我们可以区分人们对游戏的评价更积极的地方。这当然可以为游戏的本地化提供更好的见解。
为了可读性,这个故事没有代码。使用的完整 python 源代码和结果可以在下面的资源库中找到:【https://github.com/hectoramirez/Language-localization_FIFA】
国际足联 20 种语言
我们从学习已经包含在 FIFA 20 中的语言开始。根据官方网站的消息, FIFA 20 目前有以下 21 语言版本,并提供了特定地区的解说:
阿拉伯语、捷克语、丹麦语、德语(德国)、英语(美国)、西班牙语(西班牙)、西班牙语(墨西哥)、法语(法国)、意大利语、日语、韩语、荷兰语、挪威语、波兰语、葡萄牙语(巴西)、葡萄牙语(葡萄牙)、俄语、瑞典语、土耳其语、中文(简体)、中文(繁体)。
虽然这只是全球语言和玩家语言的一小部分,但我们可以肯定的是,由于这些语言的流行,大多数国家都包括在内。为了看到这一点,我通过连接来自这个公共存储库的数据构建了一个数据框架。头部看起来像这样:
然后,我过滤了游戏中包含的语言,并在地图中定位了相关的国家(在这里和所有地方,我使用了 Plotly Express 来表示地图):
在地图中,只有一种语言与每个国家相关联,但是我们对那些没有语言的国家感兴趣。
我们可以看到,除了巴尔干地区、东南亚和几个其他国家,世界大部分地区都被覆盖了。因此,我们想调查一下那些被遗漏的国家,也许还想调查一下那些已经被调查过的国家所使用的第二种(或地区性)语言。
国际足联 20 名球员数据集
FIFA 20 球员数据集可以从这个 Kaggle 库中获得。如描述所述,数据集由 103 列和 18278 个条目组成,包含:
- 100 多个属性。
- 擦伤玩家的网址。
- 球员位置,在俱乐部和国家队中的角色。
- 球员属性,包括进攻、技术、防守、心态、GK 技能等。
- 球员个人资料,如国籍、俱乐部、出生日期、工资、薪水等。
可以从此数据集执行多种分析。然而,出于本分析的目的,我们可能只需要一名球员的国籍和俱乐部。让我们也保留简称以供识别,以及整体和国际声誉分数,因为它们肯定能提供一些见解。数据框的头部看起来像:
现在,这个分析中的一个关键思想是一个球员越受欢迎,他对于一个国家就越有代表性。换句话说,一个拥有更多优秀球员的国家会影响游戏的可玩性。以克罗地亚为例,在上一届世界杯上,他们以一队公认的球员名列第二;这一事实会影响整个国家游戏的可玩性,也许克罗地亚语是我们正在寻找的一种语言。
一个拥有更多优秀球员的国家会影响游戏的可玩性
我们有国际声誉领域来衡量这种影响。然而,首先我们需要向数据中添加一个语言字段。为此,我们使用国家/语言数据框架将语言与玩家的国籍联系起来。
然后,我们可以查看 countplot ,看看每种语言有多少玩家。请记住,我们对拥有更多国际声誉(IR)的玩家的语言感兴趣。以下是 IR 提供的全套语言:

顶级语言
请注意,IR 是一个可以取 1 到 5 的离散值的属性。现在,问题是大部分这些语言已经包含在游戏中了。仅保留未包含的语言:

国际足联尚未纳入的顶级语言
请记住,我们把一个国家的所有语言与这个国家联系起来。因此,考虑到一个国家使用多种语言,一些价值观是重复的。
为了过滤掉一些语言,我们注意到以下关于顶级国家的事实:
- 首先,我们假设所有的西班牙球员都会说巴斯克语、加泰罗尼亚语和加利西亚语,这显然不是真的(很多国家都是如此)。事实上,西班牙 19%的人说加泰罗尼亚语(或巴伦西亚语),5%的人说加利西亚语,2%的人说巴斯克语。[ 参考。 ]
- 法国南部、摩纳哥、意大利的奥克西坦山谷以及西班牙的瓦勒达兰地区使用奥克西坦语,共有 10 万到 80 万人使用这种语言。参考文献。 ]
- 瓜拉尼语是南美洲的一种土著语言。它是巴拉圭的官方语言之一,大多数人口都讲这种语言。邻国的社区也说这种语言,包括阿根廷东北部、玻利维亚东南部和巴西西南部的部分地区,它是阿根廷科连特斯省的第二官方语言。尽管它有 485 万(引用于 1995 年)的母语使用者。【参。 ]
- 挪威语是挪威语的两种书面标准之一。【参。 ]
- 尽管英语在爱尔兰的其他地方是更普遍的第一语言,但爱尔兰语在很多地区被作为第一语言使用。爱尔兰语在爱尔兰共和国的官方地位仍然很高,2016 年 4 月,回答会说爱尔兰语的总人数为 1,761,420 人,占爱尔兰共和国 4,921,500 人口(2019 年估计数)的 39.8%。在北爱尔兰,1,882,000 人口中有 104,943 人被认定会说爱尔兰语(2018 年估计)。【参考。 ]
考虑到这些事实,我们将采取以下考虑因素:
- 对于说加泰罗尼亚语的人,我们只会让西班牙球员继续在巴塞罗那踢球,主要是因为他们的政策是教他们的球员加泰罗尼亚语。参考文献。 ]
- 对于说瓜拉尼语的球员,我们将只保留巴拉圭球员,因为这种语言在其他国家的大多数人口中都是一样的。
- 我们保留所有说爱尔兰语的人。
- 我们放弃巴斯克语、加利西亚语、奥克西坦语和尼诺斯克语。
- 并保留其他使用人数较少的语言。
这给我们留下了一批拥有不同国籍和语言的球员,我们现在想按照国际声誉对他们进行分类。
国际声誉
我们现在想对玩家的语言进行分析。
国际声誉,也称为国际认可,是根据球员所在俱乐部在当地和国际上的声望来影响球员评级的属性。它本质上是基于两者的受欢迎程度、历史和结果。基本上,IR 的建立是为了调整球员的评分,相对于所有与他的技术、身体和精神能力无关的事情。它被人为地收敛,以至于在全球拥有最多粉丝的球员总是获得最高的收视率,但实际上并没有真正的效果。参考文献。 ]
通过对每种语言的 IR 进行平均,我们最终得出了游戏中尚未包含的语言之间的关系,这些语言是根据玩家的平均国际声誉排序的。看一看:
顶级玩家的语言按 IR 排序
这里我们做了几处改动。首先,为了避免偏见,我们放弃了少于 15 个玩家的语言。我们还对 IR 分数进行了标准化,现在范围在[0,1]之间。最后,我们为每种语言附加了最具代表性的国家和国家代码(这是为了绘图)。
因此,我们最终得出了一个视频游戏中尚未包含的语言的关系,这些语言是根据玩家的平均 IR 排序的。看了一下可以得出结论,加泰罗尼亚语、斯洛文尼亚语、克罗地亚语、波斯尼亚语和匈牙利语是最突出的语言。
让我们最终在地图上定位这些语言:
请注意巴尔干国家是最突出的语言本地化给玩家的 IR。
社交媒体分析
在第二部分中,我们进行了社交媒体分析,以了解人们对游戏的评价,特别是在 Twitter 上。
Twitter 允许使用 tweepy 来收集推文,tweepy 是一个用于访问 Twitter API 的 Python 库。我不打算给出如何收集推文的教程;然而,遵循文档是非常简单的。你也可以看看我的剧本,但是记住你需要用你自己的凭据。
每个 tweet 对象 以 JSON 格式出现,混合了“根级”属性和子对象(用 *{}* 符号表示)。Twitter 开发者页面给出了以下例子:
{
"created_at": "Wed Oct 10 20:19:24 +0000 2018",
"id": 1050118621198921728,
"id_str": "1050118621198921728",
"text": "To make room for more expression, we will now count all emojis as equal—including those with gender and skin t… https://t.co/MkGjXf9aXm",
"user": {},
"entities": {}
}
当然,这只是组成每条推文的庞大字典中的一小部分。
很明显,出于我们的目的,我们只需要这些属性中的几个:文本、文本语言和 tweet 位置。不幸的是,这些属性并没有一个清晰的格式,相反,它们分布在 JSON 的各个层次上——例如,tweet 位置坐标位于
tweet_object['place']['bounding_box']['coordinates']
正是由于这一事实,收集的推文需要一个大的清洗和转换过程。事实上,我写了一个单独的故事来解释字典变平的过程;选择、清洗、翻译和计算文本的情感;清理文本语言字段;并使用位置字段或用户位置字段分配 tweet 的适当位置。你可以在这里找到这个故事:
使用 python 库清理和润色用于社交媒体分析的推文数据帧。
towardsdatascience.com](/twitter-json-data-processing-3f353a5deac4)
一旦我们有了处理过的 tweets 数据框架,我们就准备继续我们的研究。请注意,Twitter 不允许公开 tweet 数据,因此我不会发布任何数据帧的示例,而只是一行快照来显示字段(我们将在全文中解释):

我在几天的时间里收集了 52830 条类似图片中的推文,包含以下关键词: '#FIFA20' ,' #FIFA21' , 'FIFA20' , 'FIFA21' , 'FIFA 20' , 'FIFA 21' 和'如前所述,所有这些推文都根据我们的需求进行了相应的处理。因此,最终数据集带有关于推文位置(国家和坐标)、文本英文版本的情感(在[-1,1]范围内变化)以及文本被推文使用的语言的相关数据,但是请记住,这种语言是“检测到的”,因此可能会被错误地分配,正如我们将看到的那样。
在下文中,我们将遵循四条路径:
- 我们将研究带有准确位置(带坐标)的推文,因为它们是关于其位置的最可靠的推文。
- 然后,我们通过推特上写的语言来研究推特。
- 然后,通过手动设置用户位置。
- 最后,我们根据国际声誉(在上一节中获得)回到最著名的语言,并研究来自使用这些语言的国家的推文的情绪。
带坐标的推文(确切位置)
不幸的是,世界上只有大约 1%的推文带有精确的地理位置,主要是因为用户必须启用这个选项。
在我们的 52830 条推文中,只有 485 条推文提供了坐标级别的位置。
通过过滤这些推文,我们可以按语言对它们进行分组,并计算它们的平均情绪。这是我们的发现:
推文的语言(有确切的位置)按平均情绪排序
查看数据框架,我们可以清楚地看到,除了他加禄语/菲律宾语、印尼语和捷克语之外的所有语言都已经包含在游戏中。然而,这些数字和情绪并不能真正说明问题。因此,我们可以得出结论,这个 tweet 样本没有提供足够的洞察力,因此我们需要研究其他 tweet 属性。
按推特语言分类的推特
让我们转到语言领域。这个字段取自 Twitter JSON 中的lang属性,并将其更改为语言标准名称。如文档中所述:
如果存在,则指示与机器检测到的 Tweet 文本语言相对应的 BCP 47 语言标识符,如果没有检测到语言,则指示
und。
因此,我们按这一列对数据集进行分组,并按语言计算平均情绪。此外,为了分析这些语言的本地化,我们根据这些语言在哪里被最频繁地使用来给它们分配一个国家。以下是我们的发现:
Tweets 检测到的语言和位置按平均情绪排序
我们来看一些异常情况:海地语多在加纳使用;立陶宛语、爱沙尼亚语和他加禄语/菲律宾语,在巴西;还有斯洛文尼亚人在津巴布韦!这实际上只意味着语言检测器不能正常工作。
这些异常很难是异常值,因此我们可以得出结论,Twitter lang属性对于我们的分析来说不够可靠,因此我们需要相信手动设置的用户位置字段。
按用户位置分类的推文
如前所述,Twitter JSON 中的用户位置字段是用户用原始文本填充的字段。这意味着该字段可能会也可能不会给出实际位置,如果是这样,它可能是一个城市、州或省,而不是一个国家。
为了解决这个问题,在清理这个字段的过程中,我们使用 GeoPy 来识别一个位置(可能是一个地址)并为其分配一个国家。因此,在数据集中,location字段提供 GeoPy 的“检测到的”国家。然而,非空值的样本大约是整个数据集的一半,这意味着要么用户没有提供位置,要么提供的文本不包含实际位置。
我们根据位置对集合进行分组,并再次计算平均情绪。由于我们实际上对语言感兴趣,我们添加了这些国家的语言,然后我们按照上一节的步骤删除游戏中已经包含的国家和其他国家(巴斯克,加利西亚,欧西坦等)。).为了避免偏见,我们还删除了少于 20 条推文的条目(count)。以下是我们的发现:
按平均情绪排序的推文语言和用户位置
这个数据集显然比以前的案例提供了更多的信息!
在顶级语言中,我们可以突出保加利亚、希伯来、印地语和爱尔兰语。新西兰的毛利人和玻利维亚的艾马拉人可能不太有趣,因为他们是土著居民。还要注意,除了希腊和捷克共和国,所有国家都有积极的平均情绪。
让我们最终在地图上定位这些语言:
我们获得了人们对这款游戏持积极态度的顶级国家。然而,这些国家使用的语言与分析球员国际声誉时使用的语言不同。鉴于这一事实,让我们看看这些语言在最后一节中是如何在 tweets 集合中得分的。
国际声誉对顶级语言的感悟
在上一节中,我们通过玩家的国际声誉获得了顶级语言。为了完成分析,我们想知道这些语言的情感,并看看是否有一种语言在其他语言中既有 IR 又有情感。
然后,我们将“按 IR 排序的顶级玩家语言”数据集与“按平均情绪排序的推文语言和用户位置”数据集合并,以获得:
IR 和情感排名靠前的语言,按情感排序
上面的数据框架是按情感分类的,第一列代表了各种语言在国际上的声誉。这允许对两种情况进行简单快速的比较。
也许最好的例子是希伯来语的,它以高于平均水平的情感分数排名第二,IR 排名第十。然后乌克兰。另一方面,加泰罗尼亚此前拥有迄今为止最好的 IR,但它在人气方面表现不佳,尽管我们要记住这个分数涉及整个西班牙,而不仅仅是加泰罗尼亚。
让我们最后来看看地图上的这些语言:
结论
在这个项目中,我们旨在对 FIFA 视频游戏的语言本地化提出见解。
我们首先展示了国际足联游戏中使用一种或多种语言的国家。我们注意到巴尔干国家和东南亚没有被当前可用的语言覆盖。
然后在第一部分,我们本地化了游戏中没有的语言,并通过使用该语言的玩家的国际声誉(IR)来突出显示它们。这说明像加泰罗尼亚语、斯洛文尼亚语、克罗地亚语、波斯尼亚语或匈牙利语这样的语言是由知名玩家使用的,这可能会影响游戏在这些国家/地区的可玩性。
关于社交媒体分析,世界上只有一小部分推文(几乎 1%)包含准确的地理位置。在我们的数据集中,他们总结了近 500 条推文。我们表明这个子集不够大,不足以得出结论。
然后,我们通过手动设置的用户位置处理推文,找到归属国家并关联该国家的主要语言。然后,我们在地图上定位这些语言,并根据情绪给它们着色。我们发现保加利亚语、希伯来语、印地语和爱尔兰语是这些国家的语言——不包括在游戏中——在这些国家,人们说话更积极。
最后,我们发现通过 IR 进行本地化的一些语言很突出,而通过情感进行本地化的另一些语言则很突出。在最后一部分,我们的目标是选择一种或多种同时具备这两种属性的语言。有趣的是,希伯来语以高于平均水平的情感分数排名第二,IR 排名第十,因此是最突出的目标语言。
接下来的步骤将涉及使用非公开的,或 EA 的官方数据,以做出更专业的决定。
关于作者
我最近获得了物理学博士学位,目前正在进入数据科学领域。非常感谢您对本项目的任何意见和/或建议。另外,看看我的其他故事:
** [## 您的实时新冠肺炎跟踪与气流和 GitHub 网页
加载数据,用散景制作出色的可视化效果,将它们放在 GitHub Pages 网站上,让气流自动流动…
towardsdatascience.com](/your-live-covid-19-tracker-with-airflow-and-github-pages-658c3e048304) [## Twitter JSON 数据处理
使用 python 库清理和润色用于社交媒体分析的推文数据帧。
towardsdatascience.com](/twitter-json-data-processing-3f353a5deac4)
最后,请随时在 LinkedIn 与我联系:
[## Héctor Ramírez -西班牙巴伦西亚地区|职业简介| LinkedIn
我最近获得了物理学博士学位,专攻实验数据分析和数学建模。我领导了…
www.linkedin.com](https://www.linkedin.com/in/harr/)**
语言模型,如声学数据的预训练

基于自监督表示学习的声学数据模型— wav2vec 1,Mockingjay [4],Audio ALBERT [5],vq-wav2vec [3],CPC[6]
密切关注自然语言处理(NLP)研究的人会知道,最近引入的语言模型,如伯特[7],GPT,正在从根本上改变 NLP 领域。在自然语言处理中,无监督的语言模型预训练改善了许多任务,如文本分类、语义文本相似性、机器翻译。你有没有想过,除了自由文本,这些无监督的语言模型预训练如何帮助序列时间序列数据?
最近,我得到了一个处理声学数据的机会,我们必须根据记录的声音数据来识别机器的运行组件,比如电机或压缩机。由于没有用于尝试监督学习的标记数据,我不得不寻找替代方法。令我惊讶的是,我遇到了很多使用无监督语言模型(如预训练)即兴完成语音识别任务的研究工作。
如果你想对声学时间序列数据使用无监督语言模型预训练的能力,那么这篇文章就是为你准备的。
语言模型预训练
迁移学习现在相当流行,一个为一个任务训练的模型被重新用于另一个目标任务。在计算机视觉(CV)中,迁移学习广泛存在;例如,为了获得可靠的性能,通常会针对目标任务微调在 ImageNet 数据集上预先训练的模型。但这里的问题是,很难找到像 ImageNet 这样的 NLP 或声学时间序列数据的大规模标记数据集。
为了利用维基百科这样的在线免费文本数据,人们开始使用语言模型预训练。在传统的语言模型设置中,我们的目标通常是使用前面的上下文单词来预测序列中的 nᵗʰ单词。

伯特蒙面 LM 的描绘—作者照片
在当今时代,一个著名的语言模型预训练任务是伯特的蒙面 LM (MLM) [7]。在 MLM,目标是恢复句子中的屏蔽词。上面提到的图描述了 MLM,其中 BERT 试图根据上下文预测屏蔽的输入单词。从根本上说,在语言建模中,我们试图计算单词序列的联合概率分布。
语言模型预训练允许我们获得有用的基于上下文的单词嵌入,然后我们可以在任何目标任务中使用它。词语嵌入是一种表征方式,它能让意义相似的词语有相似的表征。更正式地,语言模型预训练将属于无监督/自监督表示学习。
wav2vec
像预训练这样的语言模型开始在声学任务中显示出一些有希望的结果,如语音识别、音频分割或通过利用未标记的音频数据进行异常检测。wav2vec 1,Audio ALBERT [5],wav2vec 2.0 2,Mockingjay [4],vq-wav2vec [3]是其中值得注意的一些。未标记的音频数据比标记的数据更容易访问。
在本文中,我们将简要地研究脸书的 wav2vec 模型。wav2vec 模型的预训练任务是从给定的信号上下文中预测未来的样本1。这项任务的目的基本上是训练模型,这些模型理解波形并生成有意义的声音嵌入。理想情况下,听起来相似的音频片段在这些模型生成的嵌入中具有相似的表示。

音频数据“X”的 wav2vec 预训练图1
wav2vec 架构由两个多层卷积神经网络叠加而成,如上图所示。编码器网络将原始音频输入‘X’映射到表示‘Z’,其中每个向量覆盖大约 30 毫秒的音频。上下文网络使用那些‘Z’向量来生成其表示‘C’,其覆盖了高达一秒的更大跨度【1】。有关 wav2vec 的更多信息,请访问此链接。
继 wav2vec 之后,脸书最近发布了 vq-wav2vec [3]和 wav2vec 2.0 2。wav2vec 2.0 模型的预训练任务与伯特的 MLM 非常相似2。
培训定制 wav2vec 模型
要基于您的未标记音频数据集训练您自己的定制 wav2vec 模型,我想推荐脸书 AI Research 的序列建模工具包,名为fair seq。Fairseq 提供 CLI 工具来快速训练您自己的 wav2vec 系列模型。Fairseq 有 wav2vec,vq-wav2vec,wav2vec 2.0 的示例实现。有关 wav2vec 系列型号的 fairseq 的更多信息,请访问此链接。
对于其他模型架构,如 Mockingjay、Audio ALBERT 等。,我想提一下即将推出的名为自我监督语音预训练和表征学习工具包( S3PRL 语音工具包 )的库。如果你打算研究除了 wav2vec 系列之外的上述任何型号,一定要看看它们。
2021 年 7 月 18 日更新:wav2vec 车型现提供 抱脸🤗变形金刚
是时候让有标签的数据集休息一下,开始利用无标签的数据集了。在许多情况下,未标记的数据相对容易收集。
无监督/自我监督表示学习开始在 NLP 之外的任务中表现良好。正如本文所讨论的,它已经为声学数据显示了一些有希望的结果。甚至 CV 也开始使用像预训练一样的无监督语言模型,例如图像 GPT 。
参考
1 Steffen Schneider,Alexei Baevski,Ronan Collobert 和 Michael Auli, wav2vec:语音识别的无监督预训练 (2019)
2 Alexei Baevski,Henry Zhou,Abdelrahman Mohamed,和 Michael Auli, wav2vec 2.0:语音表征的自我监督学习框架 (2020)
[3] Alexei Baevski,Steffen Schneider 和 Michael Auli, vq-wav2vec:离散语音表示的自我监督学习 (2019)
[4] Andy T. Liu,,Po-Han Chi,Po-chun Hsu 和 hong-yi Lee, Mockingjay:使用深度双向变压器编码器的无监督语音表示学习 (2019)
[5]迟宝汉、钟沛鸿、宗吴晗、谢春城、李尚文和李洪义,音频阿尔伯特:一个用于音频表征自我监督学习的 Lite BERT(2020)
[6] Aaron van den Oord,Yazhe Li,和 Oriol Vinyals,使用对比预测编码的表征学习 (2018)
[7] Jacob Devlin,Ming-Wei Chang,Kenton Lee,和 Kristina Toutanova, BERT:用于语言理解的深度双向转换器的预训练 (2018)
语言建模— I
这是关于语言建模的第 5 部分系列的第 1 部分。

使用键盘中的语言模型预测下一个单词 (Mandar Deshpande)
介绍
现在你可能已经猜到了,语言建模是我们日常使用的一个用例,但它仍然是一个很难理解的概念。REALM(检索增强语言模型预训练)是该领域不断发展的研究的最新成果。这是一个很大的进步,这正是为什么它使这篇论文成为一篇具有挑战性的文章来阅读和评论。
这篇博客假设你对深度学习、词向量和嵌入空间有基本的了解,因为这些是掌握语言模型的先决条件。
训练(深度)计算机视觉模型的主要方法也逐渐到达了自然语言处理的领域。我们正在谈论迁移学习。
一旦我们理解了 NLP 中的模型预训练的情况,我们将会在一个舒适而混乱的地方去理解 REALM 做什么和如何做!
为了带领我们了解语言建模领域并掌握相关概念,我们将在这一系列博客中讨论以下内容:
- 迁移学习及其与模型预训练的相关性
- 开放领域问答(Open-QA)
- 语言理解双向转换器
- Roberta(稳健优化的 BERT 预训练方法)
- 谷歌 T5
- 领域:检索增强语言模型预训练
这篇文章将特别尝试解释以下几点:
- 迁移学习
- 语言模型预训练
迁移学习
当我们有一个庞大的图像数据集,我们想解决一个图像分类和/或定位任务,我们明确利用图像像素作为特征。训练深度神经网络来解决这些任务需要我们利用海量的计算能力和数据。通常,从事该领域工作的大型科技公司和研究实验室已经从头开始训练了许多这样的网络,并在网上发布了预训练的权重。我们如何利用这一点?

使用卷积神经网络的迁移学习 (Mandar Deshpande)
让我们考虑一个简单的卷积神经网络(如上所示),它有 4 个卷积层(conv + relu +最大池),后面是一个全连接(FC)层,该层以 softmax 或 sigmoid 之类的损失函数终止。我们正在 ImageNet 数据集上训练该模型,该数据集是属于大约 1000 个类的大约 100 万个图像的集合。
现在,深度神经网络的任务是逐步提取特征,并将这些特征组合起来,以学习更复杂的特征。上图中显示的每一层都执行以下任务:
- con v1-提取简单的边、曲线和直线
- Conv2 —使用这些学习到的特征来提取图像中的形状和几何线段
- con v3——学习检测网格图案、光滑布料或道路等纹理
- 学习更复杂的特征,如眼睛、耳朵、椅子、门和其他帮助我们理解物体可能是什么的基本线索
- FC 层——使用先前学习的特征找出组合,这些组合一起很好地给出待分类物体的连贯图像
- 损失函数—FC 层给出的这个组合被转换成一个分数,高分数/概率类作为预测返回
现在,如果我们仔细观察,模型在前几层中学习的特征对于任何图像都是非常通用的,并且可以被视为在一系列图像类别中是冗余的。帮助我们明确区分对象的唯一层是具有损失函数的全连接层。
一般来说,当我们谈论训练深度神经网络时,我们的意思是我们将冻结大多数卷积层的权重(用粉色标记),我们只是用损失函数(用绿色标记)修改完全连接层的权重。本质上,我们可以在冻结层之后改变整个网络,使其适合类似的基于图像的学习任务。通过对新的用例特定数据的训练,仅修改允许改变的权重部分。这种对预训练模型的权重的更新被称为微调。
例如,我们有一个用于图像分类的预训练模型,该模型具有特定的损失函数,我们希望解决图像分割的任务。因此,我们冻结 conv 层并修改 FC 层以优化与分割相关的损失函数,使得我们的模型学习预测边界框(位置)以及对象类别预测。
使用在学习任务的特定领域训练的模型,并重新利用学习到的权重来解决另一个类似的学习任务,这被称为迁移学习。
由于使用迁移学习训练的模型不需要从头开始学习,它可以很容易地被训练到相同或更高的性能指标(例如准确性),而不需要太多的计算成本和时间。
语言模型预训练
当我们处理大量的文本数据时,了解单词序列彼此跟随的概率以及理解这种相关性需要哪些特定的特征是有帮助的。
语言建模是理解单词序列的概率分布的任务。这有助于我们创建能够根据句子和短语出现的上下文来区分它们的特征。
与单词嵌入的比较 每当我们想要在我们的模型中使用单词或文本数据作为特征时,我们通常将它们转换成稀疏向量,如一键编码,或者称为嵌入的密集向量。尽管预先训练的嵌入也已经在早期广泛地用于 NLP 任务,语言模型预先训练的新颖性在于它们是为特定的下游任务微调的,而不像嵌入那样广泛地用于文本。像 word2vec 和 GloVe 这样的嵌入是单词或句子的向量表示,它捕捉每个单词的上下文和语义特征。预先训练的语言模型进一步将这些嵌入提取为特定于任务的表示,从而通过在特定于任务的数据集上进行训练来实现特定的目标。

预培训语言模型使用管道 (Mandar Deshpande)
实际上,我们将大量未标记/未标注文本的语料库(维基百科、Quora)输入语言模型,并期望它学习不同上下文和主题之间内在的单词和句子级别的关系。一旦模型被训练,这实质上意味着模型已经学习了语言的结构,即语言已经在一些潜在向量/嵌入空间中被建模。一旦我们有了预先训练的语言模型,我们就可以利用它来完成任何下游任务,例如文本分类、文本生成和情感分类。
长期以来,预训练语言模型的使用一直是自然语言处理中最令人兴奋的消息,许多即将到来的研究都建立在这个概念上。这个领域可以通过以下预训练语言模型的开创性工作来突出:
我们将回顾其中的一些,并在的后续帖子中继续讨论专门针对 REALM 的语言建模。
链接到第一部分:语言建模 I 链接到第二部分:语言建模 II: ELMo 和 ULMFiT
链接到第三部分:变压器:快速浏览
继续学习和成长,直到那时!
在推特上与我联系:https://twitter.com/mandroid_6
以上所有图片都是我在我的 iPad 上创作的,我有权使用它们
语言建模 II: ULMFiT 和 ELMo
这是语言建模 5 部分系列的第 2 部分。

搜索引擎中常用的语言模型
介绍
在之前的帖子中,我们了解了语言建模的概念,以及它与 word2vec 和 GloVe 等常规预训练嵌入的不同之处。
在我们迈向 REALM(检索增强语言模型预训练)的旅程中,我们将简要浏览这些关于语言模型的开创性著作:
ELMo:来自语言模型的嵌入(2018)
像 word2vec 和 GloVe 这样的预训练单词嵌入是许多神经语言理解模型中的关键元素。如果我们坚持在语言建模任务中使用手套嵌入,那么无论单词“major”是否出现在任何上下文中,它都将具有相同的表示。语境对人类理解一个单词的意思起着重要作用。
例如,“少校:高级军官”和“少校:重要的、严肃的或重要的”,根据 GloVe vectors,对于单词“少校”,具有相同的嵌入。
创造如此高质量的作品是一项艰巨的任务。具体来说,任何单词表示都应该模拟:
- 句法和语义:用词的复杂特征
- 一词多义:一个词或短语在不同的语言环境中有多种可能的含义
ELMo 引入了一个深度上下文化的单词表示,它解决了我们上面定义的任务,同时仍然很容易集成到现有的模型中。这在一系列高要求的语言理解问题上取得了最先进的成果,如问答、NER、Coref 和 SNLI。
语境化的单词嵌入 既捕捉单词含义又捕捉语境中可用信息的表征被称为语境嵌入。与使用静态单词表示的 word2vec 或 GloVe 不同,ELMo 使用双向 LSTM 来完成特定任务,在对单词进行编码之前查看整个句子。
很像我们在上一篇文章中观察到的,ELMo 的 LSTM 是在一个巨大的文本数据集上训练的(与我们的下游任务使用相同的语言)。一旦这个预训练完成,我们就可以重用这些提取的单词嵌入作为另一种语言或 NLP 任务的构建块。

ELMo (Mandar Deshpande) 中使用的展开的前向语言模型
我们如何在这个庞大的数据集上训练模型? 我们简单地训练我们的模型来预测给定单词序列的下一个单词,即语言建模本身。此外,我们可以很容易地做到这一点,因为我们已经有了这个数据集,而不需要像其他监督学习任务中需要的显式标签。
ELMo 架构 由一个正向和一个反向语言模型组成,ELMo 的隐藏状态可以访问下一个单词和上一个世界。每个隐藏层都是一个双向 LSTM,因此它的语言模型可以从任一方向查看隐藏状态。您可以查看上图,了解这个 LSTM 如何访问其他隐藏状态。

ELMo 中第 k 个令牌特定嵌入的隐藏层连接和求和( Mandar Deshpande)
一旦前向和后向语言模型被训练,ELMo 将隐藏层权重连接在一起成为单个嵌入。此外,每个这样的权重串联乘以基于被解决的任务的权重。
正如您在上面看到的,ELMo 将这些串联的嵌入相加,并将其分配给正在从输入文本中处理的特定标记。ELMo 将令牌 t_k 表示为相应隐藏层的线性组合(包括其嵌入)。这意味着输入文本中的每个标记都有 ELMo 分配的个性化嵌入。

通过串联嵌入将 EMLo 集成到其他 NLP 任务中 (Mandar Deshpande)
一旦 ELMo 的 biLMs(双向语言模型)在一个巨大的文本语料库上被训练,它可以通过简单地连接到嵌入层而被集成到几乎所有的神经 NLP 任务中。
较高层似乎学习语义,而较低层可能捕捉句法特征。此外,ELMo 增强模型可以更有效地利用小数据集。
你可以在这里阅读更多关于 ELMo 的信息。
乌尔姆菲特(2018 年)
在 ULMFiT 之前,归纳迁移学习广泛用于计算机视觉,但 NLP 中的现有方法仍然需要针对特定任务的修改和从头开始的训练。ULMFiT 提出了一种有效的迁移学习方法,可以应用于任何 NLP 任务,并进一步展示了微调语言模型的关键技术。
代替模型参数的随机初始化,我们可以获得预训练的好处并加速学习过程。
常规的 LSTM 单元被用于 ULMFiT 的 3 层架构,从 AWD-LSTM 得到启示。
ULMFiT 的三个阶段包括:
- 通用领域 LM 预训练:在通用领域语料库上训练语言模型,以捕获不同层面的语言的通用特征
- 目标任务区别微调:使用区别微调和学习速率表(倾斜三角形学习速率)在目标任务数据集上对训练的语言模型进行微调,以学习特定于任务的特征
- 目标任务分类器微调:使用逐步解冻并重复阶段 2,对目标任务上的分类器进行微调。这有助于网络保留低级表示并适应高级表示。

乌尔姆菲特的三个阶段(曼达尔·德什潘德)
正如我们在上面看到的,阶段 1 在所有层上使用相同的学习速率,而阶段 2 和 3 具有逐层的三角形学习速率表。此外,请注意层权重如何在三阶段过程中逐渐达到最佳值。(较深的颜色最适合于表示目的)
区别性微调(具有倾斜三角形学习率的阶段 2/3 的学习时间表)是本文的主要启示,因为它来自于模型中的不同层捕获不同类型的特征的直觉。因此,对他们中的每一个有不同的学习速度是有意义的。像计算机视觉一样,即使在语言建模任务中,初始层也捕捉关于语言的最一般的信息,因此一旦预先训练,就需要最低量的微调。
在该过程的阶段 2 之后,该模型已经非常接近指定任务所需的最佳权重,因此目标任务分类器微调据说非常敏感。如果微调过程在此阶段显著改变了权重,那么模型预训练的所有好处都将丢失。为了解决这个问题,本文提出了逐步解冻:
- 首先,解冻最后一个 LSTM 图层,并对模型进行一个时期的微调
- 接下来,上一层之前的层被解冻并微调
- 对每一层重复类似的过程,直到收敛
你可以在这里 看论文。
希望这篇博客有助于你对这个令人兴奋的预训练语言模型领域有一个基本的了解!
在下一篇博客中,我们将讨论用于学习可微调预训练模型的 Transformers 和 BERT。
链接到第一部分:语言建模 I 链接到第二部分:语言建模 II: ELMo 和 ULMFiT
链接到第三部分:变压器:快速浏览
继续学习和成长,直到那时!
在推特上和我联系:https://twitter.com/mandroid_6
以上所有图片均由我创作,我有权使用它们
用 Penn Treebank 语言建模
使用堆叠 LSTMs 进行上下文和单词预测——以及深度学习基础设施的比较。
递归神经网络 (RNNs)在历史上是解决顺序问题的理想选择。当数据集中的一个点依赖于其他点时,该数据被称为序列。一个常见的例子是时间序列,如股票价格或传感器数据,其中每个数据点代表某个时间点的观察结果。
RNN 比传统的前馈神经网络更适合于顺序建模,因为它能够通过保持状态或上下文来记住直到给定点所做的分析。这种状态,或者说“记忆”,随着每一个新的输入而重现。
长短期记忆——解决 rnn 中的间隙
需要 rnn 来跟踪状态,这在计算上是昂贵的。此外,还有训练的问题,如消失梯度和爆炸梯度。因此,RNN,或者准确地说,香草 RNN 不能很好地学习长序列。解决这些问题的一个流行方法是一种特殊类型的 RNN,它被称为长短期记忆 (LSTM)。
LSTM 在许多时间步长上保持很强的梯度。这意味着你可以用相对较长的序列来训练 LSTM。递归神经网络中的 LSTM 单元由四个主要元件组成:存储单元和三个逻辑门。
存储单元负责保存数据。
写入、读取和忽略门定义了 LSTM 内部的数据流。写门负责将数据写入存储单元。
读取门从存储单元读取数据,并将该数据发送回递归网络,以及
遗忘门,保持或删除信息单元中的数据,或者换句话说,决定要遗忘多少旧信息。
事实上,这些门是 LSTM 中的运算,它对网络输入、网络先前的隐藏状态和先前的输出的线性组合执行某种功能
传统 rnn 和 LSTMs 的比较见下图:

传统 RNN 单元和 LSTM 单元的比较,具有使 LSTM 计算成本更低且更鲁棒的门
自然语言处理(NLP) 是一个经典的序列建模任务:特别是如何编程计算机处理和分析大量自然语言数据。NLP 的最终目标是以一种有价值的方式阅读、破译、理解和理解人类语言。NLP 的常见应用是机器翻译、聊天机器人和个人语音助理,甚至是呼叫中心使用的交互式语音应答。
从历史上看,对于自然语言处理来说,足够大的数据集很难获得。这在一定程度上是因为需要对句子进行分解,并标记一定程度的正确性——否则,在此基础上训练的模型将缺乏有效性。这意味着我们需要大量的数据,由人类注释或者至少由人类修正。
宾夕法尼亚树库,简称为 PTB,是由宾夕法尼亚大学维护的数据集。它是巨大的——里面有超过四百八十万条注释文字,全部由人类更正。
数据集被分成不同种类的注释,如词类、句法和语义框架。对于这个例子,我们将简单地为我们的模型使用一个干净的、无注释的单词样本(除了一个标签— <unk>,它用于罕见的单词,比如不常见的专有名词)。

数据集的示例
神经网络结构
- 在这个网络中,LSTM 细胞的数量是 2。为了使模型更具表现力,我们可以添加多层 LSTMs 来处理数据。第一层的输出将成为第二层的输入,以此类推。
- 200 个输入单元--> [200x200]权重--> 200 个隐藏单元(第一层)->[200 x200]权重矩阵--> 200 个隐藏单元(第二层)-> [200]权重矩阵--> 200 个输出单元
- 假设每个单词由嵌入向量表示,嵌入向量的维数 e=200。每个像元的输入层将有 200 个线性单位。这些 e=200 个线性单元连接到隐藏层中的 h=200 个 LSTM 单元中的每一个(假设只有一个隐藏层,尽管我们的例子有 2 层)。
- 输入形状是[批量大小,步数],即[30x20]。嵌入后会变成[30x20x200],然后是 20x[30x200]
隐藏层:
- 每个 LSTM 有 200 个隐藏单元,这相当于嵌入单词和输出的维数。
(改编自 PTB 培训模块和认知类. ai)
商品云对比 WML-CE
在这个托管服务的时代,有些人往往会忘记底层计算架构仍然很重要。例如,下面的截图显示了使用 A)公共云和 b)沃森机器学习-社区版(WML-CE)的同一模型的训练时间

使用商用云—培训时间 14848.5 秒(4.1 小时)

使用沃森机器学习-社区版:训练时间 317.7 秒(5.2 分钟)
沃森机器学习加速器
一个企业机器学习和深度学习平台,具有流行的开源包、最有效的扩展和 IBM Power Systems 独特架构的优势。看看下面的视频:
结论:
本文和相关代码的目的有两个:
a)演示用于语言和上下文敏感建模的堆叠 LSTMs 和
b)底层基础设施对深度学习模型训练效果的非正式演示。
感谢您的宝贵时间!
语言模型
语言模型是许多自然语言任务的基础。本文是对统计语言模型的直观介绍

定义
我在一次电话会议中,有人说“项目 A 的风险增加了 __”我听不到 of 后面的那个词,但我知道那个词是什么。我相信你也知道这个词。
我们有一个语言模型。我们的内部语言模型告诉我们,句子“项目 A 有延迟的高风险”的概率比句子“项目 A 有高风险的水”的概率高得多
这篇文章是关于统计学习语言模型(LM)——它们是什么,它们是如何被评估的,以及它们是如何被学习的。语言建模本身并没有直接的实际用途,但它是机器翻译和自动语音识别等现实应用中的一个重要组成部分。翻译系统可能会生成同一目标句子的多种翻译,语言模型会对所有句子进行评分,以选择最有可能的一个。
从形式上来说,语言建模的任务就是简单地给任何单词序列分配一个概率。或者,我们也可以把这个问题提出来作为猜词问题。填空: 狗 ____ 。下面的等式从数学上显示了这种等价性。

衡量绩效
您将如何衡量该模型的性能?最常见的内在指标是困惑。困惑衡量语言模型在预测一个看不见的单词序列中的下一个单词时有多困惑。Ravi Charan 的博客中有一个很好的关于困惑的中级概述。
但是,对于大多数实际目的来说,外在的措施更有用。LM 的外在度量是使用 LM 的底层任务的准确性。例如,使用给定语言模型的翻译任务的 BLEU 分数。
困惑是特定于语料库的度量。只有在相同的语料库上计算度量时,我们才能比较两个 LMs 的复杂度。困惑的改善并不能保证外在指标如 BLEU 评分的改善。
构建语言模型
语言模型从一个马尔可夫假设开始。这是一个简化的假设,即第 k+1 个字依赖于前 k 个字。二阶假设导致二元模型。使用现有语料库的最大似然估计(MLE)来训练模型。MLE 方法只是工作计数的一部分。

使用传统的 n 元语言模型有一些优点。
- 它们很容易在大型语料库上训练
- 他们在大多数任务中表现惊人的好!!
然而,它们也有一些缺点
- 零概率:如果我们有一个包含两个单词的三元语言模型,并且拥有 10000 个单词的词汇量。我们有 10 个三胞胎。如果我们的训练数据有 10 个⁰词,那么在训练数据中有许多三元组将永远不会被观察到,因此基本 MLE 将把零概率分配给那些事件。零概率意味着无限的困惑。为了克服这个问题,在平滑技术家族下开发了许多技术。在的这篇论文中对这些技术进行了很好的概述。
- 指数增长:第二个挑战是 n 元文法的数量以词汇量的 n 次方指数增长。一个 10,000 单词的词汇表将有 10 个三元组,一个 100,000 单词的词汇表将有 10 个⁵三元组。
- 一般化:MLE 技术的最后一个问题是缺乏一般化。如果模型在训练数据中看到术语“白马”,但没有看到“黑马”,MLE 将把零概率分配给“黑马”。(幸运的是,它也会将零概率分配给紫马)
神经语言模型
非线性神经网络模型解决了传统语言模型的一些缺点。例如,与传统模型相比,神经 LM 的参数数量增加缓慢。最早的这种模型之一是由 Bengio 等人在 2003 年提出的。在一篇名为一种神经概率语言模型的经典论文中,他们展示了使用 RNN 学习单词表示的基本结构。
引用这篇论文,他们提出了三个关键观点—
- 将词汇表中的每个单词与分布式单词特征向量(n 维实值向量)相关联
- 根据序列中这些单词的特征向量来表达单词序列的联合概率函数,以及
- 同时学习单词特征向量和概率函数的参数。
LMs 的副产品是单词表示
语言模型可以在原始文本上训练,比如来自维基百科的文本。为了训练 k 阶语言模型,我们从运行的文本中取出(k + 1)个字,并将第(k + 1)个字视为监督信号。因此,我们可以从任何语言的各种在线/数字化数据中生成大量的训练数据。
使用神经模型学习语言模型的一个特别重要的副产品是如下所示的单词矩阵。我们不仅更新训练参数,还更新单词矩阵。然后,字矩阵可以用于各种不同的监督任务。

结论
几乎所有的 NLP 任务都使用语言模型。语言模型用于语音识别、机器翻译、词性标注、语法分析、光学字符识别、手写识别和信息检索。
传统的语言模型在这些用例中表现得相当好。深度学习时代带来了新的语言模型,这些模型在几乎所有的任务中都优于传统模型。典型的深度学习模型是在大型数据语料库上训练的( GPT-3 是在从网络上搜集的一万亿单词的文本上训练的),具有很大的学习能力(GPT-3 有 1750 亿个参数),并使用新颖的训练算法(注意力网络,BERT)。
尽管学习 LMs 的机制已经发生了变化,但是 LMs 背后的基本直觉仍然是一样的。
语言模型与假新闻:宣传的民主化
用开放的 GPT- 3 模型深度伪造信息
介绍
“太危险了,不能释放。”
一个短语发布了 OpenAI 的新闻声明,以配合他们在 2019 年 2 月发布的 GPT-2 语言模型。随着上周发布更先进的 GPT-3,人工智能驱动的错误信息的可能性已经成为当今后事实信息景观中仍未解决的重大风险。

GPT-3 生成的诗歌(布朗等人。铝)
自 2016 年以来,“假新闻”一词在世界各地的政治领导层和普通民众中日益流行,作为一个不屑一顾的概念,用于不支持自己观点的报道。但是这个术语已经扩展到包括国家和非国家操作的错误信息运动。利用这种活动影响全球事件的努力已经大大加快,美国参议院两党委员会得出结论,俄罗斯在 2016 年美国总统选举期间的错误信息活动“通过俄罗斯控制的宣传渠道传播信息,以破坏公众对民主进程的信心”。罗伯特·穆勒也表达了类似的观点,他补充说,俄罗斯的干预是“全面和系统的”,并担心在即将到来的 2020 年总统选举中继续受到影响。研究人员现在认为,政治机器人和虚假信息在其他重大案件中发挥了作用,如英国退出欧盟公投和克里米亚危机。
这些具体的报告让人担心人工智能会被用作网络战的工具来支持错误信息活动。然而,研究表明大多数“人工智能支持的”解决方案只不过是机器人设计来重复特定标签下的特定短语和链接,以改变讨论的背景。这种方法更多地依赖于人类操作员理解在线话语心理的能力,而不是机器人本身的能力。最近,社交媒体平台上关于新冠肺炎危机的人工智能生成的内容的激增,导致要求改进审查的呼声日益高涨。然而,人工审查既慢又粗糙,而人工智能对大量数据进行建模以进行训练。脸书首席技术官迈克·斯科洛普夫总结了为新的不可预见的威胁构建解决方案的基本挑战:
“为一个能够理解前所未见内容的东西构建一个新颖的分类器需要时间和大量数据。”
目前还没有关于人工智能产生的错误信息的普遍性的系统研究,很可能迄今为止大多数错误信息都是由人类行为者创造的。但是随着人工智能生成的虚假账户的扩散,加上语言模型的可用性和能力的增加,预计人工智能生成的文本错误信息将在未来遇到。如今观察到的事后、意见主导的信息格局加剧了这一问题。
但是为什么对这些模型忧心忡忡呢?是什么让他们变得危险?我们正在见证真理的死亡吗?要回答这个问题,我们需要深入研究它们的原理和运作方式。出于时间和范围的考虑,在本文中,我们将把注意力集中在 OpenAI 的 GPT 系列语言模型上。
变形金刚:现代自然语言处理的基石
我们已经在以前的文章中介绍了语言模型背后的一般理论,如递归神经网络( RNNs )和长短期记忆(L STM )架构,因此鼓励读者参考这些来详细了解这些架构。
自然语言模型的 GPT 家族是基于转换器模型的,其特征是重复的编码器架构加上一个注意力机制。 Alammar 等人已经深入解释了变压器的一般架构。但是我们将在这里提供一个高层次的总结。
考虑变压器模型的一般结构,如下所示:

变压器型架构的抽象。铝)
编码器-解码器架构的工作原理是,通过编码器将输入数据缩减为潜在维度(表示单词的含义),由解码器组件以目标语言重建。正因为如此,它们在机器翻译方面一直表现强劲。然而,Transformer-models 通过将自关注层整合到每个编码器和解码器模块中来构建这种架构,每个组件拥有自己的一组权重参数。注意力层的工作是将输入单词在句子中的位置与其含义联系起来,以便改进其编码。特别是,与传统的纯 RNN 和 LSTM 架构相比,变压器模型更能够捕捉序列中的长程相关性。
我们可以用一个例子来最好地形象化注意力对编码过程的影响。考虑下面的句子:
“这只动物没有过马路,因为它太累了”
通过检查相应层的激活,我们可以用注意力来观察句子成分之间的关系。

句子编码分析(Alammar 等。铝)
你会注意到单词“它”的编码表示拥有与概念“动物”和“疲倦”的强注意力链接,在这些对之间创建了一种意义关联的形式。这种关联的好处对于机器翻译应用程序特别有用,在机器翻译应用程序中,不同语言的语法可能需要完全不同的句子结构,但是这种关联也可以扩展到条件文本生成和其他应用程序。
GPT 模式
OpenAI 的语义语言模型 GPT 家族基于谷歌大脑的工作,完全去除了编码器组件,由一堆带有注意力层的解码器块组成。

GPT-2 体系结构的抽象(Alammar 等人)
虽然该模型被训练为在给定输入文本序列的情况下预测序列中的下一个单词,但它们的高参数复杂性导致了通过元学习(或仅用新任务的几个示例进行再训练)获得的显著扩展的能力,包括:
- 长期相关性分析
- 生词记忆
- 算术计算
- 机器翻译
- 摘要
- 语境分析
最初的 GPT-1 模型由变压器模型和预训练的 ELMO 语言模型组成,具有数亿个可训练参数。GPT-2 扩展到超过 15 亿个参数,是它的 10 倍以上,并在 10 倍以上的数据量上进行训练(来自互联网和文学来源)。
最近的 GPT-3 建立了超过 1750 亿个参数,提高了其语义性能,特别是在一次性或零次训练应用中。实现这种应用程序的高性能对于接近语言模型的人类水平的响应和性能是必要的。相比之下,典型的人脑有超过 100 万亿个突触,大约比最大的 GPT-3 模型大三个数量级。鉴于 OpenAI 花了大约一年左右的时间将他们模型的参数容量增加了两个数量级,在给定时间和资源的情况下,达到这个数量似乎是可行的任务。

各种 GPT-2 参数配置的体系结构的抽象。(阿拉玛等人。铝)
GPT-2 和 GPT-3 也在不同的参数配置中进行了测试,以评估其性能并防止潜在的误用。GPT-3 配置的配置和基准性能如下所示:


当配置不同数量的训练参数时,GPT-3 模型在零炮、一炮和少炮应用中的性能精度。
我们可以通过比较 GPT 3 号卫星输出结果的差异来最好地展示其性能的提高。下面是 GPT-2 生成的文本样本,正如 Brown 等人在最初的 OpenAI 论文中所报告的。艾尔。

布朗等人报道的 GPT-2 文本输出。
虽然乍一看,这篇文章似乎语法正确,但仔细检查就会发现许多事实上的不一致。例如,考虑这个句子:
"这些银白色的四角独角兽此前并不为科学界所知。"
鉴于独角兽被定义为拥有一只角,这是事实上的不一致。自然,模型不会明确知道单词的定义,也无法从训练数据中推断出它。
下一节显示了类似的不一致之处。
虽然它们的起源仍不清楚,但有人认为这种生物可能是在人类文明之前,人类和独角兽相遇时创造出来的
鉴于文章的主题是独角兽本身,这句话没有意义。然而,由于句子在语法上是正确的,这些错误需要大量的注意力和意识才能被识别出来。
相比之下,让我们举两个报道的 at GPT-3 输出的例子——第一个具有更高的逼真度,更能够冒充为人类生成的(88%),而第二个则明显不那么逼真(39%)。


布朗等人报道的 GPT-3 文本输出。
与 GPT 新协议相比,GPT 新协议似乎抓住了词汇定义的微妙之处。然而,对这两个输出的分析表明,该模型仍然与扩展的对话片段作斗争。考虑摘录:
“一年前,乔阿金·菲尼克斯出现在金球奖红毯上,他穿着燕尾服,头上套着一个纸袋,上面写着,“我是变形人”,这成为头条新闻。我不能改变世界。我只能改变自己。这是一个不改变以适应好莱坞模式的承诺:“我认为这是一件非常特别的事情,不改变自己。我觉得说“真的很特别
事实上,文本的真实性可以通过简单地固定每行周围的标点符号,并将它们连接在一起而得到显著提高。但是,这需要学习,而不是定义。平均而言,由最大的(1750 亿)和最小的(1.25 亿)GPT-3 模型产生的检测物品的平均人类准确度为 ca。在 200 篇文章中分别为 52%和 76%。
如前所述,GPT-3 在其他各种 NLP 任务中表现出色,进行了少量射击、一次射击或零射击训练。这些任务的选择如下所示,以供参考:

GPT-3 上下文分析示例。

GPT-3 机器翻译示例。

GPT-3 算术计算示例。

GPT-3 字解扰例子。
真正令人印象深刻的是该模型在这些新应用程序中显示的性能,因为它降低了商业应用程序(如聊天机器人或评论情感分析)的开发界限。
真理的死亡?
因此,考虑到性能改善的趋势,是否有可能将模型的规模和复杂性进一步提高几个数量级,并超越随机机会愚弄人类?
也许吧。虽然条件文本生成在模型复杂性方面表现出了显著的改善,但研究人员观察到,GPT-3 在分析句子之间的关系时表现不佳,并提出这里的问题与模型复杂性无关,而且方法本身可能是不正确的。他们的结论总结了这一点:
“对于自我监督的目标,任务规范依赖于将期望的任务强制转化为预测问题。然而最终,有用的语言系统(例如虚拟助手)可能更好地被认为是采取目标导向的行动,而不仅仅是做出预测。”
提到目标导向的行动是特别有趣的,因为它表明强化学习方法将是一个更理想的解决方案。OpenAI 此前曾探索过利用人类偏好来微调 GPT-2 模型,但这种方法对于现实世界的应用来说过于粗糙和劳动密集型。一个真正的强化学习模型需要为它的应用仔细定义一个奖励函数,也许通过使用前馈鉴别器模型,正如在分子设计的[领域](http://OpenAI's GPT family of models)中所做的那样。
那么,我们注定会有一个错误信息的未来吗?也许不是。训练这些模型是极其耗费资源的,使用单个英伟达 RTX-8000 GPU 单元训练最大的 GPT-3 模型需要相当于 665 年的时间。此外,HarvardNLP、 AllenAI 和 IBM Watson 等组织的研究人员已经利用 GPT-2 等生成语言模型的可用性来构建能够检测假冒输出的鉴别器。随着 GPT-3 和其他更复杂模型的发布,鉴别器必须类似地进化,引发了对军备竞赛的恐惧,类似于对 deepfakes 的观察。此外,由于鉴别器模型的训练将需要发生器的输出,总会有一个窗口,在该窗口期间检测解决方案将是不充分的。
但是“假新闻”的真正风险不在于语言模型的能力,而在于我们在信息素养和批判性思维方面的退化技能。无论是由于社交媒体还是其他原因,两极分化已经成为话语的一个重要组成部分,导致了从极端主义观点的在线回音室到最高层治理缺乏两党合作的症状。

随着时间的推移,美国民主党和共和党的意识形态观点发生了转变。(皮尤研究中心)
除非我们能够有意识地减少两极分化,并采取一种以事实信息和尊重话语为导向的文化,否则我们将继续容易受到错误信息的影响,无论这些错误信息是由人工智能还是人类行为者产生的。
这就结束了我们对开放 GPT 模型理论进展的回顾。在我们即将发表的文章中,我们将讨论如何实现 GPT 模式来制造一些“假新闻”和诗歌。
我们希望你喜欢这篇文章,并希望你查看 GradientCrescent 上的许多其他文章,涵盖人工智能的应用和理论方面。为了保持对 GradientCrescent 的最新更新,请考虑关注该出版物并关注我们的 Github 资源库。
参考文献
[## OpenAI 巨大的 GPT-3 暗示了 AI | ZDNet 语言模型的局限性
加州研究机构 OpenAI 带着另一个巨大的深度学习模型 GPT-3 回来了。虽然它表明…
www.zdnet.com](https://www.zdnet.com/article/openais-gigantic-gpt-3-hints-at-the-limits-of-language-models-for-ai/) [## 根据人类偏好微调 GPT-2
我们已经对 774M 参数 GPT-2 语言模型进行了微调,在各种任务中使用了人类反馈,成功地匹配了…
openai.com](https://openai.com/blog/fine-tuning-gpt-2/) [## 更好的语言模型及其含义
我们已经训练了一个大规模的无监督语言模型,它可以生成连贯的文本段落,实现…
openai.com](https://openai.com/blog/better-language-models/) [## 用无监督学习提高语言理解
我们通过一个可扩展的、与任务无关的系统,在一系列不同的语言任务上获得了最先进的结果…
openai.com](https://openai.com/blog/language-unsupervised/) [## 语言模型是一次性学习者
最近的工作已经证明了在许多自然语言处理任务和基准上的巨大收益。
arxiv.org](https://arxiv.org/abs/2005.14165) [## 图解 GPT-2(可视化变压器语言模型)
讨论:黑客新闻(64 分,3 条评论),Reddit r/MachineLearning (219 分,18 条评论)翻译…
jalammar.github.io](http://jalammar.github.io/illustrated-gpt2/) [## 图示的变压器
讨论:黑客新闻(65 分,4 条评论),Reddit r/MachineLearning (29 分,3 条评论)翻译…
jalammar.github.io](http://jalammar.github.io/illustrated-transformer/) [## 揭秘 GPT-3——深度学习语言模型的最新成果
上周四,OpenAI 对语言建模的最新更新 GPT-3 出现在 arxiv 上。鉴于其影响力之大…
lambdalabs.com](https://lambdalabs.com/blog/demystifying-gpt-3/)
深度强化学习、符号学习和 AGI 之路
苹果 | 谷歌 | SPOTIFY | 其他
Tim rocktschel 在 TDS 播客

编者按:这一集是我们关于数据科学和机器学习新兴问题的播客系列的一部分,由 Jeremie Harris 主持。除了主持播客,Jeremie 还帮助运营一家名为sharpes minds的数据科学导师初创公司。可以听下面的播客:
强化学习可以做一些令人印象深刻的事情。它可以优化广告定位,帮助运行自动驾驶汽车,甚至赢得星际争霸游戏。但是当前的 RL 系统仍然是高度特定于任务的。特斯拉的自动驾驶汽车算法无法在星际争霸中获胜,DeepMind 的 AlphaZero 算法可以与围棋大师对抗,但无法优化你公司的广告支出。
那么,我们如何从利用强化学习来解决特定问题的狭义人工智能系统,向能够在世界中自我定位的更通用的系统飞跃呢?蒂姆·洛克特尔出场了,他是伦敦脸书人工智能研究所的科学家,也是伦敦大学学院计算机科学系的讲师。Tim 的大部分工作都集中在如何让 RL 代理使用相对较少的数据进行学习,使用被称为样本有效学习的策略,希望提高他们解决更一般问题的能力。蒂姆加入了我这一集的播客。
以下是我在对话中最喜欢的一些观点:
- 强化学习在由相对简单的规则结构管理的环境中工作得很好,如视频游戏、国际象棋、围棋和受约束的模拟。但是他们还不能在混乱、开放的现实世界中运作。这在很大程度上是因为他们一开始是“白板”模型,必须为他们承担的每项任务从头开始接受培训。
- 语言模型是解决这个问题的一种方法:为了有效地生成文本,算法需要开发一个相当全面的世界模型。然后,该模型可以被 RL 代理重新利用,以开发对各种对象和概念如何相互关联的基本理解,从而不必从头开始学习这些关系。举个例子:当前的 RL 系统无法承担像《我的世界》这样的游戏,在那里你会得到一些物体,它们的外观或名称会提示你它们的用途(例如,你在游戏中拿起一个火炬,并隐含地理解它可以用来烧毁东西)。语言模型可以帮助引导代理理解“火炬”和“燃烧的东西”之间的关系,这样代理就可以更清楚地知道它的所有潜在行为,而不必在学习如何在环境中移动和定位自己的同时学习火炬。
- 蒂姆还研究了基于神经网络的符号学习方法。符号学习使用符号来表示某些对象和概念,并允许开发人员显式地定义它们之间的关系。在某些方面,这是好的:因为符号系统明确地而不是隐含地学习想法或指令,它们不太可能被巧妙设计的对抗性攻击所愚弄而做错事情。不幸的是,它们还需要开发人员手动为它们提供推理结构,这使得这些系统在解决更需要隐式学习的一般问题时不切实际。蒂姆的方法包括训练神经网络学习符号逻辑——这是一种理想地结合了符号逻辑的严谨性和深度学习的灵活性的策略。原则上,这可以让神经网络理解像“父亲的任何父亲都是祖父”这样的概念,同时也正确地识别像“祖父”、“祖父”、“祖父”等这样的词,作为“祖父”的象征性等价物。
- 符号学习可能会对人工智能安全产生影响,因为符号可以用来捕捉更强大的规则和关系,我们不希望机器误解这些规则和关系(例如,“不要杀人”),而不会牺牲它们的实际效用。
本集引用的链接:
如果你有兴趣在蒂姆在播客中提到的 NetHack 环境中培训自己的强化学习代理,看看这个 GitHub repo !
章节:
- 0:00 介绍
- 0:43 什么是可解释的机器学习?
- 强化学习和自然语言处理之间的关系
- 9:11 适合强化学习的游戏
- 13:36 探索和适应新环境
- 18:32 问答系统—维基百科
- 20:21 应用于深度学习系统
- 25:34 人工智能校准
- 31:19 语言作为知识图谱
- 33:07 当前人工智能研究的目标
- 35:6 大局
- 41:45 哲学上为 GPT-4 做好准备
- 44:57 与技术相关的生存风险
- 45:34 下一步
- 50:05 符号推理
- 51:38 人工智能内部的模糊界限
- 53:13 总结
下面是第二季第二集的脚本:
Jeremie (00:00):
大家好,我是 Jeremie,我是“走向科学状态”播客的主持人,也是最敏锐思维数据科学导师项目团队的一员。今天,我们继续我们关于数据科学和机器学习中新出现的问题的系列,欢迎 Tim Rochdechel 来到播客。蒂姆是脸书人工智能研究所的研究科学家,他在那里从事许多与高级人工智能系统相关的项目,包括样本高效机器学习,该项目专注于减少训练机器学习模型所需的数据量,以及符号人工智能等事物。
Jeremie (00:31):
现在,Tim 对机器学习的当前状态有了深入的了解,我们将讨论这一点,以及人工通用智能研究的潜在未来方向。我希望你喜欢这次谈话。
耶雷米(00:43):
好的,我和蒂姆·罗彻尔在一起。所以他是脸书人工智能研究所的研究助理,抱歉,是研究科学家,也是伦敦大学学院人工智能中心的讲师。他会告诉你所有这些东西,但他的工作真的很有趣,专注于他所谓的样本高效和可解释的机器学习。我肯定我们会深入了解这意味着什么。我们将对此进行全面的讨论,以及该领域的一些最新发展,强化学习,开放 Eye 的 GPT-3 模型,我相信会有一些出现。我们有很多内容要讲,但首先,我想问你,Tim,你能用自己的话介绍一下你正在研究的领域吗?你每天处理的一些有趣的问题。
蒂姆(01:43):
当然可以。首先,非常感谢邀请。非常非常高兴来到这里。所以,我想我过去一直在强化学习和自然语言处理的交叉领域工作,现在也是。所以在强化学习中,我想我会想象很多听众对基本的设置很熟悉,你有一个环境,你有一个代理。你的代理人不是与环境一起行动,而是从环境中获得[听不清 00:02:16]并旨在随着时间的推移最大化预期的未来回报,一些未来的回报。
蒂姆(02:23):
这是一种非常通用的方法,对吗?一些非常通用的东西,你可以潜在地应用于许多不同的情况,然后与此同时,我想强化学习在适用于现实生活问题方面的进展相对有限[听不清 00:02:42]我们可以稍后再谈。
Tim (02:44):
同时,正如我提到的,我偶尔会研究自然语言处理问题,所以问题是,我们如何才能开发出能够处理并在某种程度上利用自然语言文本的机器?例如,自然语言处理中的一个常见问题是问答。我能开发出模型,给它一个问题,给你一个自由形式的答案吗?
耶雷米(03:12):
嗯嗯(肯定的)。
蒂姆(03:12):
或者,这并不是实际生活中的问题,而是一类非常受欢迎的模型,即所谓的语言模型,这些模型在给定一些文本的情况下,能够很好地预测文本中的下一个单词,然后生成文本。因此,在过去的几年里,我们已经看到了很多进步。
耶雷米(03:34):
有意思。强化学习和自然语言处理之间的联姻有什么原因吗?因为至少从历史上看,这是我从 30000 英尺的角度理解的,从历史上看,强化学习和计算机视觉可能会有更紧密的互动,重点是自动驾驶汽车,也许还有机器人。你认为 NLP 是这里有趣的成分之一是有原因的吗,还是说,它只是碰巧同时发生的两条独立的研究路线?
Tim (04:08):
没有。我确实看到了两者之间的许多协同作用,所以这是一个非常好的问题。首先,传统上,人们一直在自然语言处理任务中应用来自强化学习的各种技术。因此,人们一直在使用增强来直接优化机器翻译性能,而不是对[听不清 00:04:31]模型使用负面[听不清 00:04:30]训练。所以已经做了很多了。然后,反过来,人们也一直在研究指令跟随,所以给定一个智能体需要实现的目标的某种自然语言描述,我们如何设计能够以这样的自然语言信息为条件的智能体,然后在环境中实现目标?
Tim (04:53):
我之所以坚信自然语言处理和强化学习之间的结合,在很大程度上是因为到目前为止,我们已经看到了很多强化学习的成功案例,在这些环境中,你基本上可以从头开始训练。这意味着,随着时间的推移,您的到期策略允许代理充分学习或探索环境,以便提出非常非常好的策略。举例来说,这在你的环境动力有限的环境中是可行的。举个例子,我认为围棋是一个很好的例子,它在几年前就开始流行了,对吗?通过深刻的思考。
蒂姆(05:46):
这是一项令人印象深刻的成就,因为他们能够训练一个人工智能,在围棋比赛中击败人类专家。然而,重要的是要注意,围棋中的动力学相对简单,对吗?规则非常清楚,所以你有一个规定的时间步,有一个特定的动作,下一个时间步会发生什么是绝对清楚的。所以基本上,你可以进行蒙特卡罗树搜索。这意味着你实际上可以试着提前计划特定的行动顺序会发生什么。
蒂姆(06:23):
但是在很多其他环境中,人们会带来很多领域知识、常识和工作知识,只有这样他们才能在这些环境中做得很好,对吗?例如,我认为一个很好的例子是《我的世界》。所以如果你玩《我的世界》,有很多事情与现实世界中的事情非常相似,对吗?因此,如果你有一个火把,你开始燃烧一棵树,它只是烧毁。我觉得这很令人兴奋,对吧?那么,我们如何确保我们的代理人能够利用人类随着时间的推移收集的知识财富,他们在维基上写下来,他们写在表格里等等?他们[听不清 00:07:15]
耶雷米(07:17):
这其中的一部分,或者至少是我一直理解的,是我们的知识的一部分,当然,是随着时间的推移学习的,就像你说的,我们阅读维基或阅读教科书,或者只是被世界所教的东西,但是我想,另一部分也是先天的,是通过一个缓慢得多的过程,即进化教给我们的。所以我们生来就不是一张白纸,而是生来就对看起来像某个样子的面孔有特定的偏好,等等。我想,在某种程度上,这似乎涵盖了这两个方面。如果你真的能总结出一大堆人类知识,我不知道,维基百科语料库或人们写的所有语言,我想希望你涵盖了这两个基础?这样说公平吗?
蒂姆(08:03):
嗯,我认为这是一个非常好的观点。我相信你必须在某种程度上把它们分开,对吗?你必须说,“好吧,有人们写下来的知识。他们在一生中获得的东西,他们想和其他人分享这些知识,可能在某个时候,和代理人,人工代理人分享。”这是我大部分时间都在关注的事情。然后你提到的另一个方面,进化和天生的某些行为允许你,例如,要么直接在环境中表现得很好,要么允许你很快学会什么是环境中的好政策。我认为这也是一个非常令人兴奋的领域。我不太熟悉那个研究领域正在发生的事情,除了,我相信,我强烈认为我们需要像信使一样的代理人去探索。
Tim (09:01):
所以这是不够的,对于许多现实的环境来说,试图根据环境给你的奖励来最大化奖励真的是不够的,对吗?
耶雷米(09:10):
是的。
蒂姆(09:11):
在许多环境中,我认为给自己设定目标是绝对重要的,因为你遇到了意想不到的事情,增加了你对环境的了解。我认为这是非常关键的一点。这就是为什么人们喜欢玩像《我的世界》这样的游戏,他们只是了解某些事情是如何工作的。我在这里说了很多关于《我的世界》的事情,但实际上,我相信还有其他游戏可能更适合强化学习。
耶雷米(09:41):
喜欢什么类型的游戏?
蒂姆(09:42):
几周或几个月前,我们发布了 NetHack 学习环境。所以这是一个强化学习环境,围绕着一个非常古老的游戏,叫做 NetHack。NetHack 最初是在 1987 年发布的。它在终端播放,所以这确实是一个甚至没有任何彩色屏幕的时代。
耶雷米(10:06):
是啊。
Tim (10:06):
你真的在 Linux 终端上玩过这个。所以所有的观察值都是[听不清 00:10:12]字符。看起来很神秘,很刺激。所以基本上,你被扔进了这个地牢。你的玩家就是这个“at”符号。你可以在地牢里走动。怪物是其他 askey 字符,像 D 可能是一只狐狸或可能是一只狗或类似的东西。你走来走去,发现物品,武器,盔甲等等。这个游戏真正令人兴奋的一个方面,实际上类似于《我的世界》,是它是按程序生成的。所以,也许多谈一点会更有趣。
蒂姆(10:48):
当深度强化学习变得非常流行时,研究人员正在使用神秘的学习环境。所以 Atari games,为了测试代理是否能学会玩 Pong 或者 Pacman 女士或者 Montezuma 的复仇之类的游戏。这真的推动了强化和研究很长一段时间。但有趣的是,到现在为止,我觉得这些游戏几乎都被人工智能吃掉了。
耶雷米(11:19):
嗯嗯(肯定)。
蒂姆(11:20):
通常,这告诉我们更多关于实际环境和突出问题的信息,它告诉我们人工智能有多智能。这很重要的原因是因为在雅达利,环境在某种意义上是静态的。所以每次你玩这个游戏,都是一样的。
耶雷米(11:40):
是啊。
蒂姆(11:41):
对吗?所以每次你玩 Pong 或者 Breakout 的时候,你看到的观察结果并没有太大的变化。同样的,你想想超级马里奥,对吧?每次你玩超级马里奥,等级都是一样的。
耶肋米亚(11:53):
是啊。
蒂姆(11:54):
因此,随着时间的推移,你将学会做的几乎是记住为了做好你必须做的行动的顺序。
耶雷米(12:00):
是啊,[相声 00:12:01]你太适应你的环境了。
提摩太书(12:03):
完全正确,对吗?具体来说,环境是决定性的。这意味着,如果你发现自己在同样的情况下,你会做同样的行动,你会看到同样的结果。所以这是确定性的,我称之为静态的,就环境观测变量而言。最近成功的方法没有探索这一点。所以,我认为,2018 年优步人工智能有一个非常惊人的工作,叫做“探索”,他们解决了这个非常非常难的雅达利游戏,叫做“蒙特祖马的复仇”。他们基本上是通过确保重置代理或环境来做到这一点的,实际上,他们将代理或环境重置为以前访问过的状态,然后从那里开始浏览。对吗?所以,真的随着时间的推移,代理人通过游戏记忆特定的动作序列。
蒂姆(12:56):
这让许多研究人员开始考虑所谓的过程生成环境。这意味着,有一个生成过程,每次你开始一集,观察基本上是在你面前生成的。这意味着每次你开始一集,你会看到你以前从未见过的东西,比如在《我的世界》,对吗?每当你玩新的《我的世界》游戏时,这个世界就会产生。
提摩太书(13:20):
NetHack 也是这样。所以每次你被扔进地牢,你真的不知道在地牢的拓扑结构或特定房间和暗门的安排等方面会发生什么。这就迫使我们的特工,为了做得更好,去归纳这些新奇的情况。
耶肋米亚(13:36):
有趣。所以,这是,我猜这和蒙特祖马的复仇是一个质的不同的问题。如果我记得的话,那一个也有类似的问题,奖励经常被隐藏或者稍微远一点。你必须做一些违反直觉的事情来获得这些奖励。我想这是一个不同的问题,现在你面临着一个全新的环境,你实际上学习做的不仅仅是,嗯,在某种程度上,这感觉像是一个探索/开发的事情。你不想过度投资开发这种确定性环境。你还需要善于在这个新环境中探索和定位自己,而弄清楚自己身在何处的技能,现在人们已经开始在努力了?这是这项研究的目的吗?
蒂姆(14:21):
是的,我认为这是一个相对较好的评估。所以,在蒙特祖马的复仇中,你是对的,这是一个稀疏的奖励环境。这意味着你不会真的撞上许多来自环境的外在奖励,所以你真的必须探索很长时间,才能从环境中获得积极的信号,表明你正在做正确的事情。但有趣的是,蒙特祖马的复仇已经利用了许多人类的先验知识和偏见。所以,在蒙特祖马的复仇中,你必须收集钥匙,你必须开门,如果你作为一个人类玩家在蒙特祖马的复仇中跑来跑去,你看到一把钥匙并捡起来,那么你知道,好吧,一定有一扇锁着的门在某个地方,然后当你看到一扇锁着的门时,你就打开它。
蒂姆(15:01):
但是对于强化学习方法,至少是那些已经存在了很长时间的方法,他们有非常多的探索策略,对吗?他们偶尔会尝试一个随机的动作,看看是否真的有帮助。所以我们真正需要的是能够进行结构化和目标导向的解释的方法,这种方法能够激励他们自己,以一种非常有针对性的方式探索环境的某些方面。随着时间的推移,他们了解环境动态,了解你可以与之互动的事物以及如何与之互动。
蒂姆(15:36):
在蒙特祖马的《复仇》中,你可以看到钥匙和门等等。在 NetHack 中,你有数百个对象。各种各样的事情,对不对?各种武器,各种工具,比如开罐器,土地,钥匙等等,对吗?而且真的有如此大量的对象要学习,也有如此大量的敌人要打败,以至于人类玩家在学习玩网络黑客时,几乎所有人都必须自己查阅外部知识来源。所以有一个非常大的维基百科,叫做 NetHack Wiki,在那里人类玩家收集他们关于这个游戏如何运作的共享智慧,你可以做什么,你应该做什么和不应该做什么。当人们玩这个游戏时,他们真的学会了,嗯,在环境中做事,同时也在这个网络黑客维基上查找东西。
耶雷米(16:30):
这似乎很大程度上取决于你的创造能力,或者有一个连贯的世界模型来补充你的探索。我认为这实际上与 GPT 3 有关,当然,这是最近几个月发行的。让我想到这个的原因是,GPT 3 是那些面向自然语言的方法之一,至少试图构建一个相当完整,相当连贯的世界模型。我可以想象,仅仅基于 GPT-3 似乎能够做的一些事情,它似乎能够得出的一些联系,就承担这样的问题而言,它将是一个不错的知识基础。你认为这是一个公平的评价吗?你能把它用于迁移学习并和 RL 结合起来吗?
蒂姆(17:18):
是的,我认为至少有两种不同的方式可以利用这些预先训练好的语言模型。因此,一种方法是,假设你有一个外部文本知识源,如 NetHack Wiki,你想根据这些文本信息来调节你的强化代理。那么通常,试图学习语言,同时试图从头开始学习如何在环境中表现,这是一个坏主意,对吗?所以强化学习很难,自然语言处理从零开始也很难。如果你同时做这两件事,事情不会变得更容易。所以你想做的是,你想有一个好的起点,对吗?
蒂姆(17:59):
你希望有一个已经可以为你建立的模型,相对好地表达维基百科中所写的句子,这样你就可以在整个维基百科或 NetHack Wiki 上运行预先训练好的语言模型。你建立起所有的句子表征,或者单词和上下文表征,或者你想称之为什么的东西,然后你可以在环境中行动的同时尝试查询这些神经表征。这给了你一个操作维基的方法。
蒂姆(18:32):
虽然据我所知,这还没有完成,但对于复杂的强化学习任务,如 NetHack 学习环境,这还没有真正完成,我们有理由相信这是一种明智的方法,因为有问答系统能够处理如此大规模的维基。例如,整个维基百科。对吗?
蒂姆(18:54):
第二种方法是,或者第二个方向是……我想这可能是你的意思。是使用预先训练好的语言模型,比如 GPT-3,作为一个很好的先验,比如,物体的启示,对吗?你可以查询 GPT-3,我有一扇门,我能用它做什么?它可能会告诉你,你可以打开它,用钥匙打开它,踢它进去,无论什么,对吗?它可能会给你一些你可能想尝试的明智的东西,并且,很明显,可以用于你的强化代理可以应用的更好的探索策略[听不清 00:19:35]
耶雷米(19:35):
是的。我一直觉得语言建模,尤其是更完整的语言模型,如 GPT 3 和 GPT 4,以及其他即将出现的语言模型,对这类事情来说特别有前途,你提出的表格化的想法,空白的石板。你如何教会一个智能体从零开始在世界中定位自己,或者你如何避免不得不这样做?是的,用这些预先训练好的模型来支撑它,这看起来是一个很有前途的策略。所以,我认为一个很酷的主题,我们可以在你的研究背景下谈论,它似乎有很大一部分涉及到,找到将人类水平的信息传递给神经网络和机器学习模型的方法,我想是在非常抽象的意义上。
Jeremie (20:21):
我们已经谈过你对 NLP 的关注,以及与 RL 的互动。在我们开始讨论之前,你也提到过你一直在深度学习系统上做这项工作,并试图让它们基本上与逻辑规则一起工作,因此允许人类传达逻辑规则来约束深度学习系统的行为。你介意稍微探索一下,解释一下这项工作的内容吗?
蒂姆(20:43):
是的,当然。这是我在博士期间主要做的工作。我认为深度学习系统真的很棒。像 GPT-3 或深度强化代理这样的深度学习系统,他们真的很擅长从大量数据中学习。对吗?但是,问题是,对于许多领域,我们没有很多训练数据,或者我们可能想确保我们有一定的保证,在我们训练完系统后,它会做出一些预测。举一个例子,它总是预言人终有一死。这很有趣,因为在符号人工智能中有一个非常悠久的传统,人们一直在思考如何使用逻辑规则,如何根据现有的知识,现有的事实和现有的逻辑推断新事物[听不清 00:21:46]
蒂姆(21:46):
这真的很有趣,因为你不需要任何训练数据,对吗?所以你可以写下特定领域的事实,你可以写下特定领域的规则,然后你就可以做出推论。此外,你还有很强的保证。你知道,如果你有一个规则,告诉你每个人都会死,每次你有一个特定的人,你会预测那个人会死。如果你研究深度学习系统,就会发现有很多对抗性攻击的例子,对吗?比如说,你有一个系统,它对交通灯进行分类,你改变图像中的特定像素,预测就会不同,这显然会产生各种灾难性的后果。
蒂姆(22:31):
现在,符号系统中逻辑规则的问题是,它们不能概括你明确写下的东西。对吗?你必须写下所有你需要写下的东西,基本上,对吗?所以,给你一个具体的例子,假设你有辛普森一家,你有巴特·辛普森,荷马辛普森和辛普森爷爷。亚伯,对吧?因为辛普森爷爷。你有事实证明霍默·辛普森是巴特·辛普森的父母,阿贝·辛普森是霍默·辛普森的父母,你有一条规则规定,父母的每一个父亲都是祖父。对吗?所以现在你可以断定,实际上,亚伯·辛普森是巴特·辛普森的祖父。
提摩太书(23:15):
但那只是为了那个特定的象征,即关系的祖父。但是爷爷呢?对吗?爷爷和祖父,他们是两个不同的词,他们是两个不同的符号,所以你如何确保我们也能做出更柔和的推论?在那里,我看了很多,我想,结合了深度学习的神经表示以及符号系统的优点,所以是基于规则的系统。我们已经…是的。
耶雷米(23:44):
这是有道理的,因为你需要那种灵巧……在某种程度上,你需要为爷爷嵌入,然后你需要在那个嵌入空间附近的单词说,“哦,是的,这些可能是同义词。”这是想法的一部分吗?
蒂姆(24:00):
是的,所以我们当时遵循两个方向,一个是,你有一个工作的神经元,它试图预测给定的特定事实,就像 Bart 的祖父 Abe 一样。试图预测该事实是否是真的,并且有一些模型试图仅根据这两个实体的神经表示来预测。在这种情况下,安倍和巴特,以及关系的代表,祖父的。在那里,我们使用逻辑规则来约束或直接调整这些习得的表征,以便在未来,每当我们在神经表征中有祖父关系[听不清 00:24:42]时,我们很可能在某人的父母的父亲之间预测它。
提摩太书(24:47):
这是一项工作,另一项工作与你提到的更接近。所以这是个好主意。我是说你的评论非常好。这是 NeurIPS 在 2017 年发表的一篇论文,我们实际上采用了现有的数据锁证明系统,我们基本上把整个所谓的反向链接算法(用于序言和数据日志,老式人工智能系统)转变成了一个神经网络。那是在人们非常重视使用现有的算法和数据结构的时候,做的事情,是的,被称为神经化它们,基本上把它们变成神经网络,使它们[听不清 00:25:31]这样他们就可以做这种软比较,可以训练[听不清 00:25:35]
耶雷米(25:34):
这真有趣。所以,我发现这如此引人注目的原因之一是一个大焦点…实际上,这个播客系列的一个大焦点,也是我个人的一个大焦点,也是这个问题的人工智能对齐。只是这个想法,随着我们的智能系统变得越来越强大,越来越有效,我们需要能够向它们传达人类的价值,我们需要能够传达约束,我们不想要一个物理体现的 RL 系统或任何东西。我们不希望有一个这样的系统四处运行,对人们造成伤害,因为它是在一个分布式的环境中运行的,或者它没有考虑到一些奇怪的,敌对的可能性。
耶雷米(26:13):
这看起来就像是让我们在符号层面上交流的想法,使用逻辑,直接与神经网络交流,至少开辟了某种途径来确保,例如,你可以实际传达这样的想法,例如,不要杀人。或者类似的东西。不是说这么简单。很明显,正如你提到的,下游非常复杂。“人民”这个词将如何解释?“杀”这个词将如何解释?诸如此类。但它确实让我们和机器交流变得更容易了,在某种程度上,通过这些算法。我不严格地使用了沟通这个词,但是你是否认为它在这个外部校准问题中扮演了一个潜在的角色,让人类至少以一种更有效的方式向机器传达他们想要的东西?
蒂姆(26:59):
我认为这是一个很棒的问题。首先,我应该诚实地说,我不是人工智能对齐或人工智能安全方面的专家,所以我在这方面说的任何话都应该持保留态度。我确实相信,我们现在有新的方法来约束人工的[听不清 00:27:20]使用领域专家知识,例如以逻辑规则的形式。然而,那是假设你能以逻辑规则的形式写下所有你想教给你的人工智能系统的东西,对吗?这是一个很大的假设。我能想象出无数的场景,在这些场景中,那个简单的规则,不要杀人,对吧,是非常有问题的。我很确定,实际上,我知道人们一直在思考这种豁免。所以这是一个问题。
蒂姆(27:48):
另一个问题是,我认为我们还没有完全解决我们在多大程度上完全执行逻辑规则,在多大程度上我们希望给模型足够的自由,对吗,去了解我们生活的这个混乱的世界,对吗?如果你以自然语言为例,这里有很多混乱的东西,对吗?作为人类,我们甚至面临如此多的模糊性和问题,我们的人工智能系统或前期语言模型和自然语言理解系统仍然难以处理。所以,我确实相信我们还有很长的路要走。
蒂姆(28:32):
但与此同时,我认为在某种程度上有一些协同作用,因为这不仅仅是要确保我们的人工智能与我们的价值观保持一致,还涉及到我们如何确保我们的人工智能系统是高效的,所以这意味着,它们能快速学习以适应新的情况吗?他们能有效地探索环境吗?为此,他们也必须学会理解,我认为,自然语言,我们的意图,我们的过去和偏见。
耶雷米(29:05):
实际上,我认为有一个假设一直在我的脑海中,但没有说出来,那就是你刚才想到的最后一句话是,为什么自然语言是构建这些世界模型的如此好的候选语言?也许,我不知道,你想详细阐述一下这个想法吗?为什么一个语言模型会比,比如说,我不知道,一个在 ImageNet 或类似的东西上训练的计算机视觉模型更好?是什么让语言作为世界模型的来源变得很有前途,然后可以应用于强化学习代理,给他们一条腿,让他们不必从头开始学习这些东西?
蒂姆(29:48):
好吧,我可以给你举一个例子。再一次,这是以我之前提到的 NetHack 这个游戏为中心的,因为你也许可以使用…比如说,如果有 NetHack 的 3D 渲染,这并不…实际上,它确实存在,但是假设有 NetHack 的 3D 渲染。显然,你可以使用预先训练的计算机视觉模型来给你的模型一种什么是某些物体的感觉,对吗?也许某处有一把椅子,什么的,比如某处的盔甲。但在像 NetHack 这样的游戏中,或者在许多我认为我们在现实世界中关心的实际环境中,重要的是我们有书面的知识和程序性的文本,告诉我们如何做某些事情,对吗?
蒂姆(30:33):
net hack,维基上有很多战略指导,告诉你在某些情况下应该做什么,不应该做什么,这种知识,我们作为人类,至少可以用自然语言传达。这并不意味着自然语言是构建世界模型的最佳方式。我可以想象你可以拥有人工智能,如果它们真的很聪明,它们可能会想出各种各样的内部表示来编码世界是如何工作的,这可能不会反映或连接到我们人类的自然语言。但至少现在,这是唯一的来源,例如,我为了让代理学习网络黑客,对不对?因为在[听不清 00:31:19]中,人们一直在使用自然语言来写什么该做,什么不该做
耶雷米(31:19):
对,我想,在某种程度上,人类可以通过语言相互传递任意的知识,在某种程度上,我可以教你,或者你可以教我,任何人类可以通过书写来了解的知识。这意味着语言是这个知识图表,是这个世界的隐含模型,是人类几乎能够储存的最完整的模型。你不同意那个想法吗?
蒂姆(31:47):
嗯,我认为还有很多知识我们无法用自然语言传达,对吗?我想在某些情况下,我不得不说,“看,我可以向你演示我是如何做某些事情的,但你必须亲自体验。”我可以试着向你解释,尽管我很想解释,当我做某些动作时,不管是空手道动作还是其他什么动作,那种味道对我来说是什么样的,或者那种感觉对我来说是什么样的。但是你真的要去训练,你要自己去体验。
蒂姆(32:21):
所以,我认为,是的,公平地说,仍然有很多知识我们无法用自然语言表达或传达。但是我相信,我想,在这种推理水平上,这显然是非常[听不清 00:32:35]的术语,对吗?但这是我期望人工智能在游戏或模拟环境中能够做到的推理。我认为很多都是用自然语言传达的,对于很多游戏来说,我们有这些文本维基资源,我们应该在训练强化代理时加以利用。我还认为,从长远来看,这将使我们能够训练强化智能体,使其能够解决更多真实世界的任务,而不仅仅是这些模拟任务。
耶雷米(33:07):
也许这对你来说是一个好的长期发展。对你来说,现在正在进行的人工智能研究的目标是什么?是关于接近,比如说,AGI 的终点线吗?它是关于让我们有人工智能起飞的点,还是更多,你认为那是更远的,现在,我们只是在一系列狭窄的任务上工作?
蒂姆(33:33):
我认为这是一个非常好的问题。老实说,我不认为我是那种会说在努力创造人工智能的人。我认为有一个公开的争论,即使是人类也能在多大程度上拥有一般的智力。我们在现实中看到的是,人们在某些领域非常专业。举个例子,我可能是一个不错的科学家,但是我现在肯定不能驾驶飞机。我或许可以学会,但那显然会带来各种额外的成本,而且我在现实世界中所能学到的东西是有限的。这种想法是,我们将拥有能够完成各种任务的人工智能,我认为这是一个开放的问题,如果这是可能的话。而且老实说,我一直……我一直在努力设定相当雄心勃勃的研究目标,对吧?让代理可以在这些程序生成的环境中学习,这些环境必须以外部知识源为条件。
蒂姆(34:41):
我认为这是我们认为在一两年内不会发生的事情。我认为这是一个长期的努力,我对预训练语言模型的最新进展感到非常高兴,但我不认为这将带我们走到那一步。我认为在我们的代理人能够解决网络黑客问题之前,还有很多事情需要做。听起来很有趣,对吧?因为这是一个愚蠢的游戏。
耶雷米(35:06):
是啊。因此,我很乐意听取你的意见,因为我认为这对于这个领域的许多人来说是一个非常热门的话题。很明显,这在很大程度上是受 GPT-3 的启发。实际上,也许值得简单提一下,GPT-3 是什么,因为我们已经提到过几次了。我觉得我对这个词的使用太随意了。你介意提供一个什么是 GPT-3 的快速总结,然后也许我们可以把它联系到这个更大的图片吗?
蒂姆(35:32):
当然可以。所以,GPT-3 是一个语言模型。语言模型在自然语言处理中有着悠久的传统。例如,它们已经被用作机器翻译系统的一部分。一个语言模型基本上只是一个模型,它允许你给一个单词序列打分,它允许你给这个单词序列的可能性打分。例如,你可能想为英语训练一个语言模型,现在它可以给你一个特定的句子,语言模型会告诉你这个句子有一定的概率。你可以想象这有多有用,因为如果我有一个机器翻译系统,需要从一种特定的源语言翻译成一种[听不清 00:36:13]语言,如果我可以列举多种可能的翻译,然后我可以使用一个语言模型来评分哪一种是最好的,对吗?举例来说,这可以让你有一个很好的解码器来把它从一种特定的语言翻译成另一种语言。
蒂姆(36:30):
几年前,人们一直在使用各种语言模型的统计方法,即所谓的 MREM 模型,在大型文本语料库中计算特定单词的单字母词、双字母词和三字母词等出现的频率,然后你可以使用这些方法对单词序列进行评分。然后,再一次,我猜几年前,人们开始使用深度人工神经网络进行语言建模。以及最近所谓的变压器架构。
蒂姆(37:09):
首先,这些模型对你的词汇中的每个单词都有一个表示,基本上,在大型文本序列中,可能有 500 个左右的单词。在每一个时间点上,他们试图根据前一个单词的历史来预测下一个单词。事实证明,如果你让这些深度人工神经网络变得非常大,并且你收集了一个巨大的文本语料库,那么我们谈论的是数十亿字节的文本数据……我们谈论的是这些人工神经网络中超过 1000 亿个参数。你把这些放在一起,这样一个非常大的模型和一个非常大的高质量的文本语料库,然后你得到像 GPT-2 和 GPT-3 这样的东西。所以,真正擅长创造特定历史记号的语言模型,[听不清 00:38:04]词汇的历史产生了下一个[听不清 00:38:06]
蒂姆(38:07):
我认为真正令人惊讶的是,在 GPT-3 的情况下,你可以启动这些模型,所以你可以开始,例如,给 GPT-3 举一些例子,比如,你可以用 Java 给我编码吗,如何反转列表?然后你写下[听不清 00:38:31]列出的 Java 程序。再给它几个这样的例子,然后它就准备好了,你就可以开始用自然语言编码了。我想,你可以用自然语言进行查询,比如,你现在能数出列表中元素的数量吗?它会给你可执行的,让我们说 Java 代码为你做到这一点。这很令人兴奋,但同时,我认为,考虑到模型的整体规模和高质量文本数据的规模,这并不令人惊讶。那是用过的[听不清 00:39:00]
耶雷米(39:00):
我记得这是一个有争议的问题,大约在两三年前。在人工智能比对社区或担心缩放这些模型的人之外,你可以只是,这个所谓的缩放假设,你可以只是让模型变得更大,投入更多的计算,投入更多的数据,你不仅会得到更高质量的结果,还会从中获得更多的泛化能力。比如说,你可以从一个被美化的自动完成算法发展到现在,就像你说的,只需要相对最少的启动,就可以用 Javascript 或者别的什么来编码。我认为公平地说,它的这一方面是最近两三年的新事物,这样说公平吗?
蒂姆(39:42):
对,我认为可以这么说。我认为总有一些声音,我也是其中之一,我会说,“看,我真的不相信我们只是越来越多地缩放模型,我们只是向它扔更多的数据和更多的计算,我们会得到更令人印象深刻的结果。”但到目前为止,情况仍然是这样,我非常肯定我们将在某个时候拥有 GPT-4,这将更加令人印象深刻。所以,我想,我们还没有按下按钮,但我认为仅仅训练语言模型存在一些根本性的问题。
蒂姆(40:17):
很明显,人们已经开始把这一点拆开,研究这些模型的系统归纳能力或推理能力,对吗?举例来说,一开始,给它一个质数序列,然后你想让它继续产生更多的质数,它就是不工作,不明白,对吗?而人类,在某些时候,他们会意识到,好的,啊,这是[听不清 00:40:38]为你产生更多的质数。
蒂姆(40:41):
所以,还有很多事情要做,无论谁认为 GPD 将是我们所有问题的解决方案,并将我们直接带到 AGI,我都不同意这种说法。
耶雷米(40:56):
是的,不,这是一个有趣的观点,我听到一些人这样说,虽然不一定有希望。我认为也有潜在的担忧,因为人工智能安全研究和人工智能对齐研究还没有准备好真正适应可推广或一般水平的人类智能。关于你提到的神经网络的许多交流困难,我们不知道如何将我们想要的嵌入到这些神经网络中,如何设置我们的损失函数,使它们在道德上是一致的,等等。但是我想,我也发现了一件值得注意的事情,那就是 GPT 3 号,或者不好意思,GPT 2 号,基本上不会做加法或者很难做简单的算术加法,即使是一位数和多位数的加法。
耶雷米(41:45):
和 GPT-3,至少是它的大版本,你可以看到,当他们按比例放大时,你可以看到这些越来越大的加法和越来越多的数字的功效。我想这里有一个悬而未决的问题,在多大程度上这算是推理。但我的感觉是,我们已经在某种程度上改变了目标,潜在的是,我们在这里学到的可能更多,不是 GPT-3 比我们想象的更强大,而是可能只是人类的大脑没有我们想象的强大。也许是因为我们不仅针对参数效率进行了优化,还针对能效进行了优化。我们有各种各样额外的进化限制。飞机远不如鸟节能,但与鸟相比,它能跑得非常快。我想,不好意思,我对这个问题的一个担心是,也许我们会一次又一次地感到惊讶,GPT 4 号可能会给我们带来某种程度的能力,而我们在哲学上还没有准备好适应这种能力。在这个阶段,你认为这是可能的还是不可能的?
蒂姆(42:55):
我认为我们离那还很远。我认为,首先,你是对的,我们一直在改变目标。我们过去一直都是这么做的,对吧?我们一直在用国际象棋做这个。我一直在参加这一集的会议。我一直在有目标地做这件事,对吗?我一直在说,“看,这是超级令人印象深刻的,结果也是超级令人印象深刻的,”但是为了学习目标,你必须从现实世界中转移的东西实际上是零,对吗?有点像《我的世界》,但 NetHack 在这方面有所不同。
蒂姆(43:24):
所以我们一直在改变目标,我们将来也会这样做。我认为 GPT-4,肯定会令人印象深刻,但即使是 GPT-3,我认为如果你[听不清 00:43:34]足够长的时间,如果你用它从未见过的数字展示它,那是非常大的,对吗?如果我告诉你这两个数字,一个是一万亿左右,另一个是一万亿左右,你就能算出来,对吗?因为你可以写下一个算法,或者你可以写下一些我给你的任务的符号表示,你每次都能可靠地解决它。然而,随着 GPT-3 和 GPT-4 的出现,只要你只关注训练一个语言模型,你仍然会很挣扎。这将是令人印象深刻的,它也将有各种下游应用,对不对?
蒂姆(44:17):
这太棒了,对吧?正如我提到的,我们可以潜在地利用它们来处理文本数据,进行强化学习。基于 GPT-3 的各种有趣的应用程序层出不穷,但不知何故,我相信我们总有一天会碰壁。我不能确定,对吧?如果可以的话,我可能现在就写一篇关于这个的论文。但是我的直觉告诉我,如果我们训练这样做,如果我们集中精力,这将不会达到我们能够达到的可靠推理的水平。
耶雷米(44:57):
有意思。我想,推理的门槛也很重要,因为在某种程度上,对于那些更担心下游,甚至是与技术相关的存在风险的人来说,就像,你真的需要多少推理才能让一个人工智能系统有一些关于如何迭代自我改进的想法?目前还不清楚其中有多少是新颖的推理,因为也许在它的语料库中,有足够的信息让它进行模式匹配,直到它得出结论,或者其他什么。但我认为这是一个非常有趣的可能性空间。这也太违反直觉了。
耶雷米(45:34):
但是我要给你最后一个很难回答的问题,因为你在这个领域非常专业,如果你要猜测你需要什么技术才能与 GPT-3 这样的东西结合,打破这种模式,你会发现这种模式似乎没有你所说的推理能力。它肯定缺乏任何一种代理或内在动机。我肯定有一大堆不同的可能性,但只是问你一个不公平的问题,让你为难,你对下一步会是什么有什么想法吗?
蒂姆(46:07):
对我来说,什么是绝对不清楚的,我认为可能有很多其他研究人员已经从神经科学的角度探索了这一领域,这是我们人类能够做到的概念和符号的出现,对吗?我们想出了数学,我们能够外化我们的思维过程。如果我把它写在纸上,我就能写下一个算法,或者写下方程来解决一个特定的任务。除非我们在这些深度学习系统中有一些东西,人工神经网络,鼓励这种清晰概念的形成,然后他们可以在符号层面上进行推理,我认为我们会碰壁。因此,神经处理和符号处理的结合,我认为我们将不得不在这方面取得很大进展。
耶雷米(47:02):
那么,可以说那是你的 AGI 火警吗?如果你看到 GPT-4 展示了逻辑推理和推论的象征性水平,对你来说,会不会像这样,好吧,现在我改变主意了,现在我认为这种策略可能行得通?或者…
蒂姆(47:23):
是的,但是,这是一个很大的但是,我们仍然能够,当我们进行所有这些逻辑推理时,我们仍然能够被扔进完全陌生的情况中,并迅速适应,或者至少是理智的。我认为如果你把两者结合起来,对吗?如果你看到两者都发生了,那么,我想,是的,我会很感动。
耶雷米(47:48):
真有意思。是的,实际上,这让我意识到这也是有区别的,在…所以首先,我们对 AGI 有一个非常模糊的定义。我认为 G 才是真正让我们犯错的地方。普遍聪明是什么意思?人们谈论图灵测试是我们将要使用的东西,现在图灵测试,我认为人们可以公平地说,嗯,我们已经做出了可以通过它的系统,其中一些人假装自己是一个无能或不善言辞的人…我认为其中一个人假装自己是一个不善言辞的俄罗斯少年。
耶雷米(48:20):
所以,这就像是,一个人工智能系统可以表现得像一个不善言辞的俄罗斯青少年吗?好吧,好吧,是的,你技术上通过了图灵测试,但这到底说明了什么?但我猜这揭示了什么,至少对我来说,是 AGI 和潜在风险水平,高能力,人工智能之间的差异。这在技术上可能是狭隘的,但尽管如此,可能会带来风险。这符合你的观点吗?
蒂姆(48:47):
对,绝对是。我想,我们已经有了很多公开的、道德的问题,关于我们有能力开发的人工智能,对吗?有很多基于人的图像的人脸检测、性别检测或其他检测的例子。我们现在有能力合成高质量的人脸,对吗?也有这样的例子。你可以想象对它的各种误用。也可以想象语言模型的各种误用。是的,回到你对图灵测试的评论,我想我会很好奇的一件事…基本上,当人们问我,“好吧,我们应该用什么来测试系统的普遍智能?”
蒂姆(49:35):
我想把一位哲学家放在有这样一个系统的房间里一天,如果这位哲学家后来说,“嗯,我一整天都在进行有趣的对话”,那就是说,好吧,很明显,这个系统做得很好。需要明确的是,[听不清 00:49:52]现在的语言模型根本不具备这种能力。从表面上看,这段文字[听不清 00:49:58]如果你仔细观察细节,你会发现它非常容易被发现。什么是[听不见的 00:50:04]
耶雷米(50:05):
这看起来像是象征性的推理,那么,对你来说,这真的是圣杯吗?如果它能做符号逻辑,那么我们就有了真正有意义的东西?
提摩太书(50:13):
是的。正如我之前提到的,我想,一个人必须小心谨慎。符号推理与符号解算器和符号人工智能系统配合得非常好,对吗?所以这还不够。同时,它还必须证明这种概括和样本有效学习和分布概括
提后书(50:35):
所以两者都在一起。你必须设计,基本上测试这是不是你想要做的,对吗?您必须设计一个测试来测试这两种能力。如果你测试符号化的 AI 系统可以泛化到什么程度,比方说在飓风中间检测特定的交通标志,它会完全失败,对吗?但有些也可能是[听不清 00:50:54]人工的,或人工神经网络。我会说,你必须基本上测试这两种能力。
耶雷米(51:02):
如果这两种能力都存在,那么对于一个有这两种能力的代理人,你会说我们的道德责任是什么?你真的认为这是道德上可识别的行为吗?只为你个人。我肯定这不是你做过研究的事情,但是…
蒂姆(51:22):
是啊。我想说,我对这类问题最接近的体验是在电影《她》中,我很确定你知道这部电影。
耶雷米(51:34):
我实际上没有看过那部电影,但是抱歉,请继续。是啊。
提后书(51:38):
当然可以。在某种程度上,如果人工智能按照自己设定的意图行事,并表现出同理心和所有这些事情,对,人工和非人工之间的界限变得非常模糊,有很多科幻电影以此为核心主题。在这一点上,对我个人来说,我会发现关闭这样一个系统是非常困难的,对吗?在这一点上,你想的更多的是杀死有个性的东西,但对我来说,至少现在和在可预见的未来,这是我能说的科幻小说,对吗?看看我们最近在人工智能方面的突破,并试图推断,至少我很难在我的有生之年看到这成为现实。
耶雷米(52:35):
哦,有意思。甚至在你有生之年。所以你在这件事上有很长的时间跨度。
蒂姆(52:41):
是啊。是的,我会这么说。我认为我们可能会看到另一个人工智能的冬天,我们也会超越它,但我不认为我们会有与人类智能无法区分的东西,在不久的将来,我们会有所有这些同理心,零射击概括和符号推理的结合。是的,我认为我们谈论的是超过几十年的时间。
耶雷米(53:13):
迷人。好的,非常酷。非常感谢。我真的很感激你在谈话的最后,也放纵了一些更哲学的一面。那么,蒂姆,如果人们想关注你的工作,有没有什么地方可以让他们在社交媒体上关注你?
蒂姆(53:26):
哦,是的,我在推特上。去找蒂姆·罗彻尔。显然,你可以看看我的个人网页上的出版物。
耶雷米(53:38):
甜。是的,我们肯定会链接到下面的所有内容。Tim 在我们讨论的所有主题上做了大量的工作,所以请务必查看一下,尤其是如果你对 RL、深度学习以及我们今天在这里讨论的任何内容感兴趣的话。蒂姆,非常感谢你加入我们的播客。
蒂姆(53:51):
好的,非常感谢您的谈话。
语言战争
意见
选择数据科学语言—个人观点

马库斯·斯皮斯克在 Unsplash 上的照片
作为《走向数据科学》的一名热心读者,有一段时间我不禁注意到了关于数据科学最佳语言的争论。例如:
- 一个紧凑的比较:Julia,R 和 Python——2020 年的数据科学
- 介绍 Julia:用于数据科学的 Python 和 R 的替代品
- 【Julia 优于 Python 的 5 个方面
这只是一个简短的帖子,我对这个问题的一些想法。不幸的是,我不熟悉 Julia,因此它主要是关于使用 R 和/或 Python。
为正确的工作使用正确的工具
在我看来,一个人应该使用最适合自己需要的语言。在 R 中尝试使用 TensorFlow 简直是一场噩梦。我知道这是可以做到的,也许这与我缺乏经验有关,但安装是复杂的。此外,Python 中的文档和源代码与 R 中的相比相差甚远。至于 PyTorch,我不知道如何将其与 R 集成。如果您想开发深度学习解决方案,请选择 Python 而不是 R 。
还有,作为一个以希腊语为母语的人,我在希腊语语料库中尝试过自然语言处理的 R。这根本不可能做到。问题从编码错误到流行软件包中不存在的支持。另一方面,一些 NLP 库支持希腊语,如果不支持,也可以自己添加支持。这同样适用于其他语言。如果你有非英语的 NLP 语言,选择 Python 而不是 r。
另一方面,R 和 CRAN 使得安装库成为一个简单的过程。依赖关系破裂和版本/包冲突是非常罕见的。在这里,Python 被远远抛在了后面。此外,我还遇到过这样的情况,我可以在公司防火墙后安装 R 包,但不能安装 Python 包,尽管根据它的说法,没有一个相关的库被阻止。如果你想容易地设置和运行(尤其是在防火墙后面),选择 R 而不是 Python。
最后,有一些特定的用例,其中一个库只适用于一种语言。如果是这样的话,选择就容易了。例如,几年前,只有 Python 拥有拓扑数据分析中的 mapper 算法的包。
在罗马时
有时候,数据科学家没有选择的余地。如果你被雇佣并加入了一个使用 R 的团队,那么你将不得不使用 R。如果你开始一个项目,而只有 Python 可用,那么你将使用 Python。这听起来可能很明显,但这是你在申请职位或考虑职业道路时需要考虑的因素。如果你想加入一个使用 R 的公司/团队,那么你应该知道如何使用它。成为 Python 专家是一个优势,但这还不够!
最后的想法
在我看来,让数据科学家与众不同的是对工具基本工作原理的良好了解。一个人应该知道最常见的算法的基本理论。此外,他应该权衡利弊,以及何时选择一个而不是另一个。理想情况下,他应该有使用它们的实际经验。所以我的建议是,了解你的理论,选择一个项目,选择一门语言,把手弄脏。
套索回归教程
使用 LASSO 回归的偏差-方差评估-游轮数据集

Benjamin O. Tayo 拍摄的照片
L ASSO 回归是正则化回归的一个例子。正则化是一种通过添加额外信息来解决过度拟合问题的方法,从而缩小模型的参数值以导致对复杂性的惩罚。正则化线性回归的 3 种最流行的方法是所谓的岭回归、最小绝对收缩和选择算子(LASSO)和弹性网格法。
在本教程中,我将侧重于套索,但脊和弹性网的扩展是直截了当的。
假设我们想要在具有 n 个观测值和 m 个特征的数据集上构建一个正则化回归模型。
LASSO 回归是一种 L1 惩罚模型,我们只需将权重的 L1 范数添加到最小二乘成本函数中:

在哪里

通过增加超参数α的值,我们增加了正则化强度并缩小了模型的权重。请注意,我们没有正则化截距项 w0。还要注意,alpha = 0 对应于标准回归分析。
根据正则化强度,某些权重可以变为零,这使得套索方法成为一种非常强大的降维技术。
LASSO 伪代码
1) For given alpha, simply minimize the cost function to find the weights or model parameters w.2) Then compute the norm of w (excluding w0) using the equation below:

案例研究:使用游轮数据集预测船员人数
我们将使用游轮数据集cruise _ ship _ info . CSV来说明套索技术。
1.导入必要的库
import numpy as npimport pandas as pdimport matplotlib.pyplot as plt
2.读取数据集并显示列
df = pd.read_csv("cruise_ship_info.csv")df.head()

3.选择重要变量
在另一篇文章( 利用协方差矩阵图进行特征选择和降维 )中,我们看到了协方差矩阵图可以用于特征选择和降维。使用游轮数据集cruise _ ship _ info . CSV,我们发现,在 6 个预测特征[' 年龄'、吨位'、乘客'、长度'、舱室、乘客密度 ]中,如果我们假设重要特征的相关系数为 0 那么目标变量“乘员”与 4 个预测变量:“吨位”、“乘客”、“长度、“车厢”强相关。 因此,我们能够将特征空间的维数从 6 降低到 4。
cols_selected = ['Tonnage', 'passengers', 'length', 'cabins','crew']df[cols_selected].head()

X = df[cols_selected].iloc[:,0:4].values # features matrix y = df[cols_selected]['crew'].values # target variable
4.LASSO 回归实现
a .将数据集分成训练集和测试集
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split( X, y,
test_size=0.4, random_state=0)
b .标准化特征
from sklearn.preprocessing import StandardScalersc_y = StandardScaler()sc_x = StandardScaler()y_std = sc_y.fit_transform(y_train[:, np.newaxis]).flatten()X_train_std = sc_x.fit_transform(X_train)X_test_std = sc_x.transform(X_test)y_train_std = sc_y.fit_transform(y_train[:, np.newaxis]).flatten()
c .实施套索回归
from sklearn.linear_model import Lassofrom sklearn.metrics import r2_scorealpha = np.linspace(0.01,0.4,10)r2_train =[]r2_test =[]norm = []alpha = np.linspace(0.01,0.4,10)for i in range(10): lasso = Lasso(alpha = alpha[i]) lasso.fit(X_train_std,y_train_std) y_train_std = lasso.predict(X_train_std) y_test_std = lasso.predict(X_test_std) r2_train = np.append(r2_train,
r2_score(y_train,sc_y.inverse_transform(y_train_std))) r2_test = np.append(r2_test,
r2_score(y_test,sc_y.inverse_transform(y_test_std))) norm = np.append(norm,np.linalg.norm(lasso.coef_))
d .输出的可视化
plt.figure(figsize=(8,6))
plt.scatter(alpha,r2_train,label='r2_train')
plt.plot(alpha,r2_train)
plt.scatter(alpha,r2_test,label='r2_test')
plt.plot(alpha,r2_test)
plt.scatter(alpha,norm,label = 'norm')
plt.plot(alpha,norm)
plt.ylim(-0.1,1)
plt.xlim(0,.43)
plt.xlabel('alpha', size = 14)
plt.ylabel('R2_score',size = 14)
plt.legend()
plt.show()

我们观察到,随着正则化参数α的增加,回归系数的范数变得越来越小。这意味着更多的回归系数被迫为零,这往往会增加偏差误差(过度简化)。平衡偏差-方差权衡的最佳值是当 alpha 保持较低时,比如 alpha = 0.1 或更低。在决定使用哪种方法进行降维之前,应该将这种方法与主成分分析(PCA)进行比较。
岭回归和弹性网回归可以用同样的方式实现。更多信息,请参见以下书籍:拉什卡、塞巴斯蒂安和瓦希德·米尔贾利利。 Python 机器学习,第二版。Packt 出版公司,2017 年。
参考
- 在具有高度相关特征的数据集上训练机器学习模型。
- 使用协方差矩阵图进行特征选择和降维。
- 拉什卡、塞巴斯蒂安和瓦希德·米尔贾利利。 Python 机器学习,第二版。Packt 出版公司,2017 年。
- Benjamin O. Tayo,预测船只船员规模的机器学习模型,https://github . com/bot 13956/ML _ Model _ for _ Predicting _ Ships _ Crew _ Size。
你的标签和数据有噪音?套索叛徒!
标签噪声是训练监督算法时经常遇到的问题。了解如何使用套索叛徒来减少标签噪声( LTT )。

TL;速度三角形定位法(dead reckoning)
这篇文章发展了套索叛徒( LTT )的方法。LTT 基于外部性能度量从数据集中过滤掉噪声观测值。LTT 显著提高了基于清理数据集的估计器的性能。LTT 速度快,易于应用,并且与任务无关。
演职员表 : LTT 是我在北卡罗来纳大学教堂山分校做访问学者期间,与我的长期合著者和好朋友 Daniel M. Ringel 合作开发的。
你可以在这个Colab笔记本里找到这篇文章的可复制代码。
如果你在研究中使用 LTT,请引用这篇文章:
简介
在使用监督算法时,您会遇到数据 X 和标签 Y。我们的目标是找到一个映射 f : X → Y,它最好地概括了看不见的数据 X*。
映射函数 f 就是学习算法。该算法学习从数据将输入域 X 的值映射到输出域 Y。例如,最简单的情况是线性回归或逻辑回归。
迄今为止,如此标准。
但是,这个世界本来就乱(还是乱了更好?).如果您曾经接触过不包含在一些花哨的 API 中的数据集,您很可能会以这样或那样的方式烧伤自己的手指(我当然多次这样做过)。

这是我如何了解到的,了解到的映射的质量从根本上受到所提供标签的质量的影响。
更正式的说法是,这个原则也被称为“ GIGO ”:垃圾入——垃圾出。
虽然这种见解听起来非常平凡,但我认为它经常被忽视。
让我们只获取一些免费的可用数据,而不考虑它的细微差别,或者就此而言,错误,我们就可以走了。因为训练和调整一个算法比手动处理成千上万的观察结果更有意义和挑战性。
对数据的任何训练都强加了隐含的假设,即可用数据包含“信息”。或者至少是足以正确训练算法的信息。大部分时间可能都是这样。然而,数据中也可能存在一种特殊形式的噪声。错误,这有可能降低我们的映射功能的质量。
让我们考虑一些例子来说明这一点:
a)改编自 IMDb 情感分类数据集。
这是一部精彩的纪录片,讲述了埃尔热和他创作的丁丁的生活。
y = 0
b)改编自 IMDb 情感分类数据集。
这是一部精彩的纪录片,讲述了埃尔热和他创作的丁丁的生活。我只是不喜欢这个配乐,因为它的平淡和不恰当的演奏。
y = 1
c)改编自波士顿住房数据集。
x1 = 0.00632(CRIM)
x2 = 18.00(ZN)
x3 = 2310(INDUS)
x4 = 0(CHAS)
X5 = 0.5380(NOX)
X6 = 6.5750(RM)
y = 24.00(MDEV)
D) 5 维句子嵌入。
x1 = 1.162
x2 =-1.134
x3 = 0.105
x4 =-1.279
X5 = 0.938
y = 1
这里有点不对劲。继续阅读每个案例的分析。
这就是我们在本文中要解决的问题:使用 LASSO 回归自动检测训练数据中的错误。我们本质上是在滥用 LASSO 作为一种数据清洗方法。这种方法叫做:
LTT何TRAITORS【LTT】。

子弹躲开了!它看起来不会很酷,但肯定会有那种感觉。
标签噪音的问题
关于“标签噪声”的问题有一个完整的研究流程。见1中的调查。作者在2中将标签噪声定义为“任何模糊实例及其类的特征之间关系的东西”。1中讨论的文献基本上考虑了两种类型的标签噪声:
- 类别噪声(影响标签的观察值,Y)
- 特征噪声(影响特征的观测值,X)
如1中所述,已经开发了一大堆能够处理标签噪声的方法。出于我们的目的,我们认为这两种类型的噪声是不可区分的,因为由此产生的影响可能是以下两种之一:
- 最佳情况:标签噪声没有影响。
- 最差情况:在最差情况下,标签噪声会降低映射函数的质量,即降低分类器性能。
在我们开始对 LTT 进行实际描述之前,让我们先看看前面的例子中哪里出错了:
一)直白。只是贴错标签了。标签应该是 y = 1,因为这明显是正面评价。
B) 不那么直白。在这里,我们有一个微妙的意见,它不容易被归类为积极或消极。只是介于两者之间。将每个句子单独分类可以达到这个目的,但是我们只有一个标签。因此,这个例子可能会因其模糊性而降低整体性能。
C) 这个比较难。如果我们不知道数据规格,我们不会注意到我们在 x3 = 2.310 中遗漏了一个逗号。通过描述性分析,这一个显然可以被识别为异常值。但是很容易想到这样的情况,其中两个不同的变量在孤立时是有效的,但是在输入域中代表一个非法的,或者至少是非常不寻常的组合(年龄= 5,已婚= 1)。
D) 不可能。我们在这里无法手动找到任何东西,因为我们不知道相应的句子,这导致了嵌入。没关系,如果我们的向量 x 由五个或者一千个潜变量组成。我们盲目地强加了一个假设,即源句子是有效的和“好的”训练材料。
套索叛徒
为了解决这些例子,我提出了一个新的方法,叫做 LTT 。为什么我要把这个贴在媒体上?
- 这种方法在过去的一年里对我很有帮助,只是一些其他研究的副产品。
- 该方法简单明了且普遍适用。
- 比我所知道的一些杂志更多的人在阅读 Medium。
(*:在简短的文献研究中找不到任何东西。如果你知道 LTT 不是新的,请通知我)。
我们考虑一个元组(x d ∈ X,y d ∈ Y),一个排除变量 i d 用于观察 d 。排除变量 i d = 0 表示训练集中存在(x d ,y d )元组。如果 i d = 1,则元组被排除。
接下来,我们基于训练集定义外生性能度量 r,,它是而不是。这可能是验证数据集或更下游的性能。如果一个元组的包含对外生性能(Id= 0→r≤r+∈)和噪声)有积极贡献,如果它的包含使外生性能(Id= 0→r>r+∈)因某种贡献而恶化,则该元组被视为干净得到的排除向量I∈【0,1]^d是一个 D 维的单热点向量,并对 D 个观测值中哪些被排除(1)出训练集,哪些被包含(0)进行编码。
接下来,我们在不替换原始数据的情况下拟定了 S 个随机观测值:每个排除向量 i 是从具有参数p:It38】sb(p)∀s∈1,…, S. 的伯努利分布中随机采样的,这取决于数据大小、排除概率对于每个排除向量Is,存在相应的外部性能度量 rs 。外生性能度量是在减少的数据集上训练估计器及其随后在外生任务上评估的结果。我们假设,元组的排除独立地影响外生性能。
我们最终得到一个排除矩阵I∈【0,1]^(sxd)和一个性能度量向量 r ∈ ℜ^ S 。接下来,我们使用套索[3]和正则化参数𝜆.的一些值来回归 I 上的 r 如果训练集中的观察值 d 为套索回归的估计参数向量 𝛽 所指示的,可以用变化的𝜆s.多次重复这个过程
- 增加外生任务的性能(𝛽dt83】0),
- 降低外生任务的绩效(𝛽dt84】0),或者
- 对外生任务的表现无关紧要(𝛽 d = 0)。
之后,我们可以手动或自动干预并处理相应的观察结果。 LTT 方法的优势在于它的简单,并且它是模型不可知的。它的缺点是——你可能已经猜到了——你必须训练许多模型来获得外生性能向量 r.
我们假设,从所述训练集中移除观察值可能会影响外源性任务的执行。这种假设不一定适用于每个应用或性能指标。如果这种假设成立,则由用户来检查。
虽然 LTT 旨在过滤掉降低性能的观察结果,但是您显然可以使用该方法来调查观察结果,从而提高性能。
模拟
你可以在这个Colab笔记本里找到这篇文章的可复制代码。
为了演示 LTT 的应用和性能,我们继续进行模拟。我们用 2500 个观察值、25 个特征(其中 5 个是信息性的)和一个结果变量生成一个随机回归问题。我们将数据集分为训练集(50%)、验证集(25%)和测试集(25%)。这是我们的原始数据。训练数据集由 1250 个观察值组成。
对于训练集的结果变量 y (!),我们反转了 5%的观察值的符号,将非常简单的标签噪声引入到训练数据中。我们最终得到两个数据集:原始数据和噪声。前者包含未接触的原始数据,后者包含数据加上 y 中的标签噪声。
我们使用刀切采样(不考虑)来评估两个数据集上线性回归的性能。我们丢弃 5%的观察值,不替换,拟合回归,并评估外生性能。起泡,冲洗,重复 1500 次。我们的外生性能是验证数据的均方误差(MSE)。因此,我们最终得到 1500 毫秒。描述性结果如下所示:
- RAW:
Mean MSE = 0.04
Max MSE = 0.04
Min MSE = 0.04
Std。= 0.00 - 噪声 :
均值 MSE = 327.36
最大 MSE = 372.80
最小 MSE = 240.57
Std。= 23.23

通过改变 y,中大约 5%标签的符号,我们将平均验证 MSE 从 0.04 增加到 327.36 !(TBH:这比我预想的要多得多)
让我们继续为 LTT 创建排除矩阵 I 。排除矩阵 I 仅仅是一个具有预定义密度的随机稀疏布尔矩阵。密度表示在每次 LTT 迭代中要丢弃的观测值的百分比。该值表示每行的预期值。
接下来,我们迭代排除矩阵的行。每一行都对应于一个实验,在这个实验中我们删除了一部分观察结果。重要的是,我们存储套索的排除矩阵 I 。对于每次迭代,我们将一个任意的估计量拟合到缩减的数据集,并存储它在外生任务上的性能。
如前所述,产生的外部性能数组是我们的向量 r,。性能度量可以是任何值。你也可以使用熵、对数损失、R2 或者任何你想要的方法,只要它与任务相关并且是训练过程的外部因素。
接下来,我们使用 LASSO 在我们的排除矩阵 I 上回归外生性能 r 的结果向量。我们对𝜆 = (10e-4,10e-3,10e-2,10e-1,10e1)重复这个过程。以这种或那种方式对外生性能有贡献的观测值百分比(𝛽 ≠ 0)如下所示:

该图如下所示:对于𝜆 = 0.1,7.28%的观察值对外生绩效有积极贡献(𝛽 > 0)。相反,3.36%恶化了外生性能(𝛽 < 0). In total, 10.64% of the observations contribute to the exogenous performance.
We also see, that the percentage of observations with a positive contribution declines rather rapidly, as we increase 𝜆. This indicates, that there are probably a few observations in the training data with a relatively strong negative contribution. Recall: we inverted the sign of only 5% of the labels in the training data y. 根据图表,0.1 和 1 之间的𝜆似乎是分析数据中标签噪声的相当好的选择。
如果我们看看𝜆 = 0.1 的𝛽向量,我们会对我们的训练数据中真正发生的事情有更多的了解。记住,每个𝛽对应于训练数据集中的每个观察值 d 。

该图如下所示:排除指数为 d = 604 的观察值(i = 1),预期外生绩效 r 增加-39.23。更具体的说:排除观测值降低了验证数据上的 MSE,因为 MSE =∑ i d * 𝛽 d 。我们看到,多重观察对外生绩效有强烈的负面影响。
为了测试,如果我们正确地识别了标签,让我们执行一个健全性检查。我们根据𝛽的大小选择前 50 个系数,并将相应的指数与我们有意引入误差的标签的指数进行比较。
LTT 方法正确识别了顶部 50 噪声观测值中的 39 。显然还有改进和未来研究的空间。人们可以单独检查每个观察结果,或者编写一些定制的逻辑来进行更有效的过滤。但这取决于最终用户。
接下来,我们从训练数据中移除具有最大𝛽的 50 个观察值,并拟合新的估计量。根据新数据训练的估计器的外部性能(通过先前的刀切计算)如下:
- 噪声(用于对比) :
均值 MSE = 327.36
最大 MSE = 372.80
最小 MSE = 240.57
Std。= 23.23 - 清洁后的 :
平均 MSE = 4.75
最大 MSE = 5.61
最小 MSE = 2.25
Std。= 0.5
通过使用 LTT 从训练数据中移除噪声观测值,我们能够显著提高外部性能。

之前验证 MSE 是 327.36 ,现在是 4.75 。
满分是 0.04。然而,性能的提高已经非常显著,而且仅仅是通过从训练数据中删除了少得可怜的 50 个观察值而实现的。
复制测试数据的结果基本上复制了上面显示的结果,因此我在这里不再重复。
摘要
我们发展并实施了套索叛徒( LTT )的方法。 LTT 能够根据外部性能指标过滤掉噪声观测值。LTT 很容易应用,很容易获得,并且不知道潜在的问题。
如有疑问,请随时联系 me 。
附加说明
你可以在这个Colab笔记本里找到这篇文章的可复制代码。
如果你在研究中使用 LTT ,请引用这篇文章:
参考
- B.Frenay 和 M. Verleysen,“标签噪声存在下的分类:调查,”载于 IEEE 神经网络和学习系统汇刊,第 25 卷,第 5 期,第 845–869 页,2014 年。
- J.R. Quinlan,“决策树的归纳”,载于机器语言,第 1 卷,第 1 期,第 81–106 页,1986 年。
- R.Tibshirani,通过套索的回归收缩和选择,皇家统计学会期刊。系列 B(方法论),第 58 卷,第 1 期,第 267-288 页,1996 年。
放弃
所表达的观点仅代表我个人,并不代表我的雇主的观点或意见。作者对本网站内容的任何错误或遗漏不承担任何责任或义务。本网站包含的信息按“原样”提供,不保证完整性、准确性、有用性或及时性。






浙公网安备 33010602011771号