Python 中的决策树
在我看来,决策树模型有助于突出我们如何使用机器学习来增强我们的决策能力。我们都曾在某个时候遇到过决策树。然而,决策树机器学习模型的不同之处在于,它们使用逻辑和数学来生成规则,而不是根据直觉和主观性来选择规则。
算法
在尝试构建决策树时,应该立即想到的问题是:
我们应该在什么基础上做决定?
换句话说,我们应该选择什么作为是或否问题来对我们的数据进行分类。我们可以进行有根据的猜测(即所有体重超过 5 磅的小鼠都是肥胖的)。然而,这不一定是对我们的样本进行分类的最佳方式。如果我们可以使用某种机器学习算法来学习问什么问题,以便在分类数据方面做得最好,会怎么样?这就是决策树模型背后的目的。
假设我们试图建立一个决策树来预测一个人是否结婚。因此,我们在附近挨家挨户地敲门,礼貌地请他们为我们的小研究项目提供他们的年龄、性别和收入。在我们询问的几千人中,有 240 人没有把我们拒之门外。
现在,在我们继续之前,掌握以下术语很重要。树的顶部(或者底部,取决于你如何看待它)被称为根节点。中间节点有指向和远离它们的箭头。最后,树底部没有任何边缘指向远离它们的节点被称为叶。叶子告诉你每个样本属于哪一类。
回到我们的例子,我们需要弄清楚如何从数据表到决策树。我们决定使用机器学习算法来为我们构建决策树,而不是自己选择分支。该模型着眼于每个特征如何区分已婚和未婚人群。由于收入是一个连续变量,我们设置一个任意值。
为了确定三个分裂中哪一个更好,我们引入一个叫做 杂质的概念。 杂质是指没有一片叶子有 100%的“是嫁”。有几种方法可以测量杂质(分割的质量),然而,默认情况下,DecisionTreeClassifer
的scikit-learn
实现使用 gini ,因此,这就是我们在本文中要讨论的。
https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
为了计算左叶的基尼系数,我们用已婚人口比例的平方和未婚人口比例的平方减去 1。
等式对于右叶的杂质是完全相同的。
节点本身的基尼系数等于 1 减去左子节点的样本分数,再减去右子节点的样本分数。
信息增益(带基尼指数)写如下。
这个过程在收入和性别上重复进行。我们最终决定具有最大信息增益的分割。在这种情况下,这是收入,这是有道理的,因为收入超过 5 万英镑和已婚之间有很强的相关性。如果我们马上问这个问题,我们就向正确分类数据迈出了一大步。
一旦我们决定了根,我们对树中的其他节点重复这个过程。值得注意的是:
a)我们可以在收入上再次平分
b)每个分支中的样本数量可以不同
我们不能无限期地分开。因此,我们需要一种方法来告诉树何时停止。DecisionTreeClassifer
的scikit-learn
实现使用最小杂质减少量来确定是否应该分割节点。
https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
假设我们在更多的迭代之后,我们在树的左侧得到了下面的节点。
结果大于默认阈值 0。因此,节点将被拆分。如果它低于 0,节点的子节点将被视为树叶。
Python 代码
让我们看看如何用 Python 实现决策树分类器。首先,我们导入以下库。
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.tree import export_graphviz
from sklearn.externals.six import StringIO
from IPython.display import Image
from pydot import graph_from_dot_data
import pandas as pd
import numpy as np
在本教程中,我们将使用机器学习领域最流行的数据集,来自加州大学欧文分校机器学习知识库的虹膜数据集。
iris = load_iris()
X = pd.DataFrame(iris.data, columns=iris.feature_names)
y = pd.Categorical.from_codes(iris.target, iris.target_names)
在接下来的部分中,我们将尝试构建一个决策树分类器,根据花的尺寸来确定花的种类。
X.head()
尽管决策树可以处理分类数据,但我们仍然根据数字对目标进行编码(即 setosa=0,versicolor=1,virginica=2 ),以便在稍后创建混淆矩阵。幸运的是,pandas
图书馆为此提供了一种方法。
y = pd.get_dummies(y)
我们需要评估模型的性能。因此,我们留出四分之一的数据进行测试。
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
接下来,我们创建并训练一个DecisionTreeClassifer
类的实例。我们提供 y 值是因为我们的模型使用了监督机器学习算法。
dt = DecisionTreeClassifier()dt.fit(X_train, y_train)
我们可以通过运行下面的代码块来查看模型生成的实际决策树。
dot_data = StringIO()export_graphviz(dt, out_file=dot_data, feature_names=iris.feature_names)(graph, ) = graph_from_dot_data(dot_data.getvalue())Image(graph.create_png())
请注意它是如何提供基尼系数杂质、样本总数、分类标准以及左侧/右侧的样本数的。
让我们看看我们的决策树在测试数据面前表现如何。
y_pred = dt.predict(X_test)
如果这是一个回归问题,我们将使用某种损失函数,如均方差(MSE)。然而,由于这是一个分类问题,我们利用混淆矩阵来衡量我们的模型的准确性。混淆矩阵最好用一个例子来解释。
假设你的朋友刚刚做了怀孕测试。结果可能属于以下 4 个类别之一。
真阳性:
解读:你预测的是正的,这是真的。
你预言一个女人怀孕了,她真的怀孕了。
真阴性:
解读:你预测的是负数,这是真的。
你预言一个男人不会怀孕,他实际上也没有。
假阳性:(1 型错误)
解读:你预测的是正的,是假的。
你预言一个男人怀孕了,但他实际上没有。
假阴性:(2 型错误)
解读:你预测的是负数,这是假的。
你预测一个女人不会怀孕,但她确实怀孕了。
也就是说,混淆矩阵对角线上的数字对应着正确的预测。当有两个以上的潜在结果时,我们简单地扩展混淆矩阵中的列和行的数量。
species = np.array(y_test).argmax(axis=1)
predictions = np.array(y_pred).argmax(axis=1)
confusion_matrix(species, predictions)
正如我们所看到的,我们的决策树分类器正确地分类了 37/38 株植物。
结论
决策树很容易解释,不需要任何规范化,并且可以应用于回归和分类问题。不幸的是,决策树在实践中很少使用,因为它们不能很好地概括。请继续关注下一篇文章,我们将讨论随机森林,这是一种组合多个决策树以实现更高准确性的方法。
决策树:第 1/2 部分
培养对决策树的直觉
Photo by Subtle Cinematics on Unsplash
大约 70 年前,我发明了决策树,它是最古老的机器学习算法之一,现在用于预测建模。它们可能是最容易理解的 ML 算法之一,但是不要让它的简单性欺骗了你,让你低估了它的能力。
🌰简单地
这篇文章旨在建立一个关于决策树的直觉。我们将讨论线性可分和不可分数据集、决策边界和区域,解释为什么决策边界平行于轴,并指出使用决策树的优点和问题(以及补救措施)。
所以让我们开始吧!
Photo by Victor Rodriguez on Unsplash
优点:
决策树是最容易理解的算法之一,你可以很容易地解释它们的推理,因为它们属于**“白盒”方法。它们足够强大以适应复杂数据集**,并且足够通用以至于它们可以用于分类以及回归任务而不需要太多的数据预处理。
此外,决策树是广泛使用的**“随机森林”**方法的构建模块,这是当今最强大的机器学习算法之一。
与线性模型不同,决策树可以线性拟合不可分的数据集。不可分数据集是指不同类的数据点不能用一条线分开的数据集,而线性可分数据集则用一条线就足够了。下图描述了这些情况:
Figure 1
在图 1 中,左边的图表显示了线性分类器如何确定其决策边界——虚线。右边的一个表示决策树如何构造它的决策边界来适应线性不可分的数据集。
轴平行决策边界
您可能会注意到,决策树做出的决策边界与轴平行,并且它们总是这样:与轴平行。其原因是决策树基于特征值分割数据,并且该值在一个决策边界内始终保持不变,例如 x=2 或 y=3 ,其中 x 和 y 是两个不同的特征。而在线性分类器中,判定边界可以是例如:y=mx+c
在决策树中,为每个决策区域迭代地绘制这些决策边界,并构建一棵树。要获得直观的解释,请按照下面的一系列图表进行操作!👇
划清界限!
让我们看看下面的例子,看看这是如何发生的,只用我们人类的本能,而不是数学!
Dataset to fit the decision tree on along with its corresponding tree structure
称为“根节点”的树的第一个节点分别包含所有类的实例数。
基本上,我们必须画一条称为“决策边界”的线,将不同类的实例分成称为“决策区域”的不同区域。请记住,这条线必须与轴线平行。
开始分吧!
第一个决策边界应该在上图的 X=3 处做出。
Photo by Abby Savage on Unsplash
以 X=3 为分界点,产生如下图。既然现在我们有了两个决策区域,我们将把这两个区域作为树的两个不同节点添加,其中每个节点包含相应实例的数量。
Split point is X=3
因为一个决策区域应该包含一个类的绝大多数,所以我们需要进一步划分。我们将在 **Y=2 处分割结果图的左侧区域。**右区跟着 Y=2.5 。
Split point is Y=2
The split point is Y=2.5
现在,每个决策区域只包含一个类的实例,这是我们停止分裂的提示(因为我们没有定义任何其他停止标准)。
⚠️请注意,不设置其他停止标准可能对你的模型有害。(下文详述)
缺点:
Photo by Tim Collins on Unsplash
👎过度拟合
这里需要注意的是,正如我们上面所做的,分裂到最后一个实例并不是停止分裂的唯一标准。事实上,这可能会导致过度拟合的模型。
过拟合模型:模型对数据的学习非常好,以至于它不能很好地对看不见的数据进行归纳。
💡**修复:**停止的一些其他条件可以是树的深度、节点在进一步分裂之前必须具有的最小实例数、或者多数类或少数类之间的比率,例如,如果 80%的数据点属于一个类,则停止分裂以避免过度拟合。
Image source: Hands-On Machine Learning with Scikit-Learn & TensorFlow
👎不稳定
由于决策树使轴平行于边界,所以它们对数据旋转很敏感。看看下面的图表。可以很容易地被一条对角线分割的数据被多个决策边界分割,我们几乎可以通过观察就可以看出,对于这个特定的问题,更简单的模型会概括得更好。
Image source: Hands-On Machine Learning with Scikit-Learn & TensorFlow
💡**修复:**这个问题可以通过使用像 PCA 这样的降维技术来限制,它可以更好地确定数据的方向。
💡**修复:**一般来说,决策树对微小的数据变化很敏感,会导致不同的树结构。通过一起使用大量决策树并对它们的预测值进行平均并将其用作最终预测,可以增强决策树的健壮性。这种分类器被称为随机森林。
优点仍然大于缺点,通过一些超参数调整,决策树可以表现得非常好。
Photo by Raul Varzar on Unsplash
在我接受的所有与数据科学相关的采访中,几乎每次都有人要求我解释决策树算法。所以,我决定写一篇文章,集中在树的方面,通常没有给予太多的关注。
如果你想了解更多关于决策树及其背后的数学知识,你可以查看本系列的 第二部分 。在那里,我们将讨论寻找最佳分割的熵和信息增益及其背后的数学原理。至于这个帖子,那都是乡亲们!
如果你觉得这篇文章有帮助,请鼓掌👏拍手可以让更多的人看到一个帖子。🐦
如果您有任何问题或建议,请随时在下面发表。你也可以在 Linkedin 上和我联系。💼
直到那时和平结束。 ✌
决策树:第二部分
手动计算熵和信息增益
Photo by Subtle Cinematics on Unsplash
T 他的文章是“决策树”系列的第二篇,本系列的 第一篇 发展了关于决策树的直觉,并给你一个在哪里画决策边界的想法。在这篇文章中,我们将看到决策树是如何做到这一点的。
🙊 剧透: 这涉及到一些数学。
我们将使用一个非常小的数据集,以便于可视化和跟踪。然而,在实践中,这样的数据集肯定会过度拟合。这个数据集决定你是否应该买一辆有 3 个特征的车:年龄,里程,以及这辆车是否是路试。
在上一篇文章中,我们仅通过查看图表来绘制决策边界。但是树做不到这一点。作为人类的好处,对吧?决策树使用熵来寻找分割点和要分割的特征。
熵
熵的定义是缺乏秩序或可预测性。在一堆例子中,它是杂质的量度。如果节点只有一个类的实例,那么它就是最纯的。
其中 n =特征数量
i =特征
P =概率 i
为每个特征计算熵,并且选择产生最小值的一个用于分割。熵的数学范围是从 0 到 1。
我们开始吧!
现在让我们把它付诸实践。为每个节点计算熵。第一个节点,即根节点,总是具有数据集中的所有示例。
正如你所看到的,父节点的熵是 1 。请记住这个值,我们将在接下来的步骤中计算信息增益时使用它。
信息增益
下一步是找到信息增益(IG),它的值也在 0-1 的范围内。信息增益帮助树决定分割哪个特征:给出最大信息增益的特征。我们现在将逐个计算每个特征的信息增益。对于这个迭代,父节点的熵是我们上面计算的 1。
在上图中,我们可以看到左边子节点的熵是 1,因为类实例的比率是 1:1。这是最不纯的一个节点。右边的子节点也是如此。
这里,子节点的熵值为 0,因为每个子节点只有一个类的实例:最纯粹的节点。
总而言之,下表显示了每个特征的信息增益:
Information gain for every feature
最大信息增益是针对特征**“路试”**的,因此我们将选择它作为我们的第一个分割特征。这样做将生成下面给出的树结构:
由于叶节点的熵为零,我们将停止切割。如果不是这种情况,那么我们将继续寻找前面的父节点和子节点的信息增益,直到满足任何一个停止标准。
基尼杂质
和熵一样,基尼杂质也是计算节点杂质的一种度量,具有相同的数学范围[0–1]。其中 1 表示最大杂质,0 表示最小杂质。
Image source: Hands-On Machine Learning with Scikit-Learn & TensorFlow
基尼还是熵?
Photo by Joshua J. Cotten on Unsplash
也可以用基尼杂质代替熵。尽管如此,无论您使用哪一种,结果都不会有太大的不同。但是计算 Gini 杂质比熵稍微快一点。熵产生更平衡的树,而基尼不纯倾向于将多数阶级分成自己的分支。
Photo by Hanny Naibaho on Unsplash
如果您有任何问题或建议,请随时在下面发表。你也可以在 Linkedin 上和我联系。💼
直到那时和平结束。 ✌
决策树和恐龙
计算机如何思考:第一部分
想象你和我一起计划一次旅行。这次旅行需要很多准备,因为这是一次穿越时间的旅行,到地球遥远的史前时代。我们的旅行是一次观光探险。我们计划去看各种奇妙的生物,尤其是原始动物展览中的明星,恐龙。但是我们必须小心!这不是去动物园!恐龙看到我们的次数和我们看到它们的次数一样多,而且并不是所有的恐龙都有善良的意图。如果我们不想被这个古老世界的居民打扰,我们就必须准确地区分恐龙的两个主要分支:无害的食草动物,当我们看着它们时,它们可能会简单地盯着我们;以及致命的食肉动物,它们更喜欢吃我们。
This could be us
如何最好地实现这种朋友和敌人的确定?恐龙有很多种,其中一些鲜为人知,对它们进行详尽的研究是不切实际的。在侏罗纪时代,我们将无法获得电力或互联网,即使我们能够记住目前科学已知的每个物种的每个细节,任何未知物种对我们来说都将是一个完全的谜。我们需要能从我们现在所知道的东西中归纳出一些东西来处理新的情况。我们需要的是一些能适用于这个问题的简单规则。我们将创建一个“模型”——一套规则——来帮助我们更容易地做出决定,而不是学习恐龙生物学的每个细节。在计算机处理数据的帮助下,我们可以提出一套识别恐龙饮食的最佳规则,让我们能够安全地穿越时间,而不必在我们的时间机器中打包一堆百科全书。
这类问题的名称是“分类”,它是广泛采用的计算机学习的最早例子之一。它的应用包括识别收件箱中的垃圾邮件,为电话销售人员标记可能的线索,最复杂的是,从照片中识别人脸。
为了防止我们的史前冒险以死于食肉爬行动物的口中而告终,我们将构建一个“两类决策树分类器”,这是一个极其简单的模型,通过几个数字输入,它将告诉我们任何给定的恐龙物种是无害的好奇心,还是致命的威胁。它是“两个纲”,因为它只确定了两个不同的恐龙纲:食肉恐龙或非食肉恐龙。它是一个“决策树”,因为它用来区分这两个类别的方法采取了一系列分支决策的形式,就像一个流程图(或一棵树),引导我们做出关于最可能的类别的决策。
这种计算机辅助分类的核心是一种洞察力,即在一些聪明的数学的帮助下,计算机可以比人更准确地找到一组数据中的模式。我们可以让专家检查每个恐龙物种,记录它们的饮食偏好,然后每当我们遇到新的恐龙,翻阅我们的年鉴,直到我们找到这个物种的条目。但是对于书中没有的物种,我们就没那么幸运了。相反,我们可以让我们的人类专家教我们一套规则,通过这些规则我们可以做出决定。但是分析如此大量的数据,权衡每一个异常和排列,是一项巨大的任务,而人类往往做得很差。计算机可以更快、更准确地完成同样的工作,并处理大量数据,其规模甚至是人类无法尝试的。
为了开始构建一个分类器,我们必须收集一些关于一组恐龙物种的事实,并以这样一种方式对其进行编码,以使其适合我们的算法。我们将制作一个表,其中每一行代表一只恐龙,每一列是一个数值,代表关于那只恐龙的一些信息。因此,举例来说,侏罗纪时期温和的巨人剑龙和白垩纪晚期凶残的暴君霸王龙可以用下面两行来表示:
Table One: Data for two dinosaur species
您会注意到,这些数据中有一些是以稍微不同寻常的方式表示的。我们没有一个名为“步态”或类似的包含“两足动物”或“四足动物”的列,而是有一个名为“两足动物”的列,包含 1(这种恐龙是两足动物)或 0(它不是两足动物)。这将类别编码为算法能够解释的数字格式。
我收集了 20 种最著名的恐龙物种的信息来训练我们的分类器。这些恐龙包括食草恐龙和食肉恐龙、四足恐龙和两足恐龙、小型恐龙和大型恐龙,以及来自原始侏罗纪茂盛丛林和白垩纪晚期茂密森林的恐龙。
在这些方面,我让决策树算法——一系列重复的简单步骤——来完成它的工作。这个算法非常简单,我们自己也可以遵循:
我们检查了数据表中的每一列,找到了单个列,以及该列的单个值,这最能区分食肉动物和它们的食叶兄弟。在本例中,它是“两足动物”列。四足恐龙是严格的素食者,在我们目前的数据中没有例外。这个决策成为我们决策树的“主干”——第一个决策节点,其他决策从这个节点分支。对于我们的四足动物,算法是完整的,不需要进一步的决定。但是对于两足动物,我们剩下的是食肉动物和食草动物的混合体,我们必须构建额外的节点。在这种情况下,其余示例的最佳分割是测量主体的长度。如果你的恐龙从鼻子到尾巴超过 12 米,那么你就有麻烦了——它是食肉动物,你拿着梯子和卷尺站在它旁边。然而,较小的两足动物仍然是食肉动物和食草动物的混合体,我们可以继续构建节点。
最终的决策树有点像一本“选择你自己的冒险”的书。为了决定一只给定的恐龙是否安全,我们浏览节点,在每个节点上做一个选择,直到我们到达一个“叶子”节点,它告诉我们最可能的类。这是树:
Figure One: Decision tree diagram
算法已经学习了一些关于恐龙的规则:所有的四足动物都是食草动物,超过 12 米长的两足动物是食肉动物。对于 12 米以下的两足动物,最轻的(800 公斤以下)更可能是食肉动物,较重的是食草动物。
这对我们 20 只恐龙来说很好,但是这些规则在野外会有多好呢?我们会度过一次平静而愉快的时光之旅吗?还是我们的假期会被一只巨大爬行动物意想不到的胃口所破坏?我们可以通过找到一组新的恐龙来测试这一点,用我们学到的这些规则进行分类,并检查我们正确预测了多少。请记住,我们在模型中寻找的关键品质之一是通用性。即使我们找到了所有已知恐龙物种的数据,在遥远的过去,我们肯定会遇到各种迄今未发现的物种。我们希望尽最大努力确保我们的模式也适用于他们。
为了测试这一点,我列出了另一个稍微不太常见的恐龙列表,并通过决策树模型运行它们,根据它们的步态(两足与四足)、长度和重量对它们进行预测。结果是……不好。
恐爪龙和阿尔伯特龙被正确地归类为食肉动物(虽然,后者的大小和火鸡差不多,不太可能构成太大的威胁)。同样,根据龙的四足步态,甲龙被正确地归类为食草动物。但是无害的厚头龙,其加厚的头骨被认为是为了用头撞击竞争对手,被归类为食肉动物——它不到 12 米,体重超过 800 公斤。更麻烦的是,三种危险的食肉动物,阿尔伯特龙、巨龙和阳川龙都被归类为食草动物,这可能会给我们带来一个不受欢迎的惊喜。
Yangchuanosaurus. I hadn’t heard of it either.
我们的模型出了问题!实际情况是,该算法学习了一种偶然出现在我们数据中的模式,但并没有推广到更广泛的人群。虽然我们的训练数据中很少有小而重的食肉动物,但事实上它们很常见。这是许多算法的弱点,尤其是决策树,尤其是对于这样一个小数据集。当你有少量的例子可以学习,并且有大量不同的方法可以将这些例子分开——按重量,按长度,等等,那么就很容易找到虚假的规则。
该算法发现四足动物普遍是素食者,这一规则似乎也适用于我们数据集之外的其他物种。但是关于重量和长度的规则似乎很可疑。算法发现的分界线——12 米的长度和 800 公斤的重量——似乎不太可能是恐龙进化的一般规则,更有可能是哪个物种碰巧被纳入我们的数据的一个意外。
我们有几个选项来尝试解决这个问题:
我们可以添加更多的数据。有了更多的数据,找到偶然模式的机会就少了,我们更有可能发现恐龙的真正规律。但是获取更多的数据可能会很困难,而且也不能保证我们会找到我们想要的规则——我们正在查看的特征(重量、长度等)中可能不存在真正的模式。
我们可以尝试不同的算法。我们可以用很多其他的方法来建立分类模型,其中很多不像我们的决策树那样容易发现任意的规则。但是这些算法要复杂得多,为了本章的目的,我想把重点放在这个非常简单的方法上。
第三个选项,也是我们将选择的选项,是寻找新的特性添加到我们的数据中。这意味着在我们的化石中找到更多关于恐龙的信息,并将其添加到我们已经知道的信息中。有希望的是,这些新信息将更有助于建立关于食肉恐龙和食草恐龙的通用规则。
这让我进入了令人困惑和有争议的恐龙进化世界。古生物学中几乎没有无懈可击的正统学说,甚至连恐龙的基本家谱也不断地被连根拔起、重新种植、嫁接和修剪。
然而有几个主题保持不变。恐龙谱系的主要分界线在蜥龙类和鸟龙类之间。这些贵族住宅主要根据臀部的方向来划分——“蜥蜴臀”的蜥脚类恐龙保持臀部向下并远离身体,而“鸟类臀”的鸟臀目恐龙更喜欢臀部朝后,与现代鸟类的方向相似。然而,令人困惑的是,是蜥脚类动物成为了今天鸟类的祖先,而不是表面上更相似的鸟臀目动物。
对我们的分析有用的是,它是蜥蜴类的一个分支,代表了大量的食肉恐龙。蜥蜴类的这个分支,兽脚亚目恐龙,在它们的数量中既有纤细小巧的恐爪龙,也有体型巨大健壮的霸王龙。兽脚亚目恐龙几乎完全是肉食动物。如果我们能确定兽脚亚目恐龙的共同特征,我们就能极大地改善我们模型的性能。
我添加的第一个额外功能是一个简单的“每米吨数”计算,我推断,虽然之前的模型发现的关于重量和长度的规则可能不成立,但食肉恐龙的体型可能存在差异,一般来说,它们的体型可能比食草恐龙更重或更轻。
我还观察了一些恐龙更奇特的特征。剑龙有板状的刺,这被认为是为了展示或防御,或者可能是调节热量。副栉龙,我最喜欢的恐龙,有一个鼻冠,这被认为是允许它发出响亮的交配叫声,或者它可能有一个装饰性的褶边。我希望,食草动物可能更有可能具有这些防御或展示特征,因为它们更多地生活在群体中,不得不保护自己免受捕食者的伤害。
Parasaurolophus. The best dinosaur.
最后,也许是有争议的,根据目前的研究,我研究了哪些物种被认为有大量的羽毛。这份名单包括了数量惊人的众所周知的恐龙。事实证明,这也非常复杂,仍有几个问题存在争议。
但这是一条充满希望的道路!我们食草的鸟臀目动物都有鳞片或覆盖着丝状毛发。笨重的蜥脚类动物普遍有鳞。只有在食肉兽脚亚目恐龙中,我们才发现像现代鸟类一样的有翼羽毛,现在人们认为这种“羽状体被”(或“绒毛外套”)可能使可怕的霸王龙及其亲属更像一只巨大的毛茸茸的火鸡。
将这些添加的数据编码到我的数据中,我重新运行决策树算法,让它重新计算拆分数据行的最佳方式,以区分食草动物和食肉动物。
这是它生成的决策树:
Figure Two: A more effective tree
它发现的第一条规则和以前一样——四足恐龙从不食肉。但从那里开始,情况就大不一样了。所有长有羽毛的恐龙都是食肉动物,在那些幸存的无羽毛物种中,我们可以通过观察它们的体重与长度的比例来巧妙地将食草动物与食肉动物区分开来。
对照我们的测试集检查这些新规则,我们现在达到了完美的准确性,将无害的龙和厚头龙归类为食草动物,而危险的阿尔伯特龙、巨龙和阳川龙都被标记为食肉动物。有了这个新的分类系统,我们可以满怀信心地穿越史前史。我们可以在一张纸上画出这个流程图,带上卷尺和一套结实的天平,启动时间机器,然后出发。
但是真的这么简单吗?在测试了我们的模型并获得了完美的准确性之后,我们可能会假设我们将在实践中继续获得类似的结果。这是一个危险的假设。
任何分类模型的好坏取决于对其进行训练的数据以及对该数据所做的假设。任何模型中都隐含着无数的偏见、盲点和疏忽,这个模型也不例外。
例如,如果在一次即兴的史前游泳探险中,我们遇到了蛇颈龙,我们将很难用我们的模型将其分类。到底是不是两足动物?它很可能是由前侏罗纪二叠纪或三叠纪时期的四足鳄鱼祖先进化而来,但在侏罗纪,它用四只巨大的鳍状肢游泳。我们的模型是在陆地物种上训练的,对于如何对水生恐龙进行分类却保持沉默。
同样,我们的模型假设恐龙来自白垩纪或侏罗纪。更早的二叠纪是类似恐龙的突触体(事实上更接近哺乳动物)的家园,如帆背和食肉的双足类恐龙。Dimetrodon 是食肉动物,像二叠纪的大多数顶级食肉动物一样,是四足动物。去二叠纪的旅行者会被我们的模型严重误导。
更阴险的是我们的模型中的偏见,这些偏见是我们看不见的,因为模型是在文化或历史背景下创建的。我们的模型是在一些最知名的恐龙物种上训练的,等等知名的物种上,它表现的很好。但是,哪些物种广为人知,哪些不为人知,这是历史偶然事件的产物。古生物学主流发展的国家的本土恐龙几乎肯定会更出名。那些最先被发掘、鉴定和公布的少数物种不可避免地引起了公众的注意,这是最近的发现所没有的。
我们的模型告诉我们,有羽毛的两足动物总是食肉动物,这在美国和西欧发现的物种中很大程度上是正确的。但是最近的研究打乱了这个简洁的启发。这些发现包括西伯利亚恐龙,如长有羽毛的食草恐龙*jianianhualongi,*或 *Kulindadromeus,*一种长有羽毛状结构涂层的鸟臀目恐龙,以前被认为是兽脚亚目恐龙的专属物种。中国物种,如长爪、有绒毛的兽脚亚目食草恐龙兽暴龙,进一步混淆了画面。如果我们在中国和西伯利亚常见的恐龙物种上训练我们的模型,我们可能会创造出一个完全不同的模型,而希望参观他们祖国史前史的中国时间旅行者将不会被我们当前的算法所服务。
A friendly Therizinosaurus, a feathered herbivore
大多数分类算法的现代实现比我们在这里创建的简单模型要复杂得多。它们涉及更多的要素,对数据中的模式进行更复杂的解析,以及要学习的更大的数据集。这些模型中的许多都非常精确,它们的分类基于从数据中通过算法得出的规则,与人类驱动的决策相比具有无数优势。它们更快、更可靠、更一致,并且经常能够察觉到即使是观察力最敏锐的人也无法察觉的模式。
但是支撑我们简单恐龙模型的基本概念也适用于最复杂的分类器。该算法在给定的数据中发现模式,并使用这些模式来建立关于如何对新示例进行分类的规则。根据初始数据,该模型对更广泛的人群进行概括,这种概括就是它进行预测的方式。这些规则和归纳可能非常复杂,也非常准确,但它们只能和最初创建它们的数据以及对这些数据做出的假设一样好。这些复杂的模型和我们非常简单的模型一样容易受到偏见和限制。作为人类思维的产物,经过人类数据的训练,它们会受到人类易犯错误的影响。在我们穿越时空的旅行中,我们将把现代世界和它的失败抛在身后。但从某种意义上说,我们也会把它们带在身边,嵌入我们做出的假设中。
第二部分,“线性回归与线的继承”是 此处可用 。
决策树和随机森林:
min _ 杂质 _ 减少是做什么的,应该怎么用?
Photo by Filip Zrnzević on Unsplash
在我学习决策树和随机森林的过程中,我注意到许多超参数被广泛讨论和使用。最大深度、最小样本叶等。,包括仅适用于随机森林的超级参数。一个似乎很少被关注的超参数是最小杂质减少。
最小杂质减少是什么意思,有什么作用?
要理解这一点,你首先要理解超参数的基本标准是什么。所用的标准是测量每次分裂的杂质,从而计算出通过分裂获得的信息。然后,它可以决定如何进行最佳分割。当杂质为 0 时,则该叶子中的所有项目都被正确分类。
关于基尼指数和熵的更长的解释可以在这篇文章中看到:
关于杂质测量和信息增益,您需要了解的一切
towardsdatascience.com](/gini-index-vs-information-entropy-7a7e4fed3fcb)
min _ infinity _ decrease 的作用是在分解的减少额小于输入额时停止分解。当我们继续将它形象化时,这将更容易理解。
可视化决策树以查看正在进行哪些拆分
让我们看看我用虹膜数据集和所有默认的超参数做的决策树。请注意,由于这个数据集的情况,从这个树上得到的分数对于训练和测试来说几乎是完美的。因此,我不会在本文中显示每个模型运行的分数,我只是试图展示如何使用 min _ infinity _ decrease 超参数。
这是训练数据的决策树的可视化,每个节点和叶都有基尼指数:
在训练集中有 120 个样本,我们试图对 3 种类型的虹膜进行分类。第一次拆分右侧的值= [0,41,39]意味着第一组中没有任何项目被错误分类,第二组和第三组中的项目数量几乎相等。因此,该节点的杂质被舍入到 0.5,这意味着它们中的大约一半被正确分类,而大约一半被错误分类。
我们在建模中试图最小化的事情之一是过度拟合。其原因是,如果我们过度适应我们的训练数据,那么我们可能会对我们的测试数据或真实数据进行错误分类。因此,我们希望尽量减少分裂成很小数量的叶子。
这也是最小杂质减少可以帮助我们的地方。如果分裂的不纯度上升,那么这将意味着我们正在进行分裂,这对我们没有帮助,而是过度适应训练数据。
让我们看看上面决策树中的一个例子:
这是正在进行的第三级分割。
从右侧可以看出,我们对 5 个分类错误的项目进行了拆分。在这条分界线的左边,有 4 个正确的和 4 个不正确的,基尼系数为 0.5。在右边,有 34 个正确的和 1 个不正确的。
我们似乎在这方面做得太多了,而且这样做并没有获得太多。
在左边,我们有 36 个正确的和一个不正确的,然后我们做一个分割来捕捉最后一个。这也过度拟合了我们的训练数据。
我们如何处理这两种分裂?
最小杂质减少量的计算
这个超参数是怎么计算出来的?如果我们检查它的文档,可以在这里找到,那么我们会看到这个:
min_impurity_decrease : float, optional (default=0.)A node will be split if this split induces a decrease of the impurity greater than or equal to this value.The weighted impurity decrease equation is the following::N_t / N * (impurity — N_t_R / N_t * right_impurity
— N_t_L / N_t * left_impurity)where ``N`` is the total number of samples, ``N_t`` is the number of
samples at the current node, ``N_t_L`` is the number of samples in the left child, and ``N_t_R`` is the number of samples in the right child.``N``, ``N_t``, ``N_t_R`` and ``N_t_L`` all refer to the weighted sum, if ``sample_weight`` is passed.
让我们分解这个计算,以便更好地理解它:
**N _ t _ R/N _ t * right _ infinity:**取分裂右侧的杂质,并根据来自节点的右侧分裂中的样本百分比对其进行加权。
**N _ t _ L/N _ t * left _ infinity:**取左侧分裂的杂质,用左侧分裂中样本占节点的百分比进行加权。
然后我们从节点杂质中减去这两者。
然后,我们根据节点中样本占样本总数的百分比对该数量进行加权。
让我们把它写在分割的右边:
43/120 * (.206 - 35/43 * .056 - 8/43*.5)
我们得到的总数是 0.024149999999999999998,或者四舍五入到 0.024。
43 是正在分裂的节点中的样本总数
120 是样本总数
206 是节点的杂质
35 是分裂右侧的样本总数
056 是分裂右侧的杂质
8 是分裂左侧的样本总数
5 是分裂左侧的杂质
手动计算这一切并不容易,我制作了一个函数,允许您输入上述数字,它将为您计算分裂的杂质:
def get_impurity_score(n=None, n_t=None, n_t_l=None, n_t_r=None, node_impurity=None, left_impurity=None, right_impurity=None):
'''
n = Total number of samples overall
n_t = Samples in the node you are checking out
n_t_l = Samples in the left split from the node
n_t_r = Samples in the right split from the node
node_impurity = Impurity score of the node
left_impurity = Impurity score of the left split from the node
right_impurity = Impurity score of the right split from the node
Returns impurity decrease total of the 2 splits from the node impurity weighted by the total number of samples
'''
if n == None or n_t == None or n_t_l == None or n_t_r == None or node_impurity == None or left_impurity == None or right_impurity == None:
print('-----error------ missing values. Check inputs') return(n_t / n * (node_impurity - (n_t_r / n_t * right_impurity) - (n_t_l / n_t * left_impurity)))
左侧分离的杂质分数为 0.016341666666666666666,或四舍五入至 0.016。
用这个来修复我们的决策树
如果我们现在将最小杂质减少量设置为 0.025,则不会发生分裂,并且我们将减少模型中的过拟合。
我们更新的树:
我们现在确实阻止了这两种分裂的发生,以帮助防止我们的决策树过度拟合。
在随机森林中使用最小杂质减少
要在随机森林中使用它,我建议使用 GridsearchCV 来帮助找到对您试图构建的模型有益的超参数。
一般来说,我会建议使用这个和其他超参数来防止过度拟合。
我希望这有助于你理解最小杂质减少和如何使用它。如果您有任何问题或意见,请在下面的评论区提出。
决策树
映射的概念:
0.引言。
- 什么是决策树?
- 为什么要使用决策树?
1.CART 是如何工作的?
- 购物车中使用的术语。
- 几何分析。
- 直觉发展。
2.什么是熵值法?
- 用图形表示。
- 数学公式&解释。
3.信息增益。
- 数学公式&解释。
4.基尼杂质。
- 为什么基尼不纯比熵好?
5.纯节点的概念。
6.购物车中的过装和欠装。
7.停止标准。
- 克服过拟合&欠拟合的方法。
8.推车的优点。
9.推车的缺点。
10.正在为购物车准备数据。
- 如何进行数值特征的拆分?
- 列标准化的效果。
- 如何处理分类特征?
- 什么是决策树桩?
- 不平衡类的效果。
- 高维度的效果。
- 离群值的影响。
- 如何确定特征重要性?
0.简介:
在深入决策树的理论概念之前,让我们先澄清什么是决策树?以及我们为什么要使用它们。
什么是决策树?
决策树是由 Leo brei man提出来的,在现代也被称为 分类和回归树(CART) 。它们是有预定义目标变量的监督学习算法&,主要用于简单线性决策面的非线性决策。换句话说,它们适用于解决手边的任何类型的问题(分类或回归)。
为什么要使用决策树?
最好也是最常用的监督学习方法之一 是基于树的算法。它们 赋予预测建模 以 更高的准确性、更好的稳定性,并提供了易于解释的 。与线性建模技术不同,它们很好地映射了非线性关系。决策树、随机森林、梯度推进等方法在各种数据科学问题中得到了广泛应用。因此,对于每个分析师来说,学习这些算法并在建模时应用它们是很重要的。
1.CART 是如何工作的?
考虑下面给出的一个非常基本的例子,该例子使用 NFL 数据集 来预测球员是否会触地得分。下面的模型使用了 数据集中的 3 个特征/属性/列,即身高、速度和力量。
在这个问题中,我们需要根据三者之间高度重要的输入变量来隔离将在比赛期间得分的球员。这就是决策树帮助的地方,它将基于三个变量的所有值隔离玩家,并识别变量,这创建了玩家的最佳同质集合(彼此异质)。
- 所用术语:
决策树由 根/内部节点 组成,其进一步分裂成 决策节点/分支 ,根据分支的结果形成下一个分支或 终端/叶节点 。
- 直觉发展:
或者,我们可以认为决策树是一组嵌套的 IF-ELSE 条件 的集合,它们可以被建模为一棵树,其中在内部节点做出决策,在叶节点获得输出。
NESTED IF…ELIF…ELSE
- 几何类比:
几何上我们可以认为 决策树是一组轴平行的超平面,在推理过程中将空间划分为多个超立方体。 我们根据点属于哪个超立方体来对点进行分类。
Axis-parallel hyperplanes.
2.什么是熵值法?
创建决策树只是选择在树的每个节点上应该测试哪个属性的问题。然而,信息增益是将用于决定在每个节点应该测试哪个属性/特征的度量。信息增益本身是使用称为熵的度量来计算的,我们首先为二元决策问题的情况定义熵,然后为一般情况定义熵。我们首先为二元决策问题定义熵的原因是因为它更容易理解它试图计算什么。汤姆·米切尔说得很好:
“为了精确定义信息增益,我们首先定义信息论中常用的一种度量,称为熵,它表征任意样本集合的(不)纯度。”
- 图示:
数学上,熵可以表示为:
- 方程式说明:
这个度量满足我们的标准,因为有了 -plog2§ 结构:当 p 接近于零时(即类别中只有几个例子),那么 log§ 就变成了一个大负数,但是 p 部分在计算中占主导地位,所以熵计算出来接近于零。记住熵是计算数据中的无序度的,这个低分数是好的,因为它反映了我们想要奖励例子很少的类别。类似地,如果 p 接近 1(即,该类别具有中的大部分示例),那么 log§ 部分非常接近 0,并且“p”再次主导计算,因此整体值接近 0。因此,我们看到,当类别几乎或完全为空时,或者当类别几乎包含或完全包含所有示例时,类别的得分接近于零,这是我们想要的模型。注意 0ln(0)按惯例取为零。**
3.信息增益
让我们回到尝试确定为树中的特定节点选择最佳特征的问题。下述方法计算给定特征(A)的数值。关于一组示例。注意,属性 A 的值将在我们称为值(A)的一组可能性的范围内,并且,对于该组中的特定值 v,我们为属性 A 具有值 v 的示例组写 Sv。
属性 A 相对于示例集合 S 的信息增益计算如下:
基本上,信息增益取决于数据集被分割成属性后熵的减少。创建决策树围绕着寻找返回最高信息增益的属性的思想。
一般来说,如果所有的结果都有相同的可能性,如果一些结果比其他结果更有可能比熵减少,则熵最大。
4.基尼杂质:
基尼系数可以作为熵值法的替代方法。Gini 杂质是一种度量,用于衡量从集合中随机选择的元素被错误标记的频率,前提是根据子集中的标签分布对其进行随机标记。
数学上可以表示为:
基尼系数法中熵的计算方式相同,但熵涉及对数计算,基尼系数杂质涉及平方计算。由于计算平方比对数函数更便宜,我们更喜欢基尼系数杂质而不是熵。
5.纯节点的概念:
纯节点是其中所有数据点都属于同一类的节点,因此在这样的节点进行预测是非常容易的。
Here overcast is a pure node.
6.购物车中的超配和欠配:
过拟合和欠拟合的后果及其原因将在后面讨论(停止标准)。
- 树的深度越大,变化的可能性就越大(过度拟合)。
- 而树的深度越小,偏向树的可能性就越大(欠拟合)。
7.停止标准。
如果我们继续完全增长树,直到每个叶节点对应于最低的杂质,那么数据通常是过度拟合的。如果分割过早停止,训练数据的误差不会足够高,并且性能会由于偏差而受到影响。因此,在对决策树建模时,防止过拟合和欠拟合是至关重要的,这可以通过两种方式实现:
- 设置树大小的约束
- 树木修剪
- 设置树大小的约束:
- 为节点分裂提供最小数量的样本。
- 为终端节点(叶子)部署最小数量的样本。
- 允许树的最大深度(垂直深度)。
- 最大终端节点数。
- 分割时要考虑的最大特征。
2。树修剪:**修剪是机器学习中的一种技术通过移除树的部分来减小决策树的大小。它还降低了最终分类器的复杂性,并因此通过减少过拟合来提高预测精度。修剪树木有两种方式:修剪前或修剪后。
——预修剪:
- 如果当前节点没有将熵提高至少某个预设(阈值)值,则停止分裂当前节点。
- 如果数据点的数量小于某个预设(阈值)值,则停止分区。
- 将树的深度限制在某个预设(阈值)值。
-剪后:
- 这可以通过首先允许树增长到其全部潜力,然后在计算每一层的交叉验证准确性之后修剪每一层的树来实现。
8.购物车的优势:
- 决策树可以固有地执行 多类分类 。
- 它们提供了 大多数模型的可解释性 ,因为它们只是一系列 if-else 条件。
- 它们既可以处理 数值 也可以处理 分类数据 。
- 特征间的非线性关系 不影响决策树的性能。
9.购物车的缺点:
- 数据集中的微小变化会使树结构不稳定,从而导致变化。
- 决策树学习者创建欠适应树* 如果某些类不平衡。因此,建议在拟合决策树之前平衡数据集。*
10.为购物车准备数据:
- 数字特征 的 分裂可以通过按升序对特征进行排序并尝试将每个值作为阈值点并计算每个值的信息增益作为阈值来执行。最后,如果获得的值等于给出最大 I.G .值的阈值,则欢呼…!!
- 特征缩放 (列标准化)不需要在决策树中执行。但是,它有助于数据可视化/操作,如果您打算将性能与其他数据或其他方法(如 SVM)进行比较,它可能会很有用。
- 为了让 处理决策树中的分类特征 ,我们绝不能对分类变量执行一次热编码,即使分类变量是名义变量,因为大多数库可以自动处理分类变量。如果需要,我们仍然可以为每个变量分配一个数字。
- 如果树的高度或深度正好是 1,那么这样的树称为 决策树桩。
- 不平衡类 确实对树的结构有不利影响,因此可以根据数据集使用上采样或下采样来避免。
- 除了偏斜的类之外, 高维度 也会对树的结构产生不利影响,如果维数非常高,这意味着我们有很多特征,这意味着在每个节点上找到分裂标准将耗费大量时间。
- 离群点也会影响 树的结构随着深度的增加树中离群点的几率增加。
- 特征重要性 可以通过计算每一层的归一化总和来确定,因为我们必须降低熵,然后我们选择有助于大幅降低熵的特征。因此,对于归一化总和最高的特征,我们可以认为它是最重要的特征。类似地,具有第二高归一化总和的特征可以被认为是第二重要的特征。
参考资料:
导师:
Harshall Lamba,新潘韦尔皮莱工程学院助理教授。
用于网上购物分析的决策树
如今有一种使用在线购物解决方案的趋势,如亚马逊、易贝、全球速卖通。这些网站为卖家提供了一个向大量客户销售产品的平台。由于许多送货服务与这些在线购物平台相关联,因此来自不同国家的客户购买产品。与传统商店不同,每个卖家的评分和美誉度直接显示在购物平台上。因此,如果顾客不喜欢产品或产品有任何缺陷,卖家会让他们退货。如果顾客抱怨商品没有在承诺的期限内送达,一些卖家会全额退款。一些顾客滥用这些设施,欺骗销售者。因此,网络购物平台上的卖家遭受了巨大的利润损失。让我们讨论如何通过开发一个简单的机器学习模型来发现这些类型的客户;决策树。
如果你不熟悉决策树,可以看看这篇中型文章。快速回顾一下,决策树是机器学习中的一个模型,它包括我们对数据进行分类的条件(用于标记问题)。举个例子,想一个简单的情况,一个男人很开心,因为天气晴朗或者他在度假。这个场景的模型如下。注意,在这个模型中,你可以用天气和假期状况来预测这个男人的快乐程度。
A simple Decision Tree model
网购商品退货问题
当我参加 Datathon(数据黑客马拉松)比赛时,我从一家数据分析公司获得了一个包含在线购物平台详细信息的数据集。数据集经过编码,因此不会暴露客户和卖家的详细信息。然而,该数据集包括大量关于卖家、客户和产品的数据(以编码的方式)。上面提到的 datathon 的主要任务之一是发现项目返回模式。这包括经常返回的客户属性、一年中的月份、经常返回的商品详细信息和卖家详细信息。完整的数据集包括一年的完整数据。查看数据集架构以了解数据集。
Dataset schema
数据集加载和预处理
数据集非常庞大。即使它包含一年的数据,大小也大约是 25GB。被写成 4 个.csv
文件(一年每季度一个文件)。即使电脑有 16GB 内存和固态硬盘,文件也很难处理。因此, pandas python 包被用来分块读取数据集。
chunks = pd.read_csv('dataset/DataSet01.csv', chunksize=1000000)for chunk in chunks:
df = chunk
## Perform task on dataframe; df
请注意,chunksize
参数表示仅来自给定的 1000000 条记录。csv 文件被读取。当预处理数据、训练机器学习模型(这里是决策树)和测试模型时,我们可以逐块执行这些任务。
至于预处理,缺少属性的记录被忽略,因为有数百万条记录具有必需的属性。通过观察与退货的相关性,给定属性的子集被选择用于项目退货分析。请看这个 GitHub 库以获得更多关于相关性分析的细节和代码。最后,通过相关性分析和领域知识选择以下属性。
selected_atributes = [‘ONLINE_STORE_CATEGORY’, ‘SIZE_CDE’, ‘CLOR_CDE’, ‘SELLING_PRICE’, ‘PRODUCT_CLASS_02’, ‘FMALE_IND’, ‘MRYD_IND’, ‘BRAND_CODE’, ‘EDUC_LVL_NBR’, ‘MRYD’, ‘AGE’, ‘2017_M7_PURCHASE_AMT’, ‘2017_M7_RETURNED_AMT’,’PRODUCT_CLASS_01', ‘PRODUCT_CLASS_02’]
注意:这些属性包括商品的类别、尺寸、颜色、性别、年龄和顾客的婚姻状况、过去几个月的购买和退货金额、教育水平等。
构建决策树模型
让我们使用 sklearn 的决策树分类器来构建我们的决策树模型。
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn import metrics# load selected attributes and return indication as X and y
X = df[selected_atributes]
y = df.RETURN_INDICATION## Split dataset into training set and test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) # 70% training and 30% testmodel = DecisionTreeClassifier()# train the model
model= model.fit(X_train,y_train)# testing the model
y_pred = model.predict(X_test)# Accuracy calculation
print("Accuracy:", metrics.accuracy_score(y_test, y_pred))
保留所有的超参数默认值,我获得了 89%的准确率。您还可以通过更改官方文档中提到的参数来更改决策树的超参数。
可视化模型
现在,我们已经构建了决策树,我们希望看到客户记录被归类为退货或不退货的条件(决策)。决策树可视化是理解这些条件的好方法。让我们使用sklern.tree
中的plot_tree
选项来生成树。
tree.plot_tree(model, max_depth=5, filled=True)
注意max_depth=5
表示可视化树的前 5 个深度级别。我们的树非常复杂。因此,绘制完整的树需要大量的时间和内存。
您可以使用选项sklearn.tree.export.export_text
以文本形式导出树。这样,可以很容易地生成完整的树。
from sklearn.tree.export import export_text
r = export_text(model)
print(r)
进入 GitHub 库查看生成的情节和决策树的文本结构。
存储和重用模型
你可以使用pickle
来保存模型。
pickle.dump(clf, open('finalized_model.sav', 'wb'))
以及从转储文件中加载模型。
loaded_model = pickle.load(open('finalized_model.sav', 'rb'))
使用模型进行预测(使用模型)
要将给定的客户记录分类为退货或不退货,我们可以使用 sklearn 树模型中的predict
方法。请注意,您首先必须按照与您在模型构建步骤中相同的顺序加载相同的属性。让我们预测测试数据,因为我们将数据集分为训练集和测试集。
y_pred_loaded = loaded_model.predict(X_test)
这将返回一个预测列表(商品退货指示),可以将该列表与实际退货指示进行比较,以评估我们的模型。
print(“Accuracy:”, metrics.accuracy_score(y_test, y_pred_loaded))
>>> 0.96
更重要的是,我们可以用这个模型来预测一些看不见的数据。如网购商品退货问题小节所述,数据集有 4 个。csv 文件。我们已经使用第一个文件来训练我们的模型。让我们使用第四个文件来预测返回指示。请注意,我们使用 pandas 来分块加载数据。
selected_atributes= ['ONLINE_STORE_CATEGORY', 'SIZE_CDE', 'CLOR_CDE', 'SELLING_PRICE', 'PRODUCT_CLASS_02', 'FMALE_IND', 'MRYD_IND', 'BRAND_CODE', 'EDUC_LVL_NBR', 'MRYD', 'AGE', '2017_M7_PURCHASE_AMT', '2017_M7_RETURNED_AMT','PRODUCT_CLASS_01', 'PRODUCT_CLASS_02']
chunks = pd.read_csv('dataset/DataSet04.csv',chunksize=1000000)i = 0
for chunk in chunks:
i = i +1
if(i>10):
break
df = chunk# load features and target seperately
X_test = df[selected_atributes]
y_test = df.RETURN_INDICATION
y_pred = loaded_model.predict(X_test)
print("Accuracy for chunk ", i, metrics.accuracy_score(y_test, y_pred))>>> Accuracy for chunk 1 0.865241
>>> Accuracy for chunk 2 0.860326
>>> Accuracy for chunk 3 0.859471
>>> Accuracy for chunk 4 0.853036
>>> Accuracy for chunk 5 0.852454
>>> Accuracy for chunk 6 0.859550
>>> Accuracy for chunk 7 0.869302
>>> Accuracy for chunk 8 0.866371
>>> Accuracy for chunk 9 0.867436
>>> Accuracy for chunk 10 0.89067
在测试步骤中,我们获得了 96%的准确率。然而,这将导致 80 年代中期的精度。这是因为该模型在一年的第一季度过度适应了季节变化。(回想一下,我们只使用第一个。4 个文件的 csv 文件)因此,它没有捕获一年最后一个季度的季节性变化。然而,在使用所有 4 个训练模型之后。csv 文件可以解决这个问题。您仍然可以从所有 4 个小块中加载数据。csv 文件并训练模型。
在这个 GitHub 库查看代码。希望这篇文章对你有用。
决策树—简介(ID3)
你有没有想过如何从过去的经验中学习?
你一生中会遇到不同类型的人,经过一些经历后,你会知道你喜欢什么样的人,对吗?我的意思是,在与许多人有过几次经历之后,当你遇到一个新的人时,大多数时候你会知道你是否喜欢他们。你是怎么做到的?有了**‘经验’**!对吗?但是你不会一直将多年的经验保存在大脑的顶部,而不是感觉到一些简单快速的决策机制在你的大脑中工作。
因此,与其深入研究大脑的生物学,不如让我们尝试在更简单的层面上建立一个类似的机制。
假设在你与几个人相遇后,你不想让吸血鬼成为你未来的朋友:P
所以你列出了你遇到的几个人,他们的特征,以及他们是否是吸血鬼。( "?"在阴影中属性是因为你只在黑暗的条件下遇到那些人,所以你无法验证他们是否投下阴影)
在观察了这个数据之后,我们可能会得出一个像这棵树一样的幼稚模型,
因为有了那棵树的帮助,我们可以做出决定,所以我们称之为“决策树”。这个树必须满足给定数据集中的所有数据,我们希望它也能满足未来的输入。
但是我们怎么能做出这样的树呢?上面给出的树只是通过对数据的一些随机观察…
根据观察结果…
- 所有肤色苍白的人都不是吸血鬼。
- 所有面色红润吃大蒜的人都不是吸血鬼,如果他们不吃大蒜,那么他们就是吸血鬼。
- 所有肤色普通的人,如果他们没有影子或者我们不知道他们是否有影子,那么他们是吸血鬼,或者如果他们有影子,那么他们不是吸血鬼。
但是,这是建立决策树的正确方法吗?那棵树是我们能从给定的数据集中得到的最简单的树。
这种对大型数据集的随机分析是不可行的。我们需要一些系统的方法来解决这个问题。
让我们尝试用贪婪的方法来解决这个问题…
首先,我们查看数据集并决定我们应该为树的根节点选择哪个属性…
这是一个布尔分类,所以在决策树的末尾我们会有 2 个可能的结果(要么他们是吸血鬼,要么不是),所以每个输入的例子会被分类为真(正面例子)和假(负面例子)。
这里’ P’ 指阳性,表示一个人是吸血鬼,,‘N’指阴性,表示这个人不是吸血鬼。
我们希望属性将更多的数据分成同质的集合,这意味着在这样的集合中,只有 P 或 N 存在,因为如果我们有,我们肯定可以回答关于吸血鬼或没有,因此这些将是树的叶节点。
检查每个属性,看哪一个属性在同构集中的元素数量最多。在这里,我们发现**‘Shadow’**属性在同质集合中具有最高的元素计数,所以我们选择这个属性。
所以到目前为止,我们有这么多的树…
对于影子属性**【是】****【否】,我们可以决定一个人是不是吸血鬼,但是万一【呢?”**我们不知道,我们需要决定当 shadow = '?'时,哪个属性划分数据好
所以,让我们在阴影未知的情况下分析另一个属性…
这里我们发现“大蒜?”属性划分最大元素,实际上是同质集合中的所有元素。
所以,我们的树现在看起来像这样,
这个树看起来比我们通过选择随机属性创建的树更简单,所以我们观察到贪婪方法帮助我们获得更好的结果。
但是,这是正确的做法吗?
不会,因为如果数据集很大,我们不需要将属性划分到同质集合中,我们可能会发现同质集合中的所有属性元素都是 0。
那么我们应该如何进行呢?
所以现在让我们深入研究用于生成决策树的 ID3 算法,它使用了信息增益的概念,这是根据信息论中的基本量熵定义的。
想象一下某一属性的这两个部分…
我们观察到左边的那个有相同数量的 P s 和 N s,所以这并没有给我们任何关于决定的暗示,但是右边的一个比 N s 有更多的 P s,所以它可能在某种程度上把我们引向 P ,所以在这两个中我们可以考虑右边的一个。
所以,现在不要马上给他们 0 分,让我们用另一种方法。比方说, P s 和 N s 是相等数的一个熵最高(1),只有 P s 或 N s 的一个熵最低(0)。我们可以有这样的东西, P/(P+N) vs 熵图。
(Graph created on Desmos)
所以,当 P=N ,从而 P/(P+N) = 0.5 那么熵= 1 ,
如果P = k&N = 0那么熵= 0 。
这感觉像是一个非常合适的图表来实现我们想要的,那么有没有一些数学方法来得到这个图表…
幸运的是,这条曲线可以通过下面的等式得到
可以写成 P/(P+N) 和熵,
替换 x= P/( P+N ) 和 y =熵,
其中 P 和 N 是我们正在寻找属性的属性的 P s 和 N s 的计数,
我们想从属性中找到信息增益,它被定义为,
( IG —来自某个属性的信息增益 A 是熵的预期减少)
IG(Attribute) =属性熵—每个子集熵的加权平均值
举个例子,
^ ( Example calculation of IG )
既然现在你已经了解了熵和信息增益的概念,让我们用这种新方法从头开始重新构建我们的决策树!
我们在这里观察到,我们从影子属性中获得了最大信息增益,选择它作为我们的根节点,
我们需要为 Shadow = '?'决定另一个属性
我们从大蒜中获得最大的信息增益,
所以我们的树看起来像这样,
这与前一种方法完全相同,因为幸运的是,在每一步中,我们都能够找到一些划分为同质集的属性,但是具有信息增益的方法更加健壮,可以应用于从大型数据集生成决策树。
参考: 识别树| MIT OCW
解码 FastAI 的深度学习代码—第 1 课
我当时正在搭上人工智能炒作的列车,决定一头扎进谷歌搜索的深渊,为我的旅程指引方向。正如每个人和他们的博客所建议的那样,我看了吴恩达的机器学习课程讲座,完全被人工智能可能解决的潜在问题所吸引。但我希望作业是用 Python 写的,这种语言让我的生活变得更简单——刮网页,布置选修课,还有保护我的眼睛。而且,感觉我学了太多的理论,却没有足够的实践。
我很快了解到 FastAI 的程序员实用深度学习正是我一直在寻找的。作为一名程序员,我对 FastAI 和他们遵循的自顶向下的方法非常着迷。现在,在课程开始的 15 分钟内,我已经为一个计算机视觉问题训练了一个图像分类器。所以我决定采用同样的方法来学习 Numpy,并一路练习 Python。
我已经试着解释了第一课中的所有代码以及每个函数的作用。所以现在,你可以利用这段时间来尝试不同的时代和学习速度,并改进模型,而不是在小事情上伤脑筋。
最好先看第一课的视频或阅读第一课的相关文章。我从这里开始学习使用 Google Colab 运行我的工作空间(生活中最美好的事情是永远免费——FastAI、Google Colab 和 Python)。在本教程的最后,我有一节解释了代码中使用的 numpy 函数。我们正在处理本课中使用的狗和猫的分类数据集。
基础知识:
我们使用 resnet34 架构(一种卷积神经网络)根据图像属于狗或猫类的概率将图像分类为狗/猫。
数据变量包含训练和验证数据。训练数据是关于模型被训练的内容,验证数据用于检查我们的模型在它以前没有见过的图像上的表现如何。
data.val_y 是验证数据集标签,即带有猫的图像的标签为 0,带有狗的图像的标签为 1。
*data.val_y
array([0, 0, 0, ..., 1, 1, 1])*
学习变量包含模型。在这里,我们使用迁移学习,我们利用预训练模型已经学会识别的特征,如边缘、曲线、某些形状等。激活是一个数字,它表示—该功能在这个位置具有这个置信度(概率)。
预计算=真意味着我们预计算隐藏层的激活,并为我们的图像训练最后的年份。
learn.fit() 通过,学习率为 0.02,训练的历元数为 3。
现在让我们深入研究一下实现。
我们预测验证集中的图像,并将其存储在 log_preds 中。该值以自然对数表示。
log_preds[:2]
*array([[ -0.00323, -5.73731],
[ -0.0001 , -9.21326]], dtype=float32)*
preds 在 log_preds 的每一行中寻找最大值。
probs 通过取 log_preds 第二列的指数,包含图像是狗的概率(第一列是对猫的预测,第二列是对狗的预测)。如果 probs 小于 0.5,我们将图像分类为猫,如果大于 0.5,我们将其分类为狗。
为了了解我们的模型是如何看到这些图像的,让我们看看一些随机正确/错误分类的图像。定义相同的功能,
rand_by_mask(mask) 返回满足 *mask 中条件的四个随机元素的**索引。***我们可以通过改变 np.random.choice. 中的第二个参数 r 来选择返回多少张图片
rand _ by _ correct(is _ correct)首先检查 preds 中的预测标签和 data.val_y 中的实际标签是否与用户输入的 is_correct 参数中的 **匹配,该参数为布尔变量 True /False。它将这个经过筛选的数据集作为掩码发送到 rand_by_mask,以获得四个符合标准的随机图像。
现在我们有了获得随机正确/不正确图像的函数,让我们看看获得****最正确**/不正确分类图像的函数。**
most_by_correct(y,is_correct): y 对于猫是 0,对于狗是 1。是 _ 正确是布尔型。该函数调用 most_by_mask(mask,mult)。将掩码指定为逻辑与的:
**preds中的预测标签和 data.val_y 中的实际标签相互匹配,并且是正确的参数
与 y 参数匹配的 data.val_y
它根据以下逻辑计算 mult :
most_by_mask(mask,mult): 该函数通过 mask 和 mult 实现。首先,我们在 idxs 中得到满足遮罩条件的图像。然后我们将 mult 乘以 idxs 中数据的概率,用 np.argsort 得到结果的最小四个值,为什么要这样做呢?
考虑一下狗的情况。
- 对于正确的狗, mult = -1 和 probs 的子集看起来像 0.60,0.67,0。87,0.98(都大于 0.5)。所以当你排序( multprobs ) 时,得到-0.98,-0。87, -0.67, -0.60 .因为最正确的狗的 probs 最接近 1,所以该结果显示从最正确的顺序开始的图像。*
- 对于不正确的狗, mult = 1。所以当你排序( multprobs ) 时,得到 0.60,0.67,0。87, 0.98.由于最不正确的狗的探针距离 1 最远,因此该结果显示最不正确顺序的图像。***
以猫为例。
- 对于正确的猫, mult = 1 和 probs 的子集看起来像 0.04、0.12、0.35、0.43(都小于 0.5)。所以当你排序( multprobs ) 时,得到的是 0.04,0.12,0.35,0.43。由于最正确的 cat 的 probs 最接近 0,因此该结果显示最正确顺序的图像。*
- 对于不正确的猫, mult = -1。所以当你排序( multprobs ) 时,得到-0.43,-0.35,-0.12,-0.04。由于最不正确的 cat 的探针距离 0 最远,因此该结果显示最不正确顺序的图像。***
现在让我们看看为我们绘制图像的函数。
*****绘图:*我们使用 matplotlib 库来绘制图像。我们在 *ims 中得到一个图像数组,*在 rows、中得到要显示的行数,在 titles 中得到标题数组。我们使用 range 函数在 ims 数组的长度上循环遍历 ims 中的每个图像,为其添加相应的标题并绘制。
load_img_id: PIL 是 Python 图像库,我们从数组 ds 中打开索引 idx 的图像,并将其作为一个 np 数组返回。
plot_val_with_title: 我们得到的 idxs 是由 most_by_correct 或 rand_by_correct 返回的图像的子集。我们使用列表理解从 idxs 中获取单个索引 x ,并使用 load_img_id(data.val_ds,x)从验证集 data.val_ds 中加载每个图像。
我们还将每个图像索引 x 的分类概率存储在 title_probs 数组中。我们将这些传递给 plots ()函数。
**most _ uncertainty:这里我们的目标是找到概率非常接近 0.5 的图像(它们不确定该靠哪边)。我们把概率减去 0.5,取绝对值,排序。我们取最小的四个值,并返回对应于这些概率的元素的索引。
要获得结果图像,请尝试 FastAI 中的代码。你可以在 Google Colab 中实现它,它的教程在这个链接中。您可以自己试验这些函数,比如将参数更改为 plot_val_with_title() 并调整返回的图像数量。
NUMPY 函数解释如下:
- np.argmax(array,axis = None,out = None) : 返回数组中最大元素在特定轴上的索引。对于 2 D 矩阵,axis = 0 表示列,axis = 1 表示行。考虑以下阵列:
np.argmax( array,axis = 0) = [2 2 3 0]
np.argmax( array,axis = 1 ) = [3 1 1 2]
2) np.exp( array,out = None) 计算输入数组中所有元素的指数
现在让我们看看这些图像,了解一下哪种图像被正确/错误地预测了。在这里,我们继续定义自定义函数来选择要显示的图像。
理解这里使用的 numpy 函数:
3) np。其中(condition[,x,y]) 返回满足给定条件的输入数组中元素的索引。
****-> 条件是布尔:根据可选值 x 和 y 有两种变化。
I)当 x 和 y 都不是时:
返回满足条件的值的索引。
**x = np.arange(4).reshape(2, 2)
#Note: np.arange() returns array of evenly spaced values.print(x)
# [ [0, 1], [2, 3]]print(np.where( x > 0))
# (array([0, 1, 1]), array([1, 0, 1]))**
ii) x 和 y 包含值:当条件为真时,使用 x 的值,如果条件为假,则使用 y 替换原始值。
在这里,当数组值大于 0.5 时,该值将更改为 1。对于其他情况,该值将被更改为零。
**arr = [ 0.1 , 0.7, 0.3, 0.6 ]
res = (np.where(arr>0.5, 1, 0))
print(res)
#res = [0, 1, 0, 1]**
****-> 条件类似于数组:当条件为真时,使用 x 的位置值,如果条件为假,则在结果数组中使用 y 的相应值。这里,对于数组中的 True 值,使用 array_true,对于 False 值,使用 array_false。
**array = [[True, False], [False, True]]
array_true = [[1, 2], [3, 4]]
array_false = [[5, 6], [7, 8]]
res = np.where(array,array_cond_true,array_cond_false)print(str(res))
# [[1,6], [7,4]]**
4) np.random.choice (a,size=None,replace=True,p=None) 返回从其元素生成的随机样本。
一个可以是整数也可以是一维数组。如果是数组,则从其元素中生成随机样本。如果是 int,则生成随机样本,就像 a 是 np.arange(a)一样。
可选参数包括:
size: 要返回的数组的大小。
****替换:样品是否有替换
p: 与 a 中每个条目相关的概率。如果没有给定,样本假设在 a 中的所有条目上均匀分布。
**np.random.choice(5, 3)
# array([0, 3, 4])np.random.choice(5, 3, replace=**False**)
# array([3,1,0]) . This is like permutation, values are not repeated**
5) np.argsort(a) 返回以 numpy 数组形式对数组进行排序的索引
**a = np.array([5,7,4,1])
print(a) # [5 7 4 1]b = np.argsort(a)
print(b) # [3 2 0 1]c=a[b]
print(c) # [1 4 5 7]**
返回一个 numpy 数组
请参考以下链接了解 numpy 数组。
**** [## 1.3.1.NumPy 数组对象—科学讲义
创建一个简单的二维数组。首先,重做上面的例子。然后创造你自己的:如何奇数…
www.scipy-lectures.org](https://www.scipy-lectures.org/intro/numpy/array_object.html)
我希望我在第一课解释了代码背后的直觉。非常感谢 Jeremy 和 Rachel 通过 FastAI 开发并民主化了这门深度学习的精彩课程。****
解码我们自己的大脑
科技会释放我们大脑的真正潜力吗?
SOURCE: © ADOBE STOCK
我 一直着迷于我们的大脑可以达到超乎寻常的潜能这一想法。我们可以做远远超出我们想象的事情,发现我们未知的能力。然而,纵观历史,人类大脑的进化已经产生了一定程度的“舒适”。这种水平在某种程度上限制了我们将大脑推出其边界,并阻止我们提高我们的能力。
在过去的十年中,我们看到了神经科学和技术进步如何合作,在技术和人脑之间建立联系。这些进步旨在发展一种“共生关系”,即技术与人类的融合。这当然引发了许多问题——包括对这些创新的过程和实施的困惑,以及许多与伦理相关的问题。
有这么多要讨论的,但我们至少应该首先考虑的是,技术将帮助我们更有效地使用我们的大脑。这就是我们将在这篇文章中探讨的。
技术和人脑
SOURCE: © ADOBE STOCK
想象一下,有一天我们可以改变我们的记忆来解决抑郁和焦虑问题,或者将一整年的研究直接下载到我们的大脑中,或者体验人们的情绪,或者甚至能够只用我们的思维将我们的想法传递给其他人。这听起来似乎遥不可及,但事实是,我们正在取得很大进展,我们正在实现这一目标。
以脑机接口(BCI)为例,这项技术已经发展了几十年。这项技术允许计算机记录大脑信号,并产生转化为行动的反应,如控制机器人假肢或用大脑玩视频游戏。
该领域最有希望的发展之一归功于埃隆·马斯克,他最近的一项宣布是: Neuralink 。
Neuralink´s Robotic Surgery. SOURCE: © NEURALINK
该项目主要基于通过细电极线将人脑与智能手机或电脑等不同设备连接起来的想法,这些电极线允许我们用思想控制这些设备。第一个目标是利用这项技术来改善那些患有瘫痪或类似疾病的人的生活质量,但这只是一个开始。
在大脑和计算机之间建立一条通信路径将允许我们做一些我们认为不可能的事情。
人工智能——人类共生
SOURCE: © ADOBE STOCK
M usk 认为 BCI 对我们的未来至关重要,它将通过允许人类与未来的超级智能人工智能发展合作来减少人工智能(AI)的负面影响。
在这种情况下,共生指的是人工智能和人类之间的有益关系,我们在其中合作和共同进化。听起来有点怪异,但基本上,当人类教会机器如何改进时,机器将以“共生”的方式与人类并肩发展。
这种连接的目的是实现人类和机器之间的某种创造性协作,在这种协作中,我们不仅仅是发布命令,还可以一起集思广益,并接收彼此的反馈。
实施脑机接口技术将提高残疾人和非残疾人的学习和记忆等技能。有了这项技术,人类大脑将能够更快地访问和处理信息。想象一下,能够随时接触到世界上所有的知识,并理解它。
从长远来看,这一过程可能会在不同的阶段发展:从浏览我们大脑内部的特定信息开始,如“谷歌搜索”,到我们的大脑将成为某种“云”——一个我们可以存储、下载、上传、修改并与其他人和计算机实时分享信息的地方,以及立即了解一切的地方。
科技将显著改善我们的记忆,让我们能够储存和获取更多的信息。它可以帮助许多人,如有记忆问题的老人,轻松回忆起来。此外,对于像阿尔茨海默氏症这样的记忆没有完全丧失的残疾人来说,技术将帮助他们建立一种联系,以恢复那些隐藏的记忆。
在 Neuralink 的首次亮相期间,马斯克透露已经用老鼠做了几次测试,他们甚至用一只显然成功控制了计算机的猴子做了测试。现在,他们正在等待食品药品监督管理局(FDA)批准开始人体试验。
马斯克有一个非常有趣的观点,他认为人类大脑除了有边缘系统和皮层之外,还有某种额外的“数字层”。不同的是,我们通常通过手指而不是大脑来连接它。这是一个有趣的观点。
对我们大脑能力的未来研究
SOURCE: © ADOBE STOCK
想想你只用大脑能做的最奇怪、最神奇、最疯狂的事情。
很多想法可能会突然出现在你的脑海里…
还记得 x 战警里的泽维尔教授(X 教授)吗?他有心灵感应。他可以读取你的思想,改变你的感官,甚至放置或删除思想和记忆。这听起来很极端,但我们不应该忽视未来可能与此类似。
未来是非常不确定的,因此发展的顺序将成为现实。人类和技术的结合可能比人工智能更强大。也许我们不会成为“泽维尔教授”,但我们一定会拥有通过心灵交流的力量,不仅是与机器交流,也可以与其他人类交流;在这个层面上我们将能够体会彼此的感受。
现在,这很疯狂,但是考虑一下将我们的大脑提取到一个可以插入一个全新身体的装置中的可能性。一个更强、更快、更灵活的身体,一个只要大脑还活着就不一定会死的身体。这是能防止我们死亡的解药吗?
这些进步旨在释放我们真正的力量,我们大脑的全部潜力,同时将我们从人工智能的末日中拯救出来——如果我们不学会如何控制技术并与之合作,人类就会成为劣等物种。
埃隆·马斯克自己说过,谁想拥有自己的人工智能扩展,谁就可以拥有一个。人类与人工智能的共生可以对未来做出决定,这将建立一个人工智能是民有、民治、民享 的世界。
解码混淆矩阵
在分类问题的情况下,只有一个分类精度可能无法给出全貌。因此,混淆矩阵或误差矩阵用于总结分类算法的性能。
Photo by Joshua Sortino on Unsplash
计算混淆矩阵可以让您了解分类模型在哪里是正确的,以及它会产生什么类型的错误。
混淆矩阵用于检查分类模型对一组真实值已知的测试数据的性能。大多数性能指标,如精确度、召回率,都是从混淆矩阵中计算出来的。
本文旨在:
1。什么是混淆矩阵,为什么需要它。
2。如何用一个猫狗的例子计算一个 2 类分类问题的混淆矩阵?
3。如何在 Python 中创建混淆矩阵& R.
4?对不同指标的总结和直觉:准确度、召回率、精确度&特异性
1.混淆矩阵:
混淆矩阵提供了分类问题中预测结果的总结。表中总结了正确和不正确的预测及其值,并按类别进行了细分。
Confusion Matrix for the Binary Classification
当类别不平衡时,我们不能依赖单一的分类精度值。例如,我们有一个 100 名患者的数据集,其中 5 名患有糖尿病,95 名健康。然而,如果我们的模型仅预测大多数类别,即所有 100 个人都是健康的,即使我们具有 95%的分类准确度。因此,我们需要一个混淆矩阵。
2.计算混淆矩阵:
让我们举个例子:
我们总共有 10 只猫和狗,我们的模型预测它是否是一只猫。
实际值= [‘狗’、‘猫’、‘狗’、‘猫’、‘狗’、‘猫’、‘狗’]
预测值= [‘狗’、‘狗’、‘狗’、‘猫’、‘狗’、‘狗’、‘狗’、‘猫’、‘猫’、‘猫’]
请记住,我们将预测值描述为正/负,将实际值描述为真/假。
术语定义:
真阳性:你预测阳性,是真的。你预言一种动物是猫,它确实是。
真阴性:你预测为阴性,这是真的。你预测动物不是猫,它实际上也不是(它是一只狗)。
假阳性(类型 1 错误):你预测阳性,但它是假的。你预测动物是猫,但它实际上不是(它是狗)。
假阴性(第二类错误):你预测的是阴性,它是假的。你预测那种动物不是猫,但它实际上是。
分类精度:
分类精度由下式给出:
召回(又名敏感度):
召回定义为正确分类的正类总数除以正类总数的比值。或者说,在所有的积极类中,我们正确预测了多少。召回率应该很高。
精度:
精度定义为正确分类的正类总数除以预测的正类总数的比值。或者说,在所有的预测积极类中,我们预测正确的有多少。精度要高。
需要记住的技巧: Pre cision 在分母中有 Pre dictive 结果。
F-score 或者 F1-score:
两个精度和召回率不同的模型很难比较。所以为了使它们具有可比性,我们使用 F-Score。这是精确和回忆的调和平均值。与算术平均相比,调和平均对极值的惩罚更大。f 分应该很高。
特异性:
特异性决定了被正确识别的实际阴性的比例。
解释混淆矩阵的例子:
让我们用上面的猫和狗的例子来计算混淆矩阵:
分类精度:
精度=(TP+TN)/(TP+TN+FP+FN)=(3+4)/(3+4+2+1)= 0.70
回忆:回忆让我们知道什么时候它实际上是肯定的,它预测肯定的频率有多高。
回忆= TP / (TP + FN) = 3/(3+1) = 0.75
精度:精度告诉我们什么时候它预测是,它正确的频率是多少。
精度= TP / (TP + FP) = 3/(3+2) = 0.60
F-score:
F-score =(2 召回率准确率)/(召回率+准确率)=(2 * 0.75 * 0.60)/(0.75+0.60)= 0.67
特异性:
特异性= TN / (TN + FP) = 4/(4+2) = 0.67
3.在 Python & R 中创建混淆矩阵
让我们用 python 和 R 代码来理解上面的狗和猫的例子,这会让你更好地理解到目前为止你对混淆矩阵的了解。
混乱矩阵的 Python 代码:
首先让我们用 python 代码创建一个混淆矩阵。我们必须从 sklearn 库中导入混淆矩阵模块,这有助于我们生成混淆矩阵。
下面是上面解释的 Python 实现:
Python Code
**OUTPUT ->**Confusion Matrix :
[[3 1]
[2 4]]
Accuracy Score : 0.7
Classification Report :
precision recall f1-score supportcat 0.60 0.75 0.67 4
dog 0.80 0.67 0.73 6micro avg 0.70 0.70 0.70 10
macro avg 0.70 0.71 0.70 10
weighted avg 0.72 0.70 0.70 10
混淆矩阵的 R 代码:
现在让我们用 R 代码创建一个混淆矩阵。我们将使用 R 中的插入符号库来计算混淆矩阵。
R Code
**OUTPUT ->**Confusion Matrix and Statistics Reference
Prediction 0 1
0 4 1
1 2 3Accuracy : 0.7
95% CI : (0.3475, 0.9333)
No Information Rate : 0.6
P-Value [Acc > NIR] : 0.3823Kappa : 0.4Mcnemar's Test P-Value : 1.0000Sensitivity : 0.6667
Specificity : 0.7500
Pos Pred Value : 0.8000
Neg Pred Value : 0.6000
Prevalence : 0.6000
Detection Rate : 0.4000
Detection Prevalence : 0.5000
Balanced Accuracy : 0.7083'Positive' Class : 0
4.总结:
- 精确是你对自己的真实想法有多确定。回忆是你有多确定你没有错过任何积极的东西。
- 如果假阴性的出现不可接受/不可容忍,选择召回**。**例如,在糖尿病的情况下,你宁愿有一些额外的假阳性(假警报),而不是保存一些假阴性。
- 如果你想对你真正的阳性结果更加自信,选择精确**。例如,在垃圾邮件的情况下,你宁愿在你的收件箱中有一些垃圾邮件,而不是在你的垃圾邮件箱中有一些普通邮件。在我们将电子邮件 X 放入垃圾邮件箱之前,您想要额外确定它是垃圾邮件。**
- 如果您想要覆盖所有真阴性,选择特异性**,**即意味着我们不想要任何假警报或假阳性。例如,在毒品测试中,所有测试呈阳性的人都会立即入狱,你不会希望任何没有吸毒的人入狱。
我们可以得出结论:
- 准确度值为 70%意味着每 10 只猫中有 3 只识别不正确,7 只识别正确。
- 精度值为 60%意味着每 10 只猫中有 4 只不是猫(即狗),6 只是猫。
- 召回值为 70%意味着实际上每 10 只猫中有 3 只被我们的模型遗漏,7 只被正确识别为猫。
- 特异性值为 60%意味着现实中每 10 只狗(即非猫)中有 4 只被误标记为猫,6 只被正确标记为狗。
如果您有任何意见或问题,请在下面留下您的反馈。更多文章请访问 KeytoDataScience 。你可以在 LinkedIn 上找到我。
解码混合推荐系统的输出
在医疗环境中理解由基于协作过滤器的推荐系统提供的推荐
随着新兴分析技术的兴起,有效的推荐系统已经成为数据科学领域的游戏规则改变者。像网飞和亚马逊这样的公司已经通过建立一些可靠的推荐系统超越了他们的竞争对手。但是这些黑盒算法,它们真的是可解释的吗?在医疗保健这样复杂的领域,我们能依靠这样的算法来解决一些现实世界的医疗保健问题吗?最重要的是,这些系统能否捕获与客户的可用敏感医疗数据相关的医疗环境。这篇文章的目的是去黑盒子这些神奇的建议,并寻找符合逻辑的答案。
混合推荐系统简介
随着对可靠推荐系统需求的增加,已经从传统的基于用户-项目交互的系统转变为基于深度学习架构的推荐系统,该系统能够从复杂的输入数据集中提取模式。Autoencoder 是一种这样的无监督深度学习技术,它使用编码将输入数据嵌入压缩格式,并将该压缩数据解码为输入数据的有意义表示。此外,通过 knn 算法分析这些嵌入,以将相似的患者作为邻居分组在一起。knn 算法用来将患者分组的相似性指数是基于他们个人的医疗索赔历史。
推荐系统在医疗领域的应用
将个性化推荐系统应用于产品推荐是当前科技行业的热门话题。但当涉及到医疗保健行业时,建议的含义可能会改变生活,显然,对准确可靠的建议的需求是重中之重。
在医疗保健行业中应用推荐系统背后的直觉是拥有一个能够向健康保险公司推荐医疗干预措施的平台,以促进对患者的筛选过程。这些干预建议是使用如上所述的自动编码器的深度学习架构构建的。
推荐制度背后的方法和思想
这些建议是基于包含索赔历史以及患者人口统计数据的句子构建的。这些声明以标记为 ICD 代码的诊断和程序代码的形式出现。
这个想法是根据人口统计学和索赔历史的相似性对患者进行分组。一个可靠的推荐系统可以帮助保险公司或医疗提供者以最有效的方式接触到人们。
解释推荐系统的输出
现在我们有了一个经过深思熟虑的混合推荐系统,为我们提供了一个具体的干预建议列表,可以帮助保险公司更有效地瞄准他们的客户,问题是该系统有多可靠。不像产品推荐,我们不想在尝试和测试理论的基础上玩它。
有些人可能会认为,精度、召回率和 AUC 等性能指标可以验证我们的推荐系统,作为一种信心的衡量标准,但最终它只是一种机器学习算法。当我们在这里处理人类情感时,我们需要人类层面的认可。我们如何衡量它在捕捉与数据相关的医疗环境方面是否做得很好?我使用了一些自然语言处理技术来更深入地研究这个推荐系统的推荐
使用 NLP 技术对推荐进行逆向工程
正如上一节所讨论的,仅仅基于性能评估指标来评估推荐系统是不够的。因此,我决定对这些建议进行逆向工程,并试图理解 ML 算法为我们提供这些神奇输出所遵循的方法。
我们不希望我们的推荐系统仅仅根据人们拜访医生的次数或者他们提出索赔的次数来对他们进行分组。我们需要医学上可行的理由来将人们分组。以下是我检查的一些方法:
第一步:访问或索赔的频率
虽然这是一个很好的特征,可以看到人们多久提出一次索赔或多久去一次医院,但我们不能仅仅根据数字和统计数据来判断人们。我使用 python 中流行的 sci-kit learn 库应用了 CountVectorizer 来进行这项检查。我发现,虽然计数是发现人们相似性的重要指标之一,但是还有其他的问题。
第二步:超越频率
频率检查有助于了解与患者相关的常见医疗代码。但是我们需要一个比频率本身更好的方法,因为我们不想增加索赔计数的权重。因此,我使用术语频率-逆文档频率(Tf-Idf)矢量器来关注基于标准化计数的医疗代码的重复出现。然后,这个转换用于分析分组在一起的人,以查看我们的建议是否能够提取上下文中医疗代码的出现。
第三步:回归相关性(主题建模)
Tf-Idf 允许我们通过减少仅由代码/声明计数产生的噪声来赋予频率概念更多的内容。然而,我们可以关注更多的东西。验证一台机器的最大参数之一是它从数据中提取相关性的能力。为了验证这一点,我对我们现有的 ICD 编码应用了主题建模,并注意它们在不同主题中的分布是否传达了一些关于患者相似性分析的医学上有意义的信息。
对于主题建模,我使用了潜在狄利克雷分配(LDA)来基于它们一起出现的概率统计分布 ICD 码。python 中的 Sci-kit learn 和 gensim 库用于 LDA。这给了我一个关注 10 个主题的机会,每个主题都有 10 个 ICD 代码。因此,基于 LDA,研究了 100 个诊断代码,我试图发现这些代码是如何在被我们的推荐系统分组在一起的人群中分布的。
结果和发现
令我惊讶的是,这一分析中有一些有意义的见解。很少有主题代表了一组特定的 ICD 代码,这些代码遵循医学上可行的语义。例如,一个主题主要关注与肝病相关的诊断代码,而另一个主题代表与怀孕相关的代码。所以我们知道,机器能够根据这些代码的医学意义对它们进行分组。这令人耳目一新,我进一步寻找每个主题的分布,这些主题包含分组在相同相似性类别下的人的 ICD 码。这个结果让我百感交集,因为我在诊断代码的分布中发现了一些医学相关性,然而最近邻的样本太小,不能一概而论。进一步的步骤将是具有相同的方法,增加相似性检测技术的层和相似人的更大样本,以给予解码项目更大的权重。
写这篇文章的目的是描述我的方法和思维方式,让我们作为数据科学家喜欢的神奇数字/输出有逻辑意义。但有时我们需要退一步,想想它们在现实世界中的含义。希望你们都喜欢这篇文章,就像我喜欢与你们分享我的想法和分析一样。乐意进一步讨论。可以在这里联系我: LinkedIn-Mayur Bansal 。
解码世界上最流行的数据科学库——Numpy 的性能秘密
没有这个魔咒,任何机器学习脚本都无法启动
无论是数据科学爱好者,还是经验丰富的从业者,每个人都知道这个精彩的 Python 库的威力。
当涉及到处理大型多维数组(表格、图像等)时。),用 numpy 也不会错的很离谱。
但是你知道吗,除了超级方便之外,强大的软件包还包含相当多的性能果汁!
事实上,使用 numpy 内置的基于元素的数组操作通常比遍历标准 python list 要快得多。
考虑这个简单的任务,按元素添加两个列表
比较这两者的性能,我们可以观察到
随着元素数量从 1000 增加到 100,000,Python-lists 所用的时间成线性比例——O(n ),相对于此,*np.add()*
所用的时间几乎保持不变——O(1)。
为了让您了解阵列大小为 100,000 的一些情况,这些数字如下:
%timeit sum_using_loop(a,b,c)
# Average run time: 10.5 ms ± 15.9 µs%timeit sum_using_numpy_builtin(a, b)
# Average run time: 79.6 µs ± 835 ns
numpy 方法快了将近 130 倍!!
问题是—
Numpy 是如何实现如此荒谬的加速的??
一些显而易见的答案包括:
- Numpy 主要是用 C 写的,比 Python 快。
- Numpy 数组是同构的(所有数组元素都有固定的数据类型-
*np.float32, np.uint8*
等等)。与没有这种限制的 python 列表相比),从而允许将数字存储在连续的存储器位置中以便更快地访问(利用 引用位置 )
尽管如此,上述原因还不足以解释处理时间为何不与数组大小成比例。
走到幕后
为了找到答案,让我们开始在 Numpy Land 的秘密任务——解构源代码。
为了理解这一点,让我们先熟悉一些本地术语:
- 通用函数(uf unc)—numpy 中的函数,对“N”维数组(又名 ndarray)执行快速元素运算
- umath — Numpy 模块,包含常见数学运算的实现,如加、减、乘、正弦、余弦等。)
剧透警告 : Numpy 使用矢量指令(SIMD)来加速“ufunc ”,你可以跳到下一节,或者如果你有兴趣了解如何加速,请继续阅读。
经过一番挖掘,我们可以在*__umath_generated.c*
中找到一些我们感兴趣的添加函数的引用
我们看到,*add_functions*
是一个数组,包含对所有特定类型加法函数的引用,包括*INT_add*, *FLOAT_add*, *DOUBLE_add*
等。
How Numpy stores references to all data-type specific addition functions — Numpy source
这些*add_functions*
通过下面的代码映射到我们的 python 的*numpy.add*
函数调用。
Where ‘numpy.add’ comes from — Numpy source
现在为了简单起见,让我们只关注一种数据类型,比如说浮点加法,并弄清楚是什么让它如此快速!
我们的查询将我们带到了实现相关方法的文件— *loops.c*
‘Float_add’ method inside ‘loops.c’ — Numpy source
流程是这样的:
- 确定它是否是一个归约操作——组合输入参数并返回一个聚合结果*(在我们的例子中不是这样)*
2.尝试使用*run_binary_simd_add_FLOAT()*
将它们相加(这里的‘二进制’指的是对两个输入的运算,可以是数组或标量或者两者的组合)
3.如果对 simd_add 函数的调用失败,那么它使用标准的循环元素加法。
注意:这些名字- ’ sse2 ‘,’ simd '可能现在看起来很陌生,但是以后会有意义的
沿着*run_binary_simd_add_FLOAT()*
*,*的轨迹,我们最终会找到我们最感兴趣的那段代码*sse2_binary_add_FLOAT()*
仔细观察,我们可以发现一些奇怪的代码,这些代码(如果你还记得你的“计算机架构”课)类似于汇编语言。
*_mm512_load_ps* _*mm512_add_ps
_mm512_store_ps*
事实上,这些是 ’ 英特尔内部函数 ’ — C 函数,它们提供对汇编指令的访问,而无需实际编写汇编代码!
更确切地说,这些是矢量指令!!
向量:什么鬼东西??
在你开始思考汇编代码之前,请允许我解释一下。
现代 CPU 有称为向量寄存器的专用硬件寄存器,能够同时对多个操作数(相同类型/大小)进行操作,引入了被称为**‘单指令多数据**’(或 SIMD)机制的并行性
向量指令(也称为向量扩展)是访问这些向量寄存器的手段,允许在大型数组(也称为向量扩展)上更快地处理最常见的算术和逻辑运算。向量)。
这些通常用于涉及大型多维数组操作的应用程序,例如
- 图形处理(视频游戏、4K 视频渲染等。)
- 统计(寻找大型数组的平均值/模式)
- 机器学习(矩阵乘法->输入*权重+偏差)
啊哈!!
是什么让这些寄存器这么酷(快)?
这是他们的能力。
典型地,CPU 具有多个 32 位和 64 位通用寄存器,而向量寄存器的大小是 128/256 位,或者在较新的情况下甚至是 512 位。(我们将会看到)。
更大的容量意味着,一个 256 位向量寄存器可以在一个时钟周期内并行保存和操作“8”个 32 位浮点!—与最大的通用寄存器相比,速度提高了近4 倍
SSE 和 AVX 是最流行的向量扩展。
SSE ( 流 SIMD 扩展) 最早于 1999 年在英特尔奔腾 III 中推出,附带**‘8’-128**位向量寄存器。
12 年后,随着“ Sandy bridge ”,英特尔推出了新的 AVX ( 高级向量扩展 ) ,它拥有 256 位寄存器(几乎是上一代的两倍)
Intel Processor vectorization capacity increasing as the generations progress
因此,现在我们有了一些很酷的东西来欣赏现代 CPU 能够进行的硬件优化,而不仅仅是痴迷于它们的时钟速度。
总之,Numpy 对向量指令的利用,使得它在大型数组上执行操作的速度超快,这与标准 python-lists 相反。此外,在内部,numpy 使用了许多其他性能提升技巧,包括’',&其他编译器级优化标志,以执行’'自动向量化。
常见问题
问:上述加速仅适用于英特尔 CPU 吗?AMD 处理器呢?
AMD 确实支持 SSE 和 AVX,但是它的支持仅限于 AVX2 (256 位),而较新的英特尔处理器配备 AVX-512 (512 位)
问。)这些新获得的知识如何让我成为更聪明的数据科学家?
既然你已经知道了内部秘密,那么对你最有利的是:
-尽可能避免使用 for 循环,使用 numpy 内置的操作和方法。
-如果代码包含一维数组上的条件循环,一种快速矢量化代码的方法是使用
np.vectorize
。这里有一个帖子告诉你如何去做。-对于复杂运算,技巧是尝试将循环转换为一系列矩阵运算(点积/矩阵乘法/加法等)。).这里有一个帖子用一个例子描述了同样的情况。
以简单直观的方式分解时间序列
可解释的时间序列模型
Predict store sales
我们都曾与传统的时间序列模型如 ARIMA、指数平滑等进行过斗争,这些模型不太直观,如果不用纯粹的统计术语,很难向企业解释。
给定基于时间的销售数据,直觉上我们想到的是计算出像月度趋势、同比趋势、日间趋势、周峰值等模式。因此,这促使我设计了一种方法,可以分解时间序列以轻松找到所有这些参数,并使我们能够以更简单和直观的方式对未来进行预测。
在本帖中,我们将使用从 2013 年 1 月日到 2015 年 6 月日约 2.5 年的商店销售数据,从罗斯曼商店销售卡格尔挑战。
Table 1: Sales Data for Store XYZ
创造流动
为了实现我们的最终目标,即识别(分解)时间序列的不同组成部分,并将我们的学习转化为更简单、更直观的模型,我们对任务的总体看法是:
- 数据分析( EDA )
- 功能创建和平均销售额计算
- 推导模型的方程式
- 训练模型
- 分解时间序列的不同组成部分
- 使用分解的组件创建一个更简单和直观的模型
- 模型的质量分析并利用它获得其他有用的信息
- 结论
1.数据分析
让我们开始我们的旅程。我们有特定日期的商店销售。字段打开表示商店当天是否正常营业。XYZ 商店在星期天仍然关闭。所以,我们会考虑到日子,只有当商店开门。
一段时间内商店销售的图形可视化。
随时间推移可视化销售的代码
Store sales over time
我们在每年的 12 月份看到一个明显的高峰。除此之外,多年来的下降趋势也很明显。2014 年和 2015 年显示出类似的趋势,但与 2013 年相比明显下降。一个好的方法应该能够捕捉这些变化。
接下来,我们将执行 EDA 来了解一周内几天的销售变化。
可视化一周内销售额的代码
Store sales during days in a week
星期天没有销售,因为商店仍然关闭。我们可以在周六和周一看到一个明显的高峰。周末可能是周六销售额增加的一个原因。类似地,商店在周日停止营业可能会导致周一销售额增加。一个好的方法应该能够捕捉这些变化。
我们已经看到了 12 月份的销售高峰,但是让我们用类似的 EDA 来重新确认我们的假设,就像我们对一周内几天的销售所做的那样。
跨月销售可视化代码
Store sales across months
另一件事,我们可以调查的是一个月中几周的销售模式。我有一种直觉,这不会是一个很强的模式,一个月中几周的销售应该表现类似。但是,为什么不测试一下呢?这个世界充满了惊喜,不是吗?我们将分析一周中每天的平均销售额。
可视化一个月中几周销售额的代码
Sales across weeks in a month
在一个月的第一周和最后一周的几天里,销售额都比较高。一个随机的猜测可能是月末工资和更多人购物的功劳。
2.特色创造和平均销售额
每个日期都可以通过其年、月、周和日来唯一标识。以这种方式表示日期的主要原因是为了发现月趋势、年趋势、日趋势和周趋势。
保持周数的原因是为了确定销售是否随着月份的进展而增加、减少或者根本没有影响。我们称之为每周趋势。
此外,我们将删除商店仍然关闭的数据点。星期天,商店仍然关门。
执行特征创建和清理步骤后,数据如下所示
Table2: Data Overview
接下来,我们将对年、月、日和周字段执行一次性编码。一种热门编码是分类数据的二进制表示。这一步的结果是,我们将拥有以下字段。
'Sales', 'weekday_0', 'weekday_1', 'weekday_2',
'weekday_3', 'weekday_4', 'weekday_5', 'year_2013', 'year_2014',
'year_2015', 'month_01', 'month_02', 'month_03', 'month_04', 'month_05','month_06', 'month_07', 'month_08', 'month_09', 'month_10', 'month_11','month_12', 'weeknbr_1', 'weeknbr_2', 'weeknbr_3', 'weeknbr_4','weeknbr_5'
平均销售额
我们将从计算平均销售额开始。我们将用 avgSales 来表示。我们有 2.5 年的数据,即 2013 年、2014 年和 2015 年年中。由于没有 2015 年全年数据,如果用于平均销售额计算,很可能会添加噪声。我们将仅使用 2013 年和 2014 年的销售数据来计算 avgSales。
计算平均销售额的代码
avgSales 出来是 4825.98
3.推导模型的方程式
主要的想法是找到每月,每年,每天和每周的趋势。我们希望给它加上一个值,叫做指数。因此,我们希望获得月度、年度、日和周趋势指数。我们假设这些趋势是一天中销售额的唯一原因,超过了我们上面计算的平均销售额(avgSales)。
Model’s equation (1)
我们有一次性编码输入功能。在一个时间,只有一个月会高或设置为 1,随着一天,一周数和一年。输入会处理好的。因此,我们的输入等式被修改为:
Model’s equation (2)
让我们看看 2014 年 5 月 17 日模型方程的形式。在这种情况下,年将是 2014 年,月将是 5 月,周数将是 3 日,日将是星期六。所有其他输入将为 0。系数的 0 次方将变成 1。
Model’s equation form for 17th May 2014
我们将两边都取对数,以简化方程,并将其转换为易于应用线性回归的形式。我们将应用无截距回归,并取模型系数的反对数,以获得月度、同比、每日和每周趋势指数。
Model’s equation to apply regression
4.训练模型
这里的因变量是 ln(销售)-ln(avg 销售),我们将采用以 2 为基数的对数。我们有一家店铺从 2013 年 1 月日到 2015 年 6 月日约 2.5 年的销售数据。我们不会使用上个月的数据并保留它来验证模型的性能。
训练模型
接下来,我们将对模型的系数取反对数,以获得相应的指数。
取模型系数的对数
Yearly Index
Monthly Index
Day-wise Index
Weekly Index
5.从回归模型中学习分解时间序列
年度趋势
时间序列的一个重要组成部分是逐年趋势。与 2014 年和 2015 年相比,我们的模型学习的年度指数在 2013 年明显捕捉到了更高的趋势。捕获的年度指数将帮助我们从时间序列数据中分解年度趋势。让我们想象一下结果。
Yearly Index
Yearly trend
我们可以清楚地看到一个逐年下降的趋势。下降趋势可能有许多原因,如商店质量下降或竞争对手商店开业等。需要做更深入的分析才能发现。这将是一个有趣的发现。
月度趋势
时间序列的另一个重要组成部分是月趋势。我们的模型学习的月度指数已经清楚地捕捉到了 12 月份的较高趋势。这将有助于我们从时间序列数据中分解月趋势。让我们想象一下结果。
Monthly Index
可视化月度趋势
Monthly trend
日间趋势
在 EDA 部分中,我们分析了一周中几天的销售情况。我们已经看到星期六和星期一的销售额较高。模型学习的日指数能够捕捉这些模式。让我们想象一下结果。
可视化每日趋势
Day-wise trend
每周趋势
在 EDA 部分,我们在一个月的第一周和最后一周看到了一个小高峰。模型学习的周线指数能够捕捉到这种模式。让我们想象一下结果。
Weekly Index
可视化每周趋势
Weekly trends
6.使用分解组件的更简单和直观的模型
我们将利用上述知识设计一个新的简单直观的模型,我们称之为乘法模型。最终的模型方程将是:
Model’s equation (1)
根据日期,将从计算表中使用 yearly_index、monthly_index、day_index 和 weekNbr_index。
Coefficients table
使用上述模型对 2015 年 9 月 21 日进行预测。它发生在 2015 年 9 月的第三周
销售= avg sales * Sep _ index * 3rd week _ index * 2015 _ index
= 4825.98 * 0.880 * 0.98 * 0.9425 = 3922.54
2015 年 12 月 31 日的预测?它发生在 2015 年 12 月的第 5 周
sales = avg sales * Dec _ coefficient * 5th week _ coefficient * 2015 _ index
= 4825.98 * 1.244 * 1.069 * 0.9425 = 6048.74
7.模型的质量分析并利用它获得其他有用的信息
同时,还训练了对截距或特征对数没有任何限制的线性回归模型。让我们称之为模型 1 和我们的乘法模型,模型 2。我们对这两个模型进行了为期 3 个月的测试,测试数据来自 50 多家商店的未公开数据。
在 RMSE 值相似的情况下,这两种模型在均方根误差方面的表现基本相同。在某些情况下,与模型 1 相比,模型 2 明显是 RMSE 较低的赢家。一个可能的原因可能是领域知识的供给,avgSales,不允许它过度适应和在看不见的数据上表现良好。
比较两个模型性能的代码
Both model performing similarly for most of the cases
乘法模型(模型-2)是商店 39、85 和 88 的明显赢家
Multiplicative Model is a winner
从乘法模型中获取其他有用信息
一些重要的信息和有趣的事实可以很容易地从乘法模型中推导出来。比如,如果企业问我们该怎么回答,或者我们如何比较 2014 年 5 月和 2014 年 11 月的销售额。我们使用学到的月、年、日和周指数的值来回答这些问题。
2014 年 5 月= 5 月指数* 2014 年指数= 1.02 * 0.9879 = 1.007
2014 年 11 月= 11 月指数* 2014 指数= 1.051 * 0.9879 = 1.038
与 2014 年 5 月相比,2014 年 11 月的销售额增加了多少
(1.038–1.007)/1.007 = 0.0307
因此,2014 年 11 月的季节性比 2014 年 5 月高 3.07%。我们可以跨年度对月、周、日进行类似的比较,并从分解的预测模型中获得更清晰的图像。
8.结论
这篇博文的主要思想是调整传统模型来分解时间序列,并创建一个更简单和直观的模型。希望目的达到了。让我知道你的想法和我如何能进一步改善这种方法。
我的 Youtube 频道更多内容:
嗨,伙计们,欢迎来到频道。该频道旨在涵盖各种主题,从机器学习,数据科学…
www.youtube.com](https://www.youtube.com/channel/UCg0PxC9ThQrbD9nM_FU1vWA)
用经验模式分解法分解信号——哑元算法解释
经验模式分解(EMD)是一只什么样的‘野兽’?这是一种分解信号的算法。而我说的信号,指的是一个时序数据。我们输入一个信号到 EMD,我们将得到一些分解的信号,也就是我们信号输入的“基本成分”。它类似于快速傅立叶变换(FFT)。FFT 假设我们的信号是周期性的,它的“基本成分”是各种简单的正弦波。在 FFT 中,我们的信号是从时间频谱转换到频率频谱。
EMD 的不同之处在于输出保留在时间谱中,并且 EMD 不假设我们的信号是周期性的,它不是基于简单的正弦波,而是基于固有模式函数(IMF)。EMD 实际上是基于数据集的,没有关于数据的假设(这就是为什么它被称为经验的)。IMF 是一个波,它有两个特性:
- 最大值和最小值最多相差 1 个。最大值是波峰,最小值是波谷。
假设我们的数据集已经使用
z is the standardized value of data, x is the real value of data, μ is the mean of the dataset, and σ is the standard deviation of the dataset
然后最大值不总是大于零,最小值不总是小于零。最大值是信号的值,当信号的趋势继续上升,然后突然下降时,正好在值下降之前的值是最大值。另一方面,最小值是当信号的趋势继续下降,然后突然上升时,上升前的值是最小值。
2.IMF 的波动均值为零。
一个简单的正弦波就是一个 IMF(最小值和最大值之间的差值最多为 1,数据集的平均值为零)。
>>> import numpy as np
>>> frequency = 1
>>> total_time = 1
>>> res = 0.01
>>> time = np.arange(0, total_time, res)
>>> amplitude = np.sin(2 * np.pi * frequency * total_time * (time/time[-1]))
>>> np.mean(amplitude)
-2.6319088627735572e-17 #this value literally equal 0
The difference between maxima and minima in 1 Hz sine wave is 0
但是一个 IMF 可以有不止一个频率,而且更复杂。
为了让我们更容易理解算法,这里我呈现一个玩具测试信号。
该信号(1 Hz 正弦波)
和这个(4 Hz 正弦波)
结合成这样
瞧,我们将试着通过这一步一步的算法解释来分解这个信号。
这里是 EMD 的算法。
第一步,求最小值和最大值。
步骤 2,从最小值和最大值数组中创建最小值和最大值的包络。使用三次样条插值最小值和最大值以创建最小值和最大值的包络。
第四步,从最小值和最大值的包络中,得到中间值。
步骤 5,将真实玩具测试信号的值减少包络线的中间值。
如果你仔细看,这是我们成功提取的 4 Hz 正弦波。但是看起来有一些误差,比如波的两边有一个突然的跳跃。这来自于三次样条的插值误差。三次样条插值在信号开始和结束时变得如此糟糕。解决方法是我们必须定义一个边界条件。关于边界条件,我的意思是在进行三次样条之前,我们必须定义信号开始和结束时的最小值和最大值的包络。在这篇文章中,信号开始和结束时的最小值和最大值的包络与离它们最近的最大值和最小值相同。让我们从步骤 1 到步骤 5 重新开始,但是这次,我们定义边界条件。
哎哟,这一次的错误是影响整个提取的信号。但是这种突然的飞跃已经消失了。
步骤 6,检查该提取的信号是否是 IMF 。
#here is the ouput of python script
mean: -0.002681745482482584
Total minima 20
Total maxima 21
平均值几乎为零,我认为我们可以忽略它,将其四舍五入为零。最小值和最大值的数量也满足要求,我们得到一个 IMF 。如果您对提取信号的平均值不满意,您可以按照步骤 2-步骤 6 再处理一次。但是这一次,我们使用提取的信号,而不是输入真实的玩具测试信号。当在第一次或第二次等尝试中,提取的信号不满足 IMF 条件时,这是算法的路线。为了使它更简单,让我们承认信号是一个国际货币基金组织。
第七步,用这个 IMF 降低原来的玩具测试信号。
哇,我们得到了我们的 1 Hz 信号(但正如我们所想的,开始和结束是错误的)。看来我们成功地分解了融合信号。但是,在 EMD 算法中停止的条件是当我们的残差信号只是一个常数,单调的,或只有 1 个极值(只有 1 个最小值或最大值)。我们之前被 IMF 减少的信号被称为残差。让我们继续这个过程。
mean: -0.002681745482482584
Total minima 6
Total maxima 6
看起来渣油的要求还没有满足。让我们再处理一遍。
mean: -0.002681745482482584
Total minima 2
Total maxima 2
最后,我们找到了剩余(单调的)。由于边界的累积误差,最后提取的像噪声一样。这可以通过提高信号平均值的阈值来防止。当信号的平均值不满足阈值时(提取的信号不是 IMF),它将按照步骤 2–6 再次尝试,直到提取的信号满足阈值。阈值越趋近于零,这种噪声就越有可能消失。所以这篇文章不会太长,在前面的 EMD 算法演示中,我们使用的阈值并不是太严格。因为最终我们想要达到的是,读者一步一步地理解 EMD 算法。
第一次,我在尝试使用 google colab,所以所有构建上面所有图的代码和解释都可以通过这个链接 访问(PS:有些代码必须按顺序运行才能正常工作)。
再见。
参考资料:
https://medium . com/@ rrfd/standardize-or-normalize-examples-in-python-E3 f 174 b 65 DFC,2019 年 10 月 2 日获取
a .泽勒、r .法特尔迈尔、I. R .凯克、A. M .汤姆、C. G .蓬托内特和 E. W .朗(2010 年 7 月)。经验模态分解-导论。在2010 年国际神经网络联合会议(IJCNN) (第 1-8 页)。IEEE。
解构伯特,第 2 部分:视觉化注意力的内部运作
一种新的可视化工具展示了伯特如何形成其独特的注意力模式。
在 第一部分 (非先决条件)中我们探讨了 BERT 语言模型是如何学习各种直观结构的。在第二部分中,我们将深入探讨伯特的注意力机制,并揭示其变形超能力的秘密。
试玩一款 互动演示 搭配bertviz*。*
自人工智能领域诞生以来,赋予机器理解自然语言的能力一直是该领域的一个愿望,但事实证明这一目标难以实现。在某种意义上,理解语言需要解决更大的人工智能问题(AGI)。例如,图灵测试——最早构想的机器智能测量之一——是基于机器用自然语言与人类对话的能力。
然而,就在最近几年,自然语言处理(NLP)领域发生了一场静悄悄的革命。新的深度学习模型已经出现,大大提高了机器处理语言的能力,导致从情感分析到问题回答的 NLP 任务的性能大幅提高。
也许这些模型中最著名的是 BERT(BI directionalEn coderR表示来自Ttransformers)。BERT 基于 NLP 领域的两个最新趋势:(1)迁移学习和(2)转换模型。
迁移学习 的思想是在一个任务上训练一个模型,然后利用获得的知识提高模型在一个相关任务上的表现。BERT 首先接受两项无监督任务的训练:掩蔽语言建模(预测句子中缺失的单词)和下一句预测(预测一个句子是否自然跟随另一个句子)。通过在大型语料库(所有英语维基百科和 11,000 本书)上进行预训练,BERT 可以在英语工作的坚实基础上完成任何新任务。
BERT 的基础是 变换器 模型,这是一种接受序列作为输入(例如单词序列)并产生一些输出(例如情感预测)的神经网络。不同于传统的循环网络,如 LSTMs 依次处理每个序列元素,变压器通过注意机制在各个元素之间形成直接连接,从而同时处理所有元素。这不仅实现了更高的并行性,还提高了一系列任务的准确性。
伯特的建筑
BERT 有点像 Rube Goldberg machine(鲁布·戈德堡机器)( T17 ):虽然端到端系统看起来很复杂,但是各个组件都很简单。在这篇文章中,我将关注 BERT 的核心部分:注意力。
粗略地说,注意力是模型根据输入特征对某项任务的重要性为其分配权重的一种方式。例如,当决定一幅图像是否包含一只狗或猫时,模特可能会更多地关注图像中毛茸茸的部分,而不是背景中的灯或窗户。
类似地,一个试图完成句子“狗从街那头跑到我和 ____ ”的语言模型可能想对单词狗比对街、更关注,因为知道主语是狗对预测下一个单词比知道狗从哪里来更重要。正如我们稍后将看到的,注意力还可以用来在单词之间形成连接,使伯特能够学习各种丰富的词汇关系。**
你注意到了吗?
幸运的是,伯特的注意力机制非常简单。假设你有一些序列 X ,其中每个元素是一个向量(称为值*)。在下面的例子中, X 由 3 个向量组成,每个向量的长度为 4:*
Attention 只是一个函数,它将 X 作为输入,并返回另一个相同长度的序列 Y ,由与 X 中相同长度的向量组成:
其中 Y 中的每个向量只是 X 中的向量的加权平均值:
就是这样——注意力只是加权平均的一个花哨名字!权重显示了在计算加权平均值时,模型对 X 中的每个输入的关注度*,因此被称为注意力权重。稍后,我们将讨论这些注意力权重是如何计算的。*
(注意,注意力不是 BERT 的唯一成分;还有前馈层、残差连接和层归一化模块,它们都与注意力组件一起工作以产生模型输出。但是注意力才是真正的主力,所以我们会关注这一点。有关其他组件的更多详细信息,请查看参考资料部分的教程。)
关注语言
那么注意力是如何应用于语言的呢?好吧,假设 X 表示像“狗跑了”这样的单词序列。我们可以将每个单词与一个连续的向量相关联——称为单词嵌入— ,它捕获单词的各种属性:
可以想象,这些属性代表了单词的情感,是单数还是复数,词性指示符等等。在实践中,单词嵌入不那么容易解释,但是仍然有很好的特性。例如,在嵌入空间中,具有相似含义的单词通常彼此接近。此外,可以对单词嵌入执行算术运算并产生有意义的结果,例如嵌入(国王)—嵌入(男人 ) +嵌入(女人 ) ≈嵌入(女王)。
由于注意力也是简单算术的一种形式,因此将注意力应用于这些单词嵌入似乎是合理的:
通过关注 X 中的单词嵌入,我们在 Y 中产生了复合嵌入(加权平均)。例如, Y 中 dog 的嵌入是分别具有权重 0.2、0.7 和 0.1 的 the、和raninX*、的嵌入的组合。*
构建单词嵌入如何帮助模型实现其理解语言的最终目标?要完全理解语言,仅仅理解组成句子的单个单词是不够的;模型必须理解单词在句子的上下文中是如何相互关联的。注意机制通过形成模型可以推理的复合表示,使模型能够做到这一点。例如,当语言模型试图预测句子“the running dog was __”中的下一个单词时,除了单独理解概念 running 或 dog 之外,该模型还应该理解 running dog 的复合概念;例如,走狗经常喘气,所以气喘吁吁是句子中合理的下一个词。
视觉化注意力
注意力为我们提供了一个镜头(尽管模糊不清),通过这个镜头我们可以看到伯特是如何形成复合表征来理解语言的。我们可以使用 BertViz 来访问这个镜头,这是一个我们开发的交互式工具,可以从多个角度可视化 BERT 中的注意力。
下面的图像(在这里有交互形式)显示了一个样本输入文本引起的注意。这个视图将注意力可视化为连接被更新的单词(左)和被关注的单词(右)的线,遵循上面图的设计。颜色强度反映了注意权重;接近 1 的权重显示为非常暗的线,而接近 0 的权重显示为模糊的线或者根本看不到。用户可以突出显示特定的单词,以仅看到来自该单词的关注。这种可视化被称为注意力-头部视图,原因稍后讨论。它基于来自 Llion Jones 的优秀 Tensor2Tensor 可视化工具。****
********
Left: visualization of attention between all words in the input. Right: visualization of attention from selected word only.
在这个例子中,输入由两个句子组成:“兔子快速跳跃”和“乌龟缓慢爬行”。【SEP】符号是表示句子边界的特殊分隔符,而【CLS】是附加在输入前面的符号,用于分类任务(详见参考文献)。
可视化显示,在没有跨越句子边界的单词之间,注意力最高;该模型似乎明白,它应该将单词与同一个句子中的其他单词相关联,以便最好地理解它们的上下文。
然而,一些特定的词对比其他词对具有更高的注意力权重,例如兔子和蹦出。在这个例子中,理解这些单词之间的关系可能有助于模型确定这是对自然场景的描述,而不是肉食美食家对供应兔子的跳跃餐厅的评论。**
多头注意力
上面的可视化显示了模型中的一种注意力机制。伯特实际上学会了多种注意力机制,称为头,它们彼此平行运作。我们很快就会看到,与单个注意力机制相比,多头注意力使模型能够捕捉更广泛的单词之间的关系。**
伯特还堆叠了多层注意力,每一层都对上一层的输出起作用。通过单词嵌入的这种重复组合,BERT 能够在到达模型的最深层时形成非常丰富的表示。
因为注意力头部不共享参数,所以每个头部学习独特的注意力模式。我们在这里考虑的 BERT 版本— BERT Base — 有 12 层和 12 个头,导致总共 12 x 12 = 144 个不同的注意机制。我们可以使用模型视图(在交互形式中可用这里 )一次可视化所有头部的注意力:**
Model view (first 6 layers) for input sentences “the rabbit quickly hopped” and “the turtle slowly crawled”.
模型视图中的每个单元显示特定层(由行指示)中特定头部(由列索引)的注意模式,使用先前的注意头部视图的缩略图形式。注意模式是特定于输入文本的(在这种情况下,与上面的注意头视图的输入相同)。从模型的角度来看,我们可以看到伯特产生了丰富的注意模式。在本文的后半部分,我们将探索 BERT 是如何生成如此多样的模式的。
解构注意力
前面我们看到了模型如何使用注意力来计算单词嵌入的加权平均值,但是注意力权重本身是如何计算的呢?
答案是 BERT 使用了一个兼容性函数,它给每一对单词分配一个分数,表明它们应该多重视彼此。为了测量兼容性,模型首先为每个单词分配一个查询向量和一个关键字向量:****
这些向量可以被认为是一种单词嵌入类型,就像我们前面看到的值向量一样,但是是专门为确定单词的兼容性而构造的。在这种情况下,兼容性得分只是一个单词的查询向量和另一个单词的关键向量的点积,例如:**
为了将这些兼容性得分转化为有效的注意力权重,我们必须将它们归一化为正,并且总和为 1(因为注意力权重用于计算加权平均值)。这是通过对给定单词的分数应用 softmax 函数来实现的。例如,当计算从狗到狗和跑的注意力时,我们有:****
右侧的 softmax 值代表最终的注意力权重。注意,在实践中,点积首先通过除以矢量长度的平方根来缩放。这是因为长矢量可能会产生非常高的点积。
所以我们现在知道注意力权重是从查询和关键向量中计算出来的。但是查询和关键向量来自哪里呢?与前面提到的值向量一样,它们是基于前一层的输出动态计算的。这个过程的细节超出了本文的范围,但是您可以在最后的参考资料中读到更多关于它的内容。
我们可以使用神经元视图,下面的(在这里以交互形式**)来可视化如何从查询和关键向量中计算注意力权重。这个视图跟踪注意力的计算,从左边的选定单词到右边的完整单词序列。正值表示蓝色,负值表示橙色,颜色强度表示大小。就像前面提到的注意力-头部视图一样,连接线表示连接单词之间的注意力强度。******
Neuron View
让我们一次浏览一个神经元视图中的列,并重温前面讨论的一些概念:
****查询 q:查询向量 q 对左侧正在关注的单词进行编码,即正在“查询”其他单词的那个单词。在上例中,突出显示了“on”(所选单词)的查询向量。
键 k: 键向量 k 对关注的右边的单词进行编码。关键向量和查询向量一起确定两个单词之间的相容性分数。
q×k 这是点积(元素乘积之和)的前身,包含它是为了可视化,因为它显示了查询中的单个元素和关键向量是如何构成点积的。
q k :所选查询向量和每个关键向量的比例点积(见上图)。这是未标准化的注意力得分。
Softmax :缩放后的点积的 Softmax。这将注意力分数归一化为正值,并且总和为 1。
神经元的观点最好通过交互来理解。您可以观看下面的简短视频演示(或直接访问工具):
解释伯特的注意力模式
正如我们在前面的模型视图中看到的,伯特的注意力模式可以呈现出许多不同的形式。在本系列的第 1 部分中,我描述了其中有多少可以用少量的可解释结构来描述。在本节中,我们将重温这些核心结构,并使用神经元观点来揭示伯特可塑性力量的秘密。
聚焦定界符的注意模式
让我们从最受关注的句子分隔符【SEP】标记(来自 Part 1 的模式 6)这个简单的案例开始。正如本文中所讨论的,这种模式充当一种“无操作”;当注意力头在输入句子中找不到任何其他可以关注的东西时,它会关注*【SEP】*标记:
Delimiter-focused attention pattern for Layer 7, Head 3 of the BERT-base pretrained model.
那么,伯特究竟是如何能够专注于【SEP】记号的呢?让我们看看可视化是否能提供一些线索。这里我们看到上面例子的神经元视图:
在键列中,两次出现的【SEP】的键向量带有一个独特的签名:它们都有少量具有强正(蓝色)或负(橙色)值的活跃神经元,以及大量具有接近于零(浅蓝色/橙色或白色)值的神经元:
Key vector for first [SEP] token.
查询向量倾向于与那些活动神经元的【SEP】关键向量相匹配,从而导致元素态乘积 q×k 的高值,如下例所示:
Query vector for first occurrence of “the”, key vector for first occurrence of [SEP], and elementwise product of the two.
其他单词的查询向量遵循类似的模式:它们沿着同一组神经元匹配【SEP】关键向量。因此,看起来 BERT 已经将一小组神经元指定为“[SEP]-匹配神经元”,并且查询向量被分配与这些位置处的 [SEP] 关键向量相匹配的值。结果就是【SEP】——集中注意力模式。**
单词袋注意模式
这是一种不太常见的模式,在第 1 部分中没有讨论。在这个模式中,注意力被平均分配到同一个句子中的所有单词:**
Sentence-focused attention pattern for Layer 0, Head 0 of the BERT-base pretrained model.
BERT 本质上是通过对同一个句子中的单词嵌入进行(几乎)未加权平均来计算单词包的嵌入。
那么,BERT 是如何巧妙处理这些查询和关键字来形成这种注意力模式的呢?让我们再次回到神经元的角度:
Neuron view of sentence-focused attention pattern for Layer 0, Head 0 of the BERT-base pretrained model.
在 q×k 列中,我们看到了一个清晰的模式:少数神经元(2-4 个)主导了注意力分数的计算。当查询和关键向量在同一个句子中时(在这种情况下是第一个句子),乘积在这些神经元上显示高值(蓝色)。当查询和关键向量在不同的句子中时,在这些相同的位置,乘积是强负的(橙色),如下例所示:
The query-key product tends to be positive when query and key are in the same sentence (left), and negative when query and key are in different sentences (right).
当 query 和 key 都来自句子 1 时,它们倾向于具有沿着活动神经元的相同符号的值,导致正乘积。当查询来自句子 1,而关键字来自句子 2 时,相同的神经元倾向于具有符号相反的值,导致负乘积。
但是 BERT 是怎么知道“句子”这个概念的,尤其是在更高层次的抽象形成之前的网络第一层?如前所述,BERT 接受特殊的【SEP】记号来标记句子边界。此外,BERT 合并了添加到输入层的句子级嵌入(参见下面的图 1)。这些句子嵌入中编码的信息流向下游变量,即查询和关键字,并使它们能够获得特定于句子的值。
Figure 1: Segment embeddings for Sentences A and B are added to the input embeddings, along with position embeddings. (From BERT paper.)**
下一个词的注意模式
在下一个单词注意模式中,除了在【SEP】和【CLS】标记处,几乎所有的注意力都集中在输入序列中的下一个单词上:
Next-word attention pattern at Layer 2, Head 0 of the BERT-base pretrained model.
该模型将重点放在下一个单词上是有意义的,因为相邻的单词通常与理解单词在上下文中的含义最相关。传统的 n -gram 语言模型也是基于同样的直觉。让我们看看上面例子的神经元视图:
我们看到“the”的查询向量和“store”(下一个单词)的关键向量的乘积在大多数神经元中都是强正的。对于除了下一个标记之外的标记,键查询产品包含一些正值和负值的组合。结果是“The”和“store”之间的关注度得分较高。
对于这种注意力模式,大量的神经元被纳入注意力得分,并且这些神经元根据标记位置而不同,如下所示:
Elementwise product of query and key vectors, for query at position i and key at position i+1, for i = 2, 8, 14. Note that the active neurons differ in each case.
这种行为不同于以定界符为中心和以句子为中心的注意模式,在这两种模式中,一小组固定的神经元决定注意分数。对于这两种模式,只需要几个神经元,因为模式非常简单,而且受到关注的单词几乎没有变化。相反,下一个单词注意模式需要跟踪 512 个单词中的哪一个从给定位置受到注意,即,哪一个是下一个单词。为此,它需要生成查询和键,使得每个查询向量与来自 512 种可能性的唯一键向量匹配。使用一小部分神经元很难做到这一点。
那么 BERT 是如何生成这些位置感知查询和密钥的呢?在这种情况下,答案在于 BERT 的位置嵌入,它在输入层被添加到单词嵌入中(见图 1)。BERT 为输入序列中的 512 个位置中的每一个学习唯一的位置嵌入,并且该特定于位置的信息可以通过模型流到键和查询向量。
关于我的可视化工作和其他人工智能项目的更新,请随时关注我的Twitter。******
笔记
我们只涉及了第一部分中讨论的一些粗略的注意力模式,还没有触及围绕语言现象的更低层次的动态,如共指、同义等。我希望这个工具可以帮助为这些案例提供直觉。
试试吧!
你可以在 Github 上查看可视化工具。请玩玩它,分享你的发现!
参考
您可以在这些优秀的教程中找到有关 BERT 和其他变压器模型的架构的更多详细信息:
有插图的伯特:一本关于伯特建筑的精美插图教程。
从零开始的变形金刚:这是一个详细而直观的从零开始构建变形金刚的教程,包括 PyTorch 代码。
承认
我要感谢 Richelle Dumond、John Maxwell、Lottie Price、Kalai Ramea 和 Samuel rnqvist 为本文提供的反馈和建议。
为了进一步阅读,请查看我最近的文章 ,其中我探索了 OpenAI 的文本生成器 GPT-2。
解构伯特
揭示了它在 NLP 任务中最先进的表现的线索
This picture is an adaptation of a figure in the blog for paper — a structural probe for finding syntax in word representations
变压器架构模型,尤其是 BERT,已经被证明在许多自然语言处理任务中非常有效,只需对在大型语料库上以无监督方式预训练的模型进行微调。BERT 模型将单词序列作为输入,并产生一系列跨层的单词嵌入。这些单词嵌入考虑了单词出现的上下文。
两篇最近*(2019 年 4 月和 2019 年 6 月 6 日)*发表的论文 ( 1 及其 博 , 2 及其 博 ) 提供一些几何洞见
这些论文的一些关键发现
- BERT 的单词向量输出编码了丰富的语言结构。BERT 近似地将[语法树](http://Recovered Parse tree from BER vectors)编码到它为一个句子输出的单词嵌入中。有可能通过单词嵌入的线性变换来恢复这些树。( 1 及其 博客 )
- BERT 出现在互补子空间中对单词向量中的句法和语义特征进行编码( 2 及其 博客 )。
- 一个词的不同义项有着空间上细粒度分离的表征*(由句子语境决定)*(2及其 博客 )
从句子的 BERT 词向量中恢复分析树
语言由离散的结构组成——符号序列*(单词),句子的句法结构被捕获在一棵树中。相比之下,神经网络模型对连续数据进行操作——它们将符号信息转化为高维空间中的向量。已知这些向量(单词嵌入)在其长度/方向(例如,word2vec、fasttext 等)中捕捉语义相似性。)*。
如上所述,最近的发现显示伯特单词向量输出编码了丰富的语言结构。在向量输出中编码的句子是语法树的几何近似副本。句子中的单词被给定在高维空间中的位置,如果我们对这些单词向量进行特定的变换,这些位置之间的欧几里德距离映射到语法树距离。本质上,我们可以通过使用特定的线性变换来变换单词向量,然后根据单词向量之间的距离找到最小生成树,来恢复句子的语法树(以及具有方向边的依存树】。
语法树中的树距离*(两个节点之间的树距离是它们之间的路径中的边数)和欧几里德距离(从单词嵌入导出的最小生成树中的节点之间)之间的映射不是线性的。两个单词之间的语法树距离对应于提取的最小生成树中相应节点之间的欧几里德距离 的 的平方。第二篇论文给出了为什么它是欧几里德距离的平方而不是欧几里德距离的平方的原因(本节的剩余部分对于理解伯特模型来说不是核心,可以跳过)。*
Figure from blog on second paper
由于树枝的存在,不可能将一棵树映射到欧几里得空间。
比如左边节点 A 和 B 之间的树距离是 2 — d (A,X)+d(X,B)
由于 d *(A,B)=d(A,X)+d(X,B)*在到欧氏空间的等距映射中,A,X,B 必须共线 ( X 必须在连接 A 和 B 的线上,以上条件成立)
同样的道理应用到 A 点、X 点、C 点, d *(A,C)=d(A,X)+d(X,C)*A、X、C 也必须共线。但这隐含着 B = C,这是一个矛盾。
然而,从树到平方距离(勾股嵌入)有一个等距映射,如下图所示
Figure from blog on second paper
博客文章有更多的例子。总的来说,它们说明了
还有,
这个博客还有其他有趣的结果。例如,随机分支的树,如果被映射到足够高维的空间,其中每个子树从其父树偏移一个随机单位高斯向量,将近似为勾股嵌入。这一点的实际含义是,上下文嵌入近似于句子的依存分析树的勾股嵌入。根据平方距离属性,我们从向量中恢复了嵌入树的整体形状。
恢复的树的形状*(受节点间边长的影响)*仅近似类似于理想树——差异具有一些模式。依赖关系之间的平均嵌入距离变化很大。不知道这些差异意味着什么。也许 BERTs 表示除了依赖关系解析树之外还有其他信息。
Figure from second paper
顺便说一句,如果我们对基因/蛋白质序列做同样的练习来检查它们是否包含信息,那么看到接近的异常边缘(部分/相同/如上图所示)将是有趣的——不一定证实实际的 3-D 几何构型。
句法树也在句子的注意力矩阵中被捕获
第二篇论文还展示了句子捕获句法树的注意矩阵。想想“老狐狸看见新狗”这句话。考虑词对*“老,狐狸”。我们可以通过从所有层 (12 层,每层有 12 个注意力头)的每个注意力头中选取该对的标量值来构建向量如果我们训练线性分类器,这些线性分类器将每个单词对的这种模型范围的注意力向量作为输入,并且如果两个单词之间存在关系以及关系的类型,则进行分类,这些分类器表现得相当好(即使不是现有技术的结果)*表明句法信息被编码在句子的注意力矩阵中。
Figure from second paper
BERT 似乎在其嵌入中编码了语义特征
通过简单地将单词如 die 在不同句子上下文中的嵌入可视化,我们可以看到词义是如何影响嵌入的。
Figure from second paper
一般来说,单词嵌入显示
- 一个词的不同义项被分开*(上面三簇为“死”字)。词义消歧是通过这种分离来完成的*
- 在群集内部,似乎存在着更细微的意义差别(参见下面单词“lie”的嵌入)
Figure from second paper
- 类似于我们前面看到的表示语法的位置,这里嵌入的位置表示语义
第二篇论文声称词义是在低维空间中捕捉的,尽管还不清楚这是怎么回事。鉴于这种观察,似乎向量在互补的子空间中编码句法和语义信息
对已发布代码的实验
第一篇论文的 Github 库有代码从上述句子中恢复语法树
例如,对于输入的句子
掉进下水道的小鸭子获救了
从上面句子的单词嵌入中恢复的解析树以及同一个句子的依存解析器输出如下所示
结论
未来沿着上述路线解构模型
- 可能揭示更多的语言结构(比如解析树)或者等价的更多的子空间
- 理解内部表示的几何可以潜在地发现改进模型架构的区域