现实世界的机器学习-全-
现实世界的机器学习(全)
原文:Real-World Machine Learning
译者:飞龙
第一部分. 机器学习工作流程
在本书的第一部分,我们介绍了基本的机器学习工作流程。每一章都涵盖工作流程的一个步骤。
第一章介绍了机器学习,它的用途以及为什么你应该阅读这本书。
在第二章中,你将深入了解基本机器学习工作流程中的数据处理步骤。你将了解从现实世界和杂乱数据中清理和提取价值的一些常见方法。
在第三章中,当你学习一些建模算法及其在常见实现中的应用时,你将开始构建简单的机器学习模型。
在第四章中,你将更深入地了解我们的机器学习模型,以评估和优化其性能。
第五章专门介绍基本特征工程。从数据中提取特征可能是构建和优化机器学习系统性能的一个极其重要的部分。
第一章. 什么是机器学习?
本章涵盖
-
机器学习基础知识
-
机器学习相较于传统方法的优点
-
基本机器学习工作流程概述
-
提高模型性能的高级方法概述
1959 年,一名名叫亚瑟·萨缪尔的 IBM 计算机科学家编写了一个程序来玩跳棋。每个棋盘位置都根据其赢得比赛的可能性分配一个分数。最初,分数是基于一个使用诸如每一边的棋子数量和王的数量等因素的公式的。它起作用了,但萨缪尔有一个关于如何提高其性能的想法。他让程序与自己玩成千上万场比赛,并使用结果来细化位置评分。到 20 世纪 70 年代中期,该程序已经达到了可敬的业余选手的水平。1
¹
约翰·施瓦茨,一步之先:国际象棋的计算机完美(纽约:斯普林格,2009)。
萨缪尔编写了一个能够通过经验提高自身性能的计算机程序。它学习了——机器学习(ML)诞生了。
这本书的目的不是描述机器学习算法的数学细节(尽管我们将剥去洋葱的一层,以提供对最常见算法内部工作原理的洞察)。相反,本书的主要目的是指导非专业人士在将机器学习集成到现实世界应用和数据管道时的重要方面和常见挑战。在本章中,我们提出一个真实的企业问题——审查贷款申请,以展示使用机器学习相较于一些最常见替代方案的优点。
1.1. 理解机器学习是如何学习的
当我们谈论人类学习时,我们区分了死记硬背或记忆和真正的智慧。记住电话号码或一系列指令无疑是学习。但当我们说学习时,我们通常意味着更多的事情。
当孩子们在群体中玩耍时,他们会观察他人如何回应他们的行为。他们的未来社交行为将受到这种经验的影响。但他们不会重放和回放过去的经历。相反,他们互动中的一些可识别特征——操场、教室、妈妈、爸爸、兄弟姐妹、朋友、陌生人、成人、儿童、室内、室外——提供了线索。他们会根据新情况与过去情况共有的特征来评估每个新情况。他们的学习不仅仅是积累知识。他们正在构建可能被称为洞察力的东西。
想象一下通过使用闪卡教孩子区分狗和猫。你出示一张卡片,孩子做出选择,然后你将卡片放入两个堆叠中,分别代表正确和错误的选择。随着孩子的练习,他的表现会提高。有趣的是,没有必要首先教孩子猫和狗识别的技术。人类的认知具有内置的分类机制。所需的一切只是例子。在孩子熟练掌握闪卡后,他不仅能够分类闪卡上的图像,还能分类大多数猫或狗的图像,更不用说真实的事物了。这种概括的能力,即将通过训练获得的知识应用于新的未见过的例子,是人类和机器学习的关键特征。
当然,人类的学习比最先进的机器学习算法还要复杂得多,但计算机在记忆、回忆和处理数据方面具有更大的优势。他们的经验以历史数据的形式出现,这些数据通过本书中描述的技术进行处理,通过经验创造和优化,至少能够体现概括的能力,即使不是真正的洞察力。
人类学习和机器学习之间的类比自然让人想到术语人工智能(AI)以及一个明显的问题:“人工智能和机器学习有什么区别?”关于这个问题,并没有明确的共识,但大多数人(并非所有人)都同意机器学习是人工智能的一种形式,而人工智能是一个更广泛的主题,包括诸如机器人技术、语言处理和计算机视觉系统等领域。为了进一步增加这种模糊性,机器学习正在越来越多地应用于这些相邻的人工智能领域。我们可以这样说,机器学习学科指的是一个特定的知识体系及其相关的一套技术。对于什么是机器学习,什么不是机器学习,这一点相当清楚,而对于人工智能来说,情况则并非总是如此。用 Tom Mitchell 经常引用的定义来转述,如果一个计算机程序在执行某个任务时,其表现(通过可计算的分数来衡量)随着经验的积累而提高,那么我们就说这个程序是学习的。^([[2])
²
Tom Mitchell, Machine Learning (McGraw Hill, 1997), 2. “如果一个计算机程序在基于经验 E 对某些任务 T 和性能度量 P 的情况下,其 T 中任务的性能(通过 P 来衡量)随着经验 E 的积累而提高,那么我们就说这个程序从经验 E 中学习。”
Kaggle,一家机器学习咨询公司,举办了一场比赛,寻找最准确的用于分类图像是否描绘了狗或猫的程序。^([[3]) 竞赛者获得了 25,000 个示例图像用于训练。每个图像都被标记以指示所描绘的物种。在所有竞争者训练了他们的算法之后,他们被测试了在区分 12,500 个未标记测试图像的能力。
³
请参阅“狗与猫”比赛,www.kaggle.com/c/dogs-vs-cats。
当我们向人们解释 Kaggle 比赛时,他们通常会通过反思可能应用于完成狗和猫识别的规则来回应。猫的耳朵是三角形的,竖立着;狗的耳朵是松垂的——但并非总是如此。试着想象一下,如果你要向一个从未见过狗或猫的人解释如何区分它们,而又不能展示任何例子,你会怎么解释。
人们使用各种方法,包括形状、颜色、质地、比例和其他特征,从例子中学习和归纳。机器学习也采用各种策略,根据手头的问题以不同的组合方式应用。
这些策略体现在近几十年来统计学、计算机科学、机器人学、应用数学等学科领域的学者和实践者开发的算法集合中,这些算法应用于在线搜索、娱乐、数字广告和语言翻译等领域。它们种类繁多,各有优缺点。其中一些是分类器。其他一些预测数值测量。还有一些测量可比实体(例如,人、机器、流程、猫、狗)的相似性或差异性。这些算法的共同之处在于从例子(经验)中学习,以及将所学知识应用于新的、未见过的案例——即泛化的能力。
在猫狗竞赛中,在学习阶段,参赛者的程序反复尝试使用许多算法进行正确的分类。在学习过程的数百万次迭代中,程序执行分类,衡量结果,然后对过程进行微调,寻找增量改进。获胜者正确分类了 98.914%的未见测试图像。考虑到人类错误率大约为 7%,这相当不错。图 1.1 说明了这个过程。机器学习过程分析标记图像,并构建一个模型,该模型随后被召回(预测)过程用于对未标记图像进行分类。示例中有一个被错误标记的猫。
图 1.1. 猫狗竞赛的机器学习过程

请注意,我们在这里描述的是监督机器学习,它不是唯一类型的 ML。我们将在后面讨论其他类型。
机器学习可以应用于广泛的商业问题,从欺诈检测到客户定位和产品推荐,再到实时工业监控、情感分析和医疗诊断。它可以处理由于必须处理的大量数据而无法手动管理的问题。当应用于大型数据集时,ML 有时可以发现如此微妙的关联,以至于任何数量的手动审查都无法发现。而且当许多这样的“弱”关系结合在一起时,它们就变成了强大的预测者。
从数据中学习的过程,以及随后使用所获得的知识来指导未来决策,是非常强大的。确实,机器学习正在迅速成为推动现代数据驱动经济的引擎。
表 1.1 描述了广泛使用的监督机器学习技术和它们的一些实际应用。这不是一个详尽的列表,因为潜在的使用案例可能跨越几页。
表 1.1. 按问题类型组织的监督机器学习用例
| 问题 | 描述 | 示例用例 |
|---|---|---|
| 分类 | 根据输入数据确定每个个体所属的离散类别 | 邮件过滤、情感分析、欺诈检测、客户广告定位、客户流失预测、支持案例标记、内容个性化、制造缺陷检测、客户细分、事件发现、基因组学、药物有效性 |
| 回归 | 根据输入数据预测每个个体的实值输出 | 股票市场预测、需求预测、价格估计、广告出价优化、风险管理、资产管理、天气预报、体育预测 |
| 推荐系统 | 预测用户可能偏好的替代方案 | 产品推荐、招聘、Netflix Prize、在线约会、内容推荐 |
| 填充 | 推断缺失输入数据的值 | 不完整的患者医疗记录、缺失的客户数据、人口普查数据 |
1.2. 利用数据做出决策
在以下示例中,我们将描述一个可以从机器学习方法中受益的现实世界商业问题。我们将逐一介绍常用的各种替代方案,并展示机器学习方法的优势。
想象一下,你是一家微型贷款公司的负责人,该公司为想在困难社区开展小型生意的个人提供贷款。一开始,公司每周只收到几份申请,你能在几天内手动阅读每一份申请,并对每位申请者进行必要的背景调查,以决定是否批准每项贷款申请。这个过程的结构图显示在图 1.2 中。你的早期借款人对你的快速处理时间和个性化服务感到满意。你公司的名声开始传播。
图 1.2. 微型贷款示例的贷款审批流程

随着你的公司继续获得人气,申请者的数量开始增加。很快,你每周就会收到数百份申请。你试图通过加班来跟上申请数量的增加,但申请的积压仍在继续增长。一些申请者因为等待而感到疲惫,并从你的竞争对手那里寻求贷款。对你来说,显然,手动处理每一份申请并不是一个可持续的商业流程,而且坦白说,这也不值得承受压力。
那么,你应该怎么做呢?在本节中,你将探索几种扩大你的应用程序审核流程的方法,以满足你不断增长的业务需求。
1.2.1. 传统方法
让我们探讨两种应用于申请审核流程的传统数据分析方法:手动分析和业务规则。对于每种方法,我们将介绍实施技术的过程,并强调它在帮助你构建可扩展业务方面的不足。
聘请更多分析师
你决定再雇佣另一位分析师来帮助你。你并不喜欢将一部分利润用于新员工的费用,但有了第二个人来审核申请,你可以在相同的时间内处理大约两倍数量的申请。这位新分析师让你能够在一周内清理掉申请积压。
在最初的几周里,你和你的同事都加班加点以满足需求。然而,申请的数量仍在增长,一个月内翻倍,每周达到 1,000 份。为了跟上这种增长的需求,你现在必须再雇佣两名分析师。展望未来,你确定这种雇佣模式是不可持续的:所有来自新贷款申请人的增加收入都直接用于新员工,而不是更关键的领域,如你的小额贷款基金。随着需求的增加而雇佣更多分析师阻碍了你的业务增长。此外,你发现招聘过程漫长且昂贵,消耗了你的更多收入。最后,每位新员工的经验都比上一任少,处理申请的速度也慢,管理一个团队的个人压力也在消耗你的精力。
除了增加成本这一明显的缺点外,人们在决策过程中都会带来各种各样的有意识和无意识偏见。为了确保一致性,你可能会为审批流程制定详细的指南,并为新分析师实施广泛的培训计划,但这仍然会增加更多的成本,并且可能无法消除偏见。
使用业务规则
想象一下,在 1,000 笔还款日期已过的贷款中,有 70%按时还款。这显示在图 1.3 中。
图 1.3。经过几个月的业务和 2,500 笔贷款申请,有 1,000 笔获得批准,其中 700 位申请人在规定时间内偿还了贷款,另外 300 位违约。这一初步观察到的信息对于开始将自动化引入你的贷款审批流程至关重要。

现在,你开始寻找申请数据和贷款还款发生率之间的趋势。特别是,你手动搜索一组过滤规则,以产生一个主要是按时还款的“良好”贷款子集。通过手动分析数百份申请,你获得了关于什么使每份申请好或坏的广泛经验。^([4)] 通过一些自我反思和对贷款还款状态的回测,你注意到了信用背景审查数据中的几个趋势。^([5)]
⁴
你还可以使用统计相关性技术来确定哪些输入数据属性与贷款还款结果事件最强烈相关。
⁵
在这个例子中,我们使用了德国信贷数据集。你可以从
mng.bz/95r4下载这些数据。
-
大多数信用额度超过 7,500 美元的借款人未能按时偿还贷款。
-
大多数没有支票账户的借款人按时偿还了贷款。
现在你可以设计一个过滤机制,通过这两条规则减少你需要手动处理的申请数量。
你的第一个过滤器是自动拒绝任何信用额度超过 7,500 美元的申请人。通过查看你的历史数据,你发现 86 名信用额度超过 7,500 美元的申请人中有 44 人违约。这些高信用额度申请人的违约率大约为 51%,而其他人的违约率为 28%。这个过滤器似乎是一个排除高风险申请人的好方法,但你意识到只有 8.6%(1,000 名接受申请中的 86 名)的接受申请人的信用额度如此之高,这意味着你仍然需要手动处理超过 90%的申请。你需要进行更多的过滤以将这个数字降低到更易于管理的水平。
你的第二个过滤器是自动接受任何没有支票账户的申请人。这似乎是一个很好的过滤器,因为 348 名没有支票账户的 394 名(88%)申请人在规定时间内偿还了贷款。包括这个第二个过滤器,自动接受或拒绝的申请比例达到了 45%。因此,你只需要手动分析大约一半的新到申请。图 1.4 展示了这些过滤规则。
图 1.4。通过两条业务规则过滤新申请,使你能够将手动分析减少到仅占 incoming applications 的 52%。

使用这两条业务规则,你可以在不雇佣第二个分析师的情况下将业务规模扩大到原来的两倍,因为你现在只需要手动接受或拒绝 52%的新申请。此外,根据已知结果的 1,000 个申请,你预计你的过滤机制会错误地拒绝每 1,000 个申请中的 42 个(4.2%),并且错误地接受每 1,000 个申请中的 46 个(4.6%)。
随着业务的增长,你希望你的系统能够自动接受或拒绝越来越多的申请,而不会增加违约损失。为此,你再次需要添加更多的业务规则。很快你就会遇到几个问题:
-
随着过滤系统的复杂性增加,手动找到有效的过滤器变得越来越困难——如果不是不可能的话。
-
业务规则变得如此复杂和透明度低,以至于调试它们和移除旧的不相关规则几乎是不可能的。
-
你的规则构建没有统计严谨性。你相当确信可以通过更好地探索数据找到更好的“规则”,但无法确定。
-
随着还款模式随时间变化——可能是因为申请人群体发生变化——系统没有适应这些变化。为了保持最新状态,系统需要不断调整。
所有这些缺点都可以追溯到业务规则方法中的一个单一致命弱点:系统不会自动从数据中学习。
数据驱动系统,从简单的统计模型到更复杂的机器学习工作流程,可以克服这些问题。
1.2.2. 机器学习方法
最后,你决定调查一种完全自动化、数据驱动的微贷款申请审核流程。机器学习是一个有吸引力的选择,因为过程的完全自动化将使你的运营能够跟上不断增长的申请流入。此外,与业务规则不同,机器学习直接从数据中学习最佳决策,而不需要任意地硬编码决策规则。从基于规则的决策到基于机器学习的决策的转变意味着你的决策将更加准确,并且随着时间的推移,随着更多贷款的发放,将得到改进。你可以确信你的机器学习系统会产生最小人工干预的优化决策。
在机器学习中,数据为推导关于当前问题的见解提供了基础。为了确定是否接受每个新的贷款申请,机器学习使用历史训练数据来预测每个新申请的最佳行动方案。要开始使用机器学习进行贷款审批,你首先需要组装 1,000 个已批准贷款的训练数据。这些训练数据包括每个贷款申请的输入数据,以及每个贷款是否按时偿还的已知结果。输入数据反过来又包括一组特征——数值或分类指标,它们捕捉了每个申请的相关方面——例如申请人的信用评分、性别和职业。
在图 1.5 中,历史数据训练了机器学习模型。然后,随着新的贷款申请到来,从申请数据中即时生成未来还款概率的预测。
图 1.5. 微贷款示例中的基本机器学习工作流程

因此,机器学习建模确定了如何使用每个申请人的输入数据来最佳预测贷款结果。通过在训练集中找到并使用模式,机器学习产生了一个模型(现在你可以将其视为一个黑盒),根据每个新申请人的数据预测每个新申请人的结果。
下一步是选择一个要使用的机器学习算法。机器学习有多种风味,从简单的统计模型到更复杂的算法。在这里,我们比较两个例子:第一个是一个简单的参数模型,第二个是一个非参数的分类树集成。不要让术语吓到你。机器学习使用了很多算法和很多方法来分类它们,正如你很快就会看到的。
大多数传统的统计商业模型都属于第一类。这些参数模型使用简单、固定的方程来表达结果和输入之间的关系。然后使用数据来学习方程中未知项的最佳值。线性回归、逻辑回归和自回归模型等都属于这一类别。回归模型在第三章中有更详细的介绍。
在这个例子中,你可以使用逻辑回归来模拟贷款审批过程。在逻辑回归中,每笔贷款偿还的对数几率(对数几率)被模拟为输入特征的线性函数。例如,如果每个新的申请包含三个相关特征——申请人的信贷额度、教育水平和年龄——那么逻辑回归试图通过以下方程预测申请人将违约的几率(我们将称之为 y):

对数几率
概率比是表示概率的一种方式。你无疑听过有人说过一支(热门)球队获胜的几率是 3 比 1。几率是成功(例如,获胜)的概率除以失败(失败)的概率。从数学上讲,这可以表示如下:
概率比(Odds(A))= P(A) / P(~A) = A 发生的概率除以 A 不发生的概率
因此,3 比 1 的几率等同于 0.75 / 0.25 = 3,log(3) = 0.47712...
如果 A 是一个公平的抛硬币,那么正面的几率将是 0.5 / 0.5 = 1。log(1) = 0。结果发现,对数几率可以取任何实数值。接近 –∞ 的对数几率表示一个高度不可能的事件。接近 ∞ 的值表示几乎确定,而 log(1) = 0 表示一个均匀的随机变化。使用对数几率而不是常规概率是一种数学技巧,因为它不像概率那样受限于 0 和 1 之间的值。
方程中每个系数(在本例中为 β[0]、β[1]、β[2] 和 β[3])的最优值是从 1,000 个训练数据示例中学习的。
当你可以用这样的公式表达输入和输出之间的关系时,从输入(信贷额度、教育水平和年龄)预测输出(y)就变得容易了。你所要做的就是确定 β[1]、β[2] 和 β[3] 的哪些值在使用你的历史数据时能产生最佳结果。
但当输入和响应之间的关系复杂时,像逻辑回归这样的模型可能会受限。以图 1.6 左面板中的数据集为例。在这里,你有两个输入特征,任务是将每个数据点分类到两个类别之一。这两个类别在二维特征空间中由一条非线性曲线分开,称为决策边界(如图中的曲线所示)。在中间面板中,你可以看到在这个数据集上拟合逻辑回归模型的结果。逻辑回归模型提出了一条直线来分隔两个区域,导致许多分类错误(错误区域中的点)。
图 1.6。在这个二分类中,单个数据点可以属于圆形类别或方形类别。这个特定的数据位于一个具有非线性决策边界的二维特征空间中,该边界将类别分开,用曲线表示。而一个简单的统计模型在准确分类数据(中心)方面表现相当糟糕,而一个机器学习模型(右侧)则能够轻松地发现真实的类别边界。

这里的问题是,中间面板中描述的模型试图用一个简单的参数模型来解释一个复杂、非线性的现象。参数模型与非参数模型的正式定义很复杂,对于这本书来说过于数学化,但关键是参数模型在你对输入和你要预测的响应之间的关系有先验理解时表现良好。如果你对非线性关系了解足够多,你可能能够转换你的输入或响应变量,使得参数模型仍然有效。例如,如果某种疾病在人群中的观察率在老年人中更高,你可能会发现患病概率与受试者年龄的平方之间存在线性关系。但在现实世界中,你经常遇到无法猜测这种转换的问题。
你需要的是更灵活的模型,这些模型可以自动发现数据中的复杂趋势和结构,而无需被告知这些模式看起来像什么。这就是非参数机器学习算法发挥作用的地方。在图 1.6 右面板中,你可以看到将一个非参数学习算法(在这种情况下,是一个随机森林分类器)应用于该问题的结果。显然,预测的决策边界与真实边界非常接近,因此,分类精度远高于参数模型。
由于它们在复杂、高维、现实世界的数据集上达到了如此高的准确度,非参数机器学习模型成为许多数据驱动问题的首选方法。非参数方法的例子包括机器学习中一些最广泛使用的方法,如 k 最近邻、核平滑、支持向量机、决策树和集成方法。我们在本书的后面部分描述了所有这些方法,附录提供了某些重要算法的概述。线性算法还有一些其他特性,在某些情况下使它们具有吸引力。它们可能更容易解释和推理,并且可以更快地计算和扩展到更大的数据集。
进一步阅读
Gareth James 等人撰写的教科书《统计学习引论》(Springer,2013 年)为没有统计学或数学背景的读者提供了对机器学习中常用方法的详细介绍。PDF 版本可在作者网站上找到(www-bcf.usc.edu/~gareth/ISL/))。
回到微贷问题,扩大您业务的最佳选择是采用非参数机器学习模型。该模型可能会找到与您最初手动找到的完全相同的规则,但它们可能略有不同,以便优化统计收益。最有可能的是,机器学习模型还会自动找到其他更深层次的关系,这些关系是您在其他情况下不会考虑到的,即输入变量和期望结果之间的关系。
除了提供自动化的工作流程外,您还可能获得更高的准确度,这直接转化为更高的商业价值。想象一下,一个非参数机器学习模型比逻辑回归方法高 25%的准确度。在这种情况下,您的机器学习模型在新应用中犯的错误会更少:接受更少的不会偿还贷款的申请人,拒绝更少的会偿还贷款的申请人。总的来说,这意味着您发放的贷款的平均回报率更高,使您能够发放更多的贷款,并为您的业务创造更高的收入。
我们希望这能让您领略到机器学习所能带来的力量。在我们继续定义我们的基本机器学习工作流程之前,我们将列举一些机器学习的优势以及这种方法的一些挑战。
1.2.3. 机器学习的五个优势
为了总结我们对微贷示例的讨论,我们列出了一些使用机器学习系统相对于最常见替代方案(如手动分析、硬编码的业务规则和简单的统计模型)的一些最显著优势。机器学习的五个优势如下:
-
准确度高— 机器学习利用数据来发现针对您问题的最佳决策引擎。随着您收集更多数据,准确度可以自动提高。
-
自动化—— 当答案被验证或丢弃时,机器学习模型可以自动学习新的模式。这使用户能够将机器学习直接嵌入到自动化工作流程中。
-
快速—— 当新的数据流进来时,机器学习可以在毫秒内生成答案,允许系统实时反应。
-
可定制—— 许多数据驱动的问题可以用机器学习来解决。机器学习模型是根据您自己的数据定制的,并且可以配置以优化驱动您业务的各种指标。
-
可扩展—— 随着业务的增长,机器学习可以轻松扩展以处理增加的数据速率。一些机器学习算法可以扩展到在云中的多台机器上处理大量数据。
1.2.4. 挑战
自然地,实现这些好处涉及一些挑战。根据业务问题的规模和形状,伴随的难度程度从孩子玩耍般的简单到汉尼拔翻越阿尔卑斯山般的巨大不等。
最突出的是以可用的形式获取数据。据估计,数据科学家将 80%的时间花在数据准备上.^([6]) 你无疑已经听说过,企业捕获的数据量比以往任何时候都要大,而且确实如此。你也可能听说过这些数据被称为业务流程的“废气”。换句话说,我们的新数据宝库并非旨在满足我们机器学习系统的输入需求。从残留物中提取有用的数据可能是繁琐和混乱的工作。
⁶
史蒂夫·洛尔,《大数据科学家面临的“清洁工工作”是洞察力的关键障碍》,《纽约时报》,2014 年 8 月 17 日,
mng.bz/7W8n。
一个相关的挑战是制定问题,以便机器学习可以应用,并将产生可操作和可衡量的结果。在我们的例子中,目标是明确的:预测谁会偿还,谁会违约。分类很容易应用,结果也容易衡量。幸运的是,一些现实世界的问题是这样的简单;例如,鉴于我们对潜在客户的了解(我们有很多数据),预测他们是否会购买我们的产品。这是低垂的果实。
一个更困难的例子可能是这样的:找到最佳媒体组合和广告单元组合,以增加新产品线的品牌知名度。仅仅制定这个问题就需要构建一种衡量品牌知名度的方法,理解正在考虑的替代媒体选项,以及反映与替代方案和关联结果相关经验的数据。
当你试图预测的结果很复杂时,选择算法以及如何应用它本身可能就是一项巨大的努力。致力于预测术后并发症可能性的心脏病研究人员,对于每位患者都有一套令人眼花缭乱的资料,但机器学习算法并不自然地吸收心电图(EKG)数据和 DNA 序列。特征工程是将这些输入转换为预测特征的过程。
如果我们不提及预测模型师存在的痛苦:一个完美匹配训练数据的模型,但在使用它对不在训练集中的数据进行实际预测时却完全失败。这个问题最常见的是过拟合。
你会看到机器学习可以解决各种各样的问题,有些问题比其他问题更容易解决。你也可能注意到,解决方案的价值并不总是与所需的努力成比例。确实,机器学习并不是任何问题的万能药。但正如你将在本书中看到的,机器学习是许多现实世界、数据驱动问题的完美选择。
1.3. 按照机器学习工作流程:从数据到部署
在本节中,我们介绍了将机器学习模型集成到你的应用程序或数据管道中的主要工作流程。机器学习工作流程有五个主要组成部分:数据准备、模型构建、评估、优化以及在新的数据上的预测。这些步骤的应用有一个固有的顺序,但大多数现实世界的机器学习应用都需要在迭代过程中多次回顾每个步骤。这五个组成部分在第二章到第四章中详细说明,但我们在本介绍中概述它们,以激发你开始学习的兴趣。图 1.7 概述了此工作流程,接下来的几节将自上而下介绍这些概念。你将在本书中多次看到这张图,因为我们介绍了机器学习工作流程的各个组成部分。
图 1.7. 现实世界机器学习系统的工作流程。从历史输入数据中,你可以使用机器学习算法构建一个模型。然后你需要评估该模型的表现,并优化准确性和可扩展性以适应你的需求。使用最终模型,你可以在新的数据上进行预测。

1.3.1. 数据收集和准备
收集和准备机器学习系统所需的数据通常意味着如果数据尚未以表格格式存在,则需要将其转换为表格格式。将表格格式想象成一个电子表格,其中数据按行和列分布,每一行对应一个感兴趣的实例或例子,每一列代表该实例的测量值。存在一些例外和变化,但可以说大多数机器学习算法都需要以这种格式提供数据。不用担心;当你遇到例外时,你会处理它们。图 1.8 展示了这种格式的一个简单数据集。
图 1.8。在一个表格数据集中,行被称为实例,列代表特征。

关于表格数据的第一件事要注意的是,各个列通常包含相同类型的数据,而行通常包含各种类型的数据。在图 1.8 中,你已能识别出四种类型的数据:姓名是一个字符串变量,年龄是一个整数变量,收入是一个浮点变量,而婚姻状况是一个分类变量(具有离散的类别数量)。这样的数据集被称为异构的(与同构相对),在第二章中我们解释了我们将如何以及为什么根据特定的机器学习算法将这些数据类型强制转换为其他类型。
实际世界的数据可能以各种方式“杂乱无章”。假设在数据收集阶段,某个特定测量值对于数据中的一个实例不可用,并且无法返回去找到缺失的信息。在这种情况下,表格将包含一个或多个单元格中的缺失值,这可能会使模型构建和随后的预测复杂化。在某些情况下,人类参与了数据收集阶段,我们都知道在重复性任务,如数据记录中犯错误是多么容易。这可能导致一些数据完全错误,你必须能够处理这样的场景,或者至少知道特定算法在存在误导性数据时的表现如何。你将在第二章中更详细地了解处理缺失和误导性数据的方法。
1.3.2. 从数据中学习模型
构建一个成功的机器学习系统的第一步是提出一个可以通过数据回答的问题。使用这个简单的个人信息表,你可以构建一个机器学习模型,可以预测一个人是已婚还是单身。例如,这样的信息对于展示相关广告将是有用的。
在这种情况下,你会使用 婚姻状况 变量作为 目标 或 标签,其余变量作为 特征。然后,机器学习算法的任务就是找到如何使用输入特征集成功预测目标。然后,对于婚姻状况未知的人,你可以使用模型根据每个个体的输入变量来预测婚姻状况。图 1.9 展示了在我们玩具数据集上的这一过程。
图 1.9. 机器学习建模过程

在这一点上,将机器学习算法想象成一个神奇的盒子,它执行从输入特征到输出数据的映射。为了构建一个有用的模型,你需要不止两行。与其他广泛使用的方法相比,机器学习算法的一个优点是能够处理许多特征。图 1.9 仅显示了四个特征,其中 Person ID 和 Name 可能对预测婚姻状况没有帮助。一些算法对无信息特征相对免疫,而其他算法如果省略这些特征可能会得到更高的准确率。第三章 更详细地介绍了算法类型及其在各种问题和数据集上的性能。
然而,值得注意的是,有时可以从看似无信息特征中提取出有价值的信息。例如,位置特征本身可能没有信息,但它可以导致如人口密度这样的信息特征。这种类型的数据增强,称为 特征提取,在现实世界的机器学习项目中非常重要,也是 第五章 和 第七章 的主题。
现在我们有了机器学习模型,现在可以对新数据进行预测——这些数据的目标变量是未知的。图 1.10 展示了这一过程,使用的是 图 1.9 中构建的神奇盒子模型。
图 1.10. 使用模型对新数据进行预测

目标预测以与用于学习模型的原数据相同的形式返回。使用模型进行预测可以看作是填写新数据的目标列的空白。一些机器学习算法还可以输出与每个类别相关的概率。在我们的已婚/单身示例中,一个 概率性 机器学习模型会为每个新的人输出两个值:这个人已婚的概率和这个人单身的概率。
我们在途中省略了一些细节,但在原则上,你刚刚设计出了你的第一个机器学习系统。每个机器学习系统都是关于构建模型并使用这些模型进行预测。让我们用伪代码查看基本的机器学习工作流程,以获得另一个简单性的视角。
列表 1.1. 机器学习工作流程程序的初始结构
data = load_data("data/people.csv")
model = build_model(data, target="Marital status")
new_data = load_data("data/new_people.csv")
predictions = model.predict(new_data)
尽管我们还没有编写这些函数,但基本结构已经就位。到第三章(kindle_split_013.html#ch03)时,你会理解这些步骤;本书的其余部分(第四章(kindle_split_014.html#ch04)到第十章(kindle_split_021.html#ch10))是关于确保你为当前问题构建了最佳模型。
1.3.3. 评估模型性能
很少有机器学习系统在没有对模型性能进行某种验证的情况下投入使用。尽管我们在这章中省略了很多细节,但让我们假装你知道如何构建模型并进行预测。现在,你可以使用一个巧妙的技巧来了解你的模型在用于预测新数据之前的工作效果。
你取出一些数据,假装你不知道目标变量。然后你在剩余的数据上构建一个模型,并使用保留的数据(测试数据)进行预测。图 1.11 展示了这个模型测试过程。
图 1.11. 当使用测试集来评估模型性能时,你“假装”目标变量是未知的,并将预测与真实值进行比较。

让我们再看看这个工作流程的伪代码。
列表 1.2. 我们的机器学习工作流程程序,包含模型评估
data = load_data(...)
training_data, testing_data = split_data(data)
model = build_model(training_data, target="Marital status")
true_values = testing_data.extract_column("Marital status")
predictions = model.predict(testing_data)
accuracy = compare_predictions(predictions, true_values)
现在,你可以将预测结果与已知的“真实”值进行比较,以了解模型的准确性。在伪代码中,这个功能隐藏在compare_predictions函数后面,而本书的第四章(kindle_split_014.html#ch04)大部分内容都是关于理解这个函数如何针对各种机器学习问题进行查找。
1.3.4. 优化模型性能
机器学习基本问题的最后一部分也包含在第四章(kindle_split_014.html#ch04)中:如何使用模型评估的结果来改进模型。你可以通过以下三种方式提高模型准确性:
-
调整模型参数— 机器学习算法配置了特定于底层算法的参数,这些参数的最佳值通常取决于数据的类型和结构。每个参数的值,或者任何组合的值,都可能影响模型的表现。我们介绍了寻找和选择最佳参数值的各种方法,并展示了这如何有助于确定针对特定数据集的最佳算法。
-
选择特征子集— 许多机器学习问题包括大量的特征,而这些特征的噪声有时会使得算法难以在数据中找到真正的信号,尽管它们本身可能仍然是有信息的。对于许多机器学习问题,拥有大量数据是好事;但有时也可能成为诅咒。因为你事先不知道何时这会影响你的模型性能,你必须仔细确定构成最通用和最准确模型的特征。
-
数据预处理—— 如果你在网上搜索机器学习数据集,你会找到许多易于使用的、许多机器学习算法可以快速应用的数据集。然而,大多数现实世界的数据集并不是处于如此干净的状态,你将不得不进行清理和加工,这个过程通常被称为数据整理或数据清洗。数据集可能包括拼写不同的名称,尽管它们指的是同一个实体,或者包含缺失或错误的数据值,这些都会损害模型的性能。这听起来可能像是边缘情况,但你可能会惊讶,即使在复杂的数据驱动组织中,这种情况也经常发生。
在机器学习基础知识已经建立的基础上,你将在下一节中简要了解更高级的功能,然后再深入了解本节涵盖的主要组件的详细信息。
1.4. 使用高级技术提升模型性能
前一节介绍了任何现实世界机器学习项目中必不可少的步骤,现在你将了解一些常用于进一步提高模型性能的附加技术。根据数据和问题的不同,这些技术中的一些可以在准确度上带来显著的提升,但有时也会以训练和预测速度的降低为代价。这些技术将在第五章(kindle_split_015.html#ch05)至第十章(kindle_split_021.html#ch10)中更详细地解释,但本节将概述主要思想。
1.4.1. 数据预处理和特征工程
你将在第二章(kindle_split_012.html#ch02)中了解各种类型的数据以及如何处理常见的混乱类型。但除了这项基本的数据清理之外,你还可以更进一步,从数据中提取额外的价值,这可能会提高你的模型性能。
在任何问题域中,特定的知识用于决定要收集的数据,并且这种宝贵的领域知识也可以用来从收集的数据中提取价值,实际上是在模型构建之前增加了模型的特征。我们称这个过程为特征工程,当之前介绍的基本机器学习工作流程对你来说已经变得习以为常时,你可能会发现自己几乎把所有的时间都花在这个优化过程的这部分。这也是机器学习的创造性部分,在这里你可以利用你的知识和想象力,通过深入数据并提取隐藏的价值来想出改进模型的方法。你将广泛使用我们经过统计验证的模型评估和优化步骤来区分当时看似不错的主意和真正有用的东西。以下是一些特征工程的重要示例:
-
日期和时间— 你会在许多数据集中看到日期或时间变量,但它们本身对机器学习算法来说并不有用,因为机器学习算法往往需要原始数字或类别。然而,这些信息可能是有价值的。如果你想预测要展示哪个广告,知道一天中的时间、一周中的哪一天以及一年中的哪个时间点肯定很重要。通过特征工程,可以从日期和时间中提取这些信息,并将其提供给模型。此外,当日期和时间出现在重复活动的观察中,例如用户在一个月或一年内重复访问网站时,它们可以用来计算可能具有预测性的间隔持续时间。例如,在购物网站上,用户可能在购买前更频繁地访问网站,以查看和比较商品和价格。
-
位置— 位置数据,如经纬度坐标或位置名称,在某些数据集中可用。这种信息有时可以单独使用,但你可能能够提取对特定问题有用的额外信息。例如,如果你想预测一个县的选举结果,你可能想要提取人口密度、平均收入和贫困率作为模型中的数字。
-
数字媒体— 这类数据包括文本、文档、图像和视频。使这类数据可用的特征工程是像狗和猫比赛这样的项目中的难点。首先从图像中提取边缘、形状和颜色光谱。然后使用数学变换对这些进行分类,其输出是一组可供分类算法使用的特征。
希望很明显,特征工程对于现实世界的机器学习项目来说可能很重要。第五章和第七章将详细介绍,介绍特定的特征工程技术;你将了解这些技术如何融入你的机器学习工作流程,以便在不变得过于复杂和容易过拟合的情况下提高模型性能。图 1.12 说明了特征工程如何集成到在第 1.3 节中引入的更大的机器学习工作流程中。
图 1.12. 在原始机器学习工作流程中插入的特征工程阶段

1.4.2. 使用在线方法持续改进模型
大多数传统的机器学习模型都是静态的,或者很少重建。但在许多情况下,你会有数据和预测反馈到系统中,你希望模型随着时间的推移而改进,并适应数据的变化。几种机器学习算法支持这种类型的在线学习;第八章介绍了这些算法及其潜在的风险。图 1.13 展示了如何将持续再学习集成到机器学习工作流程中。
图 1.13. 在这个在线机器学习系统的流程中,预测被反馈到模型中进行迭代改进。

1.4.3. 随数据量和速度缩放模型
众所周知,数据集的大小和速度比以往任何时候增长得都要快。由于需要人类来获取答案,因此传统的监督方法数据集相对较小。今天,大量数据(包括答案)直接由传感器、机器或计算机产生,我们开始看到需要可扩展的机器学习算法来处理这些数据量。
第九章介绍了能够随着数据集大小的增长而扩展的机器学习方法的细节;你将看到它们是如何相互比较的,以及与非扩展算法的比较。
1.5. 摘要
本章介绍了机器学习作为一种更好的、更数据驱动的决策方法。本章的主要要点如下:
-
机器学习算法与基于规则的系统不同,因为它们根据数据创建自己的模型。监督机器学习系统通过学习具有已知结果的示例的特征来泛化。
-
机器学习通常比手动构建的基于规则的系统更准确、自动化、快速、可定制和可扩展。
-
机器学习挑战包括识别和制定机器学习可以应用的问题、获取和转换数据以使其可用、找到适合问题的正确算法、特征工程和过拟合。
-
基本的机器学习工作流程包括数据准备、模型构建、模型评估、优化以及在新的数据上的预测。
-
在线学习模型通过使用其预测结果来更新自己,不断地重新学习。
1.6. 本章术语
| 单词 | 定义 |
|---|---|
| 实例或示例 | 单个对象、观察、交易或记录。 |
| 目标或标签 | 感兴趣的数值或分类(标签)属性。这是每个新实例要预测的变量。 |
| 特征 | 用于预测目标的输入属性。这些也可能是数值或分类的。 |
| 模型 | 描述特征与目标之间关系的数学对象。 |
| 训练数据 | 包含已知目标以用于拟合机器学习模型的实例集。 |
| 回忆 | 使用模型来预测目标或标签。 |
| 监督机器学习 | 在已知输出值的示例的情况下,训练过程推断一个将输入值与输出值相关联的函数的机器学习。 |
| 非监督机器学习 | 不依赖于标记示例的机器学习技术,而是试图在未标记数据中找到隐藏的结构。 |
| 机器学习工作流程 | 机器学习过程中的阶段:数据准备、模型构建、评估、优化和预测。 |
| 在线机器学习 | 一种机器学习方法,其中对每个新示例进行预测,并更新模型。 |
在第二章中,你将深入了解收集数据、为机器学习使用准备数据以及使用可视化来获得选择最佳工具和方法所需的洞察力。
第二章. 现实世界数据
本章涵盖
-
开始机器学习
-
收集训练数据
-
使用数据可视化技术
-
准备数据以供机器学习使用
在监督式机器学习中,你使用数据来教导自动化系统如何做出准确的决策。机器学习算法被设计用来发现历史训练数据中的模式和关联;它们从这些数据中学习,并将这种学习编码到模型中,以准确预测新数据的重要数据属性。因此,训练数据在机器学习的追求中是基本的。有了高质量的数据,细微的差别和相关性可以准确捕捉,并且可以构建高保真度的预测系统。但如果训练数据质量差,即使是最好的机器学习算法的努力也可能变得毫无用处。
本章作为你收集和整理训练数据以用于监督式机器学习工作流程(图 2.1)的指南。我们提供了为机器学习建模准备训练数据的一般指南,并警告了一些常见的陷阱。机器学习的许多艺术在于探索和可视化训练数据以评估数据质量和指导学习过程。为此,我们概述了一些最有用的数据可视化技术。最后,我们讨论了如何准备用于机器学习模型构建的训练数据集,这是第三章的主题。
图 2.1. 基本的机器学习工作流程。因为本章涉及数据,所以我们突出显示了表示历史数据和新的数据的方框。

本章使用了一个真实的机器学习示例:客户流失预测。在商业中,客户流失指的是客户取消或取消订阅付费服务的行为。一个重要且价值高的任务是预测哪些客户可能在近期内流失。如果公司能够准确了解哪些客户可能会取消他们的服务,那么他们可以通过发送消息或提供折扣来干预。这种干预可以节省公司数百万美元,因为新客户获取的典型成本远超过对流失者的干预成本。因此,客户流失预测的机器学习解决方案——即提前几周预测可能流失的用户——可以非常有价值。
本章还使用了在线可用且在机器学习书籍和文档中广泛使用的数据集:泰坦尼克号乘客和汽车每加仑英里数数据集。
2.1. 开始:数据收集
要开始学习机器学习,第一步是提出一个适合机器学习方法的疑问。尽管机器学习有许多风味,但大多数现实世界的机器学习问题都涉及预测感兴趣的目标变量(或变量)。在这本书中,我们主要涵盖这些监督式机器学习问题。适合监督式机器学习方法的疑问包括以下内容:
-
本月哪些客户会流失?
-
这个用户会点击我的广告吗?
-
这个用户账户是否欺诈?
-
这条推文的情绪是负面、正面还是中性?
-
下个月我的产品需求量会是多少?
你会注意到这些问题中存在一些共同点。首先,它们都需要对感兴趣的某个或某些实例进行评估。这些实例可以是人(例如,在流失问题中),事件(例如,推文情绪问题),甚至时间段(例如,在产品需求问题中)。
第二,这些问题的每一个都有一个明确的目标,在某些情况下是二元的(流失与否,欺诈与否),在某些情况下具有多个类别(负面、正面、中性),甚至数百或数千个类别(从大型图书馆中选择一首歌),在其他情况下则具有数值(产品需求)。请注意,在统计学和计算机科学中,目标也常被称为响应或因变量。这些术语可以互换使用。
第三,这些问题的每一个都可以有包含已知目标的历史数据集。例如,在几周或几个月的数据收集过程中,你可以确定哪些订阅者流失了,哪些人点击了你的广告。通过一些手动努力,你可以评估不同推文的情绪。除了已知的目标值之外,你的历史数据文件还将包含在预测时可知的每个实例的信息。这些是输入特征(也常被称为解释性或自变量)。例如,每个客户的消费历史,连同客户的人口统计信息和账户信息,将是流失预测的适当输入特征。输入特征,连同目标变量的已知值,构成了训练集。
最后,如果目标变量是可知的,每个问题都隐含着一个行动。例如,如果你知道一个用户会点击你的广告,你就会对该用户进行出价并展示广告。同样,如果你精确地知道下个月的产品需求,你就会调整供应链以匹配该需求。机器学习算法的作用是使用训练集来确定如何使用输入特征集最准确地预测目标变量。这种“学习”的结果编码在机器学习模型中。当观察到新的实例(具有未知的目标)时,它们的特征被输入到机器学习模型中,该模型对那些实例生成预测。最终,这些预测使最终用户能够采取更明智(更快)的行动。除了产生预测外,机器学习模型还允许用户推断输入特征与目标变量之间的关系。
让我们将所有这些内容放在客户流失预测问题的背景下。想象一下,你为一家电信公司工作,而你感兴趣的问题是:“下个月,我的哪些当前手机用户会取消订阅?”在这里,每个实例都是一个当前用户。同样,目标变量是每个用户在那个月是否取消服务的二元结果。输入特征可以包括任何在月初可知的关于每个客户的信息,例如账户当前时长、订阅计划的详细信息以及如上个月的总通话次数和使用的分钟数等信息。图 2.2 显示了电信客户流失预测的一个示例训练集的前四行。
图 2.2. 用于电信客户流失问题的四个实例的训练数据

本节的目标是提供一个基本指南,以正确收集机器学习训练数据。数据收集可能因行业而异,但在组装训练数据时,会出现一些常见的问题和痛点。以下子节提供了一个实用指南,以解决四个最常见的数据收集问题:
-
我应该包含哪些输入特征?
-
我如何获得目标变量的已知值?
-
我需要多少训练数据?
-
我如何知道我的训练数据是否足够好?
2.1.1. 应包含哪些特征?
在机器学习问题中,你通常会有一打以上的特征可以用来预测目标变量。在电信客户流失问题中,关于每个客户的人口统计信息(年龄、性别、位置)、订阅计划(状态、剩余时间、上次续订时间、首选状态)以及使用情况(通话记录、短信数据和数据使用、支付历史)都可能作为输入特征可用。关于是否可以将某物用作输入特征,存在两个实际限制:
-
特征的值必须在需要预测时已知(例如,对于电信 churn 示例,在月初时)。
-
特征必须是数值或分类性质(第五章展示了如何通过特征工程将非数值数据转换为特征)。
呼叫历史数据流等数据可以通过计算数据摘要统计量(如总通话分钟数、白天/夜间通话分钟数比率、周内/周末通话分钟数比率以及网络使用分钟数比例)转换成一组数值和/或分类特征。
在如此众多的可能特征中,你应该使用哪些呢?作为一个简单的经验法则,只有当特征被认为与目标变量相关时才应该包含在内。既然监督式机器学习的目标是预测目标,那么显然与目标无关的特征应该被排除。例如,如果每个客户都有一个独特的识别号码,那么这个号码就不应该用作输入特征来预测客户是否会取消订阅。这样的无用特征使得从数据中的随机扰动(噪声)中检测真正的关联(信号)变得更加困难。不具信息量的特征越多,信噪比越低,因此机器学习模型的平均准确性就越低。
同样,排除一个输入特征,因为它之前并未被认定为与目标相关,也可能损害你的机器学习模型的准确性。实际上,机器学习的角色就是发现数据中的新模式和关系!例如,假设有一个特征是计算当前未打开语音邮件的数量,如果这个特征被排除在特征集之外,那么一些小部分人群因为决定在下个月更换运营商而停止检查语音邮件。这个信号会在数据中表现为拥有大量未打开语音邮件的客户 churn 条件概率略有增加。排除这个输入特征将使机器学习算法失去重要信息,因此会导致机器学习系统的预测准确性降低。由于机器学习算法能够发现微妙的非线性关系,超出已知的一阶效应的特征可能会对模型的准确性产生重大影响。
在选择要使用的输入特征集时,你会面临一个权衡。一方面,将所有可能想到的特征(“大杂烩”)都放入模型中,可能会淹没那些包含任何信号的少量特征,而这些特征被大量的噪声所淹没。因此,机器学习模型的准确性会受到影响,因为它无法区分真实模式与随机噪声。另一方面,手动选择一小部分已知与目标变量相关的特征,可能会导致你遗漏其他高度预测性的特征。结果,机器学习模型的准确性会受到影响,因为模型不知道被忽视的特征,而这些特征是目标变量的预测因素。
面对这种权衡,最实际的方法是以下:
-
包含所有你认为可能预测目标变量的特征。拟合一个机器学习模型。如果模型的准确性足够,则停止。
-
否则,通过包括其他与目标变量不那么明显相关的特征来扩展特征集。拟合另一个模型并评估准确性。如果性能足够,则停止。
-
否则,从扩展的特征集开始,运行机器学习特征选择算法以选择你扩展特征集中最好、最预测性的子集。
我们在第五章进一步讨论了特征选择算法。这些方法寻求在特征集的子集上构建最准确的模型;它们在特征集中保留信号,同时丢弃噪声。尽管计算成本高昂,但它们可以在模型性能上带来巨大的提升。
为了完成这个子节,重要的是要注意,为了使用输入特征,该特征不需要在每个实例中都存在。例如,如果你的客户群中只有 75%的客户年龄已知,你仍然可以使用年龄作为输入特征。我们将在本章后面讨论处理缺失数据的方法。
2.1.2. 我们如何获得目标变量的真实值?
在开始监督机器学习时,最困难的障碍之一是收集具有已知目标变量的训练实例。这个过程通常需要运行现有的次优系统一段时间,直到收集到足够的训练数据。例如,在构建电信客户流失的机器学习解决方案时,你首先需要耐心等待几周或几个月,观察一些客户取消订阅而另一些客户续订。在你收集到足够的训练实例以构建准确的机器学习模型后,你可以切换开关并开始在生产中使用机器学习。
每个用例都将有一个不同的过程,通过这个过程可以收集或估计真实值——目标变量的实际或观察到的值。例如,考虑以下几个选定的机器学习用例的训练数据收集过程:
-
广告定位—— 你可以运行几天活动以确定哪些用户点击了你的广告,哪些用户进行了转化。
-
欺诈检测—— 你可以仔细检查你的历史数据,以确定哪些用户是欺诈的,哪些是合法的。
-
需求预测—— 你可以查看你过去几个月或几年的供应链管理数据日志,以确定过去几个月或几年的需求。
-
Twitter 情感分析—— 获取真实意图的情感信息相当困难。你可以通过让人们阅读并评论一组推文(或使用众包)来进行手动分析。
虽然收集已知目标变量的实例可能既耗时又耗钱,但迁移到机器学习解决方案的好处可能会远远弥补这些损失。获取目标变量真实值的其他方法包括以下:
-
指派分析师手动检查过去或当前数据,以确定或估计目标的真实值
-
使用众包来利用“群体智慧”以获得目标估计
-
对客户进行后续访谈或其他实际实验
-
运行控制实验(例如,A/B 测试)并监控响应
这些策略都需要大量的人工劳动,但通过仅收集对机器学习模型影响最大的实例的目标变量,你可以加速学习过程并缩短收集训练数据所需的时间。这种方法的一个例子是称为主动学习的方法。给定一个现有的(小)训练集和一个(大)的数据集,其中包含未知响应变量,主动学习识别出后者集中包含在训练集中将产生最准确机器学习模型的实例子集。从这个意义上说,主动学习可以通过集中人工资源来加速准确机器学习模型的生产。有关主动学习及相关方法的更多信息,请参阅 Dasgupta 和 Langford 于 2009 年在 ICML 上的演示。^([[1)]
¹
2.1.3. 需要多少训练数据?
由于观察和收集数据实例的响应变量的困难,你可能会想知道需要多少训练数据才能使机器学习模型运行起来。不幸的是,这个问题如此特定于问题本身,以至于无法给出普遍的回应,甚至没有一个经验法则。
这些因素决定了所需训练数据量:
-
问题的复杂性。输入特征与目标变量之间的关系是简单的模式,还是复杂且非线性的?
-
准确度的要求。如果你只需要达到 60%的成功率来解决你的问题,那么所需的训练数据量将少于你需要达到 95%成功率的情况。
-
特征空间的维度。如果只有两个输入特征可用,所需的训练数据量将少于有 2,000 个特征的情况。
一个需要记住的指导原则是,随着训练集的增长,模型(平均而言)将变得更加准确。(这假设数据仍然代表持续的数据生成过程,你将在下一节中了解更多。)更多的训练数据导致更高的准确率,因为机器学习模型的数据驱动特性。由于特征和目标之间的关系完全是从训练数据中学习的,所以你拥有的越多,模型识别和捕捉更微妙模式和关系的能力就越强。
使用本章前面提到的电信数据,我们可以展示机器学习模型如何随着更多训练数据的增加而提高,并提供一种评估是否需要更多训练数据的方法。电信训练数据集包含 3,333 个实例,每个实例包含 19 个特征以及未订阅与续订的二进制结果。使用这些数据,可以轻松评估你是否需要收集更多数据。请执行以下操作:
-
使用当前的训练集,选择一个子样本大小的网格进行尝试。例如,对于这个包含 3,333 个训练数据实例的电信训练集,你的网格可以是 500;1,000;1,500;2,000;2,500;3,000。
-
对于每个样本大小,从训练集中随机抽取这么多实例(不重复抽取)。
-
对于每个训练数据的子样本,构建一个机器学习模型并评估该模型的准确率(我们在第四章中讨论了机器学习评估指标 chapter 4)。
-
评估准确率随样本大小的变化情况。如果它似乎在较大的样本大小上趋于平稳,那么现有的训练集可能足够。但如果准确率对于较大的样本继续上升,那么包含更多的训练实例可能会提高准确率。
或者,如果你有一个明确的准确率目标,你可以使用这种策略来评估你的当前基于现有训练数据的机器学习模型是否已经实现了该目标(在这种情况下,没有必要收集更多的训练数据)。
图 2.3 展示了电信数据集中使用训练实例数量作为函数的拟合机器学习模型准确率的变化。在这种情况下,很明显,随着训练数据的增加,机器学习模型会提高:从 250 个到 500 个再到 750 个训练示例,准确率水平显著提高。然而,当你将训练实例的数量增加到 2,000 个以上时,准确率趋于平稳。这是证据表明,如果你添加更多的训练实例,机器学习模型不会显著提高。(这并不意味着通过使用更多特征不能实现显著的改进。)
图 2.3. 测试现有 3,333 个训练实例的样本是否足够构建一个准确的电信客户流失机器学习模型。黑色线条表示评估流程重复 10 次后的平均准确率,阴影带表示误差范围。

2.1.4. 训练集是否足够具有代表性?
除了训练集的大小之外,生成准确预测机器学习模型的另一个重要因素是训练集的代表性。训练集中的实例与未来将要收集的实例有多相似?因为监督机器学习的目标是生成对新数据的准确预测,所以训练集必须代表你最终想要生成预测的实例类型。由未来数据可能呈现的非代表性样本组成的训练集被称为样本选择偏差或协变量偏移。
训练样本可能由于以下几个原因不具有代表性:
-
只能从某些具有偏差的子样本中获取目标变量的真实值。例如,如果你的历史数据中的欺诈实例只有在造成公司损失超过 1000 美元时才会被检测到,那么在该数据上训练的模型将难以识别损失低于 1000 美元的欺诈案例。
-
实例的性质随着时间的推移而发生了变化。例如,如果你的训练示例包括医疗保险欺诈的历史数据,但新的法律大大改变了医疗保险公司必须进行业务的方式,那么你对新数据的预测可能不合适。
-
输入特征集随着时间的推移而发生了变化。例如,假设你收集的每个客户的地理位置属性集合发生了变化;你以前收集的是邮政编码和州,但现在收集 IP 地址。这种变化可能需要你修改用于模型的特征集,并可能需要从训练集中丢弃旧数据。
在这些情况下,拟合到训练数据的机器学习模型可能无法很好地推广到新数据。借用一句谚语:你不会想用训练在苹果上的模型去尝试预测橙子!该模型在橙子上的预测准确性可能不会很好。
为了避免这些问题,重要的是尽可能使训练集与未来数据相似。这意味着要以一种方式结构化你的训练数据收集过程,以便消除偏差。正如我们在下一节中提到的,可视化也可以帮助确保训练数据具有代表性。
现在你已经了解了如何收集训练数据,你的下一个任务是结构化和组装这些数据,为机器学习模型构建做准备。下一节将展示如何预处理你的训练数据,以便开始构建模型(第三章的主题)。
2.2. 为建模预处理数据
收集数据是准备数据用于建模的第一步,但有时你必须根据数据集的组成运行数据通过几个预处理步骤。许多机器学习算法仅适用于数值数据——整数和实值数。最简单的机器学习数据集以这种格式出现,但许多还包括其他类型的特征,例如分类变量,并且一些数据集存在缺失值。有时你需要通过特征工程构建或计算特征。一些数值特征可能需要缩放以使它们可比较或使它们与频率分布保持一致(例如,在正态曲线上评分)。在本节中,你将了解现实世界机器学习所需的一些常见数据预处理步骤。
2.2.1. 分类特征
最常见的非数值特征类型是分类特征。如果一个特征可以放入桶中,并且值的顺序不重要,则该特征是分类的。在某些情况下,此类特征很容易识别(例如,当它只具有几个字符串值时,如spam和ham)。在其他情况下,一个特征是数值(整数)特征还是分类特征并不那么明显。有时两种可能都是有效的表示,并且选择可能会影响模型的性能。一个例子是表示一周中某天的特征,它可以有效编码为数值(自星期日以来的天数)或分类(星期一、星期二等名称)。你将不会在第三章和第四章中查看模型构建和性能,但本节介绍了一种处理分类特征的技术。图 2.4 指出了几个数据集中的分类特征。
图 2.4. 识别分类特征。顶部是简单的 Person 数据集,它有一个婚姻状况分类特征。底部是关于泰坦尼克号乘客的数据集。这里被识别为分类特征的有:Survived(乘客是否幸存),Pclass(乘客所乘的等级),Gender(男性或女性),和 Embarked(乘客出发的城市)。

一些机器学习算法可以原生地使用分类特征,但通常它们需要数值形式的数据。你可以将分类特征编码为数字(每个类别一个数字),但你不能将这种编码后的数据用作真正的分类特征,因为这样你引入了(任意的)类别顺序。回想一下,分类特征的一个属性是它们是无序的。相反,你可以将每个类别转换为单独的二进制特征,对于出现该类别的实例,其值为 1,未出现时为 0。因此,每个分类特征都转换为一系列二进制特征,每个类别一个。以这种方式构建的特征有时被称为 虚拟变量。图 2.5 进一步说明了这个概念。
图 2.5. 将分类列转换为数值列

将 图 2.5 中的分类特征转换为二进制特征的伪代码如下所示。请注意,categories 是一种特殊的 NumPy 类型 (www.numpy.org),使得 (data == cat) 产生一个布尔值列表。
列表 2.1. 将分类特征转换为数值二进制特征
def cat_to_num(data):
categories = unique(data)
features = []
for cat in categories:
binary = (data == cat)
features.append(binary.astype("int"))
return features
注意
熟悉 Python 编程语言的读者可能已经注意到,前面的例子不仅仅是伪代码,也是有效的 Python 代码。你会在整本书中看到很多这样的例子:我们以伪代码的形式引入代码片段,除非另有说明,否则它都是可运行的代码。为了使代码更简单,我们隐式地导入了几个辅助库,例如 numpy 和 scipy。我们的示例通常在包含 from numpy import * 和 from scipy import * 的情况下可以工作。请注意,尽管这种方法在交互式尝试示例时很方便,但你绝对不应该在实际应用中使用它,因为 import * 结构可能会导致名称冲突和意外结果。所有代码示例都可以在随附的 GitHub 仓库中检查和直接执行:github.com/brinkar/real-world-machine-learning。
分类到数值的转换技术适用于大多数机器学习算法。但有一些算法(如某些类型的决策树算法和相关算法,如随机森林)可以原生地使用分类特征。对于高度分类的数据集,这通常会得到更好的结果,我们将在下一章进一步讨论这一点。在将分类特征转换为二进制特征后,我们的简单 Person 数据集如图 2.6 所示。
图 2.6. 将分类婚姻状态特征转换为二进制数值特征后的简单 Person 数据集。(原始数据集显示在 图 2.4 中。)

2.2.2. 处理缺失数据
你已经看到了一些包含缺失数据的示例数据集。在表格数据集中,缺失数据通常表现为空单元格,或包含 NaN(非数字)、N/A 或 None 的单元格。缺失数据通常是数据收集过程中的一个副产品;由于某种原因,对于某个数据实例,特定的值无法被测量。图 2.7 展示了泰坦尼克号乘客数据集中缺失数据的示例。
图 2.7. 泰坦尼克号乘客数据集中的年龄和船舱列存在缺失值。乘客信息是从各种历史来源中提取的,因此在这种情况下,缺失值源于在来源中找不到的信息。

缺失数据主要有两种类型,你需要以不同的方式处理它们。首先,对于某些数据,数据缺失的事实可能携带着对机器学习算法有用的有意义信息。另一种可能性是,数据缺失仅仅是因为其测量是不可能的,信息的不可用本身并没有其他意义。例如,在泰坦尼克号乘客数据集中,例如,船舱列中的缺失值可能表明那些乘客处于较低的社会或经济阶层,而年龄列中的缺失值则不携带任何有用的信息(当时特定乘客的年龄根本无法找到)。
让我们先考虑信息性缺失数据的情况。当你认为数据中缺少信息时,你通常希望机器学习算法能够利用这些信息来潜在地提高预测准确性。为了实现这一点,你希望将缺失值转换为与列中一般格式相同。对于数值列,这可以通过将缺失值设置为-1 或-999 来完成,具体取决于非空值的典型值。在数值谱的一端选择一个数字来表示缺失值,并记住顺序对数值列很重要。你不希望选择分布中间的值。
对于具有潜在信息性缺失数据的分类列,你可以创建一个名为“缺失”、“None”或类似的新的类别,然后以通常的方式处理分类特征(例如,使用上一节中描述的技术)。图 2.8 展示了处理有意义的缺失数据的一个简单示意图。
图 2.8. 如何处理有意义的缺失数据

当数据项缺失的值本身没有信息价值时,你将采取不同的方法。在这种情况下,你不能引入一个特殊的数字或类别,因为你可能会引入完全错误的数据。例如,如果你将泰坦尼克号乘客数据集中年龄列的任何缺失值更改为-1,你可能会因为没有任何理由而破坏年龄分布而损害模型。一些机器学习算法能够通过忽略这些真正的缺失值来处理这些缺失值。如果不能,你需要预处理数据,要么消除缺失值,要么通过猜测真实值来替换它们。这种替换缺失数据的概念被称为插补。
如果你的数据集很大,但缺失值只有少数几个,那么删除带有缺失数据的观测值是最简单的方法。但是,当你的观测值中有较大一部分包含缺失值时,删除观测值中丢失的完美数据将降低你模型的预测能力。此外,如果带有缺失值的观测值在数据集中不是随机分布的,这种方法可能会引入意外的偏差。
另一种简单的方法是假设数据实例具有某种时间顺序,并用前一行列的值替换缺失值。在没有其他信息的情况下,你是在猜测一个测量值从一个实例到下一个实例没有变化。不用说,这个假设通常是不正确的,但比例如用零填充缺失值要正确得多,尤其是如果数据是一系列连续观测(昨天的温度不是对今天温度的不合理估计)。对于极其庞大的数据,你并不总是能够应用更复杂的方法,而这些简单的方法可能是有用的。
当可能时,通常更好的做法是使用现有数据的一部分来猜测缺失值。你可以通过替换缺失的列值来使用该列的平均值或中位数。在没有其他信息的情况下,你假设平均值最接近真实值。根据列值的分布,你可能想使用中位数;平均值对异常值敏感。这些方法在今天的机器学习中广泛使用,并且在许多情况下效果良好。但是,当你将所有缺失值设置为单个新值时,你会减少潜在的相关性可见性,这些相关性对于算法检测数据中的某些模式可能很重要。
如果您能做的话,您想做的就是使用您所能利用的所有数据来预测缺失变量的值。这听起来熟悉吗?这正是机器学习的核心,所以您基本上是在考虑构建 ML 模型,以便能够构建 ML 模型。在实践中,您通常会使用简单的算法(如线性或逻辑回归,在第三章中描述)来填补缺失数据。这不一定与主 ML 算法相同。无论如何,您正在创建一个 ML 算法的管道,它引入了更多的旋钮来最终优化模型。
再次强调,处理真正缺失数据没有唯一最佳方法。我们已经在本节中讨论了几种方法,图 2.9 总结了可能性。
图 2.9。为 ML 建模准备数据时处理缺失值的完整决策图。

2.2.3。简单特征工程
第五章 讨论了特定领域和高级特征工程技术,但为了使模型更好,值得提及简单数据预处理的基本思想。
您将在本节中再次使用泰坦尼克号示例。图 2.10 展示了数据的一部分,特别是客舱功能。未经处理,客舱功能不一定有用。一些值似乎包含多个客舱,甚至单个客舱也不太可能是一个好的分类特征,因为所有客舱都会是分开的“桶”。如果您想预测,例如,某个乘客是否幸存,住在特定客舱而不是相邻客舱可能没有任何预测能力。
图 2.10。在泰坦尼克号乘客数据集中,一些客舱值包含多个客舱,而另一些则缺失。而且客舱标识符本身可能不是好的分类特征。

然而,住在船的特定部分对于生存可能很重要。对于单个客舱 ID,您可以提取字母作为分类特征,数字作为数值特征,假设它们代表船的不同部分。您甚至可以找到泰坦尼克号的布局图,并将每个客舱映射到船的楼层和侧面,面向海洋还是内部,等等。这些方法不处理多个客舱 ID,但由于看起来所有多个客舱都彼此靠近,因此仅提取第一个客舱 ID 应该足够。您还可以将客舱数量包含在一个新特征中,这也可能相关。
总的来说,您将从 Cabin 功能中创建三个新功能。以下列表显示了这种简单提取的代码。
列表 2.2。泰坦尼克号客舱的简单特征提取。
def cabin_features(data):
features = []
for cabin in data:
cabins = cabin.split(" ")
n_cabins = len(cabins)
# First char is the cabin_char
try:
cabin_char = cabins[0][0]
except IndexError:
cabin_char = "X"
n_cabins = 0
# The rest is the cabin number
try:
cabin_num = int(cabins[0][1:])
except:
cabin_num = -1
# Add 3 features for each passanger
features.append( [cabin_char, cabin_num, n_cabins] )
return features
到现在为止,我们所说的特征工程的含义应该不再令人惊讶:使用现有的特征来创建新的特征,通过应用我们对数据或相关领域的知识,从而提高原始数据的价值。如前所述,你将研究高级特征工程概念和大多数算法需要处理的常见数据类型。这些包括用于网页或推文的自由格式文本特征。其他重要的特征也可以从图像、视频和时间序列数据中提取。
2.2.4. 数据归一化
一些机器学习算法需要数据被归一化,这意味着每个单独的特征都已经被处理,使其位于相同的数值尺度上。一个特征的价值范围可以影响该特征相对于其他特征的重要性。如果一个特征的价值在 0 到 10 之间,而另一个特征的价值在 0 到 1 之间,那么第一个特征的重要性是第二个特征的 10 倍。有时你可能想要强制设置特定的特征权重,但通常让机器学习算法确定特征的相对权重会更好。为了确保所有特征都被同等考虑,你需要对数据进行归一化。通常,数据会被归一化到 0 到 1 的范围,或者从-1 到 1 的范围。
让我们考虑这种归一化是如何进行的。以下代码示例实现了这个函数。对于每个特征,你希望数据分布在最小值(通常是-1)和最大值(通常是+1)之间。为了实现这一点,你需要将数据除以数据的总范围,以便将数据放入 0-1 的范围。从这里,你可以通过乘以这个转换后的值来重新扩展到所需的范围(在-1 到+1 的情况下是 2)。最后,你将起点从 0 移动到所需的最小值(例如,-1)。
列表 2.3. 特征归一化
def normalize_feature(data, f_min=-1.0, f_max=1.0):
d_min, d_max = min(data), max(data)
factor = (f_max - f_min) / (d_max - d_min)
normalized = f_min + (data - d_min)*factor
return normalized, factor
注意,你需要返回归一化的数据和用于归一化的因子。你这样做是因为任何新的数据(例如,用于预测)都必须以相同的方式进行归一化,才能得到有意义的结果。这也意味着机器学习模型构建者将不得不记住特定特征是如何归一化的,并保存相关的值(因子和最小值)。
我们将实现一个函数的任务留给你,该函数接受新的数据、归一化因子和归一化的最小值,并重新应用归一化。
当你扩展你的数据处理工具集并探索各种数据时,你会发现每个数据集都有其独特的品质,使其变得独特且通常具有挑战性。但是,具有许多变量的大量数据很难通过查看表格表示来完全理解。图形数据可视化工具对于理解你希望从中提取隐藏信息的数据至关重要。
2.3. 使用数据可视化
在数据收集/预处理和机器学习模型构建之间,数据可视化是一个重要的步骤。在深入机器学习的机制和预测之前,数据可视化充当了对训练特征和目标变量的合理性检查。通过简单的可视化技术,你可以开始探索输入特征与输出目标变量之间的关系,这将指导你在模型构建中的工作,并帮助你理解机器学习模型和预测。此外,可视化技术可以告诉你训练集的代表性和可能缺乏的实例类型。
本节重点介绍可视化目标变量与输入特征之间关联的方法。我们推荐四种可视化技术:约束图、箱线图、密度图和散点图。每种技术适用于不同类型(数值或分类)的输入特征和目标变量,如图 2.11 所示。
图 2.11. 按输入特征和要绘制的响应变量类型排列的四种可视化技术

进一步阅读
有许多书籍致力于统计可视化和数据绘图。如果你想要深入了解这个主题,请查看以下内容:
-
经典教科书《定量信息的视觉展示》由 Edward Tufte(Graphics Press,2001)所著,详细介绍了数据可视化的分析和展示方法。
-
对于 R 用户来说,Winston Chang(O’Reilly,2013)所著的《R Graphics Cookbook》涵盖了 R 中的数据可视化,从基础知识到高级主题,并提供了代码示例以供参考。
-
对于 Python 用户,Igor Milovanović、Dimitry Foures 和 Giuseppe Vettigli(Packt Publishing,2015)所著的《Python Data Visualization Cookbook》涵盖了从基础知识到使用 Matplotlib 运行的内容。
2.3.1. 约束图
约束图 允许你可视化两个或更多分类变量之间的关系。用于约束图的绘图软件在 R、SAS、Python 以及其他科学或统计编程语言中都有提供。
为了展示约束图的应用,你将使用它来显示乘客性别与泰坦尼克号乘客数据集中生存率之间的关系。约束图从一个边长为 1 的正方形开始。然后,通过垂直线将正方形分割成一系列矩形,其宽度对应于属于输入特征每个类别的数据比例。例如,在泰坦尼克号数据中,24% 的乘客是女性,因此你将单位正方形沿 x 轴分割成两个矩形,其面积宽度为 24% / 76%。
接下来,每个垂直矩形被水平线分割成子矩形,这些子矩形的相对面积与响应变量每个类别的实例百分比成比例。例如,在泰坦尼克号上的女性乘客中,74%幸存(这是在乘客为女性的条件概率)。因此,女性矩形被水平线分割成两个子矩形,包含矩形面积的 74% / 26%。对男性矩形(男性中,比例是 19% / 81%)也进行相同的处理。
这结果是一个关于性别与生存关系的快速可视化。如果没有关系,水平分割将在 y 轴上的相似位置发生。如果存在强烈的关系,水平分割将相隔甚远。为了增强可视化效果,矩形被着色编码以评估关系的统计显著性,与输入特征和响应变量的独立性相比,负残差较大(“低于预期计数”)被深灰色着色,正残差较大(“高于预期计数”)被浅灰色着色;参见图 2.12。
图 2.12. 展示性别与泰坦尼克号生存关系的马赛克图。可视化显示,与性别独立于生存预期相比,女性的幸存比例要高得多(男性的幸存比例要小得多)。“妇女和儿童优先。”

这说明,在构建一个用于预测泰坦尼克号生存情况的机器学习模型时,性别是一个重要的因素需要考虑。它还允许你对性别与生存之间的关系进行合理性检查:确实,众所周知,女性在这次灾难中幸存的比例更高。这为你提供了额外的保证,确保你的数据是合法的。这样的数据可视化也有助于你在模型构建后解释和验证你的机器学习模型。
图 2.13 展示了另一个关于生存与乘客等级(头等舱、二等舱和三等舱)的马赛克图。正如预期的那样,头等舱乘客的幸存比例更高(三等舱乘客的幸存比例更低)。显然,乘客等级也是预测生存的机器学习模型中的一个重要因素,关系正好如你所预期:等级更高的乘客有更高的生存概率。
图 2.13. 展示乘客等级与泰坦尼克号生存关系的马赛克图

2.3.2. 箱线图
箱线图 是一种标准的统计绘图技术,用于可视化数值变量的分布。对于一个单一变量,箱线图描绘了其分布的 四分位数:最小值、25 百分位数、中位数、75 百分位数和最大值。单一变量的箱线图可视化有助于深入了解其值分布的中心、离散度和偏度,以及是否存在任何异常值。
你还可以使用箱线图来比较在平行图中绘制的分布。特别是,它们可以用来可视化数值特征随分类响应变量的各种类别变化的分布差异。回到泰坦尼克号的例子,你可以通过使用平行箱线图来可视化幸存者和死亡者的年龄差异,如图 2.14 所示。在这种情况下,幸存者和死亡者的乘客年龄分布之间似乎没有明显的差异,因为两个箱线图在形状和位置上看起来相当相似。
图 2.14. 箱线图展示了乘客年龄与泰坦尼克号幸存率之间的关系。幸存者和死亡者的年龄分布之间没有明显的差异。(这本身 不应该是 排除年龄作为机器学习模型因素的理由,因为它可能仍然是一个预测因素。)

认识到可视化技术的局限性是很重要的。可视化不能替代机器学习建模!机器学习模型可以发现并利用数据深处隐藏的微妙关系,这些关系不适合通过简单的可视化来揭示。你不应该自动排除那些可视化没有显示出与目标变量明确关联的特征。这些特征在与其他输入特征一起使用时,可能仍然与目标变量有强烈的关联。例如,尽管年龄与生存率之间没有显示出明显的关联,但可能对于三等舱乘客来说,年龄是一个重要的预测因素(也许对于三等舱乘客,年轻且强壮的乘客比年长的乘客更容易到达船的甲板)。一个好的机器学习模型将发现并揭示这种关系,因此,可视化本身并不旨在排除年龄作为一个特征。
图 2.15 展示了探索乘客票价与生存结果之间关系的箱线图。在左侧面板中,很明显,支付票价的分布高度偏斜(许多小值和一些大异常值),这使得差异难以可视化。通过票价(在右侧面板中为平方根)的简单转换,可以解决这个问题,使得差异易于发现。支付票价与生存状态有明显的关联:支付更高票价的人更有可能生存,正如预期的那样。因此,票价金额应该包含在模型中,因为你期望机器学习模型能够发现并利用这种正相关关系。
图 2.15. 展示乘客票价与泰坦尼克号生存之间关系的箱线图。平方根转换使得显而易见,幸存下来的乘客平均支付了更高的票价。

2.3.3. 密度图
现在,我们将转向数值型响应变量,而不是分类型响应变量。当输入变量是分类型时,你可以使用箱线图来可视化两个变量之间的关系,就像你在前一节中所做的那样。你还可以使用密度图。
密度图比箱线图更详细地显示了单个变量的分布。首先,估计变量的概率分布的平滑估计(通常使用称为核平滑的技术)。接下来,该分布被绘制为曲线,表示变量可能具有的值。通过为输入特征所采取的每个类别创建响应变量的单个密度图,你可以轻松地可视化响应变量值在分类输入特征差异中的任何差异。请注意,密度图与直方图类似,但它们的平滑特性使得在单个图中可视化多个分布变得简单得多。
在下一个例子中,你将使用 Auto MPG 数据集.^([2]) 该数据集包含 1970-82 年间大量汽车每加仑行驶里程(MPG),以及每辆汽车的属性,包括马力、重量、产地和车型年份。图 2.16 展示了 MPG 与产地(美国、欧洲或亚洲)的密度图。从图中可以看出,亚洲汽车的平均 MPG 较高,其次是欧洲汽车,然后是美国汽车。因此,产地应该是我们模型中的一个重要预测因子。此外,每个曲线在密度图中都有几个次级“峰值”,这可能与不同类型的汽车(例如,卡车与轿车与混合动力车)有关。因此,有必要对这些次级峰值进行额外探索,以了解其本质,并作为进一步特征工程指南。
²
Auto MPG 数据集可在
archive.ics.uci.edu/ml/datasets/Auto+MPG获取,并在 R 编程语言中是标准的,通过输入data (mtcars)。
图 2.16. Auto MPG 数据集的密度图,显示了每个制造商地区的车辆每加仑英里数的分布。从图中可以看出,亚洲汽车往往具有最高的每加仑英里数,而美国制造的汽车每加仑英里数最低。地区显然是每加仑英里数的强指标。

2.3.4. 散点图
散点图是两个数值变量之间关系的简单可视化,是现存最受欢迎的绘图工具之一。在散点图中,特征值与响应变量的值相对应,每个实例用一个点表示。虽然简单,但散点图可以揭示输入变量和响应变量之间的线性关系和非线性关系。
图 2.17 展示了两个散点图:一个是汽车重量与每加仑英里数的关系,另一个是汽车型号年份与每加仑英里数的关系。在两种情况下,输入特征与汽车的每加仑英里数之间存在明显的关系,因此两者都应用于建模。在左面板中,数据呈现出明显的香蕉形状,表明随着车辆重量的增加,每加仑英里数呈非线性下降。同样,右面板显示了每加仑英里数与型号年份之间的增加的线性关系。两个图表都清楚地表明,输入特征在预测每加仑英里数时是有用的,并且两者都具有预期的关系。
图 2.17. 车辆每加仑英里数与车辆重量(左)和车辆型号年份(右)的关系散点图

2.4. 摘要
在本章中,你已经在现实世界的机器学习背景下了解了数据的重要方面:
-
编译训练数据的步骤包括以下内容:
-
决定包含哪些输入特征
-
确定如何获得目标变量的真实值
-
确定何时收集了足够的训练数据
-
注意是否存在有偏或非代表性的训练数据
-
-
训练数据的预处理步骤包括以下内容:
-
重新编码分类特征
-
处理缺失数据
-
特征归一化(对于某些机器学习方法)
-
特征工程
-
-
四种有用的数据可视化包括散点图、密度图、箱线图和散点图:
![]()
我们的模型数据准备就绪后,现在让我们开始构建机器学习模型!
2.5. 本章术语
| 单词 | 定义 |
|---|---|
| 虚拟变量 | 一个二元特征,表示一个观测值是否属于某个类别 |
| 真实值 | 训练集或测试集中已知的目标变量或标签的值 |
| 缺失数据插补 | 对于实例子集的未知值,用数值或分类值替换缺失数据的未知值 |
第三章. 建模与预测
本章涵盖
-
通过机器学习建模发现数据中的关系
-
使用模型进行预测和推理
-
构建分类模型
-
构建回归模型
前一章介绍了数据收集、预处理和可视化的指南和原则。机器学习工作流程的下一步是利用这些数据开始探索和揭示输入特征与目标之间存在的关系。在机器学习中,这个过程是通过基于数据建立统计模型来完成的。本章涵盖了理解机器学习建模和开始构建自己的模型所需的基本知识。与大多数机器学习教科书不同,我们花费很少的时间讨论机器学习建模的各种方法,而是专注于大局概念。这将帮助您获得对机器学习模型构建的广泛理解,并快速掌握构建自己的模型以解决现实世界问题的技能。对于那些寻求有关特定机器学习建模技术更多信息的人,请参阅附录。
我们从对统计建模的高级概述开始本章。这次讨论侧重于机器学习建模的大局概念,例如模型的目的、模型在实际中的应用方式,以及现有建模技术类型及其相对优缺点简要概述。从那里,我们深入探讨两种最常用的机器学习模型:分类和回归。在这些部分中,我们提供了更多关于如何在您的数据上构建模型的信息。我们还通过本章中散布的“算法亮点”框,强调了实践中常用的几个常见算法。
3.1. 基本机器学习建模
机器学习的目标是发现数据中的模式和关系,并将这些发现应用于实践。这一发现过程是通过使用在过去 30 年中在统计学、计算机科学和应用数学中开发的建模技术来实现的。这些各种方法可以从简单到极其复杂,但它们都有一个共同的目标:估计输入特征与目标变量之间的函数关系。
这些方法也共享一个共同的流程,如图 3.1 所示:使用历史数据构建和优化模型,然后反过来使用该模型根据新数据进行预测。本节为您准备本章后面部分的实际内容。您将在下一节中查看机器学习建模的一般目标,然后继续了解最终产品如何使用以及区分不同机器学习算法的一些重要方面。
图 3.1. 基本机器学习工作流程

3.1.1. 寻找输入与目标之间的关系
让我们围绕一个示例来讨论机器学习建模。回想一下第二章中的 Auto MPG 数据集章节 2。该数据集包含有关汽车的各种指标,例如制造商地区、车型年份、车辆重量、马力和气缸数。该数据集的目的是了解输入特征与车辆每加仑英里数(MPG)评级之间的关系。
输入特征通常用符号 X 表示,当存在多个输入特征时,下标用于区分输入。例如,我们将 X[1]表示为制造商地区,X[2]表示为车型年份,X[3]表示为车辆重量,等等。所有输入特征的集合被称为粗体X。同样,目标变量通常被称为 Y。
输入 X 和输出 Y 之间的关系可以用这个简单的公式简洁地表示:

在这个方程中,f 代表与输入变量相关联的目标变量 Y 的未知函数。机器学习建模的目标是通过使用数据来准确估计 f。符号€代表与函数 f 无关的数据中的随机噪声。函数 f 通常被称为信号,而随机变量€被称为噪声。机器学习的挑战是使用数据来确定真正的信号是什么,同时忽略噪声。
在 Auto MPG 示例中,函数 f 描述了汽车的真实每加仑英里数(MPG)评级作为该汽车众多输入特征的一个函数。如果你完全了解这个函数,你就可以知道任何汽车(无论是真实的还是虚构的)的 MPG 评级。但是,你可能会有许多噪声源,€,包括(但不仅限于)以下内容:
-
由于测量设备中的微小不准确造成的每辆车的 MPG 评级的不完美测量——测量噪声
-
制造过程中的变化,导致车队中的每辆车的 MPG 测量值略有不同——制造过程噪声
-
输入特征测量中的噪声,例如重量和马力
-
无法访问确切确定 MPG 的更广泛的特征集
使用你从数百辆车辆中获得的噪声数据,机器学习方法是通过建模技术找到 f 的良好估计。这个结果估计被称为机器学习模型。
在第 3.2 节和 3.3 节中,我们更详细地描述了这些机器学习建模技术是如何工作的。实际上,机器学习的大部分学术文献都涉及如何最好地估计 f。
3.1.2. 寻找好模型的目的
假设你有一个对 f 的良好估计,接下来是什么?机器学习有两个主要目标:预测和推理。
预测
在你有一个模型之后,你可以通过将这些新特征插入模型来生成对新数据的目标 Y 的预测,X[new]。用数学符号表示,如果 f[est]表示你对 f 的机器学习估计(回想一下,f 表示特征与目标之间的真实关系),那么通过将新数据插入此公式可以获得对新数据的预测:
Y[pred] = fest
这些预测可以用来对新数据做出决策,或者可能被输入到自动化工作流程中。
回到 Auto MPG 示例,假设你有一个机器学习模型 f[est],它描述了 MPG 与汽车输入指标之间的关系。预测能力允许你提出这样的问题:“已知输入指标的特定汽车的 MPG 是多少?”这种预测能力对于设计汽车非常有用,因为它允许工程师评估不同设计概念的 MPG 评级,并确保各个概念满足 MPG 要求。
预测是机器学习系统最常见的使用方式。预测是许多机器学习用例的核心,包括以下这些:
-
解析手写数字或语音录音
-
预测股市
-
预测
-
预测哪些用户最有可能点击、转化或购买
-
预测哪些用户需要产品支持以及哪些用户可能会取消订阅
-
确定哪些交易是欺诈的
-
提供建议
由于机器学习方法达到了高预测准确率,以及 ML 预测可以快速生成,因此成千上万的公司在预测目的上每天都在使用 ML。
推理
除了对新数据进行预测外,你还可以使用机器学习模型更好地理解输入特征与输出目标之间的关系。对 f 的良好估计能够帮助你回答关于手头变量之间关联的深入问题。例如:
-
哪些输入特征与目标变量最密切相关?
-
这些关系是正向的还是负向的?
-
f 是一个简单的关系,还是一个更微妙和非线性的函数?
这些推理可以告诉你很多关于数据生成过程的信息,并为数据中关系驱动因素提供线索。回到 Auto MPG 示例,你可以使用推理来回答这些问题:制造商地区对 MPG 有影响吗?哪些输入与 MPG 最密切相关?它们是负相关还是正相关?对这些问题的回答可以给你一个关于汽车 MPG 驱动因素的概念,并为你提供如何设计更高 MPG 车辆的线索。
3.1.3. 建模方法类型
现在是时候拂去你的统计知识灰尘,深入探讨机器学习建模的一些数学细节了。别担心——我们将保持讨论相对广泛和易于理解,即使对于那些没有太多统计背景的人来说也是如此!
统计建模在预测准确性和模型可解释性之间有一个普遍的权衡。简单的模型容易解释,但不会产生准确的预测(尤其是对于复杂的关系)。复杂的模型可能会产生准确的预测,但可能是黑盒且难以解释。
此外,机器学习模型主要有两种类型:参数和非参数。本质区别在于参数模型假设 f 采用特定的函数形式,而非参数模型则不做这样的严格假设。因此,参数方法通常简单且可解释,但准确性较低。同样,非参数方法在广泛的问题上通常可解释性较低但准确性更高。让我们更详细地看看参数和非参数方法在机器学习建模中的应用。
参数方法
参数方法的简单例子是线性回归。在线性回归中,假设 f 是输入数值的线性组合。标准的线性回归模型如下:
f(X) = β[0] + X[1] × β[1] + X[2] × β[2] + ...
在这个方程中,未知参数 β[0]、β[1]、... 可以解释为截距和斜率参数(相对于每个输入)。当你将参数模型拟合到某些数据时,你估计每个未知参数的最佳值。然后你可以将这些估计值代入 f(X) 的公式中,并加入新数据以生成预测。
常用的参数模型的其他例子包括逻辑回归、多项式回归、线性判别分析、二次判别分析、(参数)混合模型和朴素贝叶斯(当使用参数密度估计时)。在模型选择目的上常与参数模型结合使用的方法包括岭回归、lasso 和主成分回归。关于这些方法的一些更详细信息将在本章后面给出,每种方法的描述将在附录中提供。
参数方法的缺点是它们对函数 f 的真实形式做出了强烈的假设。在大多数现实世界的问题中,f 不假设这种简单的形式,尤其是在有多个输入变量(X)的情况下。在这些情况下,参数方法将数据拟合得不好,导致预测不准确。因此,大多数现实世界的机器学习方法依赖于非参数机器学习方法。
非参数方法
在非参数模型中,f 不采用简单的、固定的函数。相反,f 的形式和复杂性会适应数据的复杂性。例如,如果 X 和 Y 之间的关系是曲折的,非参数方法会选择一个匹配曲线模式的函数 f。同样,如果输入变量和输出变量之间的关系是平滑的,将选择一个简单的函数 f。
非参数模型的一个简单例子是分类树。分类树是一系列关于输入特征的递归二进制决策。分类树学习算法使用目标变量来学习最优的分割序列,使得树的终端叶节点包含具有相似目标值的实例。
以泰坦尼克号乘客数据集为例。分类树算法首先寻找最佳的输入特征进行分割,使得结果叶节点包含要么大部分生存要么大部分死亡的乘客。在这种情况下,最佳的分割是乘客的性别(男性/女性)。算法继续在每个子节点上对其他输入特征进行分割,直到算法无法再检测到任何好的后续分割。
分类树是非参数的,因为树的深度和复杂性不是预先固定的,而是从数据中学习得到的。如果目标变量与输入特征之间的关系复杂,并且有足够的数据量,那么树将生长得更深,揭示出更细微的模式。图 3.2 展示了从不同的泰坦尼克号乘客数据集子集中学习到的两个分类树。在左侧面板中,是从只有 400 名乘客中学习到的树:得到的模型很简单,只包含一个分割。在右侧面板中,是从 891 名乘客中学习到的树:更多的数据量使得模型能够增加复杂性,并在数据中找到更详细的模式。
图 3.2. 决策树是非参数机器学习算法的一个例子,因为它的函数形式不是固定的。树模型可以随着数据量的增加而增加复杂性,以捕捉更复杂的模式。在树的每个终端节点中,比例代表该节点中死亡与生存的训练实例数。

非参数机器学习方法的其他例子包括 k 近邻、样条、基函数展开方法、核平滑、广义加性模型、神经网络、Bagging、Boosting、随机森林和支持向量机。同样,关于这些方法的一些更详细的内容将在本章后面给出,每种方法的描述将在附录中提供。
3.1.4. 监督学习与无监督学习
机器学习问题可以分为两大类:监督学习和无监督学习。监督学习问题是指对于一组训练数据,你可以访问目标变量,而无监督学习问题是指没有明确的目标变量。
本书迄今为止的所有示例都属于监督学习范畴。这些问题每个都包含一个感兴趣的目标(泰坦尼克号乘客是否幸存?客户是否流失?MPG 是多少?)以及一组具有目标已知值的训练数据。实际上,机器学习中的大多数问题本质上是监督性的,大多数机器学习技术都是设计用来解决监督学习问题的。我们在这本书的大部分内容中描述了如何解决监督学习问题。
在无监督学习中,你只能访问输入特征,没有相关的目标变量。如果没有任何目标可用,你能进行哪些类型的分析?无监督学习方法有两个主要类别:
-
聚类—— 使用输入特征来发现数据中的自然分组,并将数据划分为这些组。方法:k-means、高斯混合模型和层次聚类。
-
降维—— 将输入特征转换为少数坐标,这些坐标可以捕捉到数据的大部分变异性。方法:主成分分析(PCA)、多维缩放和流形学习。
聚类和降维(尤其是 k-means 和 PCA)非常受欢迎,但在需要监督方法的情况下,它们往往被滥用和不恰当地使用。
但无监督问题在机器学习中确实扮演着重要的角色,通常在支持监督问题方面发挥作用,要么帮助编译学习所需的数据,要么推导出新的输入特征以进行学习。你将在第八章返回无监督学习的话题。
现在,让我们转向机器学习建模的更实际方面。接下来,我们将描述开始在自己的数据上构建模型所需的步骤,以及选择使用哪种算法的实际考虑。我们将本章的其余部分分为两个部分,对应于机器学习中最常见的两个问题:分类和回归。我们首先从分类这个主题开始。
3.2. 分类:预测到桶中
在机器学习中,分类描述了使用机器学习算法构建的分类器将新数据预测到桶(类别)中的过程。例如,垃圾邮件检测器将电子邮件放入垃圾邮件和非垃圾邮件桶中,手写数字识别器将图像放入从 0 到 9 的桶中。在本节中,你将学习如何根据手头的数据构建分类器。图 3.3 说明了分类的过程。
图 3.3。一个分类过程。矩形和圆形被分类器分为 A 和 B 两类。这是一个只有两个类别的二元分类案例。

让我们再次用一个例子来说明。在第二章中,你研究了泰坦尼克号乘客数据集,以预测船上乘客的生存情况。图 3.4 显示了这些数据的一个子集。
图 3.4. 泰坦尼克号乘客数据集的一个子集

如我们之前讨论的,通常开始一个机器学习项目的最佳方式是通过可视化数据来感受数据。例如,普遍认为女性比男性在泰坦尼克号上幸存的可能性更大,你可以从图 3.5 中的频率图中看到这一点(如果你忘记了频率图,请回顾第 2.3.1 节)。
图 3.5. 频率图显示女性比男性在灾难中幸存的可能性更大。

通过使用第 2.3 节中的可视化技术,你可以感受到泰坦尼克号乘客数据集中每个特征的表现。但重要的是要意识到,仅仅因为单个特征看起来好或不好,并不意味着它与其他一个或多个特征结合时能表现出该特征的性能。也许年龄与性别和社会地位的结合比任何单个特征都能更好地划分乘客。实际上,这正是最初使用机器学习算法的主要原因之一:寻找人类难以轻易发现的多个维度上的信号。
下面的子节介绍了构建分类模型和进行预测的方法。你将了解一些具体的算法以及线性算法和非线性算法之间的区别。
3.2.1. 构建分类器并进行预测
首要任务是选择用于构建分类器的分类算法。有许多算法可供选择,每种算法针对不同的数据和部署需求都有其优缺点。附录提供了一个算法表及其特性的比较。你将在本书中通过这个表来选择尝试不同问题的算法。在本节中,算法的选择不是必要的;在下一章,你将学习如何正确衡量算法的性能并选择最适合的算法。
下一步是为建模准备数据。在探索数据集的一些特征之后,你可能想要预处理数据以处理分类特征、缺失值等问题(如第二章中所述)。预处理需求也取决于特定的算法,附录中列出了每个算法的需求。
对于泰坦尼克号生存模型,你将首先选择一个简单的分类算法:逻辑回归.^([1]) 对于逻辑回归,你需要做以下几步:
¹
逻辑回归中的回归并不意味着它是一个回归算法。逻辑回归通过逻辑函数扩展线性回归,使其适合分类。
-
填充缺失值。
-
扩展分类特征。
-
从第二章中,你知道票价特征严重倾斜。在这种情况下,将变量转换为使特征分布更加对称,并减少异常值可能产生的有害影响是有利的(对于某些机器学习模型)。在这里,你将选择通过开平方根来转换票价。
你将用于建模的最终数据集在图 3.6 中显示。
图 3.6。在处理分类特征和缺失值,并将票价变量通过开平方根转换后的泰坦尼克号乘客数据集的前五行(参见源代码仓库中的prepare_data函数)。所有特征现在都是数值型,这是大多数机器学习算法首选的格式。

现在,你可以通过运行数据通过逻辑回归算法来构建模型。该算法在 scikit-learn Python 包中实现,模型构建和预测代码如下所示。
列表 3.1。使用 scikit-learn 构建逻辑回归分类器

在构建模型后,你可以根据乘客的特征预测之前未见过的乘客的生存情况。模型期望的特征格式如图 3.6 所示,因此任何新的乘客都必须经过与训练数据完全相同的处理过程。predict函数的输出将为 1,如果预测乘客幸存,否则为 0。
通过绘制决策边界来可视化分类器是有用的。图 3.7 展示了根据模型,使用数据集中的两个特征(年龄和票价平方根)来区分幸存乘客和死亡乘客的边界。
图 3.7。年龄和票价平方根特征的决策边界。菱形表示幸存乘客,而圆圈表示死亡乘客。浅色背景表示预测为生存的年龄和票价的组合。请注意,一些实例与边界重叠。分类器并不完美,但你只考虑了两个维度。在完整数据集上的算法在 10 个维度上找到这个决策边界,但可视化变得更加困难。

算法重点:逻辑回归
在这些“算法亮点”框中,您将更深入地了解本书中使用的算法背后的基本思想。这允许好奇的读者尝试编写,通过一些额外的研究,算法的基本工作版本。尽管我们主要关注本书中现有包的使用,但了解特定算法的基本原理有时对于完全实现预测潜力很重要。
您将首先查看的算法是逻辑回归算法,这可能是用于分类任务的最简单的机器学习算法。将问题视为只有两个特征并且数据集分为两类是有帮助的。图 3.7 展示了示例,其中特征为年龄和 sqrt(Fare);目标是幸存或死亡。为了构建分类器,您希望找到将数据最佳地分割成目标类别的线。二维中的一条线可以用两个参数来描述。这两个数字是您需要确定的模型参数。
算法随后包括以下步骤:
-
您可以通过随机选择参数值来开始搜索,因此在二维图中放置一条随机线。
-
测量这条线如何将两个类别分开。在逻辑回归中,您使用统计的偏差来衡量拟合优度。
-
估计参数的新值并测量其分离能力。
-
重复此过程,直到没有更好的猜测。这是一个优化过程,可以使用多种优化算法来完成。梯度下降是简单优化算法中的一种流行选择。
这种方法可以扩展到更多维度,因此您在这个模型中不必局限于两个特征。如果您对细节感兴趣,我们强烈建议您进一步研究并尝试在您选择的编程语言中实现此算法。然后查看广泛使用的机器学习包中的实现。我们省略了很多细节,但前面的步骤仍然是算法的基础。
逻辑回归的一些特性包括以下内容:
-
与更复杂的算法相比,该算法相对容易理解。它也是计算上简单的,这使得它可以扩展到大型数据集。
-
如果需要高度非线性的决策边界来分离类别,性能将下降。参见第 3.2.2 节。
-
逻辑回归算法有时会过度拟合数据,您通常需要使用一种称为正则化的技术来限制这种风险。参见第 3.2.2 节中的过度拟合示例。
进一步阅读
如果您想了解更多关于逻辑回归及其在现实世界中的应用,请查看 David Hosmer 等人所著的应用逻辑回归(Wiley,2013 年)。
3.2.2. 对复杂、非线性数据进行分类
观察到图 3.7,你可以理解为什么逻辑回归是一个线性算法:决策边界是一条直线。当然,你的数据可能不会很好地被直线分开,因此对于这样的数据集,你应该使用非线性算法。但非线性算法通常在计算上要求更高,并且不适合大规模数据集。你将在第八章中进一步了解各种类型算法的可扩展性。
再次查看附录,你可以选择一个非线性算法来建模泰坦尼克号乘客数据集。对于非线性问题,一个流行的方法是使用具有非线性核的支持向量机。支持向量机本质上是线性的,但通过使用核,这个模型变成了一个强大的非线性方法。你可以在代码清单 3.1 中更改一行代码来使用这个新算法,并且决策边界在图 3.8 中绘制:
from sklearn.svm import SVC as Model
图 3.8. 带有非线性核的泰坦尼克号生存支持向量机分类器的非线性决策边界。浅色背景表示预测为生存的年龄和船票的组合。

你可以看到图 3.8 中的决策边界与图 3.7 中的线性决策边界不同。这里你看到的是机器学习中的一个重要概念:过拟合的例子。算法能够很好地拟合数据,几乎在单个记录级别,你可能会失去对新数据做出良好预测的能力,这些新数据没有包含在训练集中;你允许模型变得越复杂,过拟合的风险就越高。
通常,你可以通过使用算法内建的模式参数来避免非线性模型的过拟合。通过调整模型的参数,保持数据不变,你可以获得更好的决策边界。请注意,你目前正使用直觉来判断何时出现过拟合;在第四章中,你将学习如何使用数据和统计学来量化这种直觉。现在,你将使用(作者们的)经验并调整一个称为gamma的参数。你目前不需要知道 gamma 是什么,只需知道它有助于控制过拟合的风险。在第五章中,你将看到如何仅通过猜测更好的值来优化模型参数。在 SVM 分类器中将 gamma 设置为 0.1,你将获得如图 3.9 所示的决策边界的大幅改进。
图 3.9. 带有 gamma = 0.1 的非线性 RBF 核 SVM 的决策边界

算法亮点:支持向量机
支持向量机(SVM)算法是线性和非线性问题的流行选择。它具有一些有趣的理论和实践特性,使其在许多场景中非常有用。
该算法背后的主要思想,就像之前讨论的逻辑回归一样,是找到最优地分离类别的线(或更高维度的等价物)。SVMs 试图找到仅位于决策线两侧的点之间的最大间隔,而不是测量所有点到线的距离。想法是,没有必要担心那些很好地位于边界内的点,只有那些接近边界的点。在下面的图像中,你可以看到线 H[1]和 H[2]是糟糕的分离边界,因为到线两侧最近点的距离不是最大的。H[3]是最佳线。

SVM 决策边界(H[3])通常优于其他机器学习算法找到的决策边界。
虽然这个算法在某种意义上也是线性的,因为分离边界是线性的,但 SVMs 能够拟合非线性数据,正如你在这部分前面看到的。SVMs 使用一种巧妙的技术来拟合非线性数据:核技巧。核是一种数学结构,可以“扭曲”数据所在的空间。然后算法可以在扭曲的空间中找到一个线性边界,使得边界在原始空间中是非线性的。
进一步阅读
关于机器学习算法的书已经写了数百本,涵盖了从它们的理论基础和高效实现到它们实际应用的所有内容。如果你在寻找对这些主题更严谨的处理,我们推荐两本关于机器学习算法的经典著作:
-
《统计学习基础:数据挖掘、推理和预测》由特里弗·哈斯蒂等人(Springer,2009 年)著。
-
《模式识别与机器学习》由克里斯托弗·贝斯希(Springer,2007 年)著。
3.2.3. 多类别分类
到目前为止,你只看到了两类的分类。在某些情况下,你将会有超过两个类别。多类别分类的一个好的现实世界例子是手写数字识别问题。每当你给家人寄老式邮件时,机器人会读取手写的 ZIP 代码并确定信件的去向,而在这一过程中良好的数字识别是至关重要的。一个公开的数据集,MNIST 数据库,^([2])可用于研究这类问题。这个数据集包含 60,000 个手写数字的图像。图 3.10 展示了其中的一些手写数字图像。
²
你可以在
yann.lecun.com/exdb/mnist/找到手写数字的 MNIST 数据库。
图 3.10. 从 MNIST 数据库中随机选择的四个手写数字

每个图像都是 28 × 28 像素,但我们把每个图像转换成 28² = 784 个特征,每个像素一个特征。除了是一个多类问题外,这也是一个高维问题。算法需要找到的是许多这些特征的复杂组合,并且这个问题本质上是非线性的。
要构建分类器,你首先需要从附录中选择要使用的算法。列表中第一个原生支持多类问题的非线性算法是 k-最近邻分类器,这是另一种简单但强大的非线性机器学习建模算法。你只需要在列表 3.1 中更改一行来使用新算法,但你还需要包含一个用于获取完整预测概率而不是仅获取最终预测的函数:
from sklearn.neighbors import KNeighborsClassifier as Model
def predict_probabilities(model, new_features):
preds = model.predict_proba(new_features)
return preds
构建 k-最近邻分类器并对图 3.10 中显示的四个数字进行预测,你将获得图 3.11 中显示的概率表。
你可以看到,对数字 1 和 3 的预测非常准确,对数字 4 的预测只有很小的(10%)不确定性。看第二个数字(3),它难以完美分类并不奇怪。这正是最初获取完整概率的主要原因:能够对那些不是完全确定的事情采取行动。在邮局机器人分拣信件的情况下,这很容易理解;如果机器人对某些数字的确定性足够低,那么在我们将其发送出去之前,也许我们应该让一个好人先看看它。
图 3.11。k-最近邻分类器应用于 MNIST 数据集的预测概率表

算法亮点:k-最近邻算法
k-最近邻算法是一种简单但强大的非线性机器学习方法。它通常在模型训练需要快速进行,但预测通常较慢的情况下使用。你很快就会看到这是为什么。
基本思想是,你可以通过将新数据记录与训练集中的相似记录进行比较来对新的数据记录进行分类。如果一个数据集记录由一组数字n[i]组成,你可以通过通常的距离公式找到记录之间的距离:

当对新记录进行预测时,你找到最近的已知记录,并将该类别分配给新记录。这将是一个 1-最近邻分类器,因为你只使用最近的邻居。通常你会使用 3、5 或 9 个邻居,并选择在邻居中最常见的类别(你使用奇数以避免平局)。
训练阶段相对较快,因为你为已知记录索引以快速计算新数据之间的距离。预测阶段是大部分工作所在的地方,即从整个数据集中找到最近的邻居。
之前的简单示例使用了常用的欧几里得距离度量。你也可以根据数据集使用更高级的距离度量。
K-最近邻不仅对分类有用,对回归也有用。你不仅取邻居中最常见的类别,还取邻居的目标值的平均值或中位数。第 3.3 节进一步详细介绍了回归。
3.3. 回归:预测数值
并非每个机器学习问题都是关于将记录放入类别中。有时目标变量取数值——例如,在金融模型中预测美元价值时。我们将预测数值的行为称为回归,而模型本身称为回归器。图 3.12 说明了回归的概念。
图 3.12. 在这个回归过程中,回归器正在预测一条记录的数值。

作为回归分析的例子,你将使用第二章中介绍的汽车燃油效率数据集。目标是构建一个模型,可以预测汽车的平均每加仑英里数,给定汽车的属性,如马力、重量、产地和车型年份。图 3.13 显示了这些数据的一个小子集。
图 3.13. 汽车燃油效率数据的小子集

在第二章中,你发现了燃油效率(MPG)评级、汽车重量和车型年份之间的有用关系。这些关系在图 3.14 中展示。
图 3.14. 使用散点图,你可以看到车辆重量和车型年份对于预测 MPG 是有用的。更多详情请见第二章。

在下一节中,你将了解如何构建一个基本的线性回归模型来预测这些车辆数据集的每加仑英里数。在成功构建基本模型之后,你将了解用于建模非线性数据的更高级算法。
3.3.1. 构建回归器并进行预测
再次,你将首先选择一个算法来使用,并将数据格式化为合适的格式。线性回归算法可以说是最简单的回归算法。正如其名所示,这是一个线性算法,附录显示了使用此算法所需的数据预处理。你需要(1)填补缺失值和(2)扩展分类特征。我们的汽车燃油效率数据集没有缺失值,但有一个分类列:产地。在扩展产地列(如第二章中的第 2.2.1 节所述)之后,你将获得图 3.15 中所示的数据格式。
图 3.15. 扩展 Origin 列后的汽车燃油效率数据

你现在可以使用该算法来构建模型。再次,你可以使用代码清单 3.1 中定义的代码结构,并更改此行:
from sklearn.linear_model import LinearRegression as Model
拿到模型后,你可以进行预测。然而,在这个例子中,在构建模型之前,你需要将数据集分成训练集和测试集。在第四章中,你将学习更多关于如何评估模型的知识,但在这个部分你将使用一些简单的技术。通过在仅使用部分数据训练模型的同时保留测试集,你可以在测试集上进行预测,并查看你的预测与实际值有多接近。如果你在所有数据上训练并在部分训练数据上做出预测,那么你就是在作弊,因为模型在训练时看到数据更有可能做出好的预测。
图 3.16 展示了在保留测试集上进行预测的结果,以及它们与已知值的比较。在这个例子中,你使用 80%的数据来训练模型,并使用剩余的 20%进行测试。
图 3.16. 将保留测试集中的 MPG 预测值与实际值进行比较

比较多个预测值的一个有用方法是再次使用我们的好朋友,散点图。对于回归问题,实际的目标值和预测值都是数值。在第二章中介绍的散点图中,将预测值相互对比,你可以可视化预测值如何跟随实际值。这可以在图 3.17 中看到的保留测试集的 Auto MPG 测试集中展示。此图显示了出色的预测性能,因为所有预测值都接近最优的对角线。通过观察此图,你可以了解你的机器学习模型在新数据上可能的表现。在这种情况下,对于更高的 MPG 值的一些预测似乎被低估了,这可能对你是有用的信息。例如,如果你想提高估计高 MPG 值的能力,你可能需要找到更多高 MPG 车辆的例子,或者你可能需要在这个范围内获得更高质量的数据。
图 3.17. 实际值与预测值在保留测试集中的散点图。对角线表示完美的回归器。所有预测值都接近这条线,则模型越好。

算法亮点:线性回归
就像用于分类的逻辑回归一样,线性回归可以说是构建回归模型最简单且最广泛使用的算法。其主要优势是线性可扩展性和高度的可解释性。
此算法将数据集记录绘制为点,目标变量位于 y 轴上,并将一条直线(或平面,如果有两个或更多特征)拟合到这些点上。以下图示了优化点到模型直线距离的过程。

线性回归如何确定最佳拟合线的演示。在这里,深色线是此数据集上的最佳线性回归拟合线,它相对于任何其他可能的线(如图中所示虚线所示)具有更小的均方偏差。
在二维空间中,一条直线可以用两个参数来描述,以此类推。你知道这个,从基本的数学公式 y = a × x + b 中的 a 和 b。这些参数与数据拟合,当优化后,它们完全描述了模型,并且可以用来对新数据进行预测。
3.3.2. 对复杂、非线性数据进行回归
在某些数据集中,特征之间的关系无法用线性模型来拟合,如果需要准确预测,线性回归算法可能不适用。其他属性,如可扩展性,可能使得降低准确性成为必要的权衡。此外,非线性算法不一定更准确,因为你可能会过度拟合数据。作为一个非线性回归模型的例子,我们介绍了随机森林算法。随机森林是用于高度非线性问题且准确性很重要的一种流行方法。正如附录中所示,它也很容易使用,因为它需要的数据预处理最少。在图 3.18 和 3.19 中,你可以看到通过随机森林模型对 Auto MPG 测试集进行预测的结果。
图 3.18. 非线性随机森林回归模型中实际与预测 MPG 值的表格

图 3.19. 非线性随机森林回归模型中 MPG 数据与预测值的比较

这个模型与线性算法在视觉上并没有太大的区别。在准确性方面,哪个算法表现最好并不明显。在下一章中,你将学习如何量化性能(通常称为模型的准确度得分),这样你就可以对预测准确度进行有意义的测量。
算法亮点:随机森林
作为本章最后一个算法亮点,我们介绍了随机森林(RF)算法。这个高度准确的非线性算法在现实世界的分类和回归问题中得到了广泛应用。
RF 算法的基础是决策树。想象一下,你需要就某事做出决定,比如下一步做什么。一些变量可以帮助你决定最佳的行动方案,而一些变量的权重高于其他变量。在这种情况下,你可能会首先问,“这能让我赚多少钱?”如果答案是少于 10 美元,你可以选择不继续这项任务。如果答案是超过 10 美元,你可能会在决策树中提出下一个问题,“从事这项工作会让我快乐吗?”并回答是或否。你可以继续构建这个树,直到你得出结论并选择一个任务来工作。
决策树算法让计算机根据训练集确定哪些变量是最重要的,并将它们放在树的顶部,然后逐渐使用不那么重要的变量。这使得它能够结合变量并说,“如果金额大于 10 并且让我开心,而且工作量少于 1 小时,那么就是。”
决策树的一个问题是树的顶层对答案有巨大影响,如果新数据没有遵循与训练集完全相同的分布,泛化能力可能会受到影响。这就是随机森林方法出现的地方。通过构建决策树集合,你可以降低这种风险。在做出答案时,在分类的情况下选择多数投票,在回归的情况下取平均值。由于你使用投票或平均值,你也可以以自然的方式返回完整的概率,这是许多算法所不具备的。
随机森林还以其其他优点而闻名,例如对不重要特征的免疫力、缺失值方面的噪声数据集以及错误标记的记录。
3.4. 摘要
在本章中,我们介绍了机器学习建模。以下是我们从本章中获得的主要收获:
-
模型的目的是描述输入特征与目标变量之间的关系。
-
你可以使用模型来为新数据(其目标未知)生成预测,或者推断数据中存在的真实关联(或不存在)。
-
机器学习建模有数百种方法。其中一些是参数化的,这意味着将特征与目标相关联的数学函数的形式在事先是固定的。参数化模型通常比非参数方法更易于解释,但准确性较低,而非参数方法更灵活,可以适应特征与目标之间关系的真实复杂性。由于它们高度的预测准确性和灵活性,非参数方法受到大多数机器学习实践者的青睐。
-
机器学习方法进一步分为监督学习和无监督学习。监督学习方法需要一个包含已知目标的训练集,而无监督学习方法不需要目标变量。本书的大部分内容都致力于监督学习。
-
监督学习中最常见的两个问题是分类,其中目标是分类的,和回归,其中目标是数值的。在本章中,你学习了如何构建分类和回归模型,以及如何使用它们对新数据进行预测。
-
你还更深入地研究了分类问题。线性算法可以定义类之间的线性决策边界,而非线性方法在数据不能线性分离时是必需的。使用非线性模型通常具有更高的计算成本。
-
与分类(其中预测的是分类目标)相反,在回归模型中预测的是数值目标变量。你看到了线性和非线性方法的例子以及如何可视化这些模型的预测。
3.5. 本章术语
| 词 | 定义 |
|---|---|
| 模型 | 使用机器学习算法在训练数据上得到的基产品。 |
| 预测 | 通过将新数据通过模型进行预测来执行预测。 |
| 推理 | 通过构建模型并不仅仅进行预测来获取对数据的洞察。 |
| (非)参数 | 参数模型对数据的结构做出假设。非参数模型则不做出假设。 |
| (无)监督 | 监督模型,如分类和回归,寻找输入特征和目标变量之间的映射。无监督模型用于在数据中寻找模式,而不需要指定的目标变量。 |
| 聚类 | 一种无监督学习方法,将数据放入自定义的簇中。 |
| 维度降低 | 另一种无监督学习方法,可以将高维数据集映射到低维表示,通常用于在二维或三维中进行绘图。 |
| 分类 | 一种预测数据到桶中的监督学习方法。 |
| 回归 | 一种预测数值目标值的监督方法。 |
在下一章中,你将学习创建和测试模型,这是机器学习的精彩部分。你将看到你的算法和特征选择是否能够解决当前的问题。你还将了解如何严格验证模型,以查看其预测在新数据上可能有多好。你还将了解用于评估模型性能的验证方法、指标和一些有用的可视化方法。
第四章. 模型评估和优化
本章涵盖
-
使用交叉验证来正确评估模型的预测性能
-
过拟合及其避免方法
-
标准二元和多类分类的评估指标和可视化方法
-
标准回归模型的评估指标和可视化方法
-
通过选择最佳参数来优化你的模型
在你拟合了一个机器学习模型之后,下一步是评估该模型的准确性。在你能够将模型投入使用之前,你需要知道它在新的数据上预测的效果如何。如果你确定预测性能相当好,你可以在生产环境中部署该模型来分析新数据。同样,如果你评估预测性能不足以完成当前任务,你可以回顾你的数据和模型,尝试改进和优化其准确性。(本章的最后部分介绍了简单的模型优化方法。第五章、第七章和第九章介绍了更复杂的提高机器学习模型预测准确性的方法。)
正确评估机器学习模型的预测性能是一项非同小可的任务。我们本章首先介绍统计上严格的评估机器学习模型预测性能的技术,通过图表和伪代码演示如何正确验证模型。
从那里,我们深入探讨机器学习分类模型的评估,重点关注机器学习从业者常用的典型评估指标和图形工具。然后,我们介绍回归模型的类似评估工具。最后,我们描述了一种通过参数调整来优化模型预测性能的简单方法。
到本章结束时,你将具备评估你在第三章中构建的机器学习模型的预测准确性的手段和知识,以及优化这些模型以实现预测准确性的方法(参见图 4.1)。这种模型评估提供了你需要的信息,以确定你构建的模型是否足够好,或者是否需要进一步的优化。
图 4.1. 机器学习工作流程中的评估和优化

4.1. 模型泛化:评估新数据的预测准确性
监督机器学习的主要目标是准确的预测。你希望你的机器学习模型在预测新数据(目标变量未知)时尽可能准确。换句话说,你希望从训练数据构建的模型能够很好地泛化到新数据。这样,当你将模型部署到生产环境中时,你可以确信生成的预测结果是高质量的。
因此,当你评估模型的表现时,你想要确定“该模型在新数据上的表现如何”。这个看似简单的任务充满了复杂性和陷阱,即使是经验最丰富的机器学习用户也可能感到困惑。本节描述了评估机器学习模型时出现的困难,并提出了一个简单的流程来克服这些问题,以实现模型性能的无偏估计。
4.1.1. 问题:过拟合和模型乐观
要描述与估计模型预测准确度相关的挑战,从例子开始最容易。
想象一下,你想要预测一个农场每英亩玉米产量作为使用一种新农药处理的种植面积比例的函数。你为此回归问题有 100 个农场的训练数据。当你绘制目标(每英亩玉米产量)与特征(农场处理的百分比)之间的关系时,很明显存在一个增加的非线性关系,并且数据也存在随机波动(见图 4.2)。
图 4.2. 玉米产量回归问题的训练数据包含明显的信号和噪声。

现在,假设你想要使用一种简单的非参数机器学习回归建模技术来构建一个玉米产量作为土地处理比例的函数的预测模型。最简单的机器学习回归模型之一是核平滑。核平滑通过取局部平均值来操作:对于每个新的数据点,目标变量的值被建模为仅与新的数据点的特征值相近的训练数据的目标变量值的平均值。一个称为带宽参数的单个参数控制局部平均的窗口大小。
图 4.3 展示了核平滑带宽参数各种值时的情况。对于带宽参数的大值,几乎所有的训练数据都被平均在一起来预测目标,对于每个输入参数的每个值。这导致模型变得平坦,并且欠拟合训练数据中的明显趋势。同样,对于带宽参数的小值,每个特征值处的模型输出仅使用一个或两个训练实例来确定。因此,模型实际上追踪了数据中的每一个波峰和波谷。这种对数据内在噪声而不是真实信号的建模敏感性被称为过拟合。你想要达到的是在金发姑娘区域:既不过度欠拟合,也不过度过拟合。
图 4.3. 核平滑回归模型对玉米产量训练集的三次拟合。对于带宽参数的小值,模型过拟合,导致模型过于崎岖。对于带宽参数的大值,模型欠拟合,导致模型过于平坦。合适的调整参数选择会导致看起来恰到好处的拟合。

现在,让我们回到手头的问题:确定你的机器学习模型将如何泛化以预测来自不同农场的玉米产量数据。这个过程的第一步是选择一个评估指标,该指标可以捕捉你预测的质量。对于回归,评估的标准指标是均方误差(MSE),它是目标变量的真实值与模型预测值之间平均平方差的度量(在本章的后面,你将了解回归和分类的其他评估指标)。
这就是事情变得复杂的地方。在训练集上评估,随着带宽参数的减小,我们模型预测的错误(用 MSE 衡量)会越来越小。这是预期的:你允许模型越灵活,它在追踪训练数据中的模式(信号和噪声)方面做得越好。但是,具有最小带宽的模型对训练数据严重过拟合,因为它们追踪训练集中的每一个随机波动。使用这些模型来预测新数据会导致预测精度差,因为新数据将具有其独特的随机噪声特征,这些特征与训练集中的不同。
因此,训练集错误和机器学习模型的泛化错误之间出现了差异。这种差异在图 4.4 中的玉米产量数据中得到了例证。对于带宽参数的小值,训练集上评估的 MSE 非常小,而新数据(在这种情况下,10,000 个新实例)上的 MSE 要大得多。简单来说,在训练集上评估的模型预测的性能并不能表明该模型在新数据上的性能。因此,在用于训练模型的数据上评估模型的性能是危险的。
图 4.4。玉米产量回归问题中训练集错误与新数据错误的比较。训练集错误是衡量新数据模型性能的一个过于乐观的指标,尤其是对于带宽参数的小值。将训练集错误用作新数据预测错误的替代指标将给你带来很多麻烦。

关于双重使用训练数据的警告
使用训练数据既用于模型拟合又用于评估可能会导致你对模型的性能过于乐观。这可能导致你最终选择一个次优模型,该模型在预测新数据时表现不佳。
如你在玉米产量数据中看到的,选择具有最小训练集均方误差(MSE)的模型会导致选择具有最小带宽的模型。在训练集上,此模型产生的 MSE 为 0.08。但是,当应用于新数据时,相同的模型产生的 MSE 为 0.50,这比最优模型(带宽=0.12 和 MSE=0.27)差得多。
你需要一个更好的评估指标,它能更好地近似模型在新数据上的性能。这样,当你将模型部署到新数据上进行预测时,你可以对模型的准确性有信心。这是下一小节的主题。
4.1.2. 解决方案:交叉验证
我们已经诊断了模型评估中的挑战:当应用于新数据时,训练集错误并不能指示模型错误。为了得到新数据错误率的良好估计,你必须使用一种更复杂的方法,称为交叉验证(通常缩写为CV),该方法严格使用训练集来评估新数据上的准确性。
交叉验证中最常用的两种方法是保留方法和 k 折交叉验证。
保留方法
使用相同的训练数据来拟合和评估模型的准确性会产生过于乐观的准确性指标。解决这个问题最简单的方法是使用独立的训练集和测试集。你只使用训练集来拟合模型,而只使用测试集来评估模型的准确性。
这种方法被称为保留方法,因为从训练过程中保留了一个随机子集的训练数据。从业者通常将 20-40%的数据作为测试集。描述了保留方法的基本算法流程,列表 4.1 提供了 Python 伪代码。
图 4.5. 交叉验证的保留方法的流程图。

列表 4.1. 使用保留方法的交叉验证

现在,让我们将保留方法应用于玉米产量数据。对于带宽参数的每个值,你应用保留方法(使用 70/30 的分割)并计算保留的 30%数据的预测 MSE。图 4.6 展示了保留方法估计的 MSE 如何与新数据上应用的模型 MSE 相比较。两个主要的事情很突出:
-
保留方法计算的错误估计接近模型的新数据误差。它们当然比训练集错误估计(图 4.4)要接近得多,尤其是对于小带宽值。
-
保留误差估计是嘈杂的。与代表新数据错误的平滑曲线相比,它们波动很大。
图 4.6. 使用玉米产量数据集比较保留误差 MSE 与新数据上的 MSE。保留误差是每个模型在新数据上误差的无偏估计。但它是一个嘈杂的估计器,在最佳模型(带宽=0.12)附近的带宽中波动很大,介于 0.14 和 0.40 之间。

你可以通过重复进行随机训练-测试分割并平均结果来降低噪声。但是,在多次迭代中,每个数据点将被分配到测试集的不同次数,这可能会对结果产生偏差。
一种更好的方法是进行 k 折交叉验证。
K 折交叉验证
一种更好但计算量更大的交叉验证方法是k 折交叉验证。与保留法类似,k 折交叉验证在训练过程中依赖于隔离训练数据的一部分。主要区别在于,k 折 CV 首先将数据随机分为k个不相交的子集,称为folds(k 的典型选择是 5、10 或 20)。对于每个 folds,使用除了该 folds 数据之外的所有数据进行模型训练,并随后使用该模型对该 folds 的数据进行预测。
在所有 k 折都经过循环后,将每个 folds 的预测汇总并与其真实目标变量进行比较,以评估准确性。图 4.7 说明了 k 折交叉验证,列表 4.2 提供了伪代码。
图 4.7. k 折交叉验证流程图

最后,让我们将 k 折交叉验证应用于玉米产量数据。对于带宽参数的每个值,你使用 k=10 进行 k 折交叉验证,并在预测上计算交叉验证 MSE。图 4.8 展示了 k 折交叉验证 MSE 估计与应用于新数据时模型 MSE 的关系。显然,k 折交叉验证误差估计接近模型在未来的数据上的误差。
图 4.8. 使用玉米产量数据集比较 k 折交叉验证误差 MSE 与新数据上的 MSE。k 折 CV 误差是评估模型在新数据上表现的一个很好的估计,允许你自信地预测模型的误差并选择最佳模型。

列表 4.2. 使用 k 折交叉验证的交叉验证

4.1.3. 使用交叉验证时需要注意的一些事项
交叉验证为你提供了一种估计你的机器学习模型在野外部署时的预测准确性的方法。这非常强大,因为它使你能够为你的任务选择最佳模型。
但是,当你将交叉验证应用于实际数据时,需要注意以下几点:
-
交叉验证方法(包括保留法和 k 折法)假设训练数据构成了感兴趣人群的代表性样本。如果你计划将模型部署到预测新数据,那么这些数据应该由训练数据很好地表示。如果不是这样,交叉验证误差估计可能对未来的数据误差率过于乐观。解决方案:确保解决并最小化训练数据中的任何潜在偏差。
-
一些数据集使用时间序列特征——例如,使用上个月的收入来预测这个月的收入。如果你的数据是这样的,你必须确保未来可用的特征永远不能用来预测过去。解决方案:你可以构建交叉验证的保留集或 k 折,以确保所有训练集数据都在测试集之前收集。
-
在 k 折交叉验证中使用更多的折数,误差估计将更好,但你的程序运行时间会更长。解决方案:当你能的时候,至少使用 10 折(或更多)。对于训练和预测速度快的模型,你可以使用留一法交叉验证(k = 数据实例数)。
接下来,你将在此基础上构建交叉验证工具,并深入探讨如何对分类模型进行严格的模型评估。
4.2. 分类模型的评估
我们通过介绍只有两个类别的例子来开始对评估分类模型的讨论,这也被称为二元分类。第三章介绍了在机器学习中,二元分类是一种基于许多因素或变量的强大方法,用于预测正/负结果。二元分类的一个好例子是疾病检测或生存预测。
假设你想根据个人、社会和经济因素预测泰坦尼克号乘客是否会幸存。你会收集关于乘客的所有信息,并训练一个可以将所有这些信息与他们的生存概率相关联的分类器。你第一次看到这个例子是在第二章,但泰坦尼克号乘客数据集的前五行再次在图 4.9 中展示。
图 4.9。泰坦尼克号乘客数据集的前五行。目标列指示乘客是否在船沉没中幸存或死亡。

要构建你的分类器,你需要将这个数据集输入到分类算法中。因为这个数据集包含不同类型的数据,你必须确保算法知道如何处理这些类型。正如前几章所讨论的,你可能需要在训练模型之前处理数据,但在这个章节中,你将把分类器视为一个黑盒,它已经学会了从输入变量到目标变量的映射。本节的目标是评估模型,以优化预测准确率并与其他模型进行比较。
数据准备就绪后,你将进入下一个任务:交叉验证。你需要将整个数据集分成训练集和测试集,并使用交叉验证的保留法。模型将在训练集上构建并在保留的测试集上评估。重要的是要重申,你的目标不一定是在训练数据上获得最大的模型准确率,而是要在未见过的数据上获得最高的预测准确率。在模型构建阶段,根据定义,你还没有掌握这些数据,所以你假装一些训练数据对学习算法是隐藏的。
图 4.10 说明了这个特定示例中的数据分割步骤。
图 4.10. 将整个数据集分成训练集和测试集,可以让你评估模型。

准备好训练集后,你可以构建分类器并在测试集上进行预测。按照图 4.5 的保留法,你将获得一系列预测值:对于测试集中的所有行,值为 0(死亡)或 1(存活)。然后你进入评估工作流程的第 3 步,将这些预测值与实际存活值进行比较,以获得一个可以优化的性能指标。
分类模型的简单性能度量是计算正确答案的分数;如果四行中有三行被正确预测,那么你可以说该模型在这个特定验证集上的准确率是 3/4 = 0.75,或 75%。图 4.11 说明了这个结果。以下几节将介绍进行这种比较的更复杂的方法。
图 4.11. 将测试集预测值与实际值进行比较,可以得到模型的准确率。

4.2.1. 按类别准确率和混淆矩阵
预测提供的信息比仅仅是正确或错误更多。例如,你可以分析每个类别的准确率(预测存活但实际上死亡或存活的人数)。对于二元分类,你可以以两种方式出错:预测 0 而正确值是 1,或者预测 1 而正确值是 0。同样,你也可以以两种方式正确。 图 4.12 说明了这一点。
图 4.12. 计算按类别准确率和错误率可以为你提供有关模型准确率的更多信息。

在许多分类问题中,除了简单的计数准确率之外,查看这种按类别准确率或类别混淆情况是有用的。结果显示,将这些四个数字显示在一个称为混淆矩阵的二维图中非常有用,如图图 4.13 所示。
图 4.13. 将按类别准确率组织到混淆矩阵中

矩阵中的每个元素都显示了正负类之间的分类准确度或混淆。 将 图 4.13 中的特定混淆矩阵与接收器操作特征(ROCs)的一般概念联系起来,这是你在本书的其余部分广泛应用的。虽然这些术语一开始可能有点令人困惑,但当你与其他人谈论你模型的性能时,它们将变得很重要。

展示了排序概率向量和设置 0.7 阈值的过程。现在所有高于这条线的行都被预测为生存,你可以将它们与实际标签进行比较,以获得在此特定阈值下的混淆矩阵和 ROC 指标。如果你为从 0 到 1 的所有阈值都遵循这个过程,你定义了ROC 曲线,如 图 4.16 所示。
到目前为止,你只看了输出为预测类别的预测;在我们的泰坦尼克号例子中,1 表示生存,否则为 0。机器学习预测通常包含一定的不确定性,许多分类算法不仅输出零一预测,还输出完整的预测概率。例如,在我们的泰坦尼克号模型中简单地预测为生存的实例可能具有 0.8、0.99 或 0.5 的生存概率。很明显,这些答案的置信度有很大的差异,在本节中,你将利用这些信息更详细地评估你的模型。
概率分类器的输出就是我们所说的概率向量或类别概率。对于测试集中的每一行,你都会为分类器中的每个类别得到一个从 0 到 1 的实数值(总和为 1)。到目前为止,你通过考虑大于 0.5 的概率来确定类别预测,并据此计算上一节中所有性能指标。我们说确定类别的阈值是 0.5。很明显,你可以选择任何其他阈值,并会得到所有指标的不同值。

4.2.2. 准确度权衡和 ROC 曲线
从 图 4.16 中,你可以读出所有阈值点的混淆矩阵,这使得 ROC 曲线在评估分类器性能时成为一个强大的可视化工具。给定任何交叉验证过程中的真实和预测标签,ROC 曲线按照 列表 4.3 中的方法计算。
图 4.16. 通过计算从 0 到 1 的 100 个阈值点的混淆矩阵和 ROC 指标定义的 ROC 曲线。按照惯例,你在 x 轴上绘制假阳性率,在 y 轴上绘制真阳性率。

列表 4.3. ROC 曲线

如果你跟随 ROC 曲线,你会看到当假阳性率增加时,真阳性率会降低。这种权衡是机器学习的“没有免费午餐”,因为你能够为了获得更高的正确性而牺牲你正确分类的实例比例,反之亦然,这取决于你选择的概率阈值参数。
在现实场景中,这种权衡可能非常重要,需要评估。如果你正在分类一个患者是否有癌症,将几个额外的健康患者错误地分类为患病患者,并避免将任何患病患者错误地分类为健康患者,会更好。因此,你会选择一个可以最小化假阴性率的阈值,从而最大化真阳性率,并将你尽可能放置在 ROC 图表的顶部,同时牺牲假阳性率。
另一个很好的例子是垃圾邮件过滤器,你需要在你收件箱中显示不想要的电子邮件或把想要的电子邮件放入垃圾邮件文件夹之间做出选择。或者信用卡公司检测欺诈活动——你更愿意经常给客户发出虚假警报,还是冒着错过潜在欺诈交易的风险?
除了权衡信息之外,ROC 曲线本身也提供了对分类器整体性能的视图。一个完美的分类器不会有假阳性也不会有漏检,所以曲线会推向左上角,如图 图 4.17 所示。这自然引导我们到另一个评估指标:ROC 曲线下方的面积(AUC)。这个面积越大,分类性能越好。AUC 是评估和比较模型时广泛使用的选择,尽管在大多数情况下,检查完整的 ROC 曲线对于理解性能权衡非常重要。你将在本书的其余部分使用 ROC 曲线和 AUC 评估指标来验证分类模型。
图 4.17. ROC 曲线说明了整体模型性能。你可以通过定义 AUC 指标来量化这一点:ROC 曲线下方的面积。这个面积越大,分类性能越好。AUC 是评估和比较模型时广泛使用的选择,尽管在大多数情况下,检查完整的 ROC 曲线对于理解性能权衡非常重要。你将在本书的其余部分使用 ROC 曲线和 AUC 评估指标来验证分类模型。

列表 4.4. ROC 曲线下方的面积

4.2.3. 多类分类
到目前为止,你只看过二进制或双类别的分类问题,但幸运的是,你可以使用许多相同的工具来处理多类分类器。一个著名的多类分类问题就是手写数字识别。我们时不时都会发送实体邮件,有很大可能性在这个过程中已经使用了机器学习算法来确定你的信件的终点地址。如果你的字迹像我们一样,这听起来像是一个巨大的挑战,但这样的自动化系统已经由邮政服务使用了几十年。
由于机器学习在手写数字识别上的早期成功,这个例子在 ML 文献中一直被用作多类分类性能的基准。想法是扫描手写数字,并将它们分成每个图像中有一个字母的图像。然后你使用图像处理算法或在原始灰度像素上构建一个多类分类器来预测数字。图 4.18 显示了名为 MNIST 的手写数字数据集的一些示例。
图 4.18. MNIST 数据集中的手写数字。整个数据集包含 80,000 个这样的数字,每个数字都是一个 28 x 28 像素的图像。没有任何图像处理,我们的数据集的每一行都包含一个已知的标签(0 到 9)和 784 个特征(每个 28 x 28 像素一个)。

你使用随机森林算法(在第三章中介绍)从训练集构建一个分类器,并从保留的测试集生成混淆矩阵。记住,你只处理过二类分类的混淆矩阵。幸运的是,你可以轻松地为多个类别定义它,因为矩阵中的每个元素都是行上的类别与列上的类别。对于 MNIST 分类器,你可以在图 4.19 中看到,大部分的力量都位于矩阵的对角线上,正如它应该的那样,因为它显示了每个数字被正确分类的实例数量。最大的非对角元素显示了分类器最困惑的地方。检查这个图,你可以看到最大的混淆发生在数字 4 和 9、3 和 5、以及 7 和 9 之间,这符合你对数字形状的了解。
图 4.19. 10 类 MNIST 手写数字分类问题的混淆矩阵

以矩阵形式显示类别准确率的原因是为了利用我们出色的视觉能力来处理更多信息。在图 4.19 中,你可以清楚地看到如何通过对比度增强混淆矩阵来利用这种能力。
那么,如何为多类分类器生成 ROC 曲线呢?原则上,ROC 曲线仅适用于二元分类问题,因为你在预测中将类别分为正类和负类,以便获得 ROC 曲线轴上常用的如真正例率(true-positive rate)和假正例率(false-positive rate)等 ROC 指标。为了在多类问题中模拟二元分类,你使用一对多技巧。对于每个类别,你将特定类别标记为正类,其余所有类别作为负类,然后像往常一样绘制 ROC 曲线。运行 MNIST 分类器进行此过程得到的 10 个 ROC 曲线如图 4.20 所示。最准确分类的数字是 0 和 1,这与图 4.19 中的混淆矩阵一致。然而,混淆矩阵是由最可能的类别预测生成的,而 ROC 曲线则显示了类别在所有概率阈值下的性能。
图 4.20。使用一对多方法模拟二元分类问题时,MNIST 10 类分类器每个类别的 ROC 曲线。请注意,由于分类器非常出色,我们已将 ROC 曲线的右上角放大,以便观察不同类别之间模型性能的差异。每个类别的 AUC 都进行了计算,并且整体模型表现良好。

然而,请注意,多类 ROC 曲线并不在曲线上显示整个混淆矩阵。原则上,在 ROC 曲线的每个点上都有一个完整的 10 x 10 混淆矩阵,但我们无法以足够简单的方式可视化这一点。在多类情况下,因此重要的是要查看混淆矩阵和 ROC 曲线。
4.3. 回归模型的评估
你已经在之前的章节中查看过回归模型。通常,回归是用于预测数值结果(如整数或浮点值)的模型的术语。对于回归,你使用本节中介绍的不同性能指标集。
你将使用在第二章中首次介绍的 Auto MPG 数据集作为本节的工作示例。图 4.21 显示了该数据集的一个小子集。你将此数据集通过所有必要的数据转换(有关数据转换的更多信息,请参阅第 2.2 节),并选择一个适当模型,如第二章和第三章中讨论的那样。在这种情况下,你感兴趣的是测量模型性能。
图 4.21。Auto MPG 数据集的一个子集

使用本章开头介绍的基模型评估工作流程,您使用数据和所选算法构建一个交叉验证的回归模型。在以下各节中介绍了在此过程中使用的潜在模型性能指标,但 图 4.22 展示了基于这些指标的回归性能的最基本可视化:预测值与实际值之间的散点图。
图 4.22. 测试集中预测 MPG 与实际值的散点图。对角线表示最佳模型。

4.3.1. 使用简单的回归性能指标
与分类模型不同,回归没有简单的 正确 预测的概念。数值预测通常不太可能完全正确,但它可以是 接近 或 远离 正确值。这也是正确值含义本质的后果,因为我们通常认为数值测量是从具有称为 误差 的不确定程度的分布中抽取的。本节介绍了两个简单的指标来衡量回归性能:均方根误差(MSE 的平方根)和 R² 值。
回归模型性能的最简单测量方法是 均方根误差,或称 RMSE。这个估计量查看每个预测值与已知值之间的差异,并以一种不受预测值可能高于或低于实际值这一事实影响的方式计算平均值。图 4.23 展示了 RMSE 的计算过程。
图 4.23. RMSE 计算:在方程中,y[i] 和 x[i] 分别表示第 i 个目标和特征向量,而 f(x) 表示将模型应用于特征向量,返回预测的目标值。

为了鼓励更好地理解 RMSE 计算的细节,以下列表展示了一段代码片段。
列表 4.5. 均方根误差
def rmse(true_values, predicted_values):
n = len(true_values)
residuals = 0
for i in range(n):
residuals += (true_values[i] – predicted_values[i])**2.
return np.sqrt(residuals/n)
RMSE 的优点是结果与自身值具有相同的单位,但这也意味着 RMSE 值依赖于问题的规模,因此在不同数据集之间不容易进行比较。如果预测值或实际值是较大的数字,RMSE 将相应地更高。尽管在比较同一项目中的模型时这不是问题,但理解整体模型性能并将其与其他模型进行比较可能是一个挑战。
为了克服这一点,通常计算 R² 或 R² 指标也是值得的,其响应是相对的,并且始终在 0–1 范围内。如果模型可以更好地预测数据,R² 值将更接近 1。以下列表展示了 R² 计算的更多细节。
列表 4.6. R² 计算方法
def r2(true_values, predicted_values):
n = len(true_values)
mean = np.mean(true_values)
residuals = 0
total = 0
for i in range(n):
residuals += (true_values[i] – predicted_values[i])**2.
total += (true_values[i] – mean)**2.
return 1.0 – residuals/total
无论使用 MSE、RMSE 还是 R²作为评估指标,你都应该始终记住以下几点:
-
总是使用交叉验证来评估模型。如果不这样做,随着模型复杂性的增加,指标总是会提高,导致过拟合。
-
在可能的情况下,评估指标应该与手头的问题相一致。例如,如果从汽车特征预测 MPG,RMSE 为 5 意味着你期望平均预测值与真实 MPG 相差 5 英里/加仑。
此外,回归还使用了许多其他评估指标,其中许多内置了对过拟合的惩罚(因此不需要交叉验证)。例如,包括赤池信息准则(AIC)和贝叶斯信息准则(BIC)。大多数回归分析教科书都涵盖了这些以及更高级的主题。
4.3.2. 检查残差
在上一节中,你看到了如何使用残差,即预测值和实际值之间的距离,用于介绍的两个简单指标。这些残差本身也值得进行视觉分析。
图 4.24 展示了我们 MPG 数据集的一个示例残差图。这展示了与图 4.23(#ch04fig23)中的散点图相同的信息,但聚焦于残差的尺度。在理想情况下,你期望残差随机分布在 0 线周围。在图的下端,MPG 值从 10 到 35,看起来残差是随机分布在 0 线周围的,可能略微偏向高估值。然而,在 35-45 的值中,你可以看到明显的低估值的倾向,导致较大的残差值。你可以使用这些信息来改进模型,要么通过调整模型参数,要么通过处理或修正数据。如果你可以获取更多数据,你可以尝试为一些高 MPG 示例获取标签。在这种情况下,你可以找到一些更多的高 MPG 汽车并将它们添加到数据集中,以改进该尺度部分的预测。
图 4.24. 在 MPG 数据集上的预测残差图。在水平 0 线上,残差为 0。

你已经看到了如何使用交叉验证来测试模型以及你可以用来评估结果的一些性能指标。对于最简单的模型,这只是一个训练、测试和计算适当的性能指标的问题。更复杂的算法有可调整的参数——用户可以调整的旋钮,这会影响它们的训练和应用方式。每种设置组合产生不同的模式。在下一节中,你将看到有时微小的调整可以在结果中产生很大的差异。
4.4. 通过参数调整进行模型优化
大多数机器学习模型都内置了一个或多个调整参数,这些参数控制学习算法的内部工作原理。这些调整参数通常控制输入特征与目标变量之间关系的复杂性。因此,调整参数可以对拟合模型及其在新数据上的预测准确性产生强烈影响。
例如,在第 4.1 节中,您看到了单个调整参数(核平滑回归算法中的带宽)如何导致在玉米产量数据集中产生截然不同的模型拟合。对于带宽参数的小值,回归函数过于颠簸,过度拟合了数据。同样,对于带宽参数的大值,回归函数过于平滑,欠拟合了数据。
本节介绍了一种严格的方法来优化机器学习算法的调整参数。
4.4.1. 机器学习算法及其调整参数
每个机器学习算法都包含一组不同的调整参数,这些参数控制算法如何使用训练数据来构建模型。随着算法变得更加复杂,通常调整参数的数量也会更多,且更加复杂。以下是您在第三章中学习的一些流行分类算法的标准调整参数,按复杂度递增的顺序列出:
-
逻辑回归— 无
-
K 近邻— 用于平均的最近邻数量
-
决策树— 分割标准,树的最大深度,进行分割所需的最小样本数
-
核支持向量机— 核类型,核系数,惩罚参数
-
随机森林— 树的数量,每个节点中用于分割的特征数,分割标准,进行分割所需的最小样本数
-
提升— 树的数量,学习率,树的最大深度,分割标准,进行分割所需的最小样本数
作为例子,回想一下第三章,在那里您将核支持向量机应用于泰坦尼克号乘客数据集。您看到,在图 3.8 和图 3.9 中,两种核系数参数(称为gamma)的选择会导致模型拟合不同:设置 gamma = 0.01 产生了一个复杂、分割的决策边界,而设置 gamma = 0.1 则创建了一个更平滑的模型。在这种情况下,拟合的模型对调整参数 gamma 的选择非常敏感。
使这变得困难的是,对于给定算法的每个调整参数的正确选择完全依赖于特定的问题和数据。对于一个问题有效的东西不一定适用于下一个问题。依赖于启发式和经验法则的默认调整参数设置可能会导致预测性能不佳。严格选择调整参数对于确保您的模型尽可能准确至关重要。
4.4.2. 网格搜索
标准的优化机器学习模型调整参数的方法是通过穷举搜索的网格搜索。在规划以下基本的网格搜索算法时,请注意,这种策略将本章前几节中关于交叉验证和模型评估的材料结合起来。网格搜索算法如下:
-
选择您想要最大化的评估指标(例如,分类中的 AUC,回归中的 R²)。
-
选择您想要使用的机器学习算法(例如,随机森林)。
-
选择您想要优化的调整参数(例如,树的数量和每个分割的特征数量)以及每个参数要测试的值数组。
-
定义网格为每个调整参数数组的笛卡尔积。例如,如果树的数量数组为[50, 100, 1000],每个分割的特征数量数组为[10, 15],则网格为[(50,10), (50,15), (100,10), (100,15), (1000,10), (1000,15)]。
-
对于网格中每个调整参数的组合,使用训练集进行交叉验证(使用保留法或 k 折交叉验证方法),并在交叉验证预测上计算评估指标。
-
最后,选择与评估指标最大值对应的调整参数集。这就是优化后的模型。
为什么这有效?网格搜索在调整参数的每个可能值组合上进行广泛的搜索。对于每个组合,它通过比较交叉验证预测与真实目标变量来估计该模型在新数据上的性能。然后,选择具有最佳估计准确度(对于新数据)的模型。这个模型在应用于新数据时最有可能表现最佳。
让我们将网格搜索应用于泰坦尼克号乘客数据集。您将使用 AUC 作为优化指标,并使用具有径向基函数(RBF)核的 SVM 作为分类算法。原则上,您也可以使用网格搜索来选择最佳核。实际上,您可以使用网格搜索在不同的算法之间进行选择!
接下来,您选择要优化的调整参数。对于具有 RBF 核的核 SVM,您有两个标准调整参数:核系数 gamma 和惩罚参数 C。以下列表显示了如何运行针对这两个参数的网格搜索。
列表 4.7. 基于核 SVM 的网格搜索


你在泰坦尼克号数据集中发现,最大交叉验证 AUC 为 0.670,出现在调整参数向量(gamma = 0.01, C = 6)。一个等高线图显示了在图 4.25 中网格上评估的 AUC,这可能是有用的。以下是一些从这个图中跳出的因素:
-
最大值出现在网格的边界(gamma = 0.01),这意味着你想要在扩展的网格上重新运行网格搜索。
-
预测的准确性对 gamma 参数数值的敏感性很高,这意味着你需要增加该参数采样的粒度。
-
最大值出现在 gamma = 0 附近,因此在对数尺度上表示网格(例如,10^(-4), 10^(-3), 10^(-2), 10^(-1))是合理的。
-
AUC 作为 C 函数的敏感性不高,因此你可以使用该参数的粗略采样。
图 4.25。等高线图显示了交叉验证的 AUC 作为两个调整参数 gamma 和 C 的函数。最大值出现在左上角,这意味着你需要扩大搜索范围并关注该区域。

在修改后的网格上重新运行网格搜索,你发现最大 AUC 为 0.690,出现在(gamma = 0.08, C = 20)。优化调整参数的价值是明显的:一个模型如果随意选择调整参数,其结果可能差到 AUC = 0.5(不如随机猜测);网格搜索优化的模型将准确度提升到 AUC = 0.69。
注意,网格搜索并不绝对确保你选择了最佳的调整参数集。由于选择有限的可能值网格所造成的限制,实际的最佳值可能位于网格值之间。对优化有一定了解的读者可能会想知道为什么更复杂的优化程序传统上没有被用于调整参数的选择。简短的回答是,无导数、非凸优化的世界尚未成为标准机器学习工具箱的一部分。更长的回答是,该领域的机器学习研究人员正在开始将这些方法纳入调整参数优化策略中。
4.5. 摘要
在本章中,你学习了评估机器学习模型性能的基础知识。以下是主要收获的简要概述:
-
当你评估模型时,你不能双重使用训练数据,既用于评估也用于训练。
-
交叉验证是模型评估的一种更稳健的方法。
-
持续交叉验证是交叉验证的最简单形式。为了更好地估计模型泛化能力,保留一个测试集用于预测。
-
在 k 折交叉验证中,每次保留一个 k 折,提供对模型性能的更自信的估计。这种改进是以更高的计算成本为代价的。如果可能,当 k = 样本数时,可以获得最佳估计,也称为留一法交叉验证。
-
基本模型评估工作流程如下:
-
获取并预处理数据集以进行建模(第二章)并确定适当的机器学习方法(第三章)。
-
根据可用的计算资源,使用留出法或 k 折交叉验证方法构建模型并进行预测。
-
根据机器学习方法是否为分类或回归,使用所选的性能指标评估预测。
-
调整数据和模型,直到获得所需的模型性能。在第五章–第八章中,你会看到在常见的实际场景中提高模型性能的各种方法。
-
-
对于分类模型,我们在工作流程的第 3 步中介绍了一些模型性能指标。这些技术包括简单的计数准确率、混淆矩阵、接收者操作特征、ROC 曲线和 ROC 曲线下的面积。
-
对于回归模型,我们介绍了均方根误差和 R 平方估计量。简单的可视化,如预测值与实际值的散点图和残差图,很有用。
-
你可以使用网格搜索算法来优化模型,以调整参数。
4.6. 本章术语
| 单词 | 定义 |
|---|---|
| 欠拟合/过拟合 | 分别使用过于简单或过于复杂的模型来处理问题。 |
| 评估指标 | 描述模型性能的数字。 |
| 均方误差 | 用于回归模型的一种特定评估指标。 |
| 交叉验证 | 将训练集分成两个或多个训练/测试集的方法,以更好地评估准确性。 |
| 留出法 | 一种交叉验证形式,其中保留一个单独的测试集,用于模型拟合过程中的测试。 |
| k 折交叉验证 | 一种交叉验证方法,其中数据被分成 k 个随机不相交的集合(折)。每次保留一个折,并在剩余数据上构建的模型上进行交叉验证。 |
| 混淆矩阵 | 一个矩阵,显示每个类别的预测值中正确分类或未正确分类的数量。 |
| 接收者操作特征(ROC) | 表示真阳性、假阳性、真阴性或假阴性的数字。 |
| 面积下限(AUC) | 一个用于分类任务的评估指标,定义为假阳性与真阳性之间的 ROC 曲线下的面积。 |
| 调整参数 | 机器学习算法的一个内部参数,例如核平滑回归中的带宽参数。 |
| 网格搜索 | 一种用于选择调整参数最佳值以优化 ML 模型的暴力策略。 |
在下一章中,您将开始关注通过关注其特征来改进您的模型。除了基本特征工程技术外,您还将学习从文本、图像和时间序列数据中提取信息的高级方法。您还将了解如何选择最佳特征以优化模型性能并避免过拟合。
第五章. 基本特征工程
本章涵盖
-
理解特征工程对您的机器学习项目的重要性
-
使用基本的特征工程过程,包括处理日期和时间以及简单的文本
-
选择最佳特征并减少模型的统计和计算复杂性
-
在模型构建和预测时使用特征工程
前四章向您展示了如何根据一组输入特征和感兴趣的输出目标来拟合、评估和优化一个监督式机器学习算法。但是,那些输入特征从何而来?你是如何定义和计算特征的?以及从业者如何知道他们是否使用了适合他们问题的正确特征集?
5.1. 动机:为什么特征工程有用?
在本章中,我们探讨了如何从原始输入数据中创建特征——这个过程被称为特征工程——并介绍了一些简单的特征工程过程示例。这将为本章 7.0 节中介绍的更复杂的特征工程算法奠定基础。
5.1.1. 什么是特征工程?
特征工程是一种使用原始输入数据的数学变换来创建用于 ML 模型的新特征的做法。以下是一些这样的变换示例:
-
将总金额除以总支付次数,以获得每笔支付的金额比率
-
计算文本文档中特定单词的出现次数
-
计算用户 ping 时间分布的统计摘要(例如,均值、中位数、标准差和偏度)以评估网络健康
-
在用户 ID 上连接两个表(例如,支付和支持)
-
将复杂的信号处理工具应用于图像并总结其输出(例如,梯度直方图)
在深入探讨几个示例以展示特征工程的实际应用之前,让我们考虑一个简单的问题:为什么使用特征工程?
5.1.2. 使用特征工程的理由
本节描述了特征工程在机器学习应用中提供价值的一些方法。这个列表并不全面,而是介绍了特征工程可以提升您的 ML 模型准确性和计算效率的几种主要方式。
将原始数据转换为与目标相关
您可以使用特征工程产生与目标变量更紧密相关的原始数据转换。以一个包含每位客户当前银行账户余额和信用债务的个人金融数据集为例。如果您正在构建一个模型来预测每位客户三个月后是否会成为支付违约者,那么工程化特征
Ratio of debt-to-balance = amount of debt / amount of balance
可能对目标变量有很高的预测性。
在这个例子中,尽管原始数据集中存在原始输入,但如果将工程化特征直接用作输入,机器学习模型将更容易找到债务与余额比率与未来违约之间的关系。这将导致预测准确性的提高。
引入外部数据源
特征工程使从业者能够将外部数据源引入他们的机器学习模型中。想象一下,你运营一个互联网订阅服务。每位客户首次登录时,你想要预测该客户的终身价值。在众多指标中,你可以捕捉到每个用户的地理位置。尽管这些数据可以直接作为分类特征(例如,IP 地址或邮政编码)输入,但模型可能很难确定基于位置的信号(在这种情况下,这些可能是每个位置的平均收入,或城市与农村的差异)。
通过引入第三方人口统计数据,您可以做得更好。例如,这将允许您计算每个用户位置的平均收入和人口密度,并将这些因素直接插入到训练集中。现在,您不再需要模型从原始位置数据中推断这些微妙的关系,这些预测因素立即变得更容易推断。此外,将位置特征工程化为收入和人口密度使您能够评估哪些位置衍生因素最重要。
使用非结构化数据源
特征工程使您能够在机器学习模型中使用非结构化数据源。许多数据源并非天生就是特征向量,可以直接插入到第一至四章中介绍的机器学习框架中。非结构化数据,如文本、时间序列、图像、视频、日志数据和点击流,占到了创建的数据的绝大多数。特征工程正是使机器学习从业者能够从这些原始数据流中产生机器学习特征向量。
本章涉及一些关于文本数据特征工程相对简单的例子。随后的章节将介绍文本、图像和时间序列数据中最常用的特征工程类型。
创建更易于解释的特征
特征工程赋予机器学习从业者创建更可解释和可操作特征的能力。通常,使用机器学习在数据中寻找模式对于做出准确预测是有用的,但你可能会面临模型可解释性和模型最终驱动变化的实际效用方面的限制。在这些情况下,可能更有价值的是设计新的特征,这些特征更能表明驱动数据生成的过程以及原始数据与目标变量之间的联系。
考虑一个简单的例子,即制造计算机硬件的机器。你可以使用原始机器数据,例如信号响应的测量和其他处理信号,来构建机器学习模型以预测部件故障。但诸如上次机器调校时间以及生产的硬件数量等特征可以提供对制造过程可变方面的洞察。
通过使用大量特征来增强创造力
特征工程使你能够尝试大量特征以查看哪些能够粘附。你可以创造出尽可能多的特征,并查看在训练模型时哪些特征具有预测力。这允许机器学习从业者从创建和测试特征时的僵化思维中解脱出来,并可能导致新发现的趋势和模式。
虽然当使用数十或数百个特征来训练机器学习模型时,过拟合成为一个关注点,但严格的特征选择算法可以被用来减少特征集,使其更易于管理。(例如,你可以自动确定使用前 10 个特征的预测与使用所有 1,000 个特征的预测一样好或更好。)我们将在本章后面描述这些算法,在 5.3 节中。
5.1.3. 特征工程和领域专业知识
另一种理解特征工程的方式是将领域专业知识注入机器学习模型中。我们所说的简单来说就是:对于手头的每个问题,关于研究的数据和系统的知识会随着时间的推移而积累。对于某些问题,这些模式将足够简单,以至于机器学习模型可以轻松地学习。但对于更具挑战性的问题,机器学习模型将从将领域专业知识编码到特征集中而显著改进。以下是将容易编码到机器学习特征中的领域专业知识声明的例子:
-
网络转化率在星期二总是更高(包括布尔特征“是否是星期二?”)。
-
家庭电力消耗随着温度的升高而增加(包括温度作为特征)。
-
垃圾邮件通常来自免费电子邮件账户(设计布尔特征“是否来自免费电子邮件账户?”或电子邮件域名)。
-
最近开设信用卡的贷款申请人更频繁地违约(使用“上次开设信用卡天数”特征)。
-
客户通常在他们网络中的其他人也更换了服务提供商之后才会更换自己的手机服务提供商(设计一个功能来统计最近更换了服务提供商的订阅者网络中的人数)。
显然,潜在领域专业知识片段的列表可以无限延续。实际上,许多公司的标准操作程序是使用这些临时规则的长列表来做出决策和预测。这些业务规则是构建机器学习模型的一个完美的工程特征集!
反过来说,特征工程可以是一种检验领域专家持有的先入为主的观念的方法。如果有任何疑问,关于某个特定假设是否具有任何价值,它可以被编码并用作机器模型中的一个特征。然后,可以通过有无该特征来测试模型的准确性,以评估该特征在预测目标变量中的条件重要性。如果准确性的提升可以忽略不计,这表明该想法的附加值不足。
接下来,我们将展示一些简单的特征工程示例,以展示这些过程在实际中是如何工作的。我们描述了特征工程如何融入整体机器学习工作流程,并展示了通过采用一些相对简单的特征工程过程如何提高机器学习模型的预测准确性。
5.2. 基本特征工程过程
在深入我们的例子之前,让我们回顾一下我们基本的机器学习工作流程,以展示特征工程是如何扩展你迄今为止所看到的。展示了工作流程。
图 5.1. 特征工程如何融入基本的机器学习工作流程。你在构建模型之前扩展训练数据中的特征。在做出预测时,你需要将新数据通过相同的特征工程管道,以确保答案是有意义的。

工作流程的特征工程扩展允许你扩展训练数据以增加机器学习算法的准确性。为了确保特征工程得到正确使用,你需要将预测数据通过应用于训练数据的相同特征工程管道。这确保了预测是通过与应用于训练数据完全相同的过程生成的。
5.2.1. 示例:活动推荐
为了说明特征工程的概念,本节引入了一个来自现实世界的例子:来自数据科学竞赛网站 Kaggle(www.kaggle.com)的挑战。
想象一下,您正在运行一个事件推荐网站,并希望预测一个特定用户是否对某个事件(如会议、Happy Hour 或讲座)感兴趣。您有一组训练数据,描述了过去哪些用户对哪些事件表示了兴趣,以及一些关于用户和事件本身的信息。您的目标是构建一个机器学习模型来预测特定事件是否对用户感兴趣——一个二分类模型。
在您在 Kaggle 网站上注册后(如果您还没有注册),可以在www.kaggle.com/c/event-recommendation-engine-challenge找到关于挑战的数据和信息。基础数据集包括 train.csv、events.csv 和 users.csv 文件,这些文件可以根据用户和事件标识符进行合并。您将数据集限制在具有明确感兴趣或未感兴趣选择的活动中,以及基本的数值和分类特征。显示了初始训练数据集的一个选择。
图 5.2. 用于训练事件推荐模型的数据集样本
![05fig02_alt.jpg]
您的样本训练数据包含以下特征:
-
invited——一个布尔值,表示个人是否被邀请参加活动 -
birthyear——人员的出生年份 -
gender——人员的性别 -
timezone——个人的当前位置时区 -
lat/lng——事件的纬度/经度
首先,您将基于这六个特征构建和评估一个模型。很明显,这个数据集在识别每个用户是否对事件感兴趣的模式方面是有限的。随着您继续本节,您将使用一些简单的特征工程转换来扩展特征集并添加新信息。
您将构建一个初始的二分类模型,从六个输入特征中预测目标变量interested。遵循第一章到第四章的 ML 工作流程 chapters 1–4,您需要执行以下操作:
-
执行初始数据处理练习(将分类列转换为数值,填充缺失值)。
-
进行模型训练(使用随机森林算法)。
-
评估模型(使用 10 折交叉验证和 ROC 曲线)。图 5.3 显示了交叉验证的 ROC 曲线。它达到了 0.81 的 AUC 分数。
图 5.3. 简单事件推荐模型的交叉验证 ROC 曲线和 AUC 指标
![05fig03_alt.jpg]
5.2.2. 处理日期和时间特征
接下来,你将使用特征工程尝试改进第一个模型的结果。除了图 5.2 中显示的数据外,数据集中的每个事件都有一个相关的start_time。这个数据元素是一个 ISO-8601 UTC 字符串,表示事件计划开始的时间。数据字段具有类似于2012-10-02 15:53:05.754000+00:00的格式,表示 yyyy-mm-dd hh:mm:ss.mmmmmm_HH:MM。
在第三章中描述的 ML 模型可以支持数值或分类输入特征,其中datetime字符串不属于这两种。因此,你不能简单地将字符串列直接插入模型中。然而,你可以执行将datetime元素转换为数值特征的转换,这些特征可以捕获datetime字符串中编码的信息。这个简单而强大的特征工程概念可以使你将每个datetime字符串转换为一系列特征,例如这些:
-
一天中的小时
-
星期
-
年份的月份
-
小时
-
年份的季度
图 5.4 显示了将你的单个start_time特征转换为 10 个datetime特征后得到的前五行数据。
图 5.4. 从事件推荐数据集的时间戳列中提取的附加日期时间列

接下来,你将在这个新的 16 特征数据集上构建随机森林模型。我们的交叉验证 ROC 曲线如图 5.5 所示。
图 5.5. 包含日期时间特征的模型的交叉验证 ROC 曲线

模型的 AUC 从 0.81 增加到 0.85。显然,start_time信息中隐藏的价值,当通过特征工程注入到 ML 模型中时,有助于提高模型的准确性。最有可能的是,在特定星期几和一天中的特定时间发生的事件比其他事件更受欢迎。
5.2.3. 处理简单文本特征
除了事件的时间外,数据还包括来自简单自然语言处理程序的文本特征。与datetime特征不能直接由模型使用一样,因为它们既不是数值也不是分类的,任意文本不能在没有某种将数据转换为两种接受类型之一的处理的情况下输入到 ML 算法中。要将文本转换为 ML 特征,你将使用一种称为“词袋”的方法。在原则上,这个想法很简单:计算文本中每个单词出现的次数,并在数据集中插入一个包含该单词计数的列。然而,你仍将有一些复杂因素需要处理。
您提供给机器学习算法的特征必须是一致的:对于数据集中的所有实例,特征的数量必须相同,并且它们必须对应于相同的基本概念。例如,如果第一个实例包含五个“家庭”这个词的出现,而下一个实例没有,您必须选择在第二个实例中包含一个“家庭”列并将计数设置为 0,或者在不包含这两个实例的情况下。通常,您会使用整个数据集的文本语料库来决定哪些单词应该有列,哪些不应该。在大多数情况下,您会为整个数据集构建词袋,并只包含出现频率最高的单词以在数据集中创建列。然后,您可以有一个包含所有剩余单词的通用列,这在原则上决定了所选顶级单词之外文本的长度。
现在,假设您正在选择前 100 个单词以在数据集中创建一个计数列。您将得到一些列,这些列包含常见但无用的单词的计数,例如“是”、“和”和“the”。在自然语言处理领域,这些单词被称为“停用词”,通常在执行词袋计数之前从文本中删除。
我们将在下一章介绍更高级的文本特征概念,但在此要提到的最后一个复杂因素是,词袋数据集很快就会变得很大且稀疏。我们有很多特征,大部分都是 0,因为特定的单词通常不太可能出现在随机文本段落中。英语词典很大(有超过 20 万个在使用的单词),但其中只有一小部分单词在大多数文本中使用。一些机器学习问题有一个更窄的空间,其中一类单词比一般情况更常见。例如,图 5.6 显示了我们事件推荐示例中顶级单词的计数特征的一些实例;数据稀疏性很明显。一些机器学习算法,如朴素贝叶斯分类器,可以很好地处理稀疏数据(不需要为 0 分配额外内存),而大多数其他算法则不行。
图 5.6. 事件推荐示例的词袋数据的一个切片。这些数字是事件描述中顶级出现单词的计数。大部分单元格包含 0,因此我们称该数据集为“稀疏”。

在我们的事件推荐示例的 events.csv 中,100 个特征代表 100 个顶级出现单词的词袋。您希望将这些用作模型中的特征,因为某些事件可能比其他事件更受欢迎。图 5.7 显示了将这些特征添加到模型后得到的 ROC 曲线。
图 5.7. 包含日期时间特征和文本特征的完整模型的交叉验证 ROC 曲线

图 5.7 中的 AUC 指标与只包含基本和日期时间特征的先前模型相比没有增加。这告诉你,仅仅因为文本,特定的事件描述更有可能对用户感兴趣。这个模型没有解决个别用户的兴趣,而是针对一般用户群体。在真实的推荐引擎中,你可以为每个用户或每个用户类别构建一个模型。其他流行的推荐引擎方法使用事件、用户和用户朋友之间的联系来寻找推荐。
5.3. 特征选择
与基本的统计方法和人类模式识别能力相比,机器学习算法的主要优势之一是处理更多特征的能力。大多数机器学习算法可以处理数千或数百万个特征。增加更多特征以提高模型准确性的策略通常是有用的。但在机器学习中,就像在许多其他情况下一样,更多并不总是更好。
由于更多特征使模型能够更详细地学习特征到目标的映射,存在模型过度拟合数据的危险。这增加了模型在训练时的出现准确率,但可能会损害对新、未见数据的预测性能。图 5.8 展示了过度拟合的一个例子(我们首次在第三章中讨论了过度拟合)。
图 5.8. 两个模型在相同训练数据上的决策边界。在顶部的模型中,决策边界过于详细,可能会影响新数据的分类性能。

在本节中,你将了解选择特征子集的方法,以避免过度拟合,从而在应用于新数据时提高模型的准确性。某些算法或多或少容易受到过度拟合的影响,但如果模型准确性特别重要,那么进行一些这些优化可能值得。
较少的特征数量和因此较小的模型的一个优点是,训练和预测的计算成本通常与特征数量相关。在模型开发阶段花些时间,可以在重新训练或进行预测时节省时间。
最后,特征选择和相关概念特征重要性可以帮助你深入了解模型,因此可以了解用于构建模型的原始数据。在某些情况下,构建模型的目标甚至可能不是进行预测,而是了解模型的重要特征;你可以使用关于最显著特征的知识来发现某些模式,例如信用状况与某些人口或社会因素相关。获取特定特征的数据可能存在成本,如果该特征对当前模型不重要,则无需承受损失。特定特征的重要性还可以揭示模型返回的预测中的宝贵见解。在许多现实世界的用例中,了解为什么做出某个特定预测很重要,而不仅仅是特定的答案。
有了这些,你应该有足够的动力深入了解特征选择和最常用的方法。选择最优特征子集的最简单方法就是尝试所有特征组合——例如,为所有特征子集构建模型,并使用你在第四章中获得的知识来衡量模型的性能。不幸的是,即使特征数量很少,这种方法也会迅速变得不可行。你必须使用可以近似最优特征子集的技术。在接下来的几个小节中,你将研究这些方法中的一些。最广泛使用的方法类别之一是前向选择/后向消除,将在下一小节中介绍。其他启发式方法将在本章后面介绍。
一些算法具有内置的特征选择功能
尽管本节讨论的方法适用于任何机器学习算法,但某些算法在特征选择领域具有优势,因为它们具有内置的类似行为。然而,在所有情况下,这些内置方法不太可能产生与通用方法相当的结果,但可能在计算上显著更高效。因此,在回退到更计算密集的通用方法之前,尝试内置方法可能是有用的,或者甚至可以将内置方法用作种子来节省通用方法上的计算时间。
内置特征选择方法的例子包括线性回归和逻辑回归算法中分配给特征的权重,以及决策树和随机森林等集成变体中的特征重要性,这些方法以计算效率高的方式捕捉到如果用随机噪声替换一个特征,预测准确性预期会降低的量。我们可以从上一节中检查随机森林事件推荐模型的顶级特征重要性。

事件推荐模型中前七个特征的随机森林特征重要性。根据这一衡量标准,用户的出生年份和事件所在的时区是判断事件是否对用户感兴趣的两个最重要的指标。
5.3.1. 前向选择和后向消除
用于近似最佳特征子集的最广泛使用的方法集是迭代选择方法,你将在下面探讨。一般概念是从没有特征开始,迭代地找到要添加的最佳特征,或者从所有特征开始,迭代地移除最差的。当所有特征都已添加或移除,当准确性的提高达到平稳,或者达到预定的特征集大小时,搜索停止。
这些方法分别被称为前向选择和后向消除。它们不能保证找到最佳特征子集,这就是为什么我们称之为近似。被遗漏或移除的特征中,可能有一些在与尚未达到的特征组合时具有更强的预测能力。记住,机器学习的力量来自于通过组合许多特征来发现模式的能力。或者换句话说,一个弱特征在存在恰好的一组其他特征时可能变得强大。
然而,在实践中,前向选择或后向消除在以比穷举搜索小得多的计算复杂度找到良好的特征子集方面效果很好。然而,当特征数量特别大时,即使是这种方法也可能在计算上不可行。在这些情况下,可能需要依赖于内置的特征重要性度量或其他搜索启发式方法,我们将在下一节中介绍。
前向特征选择的过程如图 5.9 所示。根据特征的数量,可能需要构建许多模型。如果算法运行到结束,你需要构建 N + (N – 1) + (N – 2)...(N – N + 2) + (N – N + 1),或者
。对于 20、100、500 或 1000 个特征,这分别是 210、5,050、125,250 和 500,500 个模型构建。此外,每次交叉验证迭代都需要构建 k 个模型,因此如果模型构建需要任何显著的时间,这也变得难以管理。对于特征集较小的集合,或者当运行较少的迭代次数(例如,因为准确性的提高迅速达到平稳)时,这种方法在实践中是有效的。
图 5.9. 前向特征选择的过程。从最左边的框开始,特征被迭代添加,直到根据交叉验证评估指标选择出最佳特征集。

图 5.10 展示了向后消除的等效过程。计算需求与正向选择相同,因此选择正向或向后方法通常取决于具体问题和算法的选择。例如,某些算法在非常小的特征集上表现较差,在这种情况下,向后消除是更好的方法。
图 5.10. 向后特征消除的过程

通过绘制类似于 图 5.11 的垂直条形图是一种可视化迭代特征选择过程的有用方法。
图 5.11. 迭代特征选择条形图,显示特征选择过程中的准确度演变——在这种情况下,是正向选择算法。对于问题有意义的任何准确度度量(见 第四章)都应在此处使用。

正如我们之前提到的,一些机器学习算法具有内置的特征选择方法。您可以使用混合方法,而不是基于内置特征排名进行特征选择,这种方法在正向选择或向后消除过程的每次迭代中使用内置特征重要性来找到最佳或最差特征。当您有大量特征时,这可以显著减少计算时间,但可能会产生对最优特征子集的更不精确的近似。
5.3.2. 数据探索的特征选择
特征选择不仅可以用于避免过拟合或使模型更精简。特征选择的一个强大用途是深入了解模型和训练数据。实际上,在某些情况下,您可能只想构建一个分类器来运行特征选择算法,而不是为了做出预测。
你可以使用特征选择对用于构建模型的原始数据进行探索性分析。从特征选择过程中,你可以知道最重要的特征——从所有特征中预测目标变量的最有信息量的特征集。这告诉你有关数据的一些信息,这本身可能很有用。想象一下,你的任务是预测患者是否可能患有癌症。因为你不确定特定形式癌症的原因,你添加了你所能获取的所有特征,并使用特征选择来找到顶级特征。你不仅获得了更好的交叉验证准确率,而且使用数据来指示哪些因素最有可能导致疾病,或者至少与诊断概率相关。所讨论的特征选择方法并没有告诉你特征在正方向还是负方向上是否强大(在二元分类的情况下),但你可以很容易地将特定特征与目标变量进行可视化,以理解这一点(例如,使用第 2.3 节中的可视化)。
另一个特征选择的无监督用例是用于降维。当处理包含三个以上变量的数据集时,一个巨大的挑战是如何可视化数据。人类大脑已经优化适应三维世界,我们很难理解超过三维的信息。然而,在现实世界的数据中,只有三个特征的情况极为罕见,你需要采用各种技术来可视化高维数据集。你可以使用特征选择来展示机器学习算法如何将数据划分为类别,例如,只需简单地将两个或三个最佳特征与目标变量进行对比。图 5.12 展示了在二维中显示的决策边界示例,尽管构建模型使用了更多特征。
图 5.12. 这个将数据分类为圆形和钻石的决策边界只有两个特征。模型是在许多更多特征的基础上构建的,但特征选择算法发现 sqrt(Fare)和 Age 特征在这个特定问题(泰坦尼克号生存预测)中非常重要。这个图表最初在第三章中介绍。

在下一节中,你将看到特征选择在现实世界问题中如何有用的一个示例。
5.3.3. 现实世界的特征选择示例
对于特征工程和特征选择在现实世界中的伟大用例,让我们看看科学中的一个例子。
你的任务是从小型天文图像中从大量所谓的虚假事件(看起来真实但并非如此的事件)中找到真正的超新星事件。图 5.13 展示了真实和虚假事件的示例。
图 5.13。真实超新星图像显示在左面板中。虚假候选事件显示在右面板中.^([1])分类器的工作是学习从图像中提取的特征之间的差异,以区分这两种类型的候选者。(这些是明显的例子;许多其他例子很难分类,即使是训练有素的人。)
¹
本节中的超新星图像和数据图最初发表在 2013 年《皇家天文学会月报》第 435 卷第 2 期,第 1047-1060 页(
mnras.oxfordjournals.org/content/435/2/1047)。

真实/虚假分类器是通过首先将原始图像数据处理成一组特征来构建的,其中一些将在下一章中讨论。然后,您将特征化数据通过随机森林算法来构建分类器,并执行各种模型优化,如第三章和第四章中概述的优化。在将此模型投入望远镜的实时流之前,最后一部分是确定最佳特征,避免过拟合,并使模型尽可能小,以支持项目的实时需求。特征选择图,是图 5.11 的一个稍微高级的版本,显示在图 5.14 中。
图 5.14。特征选择图显示了反向消除过程。随着算法的进行,从底部向上选择每个特征进行删除,并在每个步骤中计算 1%假阳性率(FPR)下的漏检率(MDR)的定制评估指标。条形图显示了通过删除特征(带有交叉验证的标准差)在每一步获得的性能指标(在这种情况下,越小越好)。删除了 23 个特征(共 44 个)后,交叉验证的性能提升趋于平稳,当删除太多特征时最终变得非常糟糕。最终,通过删除噪声特征,模型性能提高了 5 个百分点。

现在,通过了解哪些特征对模型最重要,您可以绘制这些特征与真实和虚假事件的关系图,以可视化特定特征如何帮助解决问题。图 5.15 显示了四个最佳特征的性能。
图 5.15。我们特征选择算法选择的四个最佳特征中四个单个特征的性能可视化。直方图显示了具有特定特征值的真实或虚假事件的数量。您可以看到,在振幅和通量比特征中,真实事件与虚假事件的分布不同,它们被选为特征选择过程中的顶级性能特征。

5.4. 摘要
本章介绍了特征工程,它将原始数据转换为提高机器学习模型准确度。本章的主要收获如下:
-
特征工程是将数学变换应用于原始数据以创建新的输入特征用于机器学习建模的过程。这些变换可以从简单到极其复杂。
-
特征工程有以下五个原因很有价值:
-
它可以创建与目标变量更紧密相关的特征。
-
它使您能够引入外部数据源。
-
它允许您使用非结构化数据。
-
它可以使您创建更可解释的特征。
-
它给您自由创建大量特征,然后通过特征选择选择最佳子集。
-
-
特征工程与领域知识之间存在复杂的联系。
-
特征工程在整体机器学习工作流程中适合两个地方:
-
在训练数据集上,在拟合模型之前
-
在预测数据集上,在生成预测之前
-
-
在事件推荐问题中可以使用两种类型的简单特征工程:
-
从日期时间信息中提取特征
-
自然语言文本的特征工程
-
-
特征选择是从数据集中选择最具预测性特征子集的一种严谨方法。
5.5. 本章术语
| 单词 | 定义 |
|---|---|
| 特征工程 | 将输入数据转换为提取更多价值并提高机器学习模型预测准确度的过程 |
| 特征选择 | 从更大的特征集中选择最具预测性的特征子集的过程 |
| 前向选择 | 一种特征选择版本,根据当前活动特征集,迭代地添加增加模型准确度最大的特征 |
| 后向消除 | 一种特征选择版本,根据当前活动特征集,移除降低模型准确度最大的特征 |
| 词袋模型 | 一种将任意文本转换为数值特征以供机器学习算法使用的方法 |
第七章扩展了这里所展示的简单特征工程方法,以便您可以对文本、图像和时间序列等数据进行更高级的特征工程。在下一章中,我们将使用本章所学的内容进行一个全章示例。
第二部分。实际应用
在第二部分中,你将超越基本的机器学习工作流程,了解如何从文本、图像和时间序列数据中提取特征,以进一步提高模型的准确性,并将你的机器学习系统扩展到更大的数据量。此外,你将阅读三个完整的示例章节,以看到一切的实际应用。
在第六章,我们的第一个完整示例章节,你将尝试预测纽约市出租车的打赏行为。
在第七章中,你将了解高级特征工程过程,这些过程允许你从自然语言文本、图像和时间序列数据中提取价值。许多现代机器学习和人工智能应用都基于这些技术。
在第八章中,你将使用这种高级特征工程知识在另一个完整的示例中:预测在线电影评论的情感。
在第九章中,你将学习将机器学习系统扩展到更大数据量、更高预测吞吐量和更低预测延迟的技术。这些都是许多现代机器学习部署的重要方面。
在第十章中,你将逐步构建一个模型——在大量数据上——该模型可以预测在线数字展示广告的点击量。
第六章。示例:纽约市出租车数据
本章涵盖
-
介绍、可视化和准备关于纽约市出租车行程的真实世界数据集
-
建立一个分类模型来预测乘客打赏习惯
-
通过调整模型参数和工程特征来优化机器学习模型
-
建立和优化回归模型以预测小费金额
-
使用模型来深入理解数据和它所描述的行为
在前五章中,你学习了如何从原始、混乱的数据开始,通过调整参数和工程特征来构建、验证和优化模型。尽管我们在这些章节中使用了各种小例子来阐述各个部分的观点,但现在是你运用所获得的知识并解决一个完整、真实世界例子的时候了。这是三个章节(连同第八章和第十章)中完全致力于一个完整、真实世界例子的第一个。
在本章的第一部分,你将更仔细地查看数据以及各种有用的可视化,这些可视化有助于你更好地理解数据的可能性。我们解释了如何进行初始数据准备,以便数据为后续章节中的建模实验做好准备。在第二部分,你将设置一个分类问题,并通过调整模型参数和工程新特征来提高模型的性能。
6.1。数据:纽约市出租车行程和费用信息
随着公司和组织产生越来越多的数据,近年来出现了一大批丰富且有趣的数据集。此外,一些这些组织正在拥抱开放数据的概念,允许任何感兴趣的各方公开传播和使用这些数据。
最近,纽约州信息自由法(FOIL)公布了一个极其详细的数据集,包含了 2013 年所有出租车行程的记录。1 这个数据集收集了每个单独出租车行程的各种信息,包括接车和下车位置、行程时间和持续时间、行驶距离和费用金额。您会看到这些数据符合现实世界数据的特征,不仅因为其生成方式,还因为其混乱:存在缺失数据、虚假记录、不重要的列、内置偏见等。
¹
该数据最初由 Chris Wong 在博客文章中发布:
chriswhong.com/open-data/foil_nyc_taxi/。
说到数据,数据量很大!完整的数据集超过 19 GB 的 CSV 数据,这使得许多机器学习实现无法在大多数系统上处理。为了简化,在本章中,您将使用数据的一个较小子集。在第九章和第十章中,您将研究能够扩展到这种大小甚至更大的方法,因此到本书结束时,您将知道如何分析全部 19 GB 的数据。
数据可在www.andresmh.com/nyctaxitrips/下载。数据集由 12 对行程/票价压缩 CSV 文件组成。每个文件包含约 1400 万条记录,行程/票价文件是逐行匹配的。
您将遵循我们的基本机器学习工作流程:分析数据;提取特征;构建、评估和优化模型;以及在新的数据上进行预测。在下一小节中,您将通过使用第二章中的一些可视化方法来查看数据。
6.1.1. 可视化数据
在开始解决一个新问题时,第一步是了解数据集包含的内容。我们建议您首先加载数据集,并以表格形式查看它。对于本章,我们将行程/票价数据合并为一个单一的数据集。图 6.1 显示了数据的前六行。
图 6.1. 纽约市出租车行程和票价记录数据的前六行。大多数列都是自解释的,但我们在随后的文本中会详细介绍其中的一些。

medallion和hack_license列看起来像简单的 ID 列,对簿记有用,但从机器学习的角度来看不太有趣。从它们的列名来看,一些列看起来像分类数据,如vendor_id、rate_code、store_and_fwd_flag和payment_type。对于单个分类变量,我们建议以表格形式或条形图形式可视化它们的分布。图 6.2 使用条形图显示了这些分类列中每个值的分布。
图 6.2. 我们数据集中一些看似分类的列的值分布

接下来,让我们看看数据集中的一些数值列。例如,验证诸如行程时长(trip_time_in_secs)、距离和行程总费用之间存在相关性是有趣的。图 6.3 显示了这些因素相互之间的散点图。
图 6.3. 出租车行程的散点图,分别显示了以秒为单位的时间与行程距离,以及以秒为单位的时间与行程金额(美元)的关系。正如预期的那样,存在一定程度的关联,但散点仍然相对较高。还出现了一些不太合理的簇,例如很多零时间行程,甚至一些昂贵的行程,这可能表明数据条目有误。

最后,在图 6.4 中,你可以可视化纬度/经度空间中的接车位置,定义纽约市出租车行程的地图。分布看起来是合理的,大多数接车位置发生在曼哈顿市中心,许多发生在其他区,令人惊讶的是,还有少数发生在东河中间!
图 6.4. 接车位置的纬度/经度。请注意,与常规地图相比,x 轴被翻转了。你可以看到曼哈顿有大量的接车点,随着你远离市中心,数量逐渐减少。

以对所处理数据的全新视角,让我们继续设想一个可以通过使用机器学习解决的现实问题,这个问题可以用这个数据集来解决。
6.1.2. 定义问题和准备数据
当我们最初查看这些数据时,一个特定的列立即引起了我们的注意:tip_amount。这个列存储了每次行程给小费的金额(美元)的信息。了解哪些因素最影响任何给定纽约市出租车行程的小费金额将是有趣的。
为了达到这个目的,你可能想要构建一个分类器,该分类器使用所有行程信息来尝试预测乘客是否会给司机小费。有了这样的模型,你可以在每次行程结束时预测是否给小费。出租车司机可以在移动设备上安装这个模型,并在小费未给的情况下收到警报,从而在情况变得太晚之前改变现状。在你等待所有纽约出租车安装你的应用程序获得批准的同时,你可以使用这个模型来了解哪些参数对于小费与否最为重要,或者具有预测性,以便在宏观层面上尝试提高整体小费率。图 6.5 显示了所有出租车行程中小费金额的直方图。
图 6.5。小费金额的分布。大约一半的行程没有小费,这比我们直观上预期的要多。

因此,我们模型的计划是预测哪些行程将导致不给小费,哪些将导致给小费。这是一项二元分类器的工作。有了这样的分类器,你将能够做到以下几点:
-
通过提供预测不给小费情况的警报来帮助出租车司机
-
通过使用数据集来揭示纽约出租车行程中给小费背后的驱动因素(有意为之!),来了解这种情况是如何以及为什么会出现。
一个来自现实世界的故事
在你开始构建这个模型之前,我们将告诉你我们第一次尝试解决这个问题时的真实故事,这个尝试非常不成功,却伪装成非常成功——最糟糕的不成功——以及我们是如何纠正它的。这种类型的偏离在处理真实数据时非常常见,因此包括在这里学到的教训是有帮助的。在处理机器学习时,密切关注两个陷阱至关重要:过于美好以至于不可能是真的的场景和基于数据的过早的假设。
在机器学习的一般规则中,如果交叉验证的准确率高于你预期的,那么很可能是你的模型在某个地方作弊。现实世界在试图让数据科学家的生活变得困难时非常具有创造性。在构建初始的小费/不给小费分类模型时,我们迅速获得了非常高的交叉验证预测准确率。因为我们对于这个新获得的数据集上的模型性能非常兴奋——我们做到了——我们暂时忽略了作弊模型的警告。但是,由于之前多次被这种事情咬过,过于乐观的结果迫使我们进一步调查。
我们考虑的一件事是输入特征的重要性(你将在后面的章节中更详细地看到)。在我们的案例中,一个特定的特征在模型中的特征重要性方面完全占主导地位:支付类型。
从我们自己的出租车经验来看,这可能是有道理的。在 Square 时代之前使用信用卡支付的人可能给小费的可能性较低。如果你用现金支付,你几乎总是会把零钱凑成整数。所以我们开始将使用信用卡支付而不是现金的人的小费与不支付小费的人数进行细分。然而,结果令人惊讶,超过 95%的数百万名使用信用卡支付的车费乘客都给了小费。那么,那个理论就到此为止了。
那么,用现金支付的人有多少人给了小费?所有人?
实际上,用现金支付的所有乘客都没有给小费!然后很快就变得很明显。每当乘客用现金支付并给小费时,司机都没有以任何必要的方式将其记录下来,以便将其包含在我们的数据中。通过进行我们的机器学习合理性检查,我们发现了数百万个潜在的欺诈案例,这些案例发生在纽约市出租车系统中!
回到我们机器学习模型的影响:在这种情况下,当数据生成存在问题的时候,我们根本无法相信这部分数据用于构建机器学习模型。如果答案以恶意的方式不正确,那么机器学习模型学到的可能完全错误,与现实脱节。
最终,为了规避这个问题,我们决定从数据集中移除所有用现金支付的车费行程。这改变了目标:只预测非现金支付者的给小费发生率。丢弃数据总是感觉不正确,但在这个案例中,我们决定在新的基于数据支持的假设下,即所有现金支付数据都是不可信的,最佳选择是使用非现金数据来回答一个稍微不同的问题。当然,不能保证其他小费记录也是正确的,但我们至少可以检查小费金额的新分布。图 6.6 显示了过滤掉任何现金支付行程后的小费金额直方图。
图 6.6. 忽略现金支付时的小费金额分布(在发现现金小费从未在系统中记录后)

在移除不良数据后,分布看起来要好得多:只有大约 5%的行程没有小费。在下一节中,我们的任务是找出原因。
6.2. 建模
准备好用于建模的数据后,你可以轻松地运用你在第三章中学到的知识来设置和评估模型。在接下来的小节中,你将构建不同版本的模型,并尝试在每次迭代中提高性能。
6.2.1. 基本线性模型
你将以尽可能简单的方式开始这个建模工作。你将使用一个简单的逻辑回归算法。你最初也将自己限制在数据集中的数值上,因为这些数值可以由逻辑回归算法自然处理,无需任何数据预处理。
你将使用 Python 中的 scikit-learn 和 pandas 库来开发模型。在构建模型之前,我们随机打乱了实例并将它们分成 80%的训练集和 20%的持有样本测试集。你还需要对数据进行缩放,这样就没有任何列在事先被认为是比其他列更重要。如果数据已经被加载到 pandas 的DataFrame中,构建和验证此模型的代码看起来如下所示。
列表 6.1。逻辑回归小费预测模型


列表 6.1 的最后部分绘制了第一个简单分类器的 ROC 曲线。持有样本的 ROC 曲线显示在图 6.7 中。
图 6.7。逻辑回归小费/无小费分类器的接收者操作特征(ROC)曲线。曲线下的面积(AUC)为 0.5,模型似乎并不比随机猜测表现得好。这对我们的模型来说不是一个好迹象。

没有办法绕过这个问题:这个分类器的性能并不好!持有样本的 AUC 为 0.51,模型的表现并不比随机猜测(抛一个 95%“小费”和 5%“无小费”的硬币来预测每次行程)好,这显然是没有用的。幸运的是,我们一开始就很简单,有几种方法可以尝试提高这个模型的表现。
6.2.2. 非线性分类器
你首先尝试的是切换到一个不同的算法——一个非线性算法。考虑到第一次尝试的结果很差,似乎线性模型对于这个数据集来说是不够用的;简单来说,小费是一个复杂的过程!相反,你将使用一个名为随机森林的非线性算法,它在现实世界数据集上以其高精度而闻名。你可以选择许多其他算法(见附录),但我们将其留给你作为评估和比较不同算法的练习。以下是构建此模型的代码(相对于前一个模型)。
列表 6.2。随机森林小费预测模型

列表 6.2 中运行代码的结果显示在图 6.8 中。你可以看到持有样本准确率有显著提高——持有样本的 AUC 现在为 0.64——清楚地表明数据集中存在预测信号。一些输入特征的组合能够预测出租车行程是否会收到乘客的小费。如果你很幸运,进一步的特征工程和优化甚至能够进一步提高准确率水平。
图 6.8。非线性随机森林模型的 ROC 曲线。AUC 显著提高:达到 0.64,数据集中很可能存在真实信号。

你也可以使用这个模型来了解在这个中等预测模型中哪些特征最重要。这个练习有几个关键原因:
-
它使你能够识别任何作弊特征(例如,非现金支付者的问题),并利用这些作为洞察来纠正任何问题。
-
它作为进一步特征工程的一个起点。例如,如果你将经纬度识别为最重要的特征,你可以考虑从这些指标中推导出其他特征,例如从时代广场的距离。同样,如果你认为某个特征很重要,但它没有出现在顶级特征列表中,那么你将想要分析、可视化和可能清理或转换该特征。
图 6.9(由列表 6.2 中的代码生成)显示了随机森林模型的特征列表及其相对重要性。从这张图中,你可以看到位置特征是最重要的,其次是时间、行程距离和车费金额。可能的情况是,城市某些地区的乘客对缓慢、昂贵的行程不太有耐心。你将在第 6.2.5 节中更仔细地研究获得的可能见解。
图 6.9。随机森林模型的重要特征。上下车位置特征似乎主导了模型。

现在你已经选择了算法,让我们确保你正在使用所有原始特征,包括分类列,而不仅仅是普通的数值列。
6.2.3。包括分类特征
在不深入特征工程领域的情况下,你可以执行一些简单的数据预处理来提高准确性。
在第二章中,你学习了如何处理分类特征。一些机器学习算法可以直接处理分类特征,但你将使用常见的“布尔化”分类特征的技巧:为特征中每个可能的类别创建一个值为 0 或 1 的列。这使得任何机器学习算法都能在不改变算法本身的情况下处理分类数据。
转换所有分类特征的代码如下所示。
列表 6.3。将分类列转换为数值特征

在创建布尔化列之后,你再次将数据通过列表 6.2 运行,并获得图 6.10 中显示的 ROC 曲线和特征重要性列表。请注意,你的保留 AUC 略有上升,从 0.64 上升到 0.656。
图 6.10。将所有分类变量转换为布尔(0/1)列的随机森林模型的 ROC 曲线和特征重要性列表。新特征为表格带来了新的有用信息,因为 AUC 从之前没有分类特征的模型中观察到有所增加。

随着模型性能的提高,你可以考虑额外的因素。当然,你还没有进行任何真正的特征工程,因为到目前为止应用的数据转换被认为是基本的数据预处理。
6.2.4. 包含日期时间特征
到目前为止,是时候开始使用数据来生成新的特征了,你之前所知道的称为特征工程。在第五章中,我们介绍了一系列将日期和时间戳转换为数值列的日期时间特征。你可以很容易地想象一天中的时间或一周中的某一天可能会对乘客的小费产生影响。
计算这些特征的代码在下面的列表中给出。
列表 6.4. 日期时间特征

使用这些日期时间特征,你可以构建一个新的模型。你再次将数据通过列表 6.2 中的代码运行,并获取图 6.11 中显示的 ROC 曲线和特征重要性。
图 6.11. 包含所有分类特征和附加日期时间特征的随机森林模型的 ROC 曲线和特征重要性列表

你可以看到,随着额外的数据预处理和特征工程的加入,模型的准确性有所提高。到目前为止,你只关注了改进数据以改进模型,但你还可以尝试以两种其他方式改进这个模型:
-
调整模型参数以查看默认值是否一定是最佳选择
-
增加数据集大小
在本章中,我们为了使算法能够处理数据集,甚至是在 16 GB 内存机器上,对数据集进行了大量子采样。我们将在第九章和第十章中更多地讨论方法的可扩展性,但在此期间,我们将这项工作留给你,以便你使用这些数据进一步提高交叉验证的准确性!
6.2.5. 模型洞察
通过构建一个预测特定答案的模型来深入了解数据是很有趣的。从特征重要性列表中,你可以了解哪些参数具有最大的预测能力,并利用这一点以新的方式查看数据。在我们最初的失败尝试中,正是因为检查了特征重要性列表,我们发现了数据中的问题。在当前的工作模型中,你也可以使用这个列表来启发一些新的可视化。
在本节中我们模型的每一次迭代中,最重要的特征都是接车和下车的位置特征。图 6.12 绘制了产生小费的乘客的下车地点的地理分布,以及没有产生小费的行程的下车地点。
图 6.12. 乘客上下车的地理分布

图 6.12 显示了在靠近城市中心下车时不给小费的有趣趋势。为什么会有这种情况?一个可能的原因是交通状况造成了许多缓慢的行程,乘客可能并不满意司机的行为。作为一个非美国公民,我还有另一个理论。这个城市的特定区域金融工作者和游客数量都很多。我们预计金融群体会在曼哈顿南部更远的地方分布。在我看来,游客很可能是造成这种差异的最可能原因:许多国家对于小费的规定与美国大相径庭。一些亚洲国家几乎从不给小费,许多北欧国家小费较少,且很少在出租车中给小费。你可以基于这个数据集进行许多其他有趣的调查。当然,重点是,现实世界的数据经常可以用来对现实世界以及生成数据的人说些有趣的事情。
6.3. 概述
本章介绍了一个来自现实世界的数据集,并定义了一个适合你在前五章中积累的机器学习知识的问题。你经历了整个机器学习工作流程,包括初始数据准备、特征工程以及模型构建、评估、优化和预测的多次迭代。本章的主要收获如下:
-
随着更多组织产生大量数据,组织内部可用的数据量也在不断增加,即使不是公开的。
-
2013 年纽约市所有出租车行程的记录已公开发布。纽约市一年中发生的出租车行程数量真是惊人!
-
现实世界的数据可能很混乱。可视化和对领域的了解有帮助。不要陷入过于完美的场景,也不要对数据做出过早的假设。
-
从最简单的模型开始迭代。不要在过早优化上浪费时间。逐渐增加复杂性。
-
做出选择并继续前进;例如,尽早选择一个算法。在理想的世界里,你会在构建模型的迭代过程的每一步都尝试所有组合,但你必须固定一些东西才能取得进展。
-
为了了解领域并可能进一步改进模型,深入了解模型和数据。
6.4. 本章术语
| 词汇 | 定义 |
|---|---|
| 开放数据 | 由机构和组织公开提供的数据。 |
| FOIL | 信息自由法。(联邦版本被称为信息自由法案,或 FOIA。) |
| 过于完美的场景 | 如果一个模型与你的预期相比极其准确,那么很可能是模型中的某些特征或某些数据特性导致模型“作弊”。 |
| 过早的假设 | 在未经验证的情况下对数据进行假设,可能会使你对结果的看法产生偏差。 |
第七章. 高级特征工程
本章涵盖
-
使用高级特征工程概念来提高你的机器学习系统的准确性
-
通过使用自然语言处理技术从文本中提取有价值的特征
-
从图像中提取意义并在你的机器学习项目中使用它们作为特征
你在第五章中探索了特征工程的基本概念,并在第六章中应用了简单的特征工程技术到现实世界的数据中。在本章中,你将了解更复杂的技巧,这些技巧可以用于面对当今世界常见的各种数据类型。其中最重要的两种是文本和图像。本章介绍了从文本和图像数据中提取特征的高级技术,以便在机器学习管道中使用这些数据。
7.1. 高级文本特征
你已经在第五章中了解了文本数据的简单特征工程,本节提供了关于这些技术背后的思想的更多细节,并介绍了可以进一步提高模型准确性的更高级概念。
回想一下,从文本中提取特征的任务是将各种长度和单词的文本转换为一种共同的特征集。在第五章中,你学习了词袋表示法,其中你统计了所有文本中单词的出现次数,并使用前 N 个单词的计数作为 N 个新的特征。将自然语言文本转换为机器可用的数据这一工作通常被称为自然语言处理,或 NLP。
7.1.1. 词袋模型
词袋是 NLP 中最简单但也是最广泛使用的技术之一。对于任何基于文本的问题,它都是一个很好的起点。它也是本章后面将要探讨的许多其他更高级方法的基础。你将分两部分了解这个模型:首先,标记化和转换,然后是向量化。
标记化和转换
将文本分割成片段的过程称为标记化。最常见的分割方式是基于单词,但在某些情况下(例如,在基于字符的语言中),你可能希望基于字符或基于单词对或单词组进行分割,甚至更高级的分割。分割中的单词组称为n-gram。两个或三个单词的组合分别称为bigram和trigram(它们在单词unigram之后是最常见的)。图 7.1 中的例子中的 bigram 包括“the lazy”、“brown fox”等等。trigram 包括“brown fox jumps”和“jumps over the”。
图 7.1. 词袋提取算法的初始步骤

在某些情况下,扩展到多个单词可能有助于你的模型,因为它提供了更多的文本上下文。但使用多个单词通常也会显著增加特征数量。在实践中,你通常只从单词表示开始。如果你想转向更高阶的语法,你必须确保使用能够处理稀疏数据的 ML 算法。你将在下一个小节中了解更多关于这一点。
我们词袋算法的下一步是对从文本中提取的标记进行必要的转换。一个很好的转换例子是将所有单词转换为小写,这样你就不会为“fox”和“Fox”产生特征,这可能会增加模型的噪声。然而,在某些情况下,你可能想保留大小写,如果这在你的项目中是有意义的(例如,如果文本中常见的专有名词具有高度预测性,或者如果 ALL CAPS 有意义)。词干提取——去除单词后缀——对于从具有相似意义的不同单词中提取更多信号也是一种强大的转换。例如,使用词干提取,单词“jump”、“jumping”、“jumps”和“jumped”在你的字典中都会表示为标记“jump”。其他如自定义处理数字、标点符号和特殊字符的转换也可能很有用,具体取决于文本内容。
接下来,你可以定义你将从中生成文本特征的字典。在机器学习项目中,通常会对字典中的特征数量(即单词数量)设置一个限制。这通常是通过按单词出现次数排序,并仅使用前 N 个单词来完成的。
向量化
你可以使用你的词袋字典来生成用于你的 ML 模型的特征。在定义字典后,你可以将任何文本转换为与文本中每个字典单词出现次数相对应的数字集合。图 7.2 显示了这一过程,这个过程被称为向量化。
图 7.2. 使用词汇表,你现在可以将每个文本表示为一个数字列表。行显示了图 7.1 中两个小文本的计数以及关于句子“The quick brown fox jumps over the lazy dog”的维基百科页面的计数,这是一个英语回文句(它包含了英语字母表中的所有字母)。

但还有一个问题我们尚未讨论。大多数自然语言文本包含许多对理解主题不重要的词,它们只是“填充”的。这些词包括“the”、“is”和“and”等。在自然语言处理研究中,这些被称为停用词,通常从字典中移除,因为它们通常不高度预测任何有趣的内容,并且可能会稀释从机器学习角度来看重要的更有意义的词。在我们的单词已经按出现次数排序的情况下,移除停用词的常用方法是丢弃所有出现次数超过某个词数阈值的单词。图 7.2 展示了示例;较大的文本(图中的第三行)中“the”这个词的出现次数比其他任何词都要多。因此,挑战在于定义一个阈值,以确定一个特定的词是停用词而不是有意义的词。大多数自然语言处理库,如 NLTK Python 库,都包含一系列语言的预构建停用词列表,这样你就不必每次都这样做。然而,在某些情况下,停用词列表将因你的特定项目而异,你需要选择一个停用词阈值(一个标准的选择是排除任何在所有文档中出现超过 90%的单词)。
虽然在图 7.2 中不明显,但任何现实的字典都会有许多词,通常只有其中的一小部分会出现在你为生成特征而创建的文本中。这种组合通常会使文本特征包含很多零。在给定的文本中,只有少数字典词会被找到,因此我们称这些词为“词袋”特征稀疏的。如果你有很多稀疏特征(通常有 1,000 个特征,只有一小部分非零元素),选择一个可以原生处理稀疏特征的机器学习算法,或者一个可以处理许多低显著性特征而不牺牲准确性的算法是个好主意。scikit-learn Python 库中的朴素贝叶斯算法可以原生处理稀疏数据,因此非常适合文本分类问题。像随机森林这样的算法已知可以很好地处理许多低显著性特征,尽管效果可能会有所不同。你应该始终通过使用第四章中讨论的评估和优化技术来测试不同方法的功效。
7.1.2. 主题建模
词袋方法简单易懂且易于实现。但其他更高级的方法可能导致机器学习模型准确性的大幅提升。本节介绍了这三种方法中的三种。
词袋模型的一个问题是简单词频的性质。如果某个词(不是停用词)在语料库中很常见——例如,在机器学习论文语料库中的“数据”一词——知道这个词也出现在新文本中并不一定有信息量。相反,你最好关注那些相对罕见且更能预测感兴趣的结果的词。为此,通常通过该词在语料库中的总计数倒数来缩放词频。因为你只想用数字尽可能好地描述文本,而在训练语料库中不常见但在新文档中常见的词可能更能表明新文档的意义,所以你最好优先考虑这个罕见的词。
词频-逆文档频率
一种试图解决这个确切问题的常用算法被称为词频-逆文档频率,简称tf-idf。这个算法是通过词频(tf)和逆文档频率(idf)的乘积来计算的。
tf 可以用不同的方式计算,但最简单的是使用一个词在特定文档中出现的次数。也常见使用 tf 因子的其他版本,例如二进制(如果词在文档中,则为 1,否则为 0)和对数(1 + log[tf])。
逆文档频率是通过总数为文档总数的对数除以包含该词的文档数来计算的,这样相对不常见的词就能获得更高的值。在它的最简单形式中,tf-idf 方程看起来是这样的:

Tf-idf 可以从任何文本语料库中生成好的机器学习特征。它也可以在其他领域有用,例如搜索。因为为任何文档生成一个数字向量,你也可以找到文档之间的“距离”,就像它们 tf-idf 向量表示之间的距离一样。如果用户的搜索查询是一个文档,你可以以这种方式找到数据集中任何其他文档之间的距离,从而根据查询返回文档的排名列表。下一节中的列表 7.1 展示了如何使用 scikit-learn Python 库从文档中生成 tf-idf 向量,以及一种更高级的技术,称为潜在语义索引。
隐含语义分析
潜在语义分析,或 LSA(也常称为潜在语义索引,或 LSI),是一种更复杂的话题建模方法。它在概念上和计算上也都更先进。想法是使用词袋计数来构建一个词-文档矩阵,其中每一行代表一个词,每一列代表一个文档。然后,这个矩阵的元素被规范化,类似于 tf-idf 过程,以避免频繁的词主导矩阵的权重。
LSA 算法的主要技巧在于其对概念的理解。概念是文档语料库中相似术语的模式。例如,“dog”的概念可能有关联术语(在这种情况下是单词)如“barking”,“leash”和“kennel”。算法不会标记“dog”这个概念,而是通过分析文档中术语的共现来找出哪些单词相关联,然后确定这些单词通过某种抽象概念相连。单词“dog”本身可能是一个与“dog”概念相关的重要术语。这些主题被认为是数据中的隐藏或潜在的,因此得名潜在语义分析。
LSA 使用奇异值分解(SVD)^([1])——一种著名的数学工具——将词-文档矩阵(A)分解为三个矩阵(T,S,D)。T是词-概念矩阵,它将术语(例如,“barking”和“kennel”)与概念(例如,“dog”)相关联,而D是概念-文档矩阵,它将单个文档与你在以后用于从 LSA 模型中提取特征的概念相关联。S矩阵持有奇异值。在 LSA 中,这些表示一个术语对一个文档的相对重要性。与你在词袋模型和 tf-idf 算法中限制特征数量相同,你现在可以选择前几个奇异值,并将特征空间限制在更易于管理的范围内;回想一下,词-文档矩阵([A])可以非常大且稀疏。
¹
对于熟悉主成分分析(PCA,本章后面将介绍)的读者来说,SVD 是使你能够从数据集中计算 PCA 坐标的相同技术。你可以将 LSA 视为“词袋的 PCA”。
使用 SVD 的前 N 个成分,你可以通过从概念-文档矩阵(D)中取出相应的行来为你的机器学习模型生成 N 个特征。当有新的文档用于预测时,你可以通过执行矩阵乘法:D = ATTS*(–1)来从先前学习的 LSA 模型中生成一组新的特征。在这里,A^T是新文档的词频(或 tf-idf),使用定义的词典,而T和S*是 SVD 中的词-概念和奇异值矩阵。
虽然理解 LSA 的原则很有用,但并不是每个人都足够熟悉线性代数来做这些计算。幸运的是,有很多实现可以方便地用于你的机器学习项目。scikit-learn Python 库包括运行 LSA 所需的功能,通过(1)使用 tf-idf 生成词-文档矩阵,(2)执行矩阵分解,(3)将文档转换为向量,如下所示。
列表 7.1. 使用 scikit-learn 进行潜在语义分析

接下来,你将了解一些最近在主题建模领域变得流行的 LSA(潜在语义分析)的高级扩展。
概率方法
LSA 基于线性代数(涉及向量和矩阵的数学),但可以使用对每个文档作为主题分布的统计混合模型进行概率方法的等效分析。这些概念都相对高级,我们在这里不会深入数学细节,但概率方法在某些数据集上可以更好地提高模型精度。
LSA 的概率对应物被称为 pLSA(代表概率)。这种更广泛使用的版本被称为潜在狄利克雷分析(LDA),其中对主题的分布做出了特定假设。您假设一个文档可以由一组小的主题来描述,并且任何术语(单词)都可以归因于一个主题。在实践中,LDA 可以在各种数据集上表现良好。以下代码示例突出了如何使用 Gensim 库在 Python 中应用 LDA。
列表 7.2. 使用 Gensim 在 Python 中进行的潜在狄利克雷分析

在 LDA 模型中使用的话题数量是一个需要根据数据和问题进行调整的参数。我们鼓励您定义您的性能指标,并使用第四章中的技术来优化您的模型。还值得注意的是,如果新的训练数据持续到来,Gensim 中的 LDA 可以实时更新。我们鼓励您探索 Gensim 中许多其他有趣的自然语言和主题建模算法。在第十章中,您将使用这些高级文本特征提取技术来解决一个实际的机器学习问题。下一节介绍了一种完全不同的文本特征提取方法:扩展文本内容。
7.1.3. 内容扩展
我们现在转向一个完全不同的概念,用于从文本中提取特征。本节的方法不是用数字表示文本,而是扩展文本内容以包含更多文本(然后可以进行特征化)或引入对特定 ML 问题有用的其他信息。以下是一些常见的内容扩展方法。
跟随链接
如果您希望通过从推文中提取文本特征来构建 ML 分类器(例如,用于 Twitter 情感分析,将帖子分类为正面或负面情感),您通常会发现 140 个字符的限制是一个问题。您可能没有足够的信息来获得模型所需的准确度。
许多推文包含指向外部网页的链接,这些网页可以包含更多的文本,您可以用链接中的文本来扩展推文,从而提高数据质量。您甚至可以深入网页上的链接,以构建更大的文本语料库。
知识库扩展
一种更高级的文本扩展方法是在文本中检测命名实体,并使用在线知识库(如维基百科)中每个命名实体的信息来扩展原始文本。在这种情况下,命名实体可以是你在维基百科上可以查找的任何东西。然后,你会从该命名实体的维基百科条目中获取文本,并执行第 7.1.2 节中提到的任何文本提取算法。
提取命名实体并非易事,一直是多个研究小组的研究课题。其中一个问题是源于名称的歧义性。如果一个单词有多种含义,你可能会因为包含完全错误的信息而扩大你的特征集。一个可能的解决方案是使用像维基百科这样的知识库再次对命名实体进行消歧。首先,你可以假设推文中出现的任何其他单词,例如,在知识库文本中也很常见。你也可以使用维基百科的链接图来找出两个命名实体在知识库中的接近程度。一个例子是包含命名实体“Tesla”的推文。一些推文会与电子汽车公司相关,而另一些则可能关于发明家尼古拉·特斯拉。如果推文中包含“car”或“model”等单词,那么它很可能是关于特斯拉公司。如果它包含与“Edison”相关的实体,那么它可能是关于这个人(特斯拉和爱迪生在 1884 年纽约市一起工作过)。
文本元特征
另一种通过分析文本以扩展具有价值数据的技巧是分析文本的元特征。与之前讨论的技术不同,这些类型的特征是问题相关的。
让我们再次以推文为例。推文包含所有 sorts of 有价值的数据,这些数据特定于推文并且可以提取,例如标签和提及,以及来自 Twitter 的元信息,例如转发和喜欢的计数。作为基于网络的文本的另一个例子,你可以从链接文本中提取基本信息,例如顶级域名。在一般文本中,你可以提取单词或字符的计数,或不同语言中特殊字符的数量。提取语言本身可能就是一个机器学习分类器,它将答案作为特征提供给另一个分类器。
要选择正确的文本元特征,你应该发挥想象力,并了解手头的问题。记住,机器学习工作流程是一个迭代过程;你可以开发一个新的特征,然后回到管道中,分析随着时间的推移准确率是如何提高的。
你还可以使用文本来获取其他类型的数据。文本可能包含对机器学习模型理解有用的日期和时间,或者文本的元数据中可能包含时间信息。第五章介绍了日期时间特征提取,这些也可以在此背景下使用。
如果你正在分析一个网页,或者文本中有一个 URL,你可能可以访问对理解文本上下文很重要的图像或视频。从图像和视频中提取特征需要更高级的技术,你将在下一节中探讨。
7.2. 图像特征
人类智能的坚强堡垒之一是我们的视觉和空间感,以及我们识别图像和日常生活中导航的 3D 场景中的模式和对象的能力。我们思考的大部分方式都基于这些能力。另一方面,计算机以比特和它们的视觉类比——像素来思考。从历史上看,这一事实严重限制了计算机在视觉模式识别方面达到人类认知水平的能力。只有随着计算机视觉和人工智能中复杂算法的出现——机器学习可以说是由此产生的——研究人员和从业者才越来越接近达到人类水平,尽管大多数情况下是在狭窄指定的领域。另一方面,如果你能通过计算机视觉和机器学习技术接近匹配人类水平的模式识别准确性,你就可以获得大多数计算系统的一些好处:可扩展性、可用性和可重复性。
本节介绍了几种从图像中提取特征的方法,这些特征可以用于你的机器学习工作流程。首先,你将查看简单的图像特征,包括原始像素、颜色和图像元数据。
7.2.1. 简单图像特征
处理图像的最简单方法值得提及,不仅因为它有时可能足够,而且还因为它展示了机器学习方法的真正力量,与手动或传统统计方法相比。你将图像中像素的值视为进入你的机器学习模型的特征。
在实践中,你将所有像素排成一行,将二维图像转换为一维。如果是一个彩色图像,你基本上有三个图像(红色、蓝色、绿色通道)。正常像素值是 0.0 到 1.0,或者 0 到 255(对于 8 位图像)。你可能已经猜到,对于任何现代图像,这会创建成千上万的特征,这将增加计算需求,并可能导致过拟合,从而影响准确性。这就是为什么这种方法在实践中并不常用。然而,你可能会惊讶地发现,对于某些机器学习问题,如区分室内和室外图像,这种方法在没有任何复杂特征工程的情况下也能很好地工作。
原则上,所有信息都编码在像素中。如果您出于性能原因(计算或准确性方面)不打算使用原始像素,您必须找到一种方法,用更少的特征来表示图像,这些特征对您特定的任务来说足够好。这正是您在前一节关于文本特征和许多其他特征工程技术中解决的问题。在 7.2.2 节的末尾,我们介绍了一些新的自动特征提取方法,但大多数当前的实际图像机器学习项目都使用本节中描述的一些技术。
颜色特征
假设您正在尝试根据图像的风景将图像分类到不同的类别中。例如,类别可以是天空、山脉或草地。在这种情况下,使用构成颜色来表示图像似乎很有用。您可以计算图像每个颜色通道的简单颜色统计信息,例如平均值、中位数、众数、标准差、偏度和峰度。这为常见的 RGB(红-绿-蓝通道)图像产生了 6 x 3 = 18 个特征。
另一组表示图像中颜色的特征是图像的颜色范围。表 7.1 显示了一个可能的颜色范围列表,它将覆盖大部分颜色空间。
表 7.1. 颜色范围特征示例。您将除数加 1,以避免除以 0 产生缺失值。
| 颜色范围 | 定义 |
|---|---|
| 红色范围 | 红色通道最大值减去红色通道最小值 |
| 红到蓝范围 | 红色范围 / (蓝色通道最大值减去蓝色通道最小值加 1) |
| 蓝到绿范围 | (蓝色通道最小值减去蓝色通道最大值) / (绿色通道最小值减去绿色通道最大值加 1) |
| 红到绿范围 | 红色范围 / (绿色通道最大值减去绿色通道最小值加 1) |
图像元数据特征
除了颜色信息外,图像可能包含对您的问题有帮助的元数据。例如,大多数照片都包含相机在拍照时记录的 EXIF 数据。如果您正在构建一个预测用户认为图像是否有趣或美丽的模型,算法可以使用相机的品牌和镜头、光圈值和变焦级别。表 7.2 概述了可能对图像元数据特征有用的内容。
表 7.2. 可包含在机器学习流程中的图像元数据特征
| 特征 | 定义 |
|---|---|
| 制造商 | 制作相机的公司 |
| 方向 | 相机的方向(横向或纵向) |
| 日期时间 | 拍摄时间(使用第五章中介绍的日期时间功能 chapter 5) |
| 压缩 | 图像的压缩方式(通常是 JPEG 或 RAW) |
| 分辨率 | 宽度和高度维度的像素数量 |
| 长宽比 | 通过除以高度和宽度分辨率来表示的测量值 |
| 曝光时间 | 曝光秒数或分数 |
| 光圈 | 表示光圈(例如,2.8 或 4.0)的 f 数 |
| 闪光灯 | 闪光灯是否开启 |
| 焦距 | 从镜头到焦点的距离 |
使用这些简单的特征,你可能能够解决许多具有图像数据部分的机器学习问题。当然,你还没有在图像中表示任何形状或对象,这在许多图像分类问题中显然是重要的!下一节将介绍更多常用的计算机视觉技术,这些技术通常用于表示对象和形状。
7.2.2. 提取对象和形状
到目前为止,你在从图像中提取信息时还没有考虑对象或形状。在本小节中,你将了解几种使用可以通过统计和计算方法自动提取的数值特征来表示形状的方法。
边缘检测
可能表示图像中形状的最简单方法就是找到它们的边缘,并在这些边缘上构建特征。图 7.3 展示了图像中边缘检测的一个示例。
图 7.3. 将 Canny 边缘检测算法应用于女孩的照片(左侧为输入)生成一个新的二值图像(右侧),其中只追踪了边缘。(图片由 JonMcLoone 在英文维基百科提供,CC BY-SA 3.0,commons.wikimedia.org/w/index.php?curid=44894482)

几种著名的算法可以在图像中找到边缘。其中最常用的有 Sobel 和 Canny 边缘检测算法。图 7.3 展示了 Canny 算法。
使用 scikit-image 进行 Python 图像处理
我们在这本书中已经提到了几次 scikit-learn Python 库,因为它提供了一种尝试许多机器学习算法的简单方法。在计算机视觉和图像处理世界中,与此类似的是 scikit-image。这是尝试本节中讨论的算法的同样有用的方法。
如果你使用 Pip,可以使用以下命令轻松安装 scikit-image:
$ pip install scikit-image
这里有一个使用此库进行边缘检测的简单示例:
>>> import skimage
>>> image = skimage.data.camera()
>>> edges = skimage.filter.sobel(image)
现在你已经从图像中提取了边缘,你可以从这些边缘中提取特征。最简单的方法是计算一个表示图像中边缘总数的数字。如果edges是你的边缘图像,而res是图像的分辨率,则方程如下:

与其他特征一起,这可能有助于确定感兴趣的对象。你可以根据你的用例定义其他基于边缘的特征。例如,你可以在网格中为图像的多个部分计算前面的边缘得分。
高级形状特征
存在更多复杂的特征提取算法,可以用来检测特定的形状和物体。其中之一是方向梯度直方图(HOG)。在机器学习中,这些算法可以用来检测图像中的人类面部或特定的动物,例如。
HOG 算法是一系列多步骤的图像处理技术。该算法的目标是在对图像区域中的形状和物体进行描述时,对尺度和小方向变化不太敏感。这是通过以下方式实现的:
-
计算梯度图像(图像边缘“移动”的方向)
-
将图像划分为称为单元格的小块
-
计算那些细胞内梯度的方向
-
计算这些方向在单个细胞中的直方图
通常,较大的图像块是从较小的单元格定义的,并用于单元格中梯度值的归一化。这样,你可以避免对光照或阴影的变化过于敏感。然后,每个单元格可以被展平成一个特征列表,这些特征描述了图像中的形状,并可用于机器学习流程。
通常,你关注的是从实用角度理解算法的有用性,因此你可以继续使用已经实现的 HOG 特征库。scikit-image Python 库提供了一个易于使用的 HOG 版本。以下列表显示了如何计算图像的 HOG 特征。图 7.4 展示了将 HOG 变换应用于美国宇航员 Eileen Collins 照片的结果,她是第一位太空船指挥官女性。
图 7.4. 应用 HOG 变换。此图像来自 scikit-image 文档中的 HOG 示例页面 (scikit-image.org/docs/dev/auto_examples/features_detection/plot_hog.html#sphx-glr-auto-examples-features-detection-plot-hog-py)。

列表 7.3. 使用 scikit-image 在 Python 中计算方向梯度直方图
import skimage
image = skimage.color.rgb2gray(skimage.data.astronaut())
hog = skimage.feature.hog(image, orientations=9, pixels_per_cell=(8,8),
cells_per_block=(3,3), normalise=True, visualise=True)
在这里,你可以看到如何轻松地计算 HOG 特征,同时定义要考虑的方向数量、单元格的像素大小、单元格中块的大小,以及是否对结果进行归一化和可视化。
使用 HOG 特征,你有一个强大的方法在图像中找到物体。就像所有的事情一样,在某些情况下,HOG 并不奏效——例如,当物体显著改变方向时。你应该像往常一样对机器学习系统进行适当的测试,以确定它对当前问题的有用性。
维度降低
在执行特征提取时,我们几乎总是在进行降维的游戏,除了上一节中的内容扩展方法。但有一些技术通常用于一般的降维,其中最广泛使用的是称为主成分分析(PCA)。
主成分分析(PCA)允许您从一组图像中找到“典型”图像,这些图像可以用作构建块来表示原始图像。结合前几个主成分可以使您重建大量训练图像,而后续成分将覆盖图像中较少出现的模式。对于新图像的特征是通过找到与主图像的“距离”来生成的,因此每个主图像代表新图像的单个数字。您可以在您的机器学习问题中使用尽可能多的主成分。
主成分分析(PCAs)被认为是线性算法;它们无法表示本质上非线性的数据。PCA 或其他类型的非线性降维方法有几种扩展。我们有过良好经验的例子是扩散映射。
自动特征提取
人工神经网络的世界经历了一次复兴。这些网络在 20 世纪 80 年代发明,并受到大脑生物学的启发,曾是人工智能领域(该领域已发展成为我们今天所知的机器学习领域)的中心。几十年来,它们被认为是某些机器学习问题有用的方法。但由于它们难以配置和解释,存在过拟合问题,并且计算扩展性较差,最终成为解决现实世界问题时的一种最后手段。现在,机器学习研究中的几个突破主要解决了这些问题。深度神经网络(DNNs)现在被认为是许多机器学习问题的最佳实践,尤其是那些处理图像、视频或声音的问题。图 7.5 显示了神经网络的布局。
图 7.5. 一个简单的人工神经网络。深度神经网络由许多这样的简单网络层组成。(图片来自维基百科。)

在深度神经网络(DNNs)中,每一层都能够定义一组对当前问题有用的新特征。节点之间的权重定义了这些特征对下一层的重要性,以此类推。这种方法传统上容易过拟合,但最近开发的技术允许以保持准确性的方式移除节点连接,从而降低过拟合的风险。
深度神经网络(DNNs),也称为深度信念网络或深度学习,仍然是一个相对较新的领域。我们鼓励您关注其发展。
7.3. 时间序列特征
许多由现代数据收集系统收集的数据集以时间序列的形式出现,这是对过程或一系列过程随时间变化的测量。时间序列数据很有价值,因为它提供了对当前主题随时间变化特性的窗口,并使机器学习从业者能够超越仅使用这些主题的静态快照来做出预测。但完全提取时间序列数据的价值可能很困难。本节描述了两种常见的时间序列数据类型——经典时间序列和点过程(事件数据)——并详细介绍了最广泛使用的时间序列特征。
7.3.1. 时间序列数据的类型
时间序列数据主要有两种类型:经典时间序列和点过程。经典时间序列由随时间进行的数值测量组成。通常,这些测量在时间上是均匀分布的(每小时、每日、每周等),但也可以是不规则采样的数据。以下是一些经典时间序列数据的例子:
-
股票市场的价值,以十亿美元为单位(例如,按小时、每日或每周衡量)
-
商业建筑或住宅的日常能源消耗
-
客户银行账户随时间变化的美元价值
-
在工业制造厂中监控的诊断集(例如,不同部件的物理性能测量或随时间变化的工厂产出测量)
另一方面,点过程是随时间发生的事件集合。与在时间上测量数值量不同,点过程由每个离散事件的时间戳组成,加上(可选的)关于事件的元数据,如类别或值。因此,点过程也通常被称为事件流。以下是一些点过程的例子:
-
网络用户的活动,衡量每次点击的时间和类型(这通常也称为点击流数据)
-
全球地震、飓风、疾病爆发等事件的发生
-
客户在其账户历史中进行的个别购买
-
制造厂中的事件日志,记录每次员工接触系统和每次制造过程步骤完成的时间
一个敏锐的读者可能会注意到,对于某些时间序列,经典时间序列表示和底层点过程之间存在一对一的映射。例如,客户的银行账户可以很容易地看作是账户随时间的变化值(经典时间序列)或一系列个别交易(点过程)。这种对应关系在创建单个数据集上的各种类型的时间序列特征时可能很有用。但转换并不总是可能的。(例如,很难想象与简单网络点击相关的经典时间序列会是什么样子。)
为了使这一点更加具体,让我们看看可以同样容易地被视为点过程或时间序列的时间序列数据。表 7.3 显示了 2003 年至 2014 年间收集的旧金山犯罪数据集的前几行(数据集在data.sfgov.org公开可用)。总的来说,该数据集包括城市中发生的超过 150 万起犯罪事件。对于每起犯罪,数据包括犯罪的确切日期和时间、犯罪类型和地点。
表 7.3. 旧金山的原始犯罪数据,作为事件序列
| 事件编号 | 日期 | 时间 | 区域 | 类别 |
|---|---|---|---|---|
| 80384498 | 04/13/2008 | 00:54 | NORTHERN | 酒精中毒 |
| 80384147 | 04/13/2008 | 00:55 | CENTRAL | 非犯罪 |
| 80384169 | 04/13/2008 | 00:56 | BAYVIEW | 攻击 |
| 80384169 | 04/13/2008 | 00:56 | BAYVIEW | 毒品/麻醉品 |
| 80384153 | 04/13/2008 | 00:57 | BAYVIEW | 其他 |
| 80384175 | 04/13/2008 | 01:00 | CENTRAL | 攻击 |
| 80384943 | 04/13/2008 | 01:00 | CENTRAL | 盗窃/盗窃 |
| 80392532 | 04/13/2008 | 01:00 | INGLESIDE | 盗窃/盗窃 |
| 80384943 | 04/13/2008 | 01:00 | CENTRAL | 诈骗 |
| 80384012 | 04/13/2008 | 01:15 | NORTHERN | 可疑事件 |
你可以通过多种方式将这原始数据聚合为经典的时间序列数据:按年、按月、按星期几等,每个区域或类别可能都有不同的时间序列。列表 7.4 演示了如何将原始事件数据聚合为旧金山每月犯罪数量的时间序列。通过月份整数犯罪计数得到的时间序列在图 7.6 中绘制。数据显示,从 2003 年每月 13,000 起犯罪的比率有显著下降,最近犯罪活动有所上升。
图 7.6. 旧金山每月犯罪计数的经典时间序列。这些数据是从原始事件数据中处理得到的。对于机器学习建模,你可以从事件数据、经典时间序列或两者中提取特征。

列表 7.4. 将旧金山犯罪事件数据转换为经典时间序列

7.3.2. 时间序列数据预测
正如存在两种常见的时间序列数据类型一样,你也可以从时间序列数据中做出两种常见的预测。第一种是 时间序列预测,它试图根据过去的测量值预测时间序列的未来值(或未来事件的时刻)。时间序列预测问题包括以下内容:
-
预测股票明天的价格
-
预测亚利桑那州凤凰城的明天温度
-
预测明年丹麦的能源消耗
-
预测北美下一次主要飓风的日期
这三个任务中的前三个涉及预测经典时间序列的未来值,而第四个是在点过程数据集上的预测。共同点是每个任务都涉及分析单个时间序列的值来预测未来。请注意,关于时间序列预测的大多数文献都属于时间序列分析的分支,而机器学习实践者在这里的关注相对较少(尽管这种情况正在改变)。有关更多详细信息,任何 Google 或 Amazon 搜索都会揭示大量结果!
第二种常见的时间序列预测类型是 时间序列分类或回归。这里的目标不是预测单个时间序列的未来值,而是对数百或数千个时间序列进行分类(或预测一个实值输出)。这类问题的例子包括以下内容:
-
使用每个用户的在线点击流来预测每个用户是否会点击特定的广告
-
使用 QA 测量值的时间序列来确定一组制造产品(例如,灯泡)中哪些最有可能在下一个月失效
-
根据用户在注册后第一周内的应用活动流预测每个在线应用的用户的终身价值
-
根据患者的病历预测哪些患者最有可能遭受术后并发症
与时间序列预测不同,机器学习对时间序列分类和回归产生了重大影响。下一节主要关注为分类/回归目的创建时间序列特征,但许多这些方法也可以应用于时间序列预测。
7.3.3. 经典时间序列特征
本节描述了经典时间序列中最常见的特征工程方法。我们从最简单的时间序列度量开始,并逐步描述更复杂和高级的方法。
简单时间序列特征
这听起来可能有些荒谬,但最简单的时间序列度量可能完全忽略时间轴!在分析测量值的分布时,不考虑时间戳,通常可以提供用于分类、回归或预测的有用信息。为了讨论的目的,我们概述了四个简单(但强大)的度量,这些度量仅涉及时间序列测量值的边缘分布:
-
平均— 测量值的平均值或中位数可以揭示时间序列平均值的趋势。
-
分散— 分布的分散度测量,如标准差、中位数绝对偏差或四分位数范围,可以揭示测量值的整体变异趋势。
-
异常值— 落在典型分布范围之外的时间序列测量值的频率(例如,比平均值大两个、三个或四个标准差),在许多用例中可以携带预测能力,例如预测生产线中断或故障。
-
分布— 估计时间序列测量值的边缘分布的高阶特征(例如,偏度或峰度),或者更进一步,对命名的分布(例如,正态分布或均匀分布)进行统计检验,在某些情况下可能是预测性的。
您可以通过计算窗口统计来使事物更加复杂,这涉及到在指定时间窗口内计算前述汇总指标。例如,仅测量数据的最后一周的平均值或标准差可能具有高度预测性。从那里,您还可以计算窗口差异,这将是从一个时间窗口到下一个时间窗口这些指标之间的差异。以下列表展示了计算这些特征的一个代码示例。
列表 7.5. 窗口统计和差异

高级时间序列特征
接下来,您将转向更复杂的经典时间序列特征。自相关特征衡量时间序列与其滞后版本之间的统计相关性。例如,时间序列的一个自相关特征会将原始时间序列与向左移动一个时间间隔的相同时间序列(移除非重叠部分)进行相关性分析。通过以这种方式移动时间序列,您可以捕捉到时间序列中的周期性和其他统计结构的存在。自相关函数的形状(在时间滞后网格上计算的自相关)捕捉了时间序列结构的核心。在 Python 中,statsmodels模块包含一个易于使用的自相关函数。图 7.7 展示了自相关是如何计算的,并绘制了 SF 犯罪数据的自相关函数。
图 7.7. 顶部:原始时间序列与 12 个月滞后时间序列的相关性定义了 12 个月的自相关。底部:SF 犯罪数据的自相关函数。对于短期尺度,自相关较高,表明任何月份的犯罪值对前几个月的值有高度依赖性。

傅里叶分析是时间序列特征工程中最常用的工具之一。傅里叶分析的目标是将时间序列分解为一系列频率上的正弦和余弦函数之和,这些频率在许多现实世界的数据集中自然存在。执行这种分解可以使你快速识别时间序列中的周期性结构。傅里叶分解是通过使用离散傅里叶变换来实现的,它计算时间序列的谱密度——即它在每个给定频率上与正弦函数的相关程度——作为频率的函数。将时间序列分解为其组成谱密度的结果称为频谱图。图 7.8 显示了使用scipy.signal.periodogram函数(几个 Python 模块有频谱估计的方法)计算出的旧金山犯罪数据的频谱图。从频谱图中,可以计算各种机器学习特征,如指定频率的谱密度、频率带内谱密度的总和,或最高谱密度的位置(这描述了时间序列振荡的基本频率)。以下列表提供了频谱计算和特征示例代码。
图 7.8. 左:旧金山犯罪数据的频谱图,显示了频率作为函数的谱密度。右:将 x 轴从频率转换为周期的相同频谱图。

列表 7.6. 频谱特征

几种经典的时间序列模型在时间序列分析文献中常用。这些模型的目的是将时间序列的每个值描述为时间序列过去值的函数。这些模型本身已经广泛用于数十年的时间序列预测。现在,随着机器学习成为时间序列数据分析的主流,它们通常与更复杂的机器学习模型(如 SVMs、神经网络和随机森林)一起用于预测。时间序列模型的例子包括以下内容:
-
自回归 (AR) 模型—时间序列中的每个值被建模为最后p个值的线性组合,其中p是一个待估计的自由参数。
-
自回归-移动平均 (ARMA) 模型—每个值被建模为两个多项式函数的和:AR 模型和一个移动平均(MA)模型,该模型是前q个误差项的线性组合。
-
广义自回归条件异方差 (GARCH) 模型—一种在金融分析中常用的模型,它使用 ARMA 模型描述时间序列的随机噪声项。
-
隐马尔可夫模型 (HMM)—一种概率模型,描述时间序列的观测值是从一系列隐藏状态中抽取的,这些隐藏状态本身遵循马尔可夫过程。
您可以使用这些模型以各种方式计算时间序列特征,包括以下这些:
-
使用每个模型的预测值(以及预测之间的差异)本身作为特征
-
使用模型的最佳拟合参数(例如,ARMA(p,q)模型中的p和q的值)作为特征
-
计算模型的统计拟合优度(例如,均方误差)并将其用作特征
通过这种方式,可以实现经典时间序列模型和最先进的机器学习方法的结合。你可以达到两者的最佳效果:如果 ARMA 模型对某个时间序列已经具有高度的预测性,那么使用这些预测的机器学习模型也将是成功的;但如果 ARMA 模型拟合不佳(如大多数实际数据集),机器学习模型提供的灵活性仍然可以产生高度准确的预测。
7.3.4. 事件流的特征工程
本节简要介绍了事件流的特征工程。正如之前在代码列表 7.4 中所示,事件数据可以转换为经典的时间序列。这使得你可以使用前两节中描述的所有特征工程过程来从点过程数据中提取经典时间序列数据。但由于事件数据的粒度更细,因此可以计算许多额外的特征。
类似于第 7.1.3 节中描述的窗口统计,你可以在事件数据上计算简单的窗口和差异统计。但由于点过程数据允许每个事件都有单独的时间戳,因此你可以在任何你想要的时间窗口上计算这些统计,甚至达到极细的粒度。此外,“自上次事件以来时间”、“过去 48 小时内事件数量”和“事件之间的平均时间长度”等统计信息突然变得可行。
最后,正如经典时间序列通常使用 ARMA 和 HMM 等统计模型进行建模一样,点过程数据通常使用泊松过程和非齐次泊松过程等模型进行描述。简而言之,这些模型将事件到达率描述为时间的函数,并使你能够预测下一次事件发生的预期时间。请随意探索这些方法!就像经典时间序列模型一样,可以从点过程模型中通过三种方式推导出机器学习特征:使用模型的预测、模型的参数以及模型的统计拟合优度。
7.4. 概述
在本章中,你学习了从文本和图像中生成特征的方法。你可以在你的机器学习算法中使用这些特征来构建具有人类水平感知能力的“阅读”或“观察”模型。主要收获如下:
-
对于基于文本的数据集,你需要将可变长度的文档转换为固定长度的特征数量。这些方法包括以下几种:
-
简单的词袋方法,其中对每个文档中的特定单词进行计数。
-
tf-idf 算法,它考虑整个语料库中单词的频率,以避免将字典偏向于不重要但常见的单词。
-
更高级的主题建模算法,如潜在语义分析和潜在狄利克雷分析。
-
主题建模技术可以将文档描述为一组主题,主题为一组单词。这允许对文档进行复杂的语义理解,并有助于构建高级搜索引擎,例如,除了在机器学习世界中的有用性之外。
-
你可以使用 scikit-learn 和 Gensim Python 库进行许多有趣的文本提取领域的实验。
-
-
对于图像,你需要能够用数值特征来表示图像的特征:
-
你可以通过定义颜色范围和颜色统计来提取图像中关于颜色的信息。
-
你可以从图像文件本身中提取可能具有价值的图像元数据;例如,通过利用大多数图像文件中可用的 EXIF 元数据。
-
在某些情况下,你需要能够从图像中提取形状和对象。你可以使用以下方法:
-
使用 Sobel 或 Canny 边缘检测滤波器进行简单的基于边缘检测的算法
-
如直方图方向梯度(HOG)等复杂的形状提取算法
-
如 PCA 之类的降维技术
-
通过使用深度神经网络进行自动特征提取
-
-
-
时间序列数据分为两种类型:经典时间序列和点过程。可以从这些数据中估计出大量的机器学习特征。
-
在时间序列数据上执行两个主要的机器学习任务:
-
预测单个时间序列的值
-
对一组时间序列进行分类
-
-
对于经典时间序列,最简单的特征涉及计算时间窗口的汇总统计量和窗口差异。
-
更复杂的特征涉及使用自相关和傅里叶分析等工具对时间序列进行统计分析。
-
可以使用各种经典时间序列模型来推导特征。这些包括 AR,ARMA,GARCH 和 HMM。
-
由于数据的更细粒度,从点过程数据中可以计算所有这些特征以及更多。
-
点过程数据的常见模型包括泊松过程和非齐次泊松过程。
-
7.5. 本章术语
| 词 | 定义 |
|---|---|
| 特征工程 | 将输入数据转换为提取更多价值并提高机器学习模型预测准确性的过程。 |
| 自然语言处理 | 旨在使计算机理解自然语言的领域。 |
| 词袋模型 | 一种将文本转换为数字的方法;计算文档中特定单词出现的次数。 |
| 停用词 | 作为特征不常用但无用的词(例如,“the”,“is”,“and”) |
| sparse data | 当数据主要由 0 组成且数据单元格很少时,我们称数据为稀疏。大多数 NLP 算法产生稀疏数据,你需要使用或转换这些数据以用于你的 ML 算法。 |
| tf-idf | 词频,逆文档频率。一种通过整个语料库中的文本进行归一化的词袋方法。 |
| latent semantic analysis | 一种在文档中寻找感兴趣的主题并将它们与一组单词连接起来的方法。 |
| latent Dirichlet analysis | LSA 思想的扩展,在实际中与许多文本问题表现良好。 |
| content expansion | 将原始内容扩展为更多数据的过程(例如,通过跟随文档中的链接)。 |
| meta-features | 一组不是从内容本身提取,而是从一些相关元数据中提取的特征。 |
| EXIF data | 定义图像元数据的标准。包括有关照片的信息(例如,相机制造商、分辨率、光圈)。 |
| edge detection | 检测图像边缘的过程,以去除大多数图像的噪声。 |
| HOG | 直方图导向梯度。一种理解特定形状和对象图像特征的方法。 |
| PCA | 主成分分析。一种通过更简单、典型的图像来表示图像的方法,从而减少图像的维度数。而不是 100 个像素,一个图像可以通过两个数字来近似:到两个主成分的距离。 |
| deep neural nets | 人工神经网络的扩展,最近在音频视觉数据的机器学习上表现出色。 |
| classical time series | 随时间进行的数值测量序列。 |
| point process | 在时间上收集的事件序列,每个事件都有一个精确的时间戳。 |
| time-series forecasting | 预测单个时间序列的未来值。 |
| periodogram | 时间序列的傅里叶功率谱密度作为振荡频率的函数的图。这项技术可以揭示基本振荡模式,是时间序列数据的有用特征工程工具。 |
第八章. 高级 NLP 示例:电影评论情感
本章涵盖
-
使用真实世界数据集预测电影评论的情感
-
探索此数据可能的用例和适当的建模策略
-
使用基本的 NLP 特征构建初始模型并优化参数
-
通过提取更高级的 NLP 特征来提高模型的准确性
-
在生产中使用此模型的扩展和部署方面
在本章中,你将使用在前一章中获得的某些高级特征工程知识来解决一个实际问题。具体来说,你将使用高级文本和 NLP 特征工程过程来构建和优化一个基于用户提交的电影评论的模型。
和往常一样,您将从调查和分析手头的数据集开始,以了解特征和目标列,这样您就可以做出最佳决定,选择使用哪些特征提取和机器学习算法。然后,您将从最简单的特征提取算法开始构建初始模型,看看您如何只用几行代码就能快速得到一个有用的模型。接下来,您将进一步深入研究特征提取和机器学习建模算法的库,以进一步提高模型的准确性。最后,您将探索将模型投入生产的各种部署和可扩展性方面。
8.1. 探索数据和用例
在本章中,您将使用来自Kaggle竞赛的数据——这是一个数据科学挑战网站,全球的数据科学家在这里解决公司提出的明确问题以赢得奖品。您将使用这些数据,在学习使用前几章开发的工具的同时,通过机器学习解决一个现实世界的问题。
本章中使用的数据来自“单词袋遇见爆米花袋”竞赛(www.kaggle.com/c/word2vec-nlp-tutorial)。您需要在 Kaggle 平台上创建一个账户来下载数据,但这可能是一件好事,因为您可能仍然想在一个大奖竞赛中尝试您新获得的机器学习技能!
在接下来的章节中,我们首先描述数据集,说明各个列的含义以及数据是如何生成的。然后,我们进一步深入,展示数据属性,并对我们拥有的数据进行一些初步观察。从这里,我们头脑风暴可能的用例,这些用例我们可以用手头的数据集来解决,并审查每个潜在用例的数据需求和现实世界影响。最后,我们使用这次讨论来选择一个将在本章剩余部分解决的单一用例。
注意,尽管我们本节的结构是先描述和探索数据,然后找出一个用例来解决问题,但通常步骤是按照相反的顺序进行的。通常,机器学习实践者会从一个用例、假设或要回答的问题集开始,然后寻找并探索数据,以适当地解决手头的问题。这是首选的方法,因为它迫使实践者在深入数据集的细节之前,认真思考用例和所需的数据。尽管如此,接到一个数据集并被要求构建一些酷炫的东西的情况并不少见!
8.1.1. 初步查看数据集
我们的语料库由来自互联网电影数据库(IMDb,www.imdb.com)的书面电影评论组成。训练数据包括 50,000 条评论,选择时确保每部电影在语料库中的评论不超过 30 条。对于每条评论,结果变量被编码为一个二进制特征,如果该评论的手动 IMDb 评分大于 6,则值为 1,如果评分小于 5,则值为 0。介于 5 到 6 之间的中间评分的评论不包括在语料库中。
这个数据集的挑战是设计一个机器学习系统来学习构成正面评论和负面评论的语言模式和结构。关键的是,你需要训练你的模型只从评论的文本中学习,而不是从其他上下文数据中学习,例如电影演员、导演、类型或发行年份。假设这些数据会帮助提高你模型预测的准确性,但在这个数据集中这些数据是不可用的。
除了训练数据集外,还提供了一个包含 25,000 条电影评论的独立测试数据集,这些电影不在训练数据集中。原则上,这组数据可以用来验证你模型的性能,并估计模型在实际部署到现实世界生产环境中的表现。但是 Kaggle 没有提供测试集的标签。因此,你需要通过将 Kaggle 的训练集分成 70%的训练集和 30%的测试集来构建自己的测试集。
注意确保训练集中没有电影出现在测试集中的重要性.^([1]) 例如,如果同一电影的评论同时包含在训练集和测试集中,那么你的模型可能会学习到哪些电影标题是好是坏,而不是专注于构成积极和消极的语言。但在生产中,你将应用这个机器学习模型到新的电影上,这些电影标题是你从未见过的。从训练集到测试集的电影泄露可能会导致你相信你的模型在预测新电影评论的情感时比实际情况更好。因此,我们建议始终使用时间截止点来构建保留测试集,以便测试集包含比训练实例更新的实例。
¹
在我们的训练集中,我们没有指示每条评论描述的是哪部电影。因此,我们假设训练集是按日期预先排序提供的,并且我们将集合分割,使得同一电影的多个评论在训练集或测试集中聚集在一起。
8.1.2. 检查数据集
这个数据集中的单个评论在长度上有所不同,从一句话到几页的文本。由于评论是从几十位电影评论家那里收集的,因此评论之间的词汇量可能会有很大差异。关键是构建一个机器学习模型,它可以检测和利用正面和负面评论之间的差异,以便它可以准确地预测新评论的情感。
机器学习过程的第一步是查看数据,看看有什么,并开始思考机器学习过程的其他步骤,如模型类型和特征化。为了开始数据审查过程,请查看图 8.1 中的 10 个最短的评论。查看第一行(id = 10962_3)。这个特定的评论展示了这个问题有多么微妙:尽管评论明确表示“电影很糟糕”,但它也说有“好的效果”。尽管使用了“好”这个词,但任何人都清楚地同意这是一篇负面电影评论。现在的挑战是教会机器学习模型,即使使用了像“好”这样的积极词汇,短语“电影很糟糕”仍然占上风!
图 8.1. 训练集中的 10 个示例评论,从最短的评论中选择。对于每个评论,你只提供了 ID、二元情感和评论文本。

同样,这 10 个样本评论包括几个负面陈述的例子。像“永远不会感到疲倦”和“没有浪费的时刻”这样的短语明显表明了电影的积极品质,即使构成这些短语的单词在本质上都是消极的。这表明,为了在预测情感方面做得好,你必须结合多个(相邻)单词的信息。
翻阅一些其他(较长的)评论,很明显,这些评论通常由冗长、描述性、华丽的语言组成。语言通常是讽刺的、讽刺的、机智的。这使得它成为一个很好的数据集,可以展示机器学习从真实数据中学习细微模式并在不稳定的情况下做出准确预测的能力。
8.1.3. 那么用例有什么用?
经常情况下,(非现实世界)机器学习的实践者在没有深思熟虑他们的机器学习模型的实际用途的情况下就一头扎进了一个问题。这是一个错误,因为用例的选择可以帮助确定你如何构建问题和解决方案,包括以下方面:
-
如何编码目标变量(例如,二元、多类或实值)
-
优化哪个评估标准
-
应考虑哪些学习算法
-
你应该使用和不应该使用哪些数据输入
因此,在你开始机器学习建模之前,你首先需要确定你想要用这个数据集解决哪个现实世界的用例。
对于三个可能的用例中的每一个,你将考虑以下方面:
-
为什么用例会有价值?
-
你需要什么样的训练数据?
-
适当的机器学习建模策略是什么?
-
你应该使用什么评估指标来预测?
-
你拥有的数据是否足够解决这个用例?
根据对这些问题的回答,你将选择一个单一用例,你将在本章的剩余部分解决它。
用例 1:对电影进行排名
对于电影评论数据集的第一个也是最明显的用例是,根据所有评论的文本自动对所有新电影进行排名:
-
为什么这个用例会有价值? 这可能是一个决定这个周末要看哪部电影的有力方式。对个别评论进行评分是一回事,但显然更有价值的用例是对每部电影的评论整体积极性进行评分。像 Rotten Tomatoes 这样的网站因其能够可靠地评估每部电影而获得大量流量。
-
你需要什么样的训练数据? 基本需求包括评论文本、每个评论的情感指示以及关于每条评论所指电影的了解。有了这三个组成部分,构建一个电影排名系统是可行的。
-
合适的机器学习建模策略会是什么? 有几个选择:(a) 你可以将每部电影视为一个机器学习实例,汇总每部电影的个别评论,并将评论情感汇总为平均分数或多类模型。(b) 你可以继续将每条评论视为一个机器学习实例,对每条新评论的积极性进行评分,然后为每部新电影分配其平均积极性分数。我们更喜欢选项 (b),因为将单一电影的全部评论汇总在一起可能会对机器学习产生一些令人困惑的模式——尤其是如果个别评论高度两极分化!对个别结果进行评分,然后将其平均到“综合评分”中是一个更直接的方法。
-
你应该使用什么评估指标来预测? 假设你为每条评论都有一个二元结果变量,并且你的机器学习算法为每条评论分配一个分数,表示其可能是正面评论的可能性,并将其汇总为每部电影的单一分数。你关心的是你的分数与该电影真实平均评分的匹配程度(例如,正面评论的百分比),这可能导致你使用如 R² 这样的指标。但你可以想象使用一个更侧重于排名列表顶部的评估指标。在现实中,你可能对电影排名感兴趣,以便从列表顶部挑选一部电影在本周六观看。因此,你会选择一个侧重于你正确获取排名列表顶部能力的指标。在这种情况下,你会选择一个如小错误正率下的真正正率(例如,5% 或 10%)这样的指标。
-
你拥有的数据是否足够解决这个用例? 不幸的是,不是。你拥有所有你需要的东西,除了知道每条评论描述的是哪部电影!
用例 2:对每条评论进行 1 到 10 的评分
第二个可能用例是根据每部电影的用户评论集自动对每个评论进行 1 到 10 级的评分(IMDb 评分):
-
为什么这个用例会有价值? 任何新的评论都可以自动分配一个评分,而无需任何人工阅读或评分。这将减少许多需要用于维护 IMDb 网站 和电影评分的体力劳动;或者,如果用户在他们的评分中提供了分数,它可以根据用户评论的文本提供更客观的评分。
-
您需要什么样的训练数据? 只需每个评论的文本和每个评论的分数,从 1 到 10。
-
合适的机器学习建模策略是什么? 同样,有两种选择:(a) 将结果变量视为实数值并拟合回归模型。(b) 将结果变量视为分类变量并拟合多类分类模型。在这种情况下,我们更倾向于选择 (a),因为与分类不同,它考虑了数值尺度上的分数。
-
您应该使用什么评估指标来评估您的预测? 如果您选择运行回归模型,典型的回归评估指标,如 R² 或均方误差,是自然的选择。
-
您拥有的数据是否足够解决这个用例? 同样,也不够。您只有每个评论的布尔版本(正面与负面),而没有精细的数值分数。
用例 3:区分正面评论和负面评论
需要考虑的最后一个用例是将所有正面评论与其他评论分开:
-
为什么这个用例会有价值? 这个用例将代表用例 2 的一个更细粒度的版本,其中每个新的评论可以自动分类为正面或负面(而不是从 1 到 10 进行评分)。这种分类对 IMDb 来说可以用来检测正面评论,然后它可以将其推广到首页或(更好的是)出售给电影制片商,用于电影海报上的引用。
-
您需要什么样的训练数据? 只需评论文本和正负二值指示器。
-
合适的机器学习建模策略是什么? 您将拟合一个二元分类模型。从那里,您可以为每个新的评论分配一个预测分数,表示它是正面评论的可能性。
-
您应该使用什么评估指标来评估您的预测? 这取决于您如何使用您的预测。如果用例是自动提取每周最积极的 10 条评论(例如,用于 IMDb 首页),那么一个好的评估指标将是极低的假阳性率下的真正阳性率(例如,1%)。但如果目标是尝试找到 所有 正面评论而忽略负面评论(例如,用于对每条评论进行完整的自动情感标记),那么准确率或曲线下面积(AUC)这样的指标将是合适的。
-
你拥有的数据是否足够解决这个用例? 最后,是的!你有一个包含电影评论文本和二元情感变量的训练集。在本章的剩余部分,你将为这个用例构建一个机器学习解决方案。
回顾一下,你首先了解了数据集的基本细节:来自 IMDb 的手写电影评分。然后,你深入探索了一些数据中的模式和趋势。最后,你考虑了可能的机器学习用例。对于每个用例,你探讨了机器学习解决方案对问题的价值、构建机器学习解决方案的基本数据需求以及如何构建解决方案。
接下来,你将构建一个机器学习解决方案来区分正面和负面的电影评论。
8.2. 提取基本 NLP 特征和构建初始模型
由于电影评论数据集仅包含评论文本,你需要使用文本和自然语言特征来构建一个对你的情感模型有意义的数据集。在上一章中,我们介绍了从文本中提取特征的多种方法,我们使用本章来讨论与机器学习和自由文本工作相关的各种实际方面。在这一节中,你将经历的步骤如下:
-
使用词袋方法从电影评论中提取特征
-
使用朴素贝叶斯机器学习算法构建初始模型
-
使用 tf-idf 算法改进你的词袋特征
-
优化模型参数
8.2.1. 词袋特征
如您从上一章关于自然语言处理特征的讨论中可能记得,我们最初使用一种简单的技术来对自然语言数据进行特征化:词袋。这种方法分析整个文本语料库,构建一个包含所有单词的词典,并将数据集中的每个实例转换为一个数字列表,统计每个单词在文档中出现的次数。为了刷新您的记忆,让我们回顾一下图 8.2 中的词袋。
图 8.2. 词袋向量化算法。从一个单词词典中,你可以将任何新的文档(例如图中的文本 1、文本 2)转换为一个数字列表,该列表统计文档中每个单词出现的次数。

在列表 8.1 中,你加载数据集,创建 70%–30%的训练-测试分割,并使用简单的词频方法提取特征。在这个过程中,一个重要的认识是,你不能用测试集中的单词污染词袋词典。这就是为什么你在构建向量器词典之前将数据集分割成训练集和测试集——为了对模型在之前未见过的数据上的准确性进行现实估计。
列表 8.1. 从电影评论数据集中构建词频特征

查看在图 8.3 中生成的特征子集。
图 8.3. 用于构建模型的词频特征的小型 7 × 10 子集视图。完整的数据集是一个大小为 17,500 × 65,005 的稀疏矩阵(训练集中有 17,500 个文档,65,005 个唯一的单词)。当大多数值都是 0 时,稀疏矩阵是有用的,这在大多数基于词袋的特征中都是这种情况;在完整的单词字典中,单个单词不太可能出现在特定的文档中。

从图 8.3 中可以看出,数据集主要由零组成,只有少数例外。我们称这样的数据集为“稀疏”,这是 NLP 数据集的常见属性。当你想使用数据集作为机器学习模型中的特征时,这会产生影响,我们将在构建实际模型来预测评论情感之前讨论这个问题。
8.2.2. 使用朴素贝叶斯算法构建模型
现在你已经有一个合适的特征化数据集,你可以像往常一样使用这些特征来构建模型。对于像这样高度稀疏的数据集,一些机器学习算法比其他算法工作得更好。具体来说,一些算法内置了对稀疏数据的支持,这些算法通常在内存使用上,甚至在 CPU 使用和时间上都要高效得多。如果你检查列表 8.1 中生成的特征集,你会发现数据集中只有 0.2%的单元格具有非零元素。使用数据集的密集表示将显著增加内存中数据的大小。
朴素贝叶斯分类器的基本原理
基于贝叶斯公式的朴素贝叶斯(NB)分类器算法是一种简单的机器学习算法,它最初是为文本分类而创建的,在机器学习的这个领域中,它仍然可以与更高级的通用算法竞争。这个名字来源于贝叶斯公式应用于数据时,对独立性的假设非常“朴素”。
这种假设通常使得算法对于一般的(密集)问题不太有用,因为特征很少是相互独立的。对于稀疏文本特征,这个假设仍然不成立,但在实践中,这个假设足够准确,使得算法可以出奇地好地工作。朴素贝叶斯分类器是少数几个足够简单,可以在几行中推导出来的机器学习算法之一,我们将在侧边栏中解释一些亮点。
在本章中,我们的目标是通过对实例的特征 x 进行分类,找到评论情感为“差”(k = 0)或“好”(k = 1)的概率 p(C[k]|x)。在概率论中使用贝叶斯公式,这可以写成如下形式:
p(C[k]|x) ~ p(C[k])p(x|C[k])
p(x|C[k])被称为如果实例属于类别 C[k] 的特征的联合概率。由于独立性假设(“朴素”部分),没有交叉特征概率,这变成了每个特征给定类别的概率的乘积:
p(C[k]|x) ~ p(C[k])p(x[1]|C[k])p(x[2]|C[k])p(x[3]|C[k])p(x[4]|C[k])...

因为 p(C[k]) 是边缘类别分布——好和坏情感评论的整体分布,你可以很容易地从数据中找到,所以你只需要弄清楚 p(x[i]|C[k]) 是什么。你可以将这个表达式读作“特定类别的特定特征的概率”。例如,你预计在正面情感评论中包含单词 great 的概率要高于在负面情感评论中。
你可以想象通过计算每个类别中所有文档中的特征(词)出现次数来从数据中学习这一点。生成这种计数的概率分布称为 多项式 分布,p(x[i]|C[k]) 变为

你将这个用于前面的方程,并移动到对数空间以方便计算:

在这里 b 是 log[p(C[k])](从数据中得知),x 代表你想要预测的实例的特征,而 w[k] 是 log(p[k[i]])—一个词在好文档或坏文档中出现的频率,你将在模型构建时学习到。请注意,我们在整个计算中省略了各种常数,当从头开始编写此算法时,需要考虑多个实现细节,但这里概述的基本内容仍然是正确的。
对于具有稀疏自然语言处理(NLP)特征的分类,有一个算法效果很好,那就是朴素贝叶斯算法,特别是多项式(见侧边栏)。在下面的列表中,你将在 列表 8.1 中的特征上构建模型。
列表 8.2. 使用多项式朴素贝叶斯构建第一个评论情感模型
from sklearn.naive_bayes import MultinomialNB
model1 = MultinomialNB()
model1.fit(features, d_train.sentiment)
pred1 = model1.predict_proba(test_features)
为了评估模型的性能,你在 列表 8.3 中定义一个函数,并在初始模型预测上调用它。本章中你将报告的准确度指标是通用分类准确率(正确分类的文档比例)、接收者操作特征(ROC)曲线以及相应的曲线下面积(AUC)数值。这些内容都在 第四章 中介绍过,并在我们的大量示例中使用过。
列表 8.3. 评估初始模型
from sklearn.metrics import accuracy_score, roc_auc_score, roc_curve
def performance(y_true, pred, color="g", ann=True):
acc = accuracy_score(y_true, pred[:,1] > 0.5)
auc = roc_auc_score(y_true, pred[:,1])
fpr, tpr, thr = roc_curve(y_true, pred[:,1])
plot(fpr, tpr, color, linewidth="3")
xlabel("False positive rate")
ylabel("True positive rate")
if ann:
annotate("Acc: %0.2f" % acc, (0.2,0.7), size=14)
annotate("AUC: %0.2f" % auc, (0.2,0.6), size=14)
performance(d_test.sentiment, pred1)
运行此代码的结果显示在 图 8.4 中。
图 8.4. 简单词袋模型的分类性能 ROC 曲线。图中的分类准确率——正确分类评论的比例——以及 AUC(ROC 曲线下的面积)指标被打印出来。准确率表明,你预计使用这个模型可以正确分类 88%的评论,但通过使用 ROC 曲线,你可以用假正率(FPR)交换真正正率(TPR),反之亦然。如果有很多评论需要根据这个分类进行人工检查,你可能希望将 FPR 设定在一个较低的水平,这反过来会降低真正正检测率。

查看图 8.4,你可以看到你的基础模型的表现并不差。你正确分类了 88%的评论,但你可以根据你对更多噪声或更好检测率的偏好,调整假正与真正正的比例。
让我们通过将一些文本通过向量化和模型进行情感预测来尝试几个新的示例评论:
>>> review = "I love this movie"
>>> print model1.predict(vectorizer.transform([review]))[0]
1
正面情绪表示为 1,所以这听起来很正确。让我们再试一个:
>>> review = "This movie is bad"
>>> print model1.predict(vectorizer.transform([review]))[0]
0
负面情绪表示为 0,所以这确实是对的。好的,让我们尝试欺骗模型:
>>> review = "I was going to say something awesome, but I simply can't because the movie is so bad."
>>> print model1.predict(vectorizer.transform([review]))[0]
0
没有成功,预测仍然是正确的。也许如果你在负面评论中引入更多的正面词汇?
>>> review = "I was going to say something awesome or great or good, but I simply can't because the movie is so bad."
>>> print model1.predict(vectorizer.transform([review]))[0]
0
没错,这是一个聪明的模型。单词bad对分类有很强的影响,所以你可能可以通过在正面评论中使用这个词来欺骗模型:
>>> review = "It might have bad actors, but everything else is good."
>>> print model1.predict(vectorizer.transform([review]))[0]
0
最后,你成功地在某种程度上欺骗了模型。这个小练习很有趣,但也展示了模型在理解电影评论领域任意自然语言方面的力量。在下一节中,你将通过比我们简单的词频特征更进一步,并找到特征和建模算法参数的更好值来尝试改进初始模型。
8.2.3. 使用 tf-idf 算法对词袋特征进行归一化
在上一章中,我们介绍了 tf-idf 作为简单词频特征的升级。本质上,tf-idf 根据每个单词在文档中出现的频率对词频进行归一化。主要思想是,常见单词获得较小的权重因子,而相对罕见的单词获得较大的权重因子,这使你能够深入挖掘(通常是高度信息丰富的)在数据集中出现频率较低的单词。
在本节中,你将使用 tf-idf 作为你的特征来查看你是否可以获得额外的准确性。使用 scikit-learn 进行更改很容易,因为你只需要将你的CountVectorizer替换为TfidfVectorizer。代码将在下一列表中展示。
列表 8.4. 在模型中使用 tf-idf 特征

tf-idf 模型的性能在图 8.5 中显示。你可以看到 tf-idf 特征如何略微提高了模型准确度。具体来说,ROC 曲线显示它应该更好地避免误报。想象一下,你有很多评论进来,但想标记出需要人类检查的不良评论。更低的误报率将向审阅者展示更少的实际上是正面的评论,这样他们可以更快地处理队列。
图 8.5. 在之前的词袋模型之上 tf-idf 模型的 ROC 曲线。你可以看到分类准确性和 AUC(ROC 曲线下的面积)都有轻微的提高。tf-idf 模型曲线特别显示了在低 FPR 范围内的改进;对于相同数量的正确分类评论,模型将产生更少的误报。如果人类在分类审查循环中,你将需要筛选的噪声会更少。

我们的两个 tf-idf NLP 特征提取算法和朴素贝叶斯建模算法都有可以调整以调整算法以适应数据集特定细节的旋钮。我们称这些旋钮为超参数。这源于模型变量(特征)也可以被视为参数,而算法参数则工作在更高的层次。在你接受模型性能之前,尝试这些参数的不同值是非常重要的,这也是下一节的主题。
8.2.4. 优化模型参数
找到模型最佳参数的最简单方法就是尝试构建具有不同参数的一组模型,并查看感兴趣的指标。问题是你不能假设参数之间是独立的——改变一个参数可能会影响另一个参数的最佳值。这可以通过为任何参数组合构建模型的方式来解决。但如果有很多参数,这很快就会变得难以处理,尤其是如果构建模型本身就需要花费一些时间。我们在第四章中讨论了一些解决方案,但你可能会惊讶地发现,ML 从业者仍然经常依赖于这种方法。你需要培养对哪些参数可能更独立以及哪些参数对哪种类型的数据集影响最大的直觉。对于这个练习,你有三个参数需要优化:两个 tf-idf 参数(max_features,min_df)和一个朴素贝叶斯参数(nb_alpha)。
你首先需要的是一个你可以反复调用来构建模型并返回参数和感兴趣指标(在这种情况下,是 AUC)的函数。下面的列表定义了这个函数。
列表 8.5. 用于参数优化的模型构建方法
def build_model(max_features=None, min_df=1, nb_alpha=1.0):
vectorizer = TfidfVectorizer(max_features=max_features, min_df=min_df)
features = vectorizer.fit_transform(d_train.review)
model = MultinomialNB(alpha=nb_alpha)
model.fit(features, d_train.sentiment)
pred = model.predict_proba(vectorizer.transform(d_test.review))
return {
"max_features": max_features,
"min_df": min_df,
"nb_alpha": nb_alpha,
"auc": roc_auc_score(d_test.sentiment, pred[:,1])
}
使用在列表 8.5 中定义的可重复模型构建函数,你可以通过定义参数的可能值(随机选择或凭直觉选择)并运行循环来运行你的优化管道。这将在下一个列表中完成。
列表 8.6. 参数优化循环

你要优化的参数如下:
-
max_features—tf-idf 算法要创建的最大词列数。从数据中可以看出,所有词加起来大约有 65,000 列,所以你尝试在类似大小的范围内尝试一些数值。None指定使用所有词。 -
min_df—一个词必须出现在数据集中多少次才能被包含在特征中。这是一个潜在的参数依赖性的例子,因为通过改变min_df,字典中的词数(以及max_features)可能会改变。 -
nb_alpha—朴素贝叶斯分类器的 alpha(平滑)参数。这是你可以调整的特定 ML 算法的唯一参数。这里要选择的值需要更多研究参数的含义以及其他人如何在其他情况下使用它。
关于列表 8.6 中的代码的最后一点是使用来自itertools模块的product函数——一组 Python 函数,使处理数据更加容易。这个函数是一种巧妙的方法来生成一组列表的所有组合(笛卡尔积)。列表 8.6 中代码运行的结果显示在图 8.6 中。
图 8.6. 参数优化循环的一些结果子集。第 27 次迭代的参数组合总体上产生了最佳模型。

图 8.6 显示了某些优化运行的结果。你只有三个参数,36 种可能的值组合,所以这没有超过 10 分钟,因为朴素贝叶斯训练时间相对较低,但你很容易想象想要尝试更多参数的更多值,优化将需要很长时间。找到最佳参数的另一个技巧是,从广泛的值开始,然后在随后的优化运行中更深入地探索最佳值范围。从表中可以看出,不同的参数似乎提高了模型的 AUC。第 27 次迭代使用这些值取得了最佳结果:
-
max_features—None(所有词,默认) -
min_df—1(默认) -
nb_alpha—0.01
因此,有趣的是,你通过找到朴素贝叶斯算法的 alpha 参数的更好值,成功地显著提高了模型性能。让我们看看当改变每个参数(固定其他参数在其最优值)时 AUC 的变化情况(图 8.7)。
图 8.7. 通过改变特征和 ML 算法的三个参数带来的 AUC 改进。您可以看到:(a)更高的max_features给出了更好的 AUC,(b)更低的min_df给出了更好的 AUC,(c)更低的 alpha 给出了更好的 AUC。这并不意味着每个参数的最佳值必然会产生最佳的组合。我们优化运行中最佳组合参数是max_features=None(所有单词,默认值),min_df=1(最小值,默认值),alpha=0.01(改进的主要原因)。最佳 AUC 是 0.974。所有显示的图表都可以使用附带的 Python 笔记本中的代码重新生成。

这些图表只是 AUC 演变的单一视角,因为您需要一个四维图表来将 AUC 作为所有参数的函数来绘制。但仍然很有趣地看到模型对每个值的变化的响应。例如,特征数量越多,效果越好(赢得了最大可能值)。min_df的数量越小,效果越好(赢得了最小可能值)。然后,nb_alpha越小,效果越好。因为这一项没有理论上的下限,这应该会促使您在另一次运行中尝试更低的值。我们将这留作您的练习(但根据经验,我们并没有找到更好的值)。
优化模型的 ROC 曲线与先前模型一起绘制在图 8.8 中。您可以看到模型性能在两个指标和 ROC 曲线的所有点上都有显著提高。这是一个很好的例子,说明调整模型超参数以获得额外的预测能力是有益的。最后要注意的一点是:当然,您可以想象新的模型参数选择可能会反过来影响哪些特征和建模算法(例如,词频与 tf-idf)将表现最好,每种算法都可能有一组新的参数需要优化。为了完全严谨,您需要优化所有算法及其参数的选择,但对于大多数现实世界问题来说这是不可行的,这里的权衡是在里程碑中完成优化。例如,首先确定要使用的 NLP 算法,然后是 ML 模型,然后优化这些参数。您的项目可能需要不同的里程碑——再次强调,您将在构建连续的 ML 模型的过程中对这些事情产生直觉。
图 8.8. 优化模型与先前模型的 ROC 曲线。在我们的测试集评估中,这个模型似乎在所有曲线上都表现得更好,预期准确率显著提高。

图 8.8 中的 ROC 曲线总结了我们的初步建模实验。仅从基本算法和少量代码中,你就成功地构建了一个在自然语言数据上具有相当高准确性的模型。在下一节中,你将在特征工程和建模工作中更进一步,并了解将此类模型部署到实际生产就绪系统中的各个方面。
8.3. 高级算法和模型部署考虑因素
在上一节中,我们关注的是使用相对简单的特征和机器学习算法构建模型。该节中任何模型的准确性可能已经足够满足我们的需求。你可以尝试下一个优化模型的想法,但时间和模型准确度增量改进带来的潜在价值之间总是存在权衡。我们鼓励你掌握每个百分比改进的价值,例如,以节省人工审查时间的形式,以及你愿意前期投入多少。正如你所见,我们的第一个模型在许多情况下确实能够理解审查情感,并且可能一开始就是一个足够好的模型。通常,将略微低精度的模型投入生产并获得系统的实时反馈更有价值。
遵循上述建议后,让我们反其道而行之,尝试进一步优化这个模型。接下来,你将研究从谷歌最初开发的新自然语言建模技术中生成特征:word2vec。在提取 word2vec 特征后,你将切换到随机森林算法以更好地支持新特征。
8.3.1. Word2vec 特征
谷歌通过 word2vec 项目引入了一种相对较新的自然语言处理方法。word2vec 模型本身就是一个使用深度神经网络构建的机器学习模型,深度神经网络是机器学习的一个分支,最近在自然语言、语音和图像等与人类相关的领域产生了最先进的结果。
要在训练集上构建 word2vec 模型,你将使用 Python 的 Gensim NLP 库,该库内置了一个很好的 word2vec 实现。你之前在第七章中使用 Gensim 处理 LDA,另一个类似于 word2vec 的主题模型。
在 Gensim 中,您需要做一些额外的工作来准备您的文档以进行建模,因为 Gensim 算法在句子(已经分割成单词的列表)上工作,而不是任意文档。这可能会在前期增加工作量,但它也使您更好地了解模型中包含的内容。在列表 8.7 中,您将构建一个简单的标记化函数,该函数删除停用词和标点符号,并将所有单词转换为小写。请注意,这都是在 scikit-learn 词向量器中自动完成的;我们可以使用相同的功能或类似的功能从 NLTK Python NLP 工具包中,但我们选择在这里自己编写它,以教育目的。
列表 8.7. 文档标记化


从这个函数中,您可以标记化任何文档列表,并且现在您可以继续构建您的第一个 word2vec 模型。有关算法参数的更多信息,请参阅 Gensim 文档.^([2])
²
列表 8.8. Word2vec 模型

您可以看到单个单词是如何表示为一个向量(在这个例子中是 300 个数字)。为了使用 word2vec 模型为您的人工智能算法生成特征,您需要将您的评论转换为特征向量。您知道如何将单个单词表示为向量,因此一个简单的方法是将评论文档(单词列表)表示为文档中所有单词的平均向量。在下一个列表中,您将构建一个函数来完成这项工作。
列表 8.9. Word2vec 特征化

您现在可以构建一个基于您新生成的 word2vec 特征的模型。如您从我们的机器学习算法讨论中回忆起第 8.2.2 节,朴素贝叶斯分类器在稀疏数据上表现良好,但在密集数据上表现不佳。word2vec 特征确实将您的文档从 65,000 个稀疏词频特征转换为仅几百个密集特征。深度学习模型已经学习了模型的高级主题(列表 8.8),每个文档都可以表示为主题的组合(列表 8.9)。
8.3.2. 随机森林模型
在上一节中引入的多项式朴素贝叶斯算法与新的 word2vec 特征不兼容,因为它们不能被认为是多项式分布生成的。您可以使用其他分布继续使用朴素贝叶斯算法,但您将依赖我们的一位老朋友:随机森林算法。在下面的列表中,您将在 word2vec 特征上构建一个 100 棵树的随机森林模型,并像往常一样在测试集上分析性能。
列表 8.10. 在 word2vec 特征上构建随机森林模型
features_w2v = featurize_w2v(model, sentences)
model4 = RandomForestClassifier(n_estimators=100, n_jobs=-1)
model4.fit(features_w2v, d_train.sentiment)
test_sentences = tokenize(d_test.review)
test_features_w2v = featurize_w2v(model, test_sentences)
pred4 = model4.predict_proba(test_features_w2v)
performance(d_test.sentiment, pred4, color="c")
在图 8.9 中比较了 word2vec 随机森林模型与您之前模型的性能。您可以看到,您的新模型确实在您选择的评估指标和 ROC 曲线的所有点上提高了模型精度。
图 8.9。word2vec 模型及其之前模型的 ROC 曲线。您可以看到 ROC 曲线的所有值都有所改进,这也反映在增加的准确性和 AUC 数值上。

在图 8.9 中展示了您的最终模型后,您对性能感到满意,现在将停止优化工作。您还可以尝试更多的事情来进一步提高准确率。很可能是,即使是人类也无法正确分类所有评论的情感;可能存在一些错误的标签,或者有些评论的情感不容易理解。
但这个模型可能比您迄今为止所取得的成果要好得多。我们将给您,亲爱的读者,一个初步的清单,其中列出了我们打算尝试的一些事情,按照优先级的大致顺序:
-
使用未标记的数据构建更好的主题模型。Kaggle 竞赛网站的数据部分包含一组未标记的评论,您可以使用这些评论进行训练。因为您正在构建一个监督模型,它们最初看起来似乎没有用。但是,因为您正在构建一个需要学习 IMDb 电影评论世界细微差别(尤其是不同单词和概念之间的联系)的 word2vec 模型,所以使用这些数据来改进您将要进入训练集特征(带有标签的那个)的 word2vec 模型将是有益的。
-
优化参数。您在找到模型超参数的更好值之后,在本章的初始模型中看到了模型性能的显著提升。我们随后引入了一个新的 NLP 模型(word2vec)和 ML 算法(随机森林),因此有许多新的参数需要优化。
-
检测短语。Gensim 库包括在文本中检测短语的支持,例如“纽约市”,这在我们的“dump”仅单词标记化函数中可能会被遗漏。英语语言往往包含多词概念,所以这可能是您句子生成函数中一个有趣的东西。
-
处理多种语言。 如果你对所有评论是否都使用单一语言(在这种情况下,英语)不确定,你将不得不在建模流程的各个地方处理多种语言。首先,你需要知道评论使用的是哪种语言,或者你需要检测语言(有几种质量各异的库可用)。然后,你需要在分词过程中使用这些信息,以使用不同的停用词和,可能的话,不同的标点符号。如果你真的很不幸,甚至可能不得不处理完全不同的句子结构,例如中文文本,在这种情况下,当存在空白时不能简单地分割单词。
现在,假设你对当前的模型感到满意。如果这是一个现实世界的用例,你将希望将模型投入生产。然后,根据具体用例,你应该考虑以下一些方面:
-
你有多少训练数据,更多的训练数据是否会使模型变得更好? 这可能会影响机器学习算法的选择,因为你需要选择一个能够随着更多训练数据而良好扩展的模型。例如,朴素贝叶斯分类器支持部分训练,也称为在线学习,而随机森林算法可能难以扩展到更大的数据集。
-
预测量有多大,是否需要实时交付? 我们将在下一章中详细讨论如何通过规模和速度来扩展预测,但关键是要认识到这可能会对算法的选择和部署的基础设施产生影响。
8.4. 摘要
在本章中,你学习了如何在真实机器学习用例中从头到尾进行操作,以及自然语言处理和优化模型参数的基础知识。本章的关键要点包括以下内容:
-
专注于正确的问题是至关重要的。你应该始终针对每个可能的用例问自己,“解决这个问题的价值是什么?”
-
对于每个用例,你需要检查数据,并系统地确定数据是否足以解决手头的问题。
-
在可能的情况下,始终从简单的现成算法开始,以构建初始模型。在我们的例子中,我们以几乎 90%的准确率预测了评论的情感。
-
通过测试和评估替代模型和模型参数的组合,可以提高准确性。
-
在不同的模型参数和评估标准之间,常常需要做出权衡。我们研究了电影评论中错误接受率和错误拒绝率之间的权衡是如何通过模型的 ROC 曲线来表示的。
-
如 word2vec 之类的最先进的自然语言和机器学习建模技术是高级特征工程如何帮助你改进模型的例子。
-
你选择的算法可能取决于除了模型准确性之外的其他因素,例如训练时间和需要整合新数据或进行近实时预测的需求。
-
在现实世界中,模型总是可以改进的。
8.5. 本章术语
| Word | 定义 |
|---|---|
| word2vec | 一种自然语言处理建模框架,最初由谷歌发布,并被用于许多涉及自然语言的先进机器学习系统中 |
| hyperparameter optimization | 选择控制机器学习算法执行以最大化其性能的参数的各种技术 |
第九章. 扩展机器学习工作流程
本章涵盖
-
确定何时扩展工作流程以提高模型准确性和预测吞吐量
-
避免在复杂的扩展策略和重型基础设施上进行不必要的投资
-
将线性机器学习算法扩展到大量训练数据的方法
-
扩展非线性机器学习算法的方法——通常是一个更大的挑战
-
降低预测延迟并提高预测吞吐量
在现实世界的机器学习应用中,可扩展性通常是一个主要关注点。许多基于机器学习的系统需要快速处理新数据并生成预测,因为预测在几毫秒后就会变得无用(例如,考虑实时应用,如股市或点击流数据)。另一方面,其他机器学习应用需要在模型训练期间进行扩展,以便在千兆或太字节的数据上学习(考虑从互联网规模的图像语料库中学习模型)。
在前面的章节中,你主要处理的是足够小,可以单机拟合、处理和建模的数据。对于许多现实世界的问题,这可能足以解决当前的问题,但许多应用需要扩展到多台机器,有时甚至需要扩展到云中的数百台机器。本章是关于决定扩展策略并了解涉及的技术。
在本章的第一部分,我们介绍了面对大数据集或高量预测需求时需要考虑的各种维度。我们展示了你可以避免在完全可扩展的方法上投入大量时间和资源的方法,以及如果无法避免这种情况需要考虑的一些技术。下一节将更深入地探讨扩展机器学习工作流程的过程,以便在大型数据集上训练模型。最后,我们将关注扩展预测工作流程以处理大量数据或降低延迟。
在下一章中,你将能够使用本章中学到的所有知识来解决一个现实世界的海量数据示例,所以请耐心等待,当你完成本章的基础知识后。
9.1. 扩展前的准备
对于任何给定问题所需的可扩展性类型最终取决于用例和存在的计算约束。本节首先描述在现代机器学习应用中通常所需的可扩展性类型。你将逐步了解需要考虑的各种维度,并确定哪些可能是你 ML 代码的瓶颈。在你确定了所需的可扩展性类型之后,你将了解确保你的 ML 应用能够处理现实世界的数据速率和体积的标准技术。
我们不直接深入到具体的方法来扩展 ML 应用,而是从高层次概述开始。以我们的 ML 工作流程为指导,让我们从 ML 可扩展性的系统视角开始。
9.1.1. 识别重要维度
让我们首先将我们的机器学习工作流程分解为两个主要流程:模型训练和模型预测。对于这两个系统,资源约束如何影响工作流程,以及它们如何抑制或破坏系统?考虑表 9.1。
表 9.1. 由于缺乏可扩展性可能发生的模型构建问题,以及它们的最终后果
| 可扩展性问题 | 后果 |
|---|---|
| 训练数据集太大,无法拟合模型。 | 没有模型被拟合,因此无法进行预测。 |
| 训练数据集太大,模型拟合速度慢。 | 模型优化不可行(或实际不可行),因此使用次优模型,牺牲了准确性。 |
在模型构建过程中,你将面临的可扩展性问题源于大规模的训练集。在一种极端情况下,如果你的训练数据集如此之大以至于你甚至无法拟合一个模型(例如,数据无法适应内存),那么这是一个你必须找到解决方案的问题。你可以选择以下三种方法:(1)找到可以学习的小数据子集,(2)使用具有更多 RAM 的机器,或者(3)使用更内存高效的算法。
在稍后,我们将描述几种快速减少数据集大小的方法,而不会显著影响模型质量。接着,我们将讨论如何通过可扩展的数据系统来扩展计算周期以适应你的问题。在本章的后面部分,我们将介绍可扩展的学习算法,这些算法可以让你在不依赖捷径或额外硬件的情况下将 ML 扩展到你的数据。
对于稍微小一些的数据集,可能只能拟合相对简单的模型(如线性/逻辑回归),而不是更复杂的模型(如提升),因为后者有额外的计算复杂性和内存占用。在这种情况下,你可能通过不拟合更复杂的学习算法而牺牲了准确性,但至少你能够拟合一个模型。在这种情况下,之前提出的相同选项是可行的尝试方法。
在相关场景中,你的训练数据集的巨大规模可能导致模型拟合,进而导致模型优化变慢。与前面的场景一样,这可能导致你使用一个不太准确的模型,因为你被迫采用粗略的调整参数优化策略,或者完全放弃调整。但与前面情况不同,这种困境可以通过启动更多节点(横向扩展)并在不同机器上(使用不同的调整参数选择)拟合模型来解决。我们将在 9.1.3 节中更多地讨论横向扩展。
在预测工作流程中,你面临的扩展性问题源于非常快速到来的数据、CPU 密集型的预测或特征工程过程,或者非常大的预测数据批量。考虑表 9.2。
表 9.2. 由于缺乏可扩展性可能导致机器学习预测中出现的问题,以及它们的最终后果
| 扩展性问题 | 后果 |
|---|---|
| 数据速率(流式)对于机器学习系统来说太快了。 | 预测所需的数据积压不断增长,最终导致崩溃。 |
| 特征工程代码和/或预测过程太慢,无法生成及时的预测。 | 预测的潜在价值丢失,尤其是在实时用例中。 |
| 数据大小(批量)太大,无法用模型处理。 | 预测系统崩溃,无法进行预测。 |
幸运的是,这三个挑战都可以通过相同的策略来解决:增加更多的机器。与模型训练相比,预测的优势在于在绝大多数用例中,预测可以独立地对每个数据实例进行。为了生成预测,在任何时候你只需要在内存中保留单个实例的特征(以及你构建的机器学习模型)。将这种情况与模型训练进行对比:通常,整个训练集需要被加载到内存中。因此,与模型训练期间的扩展性问题不同,预测的扩展性问题不需要更大的机器;只需要更多的机器——当然,还需要一个高效的数据管理系统来控制它们(关于这一点稍后还会详细介绍)。
¹
注意,在少数机器学习用例中,预测不能独立地对单独的实例进行。例如,一个时间序列预测模型,如金融或气候模型,可能依赖于多个时间戳的预测来生成单个预测。
无论你需要更快地生成预测、处理更高容量的实例,还是处理缓慢的特征工程或预测过程,解决方案都是启动更多机器,并将不同子集的实例发送到每个节点进行处理。然后,假设拟合的模型分布在所有节点上,你可以在所有机器上并行生成预测,并将它们返回到中央数据库。
在第 9.3 节中,你将深入探讨预测系统。在那里,你将探索一些构建快速且可扩展的机器学习预测计算系统的方法。
9.1.2. 用子采样代替扩展?
在某些情况下,使用整个训练集和可用的 CPU 资源进行模型训练可能不可行。如果你面临这个挑战,且没有其他可行的选择,那么作为最后的手段,你可以在模型构建之前考虑对训练数据进行子采样。
虽然我们通常不鼓励对数据进行子采样(你可能会丢失重要的信号),但某些丢弃数据的方法比其他方法更好。在某些情况下,这些方法甚至可能改善你的模型,这取决于手头的机器学习算法。你可以通过两种方式丢弃数据:丢弃特征或丢弃实例。对于每种选项,我们将描述一种统计上严格的方法来减少你的训练数据量。
特征选择
通常,数据集的广泛性会形成计算瓶颈。例如,在基因组数据中,一个训练集可能包含数百万个基因(特征)的数据,但只有数百个患者(实例)。同样,对于文本分析,将数据特征化为 n-gram 可能会导致包含数百万个特征的训练集。在这些情况下,你可以通过首先在称为特征选择的过程中消除不重要的特征来使你的模型训练可扩展。图 9.1 展示了特征选择是如何工作的示意图。
图 9.1. 使用 Lasso 降低大型数据集的维度以训练机器学习模型

正如我们在第四章和第五章中讨论的那样,特征选择在某些情况下可以导致更好的模型。通过智能地去除特征,你可以让学习算法专注于重要的信号,而不会被那些无关的特征所分散。特征选择的实际损失或收益取决于所选的机器学习模型以及由于你丢弃数据而无意中丢失的信息量,因此你应该始终通过适当验证你的模型来测试你的更改。在本节中,我们主要讨论特征选择作为处理大型数据集的一种方式。
对于大规模的训练集,我们推荐的特征选择方法是Lasso。Lasso 是一种高效的线性学习算法,它自动搜索最具预测力的特征子集。计算整个算法的迹是高效的,使用户能够洞察所有特征在线性模型中预测力方面的整个排序。此外,根据线性模型预测,还提供了最佳特征子集。
如果你非常幸运(或不幸运)拥有如此大的数据集,以至于你甚至无法拟合 Lasso 模型,你可以考虑将 Lasso 拟合到训练集中实例的子集(并且可能跨算法运行的平均值)。这可以给你一个很好的感觉,了解哪些特征可以从模型中移除,而不会降低你的机器学习算法的统计性能。
Lasso 特征选择的明显缺点是它使用线性模型来衡量每个特征的重要性。通过 Lasso 选出的特征确实可能与目标变量有非线性关系,这可能无法被 Lasso 适当地捕捉。作为替代,存在非参数特征选择方法,如随机森林特征重要性,但这些方法通常无法扩展到大型数据集。
实例聚类
如果在特征选择后,你的训练数据仍然太大,无法拟合模型,你可以考虑子选择实例。作为最后的绝对方法,你可以使用统计聚类算法来识别并删除训练实例中的冗余。
对于这种数据缩减,我们建议使用聚集层次聚类算法。这种方法将以每个训练集实例作为其自己聚类的唯一成员开始。然后,将最近的两个聚类随后合并(使用预定义的距离度量来确定“接近度”)。这种邻近聚类的合并会一直持续到达到停止标准(例如,聚类数量)为止。我们建议尽可能早地停止这个过程,以免过于大幅度地减少数据的信息内容。最终的缩减训练集由每个结果聚类的单个实例组成。
9.1.3. 可扩展的数据管理系统
无论你打算采取何种策略来扩展你的机器学习工作流程,你首先需要能够处理数据。在过去十年中,我们对所谓的大数据技术给予了极大的关注。在这本书中,我们使用“大数据”一词来指代任何在合理时间内无法由单个机器处理的数据。在这里,我们介绍了一些最成功的的大数据项目以及它们如何在机器学习框架中使用。
现代大数据系统中的基本原则是,你需要通过增加更多机器来处理更多的数据。这被称为水平扩展性。相比之下,处理更大资源需求的其他方法是垂直扩展性,即通过增加磁盘、内存或 CPU 核心来升级你拥有的少量机器。图 9.2 比较了水平和垂直扩展性。
图 9.2. 大数据系统的水平与垂直可扩展性。在水平系统中,你向你的基础设施添加新的节点(机器)来处理更多的数据或计算,因为负载在节点之间相对均匀地分布。Apache Hadoop 就是这样一个系统的例子。在垂直扩展系统中,你向现有的机器添加更多资源以处理更高的负载。这种方法最初通常更有效,但你可以添加的资源量是有限的。与这种方法很好地工作的数据库示例是 PostgreSQL 这样的 SQL 服务器。

有时候,也许比你想象的更频繁,升级你的机器就足以扩展你的机器学习工作流程。正如前几节所述,在原始数据经过处理并准备好用于分类或回归问题之后,数据可能不足以证明真正大数据系统的复杂性。但在某些情况下,当处理来自流行网站、移动应用、游戏或大量物理传感器的数据时,使用水平可扩展的系统是必要的。从现在开始,我们将假设这一点。
水平可扩展的大数据系统有两个主要层:存储和计算。在存储层中,数据被存储并传递到计算层,在那里数据被处理。最受欢迎的大数据软件项目之一是 Apache Hadoop,它仍然在科学和工业中得到广泛应用,并基于 2000 年代初谷歌和其他 Web 规模公司在获得前所未有的可扩展性水平时的想法。
Hadoop 中的存储层被称为Hadoop 分布式文件系统(HDFS)。数据集被分区并分布在多台机器上,以便可以并行处理。此外,每个分区都被复制,因此数据在硬件或软件故障的情况下不太可能丢失。
Hadoop 的计算层使用一种简单的算法,称为MapReduce,在集群中的节点之间分配计算。在 MapReduce 框架中,map 步骤将数据从 HDFS 分布到工人节点上,这些节点以某种方式转换数据,通常保持数据行数不变。这与我们之前章节中的特征工程过程类似,你在输入数据的每一行中添加新的列。在 reduce 步骤中,映射后的数据被过滤并聚合成最终形式。许多数据处理算法可以转换为 MapReduce 作业。当算法转换为这个框架时,系统如 Hadoop 将负责在集群中的任何数量的机器之间分配工作。
在原则上,存储和计算层不需要集成。许多组织使用来自云服务提供商的存储系统,例如亚马逊网络服务 (AWS) 云基础设施中的 S3 服务,与 Hadoop MapReduce 框架结合用于计算。这有一个好处,即 AWS 管理你的大量数据,但你失去了 HDFS 和 MapReduce 之间紧密集成的主要优点:数据局部性。有了数据局部性,你的系统变得更加高效,因为计算任务是在数据存储附近的数据子集上执行的。
Hadoop 社区开发了一个名为 Mahout 的机器学习库,该库实现了多种流行的 ML 算法,这些算法可以在 Hadoop 框架中的 HDFS 和 MapReduce 上运行。如果你的数据存储在 Hadoop 中,那么 Mahout 可能值得你考虑用于你的机器学习需求。Mahout 正在从简单的 MapReduce 框架转向基于 Apache Spark 的更高级的分布式计算方法。Apache Spark 是一个基于 Hadoop 思想的更近和更受欢迎的框架,它通过在内存中处理数据来努力实现更好的性能。Spark 在框架中包含了名为 MLlib 的机器学习算法库。图 9.3 展示了 Apache Spark 生态系统的简单图示。
图 9.3. 基于 Spark 核心的 Apache Spark 生态系统,用于分布式计算。Spark SQL 允许你使用 Python pandas 或 R 数据框来处理表格。Spark Streaming 允许你在数据到达时实时处理数据,与 Hadoop 和经典 Spark 的批处理特性形成对比。MLlib 是一个机器学习库,它包含了一系列针对 Spark 引擎优化的 ML 算法,而 GraphX 是一个允许在大型图(如社交网络的社会图)上进行高效计算的库。

可扩展的 ML 算法通常由于自然原因而通常是线性的。Mahout 和 MLlib 主要包括线性的 ML 算法或非线性算法的近似。在下一节中,你将了解如何使用这两种类型的算法进行扩展。
9.2. 扩展 ML 模型管道
在本章的第一节中,你了解了在投入大量资金扩大你的工作流程以处理更大的数据集之前应该知道的事情。在本节中,我们假设你已经做出了扩大你的 ML 工作流程的决定,并选择了一个大数据处理系统来使用。图 9.4 更新了我们熟悉的 ML 工作流程图,以适应大数据的世界。
图 9.4. 我们熟悉的 ML 工作流程图中建模部分的扩展组件

在第 9.1.3 节中,我们介绍了一些能够用于管理和处理几乎任何大小数据的大数据系统。由于它们基于实例进行工作,因此我们在这本书中讨论过的特征工程过程可以通过任何这些系统中的简单 map 调用来完成。接下来,您将了解一些流行的线性和非线性机器学习算法如何在大数据面前进行扩展。
9.2.1. 扩展学习算法
在本章的开头,您看到在学习阶段,基本的可扩展性挑战是处理非常大的训练集在内存中的大小。为了规避这个问题,一个选择是寻找机器学习算法的实现,这些实现要么(a)比相同算法的竞争实现占用更小的内存足迹,要么(b)可以在每个节点只需要整个数据集子集的分布式系统中进行训练。
在野外,存在无数最常见机器学习学习算法的实现。从 scikit-learn 到 mlpack,这些实现不断扩展内存效率的边界(从而增加了可以在固定数量的 RAM 上训练的数据集大小)。然而,数据量仍在超过机器学习软件和计算机硬件的进步。对于某些训练集,唯一的选项是水平可扩展的机器学习。
最常用的分布式学习算法是线性(和逻辑)回归。Vowpal Wabbit(VW)库推广了这种方法,并且已经成为跨多台机器可扩展线性学习的主要支柱。分布式线性回归的基本工作方式是首先将训练数据集的子集(按数据集行进行子集划分)发送到集群中的各个机器。然后,以迭代的方式,每台机器对其手头的子集数据进行优化问题求解,并将优化结果发送回中央节点。在那里,这些信息被组合起来,以得出最佳的整体解决方案。经过几次迭代后,最终模型将保证接近整体最优模型(如果一次性将所有数据拟合到一个模型中)。因此,线性模型可以以分布式方式拟合到数太字节或更多的数据!
正如我们在本书中多次讨论的那样,线性算法并不一定足以模拟数据的细微差别以进行准确预测。在这些情况下,转向非线性模型可能会有所帮助。非线性模型通常需要更多的计算资源,并且非线性模型不一定总是可以实现水平可扩展性。这可以通过将非线性模型视为也考虑特征之间的复杂交互来粗略理解,因此需要任何给定节点上更大比例的数据集。
在许多情况下,升级硬件或找到更高效的算法或更高效的算法实现可能更可行。但在其他情况下,需要扩展非线性模型,本节我们将讨论几种处理此问题的方法。
多项式特征
模拟非线性特征交互的最常用技巧之一是创建新的特征,这些特征是现有特征的组合,然后训练一个包含非线性特征的线性模型。组合特征的一种常见方式是将特征以各种组合相乘,例如 特征 1 乘以特征 2,特征 2 的平方,或 特征 1 乘以特征 2 乘以特征 5。假设一个数据集包含两个特征,f1 = 4 和 f2 = 15。除了在模型中使用 f1 和 f2 之外,你还可以生成新的特征 f1 × f2 = 60,f1 ^ ² = 16 和 f2 ^ ² = 225。数据集通常包含远不止两个特征,因此这种技术可以生成大量新的特征。这些特征是现有特征的非线性组合。我们称它们为 多项式特征。以下列表展示了如何使用 scikit-learn Python 库实现这一点。此列表中代码的运行结果显示了向标准 Iris 花分类模型添加多项式特征时获得的准确度:
Accuracy (linear): 0.95 (+/- 0.12)
Accuracy (nonlinear): 0.98 (+/- 0.09)
列表 9.1. 通过使用多项式特征将线性模型非线性化

另一个集成了多项式特征提取的机器学习工具包示例是 Vowpal Wabbit 库。VW 可以用于在单机上构建大型数据集上的模型,因为所有计算都是迭代性地并且离线完成的,这意味着只需要保留特定迭代中使用的数据。VW 使用随机梯度下降和特征哈希来以可扩展的方式处理非结构化和稀疏数据。VW 可以通过提供 –q 和 –cubic 标志来生成二次或三次特征,对应于所有特征对或所有特征三联乘积的多项式特征。
数据和算法近似
正如你在前一节中看到的,多项式特征方法能够显著提高模型的准确度,但也以多项式的方式增加了特征数量。这可能对于大量输入特征来说并不可行,因此在这里,你将了解一些具有已知近似值且适用于可扩展实现的非线性算法。其他算法可能有它们自己的可扩展近似,所以我们鼓励你进一步研究你喜欢的算法。
一个广泛使用的非线性学习算法是随机森林,你已经在之前的章节中了解过。随机森林模型由许多决策树组成,乍一看,通过在每个节点上仅构建树的一个子集,似乎可以轻松地将随机森林扩展到多台机器。但请注意,如果每个节点可用的数据子样本不充分相似,模型的准确性可能会受到影响。但构建更多树或更智能地分割数据可以减轻准确性损失。
可以用于扩展随机森林和其他算法的另一个近似方法是直方图近似:数据集中的每一列都被替换为该列的直方图,这通常会显著减少列中的值数。如果直方图中的箱数太少,可能会丢失很多细微差别,从而导致模型性能下降。
另一个具有自然近似的方法的算法是 k-最近邻;可以使用特殊的近似树结构来提高模型的可扩展性。支持向量机已经看到了多种近似方法,以使非线性版本更具可扩展性,包括预算随机梯度下降(BSGD)和自适应多超平面机器(AMM)。
深度神经网络
神经网络研究最近的一次革命催生了一个新的领域——深度学习,该领域产生了高度非线性的模型,并且已被证明能够扩展到非常大的数据集。在机器学习的早期,神经网络(NNs)被广泛研究并应用于科学和工业领域。后来,随着易于数学推理的算法的出现,神经网络的使用频率降低。最近,经过几个重要的进化步骤并进入深度学习领域后,神经网络再次在大型和多样化的数据集上产生了最先进的结果。
深度学习指的是一系列扩展传统神经网络的算法。通常,这些模型包括神经网络中的许多隐藏层或许多单层网络的组合。图 9.5 展示了示例神经网络。
图 9.5. 具有两个隐藏层的神经网络。松散地模拟人脑,神经元(每层的圆圈)通过在模型训练期间学习的权重相互连接。输出变量可以通过运行输入变量通过加权连接来预测。在深度学习中,这个经典的神经网络概念被扩展到包括更多形状和层间连接程度各异的隐藏层。

深度神经网络的一个缺点是,即使在 GPU 硬件上,构建和优化模型所需的计算资源也可能需要很长时间。在实践中,你可能只需使用其他算法,如随机森林,就能获得几乎相同的表现,同时花费更少的时间和资源。这始终取决于数据集和问题。另一个缺点是,理解这些神经网络模型内部发生的事情可能很困难。有些人称它们为黑盒模型,因为你必须相信你对模型进行的统计分析结果,而不需要对其内部进行任何反思。这同样取决于用例。例如,如果你在处理图像,神经元可以承担各种视觉模式的直观表示,这些模式导致特定的预测。
许多深度学习方法已经证明可以扩展到大型数据集,有时通过使用现代图形卡(GPU)来执行某些计算。对于支持 GPU 的 Python 深度学习库,请查看Theano (deeplearning.net/software/theano/)或Keras (keras.io/),它基于 Theano)。
9.3. 扩展预测
扩展机器学习不仅仅是扩展到更大的数据集。想象一下你正在构建一个电子邮件服务,突然有数百万用户。你构建了一个很好的垃圾邮件检测模型,它甚至可以扩展到大型数据集,但现在你每天需要做出数亿次的预测。这超过了每秒 10,000 次!图 9.6 说明了这种常见的模式。在本节中,我们讨论了扩展预测量以及当需要实时使用预测时的扩展速度的方法。
图 9.6. 将机器学习工作流程中的预测部分扩展到高容量或高速预测

首先,你将查看用于通过预测量扩展的基础设施架构,这样你就可以处理电子邮件客户端等的大用户群。接下来,你将了解如何扩展预测速度并保证在给定时间内得到答案。当你的机器学习模型用于例如人类在网页或移动设备上的实时反馈循环时,这一点很重要。
9.3.1. 扩展预测量
为了处理大量预测,你可以使用来自计算架构中已知的模式来扩展工作节点以支持任意数量的请求。传统的方法是有一个预测作业队列,其中多个工作节点从中提取预测,加载模型(如果需要),进行预测,并以任何对应用程序有意义的方式推送结果。图 9.7 展示了通过容量扩展预测的这种架构可能的样子。
图 9.7. 可扩展预测服务的可能基础设施。预测请求从消费者发送到一个队列,队列将任务委托给预测工人。工人在数据库中存储预测结果,并在完成后将其发送回客户端。如果队列因流入的预测请求多于工人能处理的数量而拥堵,可以启动更多的工人。

这种方法要求模型可以加载到所有工作节点上,当然,还需要有足够的工人(或已部署的自动扩展解决方案)来处理涌入的预测数量。如果你知道一个工人的平均预测时间和请求的速度,你可以轻松计算出所需的工人数量:
n_workers = request_velocity * prediction_time
例如,如果你每秒有 10 个预测请求进入,而你的工人需要 2 秒来完成,你需要至少 20 个工人来跟上。最佳的自动扩展解决方案是能够在一定时间内根据队列中等待的请求数量启动新的工人。
9.3.2. 扩展预测速度
在某些情况下,你需要预测在客户端发出请求后的一定时间内返回。预测速度可能很重要,例如,当预测是对用户操作的反应时。用户期望实时反馈,等待几秒钟都可能对用户体验产生不利影响。想象一下,一个谷歌搜索需要 20 秒——很可能你已经离开了。或者,如果你正在对金融交易进行预测,仅仅几毫秒可能意味着赚或亏很多钱。
有多种方法可以使预测更快,例如升级硬件或使用更高效的算法或算法的实现。你还可以优化网络,确保客户端尽可能靠近你的服务器。此外,你不应该调用任何可能引入额外延迟的其他服务,例如将预测记录到数据库中,或等待数据被写入磁盘并在集群中复制。在下面的例子中,我们假设你已经考虑了这些点。现在,你将查看两个用于提供实时预测的架构。
快速预测的第一个架构与前面按体积缩放部分中介绍的架构类似,但需要更多的工人。基本思路是,每个预测请求同时发送给多个工人,第一个完成的预测结果被发送回客户。图 9.8 展示了这种架构的一个示例。
图 9.8. 具有低延迟要求的预测管道的可能架构。预测调度器将预测任务发送到多个工作者,希望至少有一个能及时返回预测。它将返回第一个返回的客户,之后将其记录在日志或数据库中,以供后续检查和分析(在后台,可能在已经处理下一个预测的同时)。

另一种实时预测的方法是将预测分成几部分,以便计算可以在多台机器之间分配。集成方法是一类适合这种方法的算法。我们再次以随机森林为例。
随机森林模型由一系列决策树组成。该算法从每棵树中进行预测,并在分类的情况下,将每棵树的投票计入最终概率。例如,如果有 10 棵树,其中 6 棵树对一个特定的预测实例投赞成票,那么森林返回 6/10,即 60%作为答案。通常,查询的总树数越多,结果越准确、越有信心。这可以用于实时预测系统,以速度换取准确性。如果每个预测节点负责森林中的一棵树或树列表,那么你会要求每个节点进行预测。每当节点完成其树的预测后,结果会返回给收集服务,该服务收集所有节点的结果并做出最终预测。收集器可以观察时间限制,并在必要时在任何时候返回当前状态的预测。例如,如果只有 20 棵树中的 1,000 棵返回了任何内容,用户会得到一个答案,但它的准确性不如所有 1,000 棵树都有时间返回答案的情况。
图 9.9 显示了该架构的实际操作图。
图 9.9. 确保在特定时间内返回的预测管道的建议架构,如果一些部分预测尚未返回,可能会牺牲预测的准确性和信心。预测请求由生产者发送到工作者,而消费者服务收集准备返回给客户的部分预测,如果时间到了。

一些系统在支持这些可扩展的实时系统方面显示出希望。一个是之前提到的 Apache Spark 生态系统的一部分:Spark Streaming。使用 Spark Streaming,你获得了一套工具和库,使构建实时、面向流的数据处理管道变得更容易。别忘了,任何预测通常都必须经过与模型构建时训练数据相同的特征工程过程。
其他项目包括 Apache Storm、Apache Kafka、AWS Kinesis 和 Turi。每个项目都有针对特定用例的优缺点,所以我们鼓励你调查适合你需求的适当工具。
9.4. 摘要
在本章中,你已经研究了通过转换数据或构建水平可扩展的多机基础设施来扩展机器学习系统到大型数据集的各种方法。本章的主要收获如下:
-
扩展你的机器学习系统有时是必要的。以下是一些常见原因:
-
训练数据无法适应单个机器。
-
训练模型的时间太长。
-
进入的数据量太大。
-
预测的延迟要求很低。
-
-
有时,你可以通过以下方式避免在可扩展基础设施上花费时间和资源:
-
选择一个足够快或足够精简的机器学习算法,可以在不牺牲准确性的情况下在单个机器上工作
-
对数据进行子采样
-
垂直扩展(升级机器)
-
如果仍然比扩展更便宜,则可以牺牲准确性或放宽其他约束
-
-
如果无法避免以横向方式扩展,则广泛使用的系统可用于设置可扩展的数据管理和处理基础设施:
-
带有 Mahout 机器学习框架的 Hadoop 生态系统
-
带有 MLlib 机器学习库的 Spark 生态系统
-
Turi(以前称为 GraphLab)框架
-
流式技术,如 Spark Streaming、Apache Storm、Apache Kafka 和 AWS Kinesis
-
-
在扩展模型构建管道时,请考虑以下因素:
-
选择一个可扩展的算法,如逻辑回归或线性 SVM
-
通过对数据和算法进行近似来扩展其他(例如,非线性)算法
-
使用分布式计算基础设施构建你喜欢的算法的可扩展版本
-
-
预测可以在数量和速度上进行扩展。以下是一些有用的方法:
-
构建你的基础设施,使其能够随着预测量的增加而扩展工作者的数量
-
将相同的预测发送到多个工作者,并返回第一个以优化预测速度
-
选择一个允许你在多台机器上并行化预测的算法
-
9.5. 本章术语
| 词汇 | 定义 |
|---|---|
| 大数据 | 一个广泛使用的术语,通常用来表示无法在单个机器上处理的数据管理和处理问题。 |
| 水平/垂直扩展 | 水平扩展意味着添加更多机器来处理更多数据。垂直扩展意味着升级你的机器的硬件。 |
| Hadoop, HDFS, MapReduce, Mahout | Hadoop 生态系统在科学和工业中广泛用于处理和加工大量数据。HDFS 和 MapReduce 分别是分布式存储和并行处理系统,而 Mahout 是 Hadoop 生态系统中的机器学习组件。 |
| Apache Spark, MLlib | Apache Spark 是一个较新的项目,它试图将数据保留在内存中,使其比基于磁盘的 Hadoop 更高效。MLlib 是 Spark 伴随的机器学习库。 |
| 数据局部性 | 在数据所在的位置进行计算。在大数据项目中,数据传输往往成为瓶颈,因此避免数据传输可以大大提高资源需求。 |
| 多项式特征 | 一种技巧,可以将线性模型扩展到包括非线性多项式特征交互项,同时不失去线性学习算法的可扩展性。 |
| Vowpal Wabbit | 一种机器学习工具,可以在大型数据集上高效地构建模型,而不必使用像 Hadoop 这样的完整大数据系统。 |
| 离核计算 | 如果您只需要在内存中保留当前迭代的数据,则进行离核计算。 |
| 直方图近似 | 对训练数据的近似,将所有列转换为学习过程中的直方图。 |
| 特征选择 | 通过选择和保留最佳(最具预测性)的特征子集来减少训练数据大小的过程。 |
| Lasso | 一种线性算法,选择最具预测性的特征子集。在特征选择方面非常有用。 |
| 深度神经网络 | 神经网络的一种演变,可以扩展到更大的数据集并实现最先进的准确性。在实际应用中,相对于其他算法,它需要更多的知识和计算资源,这取决于数据集和问题。 |
| 预测量/速度 | 扩展预测量意味着能够处理大量数据。扩展速度意味着能够足够快地处理特定实时用例。 |
| 准确度与速度 | 对于实时预测,有时可以以预测速度为代价来换取预测的准确性。 |
| Spark Streaming、Apache Storm、Apache Kafka、AWS Kinesis | 建立实时流系统的即将到来的技术。 |
第十章。示例:数字展示广告
本章涵盖
-
可视化和准备一个现实世界的数据集
-
建立用户点击数字展示广告概率的预测模型
-
比较几个算法在训练和预测阶段的表现
-
通过降维和并行处理进行扩展
第九章介绍了使您能够扩展机器学习工作流程的技术。在本章中,您将应用这些技术来解决一个大规模的实际情况:优化在线广告活动。我们从对在线广告复杂世界的简要介绍开始,包括驱动它的数据,以及广告商用来最大化广告支出回报率(ROAS)的一些方式。然后我们展示如何将第九章中的一些技术应用于这个典型的大数据应用。
在我们的示例中,我们使用了几个数据集。不幸的是,此类大型数据集只有少数对公众开放。我们示例中的主要数据集不可下载,即使可以下载,也太大,不适合个人计算机使用。
可以下载并用于非商业目的的一个数据集来自由 Criteo 赞助的 Kaggle 展示广告挑战赛。Criteo 数据集包含超过 4500 万个关于 39 个特征的观测值,其中 13 个是数值型,26 个是分类型。不幸的是,正如在数据科学竞赛中使用的数据集常见的那样,特征的含义是模糊的。变量名称从 V1 到 V40。V1 是标签,V2 到 V40 是特征。在现实世界中,你会知道每个特征衡量或代表什么。但正如比赛证明的那样,你仍然可以探索它们的预测价值并创建有用的模型。
Criteo 数据集可在s3-eu-west-1.amazonaws.com/criteo-labs/dac.tar.gz获取。
10.1. 展示广告
我花在广告上的钱有一半是浪费的;麻烦的是,我不知道是哪一半。
约翰·万纳梅克
在 广告狂人 时代,这是一个无法避免的事实。但随着数字广告的出现,我们可以通过收集用户与在线广告互动的数据来发现哪些有效,哪些无效。
在线广告通过众多媒体进行传递。展示广告出现在浏览器中渲染的网页内,通常在个人电脑或笔记本电脑上。由于移动浏览器上识别用户和处理互联网 cookie 的规则不同,移动广告技术依赖于不同的一套技术,并生成相当不同的历史数据。原生广告嵌入在游戏和移动应用中,以及预播放广告,它们在在线视频内容之前播放,基于不同的传递技术,并需要针对其独特流程的分析。我们的例子仅限于传统展示广告。
展示广告的大部分术语都是从印刷广告业务中继承下来的。可以购买广告的网站被称为 出版物,其中的广告空间以尺寸和格式为特征,或称为 广告单元,而广告在网站和页面中的位置被称为 投放位置。每次广告展示都称为 印象。广告以每 1000 次印象的批量出售,这种价格被称为 CPM(每千次成本)。
当用户浏览到网页时——比如说,xyz.com——看起来是 xyz.com 的发布者提供了整个页面。实际上,页面包含由各种广告商通过复杂的中间商网络填充的广告占位符。每个提供广告的 Web 服务器都维护日志,包括有关每次印象的信息,包括发布者、用户的互联网地址以及包含在互联网 cookies 中的信息,其中可能存储了来自广告商服务器的先前交付的信息。在下一节中,您将了解在展示广告活动中捕获的数据类型。
10.2. 数字广告数据
Web 服务器为每个用户请求捕获数据,包括以下内容:
-
客户端地址— 发起请求的计算机的 IP 地址。
-
请求— URL 和参数(例如,
www.abc.com?x=1234&y=abc01)。 -
状态— 服务器发出的响应代码;通常是 200,表示成功响应。
-
来源网站— 用户链接到当前网页的网页。
-
用户代理— 识别发起请求的浏览器和操作系统的文本字符串。
-
Cookie— 当浏览器访问网站时存储的小文件。当再次访问该网站时,文件会随请求一起发送。
此外,许多现代广告都与测量程序一起提供——捕获如下信息的小型 JavaScript 程序:
-
可视化— 广告是否以及显示了多长时间。
-
用户 ID— 浏览器 cookies 用于留下唯一标识符,以便在再次遇到时识别用户。
-
可视化秒数— 广告显示的秒数。
图 10.1 展示了活动样本数据。可视化数据是从查询字符串中提取的,而 user_id 是随机生成的标识符,用于将用户与之前的访问关联起来。
图 10.1. 印象数据。域名是随机生成的真实名称的替代品。

10.3. 特征工程和建模策略
点击 是我们的目标变量。您希望预测印象导致点击的可能性(有时称为 点击率 或 点击通过率)。更具体地说,给定一个特定用户访问特定网站,您想了解用户点击广告的概率。在制定问题方面,您有几个选择。您可以尝试预测给定用户点击通过的概率,也可以尝试预测每个展示广告的发布者的点击通过率(CTR)。
正如通常情况一样,你模型的具体内容和你努力预测的确切值最终将由提出这些问题来驱动:预测将如何被使用?它将以何种方式被实施?在这种情况下,我们的广告商有选择性地将某些出版物列入黑名单的选项,因此广告商的主要关注点是识别最不可能产生点击的出版物。近年来,已经开发出实时竞价技术,使广告商能够根据竞价系统提供的用户和出版物特征对单个展示进行竞价,但我们的示例广告商尚未采用实时竞价。
你可能会在这个时候感到疑惑,为什么广告商不直接查看所有出版物的一些历史数据,并将 CTR 低的出版物列入黑名单。问题是,当一场活动的整体 CTR 在 0.1%左右时,只有少量展示的出版物的点击预期值是零。没有点击并不表示 CTR 低。此外,当我们汇总表现最好的低量级出版物时,我们经常观察到高于平均水平的 CTR(因此仅仅将所有低量级出版物列入黑名单并不是一个好的策略)。你正在寻找一个模型,它将使你能够在没有大量性能历史的情况下预测出版物的表现。
初看之下,你可能认为你没有什么可以利用的。你可以统计用户、出版商和操作系统的展示、点击和观看次数。也许一天中的某个时间或一周中的某一天会有一些影响。但进一步思考后,你意识到用户访问的域名是描述用户的功能,访问域名的用户是域名特征。突然之间,你有了大量可以工作的数据,以及一个真实世界的体验维度诅咒的机会——这是一个用来描述在高维空间中工作所遇到的困境的短语。当你探索数据时,你会发现大量特征,如果不是诅咒,也是好坏参半的祝福。
你可能会认出在这里应用的逻辑是推荐系统的基础,这些系统在 Netflix 上推荐电影,在 Amazon 上推荐产品,在 Yelp 上推荐餐厅。将用户描述为物品集合,将物品描述为用户集合的想法是协同过滤的基础,其中用户根据共同物品偏好进行聚类,物品根据共同用户的亲和力进行聚类。当然,推荐系统的动机是向用户提供他们可能购买的项目。广告问题是一个变体;不是许多项目,而是在广泛的上下文中展示相同的广告:出版物。驱动原则是,在类似那些有响应历史记录的出版物上实现用户响应(点击)的可能性最大。而且因为相似性基于共同用户,以这种方式选择的出版物将吸引与过去响应者偏好相似的人。
10.4. 数据的大小和形状
你将从 900 万个观测值的样本开始,这是一个足够小的样本,可以放入内存中,这样你就可以做一些关于基数和分布的快速计算。
列表 10.1. 数据的第一印象

幸运的是,大多数用户从未访问过大多数域名,因此用户/项目矩阵是稀疏的,你可以使用工具来处理大型、稀疏的矩阵。没有人说过用户和域名必须是巨大矩阵的行和列,但事实是,当可以在内存中操作用户/项目矩阵时,一些有价值的算法表现得特别出色。
哦,还有一件事:在列表 10.1 中提到的 900 万观测值大约占数据的 0.1%。最终,你需要处理大约 100 亿次的印象,而这只是数据的一周量。我们将 900 万次印象的数据加载到亚马逊网络服务(AWS)实例的约 53%内存中,该实例有 32GB 的 RAM,所以随着你的深入,这肯定会更有趣。
接下来,让我们看看数据如何在分类变量上分布。在列表 10.1 中,我们已经通过计算pub_domain和user_id的基数开始了这个过程。
列表 10.2. 分布


图 10.2 显示,许多域的印象数量很少,而少数域的印象数量很多。为了你能直观地看到分布图,我们绘制了以 10 为底的对数而不是原始频率(我们使用 10 为底,这样你可以将 x 轴视为 10⁰、10¹、10²...)。
图 10.2. 印象数据的直方图显示,出版域中印象数量的分布严重偏斜。

也许最显著的是,你可以看到点击率相对较低,仅为 0.12%,或者说 0.0012。这是一个令人尊重的整体点击率。但在这个例子中,你需要大量的数据集,以便有足够的目标示例来构建你的模型。这并不罕见。我们经常试图预测相对罕见的现象。通过使用大数据技术处理大量数据集的能力,使得将机器学习应用于许多全新的问题类别成为可能。
同样,按user_id计算的印象频率高度倾斜。平均用户有 2.46 次印象,但中位数是 1,所以少数几个高点击量将平均值拉高。
10.5. 奇异值分解
第三章和第七章提到了主成分分析,或 PCA,这是一种无监督的机器学习技术,常用于降维和提取特征。如果你将每个用户视为他们互动的出版物的一个特征,那么每个出版物大约有 360 万个特征,你的数据探索样本有 1500 亿个值。显然,你希望使用更少的特征,幸运的是,你可以相当容易地做到这一点。
实际上,PCA 有几个算法,其中之一是奇异值分解,或称为 SVD。你可以用各种方式从数学上解释和解释 SVD,数学家会认识到我们在这里的解释忽略了底层线性代数的一些美感。幸运的是,就像在第七章中介绍的潜在语义分析一样,SVD 在 scikit-learn Python 库中有一个出色的实现。但这次,让我们只做一点矩阵代数。如果你做过矩阵乘法,你就会知道维度很重要。如果 A[[n x p]]表示一个 n 行 p 列的矩阵,你可以将 A 与另一个维度为 p 行 q 列的矩阵相乘(例如,B[[p x q]]),结果将具有 n 行 q 列的维度(例如,C[[n x q]])。实际上,任何矩阵都可以分解为三个组成部分,分别称为左奇异向量、右奇异向量和奇异值。
在这个例子中,n 是用户数量,每个用户由矩阵 A 中的一行表示,p 是出版物数量,每个出版物由矩阵 A 中的一列表示:

使这变得有趣的是,奇异值告诉你关于由左右奇异向量(这些向量是 U 和 V^T 的行)表示的特征的重要性。特别是,奇异值告诉你相应的特征向量独立到什么程度。考虑相互依赖或协变特征的含义。或者,为了使它更容易理解,想象两个特征,A 和 B,是相同的。在模型考虑了特征 A 之后,特征 B 就没什么可以贡献的了。它不包含任何新信息。作为预测模型的构建者,你想要的特征是独立的,并且每个特征至少是目标的一个弱预测器。如果你有很多弱预测器,只要它们的预测比随机预测好,结合起来它们就会增强力量。但这种现象,集成效应,只有在特征独立时才会起作用。
让我们在我们的广告数据上运行 SVD,并查看产生的奇异值。
列表 10.3. 广告数据的 SVD

当你运行 SVD 时,你使用了 k = 最大奇异值参数来限制计算只到 1,550 个最大的奇异值。图 10.3 显示了它们的幅度;你可以看到大约有 1,425 个非零值,并且超过 450 个最独立的特征向量之外,其余的都是高度协变的。这并不奇怪。尽管有超过 300 万用户,但请记住,他们中的大多数只与非常少的 pub 互动。考虑到这些,其中 13.6 万个用户(顺便说一句,在 ebay.com)只被观察过一次。所以如果每个用户向量是 pub 的一个特征,ebay.com 就有 13.6 万个相同的特征。
图 10.3. 广告数据的奇异值

我们将 SVD 将超过 300 万个特征减少到大约 7 千个,减少了 400:1。了解这一点后,你对所需的资源有了更好的感觉。在下一节中,你将了解如何确定和优化训练模型所需的资源。
10.6. 资源估计和优化
到目前为止,你已经查看了你数据的基数和分布,并进行了某些特征工程。在本节中,你将根据你拥有的资源相对于计算工作量的任务进行评估。
为了估计资源需求,你需要从一些测量开始。首先让我们看看你的可用资源。到目前为止,你一直在使用单个 m4.2xlarge 亚马逊 EC2 实例。让我们快速解码一下。EC2 是亚马逊的弹性计算云。每个实例都是一个具有专用 CPU、随机存取内存(RAM)和磁盘或固态在线存储的虚拟服务器。"m4.2xlarge"标识符意味着一个具有八个核心和 32GB 内存的服务器。磁盘空间是单独配置的。我们的单个实例配备了 1TB 的弹性块存储(EBS)。EBS 是虚拟化存储,设置为看起来你的实例有一个专用的 1TB 磁盘卷。你已经设置了你的实例以运行 Linux。根据你的需求,你可以轻松地将单个实例升级以添加核心或内存,或者你可以配置更多的实例。
接下来,让我们看看你的工作负载。你的原始数据存储在亚马逊的简单存储服务(S3)的交易文件中,S3 旨在以低廉的价格存储大量数据。但访问速度比本地磁盘文件慢得多。每个文件大约包含 100 万条记录。你可以从 S3 中每秒读取大约 30,000 条记录,所以如果你逐个处理它们,10 亿条将需要大约 92 小时。通过并行处理多个下载(在单个实例上),可以从 S3 中加速下载,大约可以提高 75%,这样可以将时间缩短到 23 小时。
但速度并不是你唯一的问题。根据你之前的观察,将 1000 万条记录加载到内存中会消耗你 32GB 内存的 53%,要加载整个数据集需要 1.7TB 的内存。即使你能负担得起,亚马逊也没有那么多 RAM 的实例。
幸运的是,你不需要将所有数据都存储在内存中。此外,你的需求并不仅仅取决于数据的大小,还取决于其形状——我们指的是其主键的基数。结果显示,有 100 亿条记录,但只有大约 1000 万用户和大约 30 万个出版物,这意味着用户/出版物矩阵大约有 3 万亿条条目。但是,当你填充你的稀疏矩阵时,只有大约 0.01%的单元格中有值,所以 3 万亿减少到 3 亿。假设每个值有一个 64 位的浮点数,你的用户/出版物矩阵将大约占用你 32GB 中的 2.5GB。
为了减少处理时间,你需要考虑并行处理。图 10.4 图说明了使用工作节点(额外的 EC2 实例,在这种情况下)并行获取原始数据。
图 10.4。并行处理扩展了初始数据获取。

工作节点不仅从 S3 读取数据。每个节点独立构建用户和物品的稀疏矩阵。当所有工作节点完成他们的工作后,这些矩阵将由你的计算节点组合。
第九章描述了一些大数据技术:Hadoop、MapReduce 和 Apache Spark。这里描述的过程是 MapReduce 作业中发生的事情的高度简化版本。一个大任务被分解成小单元,每个单元被分配(映射)到工作节点。当工作节点完成它们的子任务时,结果被合并(减少),并将结果返回给请求者。Hadoop 通过几种方式优化了这个过程。首先,而不是让工作节点通过网络检索数据,每个工作节点将部分数据存储在本地。Hadoop 优化任务分配,以便尽可能让每个节点处理已经存储在本地卷上的数据。Spark 更进一步,让工作节点将数据加载到内存中,这样它们在处理分配的任务时就不需要进行任何 I/O 操作。
尽管这个示例问题足够大,需要一点并行处理,但实现这些框架之一所付出的努力可能并不值得。你每天只需要运行整个工作流程一次,你很容易增加几个实例,并将整个过程缩短到一小时或更少。但你可以很容易地想象一个需要你以更高频率运行各种过程的应用程序,其中工作节点在多个处理周期中保留原始数据在内存中,将性能提升几个数量级。
10.7. 模型构建
你的目标是预测每个出版物的点击率(CTR)。你从用户交互作为特征开始,并使用奇异值分解(SVD)来降低特征空间。从这里,有几种方法可以做出预测。你的第一个模型将是一个 k-最近邻算法(KNN)模型。这是一个简单但出奇有效的推荐模型。
你还将训练一个 随机森林回归器。随机森林是一种基于决策树的机器学习方法;它选择了数据的多组随机样本和特征集的随机子集,并为每个选择构建决策树。
10.8. K-最近邻算法
图 10.5 显示了简化的用户/项目和相似度矩阵。注意,相似度矩阵的对角线都是零,因为每个出版物的用户向量(用户/项目矩阵中的列)与其自身相同,因此与自身之间的距离为零。你可以看到 pub3、pub4 和 pub7 之间的距离为零,正如你所期望的,因为它们在用户/项目矩阵中的相应列是相同的。此外,请注意 pub1 与 pub5 的距离与 pub5 与 pub1 的距离相同。换句话说,不相似性是对称的。有趣的是,一些推荐算法没有定义对称的距离。项目 A 可能类似于项目 B,但项目 B 可能不类似于项目 A。
图 10.5. 相似度,或距离,矩阵显示了用户交互的相似或不同程度。在这个例子中,用户/项目矩阵是二元的,表示用户是否与 pub 互动。

你使用几种可用的度量之一计算每对 pub 之间的相似度(实际上,dissimilarity,或距离)。然后你选择最常见的方法,即 欧几里得距离。
在计算完成对距离之后,下一步是计算每个 pub 的预测 CTR。在 KNN 中,预测的目标值是通过计算 k 个最近邻的目标值的平均值来得到的,假设每个示例观测值将与其最近的邻居最相似。在这个阶段有几个重要的问题。首先,你应该选择 k 的什么值?应该考虑多少个邻居?此外,通常会给最近的邻居更大的权重,通常是通过将平均目标值的计算加权为 1/距离或[1/距离]²。
代码列表 10.4 展示了使用 scikit-learn NearestNeighbors计算一系列可能的 k 值预测值的计算。在这里,你尝试了三种加权公式,每个公式有 20 个 k 值。图 10.6 显示,最佳预测者是一个或两个最近邻,对更大范围的平均并没有真正的改进。这可能是由于我们的数据稀疏,最近邻通常相当遥远。注意,k 值的变异性也较小。无论如何,我们的测试集预测的标准化 RMSE 在 5%的范围内。还不错!
图 10.6. 三种加权函数和 k = 1 到 k = 30 的 RMSE 值

代码列表 10.4. KNN 预测


10.9. 随机森林
在随机森林的训练阶段,数据会通过一个称为 bagging 的过程(有时也称为 bootstrap aggregating)进行重复采样,并且是有放回的。对于每个样本,使用随机选择的特征子集构建一个决策树。为了对未见过的数据进行预测,每个决策树都是独立评估的,并且结果会被平均(对于回归)或者每个树对分类进行“投票”。对于许多应用来说,随机森林可能不如其他算法(如提升树或支持向量机)表现好,但随机森林有易于应用、结果易于解释和理解、以及多棵树的训练易于并行化的优点。再次强调,你将使用 scikit-learn;参见图 10.7。
图 10.7. 随机森林回归的变量重要性

代码列表 10.5. 随机森林回归


优化的随机森林回归提供了有用的点击率预测,但它不如 KNN 预测好。你的下一步可能就是探索将这些模型以及其他模型结合起来的方法。以这种方式结合模型的方法被称为集成方法。随机森林本身就是一种集成方法,因为袋装是一种生成多个模型的方式。为了结合完全不同的模型,例如本例中的两个模型,你可能需要采用堆叠或堆叠泛化,在这种方法中,多个模型的预测成为由另一个机器学习模型(通常是逻辑回归)训练和预测时结合的特征。
10.10. 其他现实世界的考虑因素
你考虑了大数据带来的现实世界问题:高维度、计算资源、存储和网络数据传输限制。正如我们简要提到的,整个过程可能适用于几种数字广告类型:移动、视频和原生。实时竞价和用户级个性化有一套完全不同的关注点。你拥有的数据可能因程序而异,而在一种情况下完美工作的模型可能在另一种情况下完全失败。
在我们的例子中,我们一开始有一个庞大的历史数据集。但我们的推荐系统方法存在一个被称为冷启动问题的问题。当一个新用户或新产品进入系统而没有历史记录可依赖时,你没有任何基础来建立关联。对我们来说,一些未知因素并不重要,但当一个新的活动从头开始时,你完全没有历史记录可以工作。基于其他类似活动的模型构建的模型可能有效也可能无效。
在现实世界中,拥有各种可以使用的工具和模型具有很大的优势。环境越大、越复杂,拥有这样一套特征构建、数据减少、训练、预测和评估工具的好处就越大,这些工具应该组织良好并集成到一个连贯的自动化工作流程中。
广告是一个很好的例子,说明外部性可能会降低你的预测模型的有效性。随着技术和商业实践的变革,行为也在改变。移动设备的增长极大地改变了数字景观。实时竞价完全改变了你应用优化的层级。新的欺诈形式、广告拦截器、新的浏览器和新的网络技术都改变了你正在建模的动态。在现实世界中,模型被构建、测试、部署、衡量、重建、重新测试、重新部署,并再次衡量。
数字广告是一个价值数十亿美元的业务,对于依赖它的品牌来说,即使是减少一点浪费支出,也能带来显著的回报。你可以消除的每一处浪费印象都能节省金钱,但当你用能带来客户获取的印象替换时,其好处将远远大于成本节省,并且将远远超过克服这个动态业务众多挑战的努力。
10.11. 摘要
本章不仅涵盖了选择算法、训练和测试模型等机器学习问题的要素,而且比仅仅选择算法、训练和测试模型更为广泛。尽管这些是机器学习学科的核心,但它们的成功往往取决于周围的实践性和权衡。以下是本章示例中的关键点:
-
第一步始终是理解你正在建模的业务或活动,其目标以及如何衡量它们。考虑你的预测如何被采取行动也很重要——预测基于你提供的洞察力可以做出哪些调整或优化。
-
不同的特征工程策略可能会产生非常不同的工作数据集。撒大网并考虑多种可能性是有益的。在第一个模型中,你大大扩展了特征集,然后使用奇异值分解(SVD)进行缩减。在第二个模型中,你使用了简单的聚合。哪种方法最有效取决于问题和数据。
-
在探索数据子样本之后,你能够估计执行分析所需的计算资源。在我们的例子中,瓶颈不是机器学习算法本身,而是将原始数据收集和汇总成适合建模的形式。这种情况并不少见,当你考虑资源需求时,考虑先决条件和下游工作流程任务同样重要。
-
通常,最好的模型不是一个单一的模型,而是一系列模型,这些模型的预测由另一个预测模型汇总。在许多现实世界的问题中,最佳可能的集成与创建、操作和维护复杂工作流程的实用性之间存在实际权衡。
-
在现实世界中,往往只有少数,有时很多,对当前问题的变体。我们讨论了其中一些用于广告的变体,它们在任何复杂学科中都很常见。
-
你所建模的现象的潜在动态通常不是恒定的。商业、市场、行为和条件都在变化。当你在现实世界中使用机器学习模型时,你必须不断监控它们的性能,有时甚至需要回到起点重新设计。
10.12. 本章术语
| 单词 | 定义 |
|---|---|
| 推荐算法 | 一类用于预测用户对各种物品亲和力的机器学习算法。 |
| 协同过滤 | 通过描述用户的物品偏好和物品的常见用户偏好来工作的推荐算法。 |
| 集成方法 | 一种机器学习策略,其中多个模型的独立预测被组合在一起。 |
| 集成效应 | 多个组合模型倾向于产生比单个组件更好的预测性能的趋势。 |
| k 最近邻 | 一种基于训练空间中最近观察值的预测算法。 |
| 欧几里得距离 | 在特征空间中测量距离的许多方法之一。在二维空间中,它是熟悉的距离公式。 |
| 随机森林 | 一种集成学习方法,它将多个决策树分类器或回归器拟合到训练数据的子集和特征中,并根据组合模型进行预测。 |
| 折叠法 | 随机森林和其他算法使用的重复有放回抽样的过程。 |
| 堆叠 | 使用机器学习算法(通常是逻辑回归)结合其他算法的预测,以创建最终的“共识”预测。 |
10.13. 回顾与结论
写这本书的第一个目标是以一种可理解且有趣的方式解释现实世界中实践中的机器学习。另一个目标是让你能够识别出机器学习何时可以解决你的现实世界问题。以下是一些关键点:
-
机器学习方法在解决某些数据驱动问题方面确实具有优势。
-
基本的机器学习工作流程包括数据准备、模型构建、模型评估、优化和预测。
-
数据准备包括确保收集了足够数量的正确数据,可视化数据,探索数据,处理缺失数据,重新编码分类特征,执行特征工程,并始终注意偏差。
-
机器学习使用了许多模型。广泛的类别包括线性和非线性、参数和非参数、监督和非监督,以及分类和回归。
-
模型评估和优化涉及迭代交叉验证、性能测量和参数调整。
-
特征工程使得应用领域知识和使用非结构化数据成为可能。它通常可以显著提高模型的性能。
-
规模不仅仅是关于大数据。它涉及工作划分、新数据摄入速率、训练时间和预测时间,所有这些都在业务或任务需求背景下进行。
机器学习的数学和计算机科学已经伴随着我们 50 年,但直到最近,它们都局限于学术界和一些神秘的应用。随着大型互联网公司的增长和世界上网的数据传播,大门已经打开。企业、政府和研究人员每天都在发现和发展机器学习的新应用。这本书主要关于这些应用,只包含足够的基础数学和计算机科学知识,不仅解释了从业者做什么,还解释了他们是如何做的。我们强调了无论算法、规模或应用如何,都适用的基本技术和流程。我们希望我们已经帮助消除了机器学习的神秘感,并在这样做的同时,帮助推进了其解决重要问题的应用。
进步如同波浪般涌现。计算机自动化浪潮改变了我们的机构。互联网的浪潮改变了我们的生活和文化。有充分的理由预期,今天的机器学习只是下一波浪潮的预览。它将是一个可预测的涨潮,还是一场狂风暴雨,或者是一场海啸?现在说还为时尚早,但采用率不仅正在推进,而且正在加速。与此同时,机器学习工具的进步令人印象深刻。我们编程让计算机系统以全新的方式进步,它们正在学习看、听、说话、翻译语言、驾驶我们的汽车,并预测我们对商品、服务、知识和关系的需求和欲望。
亚瑟·C·克拉克曾说,任何足够先进的技术都与魔法无异(克拉克第三定律)。当机器学习最初被提出时,确实听起来像是魔法。但随着它变得越来越普遍,我们开始将其视为一种工具。当我们看到许多它的应用实例时,我们可以从人类的角度进行概括,并想象其他用途,而无需了解其内部运作的所有细节。像其他曾经被视为魔法的先进技术一样,机器学习正在成为自然现象,最终比魔法更加微妙和美丽。
进一步阅读
对于那些想了解如何在 Python 语言中使用 ML 工具的人来说,我们推荐 Peter Harrington 的《机器学习实战》(Manning,2012 年)。
如果你想在 R 语言中深入了解示例,可以考虑 Max Kuhn 和 Kjell Johnson 合著的《应用预测建模》(Springer,2013 年)。
凯西·奥尼尔描述她和雷切尔·舒特的书籍《做数据科学:前线直言》(O'Reilly Media,2013 年)为“我上大学时希望存在的课程。”我们同意。
如果你感兴趣于大数据和机器学习对商业和社会的影响,可以考虑维克托·迈尔-舍恩伯格和肯尼思·库克耶合著的《大数据:一场将改变我们生活、工作和思考方式的革命》(Houghton Mifflin Harcourt,2013 年)。
网络资源包括以下内容:
-
www.analyticsvidhya.com—专注于学习的分析新闻
-
www.kaggle.com—竞赛、社区、脚本、招聘板
附录。流行的机器学习算法



浙公网安备 33010602011771号