用 BigQuery 构建群体 A/B 检验的 K 均值聚类模型
你如何使用谷歌的数据仓库来建立同质的个人群体
马丁·桑切斯在 Unsplash 上的照片
最近,我让到建立了同质的相同规模的团队,这样我们就可以分析这两个团队随着时间的推移而发生的变化——一个团队在一个新的软件工具上接受测试,而另一个团队将继续使用通常的工具。换句话说:我的目标是将 n 个观察值划分成 k 个簇——但是我们稍后会谈到技术术语。
这里的挑战是找到一个合理的方法,可以被任何人理解,同时解决我的问题。在尝试了一个简单的方法后,我转向了 k-means 聚类机器学习模型。以下是我这样做的原因,以及如何使用谷歌 BigQuery 的内置模型解决类似的问题。
1.如何将不同的个体组成相似的群体?
我的目标是根据几个指标对人进行分类。为了简单和保密,我们假设我想创建 4 个员工小组来进行如何使用 Excel 的研讨会。我希望根据个人在以下方面的相似性来创建同质群体:
- 资历,从加入公司开始计算的天数
- 参加研讨会前对 Excel 的熟练程度,由员工自己评估,1-5 分
- 平均每天花费在电脑上的时间,以分钟为单位,由电脑自己测量(默认设置或通过安装的应用程序)
这里你可能注意到了,考虑的指标都是连续的数值变量。如果它们不在您的特定用例中,我建议您将分类变量转换成数字变量。例如,这是我对定性项目“Excel 熟练程度”所做的:通过让“我对 Excel 一无所知”等于 1 和“我完全掌握 Excel,包括 VBA”等于 5,我将定性指标变成了定量指标。
然后要克服的主要障碍是创建类似规模的群体。如果唯一的约束是将员工分成具有相似特征(但不一定是相同规模)的组,计算每个指标的中位数,然后根据他们在中位数的哪一边来划分个人就足够了。但是这种方法不一定会导致相同大小的集群,而且现实往往不像理论上的手工绘图那样容易分割。
玛丽·勒费夫尔
第二个问题是我们有两个以上的指标来评估。当只评估两个度量时,有时可以找到一个图形化的解决方案,并且可以将观察结果(这里是个人)可视化地分组到或多或少可见的集群中。然而,引入两个以上的维度使得人眼和大脑很难容易地创建相同大小并且由具有相似特征的观察结果组成的集群。
为了总结第一部分,让我展示我们将在整个示例中使用的数据集:
玛丽·勒费夫尔
2.构建解决方案:如何创建和运行 k 均值模型?
首先, k-means 聚类是一种无监督的机器学习算法,旨在将相似的数据点分组在一起。这正是我们需要的。如果您想更多地了解 k-means 聚类是如何工作的,我推荐一位作者的这篇文章,在这篇文章中,您还将通过一个使用 Python 的示例得到指导:
基本上,k-means 聚类算法将从数据集中 y 个变量的框架内的 x 个点(x 由用户预先定义)开始。从这 x 个初始点,y 个变量中就其相似性而言最接近的点被聚集到每个聚类的先前点。最终,整个多维帧被分成 x 个部分,每个部分定义相似数据点的集群。因此,k 均值聚类的原理相对容易理解——这也是我选择使用这个模型而不是另一个模型的原因之一。如果说背后的数学执行是复杂繁琐的,那么它的基本原理就相对容易理解了。
在我们的示例中,我们希望获得 4 个聚类(这是上面解释中的 x ),我们有 3 个变量(这是 y ):资历、参加研讨会前对 Excel 的熟练程度,以及平均每天花在计算机上的时间。k-means 聚类模型已经内置在 Google 的 BigQuery 中,所以没有必要重新发明轮子。让我们简单地应用下面两个步骤,正如在 BigQuery ML 文档中所描述的。
步骤 1:构建模型
为此,您必须编写一个 SQL 查询,只提取与模型相关的变量。在我们的例子中,我们希望从源数据表中提取所有的观察值(或行),我们需要前面提到的 3 个变量。
步骤 2:运行模型
既然已经创建了模型,您可以使用下面几行代码将它应用到您的数据集。我们只是排除了自动创建的列“nearest_centroids_ distance ”,因为该字段的值不应该输入到运行模型的参数中。
请注意,机器学习算法的使用在这里被大大简化了。因此,严格来说,这里采取的步骤并不对应于“机器学习”。我在这里的目标是使用强大的工具,比如 k-means 聚类算法来帮助解决一个具体的问题——这个问题也可以用其他方法来解决。我想证明的是,机器学习也适用于几乎没有工程背景的人,并且可以应用于大量案例。
3.得到答案:如何解释模型的输出?
由于 k-means 聚类是一种无监督的机器学习模型,该模型将基于数据集和您在第一步中定义的参数运行。**然后它会返回一个名为“CENTROID _ ID”**的新列。该值对应于根据模型预测将每个观察值(在我们的示例中是每个个体)分配到的分类号。
玛丽·勒费夫尔
由于每次迭代都从数据集多维空间中的不同随机点开始,建议调整模型参数以最佳拟合您的数据,多次运行模型并比较其输出。如果你想深入研究机器学习算法的世界,你甚至可以尝试不同的模型,并将其他类型的推理应用到你的特定用例中。
最终你会得到一个令你满意的观察分段。在我的案例中,我将模型给出的结果和我的实地知识结合起来,建立了研讨会的最终小组。这里最重要的部分是最终的输出符合您的需求和您的特定用例。虽然你在这里唱的是机器学习算法,但你应该始终掌握你使用的数据类型,并牢记你分析的目标。这是正确解释模型输出并将分析结果传达给第三方的关键。
玛丽·勒费夫尔
结论
最重要的是,我认为 k-means 聚类在这个特定应用中的应用是帮助您做出更好决策的方法之一。最终,你如何处理机器学习模型的输出才是最重要的。
这就是为什么当您想要复制这种方法时,这里描述的三个步骤是必不可少的:
- 设置场景——你想解决什么问题?
- 构建解决方案 —您如何构建并运行最适合您正在处理的数据的模型?
- 得到答案 —你如何解释你的模型的输出?
你喜欢读这篇文章吗? 成为会员 加入一个不断成长的充满好奇心的社区吧!
https://marie-lefevre.medium.com/membership
手动构建线性回归
由 Unsplash 拍摄的图像
入门
让我们使用 Python 来创建估计我们自己的线和验证我们的结果所需的所有方程,而不依赖于库来训练我们的模型!
W 我们基于 x 的值采用线性回归来预测 Y 的值。因为我们需要知道 Y,所以这是一种监督学习方法。线性回归分为两种类型:基本的和多重的。让我们从简单的开始。所有代码的笔记本这里是这里是。所有的方程式都是用乳胶做的。
在我们开始之前,理解线性回归是一种参数方法是至关重要的。
参数化方法:
1.它预先假定了函数的形状。
2.它将估计 f (X)的问题简化为估计一组参数。这种假设简化了任务,因为估计参数集合比使用完全任意的函数更容易。
3.这些方法中最困难的方面是做出正确的估计。我们只能猜测曲线的正确形式,从而导致错误的预测。
因此,我们必须估计参数,使我们能够创建一条最接近 Y 值的线,不管是已知的还是未知的。
简单线性回归
作者图片
这是简单线性回归的函数。这个方程的变体可以在统计文献中找到,但是它们都有相同的实质。可能是 W0 和 W1,α和β,等等。
不过,我想让你注意一件事。注意符号≈。当我们估计值时,我们的主要目标是使我们的预测接近 Y 到 x 的真实值。也就是说,我们的目标是尽可能地最小化真实值和估计值之间的差异。
因此,当处理 f (X) = Y 的估计,或者更具体地,f(X)的参数,其中 f (X) = Y 或者 Y = f (X)时,我们的目标不是完美地定义 f(X),而是估计最好地代表 f(X)的参数。但是,因为 y = ^f (X)++e,我们对 f(x)的估计将等于 y 加上 e 后的余数。
其中 Y = ^f (X) + e ,则^f (X) = ^B0 + ^B1X = Y.也就是说,为了估计Y,首先要估计^f (X)、^B0、B1 的参数。Y = ^Y + e 既然 Y = ^f (X) + e 和^f (X) = ^Y.
考虑到这一点,我们将使用的公式是:
作者图片
不再分心。
什么是 B0 和 B1 ?
BO 表示截距,即 X = 0 时的 Y 值,或线性回归线开始处的 Y 值。这里有一个例子。我们希望根据活动中的投资金额来估计销售转化的数量。不投钱能卖多少?
B1 呢?斜率由 B1 的值表示。基本决定了趋势线。这在实践中是如何运作的?考虑根据体重计算身高的例子。身高以厘米为单位,体重以公斤为单位。我们发现斜率为 2.5。表示体重每增加一公斤,人的身高就增加 2.5 毫米。
假设我们知道 B0 和 B1 是什么,我们如何估计它们呢?这些参数可以用多种方法来估计。首先,让我们看看普通的最小二乘法(OLS),这是最常见和最简单的方法之一。要估算 B0,首先要估算 B1。
在统计学中,普通最小二乘法 ( OLS )是一种估计线性回归模型中未知参数的线性最小二乘法。OLS 通过最小二乘法原理选择一组解释变量的线性函数的参数:最小化给定数据集中观察到的因变量(被观察变量的值)和自变量的线性函数预测的变量之间的差的平方和。—来源:维基百科。
让我们看看这意味着什么。我们想用这种方法达到什么目的?减少一些东西。应该尽量减少什么?观察数据和估计数据之差的平方和。让我们把这个等式放在一起。
反过来,我们有观察值和估计值之间的差异。作为回归结果的估计值称为估计值。观察值是真实值。因此,
observedValue - estimatedValue
现在,平方估计值和观测值之差。因此:
square (observedValue - estimatedValue)
最后,观察数据和估计数据之间差异的平方和。:
sum (square (observedValue - estimatedValue))
好的,但是这个和的意义是什么?observedValue 和 estimatedValue 是值。考虑一下:我们有两列,Y 和 Y。第一列是真实值,观察值,第二列是估计值。正如我之前提到的,我们构建了一个模型,并利用 X 来估计 Y,从而得到 Y。假设每一列都有三个值,Y = [5,9,2]和 Y = [6,7,2]。使用我们的公式,我们得到以下结果:
(5–6)²
(9–7)²
(2–2)²
总数是这三个操作的总和。结果是,(5–6)+(9–7)+(2–2)。作为这些程序的结果,我们得到了残差平方和(RSS)。这种情况下使用 RSS = 5。我们的目标是使用 OLS 来减少 RSS。
RSS 的一般公式是:
作者图片
我们如何用 Python 来编码呢?
OLS 是减少这种 RSS 的众多方法之一。另一种做法是,我不知道,猜测 B0 和 B1 的各种参数,计算所有的误差,选择最小的一个,但是发现的最小的误差可能没有那么微小。我们将以这样的方式结束。当我们有少量的功能和列时,OLS 是最快捷和最容易使用的方法。
我们将在文章中使用虚构的数据。
在本例中,我制作了两个数组来表示 X 和 y。我创建了 1000 个值,以便提供一个更有趣的视角。我把 X 和 Y 分成四份。训练数据将包含 80%的 X 和 Y 值(X 训练和 Y 训练),而 20%的数据将用于测试(X 测试和 Y 测试)。
在估计 B0 和 B1 之前,我们先讨论一下假设。线性回归的基本假设是什么?我们利用线性回归来预测新值或做出推论。有许多方法可以估计回归中的参数。许多方法,如 OLS,需要特定的假设,以使他们的结论尽可能准确和公正。这些前提不必在每个线性回归中都严格遵循!
因变量和自变量必须有线性关系。
当使用线性回归进行预测时,满足这一要求是合乎逻辑的。本质上,线性回归将通过数据画一条直线。如果数据没有线性关系,模型就无法处理数据的复杂性。我们如何检验这个概念?
在大多数假设下,有两种形式的确认。有图形确认,也有数学确认。只要可行,我将同时介绍这两种方法。当事情变得太复杂时,我就只覆盖视觉效果。
所以我们可以把 X 数据和 Y 数据对应起来,寻找趋势。让我们执行这个命令,看看会发生什么。
plt.figure(figsize=(10,10))
plt.scatter(X_train, y_train)
plt.show()
作者图片
对我来说,它似乎是线性的!我甚至能看到一条直线!但是这有什么意义呢?我不确定你,但视觉确认并不能完全满足我。当然,你的视角是由你的时间、金钱和教育决定的。然而,我们在这里拥有世界上所有的时间,它是免费的,我们有足够的知识来使用替代方法。
除了图表,我们如何评估线性关系?计算 X 和 Y 之间的相关系数。但是这种相关性到底是什么呢?
在统计中、相关或相关是两个随机变量或二元数据之间的任何统计关系,无论是否为因果。从最广泛的意义上来说,相关性是任何统计关联,尽管它通常指一对变量线性相关的程度。依赖性现象的常见例子包括父母及其子女的身高之间的相关性,以及商品价格和消费者愿意购买的数量之间的相关性,正如所谓的需求曲线中所描述的那样…—来源:维基百科。
在这个简短的解释之后,我将重申一个统计学家的口头禅:相关性并不意味着因果关系!在我们对因果关系做出明确的判断之前,我们需要进行一些统计测试。但这是另一天的话题!
在我们的数据中,我们希望计算 X 和 y 之间的相关程度。有各种方法来解决这个问题。皮尔逊系数是最常用的。其通式如下:
作者图片
也就是说,两个变量的标准差除以它们的协方差。让我们把事情分解一下,这样你能更好地理解它。我们将看两个部分。X 相对于 Y 的协方差,以及 X 和 Y 的方差。我将把这些信息留给方差的概念,其中包括一些图形解释。绝对值得一看。总之,协方差表示两个变量协同波动的程度。
在 Python 中我们如何计算两个变量的协方差?让我们用这个公式:
作者图片
仅此而已!样本的标准差是多少?随机变量的标准偏差是对其围绕总体均值的离差的度量。低标准偏差意味着数据点经常接近平均值或预期值。较大的标准差意味着数据点分布在较大的数值范围内(维基百科)。方差的平方根也是标准差。让我们使用 Python 通过利用方差公式并计算其根来创建我们的标准差公式:
作者图片
我们先来看看标准差。
如你所见,我们利用方差公式来寻找问题的根源。我们现在可以使用皮尔逊系数。让我们从原始公式开始,并从那里创建我们的函数:
作者图片
鉴于我们已经完成了一半以上,让我们进一步简化这个公式:
covarianceOfXY / StdX * StdY
让我们看看我们的数据结果如何。
The Pearson Correlation Coefficient between X and Y is [0.98478235].
而皮尔逊系数的意义是什么?皮尔逊系数是一个介于-1 和 1 之间的数字,1 和-1 表示完全线性相关,0 表示不存在相关。完全正相关是 1,而完全负相关是-1。
理想的价值观应该是什么样的?这是有条件的。有时 0.7 的相关性是最佳的,而其他时候 0.9 是不够的。这将取决于你的问题的性质。在多元线性回归中,您可以使用皮尔逊系数来查找模型中最重要的因素或排除相关变量。
现在我们已经确定了一个假设,让我们开始估计参数。
B0 和 B1 将使用 OLS 公式进行估算。以下是方程式:
作者图片
这么看,有点难,lol。但是,实际上,这很容易。让我们从 B1 开始:
作者图片
如前所述,B1 是 X 和 Y 之间的协方差除以 X 的方差。B0 只是 X = 0 时 Y 的值,考虑了 Y 的中值与角度系数和 X 的中值的乘积之差。
我们用 Python 估算一下 B0 和 B1?
因为我们在训练和测试中划分数据,所以我们的 X 和 Y 将是我们的训练 X 和 Y,是时候估算了!
Intercept: -4.959319577525191,
Slope: [2.00341869].
换句话说,我们的线从-4.9593 开始,x 每增加一次,线就前进 2.003。现在我们将这些参数应用到新数据中,看看我们的预测结果如何!现在是时候建立我们的线性回归了!
因为我们之前分离了我们的数据,所以我们现在可以测试和评估我们的模型了!
y_pred = predict_function(b0_coeficient, b1_coeficient, X_test)
之后呢?现在是时候设计我们的返程路线了!
plt.figure(figsize=(8,6))plt.scatter(X_test, y_test, color='blue')plt.plot(X_test, y_pred, color='red', linewidth=2)plt.title("Linear Regression Demonstration", fontweight="bold", size=15)plt.show()
作者图片
看来我们的回归很顺利!
自然,线性回归线永远不会到达所有点。或者,至少,如果他们是正确的,如果模型的意图是将其推广到新数据,这将不是一件好事。这是因为每个线性方程都有误差。
此刻,我们将加入我们等式的最后一个部分,关于它我们已经说过了。错误。
作者图片
误差是 y 的预测值和实际值之间的差值。误差的成本可能是多种因素的结果。有时是你没有考虑的单一变量,而其他时候你假设了现实中不存在的线性关系。
另一个原因可能是数据短缺。由于数据如此有限,你的估计可能无法揭示问题的真正本质。首先,有几种方法可以减少错误。你可能会寻找更多的数据,选择一个非参数或线性模型,并添加更多的变量。策略不同,将由您的评估决定。寻找更多的数据要花多少钱?值得寻找进一步的信息吗?测试另一个模型需要多长时间?专业工作时,你应该问所有这些问题。
有限制吗?是的。称之为不可逆转的错误。不可逆误差是随机的,根据定义,不能测量或观察。我们会给你带来我们的新方程,我会给你解释的。
Y = ^f(X) + e
当然,我们已经完成了第一阶段,并估计了 f(X)的参数。为了有助于理解,我们采用线性回归来确定或预测给定一定量的辉瑞疫苗应用于小鼠的一小时内的平均心跳水平。
但是,该错误尚未提交,也不会提交。为什么会这样呢?我们猜测你昨晚回家很晚,很累,睡了一夜。同一天晚上,你的一只老鼠皮图被马金奥斯拴住了。Pitu 和 gaiola 里的其他老鼠一样,变得极度紧张。幸运的是,没有人受伤。皮图第二天想跟你说委屈,但是因为你不和动物说话,所以你不知道发生了什么。
Pitu 的压力水平被发生的事情和你不明白发生了什么的事实所改变。压力水平是你的结果中的一个重要变量,但你忽略了 N 个原因,其中之一是你不会说“mouseguese”。
另一只小老鼠玛格达莱娜很孤独,没有人和她说话或一起玩。当你出去的时候,其他人有一个聚会,但是玛格达莱娜留在她的角落里,沉思她的悲伤。你很可能无法识别抹大拉的悲伤,因为你没有主修老鼠心理学。这个你无法测量甚至看不到的变量,在评估抹大拉的结果时将是至关重要的!
你明白我的意思吗?有些因素对于你的分析来说是不可观察或不可收集的。
你应该感到奇怪,但这是什么错误,为什么我相信我在哪里听到过?你在上面看到了它,但是它有一个不同的名字:RSS。我们会计算模型的 RSS 吗?
print(f'The RSS is {get_rss(y_pred, y_test)}.')# The RSS is 191.16066429.
有了这个数字,我们可以想办法减少它。但这不是今天的议题!我提到这个错误是有原因的。线性回归的第二个前提。
残留物必须以规则的方式分布。
为什么会这样呢?关于为什么这个假设应该被证实,以及当它不满足时会发生什么,即使它是必要的,有几个争议。由于这些都是非常技术性的问题,所以我不会在本文中讨论它们。
我们如何知道一个数据分布是否正常?有两种类型的图形:图形和数学。我将在这部分使用图形。如果我们想检查所有剩菜的行为,我们不能使用 RSS,因为 RSS 查看剩菜的总和,但我对剩菜的总和不感兴趣,而是对单个剩菜感兴趣。
还记得一开始的注册吗?我们来看公式 Y = ^Y + e,要计算残差,只需将 y 从左向右切换,结果为:y ^y =e。
e =观察值—估计值
很简单,用 Python 来说:
residual_lr = get_residual(y_test, y_pred)
因此,我们将有一个剩菜阵列。我们会使用直方图来检查它们的分布吗?
plt.subplots(figsize=(12, 6))plt.title('Distribution of Residuals')sns.distplot(residual_lr)plt.show()
作者图片
这看起来是正态分布,尽管有点不对称!有没有另一种方法可以从图形上确认这是一个正态分布?有,有!它被称为 QQPlot 图!
lst = []
for i in residual_lr:
for n in i:
lst.append(n)sm.qqplot(np.array(lst), line='45', fit=True)
plt.show()
在这段代码中,我从一组数组中提取了值,并将它们放在一个列表中,供我们的 QQPlot 验证!你有它!
作者图片
这到底是什么我从来没见过的东西?你可能会好奇。我不会花太多时间去概念化 QQPlot,而是去解释它。如果你有兴趣了解更多。
从一个 QQ 情节中我们可以得出什么结论?我们有一条红色的直线和一个蓝色的残差离差。我们可以使用 QQ 图来可视化我们的数据分布。如果它们完全沿着红线,我们就有一个完美的正态分布。我们的数据离这条直线越远,正态分布特征就越少。为了更好的理解,你可以在这里找到可视化的解释。
基于这一可视化,我们得出结论,我们的废物有一个典型的分布,尽管一些点远离中心。
有几种统计检验可以确定分布是否正态,如夏皮罗-维尔克检验。但是现在,我们只要坚持视觉化!我们正前往下一站。
残差的方差应该是常数
线性回归模型在很大程度上依赖于同方差的前提(即“恒定方差”)。同方差定义了一种情况,其中误差项(自变量和因变量之间关系中的“噪声”或随机扰动)对于所有自变量值都是相同的。
当误差项的大小在独立变量值之间变化时,就会出现异方差(违反同方差)。违反异方差假设的影响与异方差的程度成正比。
这对我们有什么意义?当我们使用 MMQ 时,我们给所有的 X 值相同的权重。如果某些 X 值比其他值有更大的影响,我们就有问题了。
考虑基于家庭收入的奢侈品购买估计。我们有贫困的家庭,他们不买或者只买一些奢侈品。如果奢侈品的购买随着家庭收入的增加而增加,我们就会有一个恒定的方差。但假设只有一部分富裕家庭购买奢侈品,而其他人购买相对较少:我们有异方差的问题。
你还记得 B1 公式吗?X 值的方差在除数部分计算。因为 OLS 为 X 的所有变量提供了相同的权重,所以很大的变化会造成阻碍!
我们如何才能看到这一点?让我们使用 Python 吧!让我们从视觉表现开始。我们将根据预期值绘制残差图,以观察误差的变化。
plt.scatter(residual_lr, y_pred)
plt.show()
作者图片
老实说,我无法从这张图片中得出任何结论!这些点上似乎没有任何图案。那么,我们要测试一下吗?
H0 = homocedasticity
H1 != homocedasticityalpha = 0.05
让我们为此使用 statsmodels.stats 库!
print(sm.diagnostics.het_goldfeldquandt(residual_lr, y_pred))Test: 1.0206718127917291
p-value: 0.45956295321355667
我们不能因为α< p 值而拒绝零假设,因此我们不能否认同方差的存在!
咻!我们的模型确认并通过了所有的假设!你很可能在想“我们现在可以走了吗?模式太神奇了!”。如果你想利用模型来分析变量,你可以放松一下。你可以明天开始检查,看看是否能从中得到什么。如果你想利用这个模型来做预测,我们只是成功了一半!
现在是时候评估我们模型的可推广性了!如您所见,我们的模型在盯着测试数据方面做得很好。但是有多好呢?我们如何评估我们的模型?使用度量标准!
对此有多种测量方法。其中之一是 R 平方,通常称为决定系数。R2 是一种度量,它表示模型可以解释多少数据变化。换句话说,这个度量计算回归模型可能预测的方差的比例,因此向我们显示实际度量与我们的模型有多“接近”。它表示响应变量中可由预测变量或解释变量解释的可变性的比例。
它的 R 平方值从 0 到 1 不等,0 表示最差的估计值,1 表示最好的估计值。它通常用百分比表示。例如,R2 = 73 %表明模型可以解释我们数据中 73 %的波动性,而剩余的 27%理论上是剩余方差。
有可能出现负的 R 平方吗?是的,当你的模型有能力比所有 Y 值的均值更差的时候。
R2 公式到底是什么?让我们再看一遍我们的 RSS 公式。我们会根据它来改变它。我们有 RSS 中残差的平方和。然而,我们希望计算残差的总平方和。
在 RSS 中,我们取 Y 的每个观察值和估计值之间的差,或者 Y,对其求平方,并添加结果。在 TSS 中,我们计算 Y 值和 Y 平方平均值之间的差值。也就是说:
TSS = sum ( ( valuesX — meanY))
R2 基本上是:
1 — (RSS / TSS)
rss = get_rss(y_pred, y_test)
rst = rst_metric(y_test)print(f'The R2 of the model is {get_r2(rss, rst)[0]*100}%.')
该模型的 R2 达到了 97.177738738677
这意味着,我们的模型能够解释近 97.18 %的数据!该模型似乎可以推广到新的数据!
r 平方也可以通过平方皮尔逊系数来计算:
print(0.98478235 ** 2)# 0.969796276871522
你想知道如果你取平均值,R 的平方是多少吗?我们一起来看看吧!让我们做一个和 Y 一样大的列表,但是用 Y 的平均值代替。
plt.figure(figsize=(8,6))
plt.scatter(X_test, y_test, color='blue')
plt.plot(X_test, lst, color='red', linewidth=2)
plt.title("Linear Regression Demonstration", size=15)plt.show()
现在,让我们来计算 R 的平方:
rst = tss_metric(y_test)rss = get_rss(lst, y_test)print(f'The R2 of the model is {get_r2(rss, rst)[0]*100}%.')
模型的 R2 为 0.0%。
还记得我说过 R 的平方可以小于 0 吗?RST 以上的 RSS 越大,R 的平方就越低。
然而,问题依然存在。估计线性回归的另一种方法是什么?好吧,我会迅速找到一个合理的策略。
这背后的解释如下。我们先挑 100 个截距和 100 个斜率值,然后测试 10000 个线性回归,比较一下,挑 RSS 最小的组合。我们开始吧!
这里我们运行 10,000 次回归。我们要不要计算得到最小的 RSS?
min_index = rss_list.index(np.min(rss_list))print(f'The lowest RSS is: {np.min(rss_list)} with index {min_index}.')# The lowest RSS is: 190.52186974065032 with index 4552.
与使用 OLS 相比,我们使用这种变通方法得到的 RSS 要小一些!用这个指数在测试数据上画出我们的回归线。
plt.figure(figsize=(8,6))plt.scatter(X_test, y_test, color='blue')plt.plot(X_test, linear_reg[min_index], color='red', linewidth=2)plt.title("Linear Regression Demonstration", size=15)plt.show()
作者图片
R 的平方呢?
rst = tss_metric(y_test)rss = get_rss(linear_reg[min_index], y_test)print(f'The R2 of the model is {get_r2(rss, rst)[0]*100}%.')
# The R2 of the model is 97.18512940329813%.
正如你所看到的,这种差异可以忽略不计,几乎不存在。而使用 MMQ 方法我们得到 97.175%,这里我们得到 97.185%。
到此,我们将结束我们的文章!我试图通过理解五六行代码背后的东西来解决创建线性回归的最重要的方面,这些代码足以完成我们在这里讨论的所有事情。
剩下的问题是:是否需要检查所有这些?有没有另一种方法可以在不经历所有这些的情况下获得一致的结果?我现在想做的就是完成 Kaggle 的巨大线性回归。我真的有必要这样做吗?这是一场激烈的辩论!这里可以找到一些水花。但请记住,作为一名数据科学家,你必须解决问题,并向你的同行展示你的发现。
当你处理真实数据的时候,不会像这里的那些可爱,而是需要解决问题!
参考资料:
homscedastidade——应用统计中心。https://estatistica.pt/homoscedasticidade/>。Acesso em: 24 套。2021.
测试正态分布和方差分布。disponível em:<https://Bio statistics-uem . github . io/Bio/aula 8/test _ normalidade _ homocedastidade . html>。Acesso em: 24 套。2021.
HOW,你能给一个只懂均值的人解释一下协方差吗?你将如何向只懂均值的人解释协方差?disponível em:<https://stats . stack exchange . com/questions/18058/how-would-you-explain-co variance-to someone-someone-who-understand-only-the-mean>。Acesso em: 24 套。2021.
DAMACENO,l .**entendendo regresso linear:as suposis por tras de tudo!**disponível em:<https://medium . com/@ lauradamaceno/entendendo-regression % C3 % A3o-linear-as-suposi % C3 % A7 % C3 % B5es-por-tr % C3 % A1s-de-tudo-d0e 29004 C7 f 8>。Acesso em: 24 套。2021.
SHRUTIMECHLEARN.逐步假设—线性回归。可在以下网址查阅:<【https://www . kag gle . com/shruteimechlar/分步假设线性回归】 >。访问时间:9 月 24 日。2021.
蒂托。scikit-学习还是状态模式?评估我的回归模型。可在以下网址查阅:<【https://nathaliatito . medium . com/scikit-learn-or-state models-asserting-my-return model % C3 % a3 % a3-3o-F4 c04 b361 fa 7】>。访问时间:9 月 24 日。2021.
使用 Python 的多行回归。可于:<https://ichi . pro/pt/return au-multiline-using-python-75787662189>查阅。访问时间:9 月 24 日。2021.
米兰达修女。 19 线性回归|基本生物统计。可查阅:<【http://www . lamp . uerj . br/db/_ book/regret % C3 % a3 % a3-o-linear . html # straight>。访问时间:9 月 24 日。2021.
构建医疗保健提供商将使用的机器学习模型。
图片由 安德里亚·皮亚卡迪奥 来自 像素
当我第一次学习如何创建机器学习模型时,我所有的注意力都放在算法选择、交叉验证和超参数调整上。我应该对我的连续变量使用哪种缩放技术?我应该优化 AUC、精度还是召回率?我的极端离群值可以被 winsorized 吗,还是应该被删除?但事实证明,使用我们的机器学习模型的人根本不在乎技术术语。为什么琼斯博士和她的工作人员必须学习什么是 ROC 曲线,才能知道他们的病人有多大可能在医院得到缓解?
好吧,经过几个月的建模、思考和与临床提供者的互动,我得出了一个简单的结论:他们不应该!由数据科学家将模型转化为他们关心的见解。但是还有更多。让提供者仅仅理解机器模型的输出是不够的。除非护理团队信任并使用该模型,否则我们的工作不会产生任何影响。
事实证明,从“我的 ROC-AUC 是 0.8759”到“提供商定期从我构建的模型中获得价值”是一条充满各种意想不到的曲折的道路。在这篇文章中,我将分享我为实现这一目标所学到的一切。
我的旅程
首先,我将分享一些导致这篇文章的项目背景。大约一年前,我的任务是建立一个机器学习模型,预测癌症患者在 90 天内死亡的可能性。正如我从与肿瘤学家的多次互动中了解到的那样,我们试图避免的结果是,一名癌症晚期患者在重症监护室接受化疗的最后几天里,只能离开人世。一个更人道的结果是,这些病人被识别出来并被安置到临终关怀中心,这样他们就可以在家人的陪伴下舒适地结束他们的生命。付款人还激励肿瘤诊所增加临终关怀,作为基于价值的肿瘤护理计划的一部分。
我参与了这个项目从概念到试点的整个过程,我非常自豪地告诉大家,我们的死亡率预测器在全国多个肿瘤诊所得到了积极应用,并对患者护理产生了影响。目前正在研究这一影响的程度。
但是在“构思”和“试验”之间有一段旅程,因为通常感觉需要英雄主义来将这个项目的概念转化为有价值的东西。我知道有很多教训,我当然希望我在开始这个项目时就知道,在这篇文章的其余部分,我将分享它们。
第一课:阅读文献
如果你正在建立一个临床模型,可能会有许多同行评议的论文与你的项目相关。阅读这些论文,了解哪些变量具有最强的预测能力,模型达到的性能水平,以及最成功的算法。你会得到一些很好的想法和基准,可以用来比较你的结果。与你的利益相关者分享和总结同行评议的文献将有助于你提高自己工作的可信度。
第二课:建立你的临床咨询小组
一开始就建立你的临床顾问团队。不必是一大群人(2-3 人就可以了),你也不必同时会见所有人。理想情况下,他们是愿意和你一起深入探讨本质的数据书呆子。不要被医生吓倒——你会发现有些医生很感兴趣并想提供帮助。您还应该根据需要咨询护士、高级实践提供者(app)和实践人员。临床协作是建立推动采用所必需的信任和可信度的基础。这个过程必须从项目的最开始就开始。
第三课:用初学者的心态看问题。
在你启动你的 Jupyter 笔记本之前,问问你自己——我在试图解决什么问题?我使用的是正确的基本人群吗?我的预测是否正确?我的模型需要什么样的表现才有意义?走出去,采访你的临床医生和实习人员。你可能最终会改变你的基本人群,你的特征,甚至你的标签。不要认为你在以前的项目或工作中所做的会自动应用到这个项目中。要谦虚。用一个开放的“初学者的思维”去解决你遇到的每一个问题。
梅奥诊所有一个非常有启发性的案例研究,是关于一个叫做 SWIFT score 的预测再入院的模型。临床工作人员不太使用 SWIFT 评分,梅奥诊所停止了该项目。原因之一是:
“当我们看到对 SWIFT 评分预测算法贡献最大的患者特征时,我们立即发现一个问题——这些特征中没有一个是容易修改的,其中一些是绝对不可修改的!当临床医生得知一名来自疗养院的长期住在 ICU 的患者有再次入住 ICU 的高风险时,应采取什么措施?大多数人会很快丢弃这些信息,并在停止使用该工具后很快丢弃。
通过将 SWIFT 评分与再入院风险预测进行校准,我们挑选出了在床边不可操作的信息。更成功的方法可能是校准 SWIFT 评分,以确定可修改的临床特征,如果采取行动,将降低再入院的风险。”(维塔利·赫拉塞维奇&布莱恩·皮克林。健康信息技术评估手册。CRC 出版社,2018 )
多么不可思议的学习!他们有一个很好的模型,但是模型预测不可行。如果你没有从一开始就开始临床合作,你可能会像这个案例研究一样结束。
第 4 课:明确临床工作流程。
在进行访谈和背景研究时,明确说明实践或护理团队将如何以及何时使用您的解决方案。谁啊。怎么会?什么时候?对于如何从一开始就将你的模型插入到临床工作流程中,有一个可行的假设是至关重要的。这个假设将影响你如何开发你的模型和最终产品。
此外,当需要向一些试点实践/团队推广您的工具时,您必须能够建议这些工作流。例如,它会被纳入每日或每周的“会议”中吗,它会在护理点使用吗,它会被分诊护士使用吗,等等。你可能是错的,或者他们可能会做一些完全不同的事情。但是,如果你没有一个计划,他们可能会失去兴趣,根本不会使用你的模型!
第五课:建立你的“变革理论”
我曾经上过一堂发人深省的研究生课,讲的是创造健康行为改变干预。当我们提出行为改变干预的想法时,有人问我们——你的改变理论是什么?同样,如果你建立一个临床决策支持模型,比如预测患糖尿病的可能性、死亡风险等。—需要发生什么行为才能使该模型产生影响?
例如,在死亡率模型的情况下,我们假设我们的工具将导致临床医生和实践人员与他们的患者进行更多关于临终关怀和提前护理计划的对话,这将导致更高的临终关怀率。如果我们的试点项目未能影响临终关怀率,我们可以评估问题是否与模型的准确性、工具的设计、工作流程或变革理论有关。
同样,你的目标不是模型。你的目标是创造影响力。让这种想法占主导地位。
第 6 课:预计要花很多时间清理数据。
电子病历数据是有问题的,因为它是不完整的,充满了错误,并受到奇怪的离群值的困扰。如果你认为你能在 3-4 个月内建立一个模型,你就大错特错了。我们从熟悉数据的数据分析师和工程师那里得到的最佳建议是留出 3-4 个月的时间进行数据清理。
根据您的团队的成熟度,您可能需要花几周时间与数据工程师一起工作来找到您需要的表以及如何连接它们。使用实验室值时,您可能会发现一种实验室类型使用了许多不同的名称!你会看到字符串和数字混杂在几乎所有的数字字段中,每个变量都有极端的异常值。手动输入的数据,如身高和体重,将更是一场灾难。但是振作起来。你可以克服所有这些挑战,并在未来的项目中利用你的工作。
第 7 课:在数据清理和探索期间,定期与指导老师一起检查你的工作。
一旦你清理了显而易见的东西,就创建数据的分布图或条形图,并展示给你的临床顾问团队。检查你所有的假设是至关重要的。我建议每周或每两个月定期召开会议,向您的临床顾问和其他专家展示您的清洁方法和数据探索,以获得反馈。
这里有几个具体的例子。您知道您的实验室和生命体征有异常值,因此您应用标准的异常值剔除技术,如 winsorizing 或 IQR 方法。向您的临床医生顾问展示您的新数据分布,询问他们临界值是否在临床上有效。或者,也许你正试图以一种看起来非常逻辑和明显的方式将某些类型的治疗或诊断分组——将你的工作展示给能够验证该假设的人。什么都不要假设。你不知道那些数据表里潜伏着什么奇怪的怪癖!
第 8 课:将您的模型结果转化为您的利益相关者关心的指标。
当我说公司的业务或临床部门没有人关心您的 AUC 时,我说的是实话。(AUC 是评估模型的标准指标。)F1、精度、召回、对数损失、平衡精度等等也是如此。这些指标没有任何直观意义。因此,不要用复杂的表格、难以理解的图表和数据科学术语让非技术观众感到厌烦和困惑。(将这些幻灯片放在附录中,供您的数据科学家同事参考!)
他们关心的是你的模型在未来数据上测试时是否能产生稳定的结果。他们关心的是他们是否能信任这些结果,以及你的结果与科学文献相比如何。如果您生成一个高风险列表,讨论列表的准确性比使用技术术语 precision 更直观。
第九课:信任需要透明
为了与临床医生建立信任,您必须为模型及其验证提供透明度。如果这些模型要影响病人的护理,那么就需要高度的信任。我认为选择可解释的算法通常是一个好主意,比如逻辑回归或广义加法模型,这样你就可以确定模型对单个患者进行预测的原因。
为了患者的安全,我认为临床使用的每个模型都应该附有用于训练模型的患者人群、预测变量、模型的性能、验证方法和模型的局限性的信息。如果你想看一个透明性的例子,我认为这个 MDCalc 做得非常好。
第十课:评估模型的偏见和公平
人工智能中的偏见和公平是一个需要一整个系列博客文章的主题,所以让我在这里总结一下主要思想。模型对历史数据进行学习,因此,它们将把过去的歧视模式投射到未来。例如,一个训练有素的用于预测高风险患者的医疗保健成本模型不太可能识别出资金和医疗保健服务较少的贫困患者,从而无法为这些患者提供他们需要的额外护理。(https://un dark . org/2020/07/27/ai-medicine-race-bias-新冠肺炎)比较模型在性别、种族和其他健康的社会经济决定因素方面的表现是一个很好的做法,作为识别潜在偏见或伤害领域的起点。
第 11 课:参与推广和采用。
最后,不要止步于模型开发!参与工具的设计、试点项目的推广和采用流程。准备好向利益相关者陈述并回答问题。毕竟这是好玩的部分。看着你的模特“宝贝”长大,走向世界。无论这种模式是成功还是失败,从中吸取的经验教训都是无价的。
我希望这篇文章能激发读者思考新的方法,将你的工作从机器学习模型转变为现实世界的影响。我很想在下面的评论中听到你的想法。
使用图表技术构建 Python 项目的地图-可视化您的代码
使用 Neo4j 计算安全分数——您的代码有多安全?
作者图片
作为一名数学家和工作数据科学家,我着迷于编程语言、机器学习、数据,当然还有数学。
这些技术、艺术和工具当然对社会非常重要,当你阅读这篇文章时,它们正在改变我们的生活,但另一种新兴技术正在成长。而且增长很快!
这是一项基于我在大学学习的数学领域的技术,也是第一次被发现(或发明…?我们下次再谈吧,好吗?伟大的莱昂哈德·欧拉给了他一个挑战,当时没有人知道如何解决。
这个挑战是关于一个潜在的形状或结构,以相关事物的形式存在——关系。
欧拉需要一种工具来研究关系和结构,在这种关系和结构中,某些物体之间的距离并不重要,重要的是关系本身。
他需要并发现了现在被称为数学图的东西(或简称为图)。
这就是图论和拓扑学的诞生。
快进 286 年…
发现高层结构
不久前,我在一个包含数百个 Python 类、方法和函数的存储库中从事一个相对较大的项目(工作中),所有这些类、方法和函数都通过共享数据和相互调用来相互通信。
我在一个子文件夹中工作,其中包含了旨在解决大项目中一个子问题的代码,然后我突然想到:
如果能够可视化我在大画面中的位置,以及所有不同的对象是如何通过相互之间的调用和数据传递连接起来的,这不是很好吗?
那会是什么样子?
在几个晚上和(17 杯浓咖啡)里,我设法构建了一个 Python 程序,它将您的代码作为节点和关系以对象和调用、作用域和实例化的形式解析到 Neo4j 图形数据库中。
上图是通过这个 Python 映射项目解析我的一个 NLP 项目(人类语言上使用的机器学习)的结果。
对于不知道什么是图形数据库的人来说,让我们暂停一下这个故事。
首先,图是一个数学对象。它由所谓的节点和边组成。在 Neo 术语中,这些边被称为关系,这很合适,因为这正是它们所代表的——两个节点之间的某种关系。
这种图的一个经典例子是像脸书这样的社交网络,其中节点代表人,关系代表人与人之间的友谊。
然后,图形数据库存储这样的图形,以便您可以探索隐藏在大量路径中的模式。
我们应该记住的一件非常重要的事情是,在图形数据库中,节点以及关系都存储在数据库中。这意味着某些查询比在关系数据库中连接大量的表要快得多。
为了更清楚地说明我们在这里构建的是什么样的图形,我将勾画出它的结构。
我们指定 Python 项目的根文件夹。
图中的节点表示我们的项目/存储库中的文件对象。特别是函数、类和方法。这些节点有一些属性,比如它们在哪个文件中定义,如果它们有一个父节点(方法有类作为父节点,函数可以在其他函数中定义,等等。).
对于关系,我们有调用、实例化、显示方法属于哪个类的关系,等等。
作者图片
这个想法是,我们希望能够跟踪代码中的调用和依赖关系。
所以我手里拿着一个新的可视化工具——不是像 Matplotlib 这样的可视化数据的工具,而是可视化代码本身的结构。
乍一看,除了一个有趣的新方法来为“赢得”项目的办公室制作令人敬畏的海报之外,我没有想太多。
然而,在与我的一个同事(碰巧也是一个数学/图形数据库极客)讨论了它为许多不同的可能工具铺平了道路之后,我很快意识到这不仅仅是一个可视化工具。
测试和安全
当然,你可以看到代码中的依赖关系,这当然很好,它甚至可以帮助你发现一两个 bug,或者仅仅通过查看就可以优化代码,但是真正的力量来自于对嵌套代码结构的揭示。
例如,除非你真的很紧张,并且已经将你的代码分成小的可测试单元,然后在进行更大的集成测试之前,在(所谓的)单元测试中一个接一个地进行测试,否则你可能不容易回答这样的问题
- 你的代码测试到什么程度了?也就是说,哪些功能是隐式测试的,而不是显式测试的,反之亦然?
- 有没有不再被使用或者没有被测试的功能?
- 哪些函数被隐式调用得最多?
坚持住卡斯帕。首先,隐式调用是什么意思?
嗯,当我调用一个函数(或者一个方法,生成器等等。)该函数可能调用另一个函数,依此类推。这些被其他函数调用的函数被隐式地调用*。第一个函数被显式地称为或直接称为。***
好吧…为什么这很重要?
因为,如果一个函数被很多不同的函数多次(隐式)调用,有一个细微的 bug,那么,首先,这个 bug 在某个时刻发生的概率比每次只被同一个函数调用一次的概率要大,其次,依赖那个函数的函数越多,一个潜在的 bug 对整个系统/程序造成的损害就越大。
事实证明,图是解决这类问题的完美设备。我们甚至可以用一种更微妙的方式来解决它们,通过使用图形算法,用分数的方式列出函数、方法和类的重要性。
解决方案
在能够使用 Python 中的 neo4j 之前,我们需要安装 neo4j 桌面环境并执行一个
***pip install neo4j***
让我们构建一个能够从 Python 与 Neo4j 通信的类。
现在,我们可以通过如下方式在另一个类中轻松构建一个图形加载器
***self.loader = LoadGraphData("Kasper", "strong_pw_123", "bolt://localhost:7687")***
让我们来看看我的一个爱好项目,由我上面描述的映射算法映射出来的。
作者图片
在这个项目中,蓝色节点是类,橙色节点是方法,红色节点是函数。
请注意,这些代码中有一些是测试这个 graph 项目的伪代码,当然是使用了正确的 Python 语法。
我们想知道测试了哪些函数,测试的隐含程度如何,即从最近的测试函数到给定的非测试函数有多少(嵌套)调用?
嗯,我们有图表。现在我们需要查询图形数据库。
看看下面的 Cypher 查询,它实现了测试和函数之间的最短路径算法,并与图片进行比较。
请注意,我们假设测试函数是这样的对象,它们或者在一个名称以“test”开头的文件中,或者在一个类中,或者在一个名称以“test”开头的函数中,或者仅仅是名称以“test”开头的函数、方法或类(对于类来说,它当然应该以“test”开头)。
乍一看,这种假设似乎有些牵强,但是我不认为我曾经在 Python 文件中编写过以“test”开头的测试函数,更不用说函数名本身几乎总是以“test”开头。
如果您有一个以“test”开头的文件,我假设该文件中的所有函数和方法都是测试函数。
cypher 查询的输出如下表所示:
作者图片
嗯…如果我们能在熊猫的数据框架里找到那张桌子,那当然很好…
让我们这样做:
我们将上面的 cypher 查询作为字符串(使用三重引号)存储在变量 query 中。然后在一个选择的函数或方法中,你可以像这样做
**loader = self.loader
records = loader.work_with_data(query)
df = pd.DataFrame(records, columns=["distances", "test_functions", "test_source", "targets", "target_source"])**
然后,您将在 DataFrame 对象中获得该表,然后就可以使用它了。
找到所有非测试函数可能会派上用场,所以让我们构建它。
在继续之前,我们应该定义我们所说的安全分数的含义。
对于给定的函数 f ,我们将 f 的测试范数定义为图中最近的测试函数与f之间的距离
- 按照惯例,所有测试函数的测试范数都是 0。
- 如果一个函数被一个测试函数调用,范数是 1,
- 如果一个函数(未被任何测试函数调用)被另一个被测试函数调用的函数调用,则范数为 2,以此类推。
- 如果一个非测试函数没有从测试函数到其自身的路径,那么测试范数是无穷大。
现在让我们定义整个项目的安全分数σ。设 NT 为非测试函数集合,设 N = |NT|。然后我们定义
注意到
- 如果项目中的所有函数都被直接测试,也就是说,如果所有函数的测试标准都是 1,那么σ = 1
- 如果没有一个函数被测试过,既不是直接测试也不是隐式测试(通过其他函数),那么σ就是空和,按照惯例是 0。
因此,0 < σ < 1,越接近 1,代码就越安全,越容易测试。
这个公式背后的思想是,一个给定的函数离测试越远,它的测试就越弱。然而,我假设对图中更远处的函数进行了“平均”弱测试。但这当然只是一个定义。我们总能改变这一点。例如,由许多不同的测试函数调用的函数可能比只由一个函数调用的函数测试得更好,而我们在这个版本的项目中根本没有考虑这一点。不过它可能会有更高的版本。
让我们实现这一点。
这是可行的,对于上面的项目,我们得到了大约 0.2 的分数,但是我们需要记住,只有当你在文件名或者你用来测试你的代码的对象的开头有“test”这个词时,这才是可行的。
我将把构建这个映射他/她自己的 Python 作为一个练习留给读者,因为我不被允许开放这个项目的源代码。但是,我会给你一些提示,告诉你如何自己构建这个。
- 我有一个主类,当我逐行遍历文件时,它跟踪并存储节点和关系。
- 当迭代时,我们跟踪我们在范围中的位置。我们在一个班级里吗?,一个函数?等。
- 如果分别有对另一个函数或类的调用或实例化,我们存储对象并创建关系
- 如果当前行包含定义,那么我存储对象和父对象(如果有的话),例如方法和类。然后我以 IS_METHOD_IN,IS_FUNCTION_IN 的形式存储关系。
所以基本上它是关于编码一个 python 语法解析器。
让我告诉你,这比你一开始想的要复杂得多。
我们需要跟踪其他文件的导入和调用,同时构建一个文件爬虫,因为您不知道存储库有多深。我们存储的每个对象都有一个创建它的源文件,我们需要将它存储为节点的属性,因为如果两个对象在两个不同的文件中被称为相同的,我们需要小心,不要在创建图形时将它们合并到同一个对象中。
当我看完所有的。py 文件,我从存储的数据中创建了一些 CSV 文件,我使用上面定义的 LoadGraphData 类通过 LOAD CSV 查询将这些文件从 Python 加载到 Neo4j 中。
已知项目的地图
这是一个你可能听说过的项目的地图。
美汤
作者图片
这是一张很好的地图,展示了美丽的汤里发生了什么。注意大的集群是如何连接的。
虽然这段代码还不完美,但我相信它在未来会变得非常有用。我目前正在开发一个更稳定的版本,它也考虑到了从 python 打开文件的问题。
如果你想了解更多关于这个项目的信息,你可以在 LinkedIn 上找到我。请随意和我聊一两个问题。
**https://www.linkedin.com/in/kasper-müller-96ba95169/ **
在 TensorFlow 和 Keras 中从头开始构建一个面具 R-CNN
讲解如何建立一个基本的面具 R-CNN,以学习为目的,没有喧嚣。
如果你曾经想在 TensorFlow 中从头实现一个 Mask R-CNN,你很可能找到了 Matterport 的实现。这是一个伟大的,如果你只想使用一个面具 R-CNN。然而,由于它非常健壮和复杂,很难彻底理解它的每一点。更大的问题是,它不能运行新版本的 TensorFlow。
如果你有机会使用 PyTorch 实现,最常用的是 Detectron2 ,它也很难理解,因为它很复杂。
从所有关于 Mask R-CNN 如何工作的描述来看,实现起来似乎总是非常容易,但不知为何你还是找不到很多实现。
本文的目的是理解 R-CNN 掩码的基础,以及如何实现它。(假人用口罩 R-CNN?)因此,我的实现缺少了原始实现的一些重要部分,因为这主要是为了理解 R-CNN 是如何构建的。
*在我的实现中,基础模型不是特征金字塔网络(FPN),ROI Align 也没有实现。
为了训练和测试,我从 LIDC-IDRI 公共肺部 CT 扫描数据集生成了一个玩具数据集,目标是分割非常(可笑?)简单的形状。为此,我放置了不同大小的心脏,并开始进行 CT 扫描,这些是我的面罩 R-CNN 必须找到、分类和分割的对象。
这就是 R-CNN 完整的面具的样子。绿色虚线方框标记了不同的神经网络。因此,整个模型由 4 个神经网络模型组成。图片作者。
1。第一步,要有骨干模型。这是一个简单的分类器模型。在我的例子中,它是一个多类标签分类器,在 matterport 的例子中,它是一个带有 ResNet101 主干的预训练 FPN。当训练掩模 R-CNN 时,我们永远不会使用这个网络的预测,我们只需要一个内层特征图。在分类器网络内部生成的那些特征地图将成为我们的区域提议网络(RPN)的输入。
我们的分类器是从输入到标签的 keras 模型,但是我们也保存了从输入到 featuremap 的 keras 模型(featuremap_model)。在训练分类器之后,该特征映射模型将从输入图像生成特征映射。图片作者。
2。第二步是 RPN。我认为这可能是网络中最复杂的部分。RPN 需要找到感兴趣的区域(ROI)。为此,它预测了 4 个坐标,以及每个锚点的标签。什么是主播?
锚点是预定义的不同大小的矩形,覆盖整个输入图像。我们根据我们的对象选择锚的大小/比例。
我们将选择与我们的对象重叠的对象,RPN 的工作是移动它们以更好地重叠,并调整它们的大小以更好地适应(预测的 4 个坐标)。为此,RPN 还需要识别哪些锚代表对象,即哪些锚是前景锚,哪些锚是背景锚(预测的 2 个数字)。
选择固定数量的主播进行训练。为此,我们需要计算每个锚点和每个真实边界框之间的交集(IoU)。我们总是用相同数量的锚来训练,然而,在每个输入的情况下,前景锚的数量是不同的。(例如,如果我们在图像上有一个小对象,我们将有一个前景锚,如果我们有两个较大的对象,我们将有最大提议计数/2 个前景锚。)图片由作者提供。
因此,我们选择我们的建议计数(PC),它告诉我们有多少 RPN 的预测将对损失函数有贡献。(请记住,RPN 预测每个主播台!)
以我的 toydataset 为例,我们的背景(BG)远远多于前景(FG),所以我的 PC 只有 20。即使我在 CT 扫描上有一个大明星和一颗大心脏,我只有大约 10 个前景锚,我们需要一个平衡的训练。(10 FG / 10 BG)如果你有更多的多事输入图像,你的 PC 会更大。
请记住,RPN 模型预测每个锚点的增量值和 fg/bg 标签。
对于这 20 个锚,我们知道真相标签和真相增量。δ是 4 个坐标:(δx,δy,δW,δH)。前两个显示了我们需要滑动锚的中心点多少,后两个显示了我们需要改变锚的宽度和高度多少。
RPN 损失由 class_loss + boundingbox_loss 组成。PC 个预测对 class_loss 有贡献,FG 个预测对 boundingbox_loss 有贡献。
RPN 损失是 class_loss 和 bbox_loss 的总和。class_loss 是一个简单的稀疏分类交叉熵,bbox_loss 是一个光滑 L1 函数。背景锚点不会导致 bbox 丢失,因为我们只需要移动已经重叠的锚点。图片作者。
在训练期间,我们简单地使用 rpnloss 作为 classloss + deltaloss 之和。如果有必要,我们可以使用损失权重。
现在,我们选择我们预测的锚作为前景,并将其与相应的预测增量一起移动。所以我们会有 NumberOfForegrounds * 4 个坐标,这些是我们的 ROI。我们从特征图中剪切这些区域,并将它们调整到相同的大小:这些是**提议。**这些将是我们的类、boxrefinement 头和 maskhead 的输入。(这些神经网络模型需要有一个固定的输入形状,为此,我们总是可以用零填充我们的预测。)
图片作者。
因为我们最多有两个对象是输入图像,所以我们的 RPN 很有可能移动了不同的锚点来与同一个对象重叠。我们将使用非最大抑制来过滤掉高度重叠的提议,因为它们是不必要的。我们只会保留最好的。
3。最后一步是“头部”模型,这些可以并行训练。
在我们有了我们的建议之后,我们需要一个神经网络来进一步细化包围盒坐标,并且预测分类标签。因此,它不仅会预测一个区域是前景还是背景,而且如果它是前景,它会对它进行分类(在我的 toydatasets 案例中是心形或星形)。就像在 RPN 的情况下,只有前景建议会造成盒损失,并且任意固定数量的建议 classlabel 会造成类损失。
我们不仅为每个建议预测一组盒精化坐标,而是三组。三是班级人数+1 为背景。
所以在我们的例子中,我们预测每个提议的 3*4 坐标。我们将基于我们在同一网络中预测的类来选择适当的盒细化坐标。
在训练过程中,我们简单地使用 chloss 作为 classloss + deltaloss 的总和。如果有必要,我们可以使用损失权重。我们使用一个新的提议计数,因为我们对 RPN 提议使用非最大值抑制,以避免提议重叠。正因为如此,我们将只剩下很少(< 5)的前景框,我们希望有一个平衡的训练。(大约 5FG-5BG 提案)
maskhead 是一个卷积网络,末端有一个上采样层。它仅对接收到的 ROI(而不是整个图像)预测一个遮罩。
最后一个卷积层的滤波器数目等于类的数目。当检查预测掩码时,我们需要使用过滤器,对应于 classlabel。因此,如果我们的标签是:0:star,1:heart,并且我们的输入图像上有一颗心,我们将从 filter 维度中获取第一个轴。
正如我之前提到的,这些头部模型可以并行训练,但是,如果没有分类预测,你无法预测一个面具。(与预测的情况一样,您没有基础真实类标签,因此您将需要预测类标签来选择合适的掩膜。)
这就是了,我们有一个正常工作的 R-CNN。希望这篇文章有助于理解基础知识,以便您可以实现自己的,甚至是改进的 Mask R-CNN。
你可以在 https://github.com/rajkifranciska/maskrcnn-from-scratch
找到整个实现和 toydataset 生成文件
如果这篇文章有帮助,请引用我的话:
@misc {rajki_2021,
title = {在 TensorFlow 和 Keras 中从头开始构建一个面具 R-CNN },journal={Medium},
author={Rajki,Franciska},
year={2021},month={Mar}}
[1].瓦利德·阿卜杜拉
掩膜 R-CNN 用于 Keras 和 Tensorflow 上的物体检测和实例分割,2017
https://github.com/matterport/Mask_RCNN
[2.]吴雨欣,亚历山大·基里洛夫,弗朗西斯科·马萨,卢万延,罗斯·吉斯克
侦探 2 ,2019
https://github.com/facebookresearch/detectron2
[3].阿玛托三世,SG;麦克伦南,G;比达乌,L;McNitt-Gray,MF;迈耶河;美联社里夫斯;赵,乙;阿伯勒博士;亨施克,CI;埃里克·霍夫曼;卡泽罗尼,EA;麦克马洪;范·比克,EJR;Yankelevitz,D;Biancardi,AM;淡而无味,PH;布朗,密西西比州;恩格尔曼,RM;拉德拉赫,葛;Max,D;Pais 清,DPY 罗伯茨,RY;阿肯色州史密斯;斯塔基,A;巴特拉,P;卡利久里,P;法鲁奇,阿里;Gladish,GW;裘德,CM;Munden 佩特科夫斯卡,我;、乐;施瓦茨,LH;孙达拉姆湾;多德,勒;费尼莫尔,C;Gur,D;彼得里克,N;弗莱曼,J;柯比,J;休斯湾;卡斯特利,AV;Gupte,S;萨拉姆,M;医学博士希斯;MH 库恩;Dharaiya,E;伯恩斯河;Fryd,DS;萨尔加尼科夫,M;阿南德五世;Shreter,U;Vastagh,S;克罗夫特,由;克拉克唱片公司。
【http://doi.org/10.7937/K9/TCIA.2015.LO9QL9SX】肿瘤影像存档,2015
T24
使用 Google Cloud Run 构建微服务
在 Cloud Run 上设置一个简单的 web 应用程序来更新 Big Query 中的表
照片由 Sebastian Herrmann 拍摄自 Unsplash
云上运行快速介绍
Google cloud run 是一个完全托管的计算平台,用于在云上运行容器化的应用程序。Cloud run 通过基于应用流量的自动扩展功能,消除了管理所有基础架构的复杂性。
在本文中,我们将了解使用 python 和 flask 创建云运行微服务的方法,我们将把它们部署到 Docker 容器中。微服务将具有根据用户输入更新谷歌大查询表的功能。以下是将要使用的产品/服务:
- Python 和 Flask
- 码头工人
- 谷歌云运行
- 谷歌云容器注册中心
最终结果将是一个运行在 HTTP 上的 web 应用程序,用户可以提交他们的输入,更新 Google Big Query 中的一个表。
我们开始吧!
本文假设您已经设置了一个 Google Cloud 帐户。
所有的脚本都可以在这里找到: GitHub
(1)开发微服务所需的文件/脚本
对于这个例子,我们将创建一个简单的应用程序,用户可以通过将输入传递到微服务链接,将书名和作者的新记录插入到一个大的查询表中。
创建云运行服务需要准备 3 个不同的文件。
- main.py
- requirements.txt
- Dockerfile 文件
文件号 1: main.py
该文件将启动 Flask app,并包含 python 函数,该函数接收用户输入并更新到 Google Big 查询表中。
from flask import Flask, request, make_response, jsonify
import pandas as pd
import gcsfs
from google.cloud import bigquery
from google.oauth2 import service_account
import pandas_gbq
import osapp = Flask(__name__)app.config["DEBUG"] = True #If the code is malformed, there will be an error shown when visit app[@app](http://twitter.com/app).route("/books", methods=["GET"])
def books_table_update():
Title = request.args.get('title', None)
Author = request.args.get('author', None)input_table = {'book_title':[Title],'book_author':[Author]}
input_table = pd.DataFrame(input_table)
input_table["book_title"]= input_table["book_title"].map(str)
input_table["book_author"]= input_table["book_author"].map(str)
#Push table to Google Big Queryclient = bigquery.Client()
project_id = 'sue-gcp-learning-env'
table_id = 'Books.books_title_author'
pandas_gbq.to_gbq(input_table, table_id, project_id=project_id, if_exists='append')
return "Table books_title_author has been Updated"
文件号 2: requirements.txt
要求文件,以指定安装所需的库。
Flask
gunicorn
google-api-core
google-cloud-bigquery
pandas
pandas-gbq
gcsfs
3 号文件:Dockerfile
Dockerfile 文件指定如何创建容器:
- 从官方 python 3.9 映像构建一个容器
- 将本地代码复制到容器映像
- 在 requirements.txt 文件中安装软件包
- 在容器启动时运行 web 服务
# Use the official lightweight Python image.
# [https://hub.docker.com/_/python](https://hub.docker.com/_/python)
FROM python:3.9-slim# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./# Install production dependencies.
RUN pip install --no-cache-dir -r requirements.txtENV PORT 8080CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
(2)将所有 3 个文件/脚本上传到云壳编辑器
在将文件/脚本上传到云壳编辑器之前,您需要在 Google 云控制台中激活云壳并创建一个文件夹。
mkdir books_update
在云壳中打开编辑器
右键单击新创建的文件夹或通过文件,将所有需要的文件/脚本上传到 books_update 文件夹。上传完成后,点击“打开终端”返回外壳编辑器。
将所有 3 个文件上传到创建的文件夹中
(3)构建&部署新的 Docker 映像
太好了!我们现在准备构建一个新的 docker 映像,它将在我们选择的区域运行。
gcloud config set run/region asia-southeast1gcloud builds submit --tag gcr.io/sue-gcp-learning-env/books_update
构建 Docker 映像的命令
构建完成后,运行下面的命令来部署新构建的映像。您需要提供云运行服务名称。当容器构建完成后,将会提供您的服务 URL。
gcloud run deploy --image gcr.io/sue-gcp-learning-env/books_update --platform managed
部署 Docker 映像并设置云运行服务名称
(4)你的服务准备好了!
容器构建完成后,将提供服务 URL。或者,我们可以从云运行中跟踪我们部署的服务。
云运行服务:图书更新
(5)让我们测试一下我们的服务
在调用服务之前,让我们检查一下调用服务时将要更新的大查询表。在这个表中,books_title_author 当前有 2 条记录,我们将通过调用我们的服务向这个表中添加一条新记录。
大查询表:books_title_author(调用服务前)
在这里,我们调用服务并传递我们想要为新记录添加的输入值。如果服务运行成功,它将返回我们指定的消息:“表 books_title_author 已更新”。
调用云运行服务并传递用户输入
让我们在 Google Big Query 中检查我们更新的表。
大查询表:books_title_author(调用服务后)
正如我们在刷新后的表中看到的,新记录是根据调用 URL 时指定的输入插入的。我们已经成功地在 Cloud Run 上创建了一个简单的 web 应用程序,它更新了 Google Big Query 中的一个表。
结论
通过 Google Cloud Run 部署微服务变得更加容易和方便,因为管理服务器的过程已经得到处理。只需要几个步骤,您就可以立即部署无状态微服务。下面是文章中解释的步骤的摘要:
- 准备 3 个主文件/脚本,包括(main.py、requirements.txt 和 Dockerfile)
- 将您的文件上传到 Google Cloud shell 编辑器以创建 Docker 容器。
- 部署完全构建的映像以创建完全托管的 web 应用程序。
这就是在云上创建微服务所需了解的全部内容。我希望这篇文章对那些学习使用 Google Cloud Run 创建微服务的人有用。
参考文献
[1]https://cloud . Google . com/run/docs/quick starts/build-and-deploy/python
[2]https://cloud . Google . com/blog/topics/developers-从业者/cloud-run-story-server less-containers
[3]https://www . kdnugges . com/2021/05/deploy-dockerized-fastapi-app-Google-cloud-platform . html
构建朴素贝叶斯机器学习模型对文本进行分类
这是一个快速入门指南,帮助您使用 Python 启动并运行一个简单而高度相关的 NLP 项目
Python 中的朴素贝叶斯(所有图片由作者提供)
介绍
自然语言处理(NLP)是一个非常令人兴奋的领域。它位于计算机科学、语言学和人工智能的交汇点,关注人类语言和计算机之间的交互。更具体地说:它的目标是理解如何给计算机编程,以理解和解释我们的自然语言。
现在这是一个非常热门的研究领域,我很幸运能够在这个研究领域绝对前沿的大学就读。虽然作为一名卑微的本科生,我并不经常接触这种前沿工作——如果我接触了,我会理解的!
尽管如此,建立模型对自然语言进行分类还是相对简单的。这是一个很酷的练习,因为它是相关的。这是一个非常真实的 ML 应用,你可以在自己的项目中使用。
贝叶斯定理
朴素贝叶斯
朴素贝叶斯算法是一种更简单的监督贝叶斯网络模型,它是一种基于贝叶斯定理的概率分类器(您可能还记得高中的统计数据)。但它的简单性并不使它成为一个糟糕的选择,即使数据集不是很大(只有几千个样本),它也可以产生高度准确的预测。
如果你真的是机器学习的新手,我建议阅读一些关于更基本算法的文章,然后回到这一篇,因为我将建立在这些文章中详细解释的概念上。
本质上,两个事件发生的条件概率是根据每个事件的条件概率计算出来的。因此,对于给定的一段文本,计算每个标签的概率,并输出具有最高概率的标签。
还有其他合适的选择,如支持向量机(SVM),它需要更多的时间和计算资源来工作,但会产生比朴素贝叶斯更准确的预测。或者,您可以考虑基于神经网络的深度学习方法,但这将需要更多的训练数据。
米卡·鲍梅斯特在 Unsplash 上的照片
这个例子
这是一种方法:
- 导入和设置数据。
- 做一些分析以了解更多关于数据环境的信息。
- 创建我们的因变量和自变量列表,用于训练和验证。
- 给标签编码。
- 从描述中提取特征。
- 使数据符合模型。
- 检查模型的准确性。
这个项目将演示如何根据银行交易的描述对其进行分类。我的数据集包含 12500 个样本,包括交易金额和交易类型等其他特征,您可以在模型中使用任意数量的特征,甚至可以选择一些特征来查看哪些特征对预测的影响最大,但为了简单起见,我们将只使用描述。
在我的数据集中,描述是这样的:
citylink
1Jul19 OYSTER
travelodge
6Jul19 RINGGO
SUNDRY DEBIT CONTACTLESS CAMDEN PARKING
stgcoach
trainline
Fin: CMT UK LTD Cash at Transact
设置
当然,从进口开始。
- 创建数据框架的熊猫。
- sci kit-了解标签编码、特征提取、建模和测量成功指标
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.feature_extraction.text import CountVectorizer
from sklearn import naive_bayes, metrics
接下来,让我们处理 csv 文件,并为模型做好准备。(当然,你可能没有处理 csv 文件,只是把你所有的数据导入到熊猫数据框架中):
features = pd.read_csv("bank_transaction_features.csv")
labels = pd.read_csv("bank_transaction_labels.csv")
我有两个数据集:一个包含要素,一个包含标注(类别)。这些是它们各自的列:
**bank_transaction_features:**
bank_transaction_id, bank_transaction_amount, bank_transaction_type**bank_transaction_labels:**
bank_transaction_id, bank_transaction_category, bank_transaction_dataset
它们有一个共同点,ID 列。因此,我将在这一列中合并它们,并删除任何具有空条目的行(在我的数据中很少,您应该计算有多少,因此删除它们对预测的影响可以忽略不计):
combined_df = pd.merge(left=features, right=labels)
combined_df = combined_df.dropna()
探索性分析
总是从一些探索性的数据分析开始。我的数据集有数以千计的样本,我无法通过扫描看到所有的类别。我们需要做一些简单的事情来更好地理解数据。
该数据集有一列指定样本是用于训练还是验证。这将在以后派上用场,因为我们不需要创建我们自己的训练/验证分割。但是对于探索性分析,我们可以删除该列(只从我们将创建的新 dataframe 变量中删除该列,保留包含该列的变量)。
explore_df = combined_df.drop(labels=['bank_transaction_dataset'], axis=1)
我们可以很容易地看到数据中存在哪些类别,以及每个类别中有多少个样本:
print(explore_df['bank_transaction_category'].value_counts())
结果是:
ACCOMMODATION_AND_MEALS 3765
TRAVEL 3166
BANK_OR_FINANCE_CHARGES 2659
MOTOR_EXPENSES 1609
INSURANCE 1170
Name: bank_transaction_category, dtype: int64
现在,让我们检查一下培训/验证分割是什么(使用仍有相关列的数据帧):
train_set = combined_df.loc[combined_df["bank_transaction_dataset"] == "TRAIN"]
val_set = combined_df.loc[combined_df["bank_transaction_dataset"] == "VAL"]
len_train = len(train_set)
len_val = len(val_set)
len_whole = len(explore_df)
print('Amount of training data: ', len_train)
print('Amount of validation data: ', len_val)
输出:
Amount of training data: 9891
Amount of validation data: 2478
这使得训练/验证的比例为 80/20,这是一个很好的比例,所以根本不需要调整。
分类
最后,有趣的部分。首先,创建 x 和 y 训练和验证子集。我们可以通过创建只包含相关列中数据的列表来实现这一点:
y_train = train_set['bank_transaction_category'].values
x_train = train_set['bank_transaction_description'].values
y_val = val_set['bank_transaction_category'].values
x_val = val_set['bank_transaction_description'].values
现在变得非常有趣了。需要记住的是,ML 模型不“理解”文本和单词。他们理解数字。因此,准备数据以适合模型的第一件事是对标签进行编码。这意味着,给每个标签分配一个号码。例如:
ACCOMMODATION_AND_MEALS => 0
TRAVEL => 1
BANK_OR_FINANCE_CHARGES => 2
MOTOR_EXPENSES => 3
INSURANCE => 4
这是通过创建一个 LabelEncoder 对象并对因变量数据( y )使用其 fit_transform 函数来实现的:
label_encoder = LabelEncoder()
y_train = label_encoder.fit_transform(y_train)
y_test = label_encoder.fit_transform(y_val)
描述数据也是如此,只是这个稍微复杂一点。在一些模型中,你有一组统一的描述,并且你知道它们是什么,你可以把每一个编码成一个整数,它们就准备好了。但是在这里,每个事务描述都可能是唯一的。
解决方案是从文本中提取特征,并将这些特征转化为模型可以理解的向量。
特征抽出
虽然在技术上很复杂,但这可以简单地实现,通过使用计数矢量器将文本转换为令牌矩阵,并转换训练和验证独立变量( x ):
count_vector = CountVectorizer(analyzer='word', token_pattern=r'\w{1,}')
count_vector.fit(combined_df['bank_transaction_description'])
x_train_count = count_vector.transform(x_train)
x_valid_count = count_vector.transform(x_val)
就是这样!我们可以拟合数据、训练模型并做出预测:
classifier = naive_bayes.MultinomialNB()
classifier.fit(x_train_count, y_train)
predictions = classifier.predict(x_valid_count)
准确(性)
您可以使用几个指标来确定模型的工作情况。我们会用准确性。这将告诉我们模型正确预测银行交易类别的频率:
print(metrics.accuracy_score(predictions, y_test))
该模型的精确度为:
0.91
一点也不差。
结论
这是一个有趣的例子,因为它是有形的。例如,在移动金融跟踪应用程序中将银行交易分类是这种算法的一个非常真实的用例。我希望您对朴素贝叶斯是如何工作的,以及如何实现它对文本进行分类有了很好的理解。
如果你确实学到了一些东西,有任何问题,认为我错过了任何重要的东西,或者计划在你自己的项目中使用这个算法,请通过留下回复让我知道,我们可以讨论它。
编码快乐!
订阅 📚为了不错过我的一篇新文章,如果你还不是一个中等会员,加入 🚀去读我所有的,还有成千上万的其他故事!
资源
Scikit Learnsk Learn . preprocessing . label encoderhttps://Scikit-Learn . org/stable/modules/generated/sk Learn . preprocessing . label encoder . html
Scikit Learnsk Learn . feature _ extraction . text . count vectorizerhttps://Scikit-Learn . org/stable/modules/generated/sk Learn . feature _ extraction . text . count vectorizer . html
维基百科 自然语言处理https://en.wikipedia.org/wiki/Natural_language_processing
MonkeyLearn 文本分类【https://monkeylearn.com/text-classification/】T4
建立相关信息技术技能的网络
我分析了 30,000 份工作描述,构建了一个相关 IT 技能的网络图。
介绍
IT 职位描述提到了大量不同的框架、编程语言和其他技能。HTML 和 CSS 这样的语言显然是齐头并进的,但是有哪些不太明显的联系呢?在这个分析中,我分析了 30,000 份职位描述,以便找出专业职位的不同技能之间的关系。
我必须承认,我最初对工作描述数据集有另一个想法,但在这个过程中,进行这种网络分析似乎很酷。我仍然会完成原来的项目,但同时我想与你分享这个“信息技术技能分析”的过程。
请记住,本文仅仅描述了构建网络的过程。实际结果可以在这里找到。
获取数据
从这个项目一开始,我就认为寻找数据是最困难的部分。基本上,我在搜索符合以下标准的数据集:
- 至少 10k 张唱片
- 包含职位描述的完整文本
- 所有职位描述都是针对 IT 职位的
- 最好是全英文的
- 最近(不到 3 岁)
我最初的想法是刮 Indeed.com。我很快使用 BS4 构建了一个简单的刮刀,但是在大约 1000 次请求之后,他们阻止了我。这给了我三个选择;改进刮刀以避免堵塞,刮另一个来源或寻找现成可用的数据集。我选择了后者,并很快在 Kaggle 上找到了这个数据集。尽管数据集不包含完整的描述,但有一列列出了所有技能,这正是我所需要的。
我下载了数据集,旋转了一个 Jupyter 笔记本,并调用了我忠实的熊猫 (Python 库)。
实体提取
这个概念
尽管数据集包含一个列有技能的列,但数据仍然非常粗糙。分析该列时,我们得到以下指标:
- 总技能:366528
- 绝技:6783
- 最短的技能:几乎任何单个字符
- 最长技能:咨询对应
当查看每项技能的出现次数时,最受欢迎的五项是:销售、管理、开发、执行和业务。考虑到所有这些信息(技能总数、拼写错误和不相关或过于普通的技能),生成一个有限的相关技能集可能具有挑战性。在网络图中,我们使用术语实体,在这种情况下是技能。提取实体(或者在这种情况下获得一个清晰的技能列表)是生成网络数据过程的关键步骤。
创建网络图的步骤。(图片由作者提供)
方法
在我们的数据集中,每条记录代表一个不同的工作描述。“关键技能”列包含由竖线(|)分隔的技能列表,例如:
“分析| SQL| MS Office|审计|金融服务| Oracle|数据挖掘|业务运营|资产管理|监控”。
将竖条上的技能分开后,我们有了如上所述的 6783 个独特技能的长列表。现在,让我们试着把这个长长的列表简化成更小、更简洁、更有用、更相关的技能。
首先,我试图通过将所有内容转换成小写并删除所有前导和尾随空格来尽可能避免明显的重复。这应该确保例如“javascript”和“JavaScript”不被视为独立的技能,而仅仅是大写的原因。
一旦完成,我过滤掉这些技能,只显示那些出现至少 50 次的技能。这使得独特技能的总数下降到 2079。
为了进一步过滤,我使用了一个 Python 库来指示一个单词是否在英语词典中。大多数技术都有“CSS”或“PHP”这样的名字,在英语中几乎没有任何意义。然而,其他一些语言和工具确实在字典中占有一席之地,如“python”或“azure ”,所以对于剩余的单词,需要进行一些手动审查。
在完成这个人机交互的审查和筛选过程后,我有了一个大约 400 项与 IT 工作相关的技能的列表。
将这些点连接起来
好了,现在我有了要使用的技能列表和完整的数据集,是时候把这些点连接起来了。为了统计描述中每个技能的出现次数,我使用了一个叫做虚拟表的东西。基本上,它是一个表,其中你的列只有 0/1 值,表示一个真或假的位置。第一列(或索引)包含工作描述,而每一列代表一项技能。如果技能存在,单元值(工作描述和技能之间的交集)将为 1,否则为零。结果看起来像这样;
虚拟桌子。行:工作描述,列:技能(作者图片)
使用这个虚拟表,我创建了一个关联表。该表本质上指出了哪些列(或技能)具有相似的 0 和 1 模式。换句话说,它显示了哪些技能经常出现在同一个职位描述中。例如,如果两种技能总是出现在相同的描述中,它们在相同的记录中总是具有“1 值”,这将导致完美的关联:1。
从相关表中,我可以创建一个有 3 列的网络图表;两个用于所有技能的所有组合(例如 A 列(源));“HTML”,col B(target)“CSS”等)和一个与这两种技能之间的相关性。我过滤了这个表,只显示相关性至少为 0.15 的技能组合(1 表示完全相关)。这是必要的,以防止他们所谓的“一团乱麻”,一个节点和边太多的网络图变得不可读。最后,我添加了一列“权重”,表示源技能在所有描述中出现的频率。权重将用于确定节点的大小(半径)。像 JavaScript 这样的流行语言出现在许多职位描述中,因此权重更大。
这张表包含了我可视化结果所需的所有信息。然而,即使数据已经准备好可视化,我们稍后还会回到这一步。网络图构建通常是一个迭代过程,在这个过程中,您使用最终结果(可视化)来细化、过滤和重新校准您的图模型。这基本上意味着你在数据和图表之间来回切换,以获得最佳结果。
实体提取的迭代过程。(图片由作者提供)
结果呢
视觉结果
在将前面步骤中的表格转换成 JSON 文件后,我构建了一个 D3.js 强制定向图。哪像这个;
部分网络图截图。(图片由作者提供)
当然这仅仅是截图的汇编,完整的互动网络图可以在我的网站上找到,在那里你可以通过拖拽来缩放和移动节点。
节点的大小代表数据中的总出现次数,而边的厚度代表相关性的强度。换句话说,用粗边连接的两个大节点意味着这两种技能出现了很多次,并且经常一起出现。
技术细节
对于那些更熟悉开发网络图的人,我列出了一些关键指标:
- 节点:177
- 边缘:415
- 平均聚类系数:0.48
- 传递性:0.48
- 派系数量:152
中心性、Pagerank、Between 和 degree 分布。这张表是按照中心性排列的前 10 名。(图片由作者提供)
表格和直方图中显示的所有信息仅仅是网络图中显示内容的汇总版本。例如,中心性表示每个节点(或技能)相对于整个网络有多少条边(连接)。
Pagerank 和 betweenness 是相似的,但是更高级的度量标准。如果你想了解更多关于这些(和其他)网络指标的信息,你可以在维基百科或其他许多免费在线资源上找到。
洞察力
网络图清楚地显示了由 IT 中常见角色(如数据、设计、系统、前端等)定义的不同集群。该图表还显示了集群之间的关键连接器。如果你想进入一个新的领域,这可能会很有帮助,因为关键的连接器技能提供了一个与两个领域都相关的良好起点。
开始他们的计算机科学或编码之旅的人也可以识别哪些技能可能是在他们最感兴趣的领域获得个人成长的良好开端。
虽然这张图表没有提供任何有待发现的突破性见解,但它似乎提供了一种非常直观和容易理解的方式来查看 it 招聘前景。
进一步研究和改进
更多数据
这适用于我几乎所有的项目,无论是专业的还是个人的。很少有更多的数据对模型、指标、可视化或其他数据应用程序没有好处的情况。虽然我很高兴发现这个数据集有 30k 条结构良好的记录,但如果能有更多就更好了。另一种可能性也可以是使用提取的实体并将它们应用于其他数据集。这相当简单,因为构建技能列表最需要干净的数据。
时间序列
我经常感兴趣的另一个观点是时间序列。对于这个项目来说,看到不同的 it 技能和它们的重要性是如何演变的将是特别令人着迷的。在多年的时间里,你可能会看到某些新技能是如何融合和扩展的,而其他技能会像我们银河系中的黑矮星一样慢慢萎缩和消亡。
无监督聚类
对于大多数职位描述来说,把它们归类到特定的职位群中并不困难。例如,大多数需要机器学习技能的工作最有可能被贴上数据科学或者数据工程的标签。这些集群通常是显而易见的,也是众所周知的,但以一种无人监管的方式发现集群将会很有趣。这意味着我们将所有数据输入机器,看看它是否能为我们找到特定的(重复出现的)配置文件。
高级实体配对
最后,我觉得在实体配对过程中可以做很多改进。我在个人项目上投入的时间和精力是有限的,我可能在开发的这个特定部分走了太多捷径。实体配对是复杂的,需要大量的手工修改和特定领域的知识。有无数的框架、语言和专业,其中许多我都不熟悉。我可能删除了相关的或者忽略了它们的配对。在实体提取和配对上花费更多的时间肯定会改进这个模型。
技术堆栈
Python (Pandas,Numpy,NLTK 和 RegEx),JavaScript (D3.js),HTML 和 CSS。
关于我:我叫布鲁诺,是一名数据科学顾问。如果你想看看我做的其他东西,比如咕哝说唱探测器,一定要看看我的个人资料。或者通过我的网站与我联系:https://www . zhongtron . me
用 Python 在 Telegram 上构建一站式 API 调用程序
在电报机器人上检索最新的天气、新闻、推文和一丝快乐
图片由作者提供— motherofapi 电报机器人
在我之前的文章中,我写了我如何利用电报机器人进行爱的告白。这个想法实际上是在我构建我今天要写的这个 bot(如上面的截图所示)时产生的,它是一个一站式门户,集成了来自公共可用资源的多个应用程序编程接口(API)调用来检索信息。以下是我在这个机器人中包含的 API 列表,我将解释我是如何设法集成到我的电报机器人中的:
- 可引用的(/激励)**——用于随机激励引用
- random . dog***(/dog)***—为一张随机的狗狗图片/gif
- reddit(/memes)**—来自 Reddit 的随机 memes
- unsplash(/壁纸)** —从 Unsplash 中随机选择壁纸
- openweathermap***(/weather)***——新加坡今天的天气
- 推特 (/tweets) —与用户输入相关的最新推文
- newsapi(/news)**——新加坡今日最新消息
在 BotFather 上创建 Telegram bot、将其托管在 Heroku 服务器上的步骤,以及如何通过 Python 在 Telegram Bot 上构建命令处理程序,本文都不会提及。如果你有兴趣,可以参考我以前的文章或者去谷歌一下!从一开始就自己动手做东西绝对是一件有趣又充实的事情。
/motivate 命令
励志名言是我经常听到的,有时候当我需要一些额外的动力来度过一天时,我会浏览 Instagram 或脸书等社交媒体平台来寻找它们。谢天谢地,这样的 API 是存在的,而且它来自 quotable 。如果你点击链接,一个随机的引用将以 JSON 格式出现,这是一个非常好的结构化的数据返回方式。
# motivational quote
def motivate(update, context):
quote = requests.request(url='[https://api.quotable.io/random',method='get'](https://api.quotable.io/random',method='get'))
update.message.reply_text(quote.json()['content'])
这方面的 Python 代码非常简单,其中创建了一个命令motivate
,然后该命令将对 quotable API 进行请求调用。在此之后,我们的机器人将只返回返回结果的内容部分中的内容,这将在电报上向用户显示报价。
作者图片—/激励命令
/dog 命令
在最初阶段,当我对用 Python 构建一个电报机器人非常好奇时,我遇到了这个 API。这个 API 会在你调用它的时候返回一个随机的狗图片或者 gif,好消息是我们也可以得到 JSON 格式的结果。
# dog pics
def dog(update, context):
contents = requests.get('[https://random.dog/woof.json').json()](https://random.dog/woof.json').json())
update.message.reply_text(contents['url'])
代码非常类似于motivate
,其中我们创建了一个命令dog
,它将在被请求时调用 random.dog API,并以 URL 的形式返回图像/gif。然后,我们继续在 Telegram 上将 URL 返回给用户,这将直接在 Telegram 上显示图像/GIF。
图片作者—/狗命令
/memes 命令
模因现在真的很受欢迎,谢天谢地流行论坛网站 Reddit 有这样一个 API。这个命令不像前两个命令那么简单,因为我们需要在 Reddit 上创建一个帐户,以便能够使用它的 API,其中包含一些认证信息(即 client_id、client_secret、password、user_agent、username )。
# memes
def memes(update, context):
reddit = praw.Reddit(client_id='...',
client_secret='...',
password='...',
user_agent='...',
username='...')
subreddit = reddit.subreddit('memes;)
meme = subreddit.random()
update.message.reply_text(meme.url)
你可以参考上面关于如何设置帐户的链接,我在这里使用的 Python 库模块是 praw *,*你可以在这里找到文档。一旦我们用个人密钥设置了认证,我们就可以使用reddit.subreddit('memes')
生成一个随机的 meme URL,当用户执行memes
命令时,我们将返回这个 URL。
图片作者— /memes command
/wallpaper 命令
我相信 Medium 上的大多数作者都会熟悉平台 Unsplash ,它为我们提供了非常好的图片,供我们在文章中使用。我很高兴知道他们也有一个可供用户提出这种请求的 API。对于这个 API,您还需要在 Unsplash 上创建一个开发者帐户,您将获得一个 client_id 来包含在您的代码中。
# unsplash wallpaper
def wallpaper(update, context):
url = '[https://api.unsplash.com/photos/random/?client_id=...'](https://api.unsplash.com/photos/random/?client_id=ZNEwrJqYtbXb1jHagKCfRVTnOe6d2rk2ACCN5d3P2HM')
response = requests.get(url)
wall_pic = response.json()['urls']['regular']
update.message.reply_text(wall_pic)
使用 client_id ,API 将返回 JSON 格式的结果,其中我们将只提取URL和常规维度(当用户调用wallpaper
命令时,您也可以返回 raw、full、regular、small 或 thumb )。
作者图片—/壁纸命令
/天气命令
我记得当我在墨尔本学习时,每天早上出门前查看天气是必不可少的一步,因为那里的天气波动很大。谢天谢地,新加坡的天气波动不是很大,但是当你出门的时候,知道天气还是很好的。 Openweathermap API 是我在我的机器人中想要天气信息时的首选,它还包含其他信息,如道路风险、紫外线指数和空气污染指数。你需要为这个 API 创建一个开发者账户,在这里,你会得到一个 api_key。
# weather
api_key = "..."
base_url = "[http://api.openweathermap.org/data/2.5/weather](http://api.openweathermap.org/data/2.5/weather)?"
complete_url = base_url + "appid=" + api_key + "&q=" + "singapore"
response = requests.get(complete_url)
x = response.json()
current_temperature = x['main']['temp']-273.15
feels_like = x['main']['feels_like']-273.15
weather_description = x['weather'][0]['description']
def weather(update, context):
weather_stats = "\U0001F324 Singapore Weather \U0001F327" + "\n\nWeather Description = " + str(weather_description) + \
"\nCurrent Temperature (in degree celsius) = " + str(round(current_temperature,1)) + \
"\nFeels like (in degree celsius) = " + str(round(feels_like,1))
update.message.reply_text(weather_stats)
因为我住在新加坡,所以我在请求中包含了 s ingapore 作为请求的一部分,当用户调用weather
命令时,我将返回当前的温度、现在的感觉以及天气描述。注意 API 返回的温度是华氏温度,这解释了为什么需要减去 273.15 来得到摄氏度。还完成了一些文本处理和格式化步骤,以便将结果返回给用户,如下所示。
图片作者—/天气命令
/tweets 命令
我敢肯定,大多数数据科学爱好者都玩过 Twitter API,自然语言处理将在推文上完成,并可能导致情感分析。我的想法是让用户能够键入他们感兴趣的任何关键词,机器人将提取与输入的关键词相关的最新推文。我发现这在股票投资的时候(比如搜索*“比特币】)或者有兴趣了解身边发生的事情的时候(比如搜索“裕廊东方】**)特别有用。*
# twitter
def tweets(update, context):
update.message.reply_text(text='What Twitter topics are you interested in?')
def tweets_reply(update, context):
user_input = update.message.text
consumer_key= '...'
consumer_secret= '...'
access_token= '...'
access_token_secret= '...'
twitter = Twitter(auth = OAuth(access_token, access_token_secret, consumer_key, consumer_secret))
latitude = 1.3521
longitude = 103.8198
max_range = 20
query_search = user_input + "-filter:retweets"
query = twitter.search.tweets(q = query_search, geocode = "%f,%f,%dkm" % (latitude, longitude, max_range), lang='en',count=3)
answer = f'\U0001F4F1 Showing latest 3 tweets in SG for: {user_input}'
update.message.reply_text(answer)
update.message.reply_text(query['statuses'][0]['text'])
update.message.reply_text(query['statuses'][1]['text'])
update.message.reply_text(query['statuses'][2]['text'])
这个命令的代码比较长,它包含两个函数,一个是提示用户输入搜索词,另一个是内部调用 Twitter API,并将最近的 3 条相关推文返回给用户。像往常一样,需要一个开发者账户来获取消费者密钥、消费者秘密、访问令牌、访问令牌秘密。在获得 search_term 后,机器人将调用 Twitter API,并继续搜索新加坡最近的 3 条推文(即,我已经设置了纬度和经度)。然后,tweets
命令会将最近的 3 条 tweets 返回给用户。
图片由作者提供— /tweets 命令,输入“比特币”
/news 命令
最后一个命令将通过调用 newsapi API 为用户检索最新的新闻。注意,我没有将这个命令命名为news
,而是分成了 5 个不同的命令covid
、technology
、business
、sports
、entertainment
,因为 API 允许我根据类别发出请求。你还需要在这里注册一个开发者账户来获得 api_key。
# business news
newsapi = NewsApiClient(api_key='...')
business_news = newsapi.get_top_headlines(category='business', language='en', country='sg', page_size=3)
def business(update, context):
business1 = list(business_news.values())[2][0]['title'] + '\n\n' + list(business_news.values())[2][0]['url']
business2 = list(business_news.values())[2][1]['title'] + '\n\n' + list(business_news.values())[2][1]['url']
business3 = list(business_news.values())[2][2]['title'] + '\n\n' + list(business_news.values())[2][2]['url']
update.message.reply_text(business1)
update.message.reply_text(business2)
update.message.reply_text(business3)
我在 API 命令中列出了根据所选的不同类别检索最新的 3 条新加坡新闻。对于上面的代码,运行business
命令将返回预览和来自新加坡的最新 3 条商业相关新闻的 URL 链接。
图片作者—/商业命令
结尾注释
有大量其他 API 可供开发人员免费使用,我一定会在这个机器人上添加更多命令,这样它就可以真正成为用户访问日常信息的一站式门户。这个机器人对每个人都是公开的,你可以在 Telegram 上找到 motherofapi 来开始使用这个机器人。请注意,由于这个 bot 托管在 Heroku 平台上,当您运行它时,它可能需要 15 秒钟才能启动。希望你喜欢这篇文章以及我的机器人,并通过评论这篇文章向我推荐你希望在这个机器人中看到的可能的想法/API,干杯!😄
建立信用风险模型的可视化模型监控系统
在本教程中,我们将从头开始使用 ML 构建一个信用风险模型,并使用一个使用 Datapane 的可视化跟踪系统来监控它。
纽约公共图书馆拍摄于 Unsplash
想买新房?有可能你需要从银行贷款,这将涉及信用风险评估。
什么是信用风险?信用风险是指借款人因未能支付所需款项而违约的可能性。风险是金融机构和其他贷方贷款模式的固有部分。
介绍
信贷风险建模是贷款人确定贷款偿还可能性的最有效方法。贷方使用历史数据,如支付历史、当前债务水平和信用历史的平均长度,来预测消费者未来拖欠贷款的可能性。在本教程中,我们将从头开始开发一个信用风险机器学习模型,并构建一个数据面板报告来监控和跟踪管道。
为什么需要模型监控?
我们希望确保该模型仍然可以基于新的客户数据准确预测违约者,因为人口构成可能会随着时间的推移而变化。让我们假设我们使用 2000 年至 2018 年的数据建立了一个信用风险模型——这是一个强大的数据集,因为它涵盖了很长一段时间以及像 2008 年金融危机这样的中断期。该模型在 2019 年之前表现良好,但不能确定它在 2020 年或 2021 年仍然有用——只要想想世界因 COVID 而改变了多少。监控系统有助于识别随时间的变化,以便我们可以在必要时调整我们的模型。
我们将在本教程中介绍模型开发的基础,我们的主要焦点将是使用 Datapane 创建跟踪系统。详细的代码可以在 Github 上找到。
免责声明:本文是与 Datapane 合作撰写的,我是 datapane 团队的一名社区布道者。
利用机器学习建立信用风险模型
步骤 1 —初步分析
在本教程中,我们将使用来自 Kaggle 的德国信用风险分类数据集。该数据集包含 1000 个条目,具有 Hofmann 教授准备的 20 个类别/符号属性。在这个数据集中,每个条目代表一个从银行贷款的人。根据属性集,每个人被划分为好的或坏的信用风险。
来源:图片由作者创作
一旦数据加载完毕,我们将使用 Pandas Profiling 自动生成一份包含数据集基本信息的报告,如描述性统计、缺失值、相关性等。虽然通常的方法是生成一个 HTML 报告,但是我们将使用 JSON extract 来标识我们的 Datapane 报告所需的变量。
步骤 2-为报告创建数据可视化绘图
完成初步分析后,我们需要创建几个图来进行数据探索。这些图背后的想法是突出任何数据差异或现有数据的差异,这些数据是模型训练的基础。一旦创建了图,我们需要确保将它们存储在变量中,然后可以直接在我们的报告中使用。
我们为此创造了几个情节,你可以参考笔记本上的代码。
步骤 3 —预处理数据
一旦我们很好地理解了数据及其隐藏的特征,我们现在将着手建立我们的信用风险模型。但在此之前,我们将做一些基本的预处理步骤,以确保我们的数据得到很好的净化,我们可以建立一个体面的模型。
由于数据处理涉及大量数据转换,建议在报告中添加前后图像,以确保转换正常工作。
我们可以删除不需要的变量,并将数据集分成训练集和测试集。
步骤 4-训练多个模型以找到最佳模型
现在我们的数据已经准备好了,我们将训练我们的模型,根据已经标记的数据来预测一个人是否有信用风险(“Risk_bad”)。我们保留 25%的训练数据用于测试目的。
我们需要训练多个模型来找到表现最好的一个。为了快速做到这一点,我们将所有的模型添加到一个循环中,然后根据它们的回忆分数对它们进行评估。
我们以这样的情节结束-
基于此,我们将选择高斯 NB 作为我们的首选模型,因为它具有最高的准确性。
步骤 5——建立信用风险模型
我们将使用高斯 NB 算法来构建我们的模型。你可以在这里阅读更多关于这个的内容。
我们得到了 70.53%的准确率,这对于一个简单的模型来说是相当不错的。我们来评价一下分类矩阵。
我们得到了 68%的精确度和 65%的召回分数,以及 66%的 F1 分数。虽然分数不是最佳的,但我们总是可以提高。如果你对提高模型性能感兴趣,你可以在这里查看笔记本。
我们还将绘制 ROC 曲线,并将其保存为图。这些视觉元素将作为报告的一部分添加进来。
现在我们已经完成了创建信用风险模型的基本步骤,让我们设计并构建 Datapane 报告,它将作为一个监控系统来跟踪数据和模型如何随时间变化。
使用 Datapane 设计和构建可视化模型监控系统
步骤 1 —设计数据面板报告
要构建一份全面且涵盖 MLOps 清单大部分方面的报告,重要的是首先设计报告,然后在此基础上构建。我们会把报告写得非常简单,只有 5 页纸-
来源:图片由作者创作
- Summary page —该页面将提供每个迭代的变更的高级视图,例如报告更新日期、更新注释(供数据团队向报告添加关于变更的注释)、基本模型属性以及下载报告的链接。
- 项目详情 —该页面将提供关于项目、相关数据集和数据属性的简要说明。当与可能不了解项目完整细节的风险承担者共享报告时,这很有帮助。
- 数据概要 —该页面将提供数据概要元素,例如数据的不同特征、相关性、缺失变量,以及在需要时访问整个数据集的方法。
- 探索 —该页面将展示分析的数据可视化元素。分析过程中创建的所有图和可视元素都可以在此处分组和显示。
- 模型跟踪 —这将是最后一页,提供关于所用模型、其性能参数和评估矩阵的信息。
步骤 2——在 Datapane 中构建报告页面
为了构建数据面板报告,我们将遵循一个 3 步流程
- 定义页面的单个元素。
- 定义包含所有元素的页面。
- 将页面添加到报表中。
如果您是 datapane 的新手,请查看这里的指南开始使用。
例如,为了构建摘要页面,首先,我们定义文本块、图像块和 BigNumbers 块。
我们还将从我们的配置文件报告中提取值,并为它创建另一个块。
步骤 3-创建数据面板报告
接下来,我们将所有这些块添加到页面中。
最后,我们将所有页面添加到报告中。
这种结构增加了整个过程的简单性和模块化!类似地,定义所有页面并将它们添加到报告中。
步骤 4——将报告发布到 Datapane
一旦创建了报告并且预览了它 , 将报告发布到数据面板。最后你应该会有这个这样的东西。
步骤 5 —将数据面板代码添加到笔记本中
成功发布报告后,添加代码文件作为笔记本/脚本文件的一部分。
来源:图片由作者创作
因此,无论笔记本或脚本何时运行,报告都会得到更新,并反映可以根据需要与利益相关者共享的更改。
将数据面板报告集成到您的 ML 管道中
一旦您对 Datapane 报告感到满意,您就可以将笔记本作为数据管道的一部分来运行。有几种方法可以做到这一点:
- 每次想要更新模型时,请手动运行笔记本
- 从您的主 Python 笔记本创建一个 Datapane 脚本
- 根据新数据定期重新培训的模型的工作
- 气流用于更复杂的 ML 管道
结论
机器学习允许我们创造全新的产品和能力,这是通过传统的软件开发不可能实现的。然而,这些模型仍然可能以独特和不可预测的方式失败。
有了监控系统,团队可以实时跟踪模型并评估它们的性能。它还可以帮助识别基础数据中不断变化的模式和新的流入,以便在必要时重新训练模型。
使用 Datapane 这样的开源工具,而不是复杂的 MLOps 平台,可以非常容易地构建这个监控系统。它不仅是可视化的,而且可以通过电子邮件/Slack 共享,这样所有的利益相关者都可以及时了解最新情况,从而做出业务决策。
使用 Docker (2021)构建可移植的数据科学环境
一个 Docker 驱动的虚拟环境,供初学者随时随地使用
图 1 —对接过程(原始)
在过去的一年中,我不得不三次更换我的工作笔记本电脑,并且在错误的地方设置新的开发机器总是一件痛苦的事情。
我最终决定尝试一下 Docker,并发现它非常有用。
然而,学习 Docker 是一个挑战,因为不完整的资源分散在互联网上。我不想成为 Docker 大师,我只需要知道足够多的信息来避免依赖性问题,并根据我的需要构建+复制我的工作环境。
我使用 Docker 作为数据科学和分析工作的首选环境。我很少被要求制作我的作品,但是,如果你需要的话,Docker (+ Compose)是一个很好的方法。
目录(单击导航)
目标计划
1/ Docker 先决条件
2/项目需求
构建
3/编写 Dockerfile
4/从 Dockerfile 构建映像
5/从映像创建容器
6/在存储(卷)上
使用
> >目标
在本演练结束时,您应该拥有一个设备齐全的数据科学/分析环境,它:
- 可移植的——通过简单的拉取请求(类似 Git)可在任何机器上访问
- 隔离/受控 -安装的依赖关系被冻结,没有更新/升级问题
- 可复制的 -通过简单的“docker 运行”创建一个副本(或更改它)命令
- 类似协作的 Git(超出范围)
这样的环境适合于原型开发、EDA 和探索库等等。
注意:如果你不熟悉 Docker 的基础知识,可以参考我个人用过的资源:
> >计划
1/ Docker 先决条件
要构建 Docker 容器,您的机器上需要 Docker。
前往 Docker 网站下载 Docker。按照这里的步骤在 Mac、Linux 或 Windows 上设置它。这是一个简单的 GUI 步骤序列,应该不会给你带来任何问题。
在 DockerHub 上注册,就能把你的图片推送到你的存储库。这将允许您在任何机器上下载映像,并准备好您的便携环境。
新,登录您的 DockerHub 帐户:
- 启动您的终端并输入以下命令。出现提示时,输入密码。
docker login -u [USERNAME]
# Dockerhub username
- 通过运行官方的 hello-world 示例来测试 Docker 设置。
% docker pull hello-world . # pull the example image% docker images -a # list all available images% docker run hello-world # create a container from the image
如果能看到“Docker 的你好!”在您的终端上,您已经有了一个正确安装的 Docker。如果不能,再尝试安装 Docker。
2/项目要求
我们在建造什么?
- 一个 Python 环境
- 常用软件包 — Pandas、PySpark、TensorFlow、Plotly、Matplotlib、NumPy
- 冻结包—避免依赖性问题
- Jupyter 笔记本 —通过浏览器提供的首选 IDE
- 存储 —虚拟存储应该是持久的,并且必须与我的本地存储绑定(以便于轻松添加新文件和数据库)
码头工作流程
Docker 的工作原理,简而言之:
- docker file——你为你想要的那种环境(容器)创建蓝图。
- 图像——你从 Dockerfile 文件中构建一个图像。
- 容器 -你从图片中创建一个容器。你所有的工作都会在这里完成。您可以根据需要启动和停止这个“虚拟机”。
- 上传(和下载)到云——把它推送到 DockerHub,这样你就可以在任何地方下载和使用它。
集装箱化的过程
项目结构
- 我将创建一个名为“analytics_env”的任意文件/项目结构。
- 添加一个“数据”文件夹。您可以将数据添加到系统上的这个文件夹中,并在您的容器中访问它,反之亦然。
- 将创建一个没有扩展名的“Dockerfile”。我们将在这里书写我们的虚拟环境蓝图。
- 存储任何上下文信息的“readme.txt”。
注意:不要浪费时间在本地系统上寻找 Docker 映像和容器。Docker 的 UI 仪表板(在步骤 1 中安装)在访问和管理它方面更加方便。
项目文件夹结构
您可以手动创建它,或者使用您的终端/IDE 来创建它。
> >构建
3/编写 Dockerfile 文件
一旦创建了项目结构“analytics_env ”,就可以打开 IDE 并导航到它的目录。接下来,我们可以打开“Dockerfile”并定义虚拟环境的蓝图。
FROM python LABEL maintainer="jaethalal"
LABEL version="1.0"
LABEL description="docker image for data science development env" RUN pip install jupyter numpy pandas matplotlib plotly dash EXPOSE 8888
CMD [ "jupyter", "notebook", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root" ]
让我们将 docker 文件分解成它的组件:
- FROM python- Dockerhub 有一个准备好的带有基本环境的映像的注册表(比如我们的例子中的‘OS+Python’)。映像是分层构建的,基础层是一个操作系统发行版。您可以使用这些图像,并通过添加更多组件来修改它们。在这一步中,我们采用了基本的 Python 图像。
- 标签维护者,版本,描述- 添加标签进行识别。这是一个可选但强烈推荐的步骤。
- 运行 pip inst…- 一旦基本 python 映像被检索到,您运行一个 pip 命令在它上面安装所有的包。这个 pip 命令被附加到运行指令上。“运行”在映像构建时执行。因此,每当从这个 Dockerfile 文件构建映像时,所有列出的包都将被安装到 Python env。
- EXPOSE 8888- 因为 Jupyter 笔记本是通过浏览器访问的,所以你需要从你的容器向外界,也就是主机,公开一个端口(比如 8888)。
- CMD[“jupyter”…- 如果在运行容器时没有指定命令,默认情况下会执行 CMD 命令。如果你这样做,CMD 将失去优先权。因此,CMD 是设置默认指令的好方法。
在这里,我们在 localhost:8888 上默认启动和服务 Jupyter 笔记本,只要容器运行。
我们完了!继续保存 Dockerfile 文件。
蓝图已经准备好了,现在唯一剩下要做的就是“造”。
4/从 Dockerfile 文件构建映像
我们将使用以下命令从 Dockerfile 文件构建一个映像:
% docker build -t prototype_env_image . # 'prototype_envm_image' is the name I've given to the image. # You can give it any name
# Do not miss the period(.) at the end of the command, it specifies the directory where your dockerfile is located
当您运行该命令时,需要一分钟时间。python 映像将被下载,docker 文件中列出的包将被安装在它上面。
让我们看看该命令的各个组成部分:
docker- 所有 docker 命令前面都有关键字“docker”
**build-**表示您正在从 docker 文件
**prototype _ env _ image-**中构建一个图像;用户自定义
。- 表示您正在从当前目录中的 Dockerfile 文件构建一个映像
要查看所有已构建图像的列表,您可以:
docker images -a # list all available docker images
这是我手头所有 Docker 图片的列表。您可以在列表顶部找到我们的“analytics_env_image”。
现在让我们进入最后一步。我们将从刚刚构建的 Docker 映像“analytics_env_image”中旋转出一个容器。
5/从图像创建容器
我们将把我们的容器命名为“analytics_env_c1”。
要从图像创建容器,请使用:
docker run \
--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
-w /analytics_env \
-p 8888:8888 \
analytics_env_image
这是一个单独的命令,为了清楚起见,使用了“\”操作符将其分成多行。
当您运行该命令时,您会看到类似这样的内容。底部的 URL 表示您的容器已经创建并且正在运行。您也可以在命令中用“create”替换“run ”,它只会创建一个容器,而不会运行它。然后您可以使用“docker start”在以后运行它。
有效,运行=创建+启动
您只需在默认浏览器中“按住 ctrl 键并单击”最后一个链接,就可以重定向到 Jupyter 笔记本,也可以复制并粘贴它。
但是首先,让我们一步一步地构建这个命令的最后一个庞然大物:
# create a container from the image "analytics_env_image"
**docker run analytics_env_image** # use --name to give the container a name= "analytics_env_c1"
**docker run \
--name analytics_env_c1 \
analytics_env_image** # use -v to bind your local directory "/Users/apple/analytics_env" with a directory inside the container "/analytics_env"
**docker run \**
**--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
analytics_env_image ** # use -w to set the "/analytics_env" inside the container as the working directory
**docker run \
--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
-w /analytics_env \
analytics_env_image ** # use -p to assign the local machine port 8888 (unassigned; user-defined) to the container port 8888 (assigned to Jupyter Notebook) **docker run \**
**--name analytics_env_c1 \
-v /Users/apple/analytics_env:/analytics_env \
-w /analytics_env \
-p 8888:8888 \
analytics_env_image**
注意:每当需要使用冒号(:)操作符时,请记住它会将’ left:right 映射为’ host_machine:docker’ 。
6/侧栏:存储上
我们有两种存储选项—卷和绑定装载。卷由 Docker 隐式管理,与主机的物理存储无关。绑定装载使共享存储成为可能。它使 docker 使用指定的目录作为其主要存储。
正如我们在需求部分讨论的那样,我们的存储需要:
- 持久 —当容器关闭时,数据不会消失
- 绑定 —添加到主机存储的文件应该反映在容器内部,写入容器存储的数据应该可以被本地主机访问
绑定安装是提供给我们 2。这就是我们在“docker run …”命令中使用“-v”(—volume)标记来装载主机存储并将其与“analytics_env_c1”的存储绑定的原因。
> >使用
7/从容器运行 Jupyter 笔记本
当你点击链接或访问“localhost:8888”时,你会发现你的 Jupyter 笔记本正在运行。
然而,有一个复杂的问题。下次您尝试运行容器并访问此 Jupyter 笔记本时,您将无法登录,除非您使用以下任一方法为笔记本设置密码:
- Jupyter 配置文件
- 一次性密码设置
我们将采用第二种更简单的解决方案——“一次性密码设置”。遵循以下步骤:
- 在 Jupyter 笔记本的右上角,点击“注销”
- 在下一页,点击“登录页面”
- 这里,你会看到这一页
- 回到您的终端/IDE,从 Jupyter 笔记本重定向链接复制令牌
- 粘贴令牌并输入您喜欢的任何密码。我先说“赛克”。
- 点击“登录并设置新密码”。您将登录。下次运行该容器并访问该笔记本时,屏幕顶部会要求您输入密码(检查步骤 3 中的图像)。
- 继续创建一个随机数据帧,并将其作为 CSV 导出到“/data”文件夹中,以测试您的存储设置。
- 即使您是在容器中完成的,您也可以在本地系统中看到它。
8/在 Docker 中移动
- 停止运行容器:说你累了,今天的工作做完了。你想关掉这个容器然后去睡一觉。有两种方法可以做到:
- 只需回到终端/IDE,然后按“ctrl+c”。
- 您可以打开一个新的终端并键入
docker stop analytics_env_c1
- (重新)启动一个容器:下次您决定参与这个项目时,打开您的终端并键入:
docker start analytics_env_c1 # or docker restart analytics_env_c1
# These commands will not spit out the link for jupyter nb like the last time
# but you can still visit localhost:8888 and you'll find it running
- 列出所有的容器和图片:你可能会忘记你工作过的容器的名字。因此,您可以使用以下命令列出所有容器:
# list all containers
docker ps -a# list active containers
docker ps# list all images
docker images -a
- 删除容器和图像:您可能想要删除容器或图像。您可以使用:
# delete all dangling containers (dangling - containers without a base image)
docker container prune# delete all dangling images (dangling - no containers related to the image)
docker image prune# To avoid caching RUN command while installing packages in the Dockerfile
# Caches prevent docker from fetching updated packages
RUN pip install pandas, numpy --no-cache# To avoid loading previous cache while building images
docker build --no-cache -t helloapp:v2 .
- 检查容器/图像:如果你觉得勇敢,你可以使用下面的命令来检查容器或图像。它将向您显示所有的配置细节和有问题的映像/容器的状态。
# inspect the image
% docker inspect analytics_env_image#Inspect the container
% docker inspect analytics_env_c1
9/将 Docker 映像推送到云存储库— DockerHub
像 GitHub 一样,你可以在 DockerHub 上保存你的 Docker 图片,并在你需要的时候调用它。我们把“analytics_env_image”推送到 DockerHub。
- 登录 DockerHub
- 创建一个存储库“portable_analytics_env”
- 打开你的终端
- 导航到项目根位置(docker 文件所在的位置)
- 使用标记 username/repo_name 构建 Dockerfile 文件(再次是)
# build the image with the tag 'username/repo_name'
docker build -t jeathalal/portable_analytics_env .# push the image to dockerhub
docker push jeathalal/portable_analytics_env
10/在新系统上使用 Docker
比方说,你的 MacBook 在一个晴朗的日子停止工作,你不得不买一台新的。理想情况下,您希望能够访问您在早期机器上拥有的相同环境。你花了几周时间配置和设计它。
还好你推给了 DockerHub。我们将从我的存储库中提取之前推送的图像。
安装 Docker 并登录到您的 DockerHub 帐户,如上面的第 1 节所示。就像我们在 hello-world 示例中所做的那样,简单地提取先前上传的文件。
% docker pull jaethalal/ds_env
大概就是这样!如果你愿意,请在评论中留下任何问题或反馈!
构建 Python CLI 工具从 Markdown 文件中提取 TOC
通过自动化枯燥的任务来学习—第 1 部分
为降价文件创建目录—由作者创建的图像。
不久前,我在 markdown 上为我公司的 DevGuide 写了很多文章——我们用 Hugo 来构建它作为一个内部网站——并对创建和修改目录(TOC)这一非常重复、非常无聊的任务感到恼火。每当我更改标题、引入新的子章节或删除其他章节时,我都必须一次又一次地手动编辑目录。在回顾和编辑了几篇文章之后,我终于厌倦了寻找工具和“易于使用”但可配置的选项。我对它的缺乏感到惊讶。
所以我决定编写自己的最小 CLI 工具,从 markdown 文件中自动提取目录(TOC)。在本文中,我将介绍实现所需的需求、设计决策和核心功能。当然,这个项目是开源的,任何人都可以扩展它。
需求和初步想法
由于 TOC 通常被放在减价文件的不同位置,所以默认情况下没有必要将其插入文件的第一行。例如杰基尔和雨果都要求降价文件的前几行包含他们各自的封面。
一般来说,编辑文件本身并不是一个好主意。事情偶尔会出错。理想情况下,我们希望最终决定权(插入 TOC)掌握在自己手中。只有当我们能够准确地定义决策参数和最佳结果时,我们才能够自动化决策——在这种情况下,这将是章节标题的语法内容和“感觉”。难以自动化。
总之,这意味着 TOC 应该
- 返回到控制台检查结果并启用复制粘贴(这需要是默认设置),
- 可选地放置在剪贴板中,
- 可选地被复制到文件的第一行,
- 可选地放置在单独的文件中。
此外,我们应该允许用户通过对包含的标题级别设置自定义限制来限制 TOC 的深度。有些人喜欢三个标题层次的目录,有些人只喜欢看主要的。
格式注意事项
关于 TOC 本身列举的实际格式,章节的可点击链接应该是首选。也许这只是我的懒惰,但是如果 TOC 不能被点击,我不能跳转到我感兴趣的章节,那么创建一个表格 OC 内容又有什么意义呢?这意味着我们需要以下输出格式之一:
第一个选项更常用:
GitLab 风格的目录链接降价。
或者 HTML 锚的第二个选项:
目录链接的 HTML 锚。
第二种选择需要在现有的降价文件中插入和格式化锚点,并在降价文件中引入 HTML。这两件事都很难论证——我也不是特别喜欢。
它们也与上面的需求相冲突,因为我们不需要将 TOC 直接插入到文件中,尤其是不需要到处都有多个分离的锚线。请记住,我们的目标是一个小而易用的解决方案,这个决定显然有利于第一种格式。
核心功能
在明确了最初的设计决策和我们自己设定的需求之后,让我们来看看需要的功能。一般来说,我们有以下步骤:
- 读取文件
- 清理文件
- 识别标题
- 格式化标题
- 创建目录
- 输出目录
我们开始吧。
读取文件
我们在这里不需要做什么特别的事情,我们只需要读取文件并根据换行符将它分成单独的行。
正在读取文件。
旁注:与使用readlines()
相比,我更喜欢上面的语法,因为readlines()
返回的行带有一个结束换行符,稍后必须对其进行清理。我们也可以一次将整个文件加载到内存中,因为降价文件很少有千兆字节的数据。
清理文件
在提取文件头之前,我们需要从文件内容中删除所有代码块及其内容。Python(以及其他编程语言)可以将有效的 hashtags 作为一行中的前导字符(例如,作为注释),这将与我们的头检测相冲突。由于这是一个简单的转换步骤,我们可以为它编写一个快速函数。
该函数接收一个行列表,过滤掉所有代码块并返回过滤后的列表。
识别标题行
在 markdown 中有两种创建标题的方法
- 在标题标题前面的同一行中使用一定数量的标签(
#
) 的常见选项 - 或者,*在下面的下一行中,*为 1 级标题添加任意数量的等号(
=
)或连字符(-
)作为 2 级标题。
第二种选择的明显缺点(除了难看之外)是语法将我们限制在两个级别的头。到目前为止,我也很幸运地在我参与的项目中没有看到第二种形式。然而,为了确保完整的功能,让我们包括两种格式的识别方法。
检测标题行的常见类型的逻辑非常简单:我们可以使用 regex 模式将一行标识为标题行:r"^#+\ .*$"
(前导标签,后跟空格,然后是任何可能的字符)。
对于其他类型的标题,我们只需检查该行是否以等号(regex: r"^=+ *$"
)或连字符(regex: r"^-+ *$"
)开头,并且直到行尾除了空格之外没有任何其他字符。如果是这样,我们添加前面的行作为标题。为了下一步省事,我们还会统一头格式。
识别标题行并过滤掉其他行。
示例转换:
过滤非标题行的转换示例。
格式化标题
识别标题后,我们需要确定它们的级别,并为目录本身创建格式化的行。
从 GitLab 文档中,我们可以了解如何格式化 TOC 中常用的 markdown 链接:
- 所有文本都转换成小写。
- 所有非单词文本(如标点符号或 HTML)都将被删除。
- 所有空格都转换为连字符。
- 一行中的两个或更多连字符被转换为一个。
- 如果已经生成了具有相同 ID 的报头,则附加一个唯一的递增数字,从 1 开始。
下面的函数将涵盖这些规则中的大部分——无可否认,在一些边缘情况下,链接会失败,但对于 95%的情况,我们是好的。完美是令人钦佩的,但寻找边缘案例和实现解决方案所需的时间在目前是不值得的。当我们(或其他潜在的未来用户)确实遇到需要考虑的边缘情况时,我们总是可以轻松地扩展我的代码。
格式化标题和创建可点击的链接。
示例转换:
示例转换。
创建目录
对于目录本身,我们必须对标题和子标题进行格式化和编号。如果下一个标题的级别高于前一个,我们还需要重置编号。
将 TOC 中的每一行组装成一个字符串包括(按顺序):
- 副标题可能的缩进,
- 标题编号,
- 标题文本和
- 标题的链接。
我们还可以引入一个名为level_limit
的变量来限制 TOC 的深度。
创建内容行的实际表格。
示例转换:
从准备好的数据创建 TOC 行的示例。
结合目前为止的工作
我们现在已经实现了核心功能,很快就可以开始研究将它转换成 CLI 包的必要条件以及如何输出结果。
核心功能。
输出目录
根据所需的结果,我们将 TOC 复制到剪贴板,将其插入 md 文件或写入一个新文件。这主要是标准实践的东西,也许除了为我们的新 TOC 文件找到一个合适的文件名。
将目录写入不同的通道。
创建 CLI 功能
为了能够从命令行调用带有可配置参数的包,我们使用了 argparse 模块。
记住我们的要求,我们希望用户:
- 指定文件名(必需的参数)
- 能够将目录复制到剪贴板(可选参数
--copy
) - 能够将目录插入文件(可选参数
--insert
) - 能够将目录保存到一个单独的文件中(可选参数
--save
) - 能够限制 TOC 的深度(可选参数
--levels <number-of-levels>
)
在创建了带有名称和描述的ArgumentParser
之后,我们必须单独添加每个参数:
为 CLI 创建参数。
查看存储库文件中的全部参数。
之后,访问参数/变量就像下面这样简单:
最棒的是,我们自动包含了--help
参数背后的功能。这里的输出是:
打包、发布和访问
因为我们也希望能够在我们曾经接触过的任何其他计算机上安装它(并且也让其他用户可以使用它),我们可以创建一个简单的setup.py
文件,打包代码并将其发布在 pypi 上。打包 CLI 工具与任何其他 python 打包过程并无不同。
如果你对setup.py
和如何打包代码感兴趣,看看吧
- 存储库中的文件,或
- 在官方文件中,或
- 在像 geeksforgeeks 这样的教程上,或者
- 像詹姆斯·布里格斯在媒体上发表的文章。
快速旁注:为了测试你的打包软件,而不必把它上传到 pypi,然后通过 pip 安装,你可以简单地使用pip install .
直接从你的setup.py
文件所在的本地目录安装它(是的,这是一个点——表示当前目录)。
完成这一步后,世界各地的每个人都可以使用pip install extracttoc
安装 CLI 工具了!
用途
下面是该工具如何从命令行工作的几个具体使用示例:
关闭思想
一般来说,编写软件使自己的生活变得更容易是很好的编码实践。然而,创建开源包(帮助其他人解决同样的问题)会迫使你写出高质量的好代码,这些代码可以被其他人理解并在 T21 的基础上扩展。在你认为没有人会阅读的代码中,你可能没有考虑高优先级的事情(比如不仅仅命名你的迭代变量x
…)在考虑其他人将如何与代码交互时,突然变得更加重要。编写开源代码无疑会受到其他人的批评,这让我们关注风格和开发最佳实践——这让我们成为更好的程序员。
如果你觉得有空的话——试试包,或者看看 github 上的源代码,如果你想看完整的话!
创建一个 CLI 工具对我来说是新的,但在我的工具箱里是一个非常方便的技能。我确信我将来会再次使用它。
一如既往,我们永远学不完。了解有关…的更多信息
- Markdown 基本语法
- 降价 GitLab 口味
- Python 的 argparse 模块
- Stackoverflow 关于代码质量的想法
- 包装项目的 Python 文档
- geeksforgeeks 的打包教程
- 詹姆斯·布里格斯关于包装的文章
- 用 jekyll 建立网站
- 用 hugo 建网站
在 Medium 上关注我,获取更多关于数据工程工具以及软件和个人发展的文章!
构建 Python 代码生成器
使用转换器将英语问题语句转换成 Python 代码
NLP 技术可以用来生成实际的代码吗?我们离一个用 AI 写软件的世界还有多远?
在这篇博客中,我尝试构建一个 python 代码生成器,它可以将简单的英语问题语句转换成相应的 python 代码。
图 1:生成 python 代码的转换器。😉(原始图像来自 unsplash
我们通过把它作为一个序列到序列(Seq2Seq) 的学习问题来处理这个问题。在这里,我们的英语句子将是我们的输入或 SRC 序列,我们的 Python 代码将是我们的输出或 TRG 序列。
在过去的几年里,变压器已经成为解决 Seq2Seq 问题的主导架构。大多数当今的 SoA 模型,如 BERT 或 GPT-3,都在内部使用转换器。我们今天所知的变形金刚是由谷歌在他们的 “注意力是你所需要的一切” 论文中首次介绍的。我们在博客中讨论的“英语到 Python”模型也在本文中找到了它的动机。
在我们开始解决问题之前,让我们先简要回顾一下变压器。
变形金刚
图 2:变形金刚(图片来自 d2l.ai )
变压器可以从三个方面来理解:
- 将输入序列编码成状态表示向量的编码器。
- 一种关注机制,使我们的 Transformer 模型能够关注顺序输入流的正确方面。这在编码器和解码器中重复使用,以帮助它们将输入数据置于上下文中。
- 解码器,对状态表示向量进行解码,以生成目标输出序列。
在我之前的 博客 中,我已经详细解释了这些组件中的每一个,并附有代码演练。
现在让我们看看如何将数据输入到转换器中。
了解培训数据
我们将使用定制的 数据集 由AI(TSAI)学院策划来训练我们的模型。这个数据集包含大约 5000 个数据点,其中每个数据点包含一个英文问题语句及其对应的 Python 代码。可以关注我的 项目回购 了解如何解析数据。
样本数据点:
英文语句:“写一个将两个数相加的函数”
Python 代码:
def add_two_numbers (num1 ,num2 ):
sum =num1 +num2
return sum
这里的"英文语句"是我们的输入或 SRC 序列,而" Python 代码"是我们的输出或用于训练的 TRG 序列。
将数据符号化
我们的输入(SRC)和输出(TRG)序列以单个字符串的形式存在,需要进一步标记才能发送到 transformer 模型中。
**为了标记输入(SRC)序列,我们使用了空间 。这在 PyTorch 的torch text . data . field**中默认实现。我们将使用 torchtext.data.Field 通过 spacy 来标记我们的数据。
Input = data.Field(tokenize = 'spacy',
init_token='<sos>',
eos_token='<eos>',
lower=**True**)
为了对我们的输出(TRG)序列进行标记化,我们使用了基于 Python 源代码标记化器构建的自定义标记化器。Python 的 tokenizer 为每个标记返回几个属性。我们只提取元组形式的令牌类型和相应的字符串属性(即(token_type_int,token_string))作为最终令牌。
标记化输入(SRC):
SRC = [' ', 'write', 'a', 'python', 'function', 'to', 'add', 'two', 'user', 'provided', 'numbers', 'and', 'return', 'the', 'sum']
符号化输出(TRG):
TRG = [(57, 'utf-8'), (1, 'def'), (1, 'add_two_numbers'), (53, '('), (1, 'num1'), (53, ','), (1, 'num2'), (53, ')'), (53, ':'), (4, '\n'), (5, ' '), (1, 'sum'), (53, '='), (1, 'num1'), (53, '+'), (1, 'num2'), (4, '\n'), (1, 'return'), (1, 'sum'), (4, ''), (6, ''), (0, '')]
数据扩充
由于我们的数据集仅包含 5000 个数据点,我们利用数据扩充来增加数据集的大小。在标记 python 代码时,我们随机屏蔽某些变量的名称(用‘var _ 1’、‘var _ 2’等),以确保我们训练的模型不仅仅关注变量的命名方式,而且实际上试图理解 python 代码的内在逻辑和语法。
例如,考虑下面的程序。
def add_two_numbers (num1 ,num2 ):
sum =num1 +num2
return sum
我们可以替换上面的一些变量来创建新的数据点。以下是有效的扩充。
1.
def add_two_numbers (var_1 ,num2 ):
sum =var_1 +num2
return sum
2.
def add_two_numbers (num1 ,var_1 ):
sum =num1 +var_1
return sum
3.
def add_two_numbers (var_1 ,var_2 ):
sum = var_1 + var_2
return sum
在上面的例子中,我们使用随机变量替换技术将一个数据点扩展为另外 3 个数据点。
我们在生成 TRG 令牌时实现我们的扩充。
当随机选择变量来屏蔽时,我们避免关键字文字( keyword.kwlist )、控制结构(如下面的 skip_list 所示)和对象属性。我们将所有需要跳过的文字添加到 skip_list 中。
我们现在使用 Pytorch 的 torchtext.data.Field 来应用我们的扩充和标记化。
Output = data.Field(tokenize = augment_tokenize_python_code,
init_token='<sos>',
eos_token='<eos>',
lower=**False**)
我们的测试应用标记化后的标记化输出(TRG) :
TRG = [(57, 'utf-8'), (1, 'def'), (1, 'add_two_numbers'), (53, '('), (1, 'num1'), (53, ','), (1, 'var_1'), (53, ')'), (53, ':'), (4, '\n'), (5, ' '), (1, 'sum'), (53, '='), (1, 'num1'), (53, '+'), (1, 'var_1'), (4, '\n'), (1, 'return'), (1, 'sum'), (4, ''), (6, ''), (0, '')]
喂养数据
为了将数据输入到我们的模型中,我们首先使用 Pytorch 的torch text . data . bucket iterator创建批处理。这确保了具有相似长度的输入一起留在单个批次中,以便于训练。然后,我们将标记化输入(SRC)批次送入编码器,并在解码器中使用标记化输出(TRG)批次。我们的目标是使用编码器的标记化英语输入(SRC)来预测通过解码器的标记化 Python 输出(TRG)。然后,标记化的预测通过 Python 源代码标记化器的取消标记化函数取消标记化。
图 3:编码器的输入和解码器的输出。(图片来自谷歌 arxiv 研究)
损失函数
我们在数据集中使用了扩充来屏蔽变量文字。这意味着我们的模型可以预测特定变量的各种值,只要预测在代码中保持一致,所有这些值都是正确的。这将意味着我们的训练标签不是非常确定,因此以概率 1- smooth_eps 将它们视为正确,否则视为不正确将更有意义。这就是标签平滑的作用。通过添加标签平滑到交叉熵中,我们确保了模型在预测一些可以通过增强来替代的变量时不会变得过于自信。
图 4:标签平滑(来源:深度学习,Goodfellow 等人 2016)
现在我们所有的组件都设置好了,我们可以使用反向传播来训练我们的模型。我们将数据集分为训练数据和验证数据。我们的模型被训练,直到我们的验证损失不再进一步改善。
值得注意的是,与不使用标签平滑的模型相比,标签平滑会导致更高的损失值。但这是意料之中的,因为我们不打算确定我们的标签预测。对于变量尤其如此,因为只要预测在整个目标代码序列中是一致的,就可以有多个正确的选项。
完整的训练代码请参考我的笔记本。
样本结果
输入:“程序按关键字排序字典列表”
输出:
var_1 ={'Nikhil':{'roll':24 ,'marks':17 },
'Akshat':{'roll':54 ,'marks':12 },
'Akash':{'roll':15 },'marks':15 }}
sort_key ='marks'
res ='marks'
res =var_2 (test_dict .items (),key =lambda x :x [1 ][sort_key ])
print ("The sorted dictionary by marks is : "+str (res ))
输入:“列表奇数元素求和函数”
输出:
def sum_odd_elements (l :list ):
return sum ([i for i in l if i %2 ==1 ])
**输入:程序反转一串 输出:
var_1 ='Today is bad day'
var_1 [::-1 ]
更多样本请看我的项目回购。
我们已经成功训练了一个模型,它能够将简单的问题陈述(英语)转换成相应的 python 代码。看起来我们离人工智能代替人类编写软件的时代不远了。软件开发人员当心!
参考知识库
**https://github.com/divyam96/English-to-Python-Converter https://github.com/bentrevett/pytorch-seq2seq
参考
[1]阿斯顿·张(Aston Zhang)和扎卡里·c·利普顿(Zachary C. Lipton)以及李牧和亚历山大·j·斯莫拉(Alexander J. Smola),潜入深度学习 (2020)。
[2] Ashish Vaswani,Noam Shazeer,Niki Parmar,Jakob Uszkoreit,Llion Jones,Aidan N. Gomez,Lukasz Kaiser,Illia Polosukhin,(2017),第 31 届神经信息处理系统会议(NIPS 2017),美国加利福尼亚州长滩
[3] Rafael Müller,Simon Kornblith,Geoffrey Hinton,标签平滑在什么情况下有帮助? (2019),第 33 届神经信息处理系统会议(NeurIPS 2019),加拿大温哥华
[4]伊恩·古德费勒(Ian Goodfellow)与约舒阿·本吉奥(Yoshua Bengio)和亚伦·库维尔(Aaron Smith),深度学习书籍 (2016),麻省理工学院出版社。**