人工智能(AI)超越人类知识的概念通常被称为“技术奇点”。人工智能研究社区以及其他领域的一些预测表明,奇点可能在未来30年内到来。无论其时间节点如何,有一点是明确的:人工智能的崛起凸显了分析能力和机器学习技能的重要性。掌握这些学科不仅让我们能够理解和互动日益复杂的人工智能系统,还能积极参与其发展和应用的塑造,确保它们造福人类。
在本章中,我们将以机器学习的基本概念为起点,开启我们的机器学习之旅。我们将从机器学习的定义、我们为什么需要它以及它在过去几十年中的演变谈起。接着,我们将讨论典型的机器学习任务,并探讨几种基本的技巧,帮助我们处理数据和模型。
在本章的最后,我们将为Python(机器学习和数据科学中最流行的编程语言)安装软件,并配置本书所需的库和工具。
我们将详细讨论以下主题:
- 机器学习简介
- 了解必备知识
- 入门三种类型的机器学习
- 深入了解机器学习的核心
- 数据预处理和特征工程
- 模型融合
- 安装软件和配置环境
机器学习简介
在本节中,我们将通过简要介绍机器学习,探讨我们为什么需要它,它与自动化的区别,以及它如何改善我们的生活,从而开启机器学习之旅。
机器学习这一术语大约在1960年被创造,包含两个词——“机器”(指计算机、机器人或其他设备)和“学习”(指旨在获取或发现事件模式的活动,这正是我们人类擅长的)。有趣的例子包括人脸识别、语言翻译、回复电子邮件、基于数据做出商业决策以及创造各种类型的内容。你将在本书中看到更多类似的例子。
了解为什么我们需要机器学习
我们为什么需要机器学习?为什么我们希望机器能够像人类一样学习?我们可以从三个主要角度来理解:维护、风险缓解和性能提升。
首先,当然,计算机和机器人可以全天候工作,并且不会感到疲倦。机器长期来看成本远低于人工。而且,对于那些涉及庞大数据集或复杂计算的复杂问题,让计算机完成所有工作不仅更具合理性,甚至可以说是智能的。由人类设计的算法驱动的机器能够学习潜在规则和固有模式,从而使它们能够有效地执行任务。
学习型机器比人类更适合处理那些例行、公事、重复或繁琐的任务。除此之外,机器学习的自动化还能够缓解由疲劳或不注意所带来的风险。自动驾驶汽车(如图1.1所示)就是一个很好的例子:它能够通过感知周围环境并做出决策,而无需人工干预。另一个例子是生产线中的机器人臂,它能够显著减少伤害和成本。
假设人类不会感到疲倦,或者我们有足够的资源雇佣足够的轮班工人;机器学习还会有用吗?当然会!有很多已报道和未报道的案例表明,机器在许多任务上能够与领域专家相媲美,甚至表现得更好。由于算法设计的目的是从真实情况和人类专家做出的最佳决策中学习,机器可以像专家一样执行任务。
实际上,即使是最优秀的专家也会犯错误。机器可以通过利用个体专家的集体智慧来最小化错误决策的可能性。一项重要研究表明,机器在诊断某些类型的癌症方面优于医生,这证明了这一理念(www.nature.com/articles/d4…)。AlphaGo(deepmind.com/research/ca…)可能是机器战胜人类最著名的例子——由DeepMind开发的人工智能程序在五局围棋比赛中击败了世界冠军李世石。
此外,从经济和社会障碍的角度来看,部署学习型机器比训练个体成为专家更具可扩展性。目前的诊断设备能够达到类似于合格医生的性能水平。我们可以在一周内将成千上万的诊断设备分布到全球,但几乎不可能在同一时间内招募并分配同样数量的合格医生。
你可能会反驳:如果我们有足够的资源和能力雇佣最优秀的领域专家,并将他们的意见汇总——机器学习还有位置吗?可能没有(至少目前是这样)——学习型机器可能不如最聪明的人类群体的共同努力。但如果个体能够使用学习型机器,他们可能会超过最优秀的专家团队。这是一个新兴的概念,称为基于人工智能的辅助或人工智能加人类智能,它提倡将机器和人类的努力结合起来,提供支持、指导或解决方案给用户。更重要的是,它能够通过与用户的互动来适应并学习,从而随着时间的推移提高表现。
我们可以通过以下不等式总结前述观点: 人类 + 机器学习 → 最聪明、不知疲倦的人类 ≥ 机器学习 > 人类
人工智能生成内容(AIGC)是近期的一个突破。它使用人工智能技术来创建或辅助创作各种类型的内容,如文章、产品描述、音乐、图像和视频。
涉及机器人手术的医疗操作是人类与机器学习协同作用的一个绝佳例子。图1.2展示了手术室内的机器人手臂与外科医生共同工作:
区分机器学习与自动化
那么,机器学习是否仅仅等同于自动化,即涉及编程和执行人类编写或筛选的规则集?一个流行的误解认为,机器学习与自动化是相同的,因为它执行的是指令性和重复性的任务,并且不再深入思考。如果这个问题的答案是肯定的,那为什么我们不能简单地雇佣大量的软件程序员,继续编写新的规则或扩展旧的规则呢?
其中一个原因是,定义、维护和更新规则会随着时间的推移变得越来越昂贵。对于某一活动或事件,可能存在巨大的模式数量,因此,穷举所有可能的情况在实践中是不可行的。尤其是当事件是动态的、不断变化的,或是实时演变时,这种挑战会更大。相比之下,开发能够让计算机学习、从大量数据中提取模式并自行解决问题的学习算法,既更简单又更高效。
机器学习与传统编程的区别可以从图1.3中看出:
在传统编程中,计算机遵循一组预定义的规则来处理输入数据并生成结果。而在机器学习中,计算机试图模仿人类思维。它与输入数据、期望的输出以及环境进行交互,从中推导出由一个或多个数学模型表示的模式。这些模型随后用于与未来的输入数据进行交互并生成结果。在机器学习中,计算机并没有接收到明确的、指令性的编码,这与自动化不同。
数据量正在呈指数级增长。如今,文本、音频、图像和视频数据的涌现难以估量。物联网(IoT)是近年来新兴的一种互联网形式,它将日常设备互联起来。物联网将把家庭电器和自动驾驶汽车等数据推到前台。这一趋势可能会继续下去,我们将拥有更多生成和处理的数据。除了数据量的增加,过去几年中数据的质量也在不断提升,这部分归功于更便宜的存储方式。这为机器学习算法和数据驱动解决方案的发展提供了动力。
机器学习应用
阿里巴巴联合创始人马云在2018年的一次演讲中解释道,信息技术(IT)是过去20年的焦点,但接下来的30年将是数据技术(DT)的时代(www.alizila.com/jack-ma-don…)。在IT时代,企业因计算机软件和基础设施的支持而变得越来越强大。而如今,随着大多数行业的企业已经积累了大量的数据,现在正是利用数据技术挖掘洞察、提取模式并推动新业务增长的最佳时机。广义上讲,机器学习技术使企业能够更好地理解客户行为、与客户互动并优化运营管理。
对于我们个人而言,机器学习技术已经在日常生活中改善了我们的体验。一个我们都熟悉的机器学习应用是垃圾邮件过滤。另一个是在线广告,广告会根据广告商收集的关于我们的信息自动投放。接下来的几章,你将学习如何开发算法来解决这些问题,以及更多应用场景。
搜索引擎是一个我们无法想象没有的机器学习应用。它涉及信息检索,它解析我们搜索的内容,查询相关的顶级记录,并应用上下文排名和个性化排名,根据主题相关性和用户偏好对页面进行排序。电子商务和媒体公司一直在采用推荐系统,这些系统帮助客户更快地找到产品、服务和文章。
机器学习的应用几乎是无限的,我们每天都能听到新的应用例子:信用卡欺诈检测、总统选举预测、即时语音翻译、机器人顾问、AI生成艺术、客户支持聊天机器人,以及由生成式AI技术提供的医疗或法律建议——你能想到的都有!
在1983年的电影《战争游戏》中,一台计算机做出了生死攸关的决策,这些决策可能导致第三次世界大战。尽管当时的技术无法实现这种壮举,但在1997年,超级计算机Deep Blue确实成功击败了世界象棋冠军(en.wikipedia.org/wiki/Deep_B…)。2005年,一辆斯坦福大学的自动驾驶汽车在沙漠中独自行驶超过130英里(ttps://en.wikipedia.org/wiki/DARPA_Grand_Challenge_(2005))。2007年,另一个团队的汽车在常规城市交通中行驶超过60英里en.wikipedia.org/wiki/DARPA_…)。2011年,沃森计算机在与人类对手的问答比赛中获胜(en.wikipedia.org/wiki/Watson…)。如前所述,AlphaGo程序在2016年击败了世界顶级围棋选手之一。到2023年,ChatGPT已被广泛应用于各个行业,如客户支持、内容生成、市场研究以及培训和教育(www.forbes.com/sites/berna…)。
如果我们假设计算机硬件是限制因素,那么我们可以尝试推测未来。著名的美国发明家和未来学家雷·库兹韦尔(Ray Kurzweil)便做了这样的推测,他在2017年预测,人工智能将在2029年左右达到人类水平的智能(aibusiness.com/responsible…)。接下来会是什么?
迫不及待想要开启你的机器学习之旅吗?让我们从前置知识和机器学习的基本类型开始。
知道前置知识
机器学习模仿人类智能,是人工智能(AI)的一个子领域,人工智能是计算机科学的一个领域,旨在创建智能系统。软件工程是计算机科学的另一个领域。一般来说,我们可以把Python编程视为软件工程的一种。机器学习与线性代数、概率论、统计学和数学优化密切相关。我们通常根据统计学、概率论和线性代数来构建机器学习模型,然后使用数学优化来优化这些模型。
阅读本书的你们大多数应该已经具备了较好(或至少足够的)Python编程能力。那些在数学知识方面不太自信的读者可能会好奇,需要花多少时间来学习或复习上述学科的内容。别担心,本书将帮助你在不涉及深奥数学细节的情况下让机器学习为我们服务。它只需要一些基本的概率论和线性代数知识,帮助我们理解机器学习技术和算法的原理。而且这会变得更简单,因为我们将从零开始构建模型,并使用我们熟悉的Python语言和流行的Python包。
对于那些希望学习或复习概率论和线性代数的人,可以查找一些基础的概率论和线性代数资料。网上有很多资源,例如概率论入门资料(people.ucsc.edu/~abrsvn/int…)、哈佛大学的《概率论导论》在线课程(pll.harvard.edu/course/intr…)以及基础线性代数的相关论文:www.maths.gla.ac.uk/~ajb/dvi-ps…。
如果你希望系统学习机器学习,可以报名参加计算机科学、人工智能(AI)以及近年来的数据科学和AI硕士课程。也有很多数据科学训练营。需要注意的是,训练营的选拔通常更为严格,因为它们更偏向于就业导向,且课程时长通常较短,通常在4到10周之间。另一个选择是免费的MOOC(大规模开放在线课程),例如安德鲁·吴(Andrew Ng)教授的流行机器学习课程。最后,行业博客和网站也是我们保持对最新发展了解的重要资源。
机器学习不仅是一项技能,还是一项“运动”。我们可以参加多个机器学习竞赛,例如Kaggle(<www.kaggle.com>),有时是为了赢得丰厚的奖金,有时是为了乐趣,但大多数时候是发挥我们的优势。然而,要赢得这些竞赛,我们可能需要使用某些技术,这些技术仅在竞赛的背景下有用,而不一定适用于解决业务问题。没错——“没有免费午餐定理”(en.wikipedia.org/wiki/No_fre…)在这里也适用。在机器学习的背景下,这一定理表明,没有一个算法能够在所有可能的数据集和问题领域中普遍优于其他算法。
接下来,我们将介绍三种类型的机器学习。
开始了解三种类型的机器学习
机器学习系统通过输入数据进行训练——这些数据可以是数值型、文本型、视觉型或视听型。系统通常会产生输出——例如,可以是一个浮动的小数,如自动驾驶汽车的加速度,或是一个表示类别的整数(也称为类),例如图像识别中的“猫”或“老虎”。
机器学习的主要任务是探索和构建能够从历史数据中学习并对新的输入数据进行预测的算法。对于数据驱动的解决方案,我们需要定义(或通过算法定义)一个评估函数,称为损失函数或成本函数,用于衡量模型学习的效果。在这种设置下,我们创造了一个优化问题,目标是最有效和最有效地进行学习。
根据学习数据的性质,机器学习任务大致可以分为以下三类:
无监督学习
当学习数据仅包含指示信号,而没有任何附加的描述信息(我们称之为无标签数据)时,我们需要自己去发现数据下的结构,揭示隐藏的信息,或决定如何描述数据。无监督学习可以用来检测异常,如欺诈或设备故障,或将具有相似在线行为的客户分组进行营销活动。使数据更易理解的数据可视化以及通过降维从噪声数据中提炼出相关信息的技术,亦属于无监督学习的一类。
监督学习
当学习数据除了指示信号之外,还带有描述、目标或期望的输出(我们称之为带标签数据)时,学习的目标是找到一个通用规则,将输入映射到输出。学习到的规则然后用于为新的数据打上标签,这些数据的输出是未知的。标签通常由事件日志系统提供,或由人类专家进行评估。如果可行,标签也可以通过人工评分、众包等方式生成。
监督学习广泛应用于日常应用中,如人脸和语音识别、产品或电影推荐、销售预测以及垃圾邮件检测。
强化学习
学习数据提供反馈,使得系统能够根据动态条件进行调整,以最终达到某个目标。系统根据反馈评估其表现,并做出相应的反应。最著名的实例包括工业自动化中的机器人、自驾车以及棋类大师AlphaGo。强化学习和监督学习的主要区别在于与环境的交互。
下图展示了机器学习任务的类型:
如图所示,我们可以进一步将监督学习细分为回归和分类。回归用于训练和预测连续值响应,例如预测房价;而分类则试图找出合适的类别标签,比如分析正面/负面情绪或预测贷款违约。
如果并非所有学习样本都有标签,而只有部分样本有标签,那么我们就有了半监督学习。半监督学习利用无标签数据(通常是大量数据)进行训练,同时使用少量的标签数据。半监督学习适用于获取完全标记数据集成本高昂且标记一小部分数据更实际的情况。例如,标记高光谱遥感图像通常需要专家进行,而获取无标签数据则相对容易。
对这些抽象的概念感到有点困惑吗?不用担心。在本书后续章节中,我们将遇到许多具体的机器学习任务示例。例如,在第二章《使用朴素贝叶斯构建电影推荐引擎》中,我们将深入探讨监督学习中的分类任务及其流行的算法和应用。类似地,在第五章《使用回归算法预测股市价格》中,我们将探讨监督学习中的回归任务。
我们将在第八章《使用聚类和主题建模发现新闻组数据集中的潜在主题》中重点讲解无监督技术和算法。最后,第三类机器学习任务——强化学习,将在第十五章《在复杂环境中通过强化学习做出决策》中讨论。
除了基于学习任务对机器学习进行分类外,我们还可以按时间顺序对其进行分类。
机器学习算法的发展简史
事实上,我们有一整套机器学习算法,它们在时间的推移中经历了不同的流行程度。我们可以大致将这些算法分为五种主要的方法:基于逻辑的学习、统计学习、人工神经网络、遗传算法和深度学习。
基于逻辑的系统曾是最早的主流方法。它们使用由人工专家指定的基本规则,并通过这些规则,系统试图利用形式逻辑、背景知识和假设进行推理。
统计学习理论试图找到一个函数,以形式化变量之间的关系。在1980年代中期,人工神经网络(ANNs)开始崭露头角。人工神经网络模仿动物大脑,由互相连接的神经元组成,这些神经元也是生物神经元的模仿。它们试图建模输入与输出值之间的复杂关系,并捕捉数据中的模式。到1990年代,人工神经网络被统计学习系统所取代。
遗传算法(GA)在1990年代很受欢迎。它们模仿生物进化过程,试图通过突变和交叉等方法找到最优解。
到了2000年代,集成学习方法开始受到关注,它将多个模型结合起来,以提高性能。
自2010年代末以来,深度学习成为主流。深度学习这个术语大约在2006年提出,指的是具有多层结构的深度神经网络。深度学习的突破源自图形处理单元(GPU)的整合和利用,GPU大幅加速了计算过程。大数据集的可用性也推动了深度学习的革命。
GPU最初是为渲染视频游戏而开发的,它们在并行矩阵和向量代数方面非常高效。人们认为深度学习与人类学习的方式相似,因此它可能实现智能机器的承诺。当然,在本书中,我们将在第6章《使用人工神经网络预测股市价格》之后,深入探讨深度学习,分别在第11章《使用卷积神经网络对服装图像进行分类》和第12章《使用循环神经网络进行序列预测》中进一步展开。
机器学习算法仍在快速发展,当前的研究领域包括迁移学习、生成模型和强化学习,这些都是人工智能生成内容(AIGC)的核心技术。我们将在第13章《利用Transformer模型推动语言理解与生成》和第14章《使用CLIP构建图像搜索引擎:一种多模态方法》中,探索这些最新进展。
有些人可能听说过摩尔定律——这是一个经验性观察,声称计算机硬件随时间呈指数级改进。该定律由英特尔的共同创始人戈登·摩尔于1965年提出。根据定律,芯片上的晶体管数量每两年应当翻一番。在下图中,我们可以看到该定律依然有效(气泡的大小对应于GPU中晶体管的平均数量):
共识似乎认为,摩尔定律在接下来的几十年内仍然有效。这为雷·库兹韦尔(Ray Kurzweil)预测的2029年实现真正机器智能的观点提供了一定的可信度。
深入挖掘机器学习的核心
在讨论完机器学习算法的分类后,我们现在将深入探讨机器学习的核心——如何用数据进行泛化、不同级别的泛化,以及如何达到正确的泛化水平。
用数据进行泛化
数据的好处在于,世界上有大量数据。坏处在于,处理这些数据非常困难。挑战来源于数据的多样性和噪声。我们人类通常通过耳朵和眼睛来处理数据。这些输入会转化为电信号或化学信号。在最基本的层面上,计算机和机器人也在处理电信号。
这些电信号随后被转换为1和0。然而,在本书中,我们使用Python编程,在这一层面上,通常我们用数字或文本来表示数据。然而,文本并不太方便,因此我们需要将其转换为数值。
特别是在监督学习的背景下,我们有一个类似于备考的场景。我们有一组练习题和实际的考试题。我们应该能够在没有提前接触过相同题目的情况下回答考试问题。这就是所谓的泛化——我们从练习题中学到了一些东西,希望能够将这些知识应用到其他类似的问题上。在机器学习中,这些练习题被称为训练集或训练样本。这是机器学习模型从中推导模式的地方。而实际的考试则是测试集或测试样本。它们是模型最终应用的地方。学习的有效性通过学习模型与测试的契合度来衡量。
有时,在练习题和实际考试之间,我们有模拟考试来评估我们在实际考试中的表现,并帮助我们复习。这些模拟考试在机器学习中被称为验证集或验证样本。它们帮助我们验证模型在模拟环境中的表现,然后我们根据结果对模型进行微调,以便提高准确性。
一个老派的程序员可能会与业务分析师或其他专家交谈,然后实现一个添加某个值乘以另一个相应值的税收规则,例如。在机器学习环境中,我们可以给计算机一堆输入和输出示例;或者,如果我们想更有雄心壮志,我们可以将实际的税收文本输入给程序。我们可以让机器处理这些数据并找出税收规则,就像自动驾驶汽车不需要大量的明确人工输入一样。
在物理学中,我们几乎面临着同样的情况。我们想知道宇宙是如何运作的,并用数学语言制定定律。由于我们不知道它是如何运作的,我们所能做的就是衡量我们在尝试制定定律时产生的误差,并尽量减少它。在监督学习任务中,我们将我们的结果与预期值进行比较。在无监督学习中,我们通过相关的度量来衡量我们的成功。例如,我们希望数据点根据相似性分组,形成簇;度量可以是同一簇内的数据点有多相似,或者两个簇之间的数据点有多不同。在强化学习中,程序评估其行为,例如,在象棋游戏中使用预定义的函数来评估每一步。
除了正确的泛化之外,还有两个泛化的层次,过拟合和欠拟合,我们将在下一节深入探讨。
过拟合、欠拟合与偏差-方差权衡
在本节中,我们将详细探讨两个泛化层次,并深入分析偏差-方差权衡。
过拟合
达到正确拟合模型是机器学习任务的目标。那么,如果模型发生了过拟合会怎样呢?过拟合意味着模型对现有数据的拟合过于精确,但无法预测未来的新数据。我们可以通过以下类比来理解这一点。
如果我们在备考时做了许多练习题,可能会开始找到一些与学科内容无关的答题方法。例如,假设我们只有五道练习题,我们可能发现如果在一个选择题中,出现两次土豆、一次番茄、三次香蕉,那么答案总是A;如果题中出现一次土豆、三次番茄、两次香蕉,那么答案总是B。我们可能得出结论,认为这是普遍适用的规律,并在以后的考试中应用这一理论,尽管这个理论与土豆、番茄或香蕉无关。更糟糕的是,我们可能会死记硬背每一道题的答案。这样,我们在练习题上得分很高,认为实际考试的题目会和练习题一样。但实际上,我们在考试中得分会非常低,因为考试题目不可能和练习题完全一样。
这种死记硬背现象会导致过拟合。当我们从训练集中提取了过多信息,并使模型仅对这些训练数据表现良好时,就会发生过拟合。然而,过拟合并不能帮助我们将模型泛化到新数据上,或从新数据中提取真实的模式。因此,模型在未见过的数据集上表现会很差。我们将这种情况称为“高方差”问题。在机器学习中,方差衡量的是预测的分散程度,即预测结果的变化性。它可以通过以下公式计算:
这里,ŷ 是预测值,E[] 是期望值,表示基于其概率分布的随机变量的平均值,通常用于统计学中的期望计算。
以下示例展示了过拟合的典型实例,其中回归曲线试图完美地拟合所有观察到的样本:
过拟合发生在我们试图根据过多的参数来描述学习规则,而这些参数相对于观察样本的数量来说过于庞大,而不是基于潜在的关系。例如,在前面的土豆、番茄和香蕉的例子中,我们从仅有的五个学习样本中推导出三个参数。过拟合还发生在我们将模型变得过于复杂,以至于它能够完美拟合每一个训练样本,例如之前提到的记住所有问题的答案。
欠拟合
与过拟合相反的是欠拟合。当模型发生欠拟合时,它在训练集上的表现不佳,也不会在测试集上取得好成绩,这意味着它未能捕捉到数据的潜在趋势。欠拟合可能发生在我们没有使用足够的数据来训练模型时,就像我们如果没有复习足够的材料就会考砸一样;也可能发生在我们尝试使用错误的模型来拟合数据时,就像如果我们采取错误的学习方法和方式,就会在任何练习或考试中得分很低。我们将这些情况描述为机器学习中的高偏差(high bias),尽管它的方差较低,因为在训练集和测试集上的表现一致,虽然这种一致性是糟糕的。如果你需要快速回顾偏差,它是指平均预测值与真实值之间的差异。计算公式如下:
这里,ŷ 是预测值,y 是真实值。
以下示例展示了典型的欠拟合情况,其中回归曲线无法很好地拟合数据,或者未能捕捉到数据的潜在模式:
现在,让我们看看一个合适拟合的例子应该是什么样子:
偏差-方差权衡
显然,我们希望避免过拟合和欠拟合。回想一下,偏差是由于学习算法中的不正确假设导致的误差;高偏差会导致欠拟合。方差衡量的是模型预测对数据集变化的敏感度。因此,我们需要避免偏差或方差过高的情况。那么,是否意味着我们应该始终将偏差和方差尽可能地降低?答案是:如果可以的话,确实如此。但实际上,偏差和方差之间存在明确的权衡,即减少一个会增加另一个。这就是所谓的偏差-方差权衡。听起来有点抽象?让我们看一个具体的例子。
假设我们被要求建立一个模型,根据电话民调数据预测某个候选人是否会成为美国下任总统。该民调是基于邮政编码进行的。我们随机选择了来自某个邮政编码的样本,并估计该候选人获胜的几率为61%。然而,结果证明该候选人输掉了选举。我们的模型哪里出错了?我们首先可能会想到,仅仅使用一个邮政编码的样本数量太少。这也是一个高偏差的来源,因为一个地区的人群往往有相似的人口统计特征,尽管这会导致估计值的方差较低。那么,我们可以通过使用来自更多邮政编码的样本来修复这个问题吗?是的,但不要太高兴。这可能会同时导致估计值方差的增加。我们需要找到一个最佳的样本量——最佳的邮政编码数量,以实现最低的总偏差和方差。
要最小化模型的总误差,就需要仔细平衡偏差和方差。给定一组训练样本 x1,x2,…,xn 及其目标 我们希望找到一个回归函数 使其尽可能准确地估计真实关系 y(x)。我们用均方误差(MSE)来衡量估计误差,即回归模型的好坏:
这里的 E 表示期望。这个误差可以根据分析推导分解为偏差和方差成分,如下式所示(尽管理解这个公式需要一些基础的概率理论):
术语 Bias(偏差)衡量的是估计的误差,而术语 Variance(方差)描述了估计值 y^ 围绕其均值 E[y^] 的波动情况。学习模型 y^(x)越复杂,且训练样本的大小越大,偏差通常会越小。然而,这也会导致更多的模型调整,以更好地拟合增加的数据点,从而导致方差增大。
我们通常采用交叉验证技术、正则化和特征降维来找到一个平衡偏差和方差的最佳模型,从而减少过拟合。我们将在接下来讨论这些方法。
你可能会问,为什么我们只关注过拟合:那还会有欠拟合的问题吗?这是因为欠拟合很容易识别:如果一个模型在训练集上表现不佳,就说明出现了欠拟合。此时,我们需要找到一个更好的模型,或调整一些参数以更好地拟合数据,这在任何情况下都是必要的。另一方面,过拟合则难以察觉。通常,当我们在训练集上获得一个表现良好的模型时,我们会过于高兴,并认为它已经可以投入生产。这是非常危险的。相反,我们应该采取额外措施,确保出色的表现不是由于过拟合,并且该表现适用于排除训练数据之外的数据。
避免过拟合的交叉验证
你将在本书后面的章节多次看到交叉验证的应用。所以,如果你觉得这一节有些难以理解,不用担心,随着阅读的深入,你很快就会成为交叉验证的专家。
回想一下,在练习题和实际考试之间,我们有模拟考试,通过模拟考试来评估我们在实际考试中的表现,并根据评估结果进行必要的复习。在机器学习中,验证过程有助于评估模型在独立或未见数据集上的泛化能力,模拟测试其性能。在传统的验证设置中,原始数据会被分成三个子集,通常是 60% 用于训练集,20% 用于验证集,剩下的 20% 用于测试集。对于有足够训练样本的数据集来说,这种分割方式通常可以提供粗略的模拟性能估计。然而,如果训练样本较少,交叉验证会更为理想。交叉验证有助于减少模型的变异性,从而限制过拟合。
在一次交叉验证中,原始数据被分成两个子集,一个用于训练,另一个用于测试(或验证)。记录下测试结果。类似地,在不同的数据划分下,进行多轮交叉验证。所有轮次的测试结果最终被平均,以产生更可靠的模型预测性能估计。
当训练集非常大时,通常只需将数据分为训练集、验证集和测试集(三个子集),然后在后两者上进行性能检查。此时交叉验证的使用价值较低,因为每一轮都需要训练模型,计算开销较大。但如果条件允许,使用交叉验证没有问题。当数据集较小的时候,交叉验证绝对是一个不错的选择。
目前常用的交叉验证方案主要有两种:穷举式交叉验证和非穷举式交叉验证。在穷举式交叉验证中,每一轮都会固定排除一部分观察数据作为测试(或验证)样本,剩余的数据作为训练样本。这个过程会一直重复,直到所有可能的不同样本子集都被用作一次测试。例如,我们可以应用 留一法交叉验证(LOOCV) ,让每个样本都有一次作为测试集的机会。对于大小为 n 的数据集,LOOCV 需要进行 n 轮交叉验证。当 n 较大时,LOOCV 的计算速度较慢。下图展示了 LOOCV 的工作流程:
非穷举式交叉验证,如其名称所示,并不会尝试所有可能的划分。最常用的非穷举式交叉验证方案是 k折交叉验证。首先,我们将原始数据随机分成 kkk 个相同大小的子集。在每次试验中,选取其中一个子集作为测试集,其余数据作为训练集。
我们重复这一过程 k次,每次不同的子集作为测试集。最终,我们将 k次测试结果的平均值作为模型的评估指标。常见的 k 值为 3、5 和 10。以下表格展示了五折交叉验证的设置:
| 回合 | 子集 1 | 子集 2 | 子集 3 | 子集 4 | 子集 5 |
|---|---|---|---|---|---|
| 1 | 测试集 | 训练集 | 训练集 | 训练集 | 训练集 |
| 2 | 训练集 | 测试集 | 训练集 | 训练集 | 训练集 |
| 3 | 训练集 | 训练集 | 测试集 | 训练集 | 训练集 |
| 4 | 训练集 | 训练集 | 训练集 | 测试集 | 训练集 |
| 5 | 训练集 | 训练集 | 训练集 | 训练集 | 测试集 |
表 1.1: 五折交叉验证的设置
与 LOOCV(留一法交叉验证)相比,k折交叉验证通常具有较低的方差,因为我们使用的是一组样本而不是单个样本进行验证。
我们还可以多次随机将数据分为训练集和测试集。这种方法被称为 留出法。该方法的问题在于,有些样本可能永远不会被选中作为测试集,而有些样本可能会在多个测试集中出现。
最后但同样重要的是,嵌套交叉验证 是一种交叉验证的组合。它包括以下两个阶段:
- 内部交叉验证:此阶段用于找到最佳拟合模型,通常采用 k折交叉验证来实现。
- 外部交叉验证:此阶段用于模型性能评估和统计分析。
在本书中,我们将广泛应用交叉验证。在此之前,我们先通过一个类比来帮助更好地理解交叉验证。
假设一位数据科学家计划每天开车去上班,并且他的目标是在早上9点前到达公司。他需要决定出发时间和行驶路线。他在某些周一、周二和周三试验了不同的时间和路线组合,并记录了每次试验的到达时间。然后,他根据这些记录找到了最佳的时间安排,并计划每天都应用它。然而,实际效果并不像预期那样好。
原来,调度模型对前几天收集的数据点过度拟合,可能在周四和周五的效果不佳。一个更好的解决方案是,将从周一到周三得到的最佳时间组合在周四和周五进行测试,并根据不同的学习天和测试天组合重复这个过程。这个类比的交叉验证确保了所选的调度方案可以在一整周内都有效。
交叉验证通过结合不同数据子集上的预测表现来获得更准确的模型评估。该技术不仅可以减少方差、避免过拟合,还能提供对模型在实际情况中表现的洞察。
通过正则化避免过拟合
避免过拟合的另一种方法是 正则化。回想一下,模型的不必要复杂性是过拟合的一个来源。正则化通过在我们试图最小化的误差函数中加入额外的参数,从而对复杂模型进行惩罚。
根据奥卡姆剃刀原理,应该偏好简单的方法。威廉·奥卡姆是位于1320年左右的修道士和哲学家,他提出了一个观点:应该偏好那些最简单的能够拟合数据的假设。其理由之一是,简单模型的选择范围比复杂模型要少。例如,直觉上我们知道,高次多项式模型比线性模型多得多。原因在于,一条直线(y=ax+by = ax + by=ax+b)只有两个参数——截距 b和斜率 a,它们的系数在二维空间内变化。而一个二次多项式则为二次项增加了一个额外的系数,我们可以通过这些系数来描述三维空间。因此,使用高阶多项式函数来完美拟合所有训练数据点是非常容易的,因为它的搜索空间要比线性函数大得多。然而,这些轻松获得的模型通常比线性模型更难以推广(即泛化能力差),并且更容易导致过拟合。当然,更简单的模型计算时间也较少。
以下图展示了我们如何分别用线性函数和高阶多项式函数来拟合数据:
线性模型更为优选,因为它可能更好地泛化到从潜在分布中抽取的更多数据点。我们可以通过正则化来减少高阶多项式的影响,方法是在它们上加以惩罚。尽管这样会从训练数据中学习到一个不太精确且不那么严格的规则,但它会抑制模型的复杂性。
在本书中,我们将频繁使用正则化,从第4章《使用逻辑回归预测在线广告点击率》开始。现在,我们通过一个类比来帮助你更好地理解正则化。
一个数据科学家希望为他的机器人守卫犬装备识别陌生人和朋友的能力。他给它提供了以下学习样本:
| 性别 | 年龄 | 身高 | 是否戴眼镜 | 穿着 | 标签 |
|---|---|---|---|---|---|
| 男性 | 年轻 | 高 | 戴眼镜 | 灰色 | 朋友 |
| 女性 | 中年 | 一般 | 不戴眼镜 | 黑色 | 陌生人 |
| 男性 | 年轻 | 矮 | 戴眼镜 | 白色 | 朋友 |
| 男性 | 年长 | 矮 | 不戴眼镜 | 黑色 | 陌生人 |
| 女性 | 年轻 | 一般 | 戴眼镜 | 白色 | 朋友 |
| 男性 | 年轻 | 矮 | 不戴眼镜 | 红色 | 朋友 |
机器人可能会很快学习到以下规则:
- 任何中年女性,身高一般,不戴眼镜,穿黑色衣服的都是陌生人。
- 任何年长、矮个子、不戴眼镜、穿黑色衣服的男性都是陌生人。
- 其他任何人都是朋友。
尽管这些规则完美地拟合了训练数据,但它们看起来过于复杂,并且不太可能很好地泛化到新来的访客身上。与此相反,数据科学家限制了学习的复杂度。一条较松的规则,如下所示,可能对其他许多访客都适用:任何不戴眼镜且穿黑色衣服的人都是陌生人。
除了惩罚复杂度外,我们还可以通过早停(early stopping)技术来防止过拟合。如果我们限制模型的学习时间或设定一些内部停止标准,它更可能产生一个较简单的模型。通过这种方式,模型的复杂度会得到控制,从而降低过拟合的概率。这种方法在机器学习中被称为 早停。
最后,值得注意的是,正则化应保持在适中的水平,或者更准确地说,应该调整到最优水平。如果正则化过小,几乎没有任何影响;如果正则化过大,则会导致欠拟合,因为它会让模型偏离真实的规律。我们将在第4章《使用逻辑回归预测在线广告点击率》、第5章《使用回归算法预测股票价格》和第6章《使用人工神经网络预测股票价格》中探讨如何实现最优正则化。
通过特征选择和降维避免过拟合
我们通常将数据表示为一个数字网格(矩阵)。每一列代表一个变量,我们在机器学习中称之为特征。在监督学习中,其中一个变量实际上并不是特征,而是我们要预测的标签。在监督学习中,每一行代表一个示例,用于训练或测试。
特征的数量对应数据的维度。我们的机器学习方法取决于维度的数量与示例数量的关系。例如,文本和图像数据具有非常高的维度,而传感器数据(如温度、压力或GPS数据)则具有相对较少的维度。
拟合高维数据在计算上非常昂贵且容易过拟合,因为其复杂度较高。高维数据也无法进行可视化,因此我们无法使用简单的诊断方法。
并非所有特征都有用,它们可能只是增加了结果的随机性。因此,进行良好的特征选择通常是很重要的。特征选择是从中选择一组重要特征的过程,以便用于更好的模型构建。实际上,数据集中的每个特征并不都携带有助于区分样本的信息;一些特征可能是冗余的或无关的,因此可以在损失很小的情况下舍弃。
原则上,特征选择归结为关于是否包括某个特征的多个二进制决策。对于n个特征,我们有2^n个特征集,对于特征较多的情况,这个数字可能非常庞大。例如,10个特征时,我们就有1,024个可能的特征集(例如,如果我们在决定穿什么衣服,特征可以是温度、是否下雨、天气预报以及我们要去哪里)。基本上,我们有两种选择:要么从所有特征开始,逐步移除特征;要么从最小的特征集开始,逐步增加特征。然后我们在每次迭代中选择最好的特征集并进行比较。在某个时候,暴力求解变得不可行。因此,出现了更先进的特征选择算法,用于提取最有用的特征/信号。我们将在第4章《使用逻辑回归预测在线广告点击率》中详细讨论如何进行特征选择。
减少数据维度的另一种常见方法是将高维数据转换到低维空间。这被称为降维或特征投影。我们将在第7章《使用文本分析技术挖掘20 Newsgroups数据集》中详细讨论这个问题,在那一章中,我们将把文本数据编码为二维数据;在第9章《使用支持向量机识别人脸》中,我们将讨论如何将高维图像数据投影到低维空间。
在本节中,我们讨论了机器学习的目标是找到数据的最优泛化,并且如何避免不良泛化。在接下来的两个部分中,我们将探索在机器学习的不同阶段实现目标的技巧,包括接下来的数据预处理和特征工程部分,以及之后的建模部分。
数据预处理与特征工程
数据预处理和特征工程在机器学习中扮演着至关重要和基础的角色。这就像为建筑打下基础——基础越强大、准备得越充分,最终的结构(机器学习模型)就会越好。以下是它们之间关系的具体说明:
- 预处理为高效学习准备数据:来自不同来源的原始数据通常包含不一致性、错误和无关信息。预处理通过清理、整理和转换数据,将其转化为适合所选机器学习算法的格式。这使得算法能够更容易、更高效地理解数据,从而提高模型性能。
- 预处理有助于提高模型的准确性和泛化能力:通过处理缺失值、异常值和不一致性,预处理减少了数据中的噪声。这使得模型能够专注于数据中的真实模式和关系,从而提高预测的准确性,并在未见数据上更好地泛化。
- 特征工程提供有意义的输入变量:原始数据经过转化和处理,生成新的特征或选择相关特征。新特征可能会提升模型性能并带来新的洞察。
总的来说,数据预处理和特征工程是机器学习工作流中至关重要的一步。通过投入时间和精力进行适当的预处理和特征工程,你为构建可靠、准确和具有良好泛化能力的机器学习模型奠定了基础。在本节中,我们将首先讨论预处理阶段。
预处理与探索
在学习时,我们需要高质量的学习材料。我们无法从胡言乱语中学习,因此我们会自动忽略任何没有意义的内容。机器学习系统则无法识别胡言乱语,因此我们需要通过清理输入数据来帮助它。人们常说,清理数据是机器学习中的重要部分。有时清理工作已经为我们完成,但你不应完全依赖这一点。
为了决定如何清理数据,我们需要熟悉它。有一些项目尝试自动探索数据并做一些智能处理,比如生成报告。但遗憾的是,目前我们还没有一个通用的解决方案,因此你需要亲自处理数据。
我们可以做两件事,这两者并不相互排斥:首先,扫描数据;其次,可视化数据。这还取决于我们所处理的数据类型——是数字网格、图像、音频、文本,还是其他类型的数据。
最终,数字网格是最方便的形式,我们将始终朝着拥有数值特征的方向努力。让我们假设在接下来的部分中,我们拥有一张数字表格。
我们希望了解特征是否有缺失值,值的分布情况,以及特征的类型。值大致上可以遵循正态分布、二项分布、泊松分布或其他完全不同的分布。特征可以是二元的:比如是/否、正/负等。它们也可以是类别型的:属于某一类别,例如洲(非洲、亚洲、欧洲、南美洲、北美洲等)。类别型变量也可以是有序的,例如高、中、低。特征还可以是定量型的,例如温度(摄氏度)或价格(美元)。现在,让我们深入探讨如何应对每种情况。
处理缺失值
在很多情况下,某些特征会缺失值。这可能是由多种原因引起的。获取每个特征的值可能是不方便、昂贵,甚至是不可能的。也许我们过去无法测量某些量,因为我们没有合适的设备,或者我们根本不知道这个特征是相关的。然而,我们不得不面对过去缺失的值。
有时候,很容易就能发现缺失值,我们可以通过扫描数据或计算某个特征的值的数量,然后将其与我们期望的数量进行比较(基于行数)来发现这一点。某些系统会用例如 999,999 或 -1 这样的值来编码缺失值。如果有效值远小于 999,999,这样的做法是有意义的。如果你很幸运,可能会有创建数据的人提供的特征信息,通常以数据字典或元数据的形式。
一旦我们知道数据中缺失了值,问题就变成了如何处理这些缺失值。最简单的解决办法是忽略它们。然而,一些算法无法处理缺失值,程序会直接停止运行。在其他情况下,忽略缺失值可能导致不准确的结果。第二个解决方法是用固定值来替代缺失值——这称为插补(imputation)。我们可以用某个特征的有效值的算术平均值、中位数或众数来插补。理想情况下,我们应该有一些可靠的先验知识。例如,我们可能知道某个地点的季节性温度平均值,并能根据日期来推测缺失的温度值。我们将在第10章《机器学习最佳实践》中详细讨论如何处理缺失数据。同样,接下来的技术将在后续章节中进行讨论和应用,万一你对它们如何使用感到不确定。
标签编码
人类能够处理各种类型的值。然而,机器学习算法(有些例外)通常需要数值型值。如果我们提供一个字符串,例如“Ivan”,除非使用特殊的软件,否则程序不知道如何处理它。在这个例子中,我们正在处理一个类别型特征——很可能是名字。我们可以将每个唯一值视为一个标签。(在这个特定的例子中,我们还需要决定如何处理大小写——“Ivan”和“ivan”是一样的吗?)然后,我们可以用一个整数来替换每个标签——这就是标签编码(Label Encoding)。
以下示例展示了标签编码是如何工作的:
| 标签 | 编码后的标签 |
|---|---|
| Africa | 1 |
| Asia | 2 |
| Europe | 3 |
| South America | 4 |
| North America | 5 |
| Other | 6 |
表1.3:标签编码示例
这种方法在某些情况下可能会出现问题,因为学习器可能会得出一个顺序(除非这是预期的,例如 bad=0, ok=1, good=2, excellent=3)。在上面的映射表中,亚洲和北美洲在编码后相差 4,这有些反直觉,因为它们很难量化。接下来的“一热编码”(One-Hot Encoding)将采用一种替代方法来处理这个问题。
一热编码(One-hot Encoding)
一热编码(也叫“一对K编码”)使用虚拟变量来编码类别特征。最初,它被应用于数字电路中。这些虚拟变量具有二进制值(类似于位),因此它们的值为零或一(相当于真假值)。例如,如果我们想要对大陆进行编码,我们会创建虚拟变量,例如 is_asia,如果大陆是亚洲,则该变量为真(1),否则为假(0)。通常,我们需要的虚拟变量数量等于唯一值的数量减去一(或有时是唯一值的确切数量)。因为虚拟变量是互斥的,我们可以通过这些虚拟变量自动确定一个标签。
如果所有虚拟变量的值都是假(0),那么正确的标签就是没有虚拟变量对应的标签。以下表格展示了大陆的编码方式:
| 大陆 | Is_africa | Is_asia | Is_europe | Is_sam | Is_nam |
|---|---|---|---|---|---|
| Africa | 1 | 0 | 0 | 0 | 0 |
| Asia | 0 | 1 | 0 | 0 | 0 |
| Europe | 0 | 0 | 1 | 0 | 0 |
| South America | 0 | 0 | 0 | 1 | 0 |
| North America | 0 | 0 | 0 | 0 | 1 |
| Other | 0 | 0 | 0 | 0 | 0 |
表 1.4:一热编码示例
这种编码方式会生成一个矩阵(数字网格),矩阵中有许多零(假值)和偶尔的一个(真值)。这种类型的矩阵被称为稀疏矩阵(Sparse Matrix)。稀疏矩阵表示法通过 scipy 包得到了很好的处理,我们将在本章稍后讨论。
密集嵌入(Dense Embedding)
虽然一热编码是类别特征的简单且稀疏的表示方式,密集嵌入提供了一种紧凑的连续表示,可以基于数据中的共现模式捕捉语义关系。例如,使用密集嵌入,大陆类别可能被表示为 3 维的连续向量,如下所示:
- Africa: [0.9, -0.2, 0.5]
- Asia: [-0.1, 0.8, 0.6]
- Europe: [0.6, 0.3, -0.7]
- South America: [0.5, 0.2, 0.1]
- North America: [0.4, 0.3, 0.2]
- Other: [-0.8, -0.5, 0.4]
在这个例子中,你可能会注意到南美洲和北美洲的向量比非洲和亚洲的向量更接近。密集嵌入能够捕捉类别之间的相似性。在另一个例子中,你可能会发现欧洲和北美的向量更接近,这反映了它们在文化上的相似性。
我们将在第七章《使用文本分析技术挖掘20个新闻组数据集》中进一步探讨密集嵌入。
特征缩放(Scaling)
不同特征的值可能相差几个数量级。有时,这意味着较大的值会主导较小的值。具体情况取决于我们使用的算法。为了使某些算法正常工作,我们需要对数据进行缩放。
我们可以应用以下几种常见的策略:
- 标准化(Standardization) :去除特征的均值,并除以标准差。如果特征值呈正态分布,我们会得到一个均值为零、方差为一的高斯分布。
- 如果特征值不是正态分布,我们可以去除中位数并除以四分位距(Interquartile Range)。四分位距是第一四分位数和第三四分位数之间的范围(即 25% 和 75% 分位数)。
- 一个常见的选择是将特征缩放到零到一之间的范围。
我们将在本书的多个项目中使用特征缩放。
数据预处理的高级版本通常被称为特征工程。我们将在接下来的章节中讨论这一主题。
特征工程(Feature Engineering)
特征工程是创造或改进特征的过程。特征通常是基于常识、领域知识或先前经验创建的。创建特征有一些常见的技术方法,但并不能保证创建新的特征会改善结果。有时,我们能够利用无监督学习发现的聚类作为额外的特征。深度神经网络通常可以自动提取特征。
我们将简要介绍几种特征工程技术:多项式变换和分箱。
多项式变换(Polynomial Transformation)
如果我们有两个特征 a 和 b,我们可能会怀疑它们之间存在多项式关系,例如 a² + ab + b²。我们可以将 a 和 b 的交互作用视为一个新的特征,比如它们的乘积 ab。交互作用不一定是乘积——尽管这是最常见的选择——它还可以是和、差或比值。如果我们使用比值来避免除以零的情况,我们应该在除数和被除数中加入一个小常数。
多项式关系的特征数量和多项式的阶数没有严格限制。然而,如果我们遵循奥卡姆剃刀原理(Occam’s Razor),我们应该避免使用高阶多项式和多个特征的交互作用。在实际应用中,复杂的多项式关系往往计算复杂,并且容易导致过拟合,但如果你确实需要更好的结果,这些关系可能值得考虑。我们将在第10章《机器学习最佳实践》中,通过实践示例“没有领域专业知识的特征工程”来演示多项式变换。
分箱(Binning)
有时,将特征值分成几个箱子(bin)是很有用的。例如,我们可能只关心某天是否下雨。给定降水量数据,我们可以将值二值化,如果降水量不为零,则为真(true),否则为假(false)。我们还可以使用统计方法将值分为高、中、低几个箱子。在营销中,我们通常更关心年龄段(如18至24岁),而不是具体的年龄(如23岁)。
分箱过程不可避免地会导致信息的丢失。然而,根据你的目标,这可能不是一个问题,实际上还可以减少过拟合的风险。当然,这样做通常能提高计算速度,并减少内存或存储需求和冗余。
任何真实世界的机器学习系统都应该有两个模块:数据预处理模块(我们刚才讨论的)和建模模块(接下来我们将讨论的)。
模型集成(Combining Models)
模型接收数据(通常是预处理后的数据)并输出预测结果。如果我们使用多个模型会怎么样?通过结合多个模型的预测结果,是否能做出更好的决策?这一点我们将在本节中讨论。
让我们从一个类比开始。在高中,我们和其他同学一起上课并一起学习,但在考试时我们不能合作。原因很简单,老师想知道我们学到了什么,如果我们只是从朋友那里抄答案,可能根本没有学到任何东西。然而,随着时间的推移,我们发现团队合作是非常重要的。例如,这本书就是一个团队的成果,或者更准确地说,可能是多个团队的成果。
显然,团队能够比一个人创造出更好的结果。然而,这与奥卡姆剃刀原理相悖,因为一个人通常能提出比团队更简单的理论。在机器学习中,尽管如此,我们还是更倾向于让多个模型进行合作,以下是常见的模型集成方法:
- 投票和平均(Voting and Averaging)
- 自助聚合(Bagging)
- 提升(Boosting)
- 堆叠(Stacking)
接下来我们将详细介绍每一种方法。
投票和平均(Voting and Averaging)
这可能是最容易理解的模型集成类型。它的意思是最终的输出将是多个模型预测结果的多数表决或平均值。还可以对集成中的每个模型赋予不同的权重;例如,对于一些更可靠的模型,可以给予其更多的投票。
然而,结合那些高度相关的模型结果并不一定会带来显著的提升。更好的做法是通过使用不同的特征或不同的算法来实现模型的多样化。如果你发现两个模型高度相关,你可以选择将其中一个从集成中移除,并相应增加另一个模型的权重。
自助聚合(Bagging)
自助聚合(Bootstrap Aggregating,简称 Bagging)是由著名统计学家 Leo Breiman 在 1994 年提出的一种算法,它将自助法(Bootstrapping)应用于机器学习问题。自助法是一种统计方法,通过重复抽样从现有数据中创建多个数据集。自助法可以用来衡量模型的属性,如偏差和方差。
一般来说,Bagging 算法遵循以下步骤:
- 通过自助法对输入的训练数据进行抽样,生成新的训练集。
- 对每个生成的训练集,拟合一个新的模型。
- 通过平均或多数表决的方式结合各个模型的结果。
下面的示意图展示了 Bagging 步骤的过程,以分类问题为例(圆圈和叉号代表来自两个类别的样本):
正如你可以想象的,自助聚合(Bagging)可以减少过拟合的可能性。
我们将在第3章《基于树的算法预测在线广告点击率》中深入研究自助聚合方法。
提升法(Boosting)
在监督学习的背景下,我们将“弱学习器”定义为仅比基准稍微好一点的学习器,例如随机分配类别或使用平均值。就像蚂蚁一样,弱学习器单独看起来很弱,但当它们组合在一起时,却能发挥惊人的作用。
考虑到每个学习器的强度并使用权重进行调整是有意义的。这个基本思想被称为提升法(Boosting) 。在提升法中,所有模型是顺序训练的,而不是像自助聚合(Bagging)那样并行训练。每个模型都在相同的数据集上进行训练,但每个数据样本的权重不同,这个权重会考虑到前一个模型的预测结果。每当一个模型训练完成后,权重会被重新分配,并用于下一个训练轮次。一般来说,对于预测错误的样本,权重会增加,以强调这些样本的预测难度。
以下图示展示了提升法的步骤,这里以分类为例(圆圈和叉表示来自两个类别的样本,圆圈或叉的大小表示为其分配的权重):
有许多提升算法,提升算法的主要区别在于它们的加权方案。如果你曾经为考试复习过,你可能使用过类似的技巧,通过识别自己难以掌握的练习题类型,并集中精力解决这些难题。
Viola-Jones,一个流行的面部检测框架,利用提升算法有效地识别图像中的人脸。面部检测属于监督学习。我们向学习器提供包含人脸的区域作为示例。存在不平衡的问题,因为通常没有人脸的区域要比有面部的区域多得多(大约多出10,000倍)。
通过一系列的分类器级联,逐步滤除这些负面图像区域。在每个阶段,分类器使用更多的特征并且图像窗口数量逐渐减少。其核心思想是将大部分时间花费在包含人脸的图像区域中。在这种背景下,提升法用于选择特征并组合结果。
堆叠(Stacking)
堆叠将机器学习模型的输出值作为另一个算法的输入值。你当然可以将更高层次算法的输出作为另一个预测器的输入。虽然可以使用任何任意的拓扑结构,但出于实际考虑,建议首先尝试简单的设置,正如奥卡姆剃刀原理所建议的那样。
有趣的是,堆叠常常用于Kaggle竞赛中的获胜模型。例如,在Otto Group Product Classification Challenge(网址:www.kaggle.com/c/otto-grou…)中,第一名就是由30多个不同模型组成的堆叠模型。
到目前为止,我们已经介绍了在数据预处理和建模阶段,帮助机器学习模型更容易实现正确泛化的技巧。我知道你迫不及待地想开始一个机器学习项目了。让我们通过设置工作环境来做好准备吧。
安装软件和环境设置
正如书名所示,Python 是我们将在本书中实现所有机器学习算法和技术的编程语言。我们还将使用许多流行的 Python 包和工具,如 NumPy、SciPy、scikit-learn、TensorFlow 和 PyTorch。在本章结束时,即使你已经是 Python 专家或对上述工具有所了解,也请确保正确设置了工具和工作环境。
设置 Python 和环境
我们将在本书中使用 Python 3。Anaconda Python 3 发行版是数据科学和机器学习从业人员的最佳选择之一。
Anaconda 是一个免费的 Python 发行版,专为数据分析和科学计算设计。它有自己的包管理器 conda。该发行版(docs.anaconda.com/free/anacon…,根据你的操作系统和 Python 版本 3.7 至 3.11)包含大约 700 个 Python 包(截至 2023 年),这使得它非常方便。对于偶尔使用者,Miniconda(conda.io/miniconda.h…)发行版可能是更好的选择。Miniconda 包含 conda 包管理器和 Python。显然,Miniconda 占用的磁盘空间比 Anaconda 少得多。
安装 Anaconda 和 Miniconda 的过程类似。你可以按照以下链接的说明进行安装:docs.conda.io/projects/co…。首先,你需要下载适用于你的操作系统和 Python 版本的安装程序,如下所示:
按照你操作系统中的步骤进行安装。你可以选择图形用户界面(GUI)或命令行界面(CLI)。我个人觉得后者更简单。
Anaconda 自带 Python 安装。在我的电脑上,Anaconda 安装程序在我的主目录中创建了一个 anaconda 目录,并且需要大约 900 MB 的空间。同样,Miniconda 安装程序会在你的主目录中安装一个 miniconda 目录。
设置完成后,可以随意试用一下。一种验证是否正确安装 Anaconda 的方法是,在 Linux/Mac 上的终端(Terminal)或 Windows 上的命令提示符(Command Prompt)中输入以下命令(以后我们将直接提到 Terminal):
python
执行上述命令后,你应该会看到 Python 运行环境的相关信息,如下图所示:
如果你没有看到上述内容,请检查系统路径或 Python 的运行路径。
总结这一部分内容时,我想强调 Python 成为机器学习和数据科学领域最受欢迎语言的几个原因。首先,Python 以其高可读性和简洁性著称,这使得构建机器学习模型变得更加容易。我们不需要花费大量时间关注正确的语法和编译问题,从而能够将更多的精力集中在寻找合适的机器学习解决方案上。其次,Python 拥有大量用于机器学习的库和框架,涵盖了以下任务:
| 任务 | Python 库 |
|---|---|
| 数据分析 | NumPy, SciPy, pandas |
| 数据可视化 | Matplotlib, Seaborn |
| 模型构建 | scikit-learn, TensorFlow, Keras, PyTorch |
表 1.5:用于机器学习的流行 Python 库
下一步,我们将设置本书中将会用到的一些包。
安装主要的 Python 包
在本书的大多数项目中,我们将使用 NumPy(www.numpy.org/)、SciPy(scipy.org/)、pandas库(pandas.pydata.org/)、scikit-learn(scikit-learn.org/stable/)、TensorFlow(www.tensorflow.org/)和 PyTorch(pytorch.org/)。
在接下来的章节中,我们将介绍安装本书中主要使用的几个 Python 包。
Conda 环境提供了一种隔离不同项目依赖关系和包的方法。因此,建议为新项目创建并使用一个环境。我们可以使用以下命令创建一个名为“pyml”的环境:
conda create --name pyml python=3.10
在这里,我们还指定了 Python 版本 3.10,这个步骤是可选的,但强烈推荐这样做。这是为了避免默认使用最新的 Python 版本,因为许多 Python 包可能与最新版本不兼容。例如,在撰写本书时(2023 年末),PyTorch 不支持 Python 3.11。
要激活新创建的环境,可以使用以下命令:
conda activate pyml
激活后的环境将在命令提示符前显示如下:
(pyml) hayden@haydens-Air ~ %
NumPy
NumPy 是 Python 机器学习的基础包。它提供了强大的工具,包括以下内容:
- N 维数组(ndarray)类和几个表示矩阵和数组的子类
- 各种复杂的数组函数
- 有用的线性代数能力
NumPy 的安装说明可以在 numpy.org/install/ 上找到。或者,您可以使用以下命令在命令行中通过 conda 或 pip 安装它:
conda install numpy
或者
pip install numpy
验证安装是否成功的快捷方法是,在 Python 中导入它,如下所示:
>>> import numpy
如果没有显示错误消息,则表示安装成功。
SciPy
在机器学习中,我们主要使用 NumPy 数组来存储由特征向量组成的数据向量或矩阵。SciPy(scipy.org/)使用 NumPy 数组,并提供了多种科学和数学函数。安装 SciPy 的方式与安装 NumPy 类似,可以使用以下命令:
conda install scipy
或者
pip install scipy
pandas
在本书的后续部分,我们还将使用 pandas 库(pandas.pydata.org/)进行数据清理。安装 pandas 的最佳方式是使用 pip 或 conda,例如:
conda install pandas
scikit-learn
scikit-learn 库是一个为性能优化的 Python 机器学习包,因为它的很多代码运行速度几乎与等效的 C 代码一样快。NumPy 和 SciPy 也是如此。scikit-learn 需要安装 NumPy 和 SciPy。根据 scikit-learn.org/stable/inst… 中的安装指南,安装 scikit-learn 最简单的方法是使用 pip 或 conda,方法如下:
pip install -U scikit-learn
或者
conda install -c conda-forge scikit-learn
在这里,我们使用 -c conda-forge 选项告诉 conda 从 conda-forge 通道中搜索包,conda-forge 是一个由社区驱动的通道,提供了广泛的开源软件包。
TensorFlow
TensorFlow 是一个由 Google Brain 团队发明的、适合 Python 的开源库,用于高性能的数值计算。它使机器学习变得更快、深度学习变得更容易,提供了基于 Python 的便捷前端 API 和基于 C++ 的高性能后端执行。TensorFlow 2 基本上是对其第一个成熟版本 1.0 的重构,并于 2019 年底发布。
TensorFlow 以其深度学习模块而广为人知。然而,它最强大的功能是计算图,算法是基于计算图构建的。基本上,计算图用来传递输入和输出之间通过张量的关系。
例如,如果我们想要评估一个线性关系:
y=3∗a+2∗by = 3 * a + 2 * by=3∗a+2∗b
我们可以用以下计算图来表示它:
在这里,a 和 b 是输入张量,c 和 d 是中间张量,y 是输出张量。
你可以将计算图看作是一个由节点和边连接的网络。每个节点是一个张量,每条边是一个操作或函数,它接受输入节点并返回输出节点的值。为了训练机器学习模型,TensorFlow 构建计算图并相应地计算梯度(梯度是指示最陡方向的向量,最终会到达最优解)。在接下来的章节中,你将看到一些使用 TensorFlow 训练机器学习模型的示例。
如果你有兴趣深入了解 TensorFlow 和计算图,强烈建议你访问 TensorFlow 官方指南。
TensorFlow 允许轻松地在 CPU 和 GPU 上进行计算,从而支持昂贵的大规模机器学习。在本书中,我们将重点介绍以 CPU 作为计算平台。因此,根据 TensorFlow 安装指南,安装 TensorFlow 2 可以通过以下命令行完成:
conda install -c conda-forge tensorflow
或者
pip install tensorflow
你可以通过在 Python 中导入 TensorFlow 来验证是否安装成功。
PyTorch
PyTorch 是一个开源机器学习库,主要用于开发深度学习模型。它提供了一个灵活高效的框架,用于构建神经网络并在 GPU 上执行计算。PyTorch 由 Facebook 的 AI 研究实验室开发,广泛应用于研究和工业界。
与 TensorFlow 类似,PyTorch 也是基于有向无环图(DAG)执行计算。不同的是,PyTorch 使用动态计算图,这意味着计算图可以在运行时动态构建,而 TensorFlow 使用静态计算图,计算图的结构在执行前就已定义好并执行。PyTorch 的这种动态特性使得它在模型设计上更具灵活性,调试也更容易,同时还支持动态控制流,适用于各种应用。
PyTorch 由于其灵活性、易用性和高效的计算能力,已成为深度学习领域研究人员和从业者的热门选择。其直观的界面和强大的社区支持使它成为一个强大的工具,广泛应用于计算机视觉、自然语言处理、强化学习等多个领域。
安装 PyTorch
推荐查看 PyTorch 官方安装指南,根据你的操作系统和安装方式获取最新的安装命令。
作为示例,我们可以在 Mac 上使用以下命令通过 conda 安装最新的稳定版本(截至 2023 年末是 2.2.0):
conda install pytorch::pytorch torchvision -c pytorch
最佳实践
如果你在安装过程中遇到问题,请阅读安装页面上提供的平台和包特定的推荐说明。本书中的所有 PyTorch 代码都可以在 CPU 上运行,除非明确指示仅限 GPU 使用。然而,如果你希望加快神经网络模型的训练并充分利用 PyTorch 的优势,建议使用 GPU。如果你有显卡,可以参考安装指南并使用合适的计算平台设置 PyTorch。例如,在 Windows 上使用 GPU 安装 PyTorch,可以使用以下命令:
conda install pytorch torchvision pytorch-cuda=11.8 -c pytorch -c nvidia
要检查是否正确安装了带 GPU 支持的 PyTorch,可以运行以下 Python 代码:
>>> import torch
>>> torch.cuda.is_available()
True
此外,你还可以使用 Google Colab 免费使用 GPU 来训练神经网络模型。
本书中还将使用许多其他包,例如用于绘图和可视化的 Matplotlib、用于可视化的 Seaborn、用于自然语言处理任务的 NLTK、用于大型数据集预训练的最先进模型的 transformers 以及用于强化学习的 OpenAI Gym。每当我们首次使用某个包时,将提供详细的安装信息。
总结
我们刚刚完成了机器学习与 Python 之旅的第一公里!在本章中,我们熟悉了机器学习的基础知识。我们从机器学习的定义、重要性以及简短的历史开始,了解了其发展历程并探讨了近期的进展。我们还学习了典型的机器学习任务,并探讨了几种处理数据和模型的基本技术。现在,我们已经具备了基础的机器学习知识,并且完成了软件和工具的设置,接下来让我们为即将到来的真实世界机器学习示例做好准备。
在下一章,我们将构建一个电影推荐引擎,作为我们的第一个机器学习项目!