Machine Learning System Design[机器学习系统设计]

主要涉及在设计复杂的机器学习系统时,可能遇到的主要问题。同时,我们也会试着给出一些关于如何巧妙构建一个复杂的机器学习系统的建议。

具体而言,我们首先要讨论的是,当我们在进行机器学习时,着重要考虑的问题应该是什么。

Building a Spam Classifier[搭建一个垃圾分类器]

Prioritizing What to Work On[确定优先级]

我们先来看看一个关于垃圾邮件分类的例子。

假如说,我们想要建立一个垃圾邮件分类器。[左侧]这里显示的是一封垃圾邮件,它想向我们推销一些商品,而且似乎看上去并不是什么正品。[右侧]而这里则是一封正常的邮件。

我们可以注意到,垃圾邮件常常有意地使用非正式的中文或者一些符号,比如这里的劳力士,这里的”力”实际上是日文的平假名”ka”,只是看上去跟中文的”力”比较相似,而处方药的”处”其实也主要在日语中使用,并不是常用的汉字。

而右侧正常的邮件中,显然是一封正常的邮件。

假设,我们现在已经有了一些标记过标签的训练集,包括标记了的垃圾邮件,使用

Y=1表示,也包括了标记了非垃圾邮件,使用y=0表示。那么我们如何使用监督学习来构建一个分类器以区分垃圾邮件和非垃圾邮件呢?

为了使用监督学习的方法,我们首先必须确定的是,如何从邮件中提取一些特征,并以此来构造邮件的特征向量x。给定特征x和标注y,那么我们就能够训练出某种分类器,比如,我们可以用逻辑回归。

现在我们来思考下可能会有用的特征有哪些。比如,我们可能会想出,可能可以挑选出100个具有明显指示性的词来区分垃圾邮件和非垃圾邮件。

比如说,如果有封邮件,包含了词”优惠”,它可能更有可能是一封垃圾邮件,而同时如果它还含有”购买”这样的词,那么它就像是一封垃圾邮件。而如果邮件包含了我们的真名,那么这可能是认识我们的人写的邮件,这可能就意味着这封邮件不是一封垃圾邮件。也许通过观察,我们可能会认为”立刻”这个词并不是一封垃圾邮件,因为我们可能处于关键岗位,常常会收到比较紧急的邮件。  当然,可能还会有其他的词,我们可以选出这样成百上千的词。

给定这样的一封邮件,我们可以将这封邮件使用特征向量的形式表示它。比如我们按照上面的词典,检查一下这些词是否出现在我们的邮件中,然后我们就可以以此来定义一个特征向量x来表示右边这封邮件,邮件中没有出现我们的名字,所里这里是0. 这里出现了”购买”,所以这里我们填1,这里我们仅关心词是否出现与否,所以即使邮件中出现了两次”购买”,我们也只填1,所以我们的整个特征向量的元素要么是0要么是1.

所以,我们依据词出现与否来构建表示邮件的特征。在这个例子中个,因为我们限定了词典的大小,也就是100,所以我们最终构建出来表示邮件的特征向量的就是一个100维的向量。所以,简单归纳起来,对于每一个xj而言,它的取值就是0或者1,而具体取值则是看第j个词是否在邮件中出现。

顺便说一下,虽然我们所描述的这个过程是我们自己挑选的100个词,但是在实际当中,最普遍的做法是遍历整个数据集,然后选出出现次数最多的n个词,而n一般至少介于1万到五万之间。然后将它们作为我们要用的特征,因此就并不需要我们手动选取这些词。这样,我们就可以很容易地来构建邮件的特征了。

现在,如果我们正在建设一个垃圾邮件分类器,我们应该会面对这样一个问题,那就是,如何在有限的时间和精力下,改进我们的学习算法,从而使得我们的垃圾邮件分类器具有较高的精准度。一种直觉是,我们应该收集大量的数据,事实上确实有好多人这样做,很多人认为数据越多算法表现就越好。就垃圾邮件分类这个应用而言,有一个被称为“蜂蜜罐”的项目,它可以构造很多假的邮件地址,同时故意将这些邮件地址透露给发送垃圾邮件的人,这样就可以轻松地获取到大量的垃圾邮件样本了。而在其他一些领域,比如新闻分类,可以通过编写爬虫去抓取诸如网易新闻、今日头条的数据以获得标注好分类的新闻数据。

不过,我们从之前也学习到,获取更多的数据,对于改善算法的性能,可能有帮助也可能没帮助。不过对于大多数机器学习问题,还有很多其他的办法来提升机器学习的效果。比如对垃圾邮件而言,也许我们可以想到,可以使用更加复杂的特征,比如邮件的路由信息,路由信息的含义是它从发送者到我们这里,中间经过了哪些服务器,这种信息通常包含在邮件的头信息中。所以,当垃圾邮件发送者发送垃圾邮件时,它们总会试图让这个邮件的来源变得更加模糊,或者伪造邮件头信息,或者使用非常不常见的邮件服务器来发送。因此,我们可以想象,通过分析邮件的头信息,并从中提取出更加高级、复杂的特征来获取一系列的邮件路由信息,进而判断这是否是一封垃圾邮件。

我们当然也可以继续想到更多高级的特征。

实际上,当我们面对机器学习问题时,总是可以“头脑风暴”一下,想出一堆方法来试试,就像我们这里列举的。不过这些方法的效果是不确定的,而且怎么选择也是个问题,至少没有什么理论。不过我们还是可以总结一些方法论来帮助我们更加高效地工作。比如,我们下面开始要讨论的误差分析。

Error Analysis[误差分析]

误差分析会帮助我们更加系统性地做出决定,帮助我们了解数据以及目前学习算法可能存在的不足。

所以,如果要开展一个机器学习工作,一般来说最好的实践方式是,从一个可以快速实现的最简单的算法开始,比如花一天时间来快速地搭建出一个可以运行的简单系统,即使效果不好也无所谓。一旦我们完成这项工作,我们可以画出学习曲线,这个我们在前面的课程讨论过,通过画出学习曲线,我们可以观察训练集误差和交叉验证集误差,然后我们就可以找出我们的算法是否有高bias问题,或者是否有高variance问题,或者什么别的问题。在这样分析以后,我们就可以决定是否需要获取更多的训练样本,或者加入更多的特征,或者其他手段来提高算法的效果。

这样做的原因在于,在刚接触机器学习问题的时候,我们无法知道是否需要更复杂的特征,是否需要更多的样本,甚至是否需要更加复杂的算法。想一开始就知道要用什么样的特征,使用什么样的算法,需要多少样本量,这本身就是很困难的事情。因为,一开始我们没有任何可用的信息,除了要解决的问题本身。所以,一开始我们根本没办法决定应该把时间花在什么样的地方来提高算法的效果。不过,当我们实践了一个即使非常简单、不完美的算法后,通过画出学习曲线,我们就有了很多信息来决定下一步应该干什么。所以,通过这种方法,我们可以避免所谓的过早优化问题,这个的意思是,一开始没有什么信息的情况下,不要想太多,先用一个简单的模型试试看,然后就可以得到更多的信息,通过这些信息我们就能够知道应该怎么进行下一步,有的放矢地前进,而不仅仅是凭着直觉来决定下一步应该做什么,毕竟直觉不总是正确,而这种方法则是一种比较有保证的工作方式。

除了画出学习曲线,另一件非常有用的事情就是误差分析。误差分析的意思是,在我们构建机器学习系统时,比如搭建一个垃圾邮件分类器时,我们可以人工地看看交叉验证集中被算法错分的样本究竟是什么样子。所以,通过这些被算法错分的邮件,我们可以发现某些系统性的规律,什么类型的邮件总是被错分,一般来说这么做了以后,我们常常可以得到启发,并可以构造出新的特征来解决这类错分,或者也可以发现现有的特征可能存在着一些我们事先没有预料到的意外问题,比如之前我们说”立刻”一词可能是正常邮件的一种暗示,这个是基于我们的先验知识,即我们常常收到比较紧急的邮件,但是我们在进行误差分析的时候可能发现,很多广告信息中会含有”立刻购买”,”立刻拨打电话”等字样,甚至出现频率远远高于正常邮件。对于这种情况,我们可能就可以通过分析错分样本得到启发。

具体地,我们来看这个例子。假设现在我们已经搭建了一个垃圾邮件分类器,然后有一个拥有500个样本的交叉验证集。假设在这个例子中,我们的算法有非常高的误差率,它错分了100个交叉验证集中的样本。那么在这种情况下,我们需要做的事情是,人工地检查这100个错误分类,然后人工地将它们归类,这种归类并没有固定的模式,需要我们人工总结,比如这些邮件是什么类型的,然后针对它们,什么样的特征能够解决这种错分。

比如,我们检查这100个错分样本,我们发现大部分都是药品销售的广告,还有不少是卖仿品的,比如假表、假包,然后也有一些试图窃取我们密码的钓鱼邮件。所以,我们在检查这些样本并分类的时候,我们一边分类,一边对它们进行计数。比如,我们可能发现有40封是和卖药相关的,25封是关于销售仿品的,还有7封是试图窃取我们密码的钓鱼邮件。剩下的28封是其他类型的。 通过对这些类别进行计数,我们可能发现,我们的算法在针对卖药相关的邮件时,分类效果非常差,这说明我们应该花更多的时间来研究这种类型的邮件,然后看看是否能够通过构造更好的特征来正确区分这种类型的邮件。

同时,我们还要做的是,看看哪些特征可能会帮助算法正确地对这些邮件进行分类。所以假设我们有如下的一些特征来帮助算法做得更好:比如故意使用非正常字符,全角半角混用,不正常的路由,不常用的符号。那么,我们可以人工地检查这100封邮件,看看这些特征能命中多少封邮件。比如故意使用非正常字符的有5封,不正常路由的有40封,30封不常用的符号。如果我们通过交叉验证集中的错分样本得到了这样的结果,那么这可能说明故意使用非正常字符的其实没多少,不值得我们先花时间来引入这个特征。但我们发现有非常多的垃圾邮件的路由信息都不正常,那么这就是一个很强的特征,说明我们应该优先花一些时间来开发这个特征。

所以,这种类型的误差分析,其实是一种手动检测的过程,可以检查算法可能会犯的错误。这经常可以帮助我们找到更为有效的手段来提高算法的效果。这也说明了,为什么我们一开始说要先实践一种快速、简单但可能不完美的算法。我们真正想要做的,其实是想更加深入地理解我们所面对的问题,通过这种方式,我们可以有针对性地来理解我们的问题,特别是数据。这样我们可以知道这个问题到底是怎样的一个问题,已有的数据对于解决这个问题存在着什么样的障碍。所以,通过这些工作,我们就可以明确出我们通向真正目标的道路应该是怎样的了。

最后,我们要说的是,当在构造机器学习算法时,另一个有用的小窍门是,确保我们有一个数值型的指标来评估我们的学习算法。这个意思是,如果我们在构造机器学习算法时,如果我们能有一个数值型的指标来评估算法性能的话,这将是非常有用的。这意味着,每当我们对算法做了修改的时候,我们都能清楚地知道这种修改带来的变化是怎样的,是使得算法更加有效了,还是使得算法性能变差了。我们会在稍后更加详细地讨论评估指标,这里我们先看一个简单的例子。

假设说,我们试图决定是不是要将全角字符都转换成半角。全角转半角其实在文本数据处理,特别是中文文本数据处理中,是一个非常常见的功能,特别是对于unicode而言,可以用非常简单的几行代码来完成这个任务。不过,全角字符转换成半角字符是否真的能帮助算法在这个问题中提高分类效果呢?这在实际使用前是难以判断的。特别地,即使我们在误差分析中觉得可能会很有效果,但这并不是一种绝对的保证,而是一种有依据的指引。所以,最终决定是否有效的方式是,快速地将这个特征加入到算法中,然后试试看是否能够帮助算法做得更好。

所以,为了能够知道效果是否变得更好,我们就需要一个数值型的指标来评估我们的模型。那么具体而言,我们可以在交叉验证集上看看使用全角转半角和不使用它,这两种情况下的各自错分率是多少。所以,如果我们不使用全角转半角,我们的错分率假如说是10%,然后我们使用全角转半角,再次运行,发现再交叉验证集上的错分率下降到了5%。那么这就说明,全角转半角对我们的这个应用非常有效。所以,对于这个小例子,我们使用了错分率这么一个单一的数值化指标来衡量算法的性能。

我们后面会发现,这个例子中的评估指标有时候还需要做一些处理才能发挥真正的衡量作用。

所以,当我们在开发一个机器学习算法的时候,我们总是会尝试很多各种新想法,实现很多版本的学习算法。如果每一次,我们都手动检查样本是否表现得好还是坏的话,那么这很难让我们决定是否应该做这样的改变。但是,通过一个数值化的指标,我们可以仅仅看看这个数字,来判断算法的效果变好了还是变差了。这样我们就可以快速地实验各种想法,它可以非常直观快速地告诉我们这些想法是否有效。

所以,我们非常推荐在交叉验证集上进行误差分析,不过有些人还是会在测试集上做这种误差分析。因为在数学上,在测试集上做误差分析并不是那么严格有效。所以,大家在实践的时候尽量应该在交叉验证集上做这种误差分析。

最后,我们稍微总结一下。在开始处理一个新的机器学习问题时,我们总是建议,首先快速实现一个较为简单的算法,而不是一开始就花很长时间来决定应该采用什么样的算法。那么当实现这个简单算法以后,它将会成为一个非常有力的工具来帮助我们决定下一步应该要做些什么。因为我们可以看看算法造成的错误,通过误差分析,来看看算法都犯了什么样的错误,然后决定优化方法。另一件事情是,假设我们有了个快速实现的算法,又设定了一个数值化的评估指标,那么这就会帮助我们有效地尝试各种新的想法,并决定留下什么、放弃什么。

Handling Skewed Data[处理有偏数据]

Error Metrics for Skewed Classes[有偏类别的误差指标]

前面我们讨论了怎么进行误差分析,同时也讨论了设定误差衡量指标的重要性,那就是设定单个数值化的衡量指标来评估我们的学习算法,可以帮助我们很好地进行算法的迭代。

不过有时候,我们对于选择什么样的指标来衡量学习算法是需要细致考虑的。因为它可能会对我们的工作造成非常微妙的影响。这种时候一般都是遇到了“有偏数据”。

考虑之前癌症分类的问题。我们有病人的特征数据,我们希望对他们进行诊断,看看他们是否真的患有癌症。所以这非常类似我们之前讨论过的恶性肿瘤和良性肿瘤的分类问题。那么,我们假设y=1表示病人患有癌症,y=0表示病人没有癌症。我们训练一个逻辑回归模型,假设我们在测试集上的错分率仅有1%。也就是说我们的诊断99%都是正确的。这看上去是个非常不错的结果,因为我们99%的情况下都给出了正确的诊断。但是,假如我们发现在测试集中,仅有0.5%的人真的患有癌症。那么在这种情况下,1%的诊断错误率就显得不是那么好了。举个例子,我们在诊断时,压根不考虑病人的具体情况,一律认为病人不患有癌症,那么这仅仅需要一行代码,甚至都不是机器学习,那么这个分类器或者说诊断器的错分率就仅有0.5%!因此,这么看它甚至优于前面训练的逻辑回归,因为逻辑回归的错分率是1%。

这种情况一般都是因为,某一类本身出现的概率就非常小,整个数据集表现出类别分布极不均匀的情况。这种情况,被称为“类别有偏”(skewed classes)。

所以,单纯使用错分率来作为算法的性能评估指标,就会产生这样的问题。假设,我们实现算法的准确率是99.5%,也就是0.5%的错分率。我们在对算法进行了一些修改后,我们得到了99.8%的准确率,也就是0.2%的错分率。那么这个修改是不是对算法的一个提升呢?逻辑上,我们使用单一的数值化的评估指标可以快速的帮助我们确定对算法的修改是否有效。但是,当我们遇到类别有偏的情况时,我们这种评估其实就有漏洞,因为这个指标对于直接认为所有分类都是y=0或者y=1的情况具有非常高的评估。所以,对于类别有偏的情况,只使用单一的数值指标并不能很好地衡量算法的性能。

所以,当我们遇到类别有偏的情况时,我们需要一种不同的评估方案来对算法的性能进行评估。

在业界,常常使用的一种评估方案是,使用准确率和召回率来进行评估。我们来看看它们分别是什么意思。

假设我们正在测试集来评估一个二分类模型。那么,对于测试集中的样本真实标签,要么是0,要么是1。而我们的学习算法做的是,对于测试样本进行预测,预测的值也是0或者1。所以基于这些值,我们可以画一个2*2的表格。 这些格子对应不同的情况。比如,过有一个样本它实际的分类是1,学习算法预测的标签也是1,那么我们就称它是真正的,或者True Positive。这里Positive表示是正类,也就是预测的类别标签是1,而True表示的是这个预测是正确的。而如果我们的算法预测某个样本是负类,也就是类别标签是0,而它真实的类别标签也是0,那么我们就成这种是真负的,或者True Negative。这里的Negative表示的是负类,也就是预测类别标签是0,而True表示的是这个预测是正确的。

那么,如果我们的算法预测一个样本的类别标签是1,也就是positive正类,但是它真实的标签是0,这就意味着算法预测是错误的,因此我们不能再使用True了,而是使用False来表示算法的预测是错误的,因此这种情况可以称为False Positive,也就是假正。相应的,如果算法预测一个样本的类别标签是0,也就是negative负类,但是它的真实标签是1,那么算法的预测就是错的,所以也使用False来表达。因此,这种情况被称为False Negative,也叫假负。

很多人对True Positive, True Negative, False Positive以及False Negative的记忆有障碍。这也难怪,因为如果你不知道这中命名的规则,单纯依赖记忆的话,确实容易混淆。不过一旦理解它的命名规则,就很容易理解它们各自到底是什么意思。True和False表达的是,算法预测是否正确,而后面的Positive和Negative则表达的是算法把样本预测成了正类,也就是y=1还是预测成了负类,对应y=0. 所以,知道了这个规则,我们就可以清楚地理解这四者到底是什么意思,比如”True Negative”,True表示算法预测的正确的,Negative表示的是算法预测样本是个负类,也就是y=0,所以它表示算法预测y=0是正确的情况。

好了,基于这个2*2的表格,我们就可以定义出两个新的指标来评估算法的性能了。第一个指标叫准确率,它的含义是,对于我们所有预测患有癌症的病人中,有多大的比例是真的患有癌症。所以,它的计算方法就是。这就是准确率,所以准确率越高当然越好。

另一个我们要计算的数字叫做召回率。召回率的意思是,确实患有癌症的病人中,我们的算法成功地将它们确诊的比例是多少。

所以,通过准确率和召回率,我们可以更加清晰地判断算法是否工作地好。比如说,如果有个算法总是预测y=0,也就是说它总是预测没人患有癌症,那么这个分类器的召回率就是0,因为它不会有任何的True Positive存在。所以,我们就可以快速地了解到这个分类器其实在作弊,它总是预测没人有患有癌症。因此,它并不是一个好模型。

所以,总的来说,即使我们面对一个非常有偏类别地情况,算法也没办法作弊了,仅仅通过利用有偏类别的情况来蒙蔽准确率这个指标不再奏效了。所以我们就更加能够肯定,拥有高准确率和高召回率的分类算法才是好的分类算法。这就给了我们更好的对模型性能评估的指标。

最后一点要说一下,我们在定义准确率和召回率的时候使用的是y=1这种少数类,因为这种极度稀疏的分类才是我们真正关心的。
不过有两个评估指标,那么就必然会有一种情况,比如两个模型,一个模型的准确率高,而另一个模型的召回率高,这种情况又该怎么比较呢?。

Trading Off Precision and Recall[权衡精确和召回]

前面我们说到,可以使用准确率率和召回率来作为模型的评估指标。

不过我们也提到,在很多场景下,不同的模型可能不存在同时在准确率和召回率上都表现的极其优异。这里我们将要更加细致地讨论下它们二者的权衡,以及如何将二者结合起来形成一个独立的数值指标来衡量模型的效果。

我们首先回忆一下,这是准确率和召回率的定义。让我们继续使用癌症分类的例子,其中y=1表示病人患有癌症,反之y=0表示病人没有癌症。假设我们使用逻辑回归训练了一个模型,那么它的输出就介于0到1. 那么,根据惯例,当hθx大于等于0.5的时候,我们预测y=1. 而当hθx小于0.5的时候,我们预测y=0. 对于这个分类器,我们可以计算它的准确率和召回率。 但现在假如我们希望仅在有足够把握的情况下才预测y=1,也就病人患有癌症,因为如果你告诉一个病人他患有癌症,它们会非常震惊,甚至会造成心理上的疾病,因为这是一个极其不好的消息。因为,我们希望在有足够把握的情况下才对病人进行癌症确诊。那么想要达到这种效果,一种做法是,修改我们的算法,我们不再将临界值设为0.5,也许我们把它设置成0.7。所以这就是说,只有当算法预测的概率超过0.7的时候,我们才做诊断。因此,如果我们这么做了,那么我们只会在非常确信的情况下才预测病人患有癌症。这样,我们就使得我们的算法可以具有更高的准确率。但另一方面,我们的这个模型会有较低的召回率,因为当我们做诊断的时候,我们只给很小一部分的病人预测y=1.

现在我们再来考虑另一种情况,假设现在我们想避免遗漏掉患有癌症的病人,也就是我们想避免漏诊。具体地讲,如果一个病人确实患有癌症,但我们没有诊断出来,那么这可能会造成非常严重的后果。因为如果我们告诉病人它们没有患癌,那么它们就不会接受治疗,这就可能会造成很严重的后果,可能会造成病人丧失生命。那么在这种情况下,我们希望预测y=1,这样至少它们会接受进一步的检查,然后接受治疗,避免漏诊带来的严重后果。那么,针对这种场景,我们就不能再把临界值设高了,我们就可能把临界值设置的稍微低一些,比如0.3。这样做以后,我们认为,只要病人有30%以上的概率患有癌症,那么我们就可能以更加含蓄、保守的方式告诉它们它们可能患有癌症,这样它们就可以接受治疗。所以,这种情况下,我们将会得到了一个高召回率的模型,但显然找这个模型的准确率将会低一些。

很多人可能会想,那么我们不能得到一个同时拥有很高的准确率和很高的召回率的模型么?这其实是业界正在努力的方向,但在实际中确实存在这种此消彼长的情况,需要在准确率和召回率之间进行权衡。所以,对于逻辑回归模型而言,通常情况下在准确率和召回率之间进行权衡的方式就是控制进行判断的阈值,也就是我们这里的threshold。

所以,准确率和召回率通常需要进行权衡,而这又取决于我们的具体应用,有时候我们需要高准确率,可以容忍稍低一些的召回率,但另外一些时候我们又需要较高的召回率,对准确率可以稍微容忍一些。

那么,当我们权衡准确率和召回率的时候,我们通过修改参数,比如这里的阈值threshold,我们可以画出上图这样的准确率和召回率之间的关系图。比如[图中0.99]这个点,可能就对应阈值是0.99,也就是说在具有非常高的可能性的时候我们才预测y=1,这样我们的准确率就会非常高,但是相对的,我们的召回率可能就会很低。而这里[图中0.01],可能对应着阈值0.01,这意味着只要有一点可能性,我们就预测y=1,这样就会表现出很低的准确率,但召回率显然会很高。所以,通过调整阈值threshold,我们就可以得到不同的准确率和召回率。

顺便提一下,这个准确率召回率曲线可能会有各种形状,不一定就长成这样。可能会[粉线]长成这样,也可能会是这样[红线]。这取决于模型的具体算法。

那么这就又产生出了一个有意思的问题,那就是有没有办法自动的来选择阈值threshold呢?

那么,更加一般地讲,如果我们多个不同的模型,我们如何比较不同的准确率和召回率呢?比如我们这里有3个算法,我们如何决定哪一个算法最好呢?

之前我们讨论过,使用一个单一的数值型评估指标是多么重要的一件事情,它说,我们应该通过一个具体的数字来反映我们的模型到底性能如何。但是现在我们有两个数值指标:准确率和召回率,所以我们经常会遇到这样的情况:如果我们试图比较算法1和算法2,那么我们最终可能会问自己,到底是准确率0.5,召回率0.4的模型好呢,还是0.7的准确率和0.1的召回率好呢?如果每次修改算法,我们都需要坐下来思考到底是哪种好,那么这会导致我们迭代的效率大大下降,因为我们需要花费大量的时间来思考到底应该怎么做。

相反,如果我们有一个唯一的评估指标,能告诉我们到底是算法1好还是算法2好的话,这就能帮助我们更快地进行决策,提高迭代的效率。那么,我们怎样才能得到一个单一的评估指标呢?一个很简单直觉的想法是,计算一下准确率和召回率的平均值,然后看看哪个模型的平均值最高,但这可能并不是一个好的评估方式,因为类似我们之前的例子,如果我们的模型总是预测y=1,那么我们可以得到非常高的召回率,但会得到极低准确率,相反的,如果我们的模型总是预测y=0的话,那么相当于我们设定了很高的一个阈值,我们会得到一个很高的准确率但非常低的召回率的模型,所以这两种极端情况都不是一个好的模型。但是如果我们按照平均值来计算的话,我们会发现这种极端情况对应的均值还是会挺高的,比如我们这里的算法3. 所以,实际上算法1和算法2相较于算法3更加有用,但如果按照平均值来计算的话,我们会发现算法3的评估指标更高。因此我们通常认为准确率和召回率的均值并不是一个好的衡量指标。

不过,还有一种结合准确率和召回率的不同方式,叫做F1值,计算方法如这个式子。通过计算F1值,我们可以看到算法1具有最高的评估值,算法2其次,算法3最差。因此,我们可能会选择算法1. 我们来看下F1值的计算逻辑。我们看到它的分子是准确率乘以召回率,因此如果他们中的任何一个是0,那么F1值也会是0,因此它结合了准确率和召回率,对于一个较大的F1值,需要准确率和召回率都比较大。

而实际上有非常多的其他方式来结合召回率和准确率,F1值只是其中一种,但是由于历史原因,人们在机器学习中惯用这个方式来结合准确率和召回率,并以此作为模型性能的一种度量方式。另外,这个名字F1值,本身命名没有什么特殊的含义。

所以,F1值给了我们一种同时考虑准确率和召回率的方案,如果P=0或者R=0,那么F1值也是0,而最理想的F1值是,准确率是1的同时召回率也是1,这样,F1值就也是1了。所以,通过F1值,我们就又有了唯一的衡量指标。

所以,以上就是我们讨论的关于如何权衡准确和召回,以及如何使用阈值来控制想要达到的目的,最后我们也讨论了怎么将准确率和召回率融合成F1值来作为唯一的衡量模型性能的数值指标。这样,我们就对整个机器学习工作有了全面的、概括式的认识了。实际上,到这里为止,大家应该具备了基本的使用机器学习解决实际问题的能力,能够了解机器学习工程师在应用机器学习算法解决问题时的整体工作框架。

Using Large Data Sets[使用大数据集]

Data for Machine Learning[机器学习的数据]

前面我们讨论了构建一个机器学习系统要使用的一些技巧和方法论。

这里我们要继续讨论一下机器学习所使用的数据,比如应当需要多少数据来进行学习。

在前面的课程里,我们曾经说过不要盲目地去花费大量的时间去收集样本数据,因为更多的数据并不意味着更好的模型效果。不过在某些条件下,大量的样本数据可能是唯一有效的,能够提升模型效果的手段。实际上,在一些情况下,使用海量的数据可以训练出性能极佳的模型。那么,让我们来看看数据到底意味着什么。

让我们先从一个故事开始,2001年的时候,有两位研究员进行了一项研究,它们的研究内容是,使用不同的算法以及使用同样的算法在不同量级训练数据集上的效果差异。它们当时考虑的一个问题是,如何在容易混淆的词之间进行分类。比如在这个句子中,早餐我吃了__鸡蛋,应该是to,还是two,还是too呢?比如这里我们应该使用two。所以他们把这个问题作为一个监督学习的例子,来预测应该填哪一个词。他们使用了几种不同的学习算法,这些都是在当时已经被公认比较领先的。他们用了一种逻辑回归的变体,被称为感知机的算法;也用了当时很领先但现在已经不怎么使用了的算法,比如winnow算法,基于内存的一种算法,以及朴素贝叶斯。这些算法的细节实际上并不重要,甚至这个具体的分类问题都不是那么重要。我们可以理解成,一个监督学习问题,然后有一系列候选算法,而这个监督学习问题具体是什么,候选算法又是什么,这些其实都不重要。他们的研究所做的是,不断地改变训练数据集的大小,并将这些学习算法用于不同大小的训练集,右图就是他们得到的结果。

这里的趋势非常明显,首先,这些算法都具有类似的性能;其次,随着训练集的增长,从十万到10亿,这些算法的性能也在不断地增长。所以事实上,如果随便选择一个算法,即使选择了一个看上去”不怎么先进”的算法,但如果给这个算法更多的数据,那么从这个例子中看起来的话,它看上去很有可能会比其他算法的性能更优,甚至会超过最先进的算法。

所以,根据这项研究以及很多类似的研究,我们发现,如果我们能够给与一个算法大量的训练数据,我们就能获得相当不错的模型性能。类似这种研究,引起来一种呼声,那就是:“算法虽好,数据决胜”。

那么,在什么情况下,越多的数据意味着越好的性能呢?因为一旦确定了这种情况,我们就不需要纠结到底应该使用哪种具体的学习算法,而只需要专注于收集更多的训练数据就行了。

假如,我们的样本特征x包含了足够多的信息,而这些信息可以帮助我们准确地预测y。

假如说,这个问题中的特征能够准确地记住词周围的信息,那么在这种情况下,我们就可以很清楚地知道这里应该填two,而不是to,too。所以,词周围出现的其他词这个信息就可以准确地帮我们判断一个填空中应该填什么样子的词,特别是对于易混淆的这种词而言就更加容易。所以,这是一个拥有足够信息量的特征例子。

那么一个反例是,设想我们之前讨论了很多次的房价预测的例子。我们在之前的课程中很多时候仅仅使用了房子的面积,而不考虑其他特征。因此,如果别人告诉我们一所房子的面积是100平米,而没有告知其他任何信息的话,这样我们就不知道这个房子是不是位于城市房价比较昂贵的区域,我们也不知道这所房子有几间卧室,更不知道它是否有装修,装修效果如何。而实际上,一所房子的价格,显然不仅仅跟其面积相关,很多其他的因素都会影响房子的价格。所以,如果仅仅只知道房子的面积,我们是很难预测它的价格的。所以,这是一个关于拥有足够信息量特征的反例。

那么在实际应用中,我们怎么判断特征是否拥有足够的信息量来进行准确的预测呢?这其实并不是很难,一种有效的方法是,对于给定的输入特征,一个人类专家是否可以自信地对y进行预测呢?

第一个例子,如果我们找到一个会说英语的人类,那么这个人可能就可以预测出在这种情况下,应该使用什么样的词。那么这样,我们就可以很有信心的认为,这里的特征足以让我们准确的预测y。

不过与此相反的是,如果我们找到一个非常资深的房产中介,或者房地产从业人员,我们如果只告诉它房子的面积,并且不透露其他任何信息,那么我们可以想象,他也无法准确地对房子进行估价。所以,在房屋价格预测的例子中,仅仅知道房屋的面积,并不能获得足够的信息来对房价进行估计。

所以,如果最上面这个假设是正确的话。那么,我们拥有大量的数据时,是很有帮助的。

假设,我们的特征具有足够的信息量来进行预测。那么假设我们使用一种需要大量参数的学习算法,所以也许是有需要特征的逻辑回归或者线性回归,也可能是具有非常多隐层节点的神经网络。这些都是强大的学习算法,他们有许多的参数,这使得他们可以拟合复杂的函数,因此我们可以说这些算法都是低bias的算法,因为他们可以拟合非常复杂的函数。而且因为我们有非常强大的机器学习算法,这些学习算法能够拟合非常复杂的函数,所以如果我们在训练集上运行这些算法,他们很可能在训练集上效果非常好,所以训练误差可能就非常小。那么现在我们假设,我们有非常非常大的训练集,在这种情况下,那么尽管我们希望有很多参数,但是如果训练集比参数的数量还要大很多的话,那么这些算法就不太会出现过拟合,因为我们拥有如此巨大的训练集,并且不太会过拟合,也就是说训练误差和测试误差很接近。最后,把二者结合在一起,如果训练误差很小,而且测试误差和训练误差接近,那么这两者就意味着,测试集误差也会很小。

另一种思考这个问题的方式是,为了有一个高性能的学习算法,我们希望它不要有高bias和高variance的情况。因此bias问题,我们将通过确保有一个具有很多参数的学习算法来保证,以便我们可以得到一个较低bias的算法。并且通过用一个非常大的训练集来保证我们这里不会有高variance的问题。那么我们的算法将没有variance问题。这样,我们把这两者结合在一起,我们最终会得到一个低bias、低variance的学习算法,这使得我们能够很好的在测试集上进行预测。

从根本上来讲,“特征具有足够的信息量” 是一个关键假设,它能够确保我们可以得到一个低bias的算法模型。而拥有海量的训练数据则能保证我们得到一个低variance的模型。

所以,一般而言,我们在做一个机器学习工作的时候,我们首先要确认,我们的特征是否能够让人类专家足以自信地对y进行预测,这能够保证我们最终得到的模型的bias不会高;其次,我们是否拥有足够量的数据以用于训练,这能够保证我们的模型不会出现高variance的情况,也就是泛化能力不会差。

所以,这些就是关于机器学习系统设计的一些指导方案。

这些其实大部分都是方法论上的,不太是像我们之前学习具体算法时的内容,我们没有讲什么模型,也没有进行数学推导,但是这些内容确实对于进行机器学习工作具有非常重要的指导意义。

因此,希望这些内容能够帮助大家在实际的工作中,不会没有目标,能够有切实可行的路线去迭代算法,并最终得到能够解决实际问题的机器学习应用。

关于机器学习系统设计的一些思路相关推荐

  1. Coursera公开课笔记: 斯坦福大学机器学习第十一课“机器学习系统设计(Machine learning system design)”

    Coursera公开课笔记: 斯坦福大学机器学习第十一课"机器学习系统设计(Machine learning system design)" 斯坦福大学机器学习斯坦福大学机器学习第 ...

  2. 机器学习系统设计:Python 语言实现

    内容简介 机器学习模型不能给出准确结果的原因有很多.从设计的角度来审视这些系统,我们能够深入理解其底层算法和可用的优化方法.本书为我们提供了机器学习设计过程的坚实基础,能够使我们为特定问题建立起定制的 ...

  3. 斯坦福CS329S:机器学习系统设计,课程、笔记上线了!

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:蛋酱,来源:机器之心 这是一门新的课程--在学习了算法.框架等内容 ...

  4. 机器学习系列16:机器学习系统设计

    https://www.toutiao.com/a6700782123118232068/ 机器学习系列16:机器学习系统设计 偏斜分类的误差评估 举个例子,我们想训练一个模型去诊断患者是否患有癌症. ...

  5. 第十一章 机器学习系统设计-机器学习老师板书-斯坦福吴恩达教授

    第十一章 机器学习系统设计 11.1 确定执行的优先级:垃圾邮件分类例子 11.2 误差分析 11.3 不对称分类的误差评估 11.4 精准率和召回率的权衡 11.5 机器学习数据 11.1 确定执行 ...

  6. 4.4 机器学习系统设计--垃圾邮件分类-机器学习笔记-斯坦福吴恩达教授

    机器学习系统设计–垃圾邮件分类 假定我们现有一封邮件,其内容如下: From: cheapsales@buystufffromme.com To: ang@cs.stanford.edu Subjec ...

  7. 回归素材(part6)--机器学习系统设计

    学习笔记,仅供参考,有错必纠 文章目录 机器学习系统设计 最小二乘法 梯度下降 正规方程法 机器学习系统设计 最小二乘法 梯度下降

  8. 机器学习08机器学习系统设计

    首先要做什么 一个垃圾邮件分类器算法为例: 为了解决这样一个问题,首先要做的决定是如何选择并表达特征向量 x. 可以选择一个由 100 个最常出现在垃圾邮件中的词所构成的列表,根据这些词是否有在邮件中 ...

  9. 吴恩达机器学习 9.机器学习系统设计

    一.首先要做什么 今天讨论机器学习系统的设计.将谈及在设计复杂的机器学习系统时,你将遇到的主要问题.同时我们会试着给出一些关于如何巧妙构建一个复杂的机器学习系统的建议 本周以一个垃圾邮件分类器算法为例 ...

最新文章

  1. Martin Davis最新访谈:机器学习是一个收敛的过程,背后理论并不高深
  2. linux5.4iso,Redhat Linux5.4/5.5/5.8/6.0/6.3 ISO镜像文件下载
  3. LTE 中的RV版本
  4. 动手学PaddlePaddle(3):猫脸识别
  5. 小程序 array.map_Array.map解释了4个复杂级别:从5岁到功能程序员。
  6. Spring AOP技术(基于AspectJ)的Annotation开发
  7. 唐山师范学院计算机科学与技术地址,2021年唐山师范学院有几个校区,大一新生在哪个校区...
  8. 在Linux上安装MySql
  9. 责任心来自爱而不是债
  10. nginx css 304 导致图片丢失_Nginx面试三连问:如何工作?负载均衡策略有哪些?如何限流?...
  11. 《自然语言处理简明教程》读书笔记:前言
  12. SAP UI5 在 PC 端浏览器和移动设备使用摄像头进行条形码扫描的几种解决方案介绍
  13. 升级mojave后辅助功能空白无法
  14. 前缀后缀表达式 表达式X=A+B*(C-D)/E+F的后缀表示形式可以为( )
  15. 全民一起玩Python提高篇第十二课:面向对象基本原理与语法(三)
  16. Netlogon 特权提升漏洞(CVE-2020-1472)原理分析与验证
  17. 第一篇 厚黑学 二、厚黑学
  18. 2021年全球与中国汽车ABS和ESC行业市场规模及发展前景分析
  19. k8s查看pod的yaml文件_k8s yaml文件说明
  20. ERR_HTTP2_PROTOCOL_ERROR分析

热门文章

  1. 有时,你需要宣扬你的野心
  2. 证明:旋转矩阵是正交矩阵
  3. 从搬砖工到亿万富豪,这些年他经历了什么?
  4. 遇到Python嵌套不要怕,你足够认真,它就是纸老虎(14)
  5. 炫酷 RGB 之.NET nanoFramework 点灯大师
  6. 人,确实有无限的潜力!
  7. YouTube-8M 数据集简介
  8. 编写一个带有main函数的类,调用上面的汽车类,实例化奔驰、大众、丰田等不同品牌和型号,模拟开车过程:启动、加速、转弯、刹车、息火,实时显示速度。...
  9. 互联网+时代,是更加开放还是封闭
  10. 狮子鱼社区团购系统CMS任意文件2处上传漏洞