机器学习实践指南-全-
机器学习实践指南(全)
原文:
annas-archive.org/md5/0c5a0ebc55e1e877629334a7531d9961译者:飞龙
前言
在日益庞大和复杂的数据库中找到有意义的元素是现代世界的一个日益增长的需求。机器学习和预测分析已成为揭示数据金矿的最重要方法。机器学习使用复杂的算法,根据历史模式和数据集的行为来做出改进的预测。机器学习可以提供对数据中的趋势、模式和关系的动态洞察,这对商业的增长和发展具有极大的价值。
通过这本书,你不仅将学习机器学习的基础知识,而且还将深入到现实世界数据的复杂性中,在转向使用 Hadoop 及其更广泛的生态系统工具来处理和管理你的结构化和非结构化数据之前。
本书涵盖的内容
第一章, 机器学习简介,将涵盖机器学习的基础知识和机器学习语义的格局。它还将用简单的话定义机器学习,并介绍机器学习的术语或常用术语。本章将为其余章节奠定基础。
第二章, 机器学习和大规模数据集,将探讨大规模数据集的资格、常见特征、重复问题、体积超增长的原因以及处理大数据的方法。
第三章, Hadoop 架构和生态系统的介绍,将涵盖关于 Hadoop 的所有内容,从其核心框架到其生态系统组件。在本章结束时,读者将能够设置 Hadoop 并运行一些 MapReduce 函数;他们能够使用一个或多个生态系统组件。他们还将能够运行和管理 Hadoop 环境,并理解命令行使用。
第四章, 机器学习工具、库和框架,将解释实现机器学习的开源选项,并涵盖库、工具和框架的安装、实现和执行,例如 Apache Mahout、Python、R、Julia 和 Apache Spark 的 MLlib。非常重要的一点是,我们将涵盖这些框架与大数据平台——Apache Hadoop 的集成。
第五章, 基于决策树的机器学习,将探讨使用决策树来解决分类和回归问题的监督学习技术。我们将介绍选择属性、分割和修剪树的方法。在所有其他决策树算法中,我们将探讨 CART、C4.5、随机森林和高级决策树技术。
第六章,基于实例和核方法的学习,将探讨两种学习算法:基于实例和核方法;我们将发现它们如何满足分类和预测需求。在基于实例的学习方法中,我们将详细探讨最近邻算法。同样,在基于核的方法中,我们将通过实际案例来探讨支持向量机。
第七章,基于关联规则的学习,将探讨基于关联规则的学习方法和算法:Apriori 和 FP-growth。通过一个共同示例,您将学习如何使用 Apriori 和 FP-growth 算法进行频繁模式挖掘,并对算法进行逐步调试。
第八章,基于聚类的学习,将涵盖在无监督学习背景下基于聚类的学习方法。我们将通过一个示例深入探讨 k-means 聚类算法,并学习如何使用 Mahout、R、Python、Julia 和 Spark 实现它。
第九章,贝叶斯学习,将探讨贝叶斯机器学习。此外,我们将从基本命名法到各种分布等所有核心统计概念进行覆盖。我们将深入探讨贝叶斯定理,并通过示例了解如何将其应用于现实世界问题。
第十章,基于回归的学习,将涵盖基于回归分析的机器学习,特别是如何使用 Mahout、R、Python、Julia 和 Spark 实现线性回归和逻辑回归模型。此外,我们还将涵盖其他相关的统计概念,如方差、协方差、ANOVA 等。我们还将通过示例深入探讨回归模型,以了解如何将其应用于现实世界问题。
第十一章,深度学习,将涵盖生物神经元的模型,并解释人工神经元如何与其功能相关。您将学习神经网络的核心概念,并理解全连接层是如何工作的。我们还将探讨一些与矩阵乘法结合使用的关键激活函数。
第十二章,强化学习,将探讨一种名为强化学习的新学习技术。我们将看到这与传统的监督学习和无监督学习技术有何不同。我们还将探讨 MDP 的元素,并通过一个示例来了解它。
第十三章,集成学习,将涵盖机器学习的集成学习方法。具体来说,我们将探讨一些带有实际案例的监督集成学习技术。最后,本章将提供使用 R、Python(scikit-learn)、Julia 和 Spark 机器学习工具以及使用 Mahout 库的推荐引擎的源代码示例。
第十四章,机器学习的新一代数据架构,将介绍机器学习的实现方面。我们将了解传统的分析平台是什么以及它们如何无法满足现代数据需求。你还将了解推动新一代数据架构范例的架构驱动因素,例如 Lambda 架构多语言持久性(多模型数据库架构);你将了解语义架构如何帮助实现无缝数据集成。
你需要这本书的以下内容
你需要以下软件来使用这本书:
-
R (2.15.1)
-
Apache Mahout (0.9)
-
Python(sckit-learn)
-
Julia(0.3.4)
-
Apache Spark(带有 Scala 2.10.4)
这本书面向的对象
这本书是为那些想看到机器学习实际应用并探索其实际应用的数据科学家编写的。从机器学习和预测分析的基础到引领大数据革命走向未来的最新创新,这本书是任何致力于解决当前大数据挑战的人不可或缺的资源。如果你想立即开始,建议具备编程(Python 和 R)和数学知识。
规范
在这本书中,你会发现许多不同风格的文本,以区分不同类型的信息。以下是一些这些风格的示例及其含义的解释。
文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称都显示如下:“Map()函数在分布式数据上运行,并行执行所需的功能。”
代码块设置为如下:
public static class VowelMapper extends Mapper<Object, Text, Text, IntWritable>
{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException
{
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens())
{
word.set(itr.nextToken());
context.write(word, one);
}
}
任何命令行输入或输出都写作如下:
$ hadoop-daemon.sh start namenode
注意
警告或重要注意事项以如下框的形式出现。
小贴士
小贴士和技巧看起来像这样。
读者反馈
我们始终欢迎读者的反馈。告诉我们你对这本书的看法——你喜欢什么或可能不喜欢什么。读者反馈对我们开发你真正能从中获得最大收益的标题非常重要。
要向我们发送一般反馈,只需发送电子邮件到<feedback@packtpub.com>,并在邮件主题中提及书名。
如果您在某个主题上具有专业知识,并且您对撰写或为书籍做出贡献感兴趣,请参阅我们的作者指南www.packtpub.com/authors。
客户支持
现在您已经是 Packt 书籍的骄傲所有者,我们有一些事情可以帮助您从您的购买中获得最大收益。
下载示例代码
您可以从您在www.packtpub.com的账户中下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。
作者将在github.com/PacktCode/Practical-Machine-Learning上更新代码,供您在版本更新时下载。
下载本书的彩色图像
我们还为您提供了一个包含本书中使用的截图/图表彩色图像的 PDF 文件。这些彩色图像将帮助您更好地理解输出的变化。您可以从www.packtpub.com/sites/default/files/downloads/Practical_Machine_Learning_ColorImages.pdf下载此文件。
勘误
尽管我们已经尽一切努力确保内容的准确性,但错误仍然可能发生。如果您在我们的书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以避免其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入您的勘误详情来报告它们。一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误部分下的现有勘误列表中。
要查看之前提交的勘误,请访问www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将出现在勘误部分下。
侵权
互联网上版权材料的侵权是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上发现我们作品的任何非法副本,无论形式如何,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。
请通过发送链接到<copyright@packtpub.com>与我们联系,以提供涉嫌侵权材料的链接。
我们感谢您在保护我们的作者以及为我们提供有价值内容的能力方面的帮助。
问题
如果你在本书的任何方面遇到问题,可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决。
第一章:机器学习简介
本章的目标是带您了解机器学习领域,并为后续章节提前概述基本概念。更重要的是,重点是帮助您探索各种学习策略,并深入不同机器学习子领域。每个子领域下的技术和算法,以及构成任何机器学习项目实施核心的整体架构,都将进行深入探讨。
关于机器学习有许多出版物,过去在这个领域已经做了很多工作。除了机器学习概念之外,重点将主要放在通过实际案例的具体实践方面。重要的是你已经对基本编程技术和算法范式有相当高的了解;尽管对于每个编程部分,都有相应的入门指南。
本章将深入探讨以下主题:
-
机器学习简介
-
基本定义和用法环境
-
机器学习与数据挖掘、人工智能(AI)、统计学和数据科学之间的差异和相似性
-
与大数据的关系
-
术语和机制:模型、准确性、数据、特征、复杂性和评估指标
-
机器学习子领域:监督学习、无监督学习、半监督学习、强化学习和深度学习。每个机器学习子领域也涵盖了特定的机器学习技术和算法
-
机器学习问题类别:分类、回归、预测和优化
-
机器学习架构、生命周期和实际问题
-
机器学习技术、工具和框架
机器学习
机器学习已经存在很多年了,所有社交媒体用户在某个时间点都曾是机器学习技术的消费者。一个常见的例子是面部识别软件,它具有识别数字照片中是否包含特定人物的能力。如今,Facebook 用户可以在上传的数字照片中看到自动建议标记他们的朋友。一些相机和软件,如 iPhoto,也具备这种功能。本章后面将更详细地讨论许多例子和用例。
以下概念图代表了本章将涵盖的机器学习的关键方面和语义:

定义
让我们从定义机器学习是什么开始。机器学习有许多技术和功能定义,以下是一些例子:
| *"如果一个计算机程序在任务 T 中从经验 E 中学习,相对于某些任务类 T 和性能度量 P,如果其性能随着经验 E 的提高而提高,则称该程序从经验 E 中学习。" | ||
|---|---|---|
| --Tom M. Mitchell | ||
| *"机器学习是从数据中训练模型,该模型对性能度量进行泛化决策。" | ||
| --Jason Brownlee | ||
| *"人工智能的一个分支,其中计算机生成基于输入的原始数据的基本规则。" | ||
| --Dictionary.com | ||
| *"机器学习是一门科学,它涉及设计和发展算法,使计算机能够根据经验数据,如传感器数据或数据库中的数据,进化行为。" | ||
| --Wikipedia |
上述定义既迷人又相关。它们要么具有算法、统计或数学的角度。
除了这些定义之外,一个单一的术语或定义对于机器学习的定义至关重要,它有助于促进问题解决平台的定义。基本上,它是一种模式搜索机制,将智能构建到机器中,使其能够学习,这意味着它将能够从自己的经验中做得更好。
深入探讨一个模式通常是什么,模式搜索或模式识别本质上研究的是机器如何感知环境,学会区分感兴趣的行为与其他行为,并能够对分类行为做出合理的决策。这通常由人类来完成。目标是提高准确性、速度,并避免系统被不当使用的可能性。
以这种方式构建的机器学习算法处理构建智能。本质上,机器以与人类相似的方式理解数据。
机器学习实现的根本目标是开发一个通用的算法,该算法能够解决实际且具体的问题。在这个过程中需要考虑的重要方面包括数据、时间和空间需求。最重要的是,具有应用于广泛学习问题的能力,学习算法的目标是产生一个尽可能准确的结果,即一条规则。
另一个重要的方面是大数据环境;也就是说,机器学习方法已知在需要从大型、多样化和快速变化的数据集中发现洞察力的情况下也有效。关于机器学习的大规模数据方面的更多内容将在第二章 机器学习与大规模数据集 中介绍。
核心概念和术语
机器学习的核心是了解并适当地使用数据。这包括收集正确的数据、清洗数据,并使用学习算法迭代地处理数据,利用数据的关键特征构建模型,并根据这些模型的假设进行预测。
在本节中,我们将介绍机器学习中使用的标准术语或命名法,从如何描述数据、学习、建模、算法以及特定的机器学习任务开始。
什么是学习?
现在,让我们看看在机器学习背景下“学习”的定义。简单来说,历史数据或观察结果被用来预测或推导出可执行的任务。非常明显,一个智能系统的基本要求就是其学习能力。以下是一些定义学习问题的考虑因素:
-
提供一个定义,说明学习者应该学习什么以及学习的必要性。
-
定义数据需求和数据来源。
-
定义学习者是否应该在整个数据集上操作,或者一个子集就足够了。
在我们深入理解以下各节中每种学习类型的内部机制之前,你需要了解解决学习问题所遵循的简单过程,这涉及到构建和验证模型,以最大精度解决问题。
小贴士
模型不过是将算法应用于数据集的输出,它通常是数据的表示。我们将在后面的章节中更详细地介绍模型。
通常,为了执行机器学习,主要需要两种类型的数据集。第一种数据集通常是手动准备的,其中输入数据和预期的输出数据都可用并已准备。重要的是,每一条输入数据都应该有一个可预期的输出数据点,因为这将以监督方式用于构建规则。第二种数据集是我们有输入数据,我们感兴趣的是预测预期的输出。
作为第一步,给定的数据被划分为三个数据集:训练集、验证集和测试集。没有一条固定的规则规定数据集的百分比应该是多少,可以是 70-10-20、60-30-10、50-25-25 或其他任何值。
训练数据集指的是用于学习或构建分类器的数据示例,例如。验证数据集指的是用于验证构建的分类器的数据示例,可以帮助调整输出的准确性。测试数据集指的是帮助评估分类器性能的数据示例。
执行机器学习通常有三个阶段:
-
第一阶段——训练阶段:这是使用训练数据通过将给定的输入与预期的输出配对来训练模型的过程。这一阶段的输出是学习模型本身。
-
第二阶段——验证和测试阶段:这个阶段是为了衡量已经训练好的学习模型的好坏,并估计模型属性,如误差度量、召回率、精确度等。这个阶段使用验证数据集,输出是一个复杂的学习模型。
-
第三阶段——应用阶段:在这个阶段,模型需要接受实际世界的数据,并从中得出结果。
下图展示了如何将学习应用于预测行为:

数据
数据是机器学习中的主要学习来源。这里所引用的数据可以是任何格式,可以以任何频率接收,可以是任何大小。在处理机器学习环境中的大型数据集时,有一些新技术已经发展起来,并正在被实验。还有更多的大数据方面,包括并行处理、分布式存储和执行。下一章将更详细地介绍数据的这些大规模方面,包括一些独特的区分因素。
当我们想到数据时,维度就会浮现在脑海中。首先,对于结构化和非结构化数据,我们有行和列。这本书将涵盖在机器学习环境中处理结构化和非结构化数据。在本节中,我们将介绍与机器学习环境中的数据相关的术语。
| 术语 | 在机器学习环境中的目的或意义 |
|---|---|
| 特征、属性、字段或变量 | 这是学习算法所引用的单个数据列。一些特征可以作为输入提供给学习算法,而一些可以是输出。 |
| 实例 | 这是数据集中的一个单独的数据行。 |
| 特征向量或元组 | 这是一个特征列表。 |
| 维度 | 这是用于描述数据属性的一组属性子集。例如,日期维度由三个属性组成:日、月和年。 |
| 数据集 | 行或实例的集合被称为数据集。在机器学习环境中,存在不同类型的数据集,用于不同的目的。算法在不同的数据集上运行,以衡量模型的准确性。有三种类型的数据集:训练数据集、测试数据集和评估数据集。任何给定的大型数据集通常会被分成三个数据集类别,其比例通常是:60%训练,30%测试,10%评估。 |
| a. 训练数据集 | 训练数据集是模型构建或训练的基础数据集。 |
| b. 测试数据集 | 测试数据集是用于验证所构建模型的那个数据集。这个数据集也被称为验证数据集。 |
| c. 评估数据集 | 评估数据集是用于模型最终验证的数据集(可以更类似于用户验收测试)。 |
| 数据类型 | 属性或特征可以有不同的数据类型。以下列出了一些数据类型:
-
分类(例如:年轻,年老)。
-
序数(例如:0,1)。
-
数值(例如:1.3,2.1,3.2 等)。
|
| 覆盖率 | 预测或模型覆盖的数据集百分比。这决定了预测模型的置信度。 |
|---|
标记和未标记数据
在机器学习背景下,数据可以是标记的或未标记的。在我们深入探讨机器学习基础知识之前,你需要了解这种分类,以及何时使用哪些数据,因为这种术语将在整本书中使用。
未标记数据通常是数据的原始形式。它由自然或人为创造的样本组成。这类数据在数量上很容易获得。例如,视频流、音频、照片和推文等。这种形式的数据通常没有附加的解释说明。
当一个意义被附加到未标记数据上时,它就变成了标记数据。在这里,我们谈论的是附加一个“标签”或“标记”,这是必需的,并且是解释和定义相关性的强制性要求。例如,照片的标签可以是它包含的细节,如动物、树木、大学等,或者在音频文件的情况下,可以是政治会议、告别派对等。更常见的是,标签由人类映射或定义,并且比未标记的原始数据获得成本高得多。
学习模型可以应用于标记数据和未标记数据。我们可以通过结合标记和未标记数据集来推导出更精确的模型。以下图表表示了标记和未标记数据。三角形和更大的圆圈代表标记数据,而小圆圈代表未标记数据。

标记和未标记数据的应用将在以下章节中更详细地讨论。你会看到,监督学习采用标记数据,无监督学习采用未标记数据。半监督学习和深度学习技术以各种方式结合标记和未标记数据来构建准确的模型。
任务
任务是机器学习算法旨在解决的问题。我们衡量任务上的性能是很重要的。在这个上下文中,“性能”一词无非是解决问题的程度或信心。不同的算法在不同的数据集上运行会产生不同的模型。重要的是,生成的模型不应进行比较,而应衡量不同数据集和不同模型之间结果的一致性。
算法
在对当前机器学习问题有一个清晰的理解之后,重点转向哪些数据和算法是相关或适用的。有几种算法可供选择。这些算法要么按学习子领域(如监督学习、无监督学习、强化学习、半监督学习或深度学习)分组,要么按问题类别(如分类、回归、聚类或优化)分组。这些算法在多个数据集上迭代应用,并捕获随着新数据而演化的模型。
模型
模型是任何机器学习实现的核心。模型描述了系统中观察到的数据。模型是应用于数据集的算法的输出。在许多情况下,这些模型应用于新的数据集,这有助于模型学习新的行为并预测它们。针对给定问题,有广泛的机器学习算法可供应用。在非常高的层面上,模型被分类如下:
-
逻辑模型
-
几何模型
-
概率模型
逻辑模型
逻辑模型在本质上更具有算法性,通过迭代运行算法帮助我们推导出一组规则。决策树就是一个这样的例子:

几何模型
几何模型使用诸如线、平面和距离等几何概念。这些模型通常在大量数据上操作,或者可以操作。通常,线性变换有助于比较不同的机器学习方法:

概率模型
概率模型是采用统计技术的统计模型。这些模型基于一种定义两个变量之间关系的策略。由于涉及使用随机背景过程,这种关系可以确定地推导出来。在大多数情况下,可以认为整体数据的一个子集用于处理:
| Viagra | Lottery | P(Y= Spam (Viagra, lottery)) | P(Y= ham (Viagra, lottery)) |
|---|---|---|---|
| 0 | 0 | 0.31 | 0.69 |
| 0 | 1 | 0.65 | 0.35 |
| 1 | 0 | 0.80 | 0.20 |
| 1 | 1 | 0.40 | 0.60 |
机器学习中的数据和不一致性
本节详细介绍了在实施机器学习项目过程中可能遇到的所有可能的数据不一致性,例如:
-
欠拟合
-
过拟合
-
数据不稳定
-
不可预测的未来
幸运的是,目前有一些既定的流程来解决这些不一致性。以下各节将介绍这些不一致性。
欠拟合
当一个模型没有考虑足够的信息来准确建模实际数据时,我们称其为欠拟合。例如,如果只在指数曲线上映射两个点,这可能会成为一个线性表示,但可能存在没有模式的情况。在这些情况下,我们会看到不断增加的错误,随后是一个不准确的模型。此外,在分类器过于僵化或不够复杂的情况下,欠拟合不仅可能是由于数据不足,也可能是由于建模不正确。例如,如果两个类别形成同心圆,而我们试图拟合一个线性模型,假设它们是线性可分的,这可能会导致欠拟合。
模型的准确性由统计世界中称为“功率”的度量来确定。如果数据集大小太小,我们永远无法达到最优解。
过拟合
这种情况与之前解释的欠拟合情况正好相反。虽然样本太小不适合定义最优解,但大数据集也存在模型过拟合数据的危险。过拟合通常发生在统计模型描述噪声而不是描述关系时。在这个背景下详细说明前面的例子,假设我们有 500,000 个数据点。如果模型最终要适应所有 500,000 个数据点,这就变成了过拟合。这实际上意味着模型正在记忆数据。只要数据集没有曲线外的点,这个模型就能很好地工作。一个过拟合的模型表现不佳,因为数据的小幅波动往往会被夸大。过拟合的主要原因也可能是用于训练模型的准则与用于评估模型有效性的准则不同。简单来说,如果模型记住训练数据而不是学习,这种情况就会更频繁地发生。
现在,在缓解数据欠拟合问题的过程中,通过提供更多数据,这本身可能就是一个风险,并最终导致过拟合。考虑到更多数据可能意味着更多的复杂性和噪声,我们可能会得到一个解决方案模型,它只适合当前的数据,而不适合其他任何数据,这使得它无法使用。在下面的图中,随着模型复杂性和错误的增加,过拟合和欠拟合的条件被指出来:

数据不稳定
机器学习算法通常对数据中的噪声具有鲁棒性。如果异常值是由于人为错误或对相关数据的误解造成的,那么就会发生问题。这将导致数据偏斜,最终导致模型错误。
因此,有一个过程来纠正或处理可能导致构建错误模型的人为错误是非常必要的。
不可预测的数据格式
机器学习旨在与系统不断进入的新数据一起工作,并从这些数据中学习。当进入系统的新的数据格式不被机器学习系统支持时,复杂性就会逐渐增加。鉴于我们接收到的数据格式不稳定,现在很难说我们的模型对新数据是否工作良好,除非有机制来处理这种情况。
实际机器学习示例
在本节中,让我们探索一些实际的机器学习应用。我们在本章的介绍部分涵盖了各种示例,现在我们将涵盖一些特定领域的示例,并对每个问题进行简要描述。
对于在线和离线应用,以下的一些示例可以轻松猜出。在接下来的章节中,将选择这些示例的子集,以使用合适的机器学习算法展示实际实施方面的示例。
| 问题 / 问题域 | 描述 |
|---|---|
| 邮件垃圾检测 | 这里的问题陈述是要识别哪些电子邮件是“垃圾邮件”。一个机器学习算法可以根据它使用电子邮件数据的一些关键特征构建的规则,将电子邮件分类为垃圾邮件。一旦电子邮件被标记为垃圾邮件,该邮件就会被移动到垃圾邮件文件夹,其余的则留在收件箱中。 |
| 信用卡欺诈检测 | 这是信用卡公司需要解决的一个近期问题。基于消费者使用的信用卡模式和客户的购买行为,需要识别任何可能不是由客户进行的交易,并将它们标记为欺诈,以便采取必要的行动。 |
| 数字识别 | 这是一个非常简单的用例,需要根据邮编对帖子进行分组的能力。这包括准确解释手写数字并根据邮编对帖子进行分类以加快处理的需求。 |
| 语音识别 | 自动呼叫中心需要这种能力,即用户的电话请求被解释并映射到执行任务之一。一旦用户请求可以映射到任务,其执行就可以自动化。这个问题的一个模型将允许程序理解并尝试满足那个请求。配备 Siri 的 iPhone 就有这种能力。 |
| 人脸检测 | 这是今天社交媒体网站提供的关键功能之一。这个功能提供了一种在许多数字照片中标记人的能力。这为按人分组或对照片进行分类提供了能力。一些相机和软件,如 iPhoto,就有这种能力。 |
| 产品推荐或客户细分 | 这种能力几乎存在于今天所有的顶级在线购物网站上。给定一个客户的购买历史和大量产品库存,目标是识别那些客户最有可能购买的产品,从而激励更多的产品购买。许多在线购物和社交网站支持此功能(例如:亚马逊、Facebook、Google+等)。还有其他情况,比如预测试用版客户是否会选择产品的付费版本。 |
| 股票交易 | 这意味着根据当前和过去的股票走势来预测股票表现。这项任务对金融分析师至关重要,并在买卖股票时提供决策支持。 |
| 情感分析 | 许多时候,我们发现客户是基于他人的意见做出决定的。例如,我们购买一个产品是因为它的大部分用户给出了积极的反馈。不仅如前所述的商业业务中,情感分析也被政治策略家用来衡量政策声明或竞选信息的公众舆论。 |
学习问题的类型
本节重点阐述不同的学习问题类别。机器学习算法也被归类在这些学习问题中。以下图展示了各种类型的学习问题:

分类
分类是一种识别给定数据集分组技术的方法,这样根据目标或输出属性的一个值,整个数据集可以被归类为属于一个类别。这项技术有助于识别数据行为模式。简而言之,这是一种区分机制。
例如,销售经理需要帮助识别潜在客户,并想确定是否值得花费客户要求的努力和时间。经理的关键输入是客户数据,这种情况通常被称为总终身价值(TLV)。
我们获取数据,开始在图表上盲目地绘制(如下面的图表所示),其中 x 轴代表购买的总商品数量,y 轴代表花费的总金额(以美元的百倍为单位)。现在我们定义标准以确定,例如,一个客户是好是坏。在下面的图表中,所有单次购买超过 800 美元的客户都被归类为好客户(请注意,这是一个假设的例子或分析)。

现在当新的客户数据进来时,销售经理可以将新客户绘制在这个图表上,并根据他们所在的哪一侧,预测客户是否可能成为好客户或坏客户。
小贴士
注意,分类不一定是二元的(是或否,男或女,好或坏,等等),可以根据问题定义定义任意数量的分类(差,低于平均水平,平均水平,高于平均水平,好)。
聚类
在许多情况下,数据分析师只是被提供了一些数据,并期望他们能够挖掘出可能有助于得出情报的有趣模式。这个任务与分类任务的主要区别在于,在分类问题中,业务用户指定了他/她正在寻找的内容(一个好的客户或一个坏的客户,一个成功或一个失败,等等)。
现在我们来扩展在分类部分提到的相同例子。在这里,识别用于分类客户的模式时并没有考虑任何目标或先前的分类,而且与运行分类不同,结果可能并不总是相同的(例如,取决于初始质心的选择方式)。聚类的一个示例建模方法是 k-means 聚类。关于 k-means 聚类的更多细节将在下一节和后续章节中详细说明。
简而言之,聚类是一种分类分析,它并不以一个特定的目标为出发点(好/坏,会买/不会买)。
预测、预测或回归
与分类类似,预测或预测也是关于识别事物未来可能发生的方式。这种信息是从过去的经验或知识中得出的。在某些情况下,数据不足,需要通过回归来定义未来。预测和预测结果总是与不确定性的程度或概率一起呈现。这种问题类型的分类也称为规则提取。
让我们举一个例子,一个农业科学家正在研究她开发的新作物。作为试验,这种种子在各个海拔高度种植,并计算了产量。这里的要求是根据海拔细节(以及一些相关的数据点)预测作物的产量。通过在参数之间绘制图表,确定了产量与海拔之间的关系。记录了一个适合大多数数据点的方程,在数据不拟合曲线的情况下,我们可以去除这些数据。这种技术被称为回归。

模拟
除了我们之前定义的所有技术之外,可能存在数据本身具有许多不确定性的情况。例如,一个外包经理被分配了一个任务,并且可以根据经验估计,这个任务可以由一个具有特定技能的团队在 2-4 小时内完成。
假设输入材料的成本可能在 100-120 美元之间,而任何给定一天来上班的员工数量可能在 6 到 9 人之间。然后分析师估计项目可能需要多长时间。解决这类问题需要模拟大量的替代方案。
通常在预测、分类和无监督学习中,我们被给予数据,但我们实际上并不知道数据是如何相互关联的。没有方程可以描述一个变量作为其他变量的函数。
从本质上讲,数据科学家结合使用前面提到的一种或多种技术来解决具有挑战性的问题,这些问题包括:
-
网络搜索和信息提取
-
药物设计
-
预测资本市场行为
-
理解客户行为
-
设计机器人
优化
简单来说,优化是一种使某事物变得更好或为解决方案定义一个使其成为最佳的上下文的机制。
考虑一个生产场景,假设有两个机器可以生产所需的产品,但一个机器在生产高速时需要更多的能量和较少的原材料,而另一个机器则需要更多的原材料和较少的能量来在相同的时间内生产相同的输出。理解基于输入变化的输出模式非常重要;可能带来最高利润的组合可能是生产经理想要了解的。作为分析师,你需要确定在机器之间分配生产以获得最高利润的最佳方式。
下图显示了在两个机器之间绘制各种分布选项的图表时,最高利润点。识别这个点是这种技术的目标。

与存在与输入数据相关的不确定性的模拟案例不同,在优化中,我们不仅能够访问数据,而且还有关于数据属性之间依赖关系和关系的信息。
机器学习中的一个关键概念是称为归纳的过程。以下学习子领域使用归纳过程来构建模型。归纳学习是一个推理过程,它使用一个实验的结果来运行下一组实验,并通过迭代从具体信息中演变出一个模型。
下图描述了机器学习的各个子领域。这些子领域是机器学习算法分类的方式之一。

监督学习
监督学习完全是关于操作到一个已知的期望,在这种情况下,需要从定义中的数据中分析什么。在这个背景下,输入数据集也被称为“标记”数据集。归类在这个类别的算法专注于建立输入和输出属性之间的关系,并使用这种关系推测性地为新的输入数据点生成输出。在前一小节中,为分类问题定义的例子也是监督学习的一个例子。标记数据有助于构建可靠的模型,但通常成本高昂且有限。
当数据的输入和输出属性已知时,监督学习的关键是输入到输出的映射。这些映射有很多例子,但连接输入和输出属性的复杂函数是未知的。监督学习算法负责这种连接,并且给定大量输入/输出对的大数据集,这些函数有助于预测任何新输入值的输出。
无监督学习
在一些学习问题中,我们并没有特定的目标来解决。在前面的小节中,我们讨论了聚类,这是一种分类分析,我们并没有带着特定的目标(好/坏,会买/不会买)开始,因此被称为无监督分析或学习。在这种情况下,目标是解码数据中的结构,与数据输入和输出属性之间的构建映射相对,实际上输出属性并未定义。这些学习算法因此在一个“未标记”的数据集上操作。
半监督学习
半监督学习是关于使用标记数据和未标记数据来更好地学习模型。对于未标记数据,存在适当的假设是很重要的,任何不适当的假设都可能使模型无效。半监督学习从人类的学习方式中获得其动机。
强化学习
强化学习是关注最大化结果奖励的学习。例如,在教导幼儿新习惯时,每次他们遵循指示就给予奖励非常有效。事实上,他们发现哪些行为有助于他们获得奖励。这是强化学习,也称为信用评估学习。
在强化学习中,模型除了负责做出决策外,还要对收到周期性奖励的决策负责。在这种情况下,结果与监督学习不同,不是立即的,可能需要执行一系列步骤才能看到最终结果。理想情况下,算法将生成一系列决策,有助于实现最高的奖励或效用。
在这种学习技术中的目标是通过对数据进行探索和利用来有效地衡量权衡。例如,当一个人必须从点 A 到点 B 旅行时,会有许多方式,包括乘坐飞机、水路、公路或步行,通过衡量这些选项中的每一个的权衡来考虑这些数据具有很大的价值。另一个重要方面是奖励延迟的重要性。这会如何影响学习?例如,在象棋等游戏中,任何奖励识别的延迟都可能改变结果。
深度学习
深度学习是机器学习的一个领域,它侧重于将机器学习与人工智能统一。从与人工神经网络的关系来看,这个领域更多的是对在大量常见数据上工作的人工神经网络的进步,以得出实用的见解。它涉及构建更复杂的神经网络来解决半监督学习下的问题,并在具有少量标记数据的数据集上运行。以下列出了一些深度学习技术:
-
卷积网络
-
受限玻尔兹曼 机 (RBM)
-
深度信念 网络 (DBN)
-
堆叠自编码器
性能度量
性能度量用于评估学习算法,并形成机器学习的一个重要方面。在某些情况下,这些度量也用作启发式方法来构建学习模型。
现在让我们探讨可能近似正确(PAC)理论的概念。当我们描述假设的准确性时,我们通常根据 PAC 理论谈论两种类型的不确定性:
-
近似: 这个度量表示对假设错误的接受程度
-
概率: 这个度量是假设正确的百分比确定性
以下图表显示了样本数量随错误、概率和假设增长的情况:

解决方案好吗?
分类和预测问题的错误度量是不同的。在本节中,我们将介绍一些这些错误度量,然后介绍如何解决它们。
在分类问题中,你可以有两种不同类型的错误,这些错误可以用“混淆矩阵”优雅地表示。假设在我们的目标营销问题中,我们处理了 10,000 个客户记录,以预测哪些客户可能对我们的营销活动做出响应。
在分析活动后,你可以构建以下表格,其中列是你的预测,行是实际观察:
| 行动 | 预测(将有购买) | 预测(将没有购买) |
|---|---|---|
| 实际购买 | TP: 500 | FN: 400 |
| 实际未购买 | FP: 100 | TN: 9000 |
在主对角线上,我们有买家和非买家,他们的预测与实际情况相符。这些都是正确的预测。它们分别被称为真阳性(true positive)和真阴性(true negative)。在上右角,我们有那些我们预测为非买家,但实际上是买家的人。这是一个被称为假阴性错误(false negative error)的错误。在下左角,我们有那些我们预测为买家,但实际上是非买家的人。这是另一个被称为假阳性(false positive)的错误。
对于客户来说,两种错误同样昂贵吗?实际上并非如此!如果我们预测某人是买家,而他们实际上不是买家,公司最多只会损失在邮件或电话上的开支。然而,如果我们预测某人不会购买,而他们实际上确实是买家,公司就不会基于这个预测给他们打电话,从而失去了一位客户。因此,在这种情况下,假阴性错误比假阳性错误要昂贵得多。
机器学习社区在分类问题中使用三种不同的错误度量:
-
度量 1:准确率是指正确预测的百分比。
示例:准确率为(9,000+500)/ 10,000 = 95%
-
度量 2:召回率是指你能够捕捉到的阳性病例的百分比。如果假阳性率低,召回率就会高。
示例:召回率为 500/600 = 83.33%
-
度量 3:精确度是指正确预测的阳性预测的百分比。如果假阴性率低,精确度就会高。
示例:精确率为 500/900 = 55.55%
在预测中,你是在预测一个连续变量。因此,这里的错误度量相当不同。通常,错误度量是通过比较模型的预测值与目标变量的真实值,并计算平均误差来获得的。这里有一些度量。
均方误差 (MSE)
要计算 MSE,我们首先取每个记录实际值与预测值之间差值的平方。然后我们取这些平方误差的平均值。如果第i个记录的预测值是Pi,实际值是Ai,那么 MSE 是:

使用这个数量(称为均方根误差)的平方根也是很常见的。
均方误差 (MAE)
要计算 MAE,我们取每个记录预测值与实际值之间的绝对差值。然后我们取这些绝对差值的平均值。性能指标的选择取决于应用。MSE 是许多应用的优秀性能指标,因为它与方差有更多的统计基础。另一方面,MAE 更直观,对异常值不太敏感。观察 MAE 和 RMSE 可以给我们关于误差分布的额外信息。在回归中,如果 RMSE 接近 MAE,则模型会犯许多相对较小的错误。如果 RMSE 接近 MAE²,则模型会犯一些但较大的错误。

归一化均方误差和平均绝对误差(NMSE 和 NMAE)
MSE 和 MAE 都不表示误差有多大,因为它们是依赖于目标变量尺度的数值。与基准指数比较可以提供更好的洞察。常见的做法是取我们预测的主要属性的均值,并假设我们的朴素预测模型就是均值。然后我们根据朴素模型和原始模型计算 MSE。这个比率可以提供关于我们的模型与朴素模型相比是好是坏的洞察。

类似的定义也可以用于 MAE。
解决误差:偏差和方差
这种构建高度定制化高阶模型的陷阱被称为过拟合,这是一个关键概念。由此产生的错误被称为模型的方差。本质上,如果我们采用了不同的训练集,我们将得到一个非常不同的模型。方差是衡量模型对训练集依赖性的一个指标。顺便说一句,你看到的最右侧(线性拟合)的模型被称为欠拟合,由于欠拟合而产生的错误被称为偏差。在欠拟合或高偏差的情况下,模型无法解释数据之间的关系。本质上,我们试图拟合一个过于简单的假设,例如,线性拟合,而我们应该寻找更高阶的多项式。
为了避免过拟合和欠拟合的陷阱,数据科学家在训练集上构建模型,然后在测试集上找到误差。他们不断优化模型,直到测试集上的误差降低。随着模型开始定制于训练数据,测试集上的误差开始上升。他们在那个点停止优化模型。
让我们在本章中更深入地分析偏差和方差,并学习一些处理它们的实用方法。任何模型的误差都可以表示为偏差、方差和随机误差的组合。在较简单的模型中,偏差项较高,而在更复杂的模型中,方差项较高,如下面的图所示:

为了减少偏差或方差,让我们先问这个问题。如果一个模型有高偏差,它的误差如何随着数据量的增加而变化?
在非常小的数据量下,任何模型都可以很好地拟合数据(任何模型都可以拟合一个点,任何线性模型都可以拟合两个点,二次函数可以拟合三个点,依此类推)。因此,高偏差模型在训练集上的误差开始时非常小,随着数据点的增加而增加。然而,在测试集上,误差最初保持较高,因为模型高度定制于训练集。随着模型越来越精细,误差减少并等于训练集的误差。
以下图表清楚地描述了这种情况:

解决这种情况的方法可能包括以下之一:
-
很可能你正在处理非常少的特征,因此你必须找到更多特征
-
通过增加多项式和深度来增加模型的复杂性
-
如果模型有很高的偏差,增加数据量将不会有很大帮助

当你面临这种情况时,你可以尝试以下补救措施(与之前的相反):
-
很可能你正在处理太多的特征,因此你必须减少特征数量
-
减少模型的复杂性
-
增加数据量将有所帮助
一些补充的机器学习领域
机器学习与许多相关领域密切相关,包括人工智能、数据挖掘、统计学、数据科学等。实际上,机器学习是一种多学科领域,并且在某些方面与所有这些领域都有联系。
在本节中,我们将定义一些这些领域,将它们与机器学习的相关性进行类比,并了解它们之间的相似之处和不同之处。总体而言,我们将从机器学习的核心定义开始,将其作为一个包括开发自学习算法的科学领域。我们现在将要讨论的大多数领域要么使用机器学习技术,要么使用机器学习技术的超集或子集。
数据挖掘
数据挖掘是一个通过应用业务规则到(大量)数据集中,分析数据并从中提取洞察的过程。这里的重点是数据和数据的领域。在识别哪些规则相关、哪些不相关的过程中采用了机器学习技术。
| 机器学习与数据挖掘 |
|---|
| 与机器学习的相似之处 |
| 机器学习和数据挖掘都旨在从数据中提取价值。用于机器学习和数据挖掘的大多数工具都是通用的。例如,R 和 Weka 等。 |
人工智能 (AI)
人工智能专注于构建能够模仿人类行为的系统。它已经存在了一段时间,现代人工智能一直在持续发展,现在包括专门的数据需求。在许多其他能力中,人工智能应该展示以下特点:
-
知识存储和表示,以保存所有受调查和调查的数据
-
自然语言处理(NLP)能力,以便能够处理文本
-
推理能力,以便能够回答问题和促进结论
-
能够规划、调度和自动化
-
机器学习,以便能够构建自学习算法
-
机器人和更多
机器学习是人工智能的一个子领域。
| 机器学习与人工智能比较 |
|---|
| 与机器学习的相似之处 |
| 机器学习和人工智能都采用学习算法,在推理或决策时侧重于自动化。 |
统计学习
在统计学习中,预测函数是通过数据样本得出的,并且主要来源于样本数据。在这个过程中,数据的收集、清洗和管理非常重要。统计学与数学非常接近,因为它涉及数据的量化和对数字的操作。
| 机器学习与统计学习比较 |
|---|
| 与机器学习的相似之处 |
| 就像机器学习一样,统计学习也是关于从数据中推断出某些情况下代表经验的能力。 |
数据科学
数据科学是将数据转化为产品的过程。它是将分析学和机器学习付诸实践,从数据中得出推论和见解。数据科学被认为是从传统的数据分析知识系统,如数据仓库(DW)和商业智能(BI),到大数据的各个方面的一个第一步,这些系统考虑了大数据的所有方面。
数据科学生命周期包括从数据可用性/加载到推导和传达数据洞察,直至将过程投入运营的步骤,而机器学习通常是这个过程中的一个子集。
| 机器学习与数据科学 |
|---|
| 与机器学习的相似之处 |
| 机器学习和数据科学在问题背景下有一个共同的绑定结果:预测。 |
机器学习过程生命周期和解决方案架构
在本节中,我们将讨论机器学习实现过程和解决方案架构:
-
定义解决方案架构的第一步是定义问题陈述,这包括定义目标、过程和假设。
-
确定这个问题属于哪种问题类型?是分类、回归还是优化问题?
-
选择一个将用于衡量模型准确性的指标。
-
为了确保模型能够很好地处理未见过的数据:
-
使用训练数据构建模型。
-
使用测试数据调整模型。
-
根据最终版本声明准确性。
-
以下图解释了底层系统的流程和架构:

机器学习算法
现在,让我们看看重要的机器学习算法以及关于每个算法的一些简要细节。每个算法的深入实现方面将在后面的章节中介绍。这些算法要么根据问题类型,要么根据学习类型进行分类。给出了算法的简单分类,但它是直观的,并不一定是详尽的。
有许多方法可以对机器学习算法进行分类或分组,在这本书中,我们将使用基于学习模型的分组方法。从第第五章开始,我们将涵盖一个或多个学习模型及其相关算法。以下的概念模型描述了学习模型的列表:

基于决策树的算法
基于决策树的算法定义了基于提供的数据迭代或递归构建的模型。基于决策树的算法的目标是在给定一组输入变量的情况下预测目标变量的值。决策树通过基于树的方法帮助解决分类和回归问题。在树结构中,决策分支直到对给定记录做出预测决策。以下是一些算法:
-
随机森林
-
分类和 回归树(CART)
-
C4.5 和 C5.0
-
卡方检验
-
梯度 提升机(GBM)
-
卡方自动 交互 检测(CHAID)
-
决策树
-
多元自适应 回归样条(MARS)
基于贝叶斯方法的算法
贝叶斯方法是那些明确应用贝叶斯推理定理并再次解决分类和回归问题的方法。贝叶斯方法促进了建模中的主观概率。以下是一些基于贝叶斯的算法:
-
简单贝叶斯
-
平均 一依赖 估计器(AODE)
-
贝叶斯信念 网络(BBN)
基于核方法的算法
当我们听到核方法时,首先想到的是支持向量机(SVM)。这些方法通常是一组方法本身。核方法关注模式分析,正如前几节所解释的,模式分析的核心包括各种映射技术。在这里,映射数据集包括向量空间。以下是一些基于核方法的学习算法的例子:
-
支持向量机(SVM)
-
线性判别分析(LDA)
聚类方法
聚类,就像回归一样,描述了一类问题和一类方法。聚类方法通常按建模方法组织,如基于质心的和层次化的。这些方法通过评估输入数据结构中的相似性来组织数据成组:
-
K-均值
-
期望 最大化(EM)和高斯 混合模型(GMM)
人工神经网络(ANN)
与核方法类似,人工神经网络再次成为一类模式匹配技术,但这些模型是受生物神经网络结构的启发。这些方法再次用于解决分类和回归问题。它们与深度学习建模相关,并且有许多子算法领域,有助于解决特定上下文中的问题。
这个类别中的一些方法包括:
-
学习 向量 量化(LVQ)
-
自组织 映射(SOM)
-
跳频网络
-
感知机
-
反向传播
维度约简
与聚类方法一样,降维方法以迭代和无监督的方式在数据结构上工作。给定数据集和维度,更多的维度意味着在机器学习实现中需要做更多的工作。想法是迭代地减少维度,并将更多相关的维度向前推进。这种技术通常用于简化高维数据,然后应用监督学习技术。以下是一些降维方法的示例:
-
多维 尺度 (MDS)
-
主成分 分析 (PCA)
-
投影 追踪 (PP)
-
偏最小 二乘 (PLS) 回归
-
Sammon 映射
集成方法
如其名所示,集成方法包括多个独立构建的模型,这些模型的输出被组合并负责整体预测。确定要组合或包含哪些独立模型,如何组合结果以及如何实现所需结果的方式是至关重要的。组合的模型子集有时被称为较弱模型,因为这些模型的结果在独立情况下不需要完全满足预期结果。这是一类非常强大且广泛采用的技术。以下是一些集成方法算法的示例:
-
随机森林
-
Bagging
-
AdaBoost
-
自举聚合(Boosting)
-
堆叠泛化(blending)
-
梯度 提升机 (GBM)
基于实例的学习算法
实例不过是数据集的子集,基于实例的学习模型在识别的实例或对问题至关重要的实例组上工作。实例之间的结果会被比较,这可以包括新数据的一个实例。这种比较使用特定的相似度度量来找到最佳匹配并进行预测。基于实例的方法也被称为基于案例或基于记忆的学习。在这里,重点是实例的表示和实例之间比较的相似度度量。以下是一些基于实例的学习算法的示例:
-
k-最近 邻 (k-NN)
-
自组织
-
学习 向量 量化 (LVQ)
-
自组织 映射 (SOM)
基于回归分析的算法
回归是一个基于模型产生的误差进行迭代优化的过程。回归也被用来定义机器学习问题类型。回归中的一些示例算法包括:
-
普通最小二乘线性回归
-
逻辑回归
-
多元自适应回归样条 (MARS)
-
步进回归
基于关联规则的机器学习算法
考虑到变量,基于关联规则的机器学习算法提取并定义可以在数据集上应用并展示基于经验学习的规则,从而进行预测。这些规则在多维数据环境中关联时,在商业环境中也可能很有用。以下是一些基于关联规则的算法示例:
-
Apriori 算法
-
Eclat 算法
机器学习工具和框架
机器学习在技术和商业组织中迅速普及。每个组织都在积极制定战略,以利用他们的数据,并利用它来增强客户的体验和建立新的业务。当涉及到机器学习的工具或框架时,市场上有很多开源和商业选项。新一代的工具都是构建来支持大数据、分布式存储和并行处理的。在下一章中,我们将介绍机器学习环境中处理大规模数据的一些方面。
在非常高的层面上,机器学习工具有三代。
第一代机器学习工具主要关注提供丰富的机器学习算法和深度分析支持。这些工具并非专为处理大规模数据或支持分布式存储和并行处理而构建。其中一些工具由于支持垂直扩展,仍然可以处理大量数据。属于这一类别的工具包括 SAS、SPSS、Weka、R 等。尽管如此,现在大多数这些工具都在升级以支持大数据需求。
第二代工具专注于支持大数据需求,其中大多数在 Hadoop 平台上运行,并提供在 MapReduce 范式下运行机器学习算法的能力。属于这一类别的工具包括 Mahout、RapidMiner、Pentaho 和 MADlib。其中一些工具不支持所有机器学习算法。
第三代工具是道路上的聪明孩子,打破了批量操作的传统规范,支持实时分析,提供对大数据高级数据类型的支持,同时支持更深入的统计分析。属于这一类别的工具包括 Spark、HaLoop 和 Pregel。
在第四章《机器学习工具、库和框架》中,我们将介绍一些关键的机器学习工具,并展示如何根据问题的上下文使用它们。对于 R、Julia、Python、Mahout 和 Spark 等工具的实现细节将进行深入探讨。还将提供所需的技术入门和安装或设置相关的指导。
摘要
在本章中,它构成了本书其余章节的基础,我们介绍了机器学习的基础知识和机器学习语义的格局。我们首先用简单的术语定义了机器学习,并介绍了机器学习的术语或常用术语。
机器学习领域中有许多相互竞争和补充的分支。我们已经详细解释了机器学习与人工智能、数据挖掘、数据科学和统计学等领域的相似性、差异以及它们之间的关系。总体而言,所有这些领域都非常相似,并且具有重叠的目标。在大多数情况下,这些领域的从业者各不相同。即使在使用的工具方面,也存在许多共同点。
我们还研究了机器学习中可以使用的最新和最优秀的工具。其中一些工具将在使用实际例子的章节中进行演示。
在下一章中,我们将探讨机器学习的一个独特方面,这个方面在很大程度上改变了人们看待机器学习实现的方式。我们将探讨大数据或大型数据集的方面如何影响了工具选择和实现方法的选择。
第二章. 机器学习和大规模数据集
在最近过去,随着大数据的出现,数据处理的方式发生了戏剧性的变化。机器学习领域已经看到需要包括扩展策略来处理新时代的数据需求。这实际上意味着在大数据的背景下,一些传统的机器学习实现将不再相关。现在,基础设施和调整需求是挑战,需要存储和处理大规模数据,并辅以数据格式复杂性。
随着硬件架构的演变,更便宜且具有分布式架构的硬件的可用性以及新的编程范式以简化并行处理选项,这些现在可以应用于许多学习算法,我们看到对扩展机器学习系统的兴趣正在上升。
本章深入探讨了以下主题:
-
大数据简介和大规模机器学习的典型挑战
-
扩展和扩展机器学习的动机,以及针对大型数据集的并行和分布式处理概述
-
并发算法设计概述、大 O 符号和任务分解技术以实现并行性
-
云框架的出现,提供云集群、分布式数据存储、容错和高可用性,以及有效利用计算资源
-
实施大规模机器学习的框架和平台选项(例如在大规模并行处理(MPP)、MRI、GPU、FPGA 和多核平台上的并行处理框架)
大数据和大规模机器学习的背景
在我之前出版的 Packt 书籍《Greenplum 大数据分析入门》中,我已经涵盖了大数据的一些核心方面。在本节中,我们将快速回顾大数据的核心方面及其在机器学习领域的影响:
-
大规模的定义是千兆字节、太字节、艾字节或更高的规模。这通常是传统数据库引擎无法处理的数据量。以下图表列出了表示数据量的数量级:
字节倍数 国际单位制十进制前缀 名称(符号) Kilobyte (KB) Megabyte (MB) Gigabyte (GB) Terabyte (TB) Petabyte (PB) Exabyte (EB) Zettabyte (ZB) Yottabyte (YB) -
在此背景下提到的数据格式是独特的;它们被生成和消费,不需要结构化(例如,DBMS 和关系型数据存储)。现在,有新的数据来源;这些数据可以由社交网站、设备等生成。这可以是异构的流数据(例如,视频、电子邮件、推文等)。再次强调,今天没有任何传统的数据集市/数据存储和数据挖掘应用支持这些格式。
-
此外,所有大规模处理总是批量进行的,但现在我们看到需要支持实时处理能力。新的Lambda 架构(LA)解决了支持批量数据和实时数据摄取及处理的需求。
-
总体而言,响应时间窗口正在缩小,这增加了挑战。
让我们回顾一下大数据的四个关键特征。所有这些都需要特殊的工具、框架、基础设施和能力:
-
更高的数据量(达到 PB 级别)
-
数据的可用性/可访问性需求(更实时)
-
多样化的数据格式
-
未标记数据的增加,因此产生了噪声
![大数据和大规模机器学习的背景]()
功能性 vs 结构性 – 方法论上的不匹配
我们甚至无法想象五年前,关系型数据库或非关系型数据库如对象数据库将只成为单一类型的数据库技术,而不是数据库技术本身。互联网规模的数据处理改变了我们处理数据的方式。
新一代架构,如 Facebook、Wikipedia、Salesforce 等,建立在原则和范式上,这些原则和范式与当前数据管理技术发展的稳固理论基础截然不同。
商品化信息
苹果应用商店、SaaS、普适计算、移动性、基于云的多租户架构在商业层面上释放了商品化信息传递的能力。这种模式几乎改变了所有的架构决策——我们现在需要从“可以提供并作为服务计费的信息单元”的角度来思考,而不是从解决方案的总拥有成本(TCO)的角度来思考。
RDBMS 的理论局限性
如有影响力的数据库理论家迈克尔·斯坦纳布雷克最近所写,互联网规模架构的核心是一个新的数据处理和管理理论模型。数据库管理的理论现在已有三十多年历史,它们是为大型机类型的计算环境和不可靠的电子组件设计的。自然和系统及应用的特性自那时起已经发生了显著变化。随着可靠性成为底层环境的质量属性,系统由并行处理核心组成,数据创建和使用的性质也经历了巨大的变化。为了概念化这些新环境下的解决方案,我们需要从计算的角度来设计解决方案架构,而不仅仅是工程角度。
当前推动数据革命六大主要力量是:
-
大规模并行处理
-
通用信息传递
-
普遍计算和移动设备
-
非关系型数据库和语义数据库
-
社区计算
-
云计算
Hadoop 和 MapReduce 在巨规模上释放了数据的并行处理能力,并将程序平台中的复杂计算算法化。这永远地改变了分析和商业智能。同样,基于 Web 服务和 API 驱动的架构使信息传递在巨大规模上实现了通用化。
现在,可以以这种方式构建非常大的系统,即每个子系统或组件本身就是一个完整的平台,由完全不同的实体托管和管理。
迪杰斯特拉曾有过一个深刻的见解:
"计算机科学并不比天文学需要望远镜更多,天文学并不比望远镜需要天文学"
他今天可能会感到高兴,因为计算已经摆脱了个人计算机(也称为工作站和服务器)的束缚。我们今天的大部分信息消费都来自我们几乎不称之为计算机的设备。移动设备、可穿戴设备和无处不在的信息正在改变数据创建、组装、消费和分析的方式。
随着传统数据库局限性的暴露,近年来,许多专用数据库应运而生——内存数据库、列式数据库、图数据库和语义存储现在都可在商业上获得。
之前提到的创新完全改变了传统的数据架构。特别是,语义计算、基于本体论的信息建模彻底颠覆了数据设计。从哲学上讲,数据架构正在经历事实基础的转变。在传统的数据模型中,我们首先设计“数据模型”——这是对世界及其未来的固定、设计时理解。数据模型将数据的含义永久固定在固定的结构中。表不过是一个类别,一组事物。因此,数据必须意味着如果我们理解它所属的集合/类别。例如,如果我们把汽车处理系统设计成一些类别,如四轮车、两轮车、商用车辆等,那么这种划分本身就嵌入了一个相关的意义。存储在每个这些类别中的数据并没有揭示嵌入在类别设计方式中的设计目的。例如,另一个系统可能会从驱动方式——电动、石油驱动、核驱动等——的角度看待汽车世界。
这种分类本身以某种方式揭示了系统的目的,这是无法从任何单个记录的属性中获得的。语义和元数据驱动架构可以彻底颠覆这样的数据模型。在元数据模型中,首先存在的是对象。
在基于关系型数据库管理系统(RDBMS)的存储系统中,数据存储和管理的一些核心特性如下:
-
数据存储在通常由行和列特征化的表中
-
表通过数据属性之间的关系相互链接
-
它以其效率和灵活性而闻名
-
这支持了减少数据重复的规范化技术
另一方面:
-
元数据驱动/NoSQL/语义数据架构不受限制数据使用目的的关系束缚
-
重点是更多地适应业务需求的持续变化,这导致构建的软件系统变化最小
-
支持使用分布式存储技术处理大型数据集,降低存储成本在元数据驱动/NoSQL/语义数据架构中非常重要
扩容与扩展存储
随着大数据时代的到来,现在需要扩展数据存储设备以存储达到拍字节级的数据。扩展存储设备有两种方式:
-
扩容(垂直可扩展性)
-
扩展(水平可扩展性)
扩容或垂直可扩展性是指向现有系统添加更多资源,从而增加存储更多数据的能力。在这里,资源可以指 RAM、计算能力、硬盘驱动器等。
向外扩展或水平可扩展性是指向系统中添加新组件。这需要数据被存储和分发,并且存在可以并行化的任务。这通常会增加系统的复杂性,并且大多数情况下需要重新设计系统。
所有的大数据技术都在基础设施的向外扩展上工作并支持。

| 向上扩展(垂直可扩展性) | 向外扩展(水平可扩展性) |
|---|---|
| 较低容量和容量较高的服务器 | 更多和适中的,或低容量服务器 |
| 可能存在一个阈值,超过这个阈值,基础设施将无法垂直扩展 | 没有上限,基础设施可以根据需要扩展,而不会对设计产生影响 |
| 可以容纳更大的虚拟机 | 使用较低的虚拟机,并且可能受到主机故障的影响 |
| 所有共享的数据架构 | 无共享数据架构 |
| 较高总拥有成本 | 相对较低且可变成本 |
| 较低的网络设备 | 需要相对较多的设备(路由器、交换机等) |
分布式和并行计算策略
尽管分布式和并行处理已经存在多年,但随着对成本效益解决方案所需可用性优先级的出现,这些策略已成为机器学习任务的关键。
下面的图解展示了弗林分类法。分类是基于数据流数量与指令流数量的比较。

-
单指令单数据(SISD):这是一个没有数据或指令并行的单个处理器的例子。单个指令以顺序方式在单个数据上执行,例如,单处理器。
-
多指令单数据(MISD):在这里,多个指令在一个数据流上操作;一个典型的例子可以是容错性。
-
单指令多数据(SIMD):这是一个自然并行的例子;单个指令触发对多个数据流的操作。
-
多指令多数据(MIMD):这是一个多个独立指令在多个独立数据流上操作的例子。由于数据流是多个的,内存可以是共享的或分布式的。分布式处理可以归类在这里。前面的图示描绘了 MIMD 及其在“分布式”环境中的变化。
下面的图解解释了并行处理器架构和分类:

并行/分布式处理系统的关键需求之一是高可用性和容错性。有几种编程范式可以实现并行性。以下列表详细说明了重要的几个:
-
主/从模型:主模型是工作保持和随后分发给从属者的驱动器。Pivotal Greenplum 数据库和 HD(Pivotal 的 Hadoop 发行版)模块实现了这种模式。
-
生产者/消费者模型:在这里,没有所有者来触发工作。生产者生成工作项,消费者订阅并异步执行。基于企业服务总线(ESB)的数据集成系统实现了这种模式。

理论上,有两种类型的并行化;一种是数据并行化,另一种是执行或任务并行化:
-
数据并行化:它涉及并行运行具有多个输入的相同计算。在机器学习领域,这是一个我们考虑在不同数据样本上运行相同算法,而不真正关心数据样本如何分布的情况。
-
执行或任务并行化:与数据并行化不同,这是将功能分解成多个部分并以并行方式运行。这些工作部分可能处理相同的数据集,但这仅适用于可以并行化且子任务之间没有依赖关系的任务。
任务并行化可以是细粒度或粗粒度。
有许多分布式平台选项可以将效率扩展到机器学习算法并处理大数据集。一些选项包括:
-
现场可编程门阵列(FPGA)
-
图形处理单元(GPU)
-
高性能计算(HPC)
-
多核和多处理器并行系统
-
为虚拟大规模集群的云基础设施
除了可用的多个平台选项外,还有其他广泛采用的框架,它们提供了构建机器学习算法的即插即用 API。这个框架的选择特别取决于硬件的选择。
重要的是我们要选择一个能够充分利用现有架构、适合学习算法和数据结构选择的选项。
机器学习:可扩展性和性能
机器学习算法可以通过两种重要方式扩展:
-
采样
-
基于并行处理的分布式系统
可以并发执行给定的学习算法作为单独的工作块,并合并结果。这听起来像是一种相当简单的并行化方式,能够在更大的数据集上实现扩展和良好的性能。这假设数据集是离散的,并且这些分布式数据集之间没有依赖关系。
由于数据源的激增,我们现在可以访问已经分布的大型数据集,这需要我们具备在分布式模式下运行学习算法的能力。
现在有许多用于机器学习的分布式和并行框架的选项。让我们看看这些平台之间的一些关键区别因素:
-
并行化的粒度程度是一个关键方面。支持细粒度与粗粒度并行化是指什么。较低的粒度定义了细粒度任务并行化,而较高的粒度定义了粗粒度任务并行化。
-
算法定制支持的程度。
-
支持混合各种编程范式。
-
数据集扩展的容易程度。
-
支持批处理和实时处理的程度。
在给定的问题背景下,平台和编程框架的选择应受先前标准的指导。
以下是一些关键指标,用于衡量并行算法的计算性能:
-
性能是顺序算法与并行处理之间的解决方案时间的比率
-
效率或吞吐量衡量的是多个处理器之间性能的比率
-
可扩展性是随着处理器数量的增加,效率提高的百分比
下一节将介绍机器学习问题的一些关键特性,这些特性促使我们扩展机器学习算法。
数据点或实例过多
我们现在看到,在大多数机器学习问题中,数据集非常丰富,在许多情况下,所有这些数据点在模型构建和细化中都是相关的。这些数据点可能达到太字节规模,并且具有所有相关性。
这就引出了支持分布式存储和集群中处理这些数据点的带宽的需求。这里使用的是具有运行并行编程语言范式(如 MapReduce 和 LINQ)能力的高容量存储系统。
属性或特征过多
构成构建模型输入的数据集可能包含过多的特征、属性或维度。在这种情况下,机器学习算法将相关或更相关的属性分组,并在迭代中运行算法。这类数据集在文本挖掘和自然语言处理(NLP)的情况下可以见到,其中特征的数量可能达到数百万的倍数。在这种情况下,通过消除无关特征的方式并行化跨特征的计算可以有效地解决问题。随机森林和决策树是一些例子。此外,一些特定的特征选择技术,如正则化方法,将在后续章节中介绍。
缩小响应时间窗口 - 需要实时响应
某些机器学习需求,如语音识别,将要求系统提供实时响应。在这些应用中,机器学习实现的响应时间至关重要,否则响应本身将变得无关紧要。并行化可以带来这种效率。
模型的延迟和性能问题比吞吐量问题更重要。在许多用例中,这种推理延迟可能会使模型本身失效,因为响应变得过时。
对于这类问题,高度并行化的硬件架构,如 GPU 或 FPGA,将非常有效。
高度复杂的算法
这是一个选择算法本身就很复杂的情况,例如,计算密集型函数或任何非线性模型。以文本或图像内容为例;它本质上是非线性的。这种复杂性可以通过分布式计算轻松解决。
我们有多种方法可以解决这个问题,其中一种方法是优先考虑特征,并仍然追求更高的准确性。然而,这将消除学习中的自动化部分。在运行算法之前,总需要有一个工程师特征的过程。
在数据复杂性更高的情况下,存在计算复杂性。除非平台进行扩展,否则没有方法可以使学习过程运行得更快。
多核和 GPU 系统非常适合这种需求。它们带来了存储规模和计算效率的双重优势。
前馈,迭代预测周期
在机器学习领域有一些独特的用例,它们不会停止在算法执行的一个级别。算法是迭代和顺序运行的,其中一次迭代的输出会输入到另一个迭代中。这对于模型的输出至关重要。还可能需要合并所有顺序运行的迭代的推断。这可以使模型执行过程相当复杂。我们可以将推断过程视为一次性的过程,这将增加计算成本,或者可以有单个任务的并行化阶段。
一些现实世界的例子包括:
-
语音识别
-
机器翻译
模型选择过程
在某些情况下,我们需要在相同的训练和测试集上运行多个模型,这些模型的特征优先级不同,并比较准确性以选择给定问题域的适当模型。这些试验可以并行运行,因为这些模型之间没有任何依赖关系。当我们必须调整学习算法的参数并在多次执行中进行评估以从学习中进行推断时,复杂性会增加。
由于执行之间没有依赖关系,这使得它高度可并行化,并且不需要交互通信。这个用例的一个例子是统计显著性测试。对于这些任务,并行平台的有用性很明显,因为它们可以很容易地并发执行,而无需并行化实际的学习和推理算法。
大规模机器学习中的潜在问题
让我们看看在大规模机器学习实现中可能遇到的一些潜在问题:
-
并行执行:管理并行执行的准确性需要特别的关注和不同的设计范式。
-
负载均衡和管理偏差:随着数据和执行现在分布并行运行,管理数据和计算偏差变得非常迫切。不需要任何单个节点承担相对更多的数据存储或计算。
-
监控:需要放置各种硬件的有效监控和自动恢复系统。
-
容错性:一个万无一失的故障转移和恢复系统是强制性的。
-
自动扩展:扩展和升级过程是自动的。
-
作业调度:需要安排批处理作业。
-
工作流管理:协调和监控集群节点间工作执行的过程编排和编排。
算法和并发
在我们开始讨论在执行算法中构建并发性之前,让我们先看看算法的一些基础知识,时间复杂度;以及量级测量,然后探索并行化算法的方法。
一个算法可以被定义为一系列步骤,它将输入转换为所需的输出。它们是无关技术表示;让我们看看一个排序算法的例子:
Input: A sequence of *n* number—*a1, a2, …,an*
Output: A permutation (reordering)—*a1', a2', …,an'* such that *a1'<=a2'<=… <=an'*
以下是一个插入排序算法:
INSERTION-SORT(A)
1\. for j = 2 to length[A]
2\. dokey<-A[j]
3\. //insert A[j] to sorted sequence A[1..j-1]
4\. i<-j-1
5\. while i>0 and A[i]>key
6\. do A[i+1] <- A[i] //move A[i] one position right
7\. i<-i-1
8\. A[i+1]<-key
对于测量算法的时间和空间复杂度,一个元素是输入大小。时间复杂度是算法对于定义的需求“足够快”的度量;更重要的是,当数据量增加时,算法将如何反应。
频率计数是算法的一个关键度量。它是对算法的每个指令在执行过程中将运行多少次的预测。例如:
| 指令 | 代码 | 频率计数 (FC) |
|---|---|---|
| 1 |
for (int i=0; i< n ; i++)
| n+1 |
|---|
| 2 |
count << i
| N |
|---|
| 3 |
p = p + 1
| N |
|---|
| 4 |
FC 度量在未考虑相对性能与体积的关系时相对没有意义。还有一个叫做“量级”的度量,它是性能与数据体积的估计。Big-O是算法性能随所需处理的数据量增加而下降的速率的度量。
例如,O(n)代表线性性能下降,而O(n²)代表二次性能下降。
开发并发算法
开发并行算法的第一步是将问题分解为可以并发执行的任务。给定的问题可以以多种不同的方式分解为任务。任务可以是相同或不同的大小:
任务依赖图是一个有向图,节点对应任务,边表示一个任务的结果是处理下一个任务所必需的。
示例:这是数据库查询处理。
考虑以下查询的执行:
MODEL = ``CIVIC'' AND YEAR = 2001 AND (COLOR = ``GREEN'' OR COLOR = ``WHITE)
在以下数据库上:

可以有细粒度和粗粒度任务分解。随着分解变得更加精细,并发度增加。
存在许多分解技术,并没有一种单一的最好方法。以下是一些技术:
-
递归分解
-
数据分解
-
探索性分解
-
投射性分解
分解会产生多个任务,这些任务的一些特性会严重影响并行算法的性能。这些特性包括任务交互(任务间通信)、每个任务处理的数据大小以及任务大小。在设计并行执行算法时需要考虑的一些重要方面包括以最小化交互和处理粒度权衡的方式解耦任务。
扩展机器学习的技术和实现选项
在本节中,我们将探讨一些机器学习实现可以采用的并行编程技术和分布式平台选项。Hadoop 平台将在下一章介绍,我们将从第三章,Hadoop 架构和生态系统的介绍,以及一些实际例子开始探讨一些实际例子。
MapReduce 编程范式
MapReduce 是一种并行编程范式,它抽象了分布式计算环境中的并行计算和数据复杂性。它基于将计算函数带到数据而不是将数据带到计算函数的概念。
MapReduce 更像是一个带有许多内置函数的编程框架,开发者无需担心构建,可以减轻许多实现复杂性,如数据分区、调度、异常管理和跨系统通信。
下图展示了 MapReduce 函数的典型组成:

MapReduce 最初由 Google 设计并采用,作为在具有并行处理分布式存储的集群上处理大型数据集的编程模型。
MapReduce 模式现在已经成为行业标准,许多平台都是基于这个模式内部构建的,并支持 MapReduce 实现。例如,Hadoop 是一个开源实现,可以在内部运行或在云计算服务上运行,例如,Amazon EC2 配备弹性 MapReduce。
这在核心上具有 Map() 和 Reduce() 函数,这些函数能够在集群的节点上并行运行。Map() 函数在分布式数据上工作,并行运行所需的功能,而 Reduce() 函数运行数据的汇总操作。
使用消息传递接口(MPI)进行高性能计算(HPC)
MPI 被设计用来提供访问高级并行硬件的能力,旨在与异构网络和集群一起工作。这是一个令人印象深刻的规范,提供了一种可移植的方式来实现并行程序。
消息传递是发送者和接收者之间数据传输和同步的过程。以下图展示了发送者和接收者之间的消息传递:

这些过程可以被分组;发送者和接收者之间的消息共享需要在相同上下文中发生。因此,通信者是一个组合了组和上下文的概念。消息中的数据以三元组的形式发送或接收。
MPI 可以用于实现可移植性,并通过并行处理提高性能。它可以支持独特的数据结构,并且可以构建库以供重用。MPI 不支持宽松的错误容忍。
语言集成查询(LINQ)框架
LINQ 框架是一个用于大规模数据和并行计算的一般用途系统。类似于 MapReduce 模式,它附带基础实现的高层次抽象,有助于开发者减少并行和分布式执行的开发复杂性。
随着机器学习函数从通用数据处理中移出,并在包括文档、图像和图在内的多种数据类型上操作,对通用实现模式的需求正在增加。此框架仅适用于 .NET 语言。
使用 LINQ 操作数据集
LINQ 随带一套在 .NET 对象集合上操作的功能。这些集合通过包含 .NET 数据类型的 LINQ 函数被修改。

图形处理单元(GPU)
GPU 是设计用来处理内存需求并在帧缓冲区中快速创建用于视觉显示的图像的电子电路。
GPU 一直支持不断增长的计算能力。它们最初是用来处理图像处理和渲染的,但先进的 GPU 现在被视为自包含的通用计算平台。
虽然 CPU 旨在在异构工作负载上表现良好,但 GPU 是为确保大量数据集的可用性而构建的,并且以并行方式运行的任务。

GPU 主要用于深度学习和训练可能需要更大训练数据集、较少计算能力和存储空间优化的神经网络。它们被用于解决云中的分类和预测问题。大多数社交媒体公司都曾是 GPU 的早期采用者。
注意
使用 GPU,预先录制的语音或多媒体内容可以转录得更快。与 CPU 实现相比,我们能够以高达 33 倍的速度进行识别。
场可编程门阵列(FPGA)
FPGAs 正在 HPC(高性能计算)的许多领域崭露头角。FPGA 可以在大规模并行处理的环境中应用。在本节中,我们将探讨理解 FPGA 的一些架构和实现方面的内容。
已知 FPGA 提供高性能。它们支持不同的并行计算应用。它们具有片上内存,便于处理器轻松访问内存。最重要的是,内存与算法逻辑相耦合,这意味着我们不需要任何额外的快速内存。

FPGA 包含大量的可配置逻辑块(CLB);这些 CLB 通过可编程接口连接,传递它们之间的信号。I/O 块是 CLB 与外部世界的连接点。
FPGAs 提供各种范式,有助于加速硬件和软件设计中的计算。FPGA 具有成本效益,并且硬件资源以最佳方式使用。IBM Netezza 利用 FPGA 架构。
多核或多处理器系统
多处理器系统通常具有多个 CPU,这些 CPU 不一定在同一个芯片上。新一代的多处理器位于同一物理板上,通信通过高速连接接口进行。

多核处理器代表了一类处理器,可能在一个芯片上包含许多 CPU(例如两个、四个和八个。在多核系统中,多线程实现的效率取决于代码的并行程度)。
除了所有硬件和基础设施的进步之外,我们刚刚看到,基于其能够在最佳成本下扩展机器学习过程的能力,云框架在机器学习领域正获得相当大的关注。
随着云计算的出现,基础设施服务提供商,如亚马逊网络服务(Amazon Web Services),提供基于使用情况付费的、几乎无限的按需计算能力。
摘要
在本章中,我们探讨了大数据集的限定条件、它们的共同特征、重复的问题以及数据量超高速增长的原因;实际上,这是大数据的背景。
将传统机器学习算法应用于大数据集的需要为机器学习从业者带来了新的挑战。传统的机器学习库并不完全支持处理大规模数据集。使用现代并行计算框架,如 MapReduce,进行并行化已经变得流行并被广泛采用;这导致了基于这些框架的新库的诞生。
重点关注适合大规模数据的方法,并且具有并行实施的潜力。在过去十年中,机器学习应用领域的格局发生了巨大变化。仅仅增加机器并不总是能证明是一个解决方案。需要重新审视传统算法和模型在执行方式上的问题,因为现在机器学习技术研究的另一个维度是可扩展性、并行执行、负载均衡、容错性和动态调度。
我们还研究了在大数据集背景下出现的并行化和分布式架构和框架,并理解了扩展机器学习的需求。此外,我们还回顾了一些并行和分布式平台技术,如 MapReduce、GPU、FPGA 等在机器学习中的应用。
在下一章中,我们将探讨 Hadoop 是如何成为大规模机器学习最佳平台的。
第三章。Hadoop 架构和生态系统的介绍
从本章开始,我们将探讨机器学习的实现方面。让我们开始学习选择平台——一个可以扩展到高级企业数据需求(特别是机器学习的具体大数据需求)的平台——Hadoop。
在本章中,我们介绍了 Hadoop 平台及其在解决机器学习大规模加载、存储和处理挑战方面的能力。除了对 Hadoop 架构、其核心框架以及其他支持生态系统组件的概述外,还包括了一个详细的安装过程和示例部署方法。尽管有许多商业版的 Hadoop,但本章的重点是介绍开源的 Apache Hadoop 发行版(最新版本 2.x)。
在本章中,以下主题将进行深入探讨:
-
Apache Hadoop 的介绍,其演变历史,核心概念以及构成 Hadoop 的生态系统框架
-
Hadoop 发行版和特定产品
-
Hadoop 环境的安装和设置
-
Hadoop 2.0——HDFS 和 MapReduce(也称为 YARN(另一个资源协调器))架构,以及使用架构的不同组件的示例实现场景
-
理解核心生态系统组件的目的,设置并学习使用示例构建和运行程序
-
探索针对机器学习特定生态系统扩展,如 Mahout 和 R Connectors (第四章,机器学习工具、库和框架,涵盖了实现细节)
Apache Hadoop 简介
Apache Hadoop 是 Apache 软件基金会的一个基于 Java 的开源项目。该软件的核心目的是提供一个可扩展、可扩展和容错的平台,用于分布式存储和处理大数据。请参阅 第二章,机器学习和大规模数据集,了解更多关于哪些数据可以被视为大数据的信息。以下图像是 Hadoop 的标准标志:

其核心是利用节点集群,这些节点可以是商用服务器,并促进并行处理。Hadoop 这个名字是由其创造者 Doug Cutting 取的,他以自己孩子的黄色填充玩具大象命名。到目前为止,Yahoo! 是最大的贡献者和 Hadoop 的广泛使用者。有关 Hadoop 的更多详细信息、其架构和下载链接,请访问 hadoop.apache.org/。
Hadoop 是大数据的行业标准平台,它为市场上所有流行的机器学习工具提供了广泛的支持。该平台现在被微软、谷歌、Yahoo!和 IBM 等几家大型公司使用。它还被用来解决特定的机器学习需求,如情感分析、搜索引擎等。
以下章节涵盖了 Hadoop 平台的一些关键特性,使其在大型数据存储和处理能力方面效率极高。
Hadoop 的发展(首选平台)
以下图(来源 Cloudera Inc.)解释了 Hadoop 平台的发展历程。从 2002 年 Doug Cutting 和 Mike Cafarella 开始,旨在构建一个可高度扩展的、开源的、可扩展的、运行在多台机器上的搜索引擎。在这个演变阶段的一些重要里程碑包括 Google 在 2003 年 10 月发布的Google 文件系统(GFS),随后在 2004 年 12 月发布的 MapReduce 框架,它演变成了核心框架 HDFS 和 MapReduce/YARN。
另一个重要的里程碑发生在 2008 年 2 月左右,当时 Yahoo 贡献并采用了 Hadoop 的生产版本,该版本在超过 10,000 个 Hadoop 集群节点上实现了搜索索引。以下表格描述了 Hadoop 的发展历程:

Hadoop 及其核心元素
以下概念图描绘了 Hadoop 平台的核心元素和方面:

大数据机器学习解决方案架构(采用 Hadoop)
在本节中,让我们看看在考虑大数据需求时实施机器学习解决方案的基本架构组件。
建议的解决方案架构应支持以高效且经济的方式消费各种数据源。以下图总结了可能成为机器学习解决方案技术栈一部分的核心架构组件。框架的选择可以是开源或打包许可选项。在本书的背景下,我们考虑了开源(Apache)Hadoop 及其生态系统组件的最新版本。
注意
本章不涉及特定供应商的框架和扩展。

在接下来的章节中,我们将详细讨论这些参考架构层以及每一层所需的框架。
数据源层
数据源层是机器学习参考架构的关键部分。有许多内部和外部数据源形成了解决机器学习问题的输入。这些源可以是结构化、非结构化或半结构化的。此外,在实时、批量或近实时模式下,它们需要无缝集成和汇总,以便用于分析引擎和可视化工具。
在将数据摄取到系统中进行进一步处理之前,去除数据中的无关或噪声是很重要的。可以应用一些独特的技术来清理和过滤数据。
这些综合数据集在大数据和数据聚合环境中也被称为数据湖。Hadoop 是数据湖选择的存储选项之一。
以下图表显示了构成主要输入源的各种数据源。

数据架构始终被设计来支持一些协议,例如 JMS、HTTP、XML 等。然而,现在,大数据领域的最新进展已经带来了显著的变化。因此,现在的新时代数据源包括来自社交网站的数据流、GPS 数据、用户访问日志等机器生成数据以及其他专有数据格式。
摄取层
数据摄取层负责将来自多个数据源的数据引入系统,其主要责任是确保数据质量。这一层具有过滤、转换、集成和验证数据的能力。选择实施这一层的技术应能够支持高数据量和其他数据特性。以下元模型显示了摄取层组成和功能流程。摄取层可能是一个ETL(提取、转换和加载)能力的架构。
以下列出了摄取层的一组基本要求:
-
从任何源系统以任何方式高速转换数据
-
以最短时间处理大量记录
-
以语义丰富的格式生成输出,以便任何目标系统都可以查询智能数据
摄取层的架构框架需要提供以下能力;以下模型描绘了各种层和组成:
-
适配器框架——任何产品组或应用都应该能够使用适配器框架快速、可靠和程序性地开发连接到不同数据源的连接器(文件、CSV 格式和数据库)
-
一个高速、并行变换执行引擎
-
一个作业执行框架
-
语义化输出生成框架
![摄取层]()
摄取层将相关数据加载到存储层,在我们的当前环境中,这是以文件为基础的存储层 Hadoop 存储层。
下面的概念图列出了摄入核心模式(这些模式针对机器学习架构的性能和可扩展性需求):

-
并行处理和分区模式:处理大量摄入需求的基本架构是并行化执行。并行地对不同输入数据进行转换,并将单个大型输入数据分区成更小的批次以并行处理,有助于实现并行化。
-
管道设计模式:在设计摄入作业的工作流程时,需要解决一些特定问题,例如避免大型顺序管道以实现并行处理。同样,从数据可靠性角度来看,创建适当的审计和执行日志对于管理整个摄入执行过程非常重要。
-
转换模式:存在不同类别的转换。转换设计的主要方面之一是处理依赖关系。在第一类(并行化)中提到的模式也处理依赖需求。其他问题与对过去和历史数据的依赖有关,这在处理额外负载时尤其重要。
-
存储设计:在将数据加载到目标数据存储时,存在诸如从失败的转换中恢复或为特定馈送重新加载数据等问题(例如,当应该有一个固定的转换规则时)。
-
数据加载模式:数据摄入过程中最大的性能瓶颈之一是将数据加载到目标数据仓库的速度。特别是当目标是关系型数据库管理系统(RDBMS)时,并行化策略在加载数据时会导致并发问题,从而限制了可能的摄入吞吐量。这些模式展示了实现数据加载并解决加载数据时的性能和并发问题的某些技术。
Hadoop 存储层
机器学习架构具有支持在大型数据上运行分析或重计算的并行处理的分布式存储层。使用分布式存储和并行处理大量数据是企业在处理大数据方面的一种根本性变化。
典型的分布式存储通过并行处理在 PB 级数据上运行的算法,提供容错、可靠性和并行处理能力,从而实现高性能。
在当前的 Hadoop 架构背景下,Hadoop 分布式文件系统(HDFS)是核心存储机制。在本节中,让我们简要了解一下 HDFS 和 NoSQL(非 SQL)存储选项。以下几节将更详细地介绍 HDFS 及其架构。
HDFS 是核心组件之一,充当 Hadoop 的数据库。它是一个跨节点集群存储大规模数据的分布式文件系统。它附带一个框架来确保数据可靠性和容错性。应用程序可以根据大小将文件存储部分或全部,并且它促进了单次写入多次读取。
由于 HDFS 是一个文件系统,对数据的访问或操作并不简单,需要一些复杂的文件操作程序。另一种使数据管理更简单的方法是使用非关系型存储,称为 NoSQL 存储。
以下模型表示各种 NoSQL 数据存储类别,以及每个类别的示例。每个数据存储类别都满足特定的业务需求,了解这些 NoSQL 存储类别的目的对于根据特定需求做出正确的选择非常重要。CAP 定理(代表一致性、可用性和分区容错性)的属性在每种 NoSQL 存储中都有不同程度的满足,从而支持预期适用于这些属性组合的优化存储系统。实际上,这些 NoSQL 存储可能需要与关系型存储共存,因为它们需要一个记录系统来根据需要同步,或者更好的情况是我们需要使用关系型和非关系型数据的组合。
以下图展示了 NoSQL 数据库的类型以及市场上的一些产品:

Hadoop 最初是为了批处理而设计的,其中数据以批量或计划的方式加载到 HDFS 中。通常,存储层的数据是以批量加载的。一些核心和生态系统组件,如 Sqoop、HIHO(Hadoop-in Hadoop-out)MapReduce 函数和 ETL 函数等,有助于数据加载或摄入 HDFS。
Hadoop(物理)基础设施层 - 支持设备
传统架构与大数据(用于机器学习)架构之间的区别在于底层基础设施的重要性。性能、可扩展性、可靠性、容错性、高可用性和灾难恢复是该架构必须支持的一些重要质量属性。平台的基础设施处理这些需求。
Hadoop 基础设施是一个分布式架构或模型,其中数据不是存储在一个地方,而是分布到多个或一组节点上。数据分布策略可以是智能的(如 Greenplum 的情况),也可以是简单的数学方法(如 Hadoop 的情况)。分布式文件系统节点通过网络连接。这被称为无共享架构(SNA),大数据解决方案基于此参考架构。随着数据分布到多个节点,进程在数据节点本地运行。
这首先在 Michael Stonebraker 的论文中被引用,该论文可通过db.cs.berkeley.edu/papers/hpts85-nothing.pdf访问。
存储数据的节点称为数据节点,而处理发生的节点称为计算节点。数据节点和计算节点可以是本地化部署或解耦部署。以下图表示了一个具有本地化数据节点和计算节点的 SNA(无共享架构)环境:

无共享数据架构支持并行处理。冗余是默认期望,因为它处理来自不同来源的各种数据。
Hadoop 和 HDFS 通过网格基础设施连接,通过快速千兆网络或虚拟云基础设施连接,形成了支持大规模机器学习架构的基础设施层。
以下图展示了使用通用服务器设置的大数据基础设施:

Hadoop 平台/处理层
Hadoop 的平台或处理层是机器学习架构工具的核心数据处理层。这一层便于查询或访问存储在 Hadoop 存储层(通常使用 HDFS 存储文件系统的 NoSQL 数据库)中的数据,位于 Hadoop 基础设施层的顶部。
如第二章所述,机器学习与大规模数据集,计算领域的科技进步现在使得处理大量分布式计算和并行处理成为可能。
Hadoop 的 MapReduce 框架有助于高效且低成本地存储和分析大量数据。
Hadoop 平台或处理层的关键组件如下;这些组件是生态系统的一部分,将在本章后续部分详细讨论:
-
MapReduce:MapReduce 是一种编程范式,用于高效地在大量数据上执行函数,通常以批量模式运行。map函数负责将任务分配到多个系统,均匀分配负载并并行管理处理。在后续处理中,reduce函数将元素同化并合并以提供结果。在Hadoop 生态系统组件部分介绍了在 Hadoop 原生 MapReduce 架构、MapReduce v2 和 YARN 上的逐步实现。
-
Hive:Hive 是 Hadoop 的数据仓库框架,负责使用类似 SQL 的函数聚合大量数据。Hive 提供了一种高效的数据存储方式,能够最优地使用资源。Hive 的配置和实现方面在Hadoop 生态系统组件部分进行了介绍。
-
Pig:Pig 是一种简单的脚本语言,它简化了在 HDFS 上查询和操作数据的操作。它内部以 MapReduce 范式运行函数,通常被认为简化了构建 MapReduce 函数的过程。在Hadoop 生态系统组件部分提供了配置、学习语法和构建基本函数的详细逐步指南。
-
Sqoop:Sqoop 是 Hadoop 的数据导入工具,具有内置函数,可以从特定的表、列或整个数据库导入数据到文件系统。在后续处理中,Sqoop 支持从多个关系型数据库和 NoSQL 数据存储中提取数据。
-
HBase:HBase 是一个兼容 Hadoop 的 NoSQL 数据存储(一个列式 NoSQL 数据存储),它使用 HDFS 作为底层文件系统。它支持分布式存储和自动线性可伸缩性。
-
ZooKeeper:ZooKeeper 是一个监控和协调服务,有助于监控 Hadoop 实例和节点。它负责保持基础设施同步,保护分布式系统免受部分故障的影响,并确保数据一致性。ZooKeeper 框架可以独立于 Hadoop 工作。
在接下来的章节中,将深入讨论这些生态系统组件。
分析层
更常见的是,企业拥有一些真正的商业智能(BI)工具,这些工具负责运行一些分析查询并生成一些管理信息系统(MIS)报告或仪表板。现在需要现代机器学习或分析工具和框架与它们共存。现在需要分析可以在传统方式下在数据仓库或可以处理结构化、半结构化和非结构化数据的大数据存储上运行。
在这种情况下,我们可以期待使用像 Sqoop 这样的工具在传统数据存储和大数据存储之间进行数据流。
NoSQL 存储以其低延迟而闻名;它们促进了实时分析。许多开源分析框架简化了模型的构建,并使用简单的开箱即用的函数运行复杂的统计和数学算法。现在所需的是理解每个算法的相关性,以及在给定特定问题时选择合适的算法或方法的能力。
让我们来看看以下列出的开源分析和机器学习框架,在接下来的章节中会有详细介绍。
-
R
-
Apache Mahout
-
Python(scikit-learn 发行版)
-
Julia
-
Apache Spark
本节介绍了即将推出的 Spring 项目之一,称为Spring XD,它看起来像是一个可以在 Hadoop 上运行的全面的机器学习解决方案。
消费层
从分析层或数据处理中产生的洞察力以多种方式被最终客户消费。以下是一些使数据可供消费的方式:
-
服务 API(例如,基于 SOAP 或 REST 的 Web 服务接口)
-
网络应用程序
-
报告引擎和数据集市
-
仪表板和可视化工具
在所有选项中,可视化是核心,它不仅是一种重要的机器学习结果分发或沟通方式,而且是一种以有助于决策的方式表示数据的好方法。很明显,数据可视化正在大数据和数据分析领域获得关注。最能代表数据和其背后模式和关系的可视化是决策的关键。

有两种类型的可视化;一种是为了解释数据,另一种是为了探索数据和其背后的模式。可视化现在被视为一种新的沟通语言。
使用可视化解释和探索数据
用于解释和探索数据的可视化是独特的,用于不同的目的。
用于解释的可视化是我们通常在营销和销售演示中看到的典型可视化。在这种情况下,手头的数据尽可能干净。数据的意义是清晰的,沟通是通过最终决策者完成的。
另一方面,用于探索的可视化有助于纠正数据并连接数据的相关和有用属性,以理解数据本身。探索性的可视化有时可能不准确。探索通常以迭代方式进行,可能需要多次细化可视化,才能从现有数据中得出一些有意义的结论。有时需要去除数据中的某些无关属性,甚至整个数据(被识别为噪声)。使用可视化进行数据探索的这一步骤有时会取代运行复杂的算法,并且通常需要统计敏锐度。
市场上一些流行的可视化工具(包括开源和商业)有 Highcharts JS、D3、Tableau 等。尽管我们使用其中一些框架来展示如何描绘和传达洞察力,但我们并没有深入探讨任何可视化选项。
另一个重要方面是,这些可视化工具通常需要利用传统的数据仓库工具和大数据分析工具。以下图展示了所提出的机器学习架构如何支持现有数据仓库或 BI 工具与大数据分析工具共存。正如在第一章中所述,“机器学习简介”,聚合数据和数据湖成为运行机器学习工具的任何大数据分析工具的核心输入。新时代数据存储的箴言是语义数据结构。关于语义数据架构的更多内容将在第十四章中介绍,“机器学习的新一代数据架构”。以下图展示了数据湖和数据仓库背景下的可视化高级视图:

安全和监控层。
当在多个来源上处理和整合大量数据时,安全性变得极其重要,在敏感数据的情况下,保护数据隐私的需求是关键,有时也是关键合规要求。所需的身份验证和授权检查需要作为执行机器学习算法的一部分来实施。这更多的是一个先决条件,不能作为机器学习架构中的事后考虑。
数据摄取和处理功能是控制数据访问的关键区域,因此需要严格的安全实施。
由于分布式架构,大数据应用程序天生容易受到安全漏洞的影响;有必要确保安全实施得到妥善处理,并且不会影响这些应用程序的执行、可扩展性或功能。
机器学习架构本身应该支持以下作为安全性的基本需求:
-
对集群中的每个节点进行身份验证,支持如 Kerberos 等标准协议。
-
由于它是一个文件系统,因此需要提供最低限度的加密支持。
-
与节点通信应始终使用SSL(安全套接字层)、TLS 或其他包含 NameNode 的协议。
-
安全密钥和令牌以及使用标准密钥管理系统。
-
实现分布式日志记录以轻松跟踪跨层问题。
下一个重要的需求是监控。分布式数据架构配备了强大的监控和支持工具,可以处理在联邦模型中连接的大量节点集群。
对于应用程序的停机时间,总是有服务级别协议(SLA),并且恢复机制必须遵守这些 SLA,同时确保应用程序的可用性。
这些节点和集群以机器无关的方式与监控系统通信是很重要的,并且使用类似 XML 的格式是关键。监控系统的数据存储需求不应影响应用程序的整体性能。
通常,每个大数据栈都自带内置的监控框架或工具。此外,还有如 Ganglia 和 Nagios 等开源工具可以集成并用于监控大数据应用程序。
Hadoop 核心组件框架
Apache Hadoop 有两个核心组件:
-
Hadoop 分布式文件系统也称为 HDFS
-
MapReduce(在 Hadoop 2.x 版本中称为 YARN)
Hadoop 的其他组件在机器学习解决方案架构中得到了表示。使用 Hadoop,我们围绕这两个核心组件工作,形成了 Hadoop 的生态系统组件。
本章的重点是 Apache Hadoop 2.x 版本。在这个版本中,HDFS 和 MapReduce(在 Hadoop 2.x 版本中称为 YARN)的架构发生了一些变化。我们首先介绍核心架构,然后介绍 2.x 架构中引入的变化。
Hadoop 分布式文件系统 (HDFS)
HDFS(Hadoop 分布式文件系统)是从GFS(Google 文件系统)中启发并构建的。它是一个弹性可扩展的分布式文件系统,支持负载均衡和容错性,以确保高可用性。它内置了数据冗余,以展示数据的可靠性和一致性。

HDFS 实现了主从架构。在这里,主节点被称为 NameNode,从节点被称为 DataNodes。NameNode 是所有客户端应用程序的入口点,数据的分布是通过 NameNode 在 DataNodes 之间进行的。实际数据不会通过 NameNode 服务器传递,以确保 NameNode 不会成为任何数据分布的瓶颈。只有元数据会与客户端通信,实际的数据移动是直接在客户端和 DataNodes 之间进行的。
在 Hadoop 架构中,NameNode 和 DataNode 都被称作守护进程。NameNode 需要高端机器,并且预期只运行 NameNode 守护进程。以下要点说明了为什么 NameNode 需要高端机器:
-
整个集群的元数据都存储在内存中,以便快速访问,并且需要更多的内存
-
NameNode 是 Hadoop 集群的单点入口和故障点
-
NameNode 与数百或数千个 DataNode 协调,并管理批处理作业
HDFS 建立在传统的分层文件系统之上,其中创建新目录、添加新文件、删除目录或子目录、删除文件、重命名、移动或更新文件是常见任务。在各个 DataNode 上创建和存储的目录、文件、数据节点和块详情作为元数据存储在 NameNode 中。
在这个架构中,NameNode 还会与另一个节点进行通信,这个节点被称为二级 NameNode。二级 NameNode 不是 NameNode 的备份,因此不会切换到二级 NameNode。相反,它用于存储从 NameNode 复制来的元数据和日志文件。NameNode 将数据块的元数据和相关分布细节存储在一个名为fsimage的文件中。这个镜像文件不会在文件系统的每个数据操作后更新,而是通过在单独的日志文件中记录它们来定期跟踪。这确保了更快的 I/O,从而提高了数据导入或导出操作的效率。
在这方面,二级 NameNode 具有特定的功能。它定期下载镜像和日志文件,通过将日志文件中的当前操作追加到 fsimage 中创建一个新的镜像,然后将新的镜像文件上传回 NameNode。这消除了 NameNode 上的任何开销。NameNode 的任何重启都非常快,从而确保了系统的效率。以下图展示了客户端应用程序和 HDFS 之间的通信工作流程:

HDFS 是为了在 DataNode 之间读取和写入大量数据而构建的。这些大文件被分割成更小的文件块,通常大小固定,如 64 MB 或 128 MB,这些块被分布到 DataNode 上。对于这些块中的每一个,总共存储三个副本以确保冗余和支持容错。副本的数量可以更改,这是系统的配置之一。关于 HDFS 架构和特定功能的更多信息将在下一节中介绍。
二级 NameNode 和检查点过程
在定义二级 NameNode 的目的和功能时,我们了解了一个重要的功能,它负责更新或准备存储在名为fsimage的文件中的 NameNode 元数据。通过合并现有的 fsimage 和日志文件来生成新的 fsimage 的过程称为检查点。以下图展示了检查点过程:

需要对与检查点过程相关的cross-site.XML文件进行一些配置更改。
| 属性 | 目的 |
|---|---|
dfs.namenode.checkpoint.dir |
这是临时 fsimage 文件存放以运行合并过程的目录路径。 |
dfs.namenode.checkpoint.edits.dir |
这是临时编辑运行合并过程所持有的目录路径。此参数的默认值与 dfs.namenode.checkpoint.dir 相同 |
dfs.namenode.checkpoint.period |
两次 checkpoint 运行之间的时间间隔(以秒为单位)。 |
dfs.namenode.checkpoint.txns |
不论时间间隔配置如何,此属性定义了在触发 checkpoint 过程之前需要经过多少事务。 |
dfs.namenode.checkpoint.check.period |
此属性定义了 NameNode 被轮询以检查未 checkpoint 的事务的频率(以秒为单位)。 |
dfs.namenode.checkpoint.max-retries |
在失败的情况下,辅助 NameNode 会重试 checkpoint。此属性定义了辅助 NameNode 在放弃之前尝试重试 checkpoint 的次数。 |
dfs.namenode.num.checkpoints.retained |
此属性表示 NameNode 和辅助 NameNode 保留的 checkpoint 文件数量。 |
checkpoint 过程可以由 NameNode 和辅助 NameNode 触发。辅助 NameNode 还负责定期备份fsimage文件,这有助于进一步恢复。
分割大数据文件
HDFS 将大量文件的小块存储在集群中分布的数据节点上。在文件存储之前,HDFS 内部将整个文件内容分割成多个固定大小的数据块(默认为 64 MB)。此大小是可以配置的。分割文件和构建数据块没有遵循特定的业务逻辑;它纯粹是由文件大小驱动的。然后,这些数据块存储在 DataNodes 上,以便数据读写可以并行进行。每个数据块在本地文件系统中本身也是一个文件。
下图展示了如何将大文件分割成更小的固定大小块:

每个数据块的大小可以通过以下配置参数在 hdfs-site.xml 中进行控制。集群范围内的数据块大小由 hdfs-site.XML 中的 dfs.blocksize 配置属性控制。Hadoop 1.0 中的默认值为 64 MB,而在 Hadoop 2.x 中为 128 MB。数据块的大小取决于基础设施的有效性,并且随着传输速度的提高和新一代驱动器的使用而增大:
| 属性 | 目的 |
|---|---|
dfs.blocksize |
该值为 134217728。之前的字节数值代表 128 MB,或者可以定义任何带有度量单位的值。例如,512m,1g,128k,等等。 |
对块大小值的任何更新都不会应用于现有块;只有新块才有资格。
块加载到集群和复制
文件分割后,数据块由固定大小的块组成,并针对环境进行配置。
由于分布式架构,存储数据块的副本以处理数据可靠性有很强的需求。默认情况下,每个数据块存储三个副本。副本数量的配置属性称为复制因子。以下表格列出了所有与数据加载和复制相关的配置:
| 属性 | 目的 |
|---|---|
dfs.replication |
该值为 3。这定义了每个块需要存储的副本数量。 |
dfs.replication.max |
最大块复制。 |
dfs.namenode.replication.min |
最小块复制。 |
NameNode 负责确保按照配置执行块放置和复制。将这些数据块放置到 DataNodes 后,集群中的每个 DataNode 定期向 NameNode 发送块状态。NameNode 从数据节点接收信号的事实表明,数据节点是活跃的并且运行正常。
HDFS 使用一个默认的块放置策略,旨在在可用节点之间实现负载均衡。以下是该策略的范围:
-
首先,副本或复制件被写入创建文件的 DataNode;这有助于提高写入性能
-
其次,副本或复制件被写入同一机架中的另一个 DataNode;这样可以最小化网络流量
-
第三,副本被写入不同机架中的 DataNode;这样即使交换机出现故障,仍然有数据块的副本可用
应用一个默认的块放置策略,该策略使用机架上的所有节点,而不影响性能、数据可靠性和可用性。以下图像展示了如何使用两个额外副本的复制策略,将三个数据块放置在四个节点上。其中一些节点位于机架上,以实现最佳容错性。

总体而言,将数据加载到 HDFS 的流程如下所示:

写入和读取 HDFS
在将文件写入 HDFS 时,客户端首先联系 NameNode,并传递需要写入 HDFS 的文件详情。NameNode 提供有关复制配置和其他元数据详情,这些详情指定了放置数据块的位置。以下图解说明了这一流程:

处理故障
当 Hadoop 集群启动时,NameNode 进入安全模式状态,并从所有数据节点接收心跳信号。NameNode 从数据节点接收块报告的事实表明,数据节点正在运行并正常工作。
现在假设数据节点 4出现故障;这意味着名称节点没有从数据节点 4接收到任何心跳信号。名称节点记录了名称节点的不可用状态,因此,数据节点 4所做的任何操作都会被负载均衡到其他拥有副本的节点。然后,名称节点会将这些数据更新到元数据注册表中。以下图示展示了相同的内容:

HDFS 命令行
HDFS 有一个名为FS Shell的命令行界面。这便于使用 shell 命令来管理 HDFS。以下截图显示了Hadoop fs命令及其用法/语法:

RESTful HDFS
为了让外部应用程序,尤其是 Web 应用程序或类似的应用程序,能够通过 HTTP 轻松访问 HDFS 中的数据。HDFS 支持一个名为 WebHDFS 的附加协议,该协议基于 RESTful 标准,便于通过 HTTP 访问 HDFS 数据,无需 Java 绑定或完整的 Hadoop 环境。客户端可以使用 curl/wget 等常用工具访问 HDFS。在提供基于 Web 服务的 HDFS 数据访问时,WebHDFS 保留了平台内置的安全性和并行处理能力。
要启用 WebHDFS,请在hdfs-site.xml中进行以下配置更改:
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
更多关于 WebHDFS REST API 的详细信息可以在hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/WebHDFS.html找到。
MapReduce
MapReduce 与 HDFS 类似。Hadoop MapReduce 框架受 Google 的 MapReduce 框架的启发和构建。它是一个分布式计算框架,便于在集群中并行处理大量数据,并具有内置的容错机制。它基于本地数据和数据处理范式,其中处理逻辑被移动到数据,而不是数据移动到处理逻辑。

MapReduce 架构
MapReduce 框架也是基于主从架构的。主作业称为作业跟踪器(JobTracker),从作业称为任务跟踪器(TaskTrackers)。与名称节点和数据节点不同,这些不是物理节点,而是负责在数据节点上运行处理逻辑的守护进程处理器:
-
作业跟踪器:作业跟踪器安排多个任务的作业执行。它负责在任务跟踪器上运行任务或作业,并并行监控处理状态。在出现任何故障的情况下,它负责在任务跟踪器上重新运行失败的任务。
-
任务跟踪器:任务跟踪器执行作业跟踪器安排的任务,并持续与作业跟踪器通信,协同工作。
现在,让我们将 HDFS 上的主从架构与 MapReduce 进行类比。NameNode 运行 JobTracker,DataNodes 运行 TaskTrackers。
在一个典型的多节点集群中,NameNode 和 DataNodes 是独立的物理节点,但在单节点集群的情况下,如果 NameNode 和 DataNode 在基础设施上是相同的,JobTracker 和 TaskTracker 功能将在同一节点上运行。单节点集群用于开发环境。

MapReduce 过程中有两个函数——Map和Reduce。
-
Mapper:Mapper 作业将文件并行分割成多个块,并运行一些基本函数,如排序、过滤以及根据需要执行的其他特定业务或分析函数。Mapper 函数的输出是 Reducer 函数的输入。
-
Reducer:Reducer 作业用于合并 Mapper 的结果,并且可以根据需要执行任何业务或分析功能。Mapper 和 Reducer 作业的中间输出存储在文件系统中作为键值对。Map 和 Reduce 作业的输入和输出都存储在 HDFS 中。总的来说,MapReduce 框架负责调度任务、监控状态和处理(如果有)故障。以下图表描述了
Map和Reduce函数如何工作以及它们在 HDFS 中操作数据:![MapReduce 架构]()
是什么使得 MapReduce 能够满足大数据集的需求?
MapReduce 编程框架的一些优点如下列所示:
-
并行执行:MapReduce 程序默认是设计为并行执行的,可以在节点集群上执行。开发团队不需要关注分布式计算的内部细节,可以直接使用该框架。
-
容错性:MapReduce 框架在主从架构上工作,如果在任何节点发生故障,框架会自动采取纠正措施。
-
可伸缩性:MapReduce 框架具有分布式工作的能力,并且具有向外扩展(横向可伸缩性)的能力,随着数据量的增长,可以在需要时向集群添加新的节点。
-
数据局部性:MapReduce 框架的一个核心前提是将程序带到数据,而不是传统的将数据带到代码的方式。所以,更精确地说,MapReduce 总是有本地数据,这是性能最重要的原因之一。
MapReduce 执行流程和组件
在本节中,我们将深入探讨 MapReduce 的执行流程以及每个组件如何工作:
-
客户端通过 JobTracker(一个 MapReduce 作业)提交一个新作业,包括输入和输出文件路径以及所需的配置。作业被排队等待执行,然后由作业调度器选取。
-
JobTracker 在数据所在的位置获取数据,并创建一个执行计划,触发 TaskTrackers 进行执行。
-
JobTracker 将作业提交给已识别的 TaskTrackers。
-
TaskTrackers 使用它们本地的数据执行任务。如果数据不在本地 Data Node 上,它会与其他 DataNodes 通信。
-
TaskTrackers 通过心跳信号将状态报告给 JobTracker。JobTracker 能够处理任何固有的故障情况。
-
最后,JobTracker 在作业完成后向 Job 客户端报告输出。
如上所述的步骤在以下图中表示。流程分为两部分:HDFS 和 MapReduce,分别对应节点和追踪器。

让我们关注 MapReduce 程序的一些核心组件,并学习如何编写代码。以下流程图详细说明了流程从输入数据到输出数据的过程,以及 MapReduce 框架的每个组件或函数如何启动以执行。虚线红色方块是组件,蓝色方块代表通过过程传递的数据。

开发 MapReduce 组件
Hadoop 的 MapReduce 框架包含一组需要扩展或实现以包含特定功能的 Java API,这些功能旨在在 Hadoop 集群上并行执行。以下是需要完成的某些 API 实现:
-
输入和输出数据格式接口
-
Mapper 实现
-
Reducer 实现
-
Partitioner
-
Combiner
-
Driver
-
Context
InputFormat
InputFormat 类负责从文件中读取数据并将其作为输入提供给 map 函数。这个过程执行了两个核心功能;一个是将输入数据分割成逻辑片段,称为 InputSplits,另一个是将这些分割作为键值对读取,以供 map 函数使用。有两个不同的接口来执行这两个功能:
-
InputSplit
-
RecordReader
输入文件的分割不是必需的功能。如果我们需要考虑整个文件进行处理,我们需要重写 isSplittable() 函数并将标志设置为 false。
OutputFormat
OutputFormat API 负责验证 Hadoop 是否有输出数据格式与作业的输出规范相匹配。RecordWriter 实现负责将最终的输出键值对写入文件系统。每个 InputFormat API 都有一个对应的 OutputFormat API。以下表格列出了 MapReduce 框架的一些输入和输出格式 API:
| 输入格式 API | 对应的输出格式 API |
|---|---|
TextInputFormat |
TextOutputFormat |
SequenceFileInputFormat |
SequenceFileOutputFormat |
DBInputFormat |
DBOutputFormat |
Mapper 实现
所有的 Mapper 实现都需要扩展Mapper<KeyIn, ValueIn, KeyOut, ValueOut>基类,并且非常重要地覆盖map()方法以实现特定的业务功能。Mapper 实现类接受键值对作为输入,并返回一组键值对作为输出。任何其他后续输出随后由 shuffle 和 sort 函数处理。
对于给定的 MapReduce 作业,每个由 InputFormat 生成的 InputSplit 都有一个 Mapper 实例。
总体来说,Mapper 实现类需要从基类扩展四个方法。以下是简要描述的这些方法及其目的:
| 方法名称和语法 | 目的 |
|---|---|
setup(Context) |
这是当 mapper 被启动执行时第一次被调用的方法。除非需要进行任何特定的初始化或配置设置,否则不需要覆盖此方法。 |
map(Object, Object, Context) |
覆盖此方法是 mapper 实现的关键,因为这个方法将在执行 mapper 逻辑时被调用。它接受键值对作为输入,响应可以是一组键值对 |
clean (Context) |
此方法在 mapper 函数执行生命周期的末尾被调用,有助于清除 mapper 使用的任何资源。 |
run (Context) |
覆盖此方法提供了运行多线程 mapper 的额外能力。 |
让我们从一个给定的文件中举一个例子;我们想找出一个单词重复了多少次。在这种情况下,使用TextInputFormat。实际上,这是默认的 InputFormat。以下图表显示了 InputSplit 函数的作用。它将每一行分割并构建一个键值对。
图表显示了文本如何在多个 DataNode 块上存储。TextInputFormat随后读取这些块并生成多个 InputSplit(我们可以看到有两个 InputSplit,因此有两个 mapper)。每个 mapper 选择一个 InputSplit 并为每个跟随数字 1 的单词的出现生成一个键值对。

mapper 函数的输出在处理结束时写入磁盘,中间结果不会写入文件系统。它们被保存在内存中。这有助于优化性能。这是可能的,因为键空间被分区,每个 mapper 只获取总数据集的一部分。现在,关于为此目的分配多少内存,默认情况下分配了 100 MB,对于任何对此值的更改,都需要设置io.sort.mb属性。通常会有一个阈值设置在此限制,如果超过此限制,则会有一个后台进程开始写入磁盘。以下程序片段演示了如何实现 mapper 类。
public static class VowelMapper extends Mapper<Object, Text, Text, IntWritable>
{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException
{
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens())
{
word.set(itr.nextToken());
context.write(word, one);
}
}
}
Hadoop 2.x
在 Hadoop 2.x 之前,所有发行版都专注于解决 Hadoop 1.x 的局限性,但并未偏离核心架构。Hadoop 2.x 真正改变了底层架构假设,并成为了一个真正的突破;最重要的是,YARN 的引入。YARN 是一个用于管理 Hadoop 集群的新框架,它引入了处理实时处理需求的能力,除了批处理。以下是一些已解决的问题:
-
单个 NameNode 问题
-
集群节点数量的显著增加
-
将 Hadoop 能够成功处理的任务数量扩展
以下图展示了 Hadoop 1.x 和 2.x 架构之间的差异,以及 YARN 如何连接 MapReduce 和 HDFS:

Hadoop 生态系统组件
Hadoop 已经衍生出许多辅助和支持框架。以下图展示了开源开发者团体贡献的支持框架的全貌:

以下表格列出了所有框架及其每个框架的目的。这些框架与 Apache Hadoop 发行版一起工作。有许多由供应商构建的框架,它们在商业上定位,并不在本书的范围之内:
| 框架 | URL | 目的(简要) |
|---|---|---|
| HDFS (Hadoop 分布式文件系统) | hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html |
Hadoop 文件存储系统是 Hadoop 的核心组件,它具有内置的容错能力(有关架构和实现细节的更多信息,请参阅 HDFS 部分)。 |
| MapReduce | hadoop.apache.org/docs/current/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html |
MapReduce 是一个用于在分布式平台(如 Hadoop)上处理大量数据的编程模型和框架。Apache MapReduce 的最新版本扩展了另一个框架 Apache YARN。YARN:MapReduce 在 Hadoop 2.0 中经历了彻底的重构,现在被称为 MapReduce 2.0,但 MapReduce 编程模型并未改变。YARN 提供了一种新的资源管理和作业调度模型,以及其执行 MapReduce 作业的实现。在大多数情况下,现有的 MapReduce 作业无需任何更改即可运行。在某些情况下,可能需要进行一些小的更新和重新编译。 |
| Pig | pig.apache.org/ |
Pig 是一个并行执行数据流的框架。它包含一种脚本语言 Pig Latin,有助于开发数据流。Pig Latin 包含一系列内部操作,如连接、拆分、排序等。Pig 在 Hadoop 上运行,并利用 HDFS 和 MapReduce。编译后的 Pig Latin 脚本并行且内部执行其功能。 |
| Hive | hive.apache.org/ |
Hive 是 Hadoop 的数据仓库框架。它支持查询和处理分布式存储中持有的大数据集。可以使用类似 SQL 的查询语言 HiveQL,允许插入映射器和归约器程序。 |
| Flume | flume.apache.org/ |
Flume 框架更像是高效的传输框架,它促进了大量日志数据的聚合、分析、处理和移动。它包含一个可扩展的数据模型,并支持在线分析。 |
| Chukwa | chukwa.apache.org/ |
Chukwa 框架包含一个 API,它有助于轻松收集、分析和监控重要的数据集合。Chukwa 在 HDFS 和 MapReduce 框架之上运行,因此继承了 Hadoop 的可扩展性能力。 |
| HBase | hbase.apache.org/ |
HBase 受 Google BigTable 的启发。它是一个 NoSQL、列式数据存储,旨在补充 Hadoop 平台,并支持对数据的实时操作。HBase 是一个 Hadoop 数据库,负责支持 MapReduce 作业的输出。 |
| HCatalog | cwiki.apache.org/confluence/display/Hive/HCatalog |
HCatalog 类似于 HDFS 中数据的关联视图。它无关乎底层数据存储的位置、方式或格式。目前它是 Hive 的一部分,并且当前版本没有单独的发行版。 |
| Avro | avro.apache.org/ |
Apache Avro 框架更像是数据的一个接口。它支持建模、序列化和执行远程过程调用(RPC)。Avro 中的每个模式表示,也称为元数据定义,都靠近数据并且位于同一文件中,从而使得文件具有自描述性。 |
| HIHO | github.com/sonalgoyal/hiho/wiki/About-HIHO |
HIHO 代表 Hadoop-in Hadoop-out。这个框架帮助连接多个数据存储与 Hadoop 系统,并促进互操作性。HIHO 支持多种关系型数据库管理系统(RDBMS)和文件系统,提供内部功能以并行地在 RDBMS 和 HDFS 之间加载数据和卸载数据。 |
| Sqoop | sqoop.apache.org/ |
Sqoop 是一个广泛采用的数据传输框架,用于在 HDFS 和 RDBMS 之间进行批量或批量传输。它与 Flume 非常相似,但与 RDBMS 一起操作。Sqoop 是 Hadoop 的ETL(提取-转换-加载)工具之一。 |
| Tajo | tajo.apache.org/ |
Tajo 是一个基于 Apache Hadoop 的分布式数据仓库系统,本质上是一个关系型系统。Tajo 支持即席查询和在线集成,以及存储在 HDFS 或其他数据存储中的大数据集的提取-转换-加载功能。 |
| Oozie | oozie.apache.org/ |
Oozie 是一个促进工作流管理的框架。它作为 MapReduce 作业的调度系统,使用DAG(有向无环图)。Oozie 在调度和执行作业时可以是数据感知的或时间感知的。 |
| ZooKeeper | zookeeper.apache.org/ |
如其名所示,Zookeeper 更像是一个 Hadoop 的编排和协调服务。它提供构建、管理和为分布式应用程序提供高可用性的工具。 |
| Ambari | ambari.apache.org/ |
Ambari 是一个直观的 Hadoop 管理 Web UI,具有 RESTful API。Apache Ambari 是 Hortonworks 的贡献。它作为许多其他 Hadoop 框架在生态系统中的接口。 |
| Mahout | mahout.apache.org/ |
Apache Mahout 是一个开源的机器学习算法库。Mahout 的设计重点是提供一个可扩展的库,用于跨多个系统分布式的大数据集。Apache Mahout 是一个从原始数据中提取有用信息的工具。 |
Hadoop 安装和设置
设置 Hadoop 有三种不同的方式:
-
独立操作:在此操作中,Hadoop 以非分布式模式运行。所有守护进程都在单个 Java 进程中运行,有助于轻松调试。这种设置也称为单节点安装。
-
伪分布式操作:在此操作中,Hadoop 配置为在单个节点上运行,但以伪分布式模式运行,可以在不同的 JVM 上运行不同的守护进程进程。
-
全分布式操作:在此操作中,Hadoop 配置为在多个节点上以全分布式模式运行,所有 Hadoop 守护进程(如 NameNode、Secondary Namenode 和 Master 节点上的 JobTracker;以及从节点上的 DataNode 和 TaskTracker)都在节点集群上运行(简而言之,在节点集群上运行)。
基于 Ubuntu 的 Hadoop 安装的先决条件如下:
-
Java v1.7
-
创建专用的 Hadoop 用户
-
配置 SSH 访问
-
禁用 IPv6
安装 Jdk 1.7
-
使用以下命令下载 Java:
wget https://edelivery.oracle.com/otn-pub/java/jdk/7u45-b18/jdk-7u45-linux-x64.tar.gz![安装 Jdk 1.7]()
-
使用以下命令解压二进制文件:
sudo tar xvzf jdk-7u45-linux-x64.tar.gz -
使用以下命令创建用于安装 Java 的目录:
mkdir -P /usr/local/Java cd /usr/local/Java -
将二进制文件复制到新创建的目录中:
sudo cp -r jdk-1.7.0_45 /usr/local/java -
配置 PATH 参数:
sudo nano /etc/profile或者,使用此命令:
sudo gedit /etc/profile -
在文件末尾包含以下内容:
JAVA_HOME=/usr/local/Java/jdk1.7.0_45 PATH=$PATH:$HOME/bin:$JAVA_HOME/bin export JAVA_HOME export PATH -
在 Ubuntu 中,配置 Java 路径:
sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/local/java/jdk1.7.0_45/bin/javac" 1 sudo update-alternatives --set javac /usr/local/Java/jdk1.7.0_45/bin/javac -
检查安装完成情况:
java -version![安装 Jdk 1.7]()
为 Hadoop 创建系统用户(专用)
-
创建/添加一个新的组:
sudo addgroup hadoop -
创建/添加新用户并将其附加到组:
sudo adduser –ingroup hadoop hduser![为 Hadoop 创建系统用户(专用)]()
-
创建/配置 SSH 密钥访问:
ssh-keygen -t rsa -P "" cat $HOME/.ssh/id_rsa.pub >> $HOME/.ssh/authorized_keys -
验证 SSH 设置:
ssh hduser@localhost
禁用 IPv6
使用以下命令打开sysctl.conf:
sudo gedit /etc/sysctl.conf
小贴士
下载示例代码
您可以从www.packtpub.com的账户下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了此书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。
在文件末尾添加以下行。重启机器以正确更新配置:
#disable ipv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
安装 Hadoop 2.6.0 的步骤
-
使用此方法下载 Hadoop 2.6.0:
wget http://apache.claz.org/hadoop/common/hadoop-2.6.0/hadoop-2.6.0.tar.gz -
使用此方法解压缩压缩的 Hadoop 文件:
tar –xvzf hadoop-2.6.0.tar.gz -
移动 hadoop-2.6.0 目录(一个新目录):
mv hadoop-2.6.0 hadoop -
使用此命令将 Hadoop 移动到本地文件夹(方便起见):
sudo mv hadoop /usr/local/ -
更改文件夹的所有者:
sudo chown -R hduser:hadoop Hadoop -
接下来,更新配置文件。
有三个特定于站点的配置文件和一个与主节点(NameNode)和从节点(DataNodes)通信的环境设置配置文件:
-
core-site.xml -
hdfs-site.xml -
mapred-site.xml -
yarn-site.xml
导航到包含配置文件的路径:
cd /usr/local/Hadoop/etc/Hadoop![安装 Hadoop 2.6.0 的步骤]()
yarn-site.xml -
core-site.XML文件包含主节点 IP 或主机名的详细信息,Hadoop 临时目录路径等。

core-site.xml
hdfs-site.xml文件包含以下详细信息:
-
NameNode 存储命名空间和事务日志的本地文件系统路径
-
存储块的本地文件系统路径列表
-
块大小
-
复制次数

hdfs-site.xml
mapred-site.xml文件包含以下详细信息:
-
JobTracker 运行的主机或 IP 和端口号
-
Map/Reduce 存储文件的 HDFS 路径
-
本地文件系统上的路径列表,用于存储中间 MapReduce 数据
-
每个任务跟踪器的 Map/Reduce 任务的最大限制
-
需要包含或排除的数据节点列表
-
需要包含或排除的任务跟踪器列表
![安装 Hadoop 2.6.0 的步骤]()
mapred-site.xml
按照以下截图编辑.bashrc文件:

启动 Hadoop
-
要启动 NameNode:
$ Hadoop-daemon.sh start namenode $ jps -
要启动 DataNode:
$ Hadoop-daemon.sh start datanode $ jps -
要启动 ResourceManager,请使用以下命令:
$ yarn-daemon.sh start resourcemanager $ jps![启动 Hadoop]()
-
要启动 NodeManager:
$ yarn-daemon.sh start nodemanager -
检查 Hadoop Web 界面:
NameNode:
http://localhost:50070次要 NameNode:
http://localhost:50090 -
要停止 Hadoop,请使用以下命令:
stop-dfs.sh stop-yarn.sh
Hadoop 发行版和供应商
由于 Apache Hadoop 发行版是开源和核心版本,大数据社区正在采用,因此几个供应商都有自己的 Apache Hadoop 开源版本。其中一些仅仅增加了支持,而另一些则封装并扩展了 Apache Hadoop 及其生态系统组件的功能。在许多情况下,他们基于核心框架构建了自己的框架或库,以向底层核心组件添加新的功能或特性。
在本节中,让我们探讨一些 Apache Hadoop 的发行版以及一些区分数据事实,这些事实有助于开发团队或组织做出关于最适合其需求的发行版的决定。
让我们考虑以下供应商:
-
Cloudera
-
Hortonworks
-
MapR
-
Pivotal / EMC
-
IBM
| 类别 | 功能/框架 | Cloudera | Hortonworks | MapR | Pivotal | IBM |
| --- | --- | --- | --- | --- | --- |
| 性能和可扩展性 | 数据摄取 | 批量 | 批量 | 批量和流式 | 批量和流式 | 批量和流式 |
| | 元数据架构 | 集中式 | 集中式 | 分布式 | 集中式 | 集中式 |
| | HBase 性能 | 延迟峰值 | 延迟峰值 | 低延迟 | 低延迟 | 延迟峰值 |
| | NoSQL 支持 | 主要为批量应用程序 | 主要为批量应用程序 | 批量和在线系统 | 批量和在线系统 | 批量和在线系统 |
| 可靠性 | 高可用性 | 单次故障恢复 | 单次故障恢复 | 多次故障自愈 | 多次故障自愈 | 单次故障恢复 |
| | 灾难恢复 | 文件复制 | N/A | 镜像 | 镜像 | 文件复制 |
| | 复制 | 数据 | 数据 | 数据和元数据 | 数据和元数据 | 数据 |
| | 快照 | 与关闭文件一致 | 与关闭文件一致 | 时间点一致性 | 与关闭文件一致 | 与关闭文件一致 |
| | 升级 | 滚动升级 | 计划 | 滚动升级 | 计划 | 计划 |
| 可管理性 | 体积支持 | 否 | 否 | 是 | 是 | 是 |
| | 管理工具 | Cloudera 管理器 | Ambari | MapR 控制系统 | 专有控制台 | 专有控制台 |
| | 与 REST API 集成 | 是 | 是 | 是 | 是 | 是 |
| | 作业替换控制 | 否 | 否 | 是 | 是 | 否 |
| 数据访问与处理 | 文件系统 | HDFS、只读 NFS | HDFS、只读 NFS | HDFS、读写 NFS 和 POSIX | HDFS、读写 NFS | HDFS、只读 NFS |
| | 文件 I/O | 仅追加 | 仅追加 | 读写 | 仅追加 | 仅追加 |
| | 安全 ACLs | 是 | 是 | 是 | 是 | 是 |
| | 认证 | Kerberos | Kerberos | Kerberos 和本地 | Kerberos 和本地 | Kerberos 和本地 |
摘要
在本章中,我们涵盖了关于 Hadoop 的所有内容,从核心框架到生态系统组件。本章结束时,读者应该能够设置 Hadoop 并运行一些 MapReduce 函数。用户应该能够运行和管理 Hadoop 环境,并使用一个或多个生态系统组件理解命令行使用。
在下一章中,我们的重点是关键机器学习框架,如 Mahout、Python、R、Spark 和 Julia;这些框架要么在 Hadoop 平台上具有内在支持,要么需要与 Hadoop 平台直接集成以支持大数据集。
第四章:机器学习工具、库和框架
在上一章中,我们介绍了机器学习解决方案架构和技术平台——Hadoop 的实施方面。在本章中,我们将探讨一些高度采用和即将推出的机器学习工具、库和框架。本章是后续章节的入门,因为它涵盖了如何使用特定机器学习框架的现成函数实现特定的机器学习算法。
我们将首先介绍市场上可用的开源和商业机器学习库或工具的概况,并挑选出前五个开源选项。对于每个已确定的选项,从安装步骤开始,学习语法,实现复杂的机器学习算法,到绘制图表,我们将全面介绍。对于读者来说,本章是按顺序出现的,因为它构成了后续章节中所有示例实现的基础。
每个已确定的框架都可以作为独立的库运行,也可以在 Hadoop 上运行。除了学习如何编程和实现机器学习算法外,我们还将介绍每个已确定的框架如何集成和运行在 Hadoop 上;这正是这些教程与网上主流教程的不同之处。
本章详细介绍了以下主题:
-
商业和开源机器学习库的简要列表。
-
涵盖的顶级库或框架是 R、Mahout、Julia、Python(特别是机器学习库)和 Spark。
-
Apache Mahout 是一个用于在 Hadoop 上运行机器学习算法的框架,是一个基于 Java 的开源机器学习选项。这个框架也可以独立运行。它以运行大量数据的机器学习算法而闻名。这个框架是 Hadoop 生态系统组件的一部分,并有自己的发行版。
-
R 是一种在机器学习社区中广泛采用的机器学习和数据挖掘工具。这个框架库既可以独立运行,也可以使用 Hadoop 运行时 R 扩展在 Hadoop 上运行。
-
Julia 是一种开源的高性能编程语言,支持以分布式和并行的方式运行数值和统计计算函数。
-
Python 是一种解释型、高级编程语言,旨在尝试不同的事物,并且它不属于传统的瀑布式开发方式。我们将探索基本的 Python 库——NumPy和SciPy,并使用 scikit-learn 来执行我们的第一个机器学习程序。此外,我们还将探讨如何在 Python 中编写 Hadoop MapReduce 程序。
-
Apache Spark 及其机器学习核心库:Spark 是一个具有 Java、Python 和 Scala API 的集群计算系统。我们将探索MLlib API用于机器学习,并使用 Apache Hadoop 的一个版本。重点将放在探索 Spark Java API 上。
-
对 Spring XD 及其相关机器学习库的简要介绍。
-
对于每个已识别的机器学习框架,与 Hadoop 的集成将是一个主要关注点。
机器学习工具 – 一览图
市场上存在许多开源和商业机器学习框架和工具,在过去几十年中不断发展。虽然机器学习本身在构建满足不同领域多样化需求的强大算法方面也在不断发展,但我们现在看到开源的大规模机器学习选项激增,这些选项已经达到显著成熟水平,并且被数据科学和机器学习社区广泛采用。
模型在最近几年发生了显著变化,研究人员被鼓励在开源模式下发布他们的软件。由于作者在发布他们的工作时使用算法实现机器学习会遇到问题,因此任何经过数据科学社区审查和改进的工作都被认为更有价值。
以下图展示了市场上一些重要的商业和开源机器学习框架和工具的概念模型。本章将深入探讨其中突出显示的部分。

其中一些库针对特定的编程语言,如 Java、Python、C++、Scala 等。其中一些库,如 Julia、Spark 和 Mahout 已经支持分布式和并行处理,而其他如 R 和 Python 则可以在 Hadoop 上作为 MapReduce 函数运行。
在以下各节中,对于每个突出显示的机器学习库,以下内容将被涵盖:
-
对库或工具的概述,包括支持的即用型机器学习函数的详细信息
-
安装、设置和配置指南
-
语法介绍和基本数据处理函数,然后是高级机器学习函数示例实现
-
可视化和绘图示例( wherever applicable)
-
在 Hadoop 平台上的集成和执行
Apache Mahout
Apache Mahout 是一个与 Apache Hadoop 打包的机器学习库,构成了 Hadoop 生态系统的重要组成部分。
Mahout 于 2008 年作为 Apache Lucene(一个开源搜索引擎)的子项目诞生。Lucene 是一个具有搜索、文本挖掘和信息检索技术实现的 API。大多数这些搜索和文本分析在内部应用机器学习技术。为搜索引擎构建的推荐引擎最初是在一个新的子项目 Mahout 下开始的。Mahout 意味着“大象的骑手”,象征着机器学习算法在 Hadoop 上的运行。它是一个可扩展的机器学习实现,可以以独立模式运行(不紧密集成到 Hadoop 中)。

Mahout 是一组基本的机器学习 Java 库,用于分类、聚类、模式挖掘等。尽管今天的 Mahout 提供了对机器学习算法子集的支持,但它仍然是最受欢迎的框架之一,因为它本质上支持对数亿行的大型数据集进行数据分析,这些数据集在本质上可能是非结构化的。
如何工作?
Mahout 实现了 Hadoop MapReduce,最重要的方面是它在 Hadoop 之上运行并应用分布式计算范式。

以下是 Mahout 目前实现的一些特定机器学习任务:
-
协同过滤/推荐:这接受用户输入并找到用户可能喜欢的项目
-
聚类:这接受一些文档作为输入,并根据它们所涉及或属于的主题将它们分组
-
分类:这接受一些文档,并根据文档的现有分类,学习给定文档可能属于哪个类别,并将文档映射到该类别
-
频繁项集挖掘:这接受一些项目作为输入,并根据从实际发生的学习中,确定哪些项目发生或一起出现
有一些算法,例如逻辑回归和 SVM(关于这些算法的更多内容将在后续章节中介绍),不能并行化并在独立模式下运行。
安装和设置 Apache Mahout
在本章中,我们将探讨如何在独立模式和 Hadoop 上运行 Mahout。尽管在撰写本书时 Apache Mahout 有新的 1.0 版本可用,但我们将在所有示例中使用 0.9 版本(最新的稳定版本)。使用的操作系统是 Ubuntu 12.04 桌面 32 位版本。
以下是安装 Apache Mahout 的依赖项和关键要求:
-
JDK (1.6 或更高版本;本书中的示例我们将使用 1.7 u9 版本)
-
Maven (2.2 或更高版本;本书中的示例我们将使用 3.0.4 版本)
-
Apache Hadoop (2.0;不是强制性的,因为 Mahout 可以在本地运行)
-
Apache Mahout (0.9 版本)
-
开发环境——Eclipse IDE(Luna)
在 第三章 中,我们了解到如何进行 Apache Hadoop 2.0 单节点安装,以及所需的先决条件,如 Java。
在本章中,我们将介绍 Maven、Eclipse 开发环境的设置,以及配置 Apache Mahout 在 Hadoop 上和离线运行。由于所考虑的平台和相关框架是开源的,我们将使用 Windows 7 专业版提供的 VirtualBox 虚拟机仿真器。
如您所回忆的,Hadoop 不能以 root 用户身份运行,因此我们为此创建了用户 practical-ml 来安装和运行所有内容。
设置 Maven
建议使用 Maven 来获取所需的 Mahout jar 包,这样就可以轻松地切换到任何更新的 Mahout 版本。如果没有 Maven,下载依赖项将会变得更加复杂。有关 Maven 的具体功能和其在应用程序开发中的实用性的更多详细信息,请参阅www.packtpub.com/application-development/apache-maven-3-cookbook。
Maven 版本 3.0.4 可以从 Apache 网站的镜像之一下载。以下命令可用于此目的:
wget http://it.apache.contactlab.it/maven/maven-3/3.0.4/binaries/apachemaven-3.0.4-bin.tar.gz
要手动安装 Maven,请按照以下说明操作:
-
将分发存档文件,即
apache-maven-3.0.4-bin.tar.gz,提取到您希望安装 Maven 3.0.4 的目录中。 -
使用这些说明,将选择
/usr/local/apache-maven路径。从存档中创建一个apache-maven-3.0.4子目录。 -
以下行需要追加到
.bashrc文件中:export M2_HOME=/usr/local/apache-maven-3.0.4 export M2=$M2_HOME/bin export PATH=$M2:$PATH export JAVA_HOME=$HOME/programs/jdk
JAVA_HOME 应指向 JDK 安装的位置。例如,导出 JAVA_HOME=/usr/java/jdk1.7,JAVA_HOME/bin 应包含在您的 PATH 环境变量中。PATH 变量是在 Java 安装期间设置的。这应该得到验证。
我们现在可以通过运行以下命令来检查 Maven 的安装是否成功:
mvn –version
如果有任何代理设置,我们必须明确更新 Maven 安装目录中 conf 文件夹下的 settings.xml 文件中的代理设置。
使用 Eclipse IDE 设置 Apache Mahout
下一步详细说明了设置 Mahout 环境、代码库、访问示例、运行、调试和测试的步骤,使用 Eclipse IDE 进行这些操作是推荐的,也是最简单的方法来为开发团队设置 Apache Mahout。
执行以下步骤以获取 Apache Mahout 的 tar 文件,解压它并导航到安装目录。
-
设置 Eclipse IDE。
可以从以下链接下载最新版本的 Eclipse:
-
使用以下命令从直接链接下载 Mahout 分发版:
$ wget -c http://archive.apache.org/dist/mahout/0.9/mahout-distribution-0.9.tar.gz -
使用以下命令从存档中提取:
$ tar zxf mahout-distribution-0.9.tar.gz -
将项目转换为 Eclipse 项目:
$ cd mahout-distribution-0.9 $ mvn eclipse: eclipse之前的命令构建了 Eclipse 项目。
-
将
M2_REPO类路径变量设置为指向本地仓库路径。以下命令将所有 Maven jar 添加到 Eclipse 类路径:mvn -Declipse.workspace= eclipse:add-maven-repo -
现在,让我们导入 Eclipse Mahout 项目。
从菜单中导航,文件 | 导入 | 通用 | 现有项目到工作空间。
![使用 Eclipse IDE 设置 Apache Mahout]()
设置 Apache Mahout 而不使用 Eclipse
-
使用以下命令从直接链接下载 Mahout 发行版:
$ wget -c http://archive.apache.org/dist/mahout/0.9/mahout-distribution-0.9.tar.gz -
将 Mahout 发行版提取到
/usr/local文件夹:$ cd /usr/local $ sudo tar xzf mahout-distribution-0.9.tar.gz $ sudo mv mahout-distribution-0.9.tar.gz mahout $ sudo chown –R practical-ml:hadoop mahout -
在
.bashrc文件中设置 Java、Maven 和 Mahout 路径。使用以下命令打开
.bashrc文件:gedit ~/.bashrc将以下内容添加到文件中:
export MAHOUT_HOME = /usr/local/mahout path=$path:$MAHOUT_HOME/bin export M2_HOME=/usr/local/maven export PATH=$M2:$PATH export M2=$M2_HOME/bin PATH=$PATH:$JAVA_HOME/bin;$M2_HOME/bin -
要在本地模式(这意味着在独立模式中,不需要 Hadoop,算法将不会以并行或 MapReduce 模式运行)下运行 Mahout。
使用以下命令将本地模式设置为 true:
$MAHOUT_LOCAL=true这将强制 Mahout 不在
$HADOOP_CONF_DIR中查找 Hadoop 配置。MAHOUT_LOCAL已设置,因此我们不需要将HADOOP_CONF_DIR添加到类路径中。
有一种在 Hadoop 上运行 Mahout 的替代方法。首先,确保已成功安装和配置 Hadoop 2.x。然后,按照以下说明操作:
-
设置
$HADOOP_HOME、$HADOOP_CONF_DIR并将其添加到$PATH。export HADOOP_CONF_DIR=$HADOOP_HOME/conf上面的设置设置了 Hadoop 运行的模式(例如,在
core-site.xml、hdfs-site.xml、mapred-site.xml等等中)。 -
现在,使用以下命令启动 Hadoop 实例:
$HADOOP_HOME/bin/start-all.sh -
检查
http://localhost:50030和http://localhost:50070网址以确认 Hadoop 是否正在运行。 -
使用 Maven 从 Mahout 目录运行以下 Maven 命令来构建 Apache Mahout:
/usr/local/mahout$ mvn install
在成功安装后,将看到以下输出:

Mahout 包
以下图展示了 Mahout 中提供对多个机器学习算法一些即用型支持的不同的包。在核心,模块包括实用工具、数学向量、集合、以及用于并行处理和分布式存储的 Hadoop 和 MapReduce。
此外,在核心模块之上还有以下列出的机器学习包:
-
分类
-
聚类
-
进化算法
-
推荐系统
-
回归
-
FPM
-
维度缩减
![Mahout 包]()
在接下来的章节中,将详细介绍之前提到的包,并使用每个包针对一个已识别的问题提供示例实现。
在 Mahout 中实现向量
如我们所知,为了演示 Mahout 中大多数机器学习算法的实现,我们需要经典 Mahout 数据集格式的数据。在核心,此代码主要使用一些 Mahout 可用脚本,并在设置中进行一些小的更改。以下为标准流程:
-
从原始文本文件创建序列文件。
序列文件主要是数据的关键/值对表示的二进制编码。以下给出的属性是键头元素,代表元数据细节:
-
版本
-
键名
-
值名
-
压缩
-
-
从序列文件生成向量。关于生成序列文件的实际命令的更多内容将在以下章节中介绍,同时展示每个已识别的机器学习算法的实现。
-
在这些工作向量上运行函数
Mahout 中有不同类型的向量实现,这些定义在一般情况下也是适用的。

-
密集向量:这些向量通常是一个双精度浮点数数组,这个向量的大小与数据集中特征的数量相同。由于所有条目都是预先分配的,无论是否为零值,因此这些向量被称为密集向量。
-
稀疏向量:这些向量是向量的数组,并且只表示非零或空值。对于稀疏向量,有两种子类别:随机访问和顺序访问稀疏向量。
-
随机访问稀疏向量:随机访问稀疏向量是 HashMap 表示,其中键是一个整数值,值是一个双精度浮点数。在任何给定的时间点,可以通过传递给定的键来访问一个值。
-
顺序访问稀疏向量:这些向量实际上是一组两个数组,第一个数组是键(整数)数组,第二个数组是值(双精度浮点数)数组。这些向量针对线性读取进行了优化,与随机访问稀疏向量不同。同样,存储仅针对非零值。
注意
为了详细了解如何使用 Apache Mahout,请参考 Packt 出版社出版的关于 Apache Mahout 的书籍《Apache Mahout Cookbook》。
-
虽然本节涵盖了只需进行少量配置更改即可与 Hadoop 一起工作的框架,但在下一节中,我们将介绍市场上广泛采用的强大选项——R。Hadoop 提供了明确的适配器,以便 R 程序能够在 MapReduce 模型中运行,这一点将在下一节中介绍。
R
R 是一种数据分析语言,它被用作机器学习、统计计算和数据挖掘领域的主要驱动环境,并为基本和高级可视化或图形提供了一个全面的平台。如今,R 是几乎所有数据科学家或即将成为数据科学家的人必须学习的基本技能。
R 主要是一个 GNU 项目,类似于最初在贝尔实验室(以前称为 AT&T,现在是朗讯科技)由约翰·查默斯及其团队开发的 S 语言。S 的初始目标是支持所有统计函数,并被硬核统计学家广泛使用。
R 随带一系列开源包,可以免费下载和配置,并根据需要安装或加载到 R 环境中。这些包为各种统计技术提供即插即用的支持,包括线性和非线性建模、时间序列分析、分类、聚类等。
此外,还提供了高度可扩展的图形功能。这些高级图形功能的支持是 R 的主要差异化因素,因为其输出以其出版物质量的图表而闻名。除此之外,R 还支持许多开源图形库和可视化工具,这些工具既开源又商业。
尽管 R 在核心上并不旨在在分布式环境中工作或以并行模式运行算法,但有一些扩展(包括开源和商业)可以使 R 更具可扩展性并支持大数据集。在本章中,我们将介绍如何将 R 与 Apache Hadoop 集成,从而可以运行并利用 MapReduce 功能。
最重要的是,R 是一种广泛采用的免费软件,拥有许多提交者和支持小组不断努力保持其在数据科学领域的极高相关性。
R 支持的一些关键功能如下列出:
-
能够有效管理和存储模型操作的数据的能力
-
方便进行数组、向量和其他核心函数的计算
-
几种即插即用的机器学习函数,可以根据需要加载,并有助于轻松实现数据科学项目。
-
可以轻松使用并帮助生成对商业主有价值的仪表板的先进和复杂的图形功能
-
一个广泛且活跃的采用者和提交者社区,通过大量包的扩展迅速发展
-
R 被视为一个支持新兴的交互式数据分析方法的平台
安装和设置 R
在本书的所有示例中,我们将使用 R 的稳定版本 2.15.1 和 CRAN 引用,以获取所有最新的 R 包。
请参阅cran.r-project.org/bin/windows/base/old/2.15.1/链接下载 R for Windows。
详细安装过程请参阅cran.r-project.org/doc/manuals/R-admin.html#Top。
我们可以使用 R GUI 或 RStudio 来使用 R。以下是用户在成功安装 R GUI、R IDE 和 RStudio 后可以看到的 R 界面截图。

我们需要设置 CRAN 镜像路径,以便通过导航到菜单路径 包 | 设置 CRAN 镜像 来访问和加载所需的 R 包。

以下截图显示了开发者可以选择的最合适的镜像站点列表:

R 编辑器可以用来编写任何高级操作,结果可以在控制台看到,如下所示:

以下是一个图形图表的截图:

将 R 与 Apache Hadoop 集成
到目前为止,我们已经看到了 Apache Hadoop 及其核心组件,HDFS 和 YARN(MapReduce 2.0),以及 R。我们可以以三种不同的方式来看待将 R 与 Hadoop 集成,因此支持大规模机器学习。
方法 1 – 在 Hadoop 中使用 R 和 Streaming API
要将 R 函数与 Hadoop 集成并看到它在 MapReduce 模式下运行,Hadoop 支持 R 的 Streaming API。这些 Streaming API 主要帮助在 MapReduce 模式下运行任何可以访问和操作标准 I/O 的脚本。因此,在 R 的情况下,不会与 R 进行任何显式的客户端集成。以下是一个 R 和流处理的示例:
$ ${HADOOP_HOME}/bin/Hadoop jar
${HADOOP_HOME}/contrib/streaming/*.jar \
-inputformat
org.apache.hadoop.mapred.TextInputFormat \
-input input_data.txt \
-output \
-mapper /home/tst/src/map.R \
-reducer /home/tst/src/reduce.R \
-file /home/tst/src/map.R \
-file /home/tst/src/reduce.R
方法 2 – 使用 R 的 Rhipe 包
R 中有一个名为 Rhipe 的包,允许在 R 中运行 MapReduce 作业。要使用这种方式在 Hadoop 上实现 R,有一些先决条件:
-
需要在 Hadoop 集群中的每个 DataNode 上安装 R
-
Protocol Buffers 将在每个 DataNode 上安装和可用(有关 Protocol Buffers 的更多信息,请参阅
wiki.apache.org/hadoop/ProtocolBuffers) -
Rhipe 应该在每个数据节点上可用
以下是在 R 中使用 Rhipe 库实现 MapReduce 的示例格式:
library(Rhipe)
rhinit(TRUE, TRUE);
map<-expression ( {lapply (map.values, function(mapper)…)})
reduce<-expression(
pre = {…},
reduce = {…},
post = {…},
)
x <- rhmr(map=map, reduce=reduce,
ifolder=inputPath,
ofolder=outputPath,
inout=c('text', 'text'),
jobname='test name'))
rhex(x)
方法 3 – 使用 RHadoop
与 Rhipe 非常相似的 RHadoop,便于在 MapReduce 模式下运行 R 函数。它是由 Revolution Analytics 开发的开源库。以下是一些 RHadoop 库的组成部分:
-
plyrmr:这是一个提供用于在 Hadoop 上运行大型数据集的常见数据操作函数的包
-
rmr:这是一个包含将 R 和 Hadoop 集成的函数集合的包
-
rdfs:这是一个提供帮助 R 和 HDFS 交互的函数的包
-
rhbase:这是一个包含帮助 R 和 HBase 交互的函数的包
以下是一个使用 rmr 包的示例,展示了使用该包中的函数集成 R 和 Hadoop 的步骤:
library(rmr)
maplogic<-function(k,v) { …}
reducelogic<-function(k,vv) { …}
mapreduce( input ="data.txt",
output="output",
textinputformat =rawtextinputformat,
map = maplogic,
reduce=reducelogic
)
R/Hadoop 集成方法总结
总结来说,所有前面三种方法都能产生结果并促进 R 和 Hadoop 的集成。它们帮助将 R 规模化以在 HDFS 上操作,这将有助于处理大规模数据。每种方法都有其优缺点。以下是一些结论的总结:
-
Hadoop Streaming API 是所有方法中最简单的一个,因为没有关于安装和设置要求的复杂性
-
Rhipe 和 RHadoop 都需要在 Hadoop 集群上设置 R 和相关包,这需要一些努力
-
关于实现方法,Streaming API 更像是一个命令行映射,reduce 函数是函数的输入,而 Rhipe 和 RHadoop 允许开发者在 R 中定义和调用自定义的 MapReduce 函数
-
在 Hadoop Streaming API 的情况下,不需要客户端集成,而 Rhipe 和 RHadoop 都需要客户端集成
-
机器学习的替代方案包括 Apache Mahout、Apache Hive 以及来自 Revolution Analytics、Segue 框架和其他一些商业版本的 R
在 R 中实现(使用示例)
在本节中,我们将简要介绍 R 的某些实现方面,并专注于学习语法以及理解一些核心函数及其用法。
R 表达式
R 可以用作简单的数学计算器;以下是使用它的基本方法。以下是 R 控制台上的输出跟踪:
> 1+1
[1] 2
> "Welcome to R!"
[1] "Welcome to R!"
> 6*7
[1] 42
> 10<22
[1] TRUE
> 2+7==5
[1] FALSE
分配
这用于将值分配给变量并对该变量执行一些操作:
情况 1:分配一个数值:
> x<-24
> x/2
[1] 12
情况 2:分配一个字符串字面量:
> x <- "Try R!"
[1] "Try R!"
> x
[1] " Try R!"
情况 3:分配一个逻辑值:
> x <- TRUE
[1] TRUE
函数
有许多现成的函数,要在 R 中调用一个函数,我们应该提供函数名并传递所需的参数。以下是一些函数及其结果的示例,如 R 控制台所示:
> sum(4,3,5,7)
[1] 19
> rep("Fun!", times=3)
[1] " Fun!" "Fun!" "Fun!"
> sqrt(81)
[1] 9
这是获取 R 中函数帮助的命令:
> help(sum)
sum package: base R Documentation
Sum of Vector Elements
Description:
'sum' returns the sum of all the values present in its arguments.
Usage:
sum(..., na.rm = FALSE)
R 向量
根据定义,向量是一个简单的值列表,它是 R 数据类型的核心。许多机器学习函数都利用了这些。
这里有一些关键函数及其使用上下文:
| 函数/语法 | 目的 | 示例 | R 控制台上的输出 |
|---|---|---|---|
m:n |
输出从 m 到 n 的数字,每次增加 1 |
> 5:9 |
[1] 5 6 7 8 9 |
seq(m,n) |
输出从 m 到 n 的数字,每次增加 1 |
> seq(5,9) |
[1] 5 6 7 8 9 |
seq(m,n, i) |
输出从 m 到 n 的数字,每次增加 i |
> seq(1,3,0.5) |
[1] 1 1.5 2 2.5 3 |
分配、访问和操作向量
下表提供了在 R 中创建、访问和操作矩阵的示例:
| 目的 | 示例 |
|---|---|
| 创建一个字面量向量 | > sentence <- c('practical', 'machine', 'learning') |
| 访问向量的第三个值 | > sentence[3]``[1] "learning." |
| 更新向量中的值 | > sentence[1] <- "implementing" |
| 向向量中添加新值 | > sentence[4] <- "algorithms" |
| 获取给定索引的值 | > sentence[c(1,3)]``[1] "implementing" "learning" |
| 获取指定索引范围的值 | > sentence[2:4]``[1] "machine" "learning" "algorithms" |
| 添加一系列新值 | > sentence[5:7] <- c('for','large','datasets') |
| 向量值加 1 | > a <- c(1, 2, 3)```> a + 1``[1] 2 3 4 |
| 将向量中的每个值除以一个值 | > a / 2``[1] 0.5 1.0 1.5 |
| 将向量的每个值乘以一个值 | > a*2``[1] 2 4 6 |
| 添加两个向量 | > b <- c(4, 5, 6)``> a + b``[1] 5 7 9 |
| 比较两个向量 | > a == c(1, 99, 3)``[1] TRUE FALSE TRUE |
| 对向量的每个值应用一个函数 | > sqrt(a)``[1] 1.000000 1.414214 1.732051 |
R 矩阵
矩阵是具有行和列的二维向量。以下表格展示了在 R 中创建、访问和操作矩阵的示例:
| 目的 | 示例 |
|---|---|
| 创建一个默认值为零的 3 X 4 矩阵 | > matrix(0, 3, 4)``[,1] [,2] [,3] [,4]``[1,] 0 0 0 0``[2,] 0 0 0 0``[3,] 0 0 0 0 |
| 使用一系列值初始化矩阵 | > a <- 1:12``> m <- matrix(a, 3, 4)``[,1] [,2] [,3] [,4]``[1,] 1 4 7 10``[2,] 2 5 8 11``[3,] 3 6 9 12 |
| 从矩阵中访问一个值 | > m[2, 3]``[1] 8 |
| 在矩阵中选择的位置赋值 | > m[1, 4] <- 0 |
| 获取整个行或所选列的数组 | > m[2,]``[1] 2 5 8 11``> m[3,]``[1] 7 8 9 |
| 从较大的矩阵中检索子集 | > m[, 2:4]``[,1] [,2] [,3]``[1,] 4 7 10``[2,] 5 8 11 |
R 因子
在数据分析与机器学习中,分组或分类数据是很常见的。例如,好客户或坏客户。R 的 factor 数据类型用于跟踪分类数据。需要做的只是定义一个类别向量,并将其作为参数传递给 factor 函数。
以下示例展示了使用 factors 创建和赋值类别的操作:
> ornaments <- c('ring', 'chain', 'bangle', 'anklet', 'nosepin', 'earring', 'ring', 'anklet')
> ornamenttypes <- factor(ornaments)
> print(ornamenttypes)
[1] ring chain bangle anklet nosepin earring
Levels: anklet bangle chain earring nosepin ring
每个定义的类别通常与一个整数值相关联。将 factor 传递给 as.integer 函数将给出整数等效值,如下所示:
> as.integer(ornamenttypes)
[1] 6 3 2 1 5 4 6 1
R 数据框
数据框与数据库表的概念相关。在 R 中,这种数据类型非常强大,它有助于将数据集的不同相关属性联系起来。例如,购买的商品数量与总账单价值以及整体适用折扣有关。应该有一种方法将这些属性联系起来,数据框有助于做到这一点:
| 目的 | 示例 |
|---|---|
| 创建数据框并检查值 | > purchase <- data.frame(totalbill, noitems, discount``> print(purchase)``totalbill noitems discount``1 300 5 10``2 200 3 7.5``3 100 1 5``) |
| 使用索引或标签访问数据框的数据 | > purchase[[2]]``[1] 5 3 1``> purchase[["totalbill"]]``[1] 300 200 100``> purchase$discount``[1] 10 7.5 5 |
| 使用从 CSV 文件加载数据的数据框 | > list.files()``[1] "monthlypurchases.csv"``> read.csv("monthlypurchases.csv")``Amount Items Discount``1 2500 35 15``2 5464 42 25``3 1245 8 6 |
R 统计框架
R 支持大量统计内置函数,帮助统计学家解释数据。以下表格展示了其中一些带有示例的函数:
| 函数 | 示例 |
|---|---|
| 平均值 | limbs <- c(4, 3, 4, 3, 2, 4, 4, 4) names(limbs) <- c('One-Eye', 'Peg-Leg', 'Smitty', 'Hook', 'Scooter', 'Dan', 'Mikey', 'Blackbeard') > mean(limbs) [1] 3.5 |
| 中位数 | > median(limbs) [1] 4 |
| 标准差 | pounds <- c(45000, 50000, 35000, 40000, 35000, 45000, 10000, 15000) > deviation <- sd(pounds) |
每段包含的 R 代码都保存在一个以.R扩展名命名的文件中,以便于运行。
在本节中,我们看到了如何设置 R 以及如何使用一些基本函数和数据类型。在接下来的章节中,我们将探索许多特定于机器学习的包。
注意
对于使用 R 进行机器学习的详细理解,请参阅 Packt 出版的《Machine learning with R》。
Julia
近年来,Julia 在机器学习和数据科学领域获得了广泛的流行和采用,作为 Python 的高性能替代品。Julia 是一种动态编程语言,旨在支持分布式和并行计算,因此被认为是方便且快速的。
Julia 的性能是 JIT 编译器和类型接口功能的结果。此外,与其它数值编程语言不同,Julia 不强制执行值的向量化。类似于 R、MATLAB 和 Python,Julia 为高级数值计算提供了便利和表达性。
以下是 Julia 的一些关键特性:
-
核心 API 和数学原始操作是用 Julia 编写的
-
它包含丰富的类型,用于构建和描述对象
-
Julia 支持多派发,允许在许多参数组合中使用函数
-
它简化了针对不同参数类型的专用代码生成的自动化
-
经证实的性能与静态编译语言如 C 相当
-
它是一种免费且开源的编程语言(MIT 授权)
-
用户自定义类型与内置类型一样快速且紧凑
-
它不强制或要求为性能编写向量化代码
-
它是为分布式和并行计算设计的
-
Julia 自带协程和轻量级线程
-
Julia 支持直接调用 C 函数的能力
-
类似于 shell 的能力来管理进程
-
它提供了 Lisp 样式的宏
安装和设置 Julia
我们将使用本书编写时可用的最新版本的 Julia——v 0.3.4。
Julia 程序可以通过以下方式构建和执行:
-
使用 Julia 命令行
-
使用 Juno——Julia 的 IDE
-
在
juliabox.org/使用现成的环境,可以通过浏览器访问 Julia 环境
下载和使用 Julia 的命令行版本
使用julialang.org/downloads/链接下载所需的 Julia 版本。
-
下载适当的可执行文件并运行它。
![下载和使用 Julia 的命令行版本]()
-
安装成功后,打开 Julia 控制台,Julia 即可使用。
![下载和使用 Julia 的命令行版本]()
使用 Juno IDE 运行 Julia
Juno IDE 使开发 Julia 代码变得简单。从 junolab.org/docs/install.html 下载最新的 Juno IDE 版本。
Juno 拥有 Julia 的核心 API 和函数,有助于简化开发过程。以下是如何使用 Juno 的截图:

通过浏览器使用 Julia
使用此选项不需要安装 Julia。按照以下步骤在线访问 Julia 环境:
-
通过浏览器访问
juliabox.org/![通过浏览器使用 Julia]()
-
使用 Google 账户登录。这将为登录用户创建一个独特的 Julia 实例。这将提供访问 Julia 控制台和 IJulia 实例的权限。
通过我们之前看到的三种方法之一,我们可以从 Julia 控制台执行 Julia 代码。包含的每段 Julia 代码都构建在一个以 .jl 扩展名结尾的文件中。
从命令行运行 Julia 代码
Julia 在运行时编译代码,并使用即时编译器(JIT)将每个方法转换为机器代码。内部,它使用低级虚拟机(LLVM)进行优化和代码生成。LLVM 是一个完整的项目,它是一系列标准编译技术的集合。这被用作 iOS 的一部分。
从所选的壳中运行以下命令:
<</path/to/Julia>>/myjuliascript.jl
或者,从 Julia 命令行安装中打开 Julia 控制台并运行以下命令:
julia> include("<<path/to/juliascript>>/myjuliascript.jl")
在 Julia 中实现(示例)
在本节中,我们将介绍一些关于 Julia 编程和语法理解的基本主题。在本节结束时,读者应该能够轻松地编写他们的 Julia 脚本并运行它。关于语法,Julia 编程语言与 MATLAB 非常相似。
使用变量和赋值
在 Julia 中,变量像任何其他编程语言一样,用于存储和操作数据。以下是一个定义、赋值和操作变量及值的示例:
# Assign a numeric value to a variable
julia> x = 10
10
# Perform a simple mathematical manipulation of variables
julia> x + 1
11
# Assigning or reassigning values to variables.
julia> x = 1 + 1
2
# Assigning a string literal to a variable
julia> x = "Hello World!"
"Hello, World!"
Julia 作为一种数学编程语言,提供了几个基本常数。以下是一个可以直接在代码中使用的示例。此外,我们可以定义自己的常数并重新赋值:
julia> pi
π = 3.1415926535897...
数值原语
对于任何支持基于数值计算的数学编程语言,整数和浮点值构成了基本构建块,被称为数值原语。
Julia 随带支持大量数值原语,这些原语广泛且与数学函数非常互补。
数据结构
Julia 支持多种数据结构,除了所有原始数据类型(如 Vectors、Matrices、Tuples、Dictionaries、Sets 等)之外。以下是一些示例表示及其用法:
# Vector
b = [4, 5, 6]
b[1] # => 4
b[end] # => 6
# Matrix
matrix = [1 2; 3 4]
# Tuple
tup = (1, 2, 3)
tup[1] # => 1
tup[1] = 3 # => ERROR #since tuples are immutable, assigning a value results in an error
# Dictionary
dict = ["one"=> 1, "two"=> 2, "three"=> 3]
dict["one"] # => 1
# Set
filled_set = Set(1,2,2,3,4)
与字符串和字符串操作一起工作
这里有一些在 Julia 中操作字符串的示例:
split("I love learning Julia ! ")
# => 5-element Array{SubString{ASCIIString},1}:
"I"
"love."
"learning."
"Julia"
"!"
join(["It seems to be interesting", "to see",
"how it works"], ", ")
# => "It seems interesting, to see, how it works."
包
Julia 随带了一些内置函数和许多开箱即用的功能,支持实现机器学习算法。以下是列表:
-
Images.jl -
Graphs.jl -
DataFrames.jl -
DimensionalityReduction.jl -
Distributions.jl -
NLOpt.jl -
ArgParse.jl -
Logging.jl -
FactCheck.jl -
METADATA.jl
更多关于 Julia 包的详细信息可以在 github.com/JuliaLang/ 查找。
互操作性
以下部分涵盖了 Julia 与各种其他编程语言的集成方面。
与 C 集成
Julia 灵活,无需任何包装,可以直接调用 C 函数。以下是一个示例,演示了如何做到这一点:
julia> ccall(:clock, Int32, ())
2292761
julia> ccall(:getenv, Ptr{Uint8int8}, (Ptr{Uint8},), "SHELL")
Ptr{Uint8} @0x00007fff5fbffc45
julia> bytestring(ans)
"/bin/bash"
与 Python 集成
与 C 函数调用类似,Julia 支持直接调用 Python 函数。重要的是我们必须安装 PyCall 包才能这样做。PyCall.jl 提供了 Julia 和 Python 之间的自动类型转换。例如,Julia 数组被转换为 NumPy 数组。
以下是一个示例,演示了从 Julia 代码中调用 Python 函数:
julia> using PyCall # Installed with Pkg.add("PyCall")
julia> @pyimport math
julia> math.sin(math.pi / 4) - sin(pi / 4)
0.0
julia> @pyimport pylab
julia> x = linspace(0,2*pi,1000); y = sin(3*x + 4*cos(2*x));
julia> pylab.plot(x, y; color="red", linewidth=2.0, linestyle="--")
julia> pylab.show()
与 MATLAB 集成
以下示例演示了将 Julia 与 MATLAB 函数集成:
using MATLAB
function sampleFunction(bmap::BitMatrix)
@mput bmap
@matlab bmapthin = bwmorph(bmap, "thin", inf)
convert(BitArray, @mget bmapthin)
end
图形和绘图
Julia 有几个包可以帮助生成图表和图形。其中一些列在这里:
-
Gadfly.jl: 这与 ggplot2 非常相似 -
Winston.jl: 这与 Matplotlib 非常相似 -
Gaston.jl: 这与 gnuplot 接口
此示例演示了使用 PyPlot:
using PyPlot
x = linspace(-2pi, 2pi)
y = sin(x)
plot(x, y, "--b")

采用 Julia 的好处
以下是采用 Julia 在机器学习实现中可以期待的一些直接好处:
-
Julia 促进了快速原型设计,同时不牺牲性能
-
它固有地支持代码的并行化
-
它提供了一种更简单的方式来使用特殊的 Julia 类型表达算法
-
Julia 可以轻松调用或与 C、Python、MATLAB 和 C++ 集成
-
Julia 由一个热情、友好和支持性的社区所促进
-
它与 Hadoop 一起工作,并利用基于 Hive 的查询
将 Julia 与 Hadoop 集成
将任何编程语言与 Hadoop 集成通常意味着存储在 Hadoop 中的数据应该是可访问的,并且程序应该能够对数据进行特定的逻辑处理。这可以通过从 Hadoop 中检索数据并将其移至程序附近,或者将程序移动到数据所在位置并执行 MapReduce 或并行处理模式来实现。显然,在第一种情况下,即从 Hadoop 中检索数据并将其带到代码中以执行逻辑时,需要足够的 RAM 来在内存中保存和处理这些数据,这可能会限制在真正大型数据量上运行的能力。在第二种情况下,即将代码带到分布在不同数据节点上的数据时,逻辑应该是可并行化的,并且应该构建 Map 和 Reduce 逻辑。
Julia 与 Hadoop 平台的集成目前还处于初期阶段,详细说明的当前方法是之前描述的第一个方法,即使用标准 ODBC 连接从 Julia 代码连接到 Hadoop/HDFS。数据被检索到 RAM 中以进行进一步处理。现在,此代码可以直接在 DataNode 上运行并更新 HDFS 数据。
我们将使用可以从 GitHub 获取的 ODBC.jl——[ODBC.jl](https://github.com/quinnj/ODBC.jl)。
这是一个为 Julia 设计的简单低级 ODBC 接口。您可以使用以下命令通过 Julia 软件包管理器进行安装:
以下命令创建 Julia 软件包仓库(对于所有软件包只运行一次)
julia> Pkg.init()
以下命令创建 ODBC repo 文件夹并下载 ODBC 软件包及其依赖项(如果需要)
julia> Pkg.add("ODBC")
以下命令用于加载 ODBC 模块以供使用(需要与每个新的 Julia 实例一起运行)
julia> using ODBC
以下是一些可以用于与 Hadoop/HDFS 一起使用的重要函数:
-
要使用 ODBC 数据源、用户名和密码进行连接,请使用——
co = ODBC.connect("mydatasource",usr="johndoe",pwd="12345")。 -
要断开连接,请使用
disconnect(connection::Connection=conn)。 -
要使用连接字符串进行连接,请使用
advancedconnect(conn_string::String)。 -
要对数据源进行查询并检索数据子集,此查询字符串是一个将在 HDFS 上运行的 Hive 查询——
query(connecti on Connection=conn, querystring; fi le=: DataFrame,delim='\t')。
以下是一个示例实现:
使用以下命令来加载 ODBC 模块:
using ODBC
要通过 Hive 连接到 Hadoop 集群,请使用以下命令:
hiveconn = ODBC.connect("servername"; usr="your-user-name", pwd="your-password-here")
要编写 Hive 查询并将其存储为 Julia 字符串,请使用以下命令:
hive_query_string = "select …;"
要运行查询并将结果直接保存到文件,请使用以下命令:
query(hive_query_string, hiveconn;output="C:\\sample.csv",delim=',')
现在,Julia 程序可以访问此文件中的数据以执行机器学习算法。
Python
Python 是机器学习和数据科学领域中高度采用的编程或脚本语言之一。Python 总是以其易于学习、实现和维护而闻名。Python 高度可移植,可以在基于 Unix 的、Windows 和 Mac 平台上运行。随着 Pydoop 和 SciPy 等库的可用性,其在大数据分析领域的重要性大大增加。以下是一些 Python 在解决机器学习问题中流行的关键原因:
-
Python 被认为非常适合数据分析。
-
它是一种多用途的脚本语言,可以用来编写一些基本的快速脚本,用于测试一些基本功能,或者可以用于实时应用,利用其功能齐全的工具包。
-
Python 附带完整的机器学习包(请参阅
mloss.org/software/),并且可以以即插即用的方式使用。
Python 中的工具包选项
在我们深入探讨 Python 中可用的工具包选项之前,让我们首先了解在选择工具包之前应考虑的工具包选项权衡。
我们应该评估的一些关于适当工具包的问题可能如下:
-
我的性能优先级是什么?我需要离线或实时处理实现吗?
-
工具包的透明度如何?我能自己定制库吗?
-
社区状况如何?错误修复的速度如何?社区支持和专家沟通的可用性如何?
Python 中有三种选项:
-
使用 Python 外部绑定。这些是 Matlab、R、Octave 等市场中的流行包的接口。如果我们已经有一些在之前提到的框架中存在的实现,并且希望无缝迁移到 Python,这个选项将工作得很好。
-
使用基于 Python 的工具包。有一些用 Python 编写的工具包附带了一系列算法。下一节将介绍一些 Python 工具包。
-
编写你的逻辑/工具包。
Python 的实现(使用示例)
Python 有两个核心工具包,它们更像是构建块,并且这里列出的几乎所有专用工具包都使用这些核心工具包。以下是这些工具包:
-
NumPy:NumPy 是关于在 Python 中构建快速高效的数组。
-
SciPy:这是一系列在 NumPy 中构建的标准操作算法。
有许多基于 C/C++的实现,例如 LIBLINEAR、LIBSVM、OpenCV 等。
现在让我们看看一些流行的 Python 工具包,以及那些在本书编写一年内更新的工具包:
-
NLTK:这代表自然语言工具包。它专注于自然语言处理(NLP)。
-
mlpy:这是一个包含对一些关键机器学习算法(如分类、回归和聚类等)支持的机器学习算法工具包。
-
PyML:这个工具包专注于支持向量机(SVM)。我们将在接下来的章节中详细介绍。
-
PyBrain:这个工具包专注于神经网络和相关功能。
-
mdp-toolkit:这个工具包的焦点是数据处理,它支持调度和并行化处理。
-
scikit-learn:这是最受欢迎的工具包之一,在最近几年被数据科学家广泛采用。它支持监督学习和无监督学习,一些特殊支持用于特征选择和可视化。有一个大型团队正在积极构建这个工具包,以其出色的文档而闻名。
-
Pydoop:这是与 Hadoop 平台集成的 Python。
Pydoop和SciPy在大数据分析中被广泛部署。
在本章中,我们将探讨 scikit-learn 工具包,并在接下来的章节中使用这个工具包演示所有示例。
对于 Python 程序员来说,使用 scikit-learn 可以帮助非常容易地将机器学习引入生产系统。
安装 Python 和设置 scikit-learn
以下是安装 Python 和 scikit-learn 的核心 Python 工具包版本和依赖项:
-
Python(>= 2.6 或>= 3.3)
-
NumPy(>= 1.6.1)
-
SciPy(>= 0.9)。
-
一个有效的 C++编译器
我们将使用来自 PyPI 的 scikit-learn 的 wheel 包(.whl文件),并使用 pip 实用程序进行安装。
要在您的家目录中安装,请使用以下命令:
python setup.py install --home
要直接从 GitHub 的 git 仓库安装 scikit-learn 到本地磁盘,请使用以下命令:
% git clone git://github.com/scikit-learn/scikit-learn/
% cd scikit-learn
加载数据
Scikit-learn 附带了一些标准数据集,例如iris和digits数据集,可用于构建和运行机器学习算法。
以下是加载 scikit-learn 附带的标准数据集的步骤:
>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> digits = datasets.load_digits()
>>> print digits.data
[[ 0\. 0\. 5\. ..., 0\. 0\. 0.]
[ 0\. 0\. 0\. ..., 10\. 0\. 0.]
[ 0\. 0\. 0\. ..., 16\. 9\. 0.]
...,
[ 0\. 0\. 1\. ..., 6\. 0\. 0.]
[ 0\. 0\. 2\. ..., 12\. 0\. 0.]
[ 0\. 0\. 10\. ..., 12\. 1\. 0.]]
>>> digits.target
array([0, 1, 2, ..., 8, 9, 8])
Apache Spark
Apache Spark 是一个开源框架,用于快速处理大数据或大规模数据,支持流处理、SQL、机器学习和图处理。这个框架是用 Scala 实现的,并支持 Java、Scala 和 Python 等编程语言。性能比传统的 Hadoop 堆栈高 10 倍到 20 倍。Spark 是一个通用框架,允许交互式编程,并支持流处理。Spark 可以以独立模式与支持 Hadoop 格式的 Hadoop 一起工作,如 SequenceFiles 或 InputFormats。它包括本地文件系统、Hive、HBase、Cassandra 和 Amazon S3 等。
我们将在整本书中使用 Spark 1.2.0。
下图展示了 Apache Spark 的核心模块:

Spark 框架的一些基本功能包括任务调度、与存储系统的交互、容错性和内存管理。Spark 遵循名为弹性分布式数据集(RDD)的编程范式。这主要与分布式数据存储和并行计算管理相关。
-
Spark SQL是 Spark 用于查询和处理结构化和非结构化数据的包。此包的核心功能包括:
-
为了便于从各种结构化数据源(如 Hive、JSON 等)加载数据
-
为了在 SQL 和常规 Python 或 Java 或 Scala 代码之间提供集成,并提供构建可以在分布式数据上并行执行的自定义函数的能力
-
支持通过标准数据库连接(JDBC/ODBC)从外部工具进行基于 SQL 的查询,包括Tableau
-
-
Spark Streaming模块用于处理实时、大规模的数据流。此 API 与 Hadoop 的 Streaming I/O API 不同。
-
MLib模块提供开箱即用的可扩展机器学习算法函数,可以在集群上运行。
-
GraphX模块提供图形操作的功能。
在本章中,我们将学习如何结合 Scala 编程语言使用 Spark。现在让我们快速概述 Scala 并学习如何在 Scala 中编码。
Scala
Scala 是一种强类型编程语言,需要JVM(Java 虚拟机)来运行。它是一个独立平台,可以利用 Java API。我们将使用解释器提示符来运行带有 Spark 的 Scala。这里的命令提示符显示了如何使用解释器提示符运行 Spark 中的 Scala。

让我们看看一些 Scala 的示例。
以下代码可以直接粘贴到命令提示符中:
//Default variables are assigned to any expressions
scala>8 * 5 + 2
Res0: Int = 42
Scala>0.5 * res0
Res1= Double = 21.0
//All simple data types are objects
scala>"Hello, " + res0
Res2: java.lang.String = Hello, 42
scala>10.toString()
Res2: String = 10
scala>a.+(b)
Res1: Int = 200 //So you can consider , the operator as a method
A method b as a shorthand for a.method(b)
scala>val myVal: String = "Foo"
keyword "val" this means that a variable cannot change value (immutable variable)
scala>var myVar:String = "Foo"
the keyword var means that it is a variable that can be changed (mutable variable)
scala> def cube(a: Int): Int = a * a * a
cube: (a: Int)Int
scala> myNumbers.map(x => cube(x))
res8: List[Int] = List(1, 8, 27, 64, 125, 64, 27)
scala> myNumbers.map(x => x * x * x)
res9: List[Int] = List(1, 8, 27, 64, 125, 64, 27)
scala> val myNumbers = List(1,2,3,4,5,4,3)
myNumbers: List[Int] = List(1, 2, 3, 4, 5, 4, 3)
scala> def factorial(n:Int):Int = if (n==0) 1 else n * factorial(n-1)
factorial: (n: Int)Int
scala> myNumbers.map(factorial)
res18: List[Int] = List(1, 2, 6, 24, 120, 24, 6)
scala> myNumbers.map(factorial).sum
res19: Int = 183
scala> var factor = 3
factor: Int = 3
scala> val multiplier = (i:Int) => i * factor
multiplier: Int => Int = <function1>
scala> val l1 = List(1,2,3,4,5) map multiplier
l1: List[Int] = List(3, 6, 9, 12, 15)
scala> factor = 5
factor: Int = 5
使用弹性分布式数据集(RDD)进行编程
RDD 是 Spark 处理数据的核心抽象。它们是不可变的分布式元素集合。Spark 中的所有函数都仅在 RDD 上操作。
Spark 自动将 RDD 中包含的数据分布到集群中的节点上作为分区,并支持对这些分区进行并行处理。可以通过从外部数据集导入或分发驱动程序程序中的集合来创建 RDD。以下命令演示了此功能:
scala> val c = file.filter(line => line.contains("and"))
collect()方法将输出写入控制台:
scala>c.collect()
结果的输出通常保存到外部存储系统。count()函数给出输出行的数量。以下将打印出这些行:
scala>println("input had " + c.count() + " lines")
take()函数将获取结果中的n条记录:
scala>c.take(10).foreach(println)
RDDs 通过 Spark 以懒加载的方式处理,从而在处理大数据集时提高效率。
要在多个操作中重用 RDD,你可以要求 Spark 使用RDD.persist()来持久化它。
我们可以要求 Spark 将我们的数据持久化到不同的位置。第一次计算后,Spark 将 RDD 内容存储在内存中(跨集群中的机器分区)并用于未来的操作。
因此,以下处理 RDD 的基本步骤:
-
从外部数据创建输入 RDD。
-
使用转换(例如
filter())将它们转换为定义新的 RDD。 -
使用
persist()存储中间 RDD 以供重用。 -
调用任何所需的函数(例如,
count())以启动并行计算过程。
以下是一个使用 Scala 的 Pi Estimation 的 RDD 示例:
scala>var NUM_SAMPLES=5
scala> val count = sc.parallelize(1 to NUM_SAMPLES).map{i =>
| val x = Math.random()
| val y = Math.random()
| if (x*x + y*y < 1) 1 else 0
| }.reduce(_ + _)
scala>println("Pi is roughly " + 4.0 * count / NUM_SAMPLES)
Spring XD
虽然这本书没有包括 Spring XD 框架来演示机器学习算法,但在这里给出一个小介绍,因为发现在机器学习世界中快速被采用。
XD 代表极端数据。这个开源框架由 Pivotal 团队(之前称为 SpringSource)构建,作为开发和大数据应用程序部署的一站式商店。
Spring XD 是一个分布式且可扩展的框架,它统一了数据摄取、实时、批处理中的分析功能,并支持数据导出。Spring XD 建立在 Spring Integration 和 Spring Batch 框架之上。
以下是一些关键特性:
-
Spring XD 是一个批处理和流工作负载的统一平台。它是一个开放且可扩展的运行时。
-
可扩展且高性能,它是一个分布式数据摄取框架,可以从包括 HDFS、NOSQL 或 Splunk 在内的各种来源摄取数据。
-
它支持在摄取时进行实时分析,例如收集指标和计数值。
-
它通过批处理作业进行工作流管理,包括与标准 RDBMS 和 Hadoop 系统的交互。
-
它是一个可扩展且高性能的数据导出,例如从 HDFS 到 RDBMS 或 NoSQL 数据库。
Spring XD 已知实现了 Lambda 架构,理论上定义了支持批处理和实时处理。有关 Lambda 架构等进化架构的更多信息,请参阅第十四章,机器学习的新一代数据架构。
Spring XD 架构主要包含三个架构层,以帮助实现上述功能:
-
速度层:这是关于实时访问和处理数据。这个过程使系统保持更及时。
![Spring XD]()
-
批处理层:批处理层可以访问完整的 master 数据集,也称为数据湖,意味着真相之源。
![Spring XD]()
-
服务层:服务层更像是查询层,负责将后处理数据暴露给未订阅的消费者。这一层使得批数据可查询,并且通常以其高吞吐量驱动的响应而闻名。
![Spring XD]()
这里展示了 Spring XD 运行时架构(来源:Pivotal):

摘要
在本章中,我们学习了实现机器学习的开源选项,并涵盖了 Apache Mahout、Python、R、Julia 和 Apache Spark 的 MLib 等库、工具和框架的安装、实现和执行。重要的是,我们还介绍了这些框架与大数据平台 Apache Hadoop 的集成。本章更多的是为后续章节打基础,在后续章节中我们将学习如何使用这些框架来实现特定的机器学习算法。
第五章。基于决策树的学习
从本章开始,我们将深入研究每种机器学习算法。我们从一个非参数监督学习方法——决策树及其用于分类和回归的高级技术开始。我们将概述一个可以通过构建基于决策树的模型来解决的问题,并学习如何在 Apache Mahout、R、Julia、Apache Spark 和 Python 中实现它。
本章深入探讨了以下主题:
-
决策树:定义、术语、需求、优点和局限性。
-
构建和理解决策树的基本知识以及一些关键方面,如信息增益和熵。你还将学习构建回归树、树的分类以及测量误差。
-
理解决策树的一些常见问题、修剪决策树的需求以及修剪技术。
-
你将学习决策树算法,如 CART、C4.5、C5.0 等;以及专门的树,如随机森林、斜树、进化树和 Hellinger 树。
-
理解分类和回归树在业务用例中的应用,以及使用 Apache Mahout、R、Apache Spark 和 Julia 以及 Python(scikit-learn)库和模块的实现。
决策树
决策树被认为是机器学习领域中最为强大和广泛使用的建模技术之一。
决策树自然地诱导出可用于数据分类和预测的规则。以下是从构建决策树中得出的规则定义示例:
如果(笔记本电脑型号是x)并且(由y制造)并且(z年)并且(某些所有者是k)那么(电池寿命是n小时)。
当仔细观察时,这些规则以简单、可读和易于理解的形式表达。此外,这些规则可以存储在数据存储中,以便以后参考。以下的概念图展示了将在以下章节中涵盖的决策树的各种特性和属性。

术语
决策树通过从根节点到叶节点的树结构来表示实例的分类。最重要的是,在高级别上,决策树有两种表示形式——节点和连接节点的弧。为了做出决策,流程从根节点开始,导航到弧,直到达到叶节点,然后做出决策。树中的每个节点表示属性的测试,分支表示属性可能采取的可能值。
以下是一些决策树表示的特性:
-
每个非叶节点(例如,决策节点)表示属性值的表示
-
每个分支表示值表示的其余部分
-
每个叶节点(或终端节点)代表目标属性的值
-
起始节点被称为根节点
下面的图表示了相同的内容:

目的和用途
决策树用于分类和回归。在此背景下使用两种类型的树:
-
分类树
-
回归树
分类树用于将给定的数据集分类到类别中。要使用分类树,目标变量的响应需要是分类值,如是/否、真/假。另一方面,回归树用于解决预测需求,并且当目标或响应变量是数值或离散值(如股票价值、商品价格等)时总是使用。
下一个图展示了决策树的目的以及相关的树类别,即分类树或回归树:

构建决策树
通过一个简单的例子和手动构建决策树,可以最好地学习决策树。在本节中,让我们看一个简单的例子;以下表格显示了手头的数据集。我们的目标是预测客户是否会接受贷款,给定他们的人口统计信息。显然,如果我们可以为这个数据集制定一个规则作为模型,这将最有用。

从前一个表中,由于年龄和经验高度相关,我们可以选择忽略其中一个属性。这隐式地帮助了特征选择。
情况 1:让我们开始构建决策树。首先,我们将选择根据 CCAvg(平均信用卡余额)进行分割。

使用这个决策树,我们现在有两个非常明确的规则:
如果 CCAvg 中等则贷款 = 接受 或 如果 CCAvg 高则贷款 = 接受
为了更清晰地说明规则,让我们添加收入属性。我们还有两个额外的规则:
如果 CCAvg 低且收入低,则贷款不接受
如果 CCAvg 低且收入高,则贷款接受
通过结合这里的第二个规则和前两个规则,我们可以推导出以下规则:
如果 (CCAvg 中等) 或 (CCAvg 高) 或 (CCAvg 低且收入高),则贷款 = 接受
情况 2:让我们使用家庭作为开始构建决策树。

在这种情况下,只有一个规则,因为它只有两个数据点,所以结果并不准确。
因此,选择一个有效的属性来开始构建树对模型的准确性有影响。从先前的例子中,让我们列出构建决策树的一些核心规则:
-
我们通常从一个属性开始构建决策树,根据该属性分割数据,然后对其他属性继续同样的过程。
-
对于给定的问题,可能有多个决策树。
-
树的深度与所选属性的数目成正比。
-
需要有一个终止标准来确定何时停止进一步构建树。在没有终止标准的情况下,模型可能会导致数据过拟合。
-
最后,输出总是以简单规则的形式呈现,这些规则可以存储并应用于不同的数据集进行分类和/或预测。
决策树在机器学习领域被优先选择的原因之一是它们对错误的鲁棒性;当训练数据集中存在一些未知值时,它们也可以被使用(例如,收入数据并非所有记录都有)。
处理缺失值
为一些未知值分配值的一个有趣的方法是观察最常见的值被分配,在某些情况下,如果可能的话,它们可以属于同一类,如果可能的话,我们应该将其与准确性更接近。
这还有另一种概率方法,预测是按比例分配的:
为 x 的每个值 vi 分配一个概率 pi。
现在,将 x 的分数 pi 分配给每个后代。这些概率可以根据节点 n 中 A 的各种值的观察频率再次估计。
例如,让我们考虑一个布尔属性 A。假设 A 有 10 个值,其中三个值为 True,其余 7 个值为 False。因此,A(x) = True 的概率是 0.3,而 A(x) = False 的概率是 0.7。
其中 0.3 的分数沿着 A = True 的分支分布,0.7 的分数沿着另一个分支分布。这些概率值用于计算信息增益,如果需要测试第二个缺失的属性值,则可以使用这些值。同样的方法可以在学习时应用,当我们需要为新分支填充任何未知值时。C4.5 算法使用这种机制来填充缺失值。
构建决策树的考虑因素
构建决策树的关键在于知道如何对它们进行分割。为此,我们需要明确以下内容:
-
从哪个属性开始,以及随后的属性应用哪个?
-
我们何时停止构建决策树(即避免过拟合)?
选择合适的属性(或属性组合)。
有三种不同的方法来识别最适合的属性:
-
信息增益和熵
-
吉尼指数
-
收益率
信息增益和熵
这个实体在名为 C4.5 的算法中使用。熵是数据不确定性的度量。让我们用一个直观的方法来理解信息增益和熵的概念。
例如,考虑一个硬币正在被抛掷,有五个硬币,正面朝上的概率分别为 0, 0.25, 0.5, 0.75 和 1。所以,如果我们考虑哪个具有最高的不确定性和哪个具有最低的不确定性,那么 0 或 1 的情况将是最低的确定性,而最高的是当它是 0.5 时。以下图展示了相同的表示:

这里展示了数学表示:
H = -∑p[i]log2p[i]
在这里,p[i] 是特定状态的概率。
如果一个系统有四个事件,概率分别为 1/2, 1/4, 1/5 和 1/8,则表示系统的总熵如下:
H = -1/2 log2(1/2)-1/4log2(1/4)-1/5log2(1/5)-1/8log2(1/8)
在 C5.0 和 C4.5 算法的原始版本(ID3)中,根节点是根据如果选择此节点将减少多少总熵来选择的。这被称为信息增益。
信息增益 = 分割前系统的熵 - 分割后系统的熵
分割前的系统熵如下:

使用 A 将 D 划分为 v 个分区以分类 D 后的熵:

在属性上分支获得的信息增益:
现在我们来计算从我们的数据中获得的信息增益:

类 P 接受贷款 = 是/ 1. 类 N 接受贷款 = 否 / 0
分割前的熵如下:

这是很明显且预期的,因为我们几乎有一半的数据是平分的。现在让我们看看哪个属性能给出最佳的信息增益。
如果分割是基于 CCAvg 和 Family,则熵的计算可以表示如下。总熵是作为创建的每个节点的熵之和的加权总和。

其分割后的熵如下:

信息增益如下:

这种方法被应用于计算所有其他属性的信息增益。它选择信息增益最高的一个。这将在每个节点上进行测试以选择最佳节点。
Gini 指数
Gini 指数是一个通用的分割标准。它以意大利统计学家和经济学家 Corrado Gini 命名。Gini 指数用于衡量两个随机项目属于同一类的概率。在真实数据集的情况下,这个概率值是 1。一个节点的 Gini 测量值是类比例的平方和。具有两个类的节点得分为 0.52 + 0.52 = 0.5。这是因为随机选择相同类的概率是 2 中的 1。现在,如果我们对数据集应用 Gini 指数,我们得到以下结果:
原始基尼系数 =
= 0.502959
当与 CCAvg 和 Family 分割时,基尼系数变为以下:

增益率
与 ID3 相比,C4.5 的另一个改进是决定属性的因子是增益率。增益率是信息增益和信息含量的比率。提供最大增益率的属性是用于分割的属性。
让我们用一个极其简单的例子来做一些计算,以突出为什么增益率比信息增益是一个更好的属性:

因变量是他们在特定情况下是否已婚。让我们假设在这种情况下,没有男人已婚。而所有女人(除了最后一位 60 位女性)都是已婚的。
所以,直观上规则必须如下:
-
如果是男性,那么他是未婚的
-
如果是女性,那么她是已婚的(唯一一个她未婚的孤立案例必须是噪声)。
让我们系统地解决这个问题,以深入了解各种参数。首先,让我们将数据分成两半作为训练数据和测试数据。因此,我们的训练集包括最后 20 个男性(所有不可感知且年龄在 21-40 岁之间),以及最后 30 个女性(所有已婚且年龄在 71-99 岁之间,除了最后一位)。测试数据包含另一半,其中所有女性都是已婚的。
增益率需要衡量信息含量。
信息含量定义为 -f[i] log[2] f[i]。请注意,在这里,我们不考虑因变量的值。我们只想知道一个状态中成员的分数除以总成员数。
性别的信息含量是指它只有两种状态;男性是 20,女性是 30。因此,性别信息含量为 2/5LOG(2/5,2)-3/5LOG(3/5,2)=0.9709。
年龄的信息含量是指年龄共有 49 个状态。对于只有一个数据点的状态,信息含量是 -(1/50)log(1/50,2) = 0.1129*。
有 48 个这样的状态只有一个数据点。因此,它们的信息含量是 (0.1129*48), 5.4192。在最后一个状态中,有两个数据点。因此,它的信息含量是 -(2/50 * LOG(2/50,2)) = 0.1857。年龄的总信息含量是 5.6039。
性别的增益率 = 性别的信息增益 / 性别的信息含量 = 0.8549/0.9709 = 0.8805。
年龄的增益率 = 0.1680
所以,如果我们考虑增益率,我们会得到性别是一个更合适的度量。这与直觉相符。现在让我们假设我们使用了增益率并构建了树。我们的规则是如果性别是男性,那么这个人未婚,如果性别是女性,那么这个人已婚。
终止标准/剪枝决策树
每个分支都足够深入地生长,以便通过决策树算法完美地分类训练示例。这可能会成为一种可接受的方法,但在数据中存在噪声时,通常会导致问题。如果训练数据集太小,无法代表实际数据集的真实情况,决策树可能会最终过拟合训练示例。
在决策树学习中避免过拟合有许多方法。以下是两种不同的情况:
-
一种情况是决策树在完成训练数据的完美分类之前就终止了生长
-
另一种情况是数据过拟合后,然后剪枝以恢复
虽然第一种情况看起来可能更直接,但第二种情况,即对过拟合树进行后剪枝,在现实中更成功。原因是难以知道何时停止树的生长。无论采取何种方法,确定最终、适当的树大小的标准更为重要。
以下是一些寻找正确树大小的方法:
-
识别一个与目标训练数据集不同的独立数据集,并评估树中后剪枝节点的正确性。这是一个常见的方法,被称为训练和验证集方法。
-
在训练集中不使用数据子集,而是使用训练集中的所有数据,并应用概率方法来检查剪枝特定节点是否有任何可能产生超过训练数据集的改进。使用所有可用数据进行训练。例如,可以使用卡方检验来检查这个概率。
减少错误剪枝(D):通过移除以节点为根的子树来剪枝。我们将该节点变为叶节点(具有相关示例的大多数标签);算法如下所示:

规则后剪枝是一种更常用的方法,是一种高度准确的理论技术。C4.5 中使用的是这种剪枝方法的变体。
以下是规则后剪枝过程的步骤:
-
通过生长直到出现明显的过拟合来从训练集中构建决策树。
-
从根节点到特定叶节点的每一条路径生成决策树中的规则,映射到一个规则。
-
对每个规则应用剪枝,以去除已识别的先决条件,并有助于提高概率准确性。
-
接下来,按照它们在后续实例中增加的准确度顺序使用剪枝规则。
以下是基于规则的剪枝的优点及其转换为规则的需求:
-
提高规则的易读性
-
可以在根节点和叶节点级别进行一致的测试。
-
可以清楚地决定是移除决策节点还是保留它
决策树图形表示
到目前为止,我们已经看到决策树是如何通过在节点处划分数据并与常数比较来描述的。另一种表示决策树的方法是可视化和图形表示。例如,我们可以在两个维度中选择两个输入属性,然后比较一个属性的值与常数,并在平行轴上显示数据分割。我们还可以比较两个属性,包括属性的线性组合,而不是与轴不平行的超平面。

对于给定的数据,可以构建多个决策树。识别最小和完美树的过程称为最小一致假设。让我们用两个论点来看为什么这是最好的决策树:
奥卡姆剃刀原理很简单;当有两种方法可以解决问题并且两者都给出相同的结果时,最简单的那一个占上风。
在数据挖掘分析中,人们可能会陷入复杂方法和大量计算陷阱。因此,内化奥卡姆的推理路线至关重要。始终选择一个大小和误差最佳组合的决策树。
诱导决策树 – 决策树算法
有许多诱导决策树的方法。在所有方法中,C4.5 和 CART 是最被采用或最受欢迎的。在本节中,我们将深入探讨这些方法,并简要介绍其他方法。
CART
CART 代表分类和回归树(Breiman 等,1984)。CART 创建二叉树。这意味着从给定的节点总是有两个分支可以产生。CART 算法的哲学是遵循一个良好性标准,这关乎选择最佳可能的分区。此外,随着树的成长,采用成本复杂度剪枝机制。CART 使用基尼指数来选择适当的属性或分割标准。
使用 CART,可以提供先验概率分布。我们可以使用 CART 生成回归树,这反过来又有助于预测一个类别对实数的预测。预测是通过应用节点的加权平均值来完成的。CART 识别出最小化预测平方误差的分割(即最小二乘偏差)。
下图中 CART 的描述是针对前一小节中提到的相同示例,其中展示了决策树构建过程:

C4.5
与 CART 类似,C4.5 是一种决策树算法,其主要区别在于它可以生成超过二叉树,这意味着支持多路分割。在属性选择上,C4.5 使用信息增益度量。正如前一部分所解释的,具有最大信息增益(或最低熵减少)值的属性有助于以最少的数量数据实现更接近准确的分类。C4.5 的一个主要缺点是需要大量的内存和 CPU 容量来生成规则。C5.0 算法是 C4.5 的商业版本,于 1997 年推出。
C4.5 是 ID3 算法的演变。使用增益率度量来识别分割标准。分割过程在分割数量达到边界条件定义的阈值时停止。在树的这个生长阶段之后,进行剪枝,并遵循基于错误的剪枝方法。
这里是 C4.5 构建决策树的表示,用于与上一节中使用的相同示例:

| 树形归纳法 | 它是如何工作的? |
|---|---|
| ID3 | ID3(迭代二分器 3)算法被认为是决策树算法中最简单的一种。它使用信息增益方法作为分割标准;分割会一直进行,直到最佳信息增益不再大于零。ID3 没有进行特定的剪枝操作。它无法处理数值属性和缺失值。 |
| CHAID | CHAID(卡方自动交互检测)是为了仅支持名义属性而构建的。对于每个属性,选择一个值,使其与目标属性最接近。根据目标属性的类型,有一个额外的统计度量,区分了该算法。对于连续目标属性使用 F 检验,对于名义目标属性使用皮尔逊卡方检验,对于有序目标属性使用似然比检验。CHAID 检查一个条件以合并,这可能有一个阈值,并移动到下一个合并检查。这个过程会重复进行,直到找不到匹配的对。CHAID 以简单的方式处理缺失值,并假设所有值都属于一个单一的合法类别。在这个过程中没有进行剪枝操作。 |
| QUEST | QUEST 的缩写代表快速、无偏、高效和统计树。此算法支持单变量和线性组合分割。根据属性类型,使用 ANOVA F 检验或皮尔逊卡方检验或双均值聚类方法来计算每个输入属性与目标属性之间的关系。分割应用于与目标属性关联更强的属性。为了确保达到最优分割点,应用二次判别分析(QDA)。再次,QUEST 实现了二叉树,并且为了剪枝使用了 10 折交叉验证。 |
| CAL5 | 这与数值属性一起工作。 |
| FACT | 此算法是 QUEST 的早期版本,使用统计方法,随后进行判别分析以进行属性选择。 |
| LMDT | 这使用多元测试机制来构建决策树。 |
| MARS | 使用线性样条及其张量积来近似多个回归函数。 |
贪婪决策树
决策树的一个关键特征是它们是贪婪的!贪婪算法通过在每个阶段实现局部最优来全局地实现最优解。虽然全局最优并不总是有保证,但局部最优有助于最大限度地实现全局最优。
每个节点都会贪婪地搜索以达到局部最优,并且陷入局部最优的可能性很高。大多数时候,针对局部最优可能有助于提供足够好的解决方案。
决策树的好处
使用决策树的一些优点如下:
-
决策树构建快速且简单,且需要很少的实验
-
它们是健壮的
-
它们易于理解和解释
-
决策树不需要复杂的数据准备
-
它们可以处理分类数据和数值数据
-
它们通过使用统计模型进行验证来得到支持
-
它们可以处理高维数据,并且可以操作大型数据集
专用树
在本节中,我们将探讨一些重要的特殊情况以及特殊的决策树类型。在解决特殊类型的问题时,这些情况非常有用。
倾斜树
在数据极其复杂的情况下使用倾斜树。如果属性是 x1, x2, AND x3…xn,那么 C4.5 和 CART 测试标准为 x1>某个值 或 x2<另一个值,依此类推。在这种情况下,目标是找到每个节点要测试的属性。这些是如图所示图形上的平行轴分割:

显然,我们需要构建巨大的树。在这个时候,让我们学习一个称为超平面的数据挖掘术语。
在一维问题中,一个点对空间进行分类。在二维中,一条直线(直线或曲线)对空间进行分类。在三维问题中,一个平面(线性或曲线)对空间进行分类。在更高维的空间中,我们想象一个平面像东西一样分裂并对空间进行分类,称之为超平面。以下图表展示了这一点:

因此,传统的决策树算法产生的是与轴平行的超平面来分割数据。如果数据复杂,这可能会变得很繁琐。如果我们能构建斜面,虽然可解释性可能会降低,但我们可能会大幅减少树的大小。所以,我们的想法是将测试条件从以下内容改变:
xi > K 或 < K 到 a1x1+ a2x2+ … + c > K 或 < K
这些斜面超平面有时可以极大地减少树的大小。图 2 中所示的数据在这里使用斜面进行分类:

随机森林
当维度过多时,我们会使用这些专门的树木。我们在机器学习简介章节中学习了维度的诅咒。维度诅咒的基本前提是高维数据带来了复杂性。随着维度和特征的增多,错误的可能性也相应提高。在我们深入探讨随机森林之前,让我们先了解提升法的概念。关于提升法的更多细节可以在第十三章 集成学习中找到。在随机森林的情况下,提升法的应用主要涉及如何将单个决策树方法结合起来,以提升结果的准确性。

随机森林通过包含更多的决策树来扩展决策树。这些决策树是通过随机选择数据(样本)和随机选择属性子集的组合来构建的。以下图表展示了构建每个决策树时数据集的随机选择:

制作多个决策树所需的另一个变量输入是属性的随机子集,这在以下图表中有所表示:

由于每棵树都是使用随机数据集和随机变量集构建的,因此这些树被称为随机树。此外,许多这样的随机树定义了一个随机森林。
随机树的结果基于两个根本的信念。一是每棵树都能对大部分数据做出准确的预测。二是错误会在不同的地方发生。因此,通常会对决策树的结果进行平均,以得出结论。
观察数据不足,无法得到良好的估计,这导致了稀疏性问题。空间密度指数的指数增长有两个重要原因,一是维度增加,二是数据中等距点的增加。大部分数据都在尾部。
为了估计给定精度的密度,以下表格显示了样本大小如何随着维度的增加而增加。随后的计算表格显示了多元正态分布估计的均方误差如何随着维度的增加而增加(如 Silverman 所展示,并使用此处给出的公式计算):


随机森林是决策树的一个重要扩展,非常容易理解,效率极高,尤其是在处理高维空间时。当原始数据有许多维度时,我们随机选择维度(列)的小子集并构建一棵树。我们让它无修剪地生长。现在,我们迭代这个过程,每次构建具有不同属性集的数百棵树。
对于预测,一个新的样本被推入树中。训练样本的新标签被分配给终端节点,它最终结束的地方。这个程序在组中的所有树上迭代,所有树的平均投票结果被报告为随机森林预测。
进化树
当达到全局最优解似乎几乎不可能时,会使用进化树。正如你所学的,决策树是贪婪的。因此,有时我们可能只是因为陷入了局部最优解,而构建出更大的树。所以,如果你的树长度实在太大,可以尝试斜树或进化树。
进化树的概念起源于一个非常激动人心的概念,即遗传算法。你将在另一门课程中详细了解它。让我们只看看其本质。
与在每一个节点数学上计算最佳属性不同,进化树在每个点随机选择一个节点并创建一棵树。然后它迭代并创建一系列树(森林)。现在,它识别森林中最佳树木用于数据。然后通过随机组合这些树来创建森林的下一代。
另一方面,进化树选择一个截然不同的顶级节点,并生成一个更短的树,具有相同的效率。进化算法的计算时间更长。
希尔林格树
已有尝试识别比熵或基尼指数对依赖变量值分布更不敏感的纯度度量。一篇最新的论文建议使用希尔林格距离作为不依赖于目标变量分布的纯度度量。

实质上,P(Y+|X) 是对于每个属性找到 Y+ 的概率,同样地,对于每个属性的 P(Y-|X) 也是计算出来的。

从上一张图中可以看出,对于第一个属性的高值,只有第二个属性的高值才能得到概率值为 1。这使得总距离值为 sqrt(2)。
实现决策树
请参考本章提供的源代码以实现决策树和随机森林(源代码路径 .../chapter5/... 在每个文件夹下的技术中)。
使用 Mahout
请参考文件夹 .../mahout/chapter5/decisiontreeexample/。
请参考文件夹 .../mahout/chapter5/randomforestexample/。
使用 R
请参考文件夹 .../r/chapter5/decisiontreeexample/。
请参考文件夹 .../r/chapter5/randomforestexample/。
使用 Spark
请参考文件夹 .../spark/chapter5/decisiontreeexample/。
请参考文件夹 .../spark/chapter5/randomforestexample/。
使用 Python (scikit-learn)
请参考文件夹 .../python scikit-learn/chapter5/decisiontreeexample/。
请参考文件夹 .../python scikit-learn/chapter5/randomforestexample/。
使用 Julia
请参考文件夹 .../julia/chapter5/decisiontreeexample/。
请参考文件夹 .../julia/chapter5/randomforestexample/。
摘要
在本章中,你学习了使用决策树进行监督学习的技术,以解决分类和回归问题。我们还介绍了选择属性、分割树和剪枝树的方法。在所有其他决策树算法中,我们还探讨了 CART 和 C4.5 算法。对于特殊需求或问题,你还学习了如何使用 Spark、R 和 Julia 的 MLib 实现基于决策树的模型。在下一章中,我们将介绍最近邻和支持向量机(SVM)来解决监督学习和无监督学习问题。
第六章:基于实例和核方法的实例学习
在上一章中,我们介绍了用于解决分类和回归问题的决策树模型。在本章中,我们将介绍两种重要的监督学习和无监督学习技术模型,即使用基于实例学习模型的最近邻方法,以及使用基于核方法学习模型的支持向量机(SVM)模型。对于这两种方法,我们将学习其技术基础,并了解如何在 Apache Mahout、R、Julia、Apache Spark 和 Python 中实现。以下图展示了本书中涵盖的不同学习模型以及将在本章中讨论的技术。

本章节深入探讨了以下主题:
-
基于实例的学习模型
-
基于实例学习的简介
-
懒学习和积极学习
-
简要介绍基于实例学习的不同算法/方法,如最近邻方法、案例推理、局部加权回归和径向基函数
-
深入探讨 KNN(k-最近邻)算法,并附上实际应用案例;加快 KNN 的机制
-
Apache Mahout、R、Apache Spark、Julia 和 Python(scikit-learn)库和模块的示例实现
-
基于核的学习模型
-
基于核的学习简介
-
简要介绍基于核的学习技术、支持向量机(SVM)、线性判别分析(LDA)等不同算法/方法
-
深入探讨 SVM 算法,并附上实际应用案例
-
基于实例的学习(IBL)
基于实例学习的 IBL 技术通过简单地存储提供的训练数据,并将其用作预测/确定新查询行为时的参考。正如在第一章中学习的,机器学习简介,实例不过是数据集的子集。基于实例的学习模型在识别的实例或对问题至关重要的实例组上工作。实例之间的结果进行比较,可以包括新数据的一个实例。这种比较使用特定的相似性度量来找到最佳匹配并进行预测。由于它使用存储在内存中的历史数据,这种学习技术也被称为基于内存或基于案例的学习。在这里,重点是实例的表示以及它们之间比较的相似性度量。

每当接收到一个新的查询实例进行处理时,都会从内存中检索出一组相似的、相关的实例,然后使用这些数据来对新查询实例进行分类。
基于实例的学习者也被称为懒惰学习者。总的来说,整个数据库被用来预测行为。一组被称为邻居的数据点被识别出来,它们有与目标属性一致的历史。一旦形成数据点的邻域,邻居的偏好将被结合以产生对活动目标属性的预测或top-K 推荐。
这些方法适用于可以用更简单的局部近似表示的复杂目标函数。不幸的是,使用这些方法,对新的实例进行分类的成本总是很高的,在存在维度诅咒的情况下,这些方法可能会留下更大的足迹,因为所有实例的所有属性都被考虑在内。分类器和回归将在本节和即将到来的下一章中介绍。使用分类器,我们试图预测一个类别,而使用回归,我们预测一个实数。我们将首先查看最近邻算法,它可以用于分类和回归问题。
死记硬背学习者是实例化分类器之一,专注于记忆整个训练数据。分类主要是在目标属性值与训练示例中的属性值完全匹配时才进行。另一个分类器是最近邻,它根据最近的邻居进行分类。在下节中,我们将深入探讨最近邻算法。
最近邻
在我们开始理解最近邻算法是什么之前,让我们从一个例子开始;以下图表显示了数据点 X 和 Y 的绘制,它们有两个类别:星星和三角形。我们不必真正担心确切的数据表示或数据点。如果我们必须直观地解决找出那个特定红色方块数据点的问题,那么答案显然是一个绿色三角形。这是一种直觉,而且,在不真正理解或分析数据点的情况下,我们可以得出这个结论。但实际上发生的情况是,我们已经看到了数据点上下文中邻居的特征,并预测了新数据点可能属于的类别。总的来说,学习算法的基础实际上是附近或邻近点的行为。

最近邻算法是一种利用直觉基本技术的算法。该算法使用一些将在下文讨论的距离测量技术来找到最近邻。现在让我们扩展到另一个示例数据集;再次,需要一个新的带有问号(?)的数据点来进行分类。

假设新的数据点所属的类别是黄色星号。距离度量的重要方面之一是最近邻永远不会只是一个单独的点,而通常是一个区域。以下图显示了该区域以及所有属于该区域的点都属于黄色星号类别。这个区域被称为Voronoi 单元。这个区域通常是具有直线边界的多边形,如果使用的距离度量是欧几里得距离度量。

对于每个训练示例,如果计算了 Voronoi 单元,我们可以看到如以下图所示的 Voronoi 网格。这种网格表示空间被划分为非重叠区域,通常每个区域有一个示例。

单元的大小由可用示例的数量确定。示例越多,区域的大小就越小。Voronoi 网格的另一个有趣方面是,可以雕刻出边界,形成类别的分隔,如下面的图所示。粗线的右侧属于三角形类别,左侧属于星号类别。

使用最近邻方法的一个主要问题是其对异常值的敏感性,这会真正搞乱边界,解决这个问题的方法之一是考虑多个邻居,这将使模型更加稳定和光滑。因此,考虑 k 个邻居意味着 k-最近邻算法。

现在我们来看一下 KNN 分类算法是如何工作的:
给定 {x[i], y[i]} 训练示例,其中 x[i] 表示属性值,y[i] 表示类别标签,并且有一个新的测试点 X 需要被分类,在 KNN 分类算法中执行以下步骤:
-
在每个给定的 x[i] 值之间计算 x 和 x[i] 的距离。
-
选择 k 个最近的邻居 xi1, … xik 以及相应的类别标签 yi1, … yik。
-
返回列表 yi1, … yik 中出现频率最高的 y。
现在我们来看一下 KNN 回归算法在重要差异中的不同之处。与输出一个类别不同,我们将输出实数,如评分或年龄等。算法是相同的,但唯一的区别在于返回值,即第 3 步,我们取 y's 的平均值,而不是最频繁的值。
KNN 中的 k 值
k 的值对 KNN 的性能有巨大的影响。如果 k 的值太大,KNN 算法会使用前一个值,从而可能导致不准确。在 k 值太小的情况下,模型会像前一个章节中看到的那样对异常值过于敏感。因此,准确的 k 值通常位于最小值和最大值之间。方法是选择这个范围内的一个值,并在训练数据上测量误差,选择一个给出最佳泛化性能的 k 值。
以下图展示了点 x 的 1、2 和 3 个最近邻:

点 x 的 k-最近邻是所有与 x 距离最小的 k 个数据点。
KNN 中的距离度量
这是最近邻算法的一个属性,可能是唯一可以实验或尝试替代方法的领域。有许多距离测量选项,在本节中,我们将讨论一些常用的度量。距离度量的主要目的是识别相似或不相似的例子。与 k 值类似,距离度量决定了 KNN 的性能。
欧几里得距离
欧几里得距离是数值属性的默认选项。距离度量公式如下:

欧几里得距离度量是对称的和球形的,并且对所有的维度都同等对待。这个度量方法的一个缺点是对单个属性中极端值的敏感性。这与均方误差类似。
汉明距离
汉明距离度量是我们需要处理分类属性时的默认选项。汉明距离度量的主要功能是检查两个属性是否相等。当它们相等时,距离为 0,否则为 1;实际上,我们检查两个实例之间的属性数量。汉明距离度量的公式如下:

不同的属性在不同的尺度上被测量,因此需要对属性进行归一化。
Minkowski 距离
我们现在将探讨p-范数距离度量族,它是欧几里得距离度量的推广。这些度量相对比较灵活。
Minkowski 距离公式与欧几里得距离类似,如下所示:

如果 p=0,距离度量是汉明度量。
如果 p=1,距离度量是曼哈顿度量。
如果 p=2,距离度量是欧几里得度量。

基于案例推理(CBR)
CBR 是一种高级基于实例的学习方法,用于更复杂的实例对象。除了拥有固定的过去案例数据库外,CBR 还积累和存储了分类的新数据。像所有其他基于实例的学习方法一样,CBR 通过匹配新案例来寻找相似的过去案例。在这种情况下,应用基于语义网的距离度量进行匹配数据。这是一种不同于欧几里得距离度量等方法的图示匹配方法。
与其他基于实例的学习方法类似,CBR 是一种懒惰学习器,其力量来自于案例的组织和内容。
重复使用过去的案例是人类解决问题和推理方式的关键因素之一。由于 CBR 是基于人类问题解决建模的,因此对人类来说更容易理解。这意味着 CBR 的工作方式可以通过专家或专家咨询来改变。
由于其处理非常复杂实例的能力,CBR 常用于医学诊断,用于检测心脏病、听力缺陷和其他相对复杂的情况。以下图展示了典型的 CBR 学习流程,并被称为 R4 模型。
机器学习中的懒惰学习就是将泛化过程推迟到查询时间,超出训练数据。其优点是现在可以执行并行处理,但缺点是内存需求更高。以下图表展示了一个 CBR 函数的过程流程:

-
首先,接收到一个新案例。
-
然后,触发一个匹配过程,将接收到的案例与具有现有案例和已分类案例的案例库进行匹配。这是检索过程。
-
检查匹配的案例是否完美地符合新案例。
-
如果是,则重复使用,如果不是,则修改。
-
输出最终的推荐解决方案。
-
在以后的某个时间点,基于事实,如果推荐是一致的,保留学习并添加到案例库中。学习阶段也可能向知识库添加规则,这些规则最终的事实建议。
本地加权回归(LWR)
LWR 是线性回归的一个特例,由于噪声,数据集不再是线性的,线性回归对训练数据欠拟合。通过为最近邻分配权重来解决非线性问题。分配的权重通常对于需要预测的数据点更接近的数据点更大。
实现 KNN
请参考本章提供的源代码以实现 k-Nearest Neighbor 算法(在每个技术文件夹下的.../chapter6/...路径下)。
使用 Mahout
请参考文件夹.../mahout/chapter6/knnexample/。
使用 R
请参考文件夹.../r/chapter6/knnexample/。
使用 Spark
请参考文件夹.../spark/chapter6/knnexample/。
使用 Python(scikit-learn)
请参考文件夹.../python scikit learn/ chapter6/knnexample/。
使用 Julia
请参阅文件夹 .../julia/chapter6/knnexample/。
基于核方法的机器学习
我们刚刚了解了基于实例的学习方法,并深入探讨了最近邻算法及其特定的实现方面。在本节中,我们将探讨核函数以及基于核的机器学习算法。
简单来说,核是一个相似性函数,它被输入到机器学习算法中。它接受两个输入并建议它们有多相似。例如,如果我们面临一个分类图像的任务,输入数据是一个键值对(图像,标签)。因此,在流程方面,图像数据被提取,计算特征,然后将特征向量输入到机器学习算法中。但是,在相似性函数的情况下,我们可以定义一个核函数,它内部计算图像之间的相似性,并将其与图像和标签数据一起输入到学习算法中。这样做的结果是得到一个分类器。
标准的回归或 SVM 或感知器框架使用核函数,并且只使用向量。为了满足这一需求,我们将机器学习算法表示为点积,以便可以使用核函数。
核函数比特征向量更可取。有许多优点;其中一个关键原因在于计算的简便性。此外,与点积相比,特征向量需要更多的存储空间。可以编写机器学习算法来使用点积,并将其映射到使用核函数。这样,就可以完全避免使用特征向量。这将使我们能够轻松地处理高度复杂、计算效率高且性能优异的核函数,而无需真正开发多维向量。
核函数
让我们了解核函数究竟是什么;以下图示通过一个简单的 1 维示例来表示 1 维函数。假设给定的点如下:

如前所述的一般 1 维超平面将是一条垂直线,没有其他垂直线可以分离数据集。如果我们观察下一个 2 维表示,如所示,有一个超平面(2 维空间中的任意线)将红色和蓝色点分开,因此可以使用 SVM 进行分离。

随着维度空间的增长,需要能够分离数据的需求增加。这种映射,x -> (x, x2),被称为核函数。
在维度空间不断增长的情况下,计算变得更加复杂,核技巧需要被应用以廉价地解决这些计算。
支持向量机 (SVM)
支持向量机用于解决分类问题。总的来说,作为一个方法,目标是找到一个能够有效划分数据类别表示的超平面。超平面可以定义为二维空间中线的推广和三维空间中平面的推广。现在让我们举一个例子来了解 SVM 如何对线性可分二元数据集起作用。我们将使用与最近邻算法中相同的例子。以下图表表示具有两个特征X和Y的数据以及可用的类别为三角形和星星。

SVM 的目标是找到能够分离这两个类别的超平面。以下图表描绘了一些可以划分数据集的可能超平面。最佳超平面的选择由为两个类别留下的最大边缘程度定义。边缘是超平面与分类中最接近的点之间的距离。

让我们取两个超平面中的两个,并检查由M1和M2表示的边缘。很明显,边缘M1 > M2,因此选择最佳分离的超平面是新平面,位于绿色和蓝色平面之间。

新的平面可以用线性方程表示为:
f(x) = ax + b
假设这个方程给出了三角形类别的所有≥1 的值,对于星星类别,≤-1。这个平面与两个类别中最接近的点的距离至少为 1;模长为 1。
对于三角形,f(x) ≥ 1,对于星星,f(x) ≤ 1或|f(x)| = 1。
使用以下公式可以计算超平面与点之间的距离。
M1 = |f(x)| / ||a|| = 1 / ||a||
总边缘是1 / ||a|| + 1 / ||a|| = 2 / ||a|。
为了最大化可分性,这是 SVM 的目标,我们需要最大化||a||值。这个值被称为权重向量。最小化a权重值的过程是一个非线性优化任务。一种方法是使用Karush-Kuhn-Tucker(KKT)条件,使用拉格朗日乘子λ[i]。


让我们取两个属性X和Y之间的两个点的例子。我们需要找到一个点,这个点在这两个点之间具有最大的距离。这个要求在下面的图中表示。最优点用红色圆圈表示。

最大边缘权重向量与从(1, 1)到(2, 3)的线平行。权重向量在(1,2),这成为一条决策边界,位于中间,垂直于通过(1.5, 2)的线。
因此,y = x1 +2x2 − 5.5,几何边缘计算为√5。
计算 SVM 的步骤如下:
对于 w = (a, 2a),其中 a 是点 (1,1) 和 (2,3) 的函数,可以表示如下:
对于点 (1,1),有 a + 2a + ω[0] = -1
对于点 (2,3),有 2a + 6a + ω[0] = 1
权重可以按以下方式计算:


这些是支持向量:

最后,最终的方程如下:

不可分数据
SVMs 可能能帮助你找到存在的分离超平面。可能存在无法定义超平面的情况,这可能是由于数据中的噪声引起的。实际上,另一个原因可能是非线性边界。下面的第一个图表展示了噪声,第二个图表展示了非线性边界。


在数据噪声引起的问题的情况下,最好的方法是减少边际并引入松弛。

通过引入核函数可以解决非线性边界问题。以下图表展示了可以引入的一些核函数:

实现 SVM
请参考本章提供的源代码以实现 SVM 算法(源代码路径为 .../chapter6/...,位于每个技术文件夹下)。
使用 Mahout
请参考文件夹 .../mahout/chapter6/svmexample/。
使用 R
请参考文件夹 .../r/chapter6/svmexample/。
使用 Spark
请参考文件夹 .../spark/chapter6/svmexample/。
使用 Python (Scikit-learn)
请参考文件夹 .../python-scikit-learn/chapter6/svmexample/。
使用 Julia
请参考文件夹 .../julia/chapter6/svmexample/。
摘要
在本章中,我们探讨了两种学习算法,基于实例和核方法,并看到了它们如何解决分类和预测需求。在基于实例的学习方法中,我们详细探讨了最近邻算法,并看到了如何使用我们的技术栈 Mahout、Spark、R、Julia 和 Python 来实现它。同样,在基于核的方法中,我们探讨了 SVM。在下一章中,我们将介绍基于关联规则的学习方法,重点关注 Apriori 和 FP-growth 算法。
第七章:基于关联规则的学习
在前几章中,我们已经介绍了决策树、实例和基于核的监督学习和无监督学习方法。在前几章中,我们还探讨了这些学习算法中最常用的算法。在本章中,我们将介绍基于关联规则的学习,特别是 Apriori 和 FP-Growth 算法等。我们将学习这项技术的基礎,并使用 Apache Mahout、R、Julia、Apache Spark 和 Python 等工具获得实际操作指导。以下图表展示了本书中涵盖的不同学习模型。本章将详细讨论橙色突出显示的技术。

本章深入探讨了以下主题:
-
理解基于关联规则学习模型的基礎和核心原理
-
关联规则的核心应用案例,例如市场篮子问题
-
关键术语,如项集、提升度、支持度、置信度和频繁项集,以及规则生成技术
-
深入探讨基于关联规则的算法,如 Apriori 和 FP-Growth;在大型数据集的背景下比较和对比 Apriori 和 FP-Growth
-
一些高级关联规则概念(如相关规则和序列规则)的概述和目的
-
Apache Mahout、R、Apache Spark、Julia 和 Python(scikit-learn)库和模块的示例实现。
基于关联规则的学习
基于关联规则的机器学习处理的是寻找频繁模式、关联和交易,这些可以用于分类和预测需求。基于关联规则的学习过程如下:给定一组交易,找到规则并使用这些规则根据交易中其他项目的发生来预测项目的发生是关联规则学习。以下图表表示了机器学习的范围:

关联规则——一个定义
关联规则是对一个模式的表现,描述了在另一个事件发生的情况下,一个事件发生的概率。通常,关联规则的语法遵循如果...那么语句,这些语句将来自存储库的两个无关数据集联系起来。简而言之,它有助于找到经常一起使用的对象之间的关系。关联规则的目标是使用大数据集找到所有支持度大于最小支持度的项目集,以预测置信度大于最小置信度的规则。关联规则最常用的例子之一是市场篮子示例。为了详细说明市场篮子示例,如果一个顾客购买了 iPad,那么他或她很可能也会购买 iPad 保护套。
关联规则中使用两个重要标准,支持度和置信度。每个关联规则都应该同时具有最小置信度和最小支持度。这通常是用户定义的。
现在,让我们看看支持度、置信度和提升度度量是什么。让我们考虑之前解释的相同例子,如果 X 则 Y,其中 X 是购买 iPad,Y 是购买 iPad case。
然后,支持度定义为在所有购买或交易次数中,X 和 Y 一起购买的总频率。

置信度可以定义为 X 和 Y 一起购买的频率与 X 单独购买的频率之比。

提升度定义为 X 的支持度除以 X 的支持度乘以 Y 的支持度。


在理解这些度量的重要性之前,让我们以一个例子来看看这个上下文中使用的术语。仓库中物品的集合称为项集,表示为 I = { i[1], i[2], …. i[n]},所有交易的集合,其中每个交易由项集的子集组成,表示为 T = { t[1], t[2], …. t[n]},其中 t[x] 是 I 的一个具有唯一交易标识符(UTI)的子集。
现在让我们用一个例子来表示物品、交易和度量。
考虑五个项目和五个交易,如图所示:
I = {iPad(A), iPad case(B), iPad scratch guard(C), Apple care (D), iPhone (E)}

T = {{ iPad, iPad case, iPad scratch guard }, { iPad, iPad scratch guard, Apple care }, { iPad case, iPad scratch guard, Apple care }, { iPad, Apple care, iPhone }, { iPad case, iPad scratch guard, iPhone }}
下表显示了每个识别出的规则的支持度、置信度和提升度值。
| # | 规则 | 支持度 | 置信度 | 提升度 |
|---|---|---|---|---|
| 1 | 如果购买 iPad (A),则也会购买 iPhone (D) | 2/5 | 2/3 | 10/9 |
| 2 | 如果购买 iPad scratch guard(C),则也会购买 iPad (A) | 2/5 | 2/4 | 5/6 |
| 3 | 如果购买 iPad (A),则也会购买 iPad scratch guard (C) | 2/5 | 2/3 | 5/6 |
| 4 | 如果购买 iPad case(B) 和 iPad scratch guard (C),则也会购买 apple care (D) | 1/5 | 1/3 | 5/9 |
从这些项集中,基于支持和置信度的计算,可以确定频繁项集。关联规则挖掘的目的是找到满足以下标准的规则:
-
支持度 ≥ 最小支持度(minsup)阈值
-
置信度 ≥ 最小置信度(minconf)阈值
频繁项集生成和关联规则挖掘涉及以下步骤:
-
列出所有可能的关联规则。
-
计算每个规则的支撑度和置信度。
-
删除不满足最小支持度(minsup)和最小置信度(minconf)阈值值的规则。
这种方法称为暴力方法,通常被认为是计算上不可行的。
小贴士
来自同一项集的规则通常具有相同的支撑度,但置信度不同。最小支持度(minsup)和最小置信度(minconf)是在问题定义陈述中达成一致的价值。例如,最小支持度和置信度可以取百分比值,如 75%和 85%。
为了避免所有昂贵的计算,我们可以将这个过程简化为两个步骤:
-
频繁项集生成:这需要生成所有支持度 ≥ minsup 的项集
-
规则生成:从识别出的频繁项集中生成置信度最高的规则
当有五个项目时,有 32 个候选项集。以下图显示了五个项目的项集组合:A、B、C、D和E:

给定项目数量,可能的项集和规则数量在此定义:
给定d个唯一项目:
可能的项集总数 = 2^d
计算总可能关联规则的标准公式在此定义:

例如,如果d等于 6,那么可能的项集总数 = 2^d = 64
因此,可能的关联规则总数 = 602 条规则
下图显示了项目数量与可能的关联规则之间的关系。

生成频繁项集和关联规则的高效方法决定了关联规则算法的效率。在接下来的章节中,我们将详细介绍 Apriori 和 FP-Growth 算法。
Apriori 算法
在本节中,我们将通过一个示例逐步介绍 Apriori 算法。Apriori 算法如下所述:

小贴士
Apriori 原理——对于所有频繁项集,其子集也必须是频繁的。
考虑前一个示例中的五个项目
I = {iPad(A), iPad case(B), iPad scratch guard(C), Apple care (D), iPhone (E)},以下九个事务。假设最小支持度计数为两个:
| TID | 在机器学习中的目的或意义 |
|---|---|
| 1 | iPad(A)、iPad case(B)和 iPhone(E) |
| 2 | iPad case(B)和 Apple care(D) |
| 3 | iPad case(B)和 iPad scratch guard(C) |
| 4 | iPad(A)、iPad case(B)和 Apple care(D) |
| 5 | iPad(A)和 Apple care(D) |
| 6 | iPad case(B)和 iPad scratch guard(C) |
| 7 | iPad(A)和 Apple care(D) |
| 8 | iPad(A)、iPad case(B)、iPad scratch guard(C)和 iPhone (E) |
| 9 | iPad(A), iPad case(B), and iPad scratch guard(C) |
使用之前的数据集调试之前的算法:
-
从之前的交易中获取每个项目的出现次数(C[1]):
Itemset Support count {iPad(A)} 6 {iPad case(B)} 7 {iPad scratch guard(C)} 6 {Apple care(D)} 2 {iPhone(E)} 2 从C[1]确定频繁 1 项集(L[1]):
| Itemset | Support count |
| --- | --- | --- |
| {iPad(A)} | 6 |
| {iPad case(B)} | 7 |
| {iPad scratch guard(C)} | 6 |
| {Apple care(D)} | 2 |
| {iPhone(E)} | 2 | -
生成 2 项候选集(C[2])并扫描数据集以确定支持计数:
Itemset Support count {iPad(A), iPad case(B)} 4 {iPad(A), iPad scratch guard(C)} 4 {iPad(A), Apple care(D)} 1 {iPad(A), iPhone(E)} 2 {iPad case(B), iPad scratch guard(C)} 4 {iPad case(B), Apple care(D)} 2 {iPad case(B), iPhone(E)} 2 {iPad scratch guard(C), Apple care(D)} 0 {iPad scratch guard(C), iPhone(E)} 1 {Apple care(D), iPhone(E)} 0 -
从C[2]确定频繁 2 项集(L[2]):
Itemset Support count {iPad(A), iPad case(B)} 4 {iPad(A), iPad scratch guard(C)} 4 {iPad(A), Apple care(D)} 2 {iPad case(B), iPad scratch guard(C)} 4 {iPad case(B), Apple care(D)} 2 {iPad case(B), iPhone(E)} 2 -
生成 3 项候选集(C[3])。
-
最后,扫描数据集以确定支持计数和频繁 3 项集识别。
这与之前遵循的步骤类似,但我们将演示如何根据 Apriori 原则有效地应用剪枝来识别频繁项集。首先,我们识别可能的子集项集。然后检查是否有任何子集项集不属于频繁项集列表。如果没有找到,我们消除该 3 项集的可能性。
| C3 | Itemset | Possible subset itemsets |
|---|---|---|
| 1✓ | {A,B,C} | {A,B}✓ |
| 2✓ | {A,B,D} | {A,B}✓ |
| 3✕ | {A,C,D} | {A,C}✓ |
| 4✕ | {B,C,D} | {B,C}✓ |
| 5✕ | {B,C,E} | {B,C}✓ |
| 6✕ | {B,D,E} | {B,D}✓ |
在前一个表中,使用 Apriori 技术剪枝了✕项集,并使用了步骤 4(L[2])的数据。为了便于理解,项集使用项代码A、B、C、D和E表示,而不是实际名称。3 项集候选集可以按以下方式识别:
| C[3] | Itemset | Support Count |
|---|---|---|
| 1 | {iPad(A), iPad case (B), iPad scratch guard(C)} | 2 |
| 2 | {iPad(A), iPad case (B), Apple care(C)} | 2 |
因此,频繁的 3 项集如下:
| L[3] | Itemset | Support Count |
|---|---|---|
| 1 | {iPad(A), iPad case (B), iPad scratch guard(C)} | 2 |
| 2 | {iPad(A), iPad case (B), Apple care(C)} | 2 |
-
生成 4-项集候选(C[4])。
-
最后,扫描数据集以获取支持度计数和频繁 3-项集识别(L[4])。
如我们所见,剪枝在这里停止,因为没有更多的 C[3] 选项可用。
Apriori 算法效率不高,因为它需要多次数据集扫描。然而,有一些技术可以提高效率。以下是一些方法:
-
如果一个事务不包含任何频繁项集,则它没有用,不需要参与后续扫描
-
任何在数据集中频繁出现的项集至少应该在数据集的一个分区中频繁出现
-
应用采样,包括整个数据集的一个子集,具有较低的支持度阈值,将提高效率
规则生成策略
假设我们有一个频繁项集 {A, B, C, D},可能的候选规则如下:
ABC→D
ABD→C
ACD→B
BCD→A
AB→CD
AC→BD
AD→BC
BC→AD
BD→AC
CD→AB
A→BCD
B→ACD
C→ABD
D→ABC
标准公式是,对于频繁项集中的每个 k 个项,可以定义 2k-2 个可能的候选规则。只有具有高置信度的规则可以保留。以下图示了标记低置信度规则并去除它们:

定义适当最小支持度的规则
在定义基于关联规则挖掘的最小支持度阈值时,需要遵循的一些重要指南如下:
-
最小支持度太高:这将导致丢失包含稀有物品的项集
-
最小支持度太低:这将导致计算开销,因为需要更多的扫描
Apriori – 不足之处
现在很清楚,在 Apriori 算法中,对于每个 k 项集,我们都需要使用 (k-1) 个频繁项集,当数据库扫描完成后,使用模式匹配方法。主要瓶颈是两个巨大的候选集和多次数据库扫描。让我们看看一个例子——如果有 10⁴个频繁 1 项集,那么这将导致 10⁷个候选 2 项集。并且对于每个 n 项集,需要 n + 1 次扫描。
解决这个问题的方法是完全避免候选项集的生成,一种解决方法是将大型数据集或数据库压缩成一个紧凑的频繁模式树(FP-tree),这将避免昂贵的扫描。
有几种方法可以优化 Apriori 实现,以下是一些重要的方法:
-
方法 1—基于项集计数的近似方法:为每个 k 项集桶设置一个阈值,如果该项集的计数低于阈值,则该桶将不会处理。这反过来减少了需要考虑处理的项集桶,从而提高了效率。
-
方法 2—事务消除/计数:如果一个事务不包含目标 k 项集,则该事务不会增加价值或没有意义进行处理。因此,这种方法是识别这些事务并将它们从处理中排除。
-
方法 3—分区:任何在数据集中可能频繁的项集也必须在数据集的分区中频繁;否则,项集可能会被排除在处理之外。
-
方法 4—采样:这是一种考虑样本或大数据集子集的更简单方法,并运行挖掘过程。这将减少 k 值,从而减少频繁 k 项集。
-
方法 5—动态项集计数:这是最有效的方法之一,它只在新项集在其所有子项集中频繁时才包括新项集。
尽管 Apriori 有优化技术;但它由于固有的昂贵扫描而效率低下,这需要解决。这使我们来到了基于关联规则学习的下一个算法,即FP-growth算法。
FP-growth 算法
FP-growth 算法是一种高效且可扩展的挖掘频繁模式、从而关联规则挖掘的替代方法。它解决了 Apriori 算法可能遇到的大部分性能瓶颈。它允许在不实际生成候选项集的情况下生成频繁项集。此算法主要有两个步骤:
-
从数据库中构建紧凑的数据结构称为 FP 树
-
直接从 FP 树中提取频繁项集
让我们考虑与 Apriori 算法中使用的相同示例。总共有五个项目(来自上一节中的示例):
I 是{iPad(A), iPad 保护壳(B), iPad 防刮保护膜(C), Apple Care (D), iPhone (E)},以及以下九个事务。假设最小支持计数为二:
| TID | 事务项集 |
|---|---|
| 1 | iPad(A), iPad 保护壳(B), 和 iPhone(E) |
| 2 | iPad 保护壳(B), Apple Care(D) |
| 3 | iPad 保护壳(B), iPad 防刮保护膜(C) |
| 4 | iPad(A), iPad 保护壳(B), 和 Apple Care(D) |
| 5 | iPad(A), Apple Care(D) |
| 6 | iPad 保护壳(B), iPad 防刮保护膜(C) |
| 7 | iPad(A), Apple Care(D) |
| 8 | iPad(A), iPad 保护壳(B), iPad 防刮保护膜(C), 和 iPhone (E) |
| 9 | iPad(A), iPad 保护壳(B), 和 iPad 防刮保护膜(C) |
我们现在将查看为该数据库构建 FP 树:
-
识别/计算最小支持计数。由于需要 30%,最小支持计数计算如下:
最小支持计数 = 30/100 * 9 = 2.7 ~ 3
-
计算单项集的出现频率。此外,根据支持计数,添加优先级:
项集 支持计数 优先级 {iPad(A)} 6 2 {iPad 保护壳(B)} 7 1 {iPad 防刮保护膜(C)} 6 3 {Apple care(D)} 2 4 {iPhone(E)} 2 5 -
根据优先级对每笔交易的物品进行排序:
TID 交易项集 根据优先级重新排序的项集 1 iPad(A),iPad 保护壳(B), 以及 iPhone(E) iPad 保护壳(B), iPad(A), 以及 iPhone(E) 2 iPad 保护壳(B), Apple care(D) iPad 保护壳(B), Apple care(D) 3 iPad 保护壳(B),iPad 防刮保护膜(C) iPad 保护壳(B),iPad 防刮保护膜(C) 4 iPad(A),iPad 保护壳(B),以及 Apple care(D) iPad 保护壳(B),iPad(A),以及 Apple care(D) 5 iPad(A),Apple care(D) iPad(A),Apple care(D) 6 iPad 保护壳(B), iPad 防刮保护膜(C) iPad 保护壳(B), iPad 防刮保护膜(C) 7 iPad(A),Apple care(D) iPad(A),Apple care(D) 8 iPad(A),iPad 保护壳(B),iPad 防刮保护膜(C),以及 iPhone (E) iPad 保护壳(B), iPad(A), iPad 防刮保护膜(C), 以及 iPhone (E) 9 iPad(A),iPad 保护壳(B),以及 iPad 防刮保护膜(C) iPad 保护壳(B), iPad(A), 以及 iPad 防刮保护膜(C) -
为TID = 1的交易创建 FP 树,并按顺序排列的项集是 iPad 保护壳(B),iPad(A),以及 iPhone(E)。
![FP-growth 算法]()
-
现在,扫描数据库以查找TID = 2,iPad 保护壳 (B) 和 Apple care(D)。更新后的 FP 树将如下所示:
![FP-growth 算法]()
-
按照 L 的顺序扫描所有交易并相应地更新 FP 树。最终的 FP 树将如下所示。请注意,每次在交易中遇到重复的项目时,节点上的计数值都会增加。
![FP-growth 算法]()
-
为每笔交易生成一个条件 FP 树并定义条件模式基。
-
最后,生成频繁模式。给定数据集的结果如下所示:
E: {B, E: 2}, {A, E: 2}, {B, A, E: 2} D: {B, D: 2} C: {B, C: 4}, {A, C: 4}, {B, A, C: 2} A: {B, A: 4}
Apriori 与 FP-growth 对比
下面的图显示了不同 minsup 阈值值算法之间的关系:

图片来源:Pier Luca Lanzi 教授的文章
FP-growth 算法的优点在此详细说明:
-
完整地保留了频繁模式挖掘的信息,而不会在长交易中打断模式。
-
通过消除不相关信息(在事先避免不频繁项集)来压缩数据。
-
FP-growth 算法以分而治之的模式工作,将数据集根据迄今为止发现的频繁项集模式进行分解。这减少了搜索到数据集的子集,而不是完整的数据库。
-
在这种情况下不会生成候选项集,因此不需要进行测试。
实现 Apriori 和 FP-growth
请参考本章提供的源代码以实现 Apriori 分类器(源代码路径在各个技术文件夹下的.../chapter7/...中)。
使用 Mahout
请参考代码文件文件夹 .../mahout/chapter7/aprioriexample/。
请参考代码文件文件夹 .../mahout/chapter7/fpgrowthexample/。
使用 R
请参考代码文件文件夹 .../r/chapter7/aprioriexample/。
请参考代码文件文件夹 .../r/chapter7/fpgrowthexample/。
使用 Spark
请参考代码文件文件夹 .../spark/chapter7/aprioriexample/。
请参考代码文件文件夹 .../spark/chapter7/fpgrowthexample/。
使用 Python (Scikit-learn)
请参考代码文件文件夹 .../python-scikit-learn/ chapter7/aprioriexample/。
请参考代码文件文件夹 .../python-scikit-learn/chapter7/fpgrowthexample/。
使用 Julia
请参考代码文件文件夹 .../julia/chapter7/aprioriexample/。
请参考代码文件文件夹 .../julia/chapter7/fpgrowthexample/。
摘要
在本章中,你学习了基于关联规则的学习方法以及 Apriori 和 FP-growth 算法。通过一个共同示例,你学习了如何使用 Apriori 和 FP-growth 算法进行频繁模式挖掘,并通过逐步调试算法来学习。我们还比较和对比了算法及其性能。我们提供了使用 Mahout、R、Python、Julia 和 Spark 的 Apriori 示例实现。在下一章中,我们将介绍贝叶斯方法,特别是朴素贝叶斯算法。
第八章:基于聚类的学习
在本章中,我们将介绍基于聚类的学习方法,特别是 k-means 聚类算法等。基于聚类的学习是一种无监督学习技术,因此无需对目标属性有具体的定义。您将学习该技术的基礎和高级概念,并获得使用 Apache Mahout、R、Julia、Apache Spark 和 Python 实现 k-means 聚类算法的实践指导。
以下图表展示了本书中涵盖的不同学习模型,以及用橙色突出显示的技术将在本章中详细讨论:

下面的主题将在本章中深入探讨:
-
基于聚类的学习方法的核心原则和目标
-
如何表示簇和理解所需的距离测量技术
-
深入学习 k-means 聚类、选择合适的聚类算法和簇评估规则。更重要的是,选择合适的簇数量。
-
层次聚类的概述、数据标准化、发现空洞和数据区域。
-
使用 Apache Mahout、R、Apache Spark、Julia 和 Python(scikit-learn)库和模块的示例实现。
基于聚类的学习
基于聚类的学习方法被识别为一种无监督学习任务,其中学习从没有特定目标属性开始,数据被探索以寻找其中的内在结构。
以下图表展示了本章将要介绍的基于聚类的学习方法范围:

聚类技术的首要目标是找到数据中的相似或同质群体,这些群体被称为簇。这样做的方式是——相似或简而言之,彼此靠近的数据实例被分组到一个簇中,而不同的实例被分组到不同的簇中。以下图表展示了图表上的数据点,以及簇是如何被标记的(在这里,是通过纯粹直觉)由三个自然簇:

因此,簇可以被定义为包含彼此相似且与其他簇中的对象不同的对象的集合。以下图表展示了聚类过程:

聚类的简单示例可以如下:
-
衬衫根据尺寸分为小号(S)、中号(M)、大号(L)、加大号(XL)等。
-
目标营销:根据客户的相似性对客户进行分组
-
文本文档的分组:这里的要求是组织文档,并基于它们的内容相似性构建主题层次结构
实际上,聚类技术在许多领域都有非常广泛的应用,例如考古学、生物学、市场营销、保险、图书馆、金融服务以及许多其他领域。
聚类类型
聚类分析主要关注的是在给定数据的情况下,可以用来自动找到聚类的算法。主要有两类聚类算法;如下所示:
-
层次聚类算法
-
划分聚类算法
![聚类类型]()
层次聚类算法定义了具有层次结构的聚类,而划分聚类算法定义了将数据集划分为互斥分区的聚类。
层次聚类
层次聚类是关于定义具有层次结构的聚类,这可以通过迭代地将较小的聚类合并成较大的聚类,或者将较大的聚类划分为较小的聚类来实现。由聚类算法产生的这种聚类层次结构被称为树状图。树状图是表示层次聚类的一种方式,用户可以根据树状图定义的级别实现不同的聚类。它使用一个相似度尺度,表示从较大的聚类中分组出来的聚类之间的距离。以下图展示了层次聚类的树状图表示:

存在另一种表示层次聚类的简单方法;那就是维恩图。在这种表示中,我们圈出属于聚类的数据点。以下图展示了五个数据点的维恩图表示:

层次聚类中有两种聚类算法:聚合聚类算法和划分聚类算法。
聚合聚类算法采用自底向上的方法,将一组聚类合并成一个更大的聚类。划分聚类算法采用自顶向下的方法,将一个聚类划分为子聚类。确定哪个聚类将被考虑合并或划分,是通过贪婪方法决定的,距离测量在这里变得至关重要。让我们快速回顾一下第六章中的实例学习方法,基于实例和核方法的学习。我们已经介绍了欧几里得距离、曼哈顿距离和余弦相似度作为数值数据中最常用的相似性度量,以及汉明距离用于非数值数据。对于层次聚类,实际上不需要实际数据点,只需要距离度量矩阵就足够了,因为分组是基于距离进行的。
层次聚类算法的步骤可以定义为如下:
-
从如下聚类开始,例如 S1={X1}, S2={X2} … Sm= {Xm}。
-
找到一组最近的聚类并将它们合并成一个单独的聚类。
-
重复步骤 2,直到形成的聚类数量等于定义的数量。
划分聚类
与层次聚类算法相比,划分聚类算法不同,因为聚类或分区是通过使用特定预定义的标准来生成和评估的,该标准是特定领域的。由于每个形成的聚类都是互斥的,因此聚类之间永远不会存在层次关系。实际上,每个实例都可以放置在仅有的一个k个聚类中。要形成的聚类数量(k)作为输入输入到该算法中,这组k个聚类是划分聚类算法的输出。在本章中我们将要介绍的最常用的划分聚类算法之一是 k-means 聚类算法。
在我们深入探讨 k-means 聚类算法之前,让我们在这里快速定义一下。输入为k,表示期望的聚类数量,将定义k个中心或质心,这将有助于定义k个分区。基于这些中心(质心),算法识别成员并因此构建一个分区,然后根据识别的成员重新计算新的中心。这个过程会迭代进行,直到暴露出清晰且最优的不相似度,使分区真正独特。因此,质心的准确性是分区聚类算法成功的关键。以下是在基于质心的划分聚类算法中涉及到的步骤:
输入:k(聚类数量)和d(包含n个对象的数据库)
输出:一组k个聚类,这些聚类将所有对象到识别的中位数(质心)的不相似度之和最小化。
-
识别k个对象作为第一组质心。
-
将剩余的最近质心的对象分配到聚类中。
-
随机选择一个非质心对象,并重新计算将进行交换以形成新的质心集的总点数,直到不再需要交换。
层次聚类和划分聚类技术在许多方面本质上存在关键差异,其中一些包括一些基本假设;执行时间假设、输入参数和结果聚类。通常,划分聚类比层次聚类更快。虽然层次聚类可以仅使用相似度度量进行工作,但划分聚类需要指定聚类数量以及初始中心的相关细节。与划分聚类结果产生的精确且精确的“k”聚类相比,层次聚类技术的聚类定义更为主观。
小贴士
聚类的质量取决于选择的算法、距离函数和应用。当簇间距离最大化,簇内距离最小化时,簇质量被认为是最佳的。
k-means 聚类分析算法
在本节中,我们将深入探讨 k-means 聚类分析算法。k-means 是一种划分聚类算法。
设数据点集(或实例)如下:
D = {x[1], x[2], …, x[n]}, 其中
xi = (xi[1], xi[2], …, xi[r]) 是实值空间 X ⊆ R[r,] 中的一个向量,且 r 是数据中的属性数量。
k-means 算法将给定的数据划分为 k 个簇,每个簇都有一个称为中心点的中心。
k 由用户指定。
给定 k,k-means 算法的工作原理如下:
算法 k-means (k, D)
-
识别 k 个数据点作为初始中心点(簇中心)。
-
重复步骤 1。
-
对于每个数据点 x ϵ D 执行以下操作。
-
计算数据点 x 到中心点的距离。
-
将 x 分配到最近的中心点(中心点代表一个簇)。
-
endfor
-
使用当前的簇成员资格重新计算中心点,直到满足停止标准。
k-means 聚类分析的收敛或停止标准
以下列表描述了 k-means 聚类分析算法的收敛标准:
-
数据点重新分配到不同簇的数量为零或最小
-
中心点的变化为零或最小
-
否则,预测平方误差和(SSE)的减少是最小的
如果 C[j] 是第 j 个簇,那么 m[j] 是簇 C[j] 的中心点(C[j] 中所有数据点的均值向量),如果 dist(x, m[j]) 是数据点 x 和中心点 m[j]* 之间的距离,那么以下使用图形表示的示例说明了收敛标准。
例如:
-
随机识别 k 个中心点:
![k-means 聚类分析的收敛或停止标准]()
-
迭代 1:计算中心点并分配簇:
![k-means 聚类分析的收敛或停止标准]()
-
迭代 2:重新计算中心点并重新分配簇:
![k-means 聚类分析的收敛或停止标准]()
-
迭代 3:重新计算中心点并重新分配簇:
![k-means 聚类分析的收敛或停止标准]()
-
由于中心点或簇重新分配的最小变化而终止过程。
磁盘上的 k-means 聚类分析
K-means 聚类算法也可以在磁盘上的数据上实现。这种方法用于无法容纳在内存中的大型数据集。这里使用的策略是通过对数据集进行一次扫描来增量计算质心。该算法的性能取决于迭代次数的控制程度。建议运行少于 50 次的有限迭代次数。尽管这个版本有助于扩展,但它并不是扩展的最佳算法;还有其他可扩展的聚类算法,例如,BIRCH 就是其中之一。以下算法描述了磁盘上 k-means 算法的步骤:
磁盘 k-means 算法 (k, D)
-
选择 k 个数据点作为初始质心(聚类中心) m[j],其中 j = 1,2,3….k。
-
重复
-
初始化 s[j]=0,其中 j=1,2,3….k;(一个所有值都为零的向量)。
-
初始化 n[j]=0,其中 j=1,2,3….k;(n[j] 是聚类中的点数),
-
对于每个数据点 x ϵ D 进行。
-
j = arg min dist(x, m[j])。
-
将 x 分配到聚类 j。
-
s[j] = s[j] + x。
-
n[j] = n[j] + 1。
-
endfor.
-
m[i] = s[j]/n[j],其中 i=1,2,…k。
-
直到满足停止条件。
k-means 方法的优点
无监督学习的 k-means 方法有许多好处;其中一些如下:
- 由于其简单性和易于实现,k-means 聚类在流行和广泛采用。
它是高效的,并且具有由 O(ikn) 定义的优化的时间复杂度,其中 n 是数据点的数量,k 是聚类的数量,i 是迭代的数量。由于 l 和 k 的值保持较小,k-means 聚类也可以表示线性表达式。
k-means 算法的缺点
以下 k-means 算法的缺点或劣势:
-
k 的值始终是用户输入的,并且与识别出的 k 数值相同。
-
此算法仅适用于均值可用时,在分类数据的情况下,质心不过是频繁值。
-
聚类永远不会是椭圆形的,总是超球形的。
-
识别出的聚类对最初识别的种子非常敏感,当涉及不同的随机种子多次运行时可能会有所不同。以下图展示了两个不同的质心如何改变聚类。这可以通过迭代处理实现:
![k-means 算法的缺点]()
-
再次强调,k-means 算法对异常值非常敏感。异常值可能是数据记录中的错误,或者是具有非常不同值的特殊数据点。以下图表展示了异常值可能对簇形成带来的偏斜:第一个表示理想簇,第二个表示不理想的簇:
![k-means 算法的缺点]()
![k-means 算法的缺点]()
我们至今所见到的许多算法和学习技术都对异常值敏感。有一些标准技术可以被采用。
一种方法是从评估中过滤掉异常值,这需要我们应用一些技术来处理数据中的噪声。噪声减少技术将在下一章中介绍。在 k-means 聚类的情况下,可以在几次迭代后删除异常值,以确保确定的数据点确实是异常值。或者,另一种方法是坚持使用较小的数据样本来运行算法。这样,选择异常值的可能性将最小。
距离度量
距离度量在聚类算法中非常重要。重新分配数据点到簇中是由重新定义质心来决定的。以下是一些测量两个簇之间距离的方法:
-
单链: 这种方法指的是测量属于两个不同簇的两个最近数据点之间的距离。数据中可能存在噪声,这也应被认真考虑。
-
完全链: 这种方法指的是测量属于两个不同簇的两个最远数据点之间的距离。这种方法可以使簇对异常值更加敏感。
-
平均链: 这种方法使用两个簇之间所有距离对的平均距离度量。
-
质心: 这种方法指的是通过测量两个簇之间的质心距离来测量两个簇之间的距离。
复杂度度量
选择最佳的聚类算法一直是一个挑战。有许多算法可供选择,并且准确性和复杂性度量在选择正确的算法时都很重要。单链方法可以帮助实现 O(n²);完全链接和平均链接可以在 O(n²logn) 内完成。每种算法都有其优点和局限性,它们在数据分布的某些上下文中表现良好;数据分布中没有标准模式使得解决这个问题变得复杂。因此,数据准备和标准化成为机器学习中的一个重要方面。哪种距离度量是一个理想的选择,只能通过迭代实现不同的距离度量,并比较迭代结果来确定。总体而言,聚类方法高度依赖于初始选择,并且可能具有主观性。
实现 k-means 聚类
请参考本章提供的源代码以实现 k-means 聚类方法(仅监督学习技术 - 每个技术文件夹下的源代码路径为.../chapter08/...)。
使用 Mahout
请参考文件夹.../mahout/chapter8/k-meansexample/。
使用 R
请参考文件夹.../r/chapter8/k-meansexample/。
使用 Spark
请参考文件夹.../spark/chapter8/k-meansexample/。
使用 Python(scikit-learn)
请参考文件夹.../python-scikit-learn/chapter8/k-meansexample/。
使用 Julia
请参考文件夹.../julia/chapter8/k-meansexample/。
摘要
在本章中,我们介绍了基于聚类的学习方法。我们通过一个示例深入探讨了 k-means 聚类算法。你已经学会了使用 Mahout、R、Python、Julia 和 Spark 实现 k-means 聚类。在下一章中,我们将介绍贝叶斯方法,特别是朴素贝叶斯算法。
第九章:贝叶斯学习
在本章中,我们将回顾一个重要的基于统计的学习方法,称为贝叶斯学习方法,特别是其中的朴素贝叶斯算法等。统计模型通常具有一个明确的概率模型,它揭示了实例属于特定类别的概率,而不仅仅是分类,在解决分类问题时。在深入探讨贝叶斯学习之前,你将学习一些统计学中的重要概念,如概率分布和贝叶斯定理,这是贝叶斯学习的核心。
贝叶斯学习是一种监督学习技术,其目标是构建一个具有明确目标属性定义的类别标签分布模型。朴素贝叶斯基于应用贝叶斯定理,并假设每个特征对之间都是朴素的独立性。
你将学习该技术的基本和高级概念,并获得使用 Apache Mahout、R、Julia、Apache Spark 和 Python 实现均值聚类算法的实践指导。
以下图展示了本书中涵盖的不同学习模型,本章将详细处理突出显示的技术:

本章将深入探讨以下主题:
-
贝叶斯统计概述及其核心原理或概念,如概率、分布以及其他相关统计度量
-
贝叶斯定理及其机制
-
深入探讨朴素贝叶斯算法及其变体,如多项式和伯努利分类器
-
对贝叶斯学习技术可以解决的某些现实世界问题或用例的详细解释
-
使用 Apache Mahout、R、Apache Spark、Julia 和 Python(scikit-learn)库和模块的示例实现
贝叶斯学习
在监督学习技术中,归类于统计方法的模型包括基于实例的学习方法和贝叶斯学习方法。在我们理解贝叶斯学习方法之前,我们将首先概述与机器学习相关的概率建模和贝叶斯统计概念。统计学的基本概念非常深入,接下来几节将主要关注为你提供概率机器学习动态和多样性的基本理解,这对于解释贝叶斯学习方法的运作是足够的。
统计学家的思维方式
统计学家的目标是使用数据回答来自各个领域的人们提出的问题。典型的工程方法使用一些主观/客观的方法来回答问题,而这些方法不需要数据。但是,统计学家总是查看数据来回答问题。他们还在所有模型中纳入了可变性(在两个不同时间对精确数量进行测量的概率略有不同)。
让我们举一个例子:M.F. 胡赛因是一位优秀的画家吗? 回答这个问题的方法之一是根据某些被接受的标准(由个人或社区制定)来衡量画作的质量。在这种情况下,答案可能基于创造性表达、色彩运用、形式和形状。我相信 M.F. 胡赛因是一位优秀的画家。 在这种情况下,这种回应可以相当主观(这意味着你从一个人那里得到的回应可能与从另一个人那里得到的回应大相径庭)。统计学家回答这个问题的方法非常不同。他们首先从被认为在评估画作质量方面是专家的人群中收集数据(艺术大学的教授、其他艺术家、艺术收藏家等)。然后,在分析数据后,他们会得出结论,例如:“在 3000 名调查参与者(每个类别的人数相等)的数据中,75%的艺术大学教授、83%的专业艺术家和 96%的艺术收藏家认为 M.F. 胡赛因先生是一位优秀的画家”。因此,可以说他被认为是大多数人眼中的优秀画家。非常明显,这是一个非常客观的衡量标准。
重要的术语和定义
以下是一些用于评估和理解数据的必要参数和概念。在某些情况下,它们被解释为定义,在其他情况下则用例子和公式解释。它们被归类为“词汇”和“统计量”。你将在本章的下一部分遇到一些这些术语:
| 术语 | 定义 |
|---|---|
| 总体 | 这是数据的宇宙。通常,统计学家想要对一组对象(印度人、星系、国家等)做出预测。该组的所有成员被称为总体。 |
| 样本 | 大多数时候,对整个群体进行工作是不切实际的。因此,统计学家从群体中收集一个代表性的样本,并在其上进行所有计算。用于分析的群体子集被称为样本。与群体或人口普查相比,编制样本总是更便宜。收集样本有几种技术:
-
分层抽样:这被定义为在抽样之前将总体成员划分为同质子组的流程。每个子组应该是相互排斥的,并且总体中的每个元素都应该分配到一个子组。
-
聚类抽样:这种方法确保 n 个独特的集群,其中每个集群的元素没有重复。
|
| 样本大小 | 这是一个每个统计学家都曾遇到的明显困境。样本的大小应该是多大?样本越大,准确性就越高。然而,收集和分析的成本也会相应增加。因此,挑战在于找到一个最佳样本大小,这样结果准确,成本较低。 |
|---|---|
| 抽样偏差 | 偏差是一种系统性的错误,以某种方式影响结果。抽样偏差是由于样本选择而产生的持续错误。 |
| 变量 | 它是样本或人口的一个测量指标。如果我们正在取一个班级的所有成员,那么他们的年龄、学术背景、性别、身高等等,就变成了变量。一些变量是独立的。这意味着它们不依赖于任何其他变量。一些是相关的。 |
| 随机性 | 如果一个事件在发生之前其结果是不确定的,那么这个事件被称为随机事件。一个随机事件的例子是明天下午 1 点黄金价格的值。 |
| 均值 | 它等于样本中所有值的总和除以样本中观察值的总数。 |
| 中位数 | 中位数是数据集最低值和最高值之间的中间值。这也称为第二四分位数(表示为 Q2)= 切割数据集一半 = 50^(th) 百分位数。如果没有确切的中间值(即样本中的观察值是偶数),则中位数是中间两个点的平均值。 |
| 众数 | 这是变量出现频率最高的值。数据可以是单峰(单众数),或多峰(频繁的多个值)。如果数据遵循正态分布(关于这一点你将在以后学习),则使用经验公式获得众数:均值 – 众数 = 3 x (均值 - 中位数) |
| 标准差 | 它是衡量样本中每个测量值与平均值偏离程度的一个平均值。标准差也称为平均标准差。![]() |
概率
在我们开始理解概率之前,让我们首先看看为什么我们首先需要考虑不确定性。任何现实生活中的行动总是与结果或结果的不确定性相关联。让我们举一些例子;我今天能否准时赶上火车?我们最畅销产品的销量在本季度是否将继续保持领先地位?如果我掷硬币,我会得到正面还是反面?我能否在t分钟内到达机场?
可能存在许多不确定性的来源:
-
由于缺乏知识导致的不确定性,这是由于数据不足、分析不完整和不准确的测量结果
-
否则,不确定性也可能由于复杂性,这是由于不完整处理条件的结果
在现实世界中,我们需要使用概率和不确定性来总结我们缺乏知识和预测结果的能力。
让我们详细说明上一个例子。
我能在 25 分钟内到达机场吗?可能会有很多问题,比如对道路状况的不完整观察、嘈杂的传感器(交通报告),或者行动的不确定性,比如轮胎没气或交通模型复杂。为了预测结果,肯定需要做出一些假设,并且我们需要以原则性的方式处理不确定性;这被称为概率。简而言之,概率是随机性和不确定性的研究。
在概率论中,实验是可以重复进行并且结果具有不确定性的。实验的单个结果被称为单个事件,事件是一系列结果的集合。样本空间概率是实验所有可能结果的列表。
事件 E 的概率表示为 P(E),定义为该事件发生的可能性。
备注
事件 P(E)的概率 = 事件发生的方式数 / 可能的结果数
例如,对于掷硬币,有两种可能性:正面或反面。
正面朝上的概率是 P(H) = ½ = 0.5
当掷骰子时,有六种可能性,即 1、2、3、4、5 和 6。
数字 1 的概率是 P(1) = 1/6 = 0.16667
投掷任何事件 E 的概率 P(E) 必须在 0 和 1 之间(包括两端)。
0 ≤ P(E) ≤ 1
概率为 0 表示事件不可能发生,而概率为 1 表示事件必然发生。如果有 n 个事件,那么每个事件概率的总和为 1。这可以表示为:
如果 S = {e1, e2, ….en},那么 P(e1) +P(e2)+…P(en) = 1
确定概率的方法有很多:
-
经典方法:这是我们之前章节中用来定义概率的方法。这种方法要求结果等可能。因此,如果一个实验有等可能的 n 个事件,并且有 m 种可能性,那么事件 E 就可以发生。
P(E) = 事件 E 发生的方式数 / 可能的结果数 = m/n。
例如,一个装有巧克力的袋子里有五块棕色包装的巧克力,六块黄色包装的巧克力,两块红色包装的巧克力,八块橙色包装的巧克力,两块蓝色包装的巧克力和七块绿色包装的巧克力。假设随机选择一块巧克力。巧克力是棕色的概率是多少?
P (B) = 5/30
-
经验方法:概率计算的经验方法也称为相对频率,因为这个公式需要实验重复的次数。这种方法定义了事件 E 的概率,即事件在实验重复的总次数中被观察到的次数。在这种情况下,计算概率的基础是观察或经验。
P(E) = 实验中 E 的频率 / 实验次数。
例如,我们想要计算研究生选择医学作为主修的概率。我们选取,比如说,200 名学生的样本,其中 55 人选择医学作为主修,那么:
P(有人选择医学) = 55/200 = 0.275
-
主观方法:这种方法使用一些公平的、计算出的或基于经验的假设。它通常描述了个人对事件发生的可能性的感知。这意味着个人的信念程度被考虑在内,因此可能会存在偏见。例如,有 40%的可能性物理教授不会来上课。
事件类型
事件可以是互斥的、独立的或相关的。
互斥或不相交事件
互斥事件是指不能同时发生的事件。简而言之,两个事件同时发生的概率是0。P(1)和P(5)。当掷骰子时,存在互斥事件。互斥事件的维恩图表示如下:

对于互斥事件 A 和 B,加法规则是:
P(A 或 B) = P(A) + P(B)
对于互斥事件 A 和 B,乘法规则是:
P(A 和 B) = P(A) x P(B)
独立事件
如果一个事件的结果不影响另一个事件的结果,这两个事件被称为独立事件。例如,事件 A 是周日下雨,事件 B 是汽车轮胎没气。这两个事件不相关,一个事件发生的概率不会影响另一个。独立事件可以是互斥的,但反之则不然。
在事件 A 和 B 独立的情况下,乘法规则是:
P(A 和 B) = P(A) x P(B)
相关事件
相关事件是指一个事件的发生可以影响另一个事件的发生。例如,一个将英语作为第一专业的学生可以选择政治学作为第二专业。相关事件的维恩图表示如下:

事件 A 和 B 的加法规则是:
P(A 或 B) = P(A) + P(B) – P(A 和 B)
事件 A 和 B 的乘法规则是:
P(A 和 B) = P(A) x P(B)
概率的类型
在本节中,我们将探讨不同类型的概率,具体如下:
-
先验概率和后验概率:先验概率是在没有任何先验信息或对问题背景中任何假设的了解的情况下,事件 E 发生的概率。
让我们举一个例子。如果你的朋友正在乘飞机旅行,有人问你他们的邻居是男性还是女性,根据概率的基础公式,有 0.5(50%)的概率是男性,有 0.5(50%)的概率是女性。当提供更多信息时,这些值可能会改变,那时测量的概率被称为后验概率。
-
条件概率:条件概率是指给定另一个事件已经发生的情况下,一个事件发生的概率。P(B|A) 被解释为在事件 A 发生的条件下,事件 B 的概率。
例如,让我们计算一个人在马路上行走时被汽车撞到的概率。设 H 为一个离散随机变量,描述一个人被汽车撞到的概率,将撞击定义为 1,不撞击定义为 0。
设 L 为一个离散随机变量,描述在某一时刻交叉交通信号灯的状态,取值于 {red, yellow, green}:
P(L=red) = 0.7,
P(L=yellow) = 0.1,
P(L=green) = 0.2.
P(H=1|L=R) = 0.99,
P(H|L=Y) = 0.9 and
P(H|L=G) = 0.2.
使用条件概率公式,我们得到以下结果:
P(H=1 and L=R) = P(L=R)P(H|L=R) = 0.693;*
P(H=1 and L=Y) = 0.10.9 = 0.09*
同样,如果红灯亮时的撞击概率是 0.99,那么不被撞击的概率是 0.01。因此,P(H=0|L=R) = 0.01。从这些中,我们可以计算出 H=0 和 L=R 的概率。
-
联合概率:联合概率是两个或更多事件同时发生的概率。在两个变量的情况下,f(x,y|θ) 是联合概率分布,其中 f 是在给定分布参数—θ 的情况下,x 和 y 作为一对同时发生的概率。对于离散随机变量,联合概率质量函数如下:
P(X and Y) = P(X).P(Y|X) =P(Y).P(X|Y)
你在学习条件概率时已经看到了这一点。由于这些都是概率,所以我们有以下公式:
![概率类型]()
-
边缘概率:边缘概率用 f(x|θ) 表示,其中 f 是在给定分布参数—θ 的情况下,对于所有可能的 y 值,x 的概率密度。在随机分布中,边缘概率是通过对所有 y 的值求和从 x 和 y 的联合分布中确定的。在连续分布中,它通过对所有 y 的值进行积分来确定。这被称为积分消去变量 y。对于离散随机变量,边缘概率质量函数可以写成 P(X = x)。如下所示:
![概率类型]()
从上述方程中,P(X = x,Y = y) 是 X 和 Y 的联合分布,而 P(X = x|Y = y) 是在 Y 的条件下的 X 的条件分布。变量 Y 被边缘化。这些离散随机变量的双变量边缘和联合概率通常以双向表的形式显示(如图所示)。我们将在下一节中展示计算过程。
例如,假设掷两个骰子,记录得分序列 (X1, X2)。令 Y=X1+X2 和 Z=X1−X2 分别表示得分的和与差。找出 (Y, Z) 的概率密度函数。找出 Y 的概率密度函数。找出 Z 的概率密度函数。Y 和 Z 是否独立?
假设 X1 和 X2 是独立的,它们可以取 36 种可能性,如表中所示:
![概率类型]()
现在我们构建联合、边缘和条件表。在这个表中,我们将有 Z 的值作为行,Y 的值作为列。Y 的值从 2 到 12,Z 的值从-5 到 5。我们可以通过计数来填充所有条件分布。例如,取 Z=-1;我们看到这种情况发生在 Y=3, 5, 7, 9, 11。我们还注意到,每个值(比如说,给定 Y=3 时 Z=-1 的条件概率)的概率是 1/36。我们可以用这种方法为所有值填充表格:

因此,最后一行是 Y 的边缘分布。最右侧的列是 Z 的边缘分布。整个表是联合分布。显然,它们是相关的。
分布
分布要么是离散概率分布,要么是连续概率分布,这取决于它们是否定义与离散变量或连续变量相关的概率:

我们将在这里介绍一些之前提到的分布。
在本节中,我们主要关注建模和描述数据的一个给定属性。为了了解这项技能的重要性,让我们看看几个例子:
-
一家银行想要查看在一段时间内自动取款机(ATM)每笔交易中取款的金额,以确定交易的限额
-
一家零售商想要了解他在每次装运中得到的损坏玩具的数量
-
一家制造商想要了解探针直径在各个制造周期之间的变化情况
-
一家制药公司想要了解其新药如何影响数百万患者的血压
在所有这些情况下,我们需要提出一些精确的定量描述,以了解观察到的数量是如何变化的。本节就是关于这个内容的。无论如何,直观上,你认为你想要测量哪些质量来获得理解?
-
一个给定变量所取的所有值是什么?
-
取一个特定值的概率是多少?哪些值的概率最高?
-
平均值/中位数是多少?方差是多少?
-
给定一个值,我们能否知道有多少观测值落入其中,有多少观测值偏离它?
-
我们能否给出一个范围,其中我们可以告诉 90%的数据位于其中?
实际上,如果我们能回答这些问题,更重要的是如果我们开发了一种描述此类量的技术,那么在考虑这个属性时,我们几乎是无敌的!
这里有两个主要观察结果。首先,一个属性以这种方式分布,具有成为随机变量的所有品质(知道一个量的值并不能帮助我们了解下一个值)。然后,如果我们知道这个随机变量的概率质量函数或分布函数,我们可以计算出所有之前的事情。这就是为什么理解数学如此重要的原因。一般来说,我们遵循(就这一点而言,几乎任何对分析后续数据感兴趣的人)一个描述量的系统过程:
-
我们首先理解随机变量。
-
接下来,我们将计算概率质量(或分布)函数。
-
然后,我们将预测所有重要的参数(平均值和方差)。
-
然后,我们将通过实验数据来检查我们的近似值有多好。
例如,在 50 天期间,汽车租赁代理机构所要求的租赁货车数量已在下表中识别。表中最后一列已将观察到的频率转换为这 50 天的概率:

预期值是 5.66 辆货车,如上图所示:

类似地,方差计算如下:

标准差是方差的平方根,等于 1.32 辆货车。让我们系统地分析各种分布。
二项分布
这是最简单的分布,人们可以想到的。很多时候,一个属性只取离散值;比如抛硬币、掷骰子、人的性别等等。即使它们不是完全离散的,我们也可以通过分箱在某些情况下将它们转换。例如,当我们观察个人的净资产时,我们可以根据他们确切的财富重新划分他们为富有和贫穷(离散量),而财富是连续量。假设该属性取特定值的概率是 p(当然,它不取该值的概率是 (1-p))。如果我们收集足够大的样本,那么数据集看起来会怎样?好吧,将会有一些正值(变量取了该值)和负值(变量没有取该值)。假设我们用 1 表示正值,用 0 表示负值。
然后,我们有以下内容:
平均值 = 概率的加权平均值 = 1p +0(1-p) = p
二项分布
这是伯努利思想的扩展。让我们举一个具体的例子。你在一个人口统计局工作,并拥有一个州内所有家庭的数据。假设你想要确定有两个孩子的家庭中有两个男孩的概率。正如你所看到的,一个家庭有两种孩子只有四种不同的方式:MM、MF、FM 和 FF。如果我们把有男孩作为感兴趣的事件,那么只有男孩的概率是0.25(1/4)。有一个男孩的概率是0.5(0.25+0.25)(1/4+1/4),没有男孩的概率是0.25(1/4)。
那么,如果你观察 100 个家庭,恰好有 20 个家庭有两个男孩的概率是多少?我们稍后会给出答案。让我们扩展这个论点来找出有三个孩子的家庭中所有孩子都是男孩的概率:总的可能性有 FFF、FFM、FMF、FMM、MFM、MMF、MFF 和 MMM(共八种可能性)。三个孩子都是男孩的概率是1/8。其中两个孩子是男孩的概率是3/8。其中一个是男孩的概率是3/8。没有男孩的概率是1/8。请注意,所有事件的概率总和始终等于 1。
泊松概率分布
现在,让我们尝试将二项式定理扩展到无限次试验,但有一个限制。我们已选取的例子(抛硬币等)有一个有趣的性质。事件在试验中发生的概率即使增加试验次数也不会改变。然而,有许多例子,而试验次数(或其等效值)增加时,事件发生的相应概率会减少。因此,我们需要将时间间隔减少到零,或者将观察次数增加到无限,以确保在任何试验中只看到一次成功或失败。在这个极限情况下,我们在 n 次观察中看到 r 次成功的概率可以按以下方式计算:

泊松随机变量 X 的概率分布如下。这考虑了在给定时间间隔内发生成功的数量:

在这里,r是第 r 次试验,λ是给定时间间隔或空间区域内的平均成功次数。
指数分布
现在让我们看看泊松的例子,并问自己一个不同的问题。检查员在t小时后看不到第一辆车的概率是多少?在这种情况下,这可能并不相关,但当我们研究组件的故障时,了解在什么时间看不到故障的概率较高是有意义的。所以,假设汽车(或首次故障)遵循泊松过程。然后,我们定义L,一个随机变量,表示检查员在时间t之前看不到第一辆车的概率,即第一次看到汽车之前的时间。从泊松分布来看,她在 1 小时内看不到第一辆车的概率如下:

她在第二小时内看不到汽车的概率也是相同的,她在t小时内看不到汽车的概率是e^(−λt) (e^(−λ) * e^(−λ) **…times)。她在前t小时内看到汽车的概率是1-e*^(-λt)。
指数分布的应用如下:
-
泊松过程中的首次故障时间
-
种子从母体植物散布的距离
-
忽略衰老过程(衰老过程导致由于事故、感染等原因而结束)的有机体的预期寿命
正态分布
正态分布是非常广泛使用的一类连续分布。它也常被称为钟形曲线,因为其概率密度的图形类似于钟。大多数现实生活中的数据,如重量、身高等(尤其是当有大量集合时),都可以很好地用正态分布来近似。

一旦我们知道高度值,具有这个值的样本数量可以用以下方式数学描述:

在这里,σ是标准差,µ是均值。要描述正态分布,我们只需要知道两个概念(平均值和标准差)。
每一个正态分布都遵循以下规则:
-
大约 68%的曲线下面积位于均值的一个标准差范围内
-
大约 95%的曲线下面积位于均值的两倍标准差范围内
-
大约 99.7%的曲线下面积位于均值的三个标准差范围内
这些点共同被称为经验法则或68-95-99.7 规则。
分布之间的关系
虽然我们知道几乎所有的事物都趋于正态分布,但最好了解每个分布适合的位置。以下图表有助于这一过程:

贝叶斯定理
在我们进入贝叶斯定理之前,我们在本章开头提到了贝叶斯学习中的贝叶斯定理是什么。
让我们从例子开始。假设有两个坚果碗;第一个碗里有 30 个腰果和 10 个开心果,第二个碗里有每种各 20 个。让我们随机选择一个碗,闭着眼睛拿一个坚果。拿到的坚果是腰果。现在,选择的是第一个碗的概率是多少?这是一个条件概率。
因此,p(Bowl 1|cashew) 或在坚果是腰果的条件下是第一个碗的概率,并不是一个容易或明显的问题。
如果问题反过来问,p(cashew|bowl1) 或在碗 1 的条件下坚果是腰果的概率是容易计算的,p(cashew|Bowl 1) = ¾。
正如我们所知,p(cashew|Bowl 1) 并不等于 p(Bowl 1|cashew),但我们可以使用一个值来得到另一个值,这正是贝叶斯定理的核心所在。
定义贝叶斯定理结合的第一步是交换律;以下步骤:
p (A and B) =p (B and A),
进一步,A 和 B 的概率是 A 的概率和给定 A 的 B 的概率:
p (A and B) = p (A) p (B|A),同样
p (B and A) = p (B) p (A|B)
所以,
p (A) p (B|A) = p (B) p (A|B) 和

这就是贝叶斯定理!
这可能不是很明显,但它是一个非常强大的定义。
现在,让我们应用这个方法来解决之前的 坚果 问题,找到 p(bowl1 cashew),如果我们能得到 p(cashew|bowl 1),我们就可以推导它:
p (bowl1 cashew) = (p(bowl1) p(cashew|bowl1)) / p (cashew)
p (bowl1) = ½
p (cashew|bowl1) = ¾
p (cashew) = 总腰果数 / (碗 1 和碗 2 之间的总坚果数) = 50/80 = 5/8
将这些放在一起,我们得到以下:
p (bowl1 cashew) = ((1/2) (3/4))/(5/8)= 3/5 = 0.6
现在需要考虑的额外方面是如何在时间变化中体现特征,随着新数据的到来。这样,可以在特定时间点的数据背景下测量假设的概率。这被称为贝叶斯定理的历史解释。
以下是用给定数据 (D) 的假设 (H) 重新表述的贝叶斯定理:

p (H) 是在看到数据 D 之前假设 H 的概率。
p (D) 是数据 D 在任何假设下的概率,这通常是常数。
p (H|D) 是在看到数据 D 后假设 H 的概率。
p (D|H) 是在假设 H 的条件下数据 D 的概率。
注意
p (H) 被称为先验概率;p (H|D) 是后验概率;p (D|H) 是似然;p (D) 是证据:

简单贝叶斯分类器
在本节中,我们将探讨贝叶斯分类器及其如何用于解决分类问题。贝叶斯分类器技术基于贝叶斯定理,并假设预测因子是独立的,这意味着知道一个属性的价值会影响任何其他属性的价值。独立性假设使得贝叶斯分类器简单。
简单贝叶斯分类器易于构建,不涉及任何迭代过程,并且在大数据集上工作得非常好。尽管其简单性,贝叶斯分类器通常优于其他分类方法。
我们需要计算给定一个类别的假设的概率。
即,P(x[1], x[2], ….x[n|y])。显然,有多个证据由 x[1],x[2],…x*[n] 表示。
因此,我们从一个假设开始,即 x[1],x[2],…x*[n] 在给定 y 的条件下是条件独立的。另一种简单的方法是,我们需要根据多个证据预测一个结果,而不是单个证据。为了简化,我们将这些多个证据分开:
P(结果|多个证据) = [P(证据 1|结果) x P(证据 2|结果) x ... x P(证据 N|结果)] x P(结果) / P(多个证据)
这也可以写成以下形式:
P(结果|证据) = P(证据的似然性) x 结果的先验概率 / P(证据)
为了将贝叶斯分类器应用于预测结果,需要对每个结果运行之前提到的公式。只需为每个可能的结果运行此公式,在分类问题的情况下,结果将是类别。我们将通过著名的果实问题来帮助你轻松理解这一点。
给定一个水果的任何三个重要特征,我们都需要预测它是什么水果。为了简化案例,让我们考虑三个属性——长、甜和黄;以及三个水果类别——香蕉、橙子和其他。训练集中有 1,000 个数据点,这是可用信息的样子:
| 类型 | 长 | 不长 | 甜 | 不甜 | 黄色 | 非黄色 | 总计 |
|---|---|---|---|---|---|---|---|
| 香蕉 | 400 | 100 | 350 | 150 | 450 | 50 | 500 |
| 橙子 | 0 | 300 | 150 | 150 | 300 | 0 | 300 |
| 其他 | 100 | 100 | 150 | 50 | 50 | 150 | 200 |
| 总计 | 500 | 500 | 650 | 350 | 800 | 200 | 1000 |
以下是从上一个表中派生出的值/先验概率如下:
类别概率
p (香蕉) = 0.5 (500/1000)
p (橙子) = 0.3
p (其他) = 0.2
证据概率
p (长) = 0.5
p (甜) = 0.65
p (黄色) = 0.8
似然概率
p (长|香蕉) = 0.8
p (长/橙) = 0 P(黄色/其他水果) =50/200 = 0.25
p (非黄色|其他水果) = 0.75
现在,给定一个水果,让我们根据属性对其进行分类。首先,我们计算每个三个结果的概率,取最高的概率,然后进行分类:
p (Banana|/Long, Sweet and Yellow) = p (Long|Banana) x p (Sweet|Banana) x p (Yellow|Banana) x p (banana) /p (Long) xp (Sweet) x. p (Yellow)
p (Banana||Long, Sweet and Yellow) =0.8 x 0.7 x 0.9 x 0.5 / p (证据)
p (Banana||Long, Sweet and Yellow) =0.252/ p (证据)
p (Orange||Long, Sweet and Yellow) = 0
p (Other Fruit/Long, Sweet and Yellow) = p (Long/Other fruit) x p (Sweet/Other fruit) x p (Yellow/Other fruit) x p (Other Fruit)
= (100/200 x 150/200 x 50/150 x 200/1000) / p (证据)
= 0.01875/ p (证据)
在最大的边缘 0.252 >> 0.01875 下,我们现在可以将这个甜/长/黄色的水果分类为可能是 香蕉。
由于朴素贝叶斯假设每个特征都服从高斯分布,因此它也被称为高斯朴素贝叶斯分类器。
朴素贝叶斯在存在缺失数据时尤其出色。在接下来的章节中,我们将探讨不同类型的朴素贝叶斯分类器。
多项式朴素贝叶斯分类器
正如我们在上一节中看到的,朴素贝叶斯假设模型相对于特征分布的独立性。在多项式朴素贝叶斯的情况下,p(x[i]|y) 是一个多项式分布;简而言之,假设每个特征都是多项式分布。适合这种变体的例子是文档,其中我们需要计算单词计数。这里给出了多项式朴素贝叶斯的一个简单算法:

伯努利朴素贝叶斯分类器
伯努利朴素贝叶斯分类器将一个布尔指示符附加到一个单词上,如果它属于正在检查的文档,则为 1,如果不属于,则为 0。这种变体的重点是它考虑了在特定文档中一个单词的出现或未出现次数。一个单词的未出现是一个重要的值,因为它用于计算一个单词出现的条件概率。伯努利朴素贝叶斯算法的详细内容如下:

| 多项式朴素贝叶斯 | 伯努利朴素贝叶斯 | |
|---|---|---|
| 模型变量 | 在这里,生成并检查一个标记在该位置是否出现 | 在这里,生成并检查一个文档在该文档中是否出现 |
| 文档 | ![]() |
![]() ![]() |
| 参数估计 | ![]() |
![]() |
| 规则 | ![]() |
![]() |
| 出现次数 | 这考虑了多次出现 | 这考虑了单次出现 |
| 文档大小 | 处理大文档 | 适合处理小文档 |
| 特征 | 这支持处理更多特征 | 这适用于较少的特征 |
| 项的估计 | ![]() |
![]() |
实现朴素贝叶斯算法
请参考本章提供的源代码以实现朴素贝叶斯分类器(源代码路径 .../chapter9/... 在每个技术文件夹下)。
使用 Mahout
请参考文件夹 .../mahout/chapter9/naivebayesexample/。
使用 R
请参考文件夹 .../r/chapter9/naivebayesexample/。
使用 Spark
请参考文件夹 .../spark/chapter9/naivebayesexample/。
使用 scikit-learn
请参考文件夹 .../python-scikit-learn/chapter9/naivebayesexample/。
使用 Julia
请参考文件夹 .../julia/chapter9/naivebayesexample/。
摘要
在本章中,你学习了贝叶斯机器学习以及如何使用 Mahout、R、Python、Julia 和 Spark 实现朴素贝叶斯分类器和基于关联规则的学习。此外,我们还涵盖了所有核心的统计概念,从基本命名法到各种分布。我们深入探讨了贝叶斯定理,并通过实例来理解如何将其应用于现实世界的问题。
在下一章中,我们将介绍基于回归的学习技术,特别是线性回归和逻辑回归的实现。
第十章。基于回归的学习
回归分析使我们能够使用简单的代数数学模型来描述两个变量之间的关系。在本章中,我们将专注于介绍另一种监督学习技术:回归分析或基于回归的学习。在前一章中,我们介绍了本章将用到的统计学基础。我们将从理解多个变量如何影响结果开始,以及如何使用统计调整技术来权衡这种影响,通过实际案例了解相关性和回归分析,并深入探讨如混杂和效应修饰等概念。
您将学习该技术的初级和高级概念,并获得使用 Apache Mahout、R、Julia、Apache Spark 和 Python 进行简单、多元线性回归、多项式回归和逻辑回归的实践指导。
本章结束时,读者将理解回归模型的使用和局限性,学习如何将线性回归和逻辑回归模型拟合到数据中,进行统计推断,并最终评估和诊断模型的性能。
以下图表展示了本书涵盖的不同学习模型,本章将详细讨论橙色高亮的技术:

本章将深入探讨以下主题:
-
介绍相关性和回归分析;复习额外的统计概念,如协方差和相关系数。我们将涵盖回归模型和方差分析模型中期望、方差和协方差的性质。
-
您将学习简单线性回归、多元线性回归:线性关系、线性模型、基本假设(正态性、同方差性、线性性和独立性)以及最小二乘估计。总体而言,您将学习模型诊断和选择。
-
您将了解广义线性模型(GLMs)的概述以及 GLM 下的回归算法列表。此外,还将介绍混杂和效应修饰的现象,以及相应的实现和调整。
-
逻辑回归简介,理解赔率和风险比,构建逻辑回归模型,以及评估模型的内容将得到涵盖。
-
将涵盖使用 Apache Mahout、R、Apache Spark、Julia 和 Python(scikit-learn)库和模块的示例实现。
回归分析
在监督学习技术中,归类于统计方法的模型包括基于实例的学习方法、贝叶斯学习方法和回归分析。在本章中,我们将重点关注回归分析和相关的回归模型。回归分析被认为是最重要的统计技术之一。正如所提到的,它是一种统计方法,用于衡量两个或更多变量之间的关系,并检查关系的有效性和强度。
传统上,研究人员、分析师和交易员一直使用回归分析来构建交易策略,以了解投资组合中包含的风险。回归方法用于解决分类和预测问题。
我们在前面章节中介绍了一些关键的统计概念;在本章中,我们将介绍一些与回归分析相关的更多概念。举几个例子,我们有变异性的度量、线性、协方差、系数、标准误差等。

回顾统计学
在前面的章节中,我们学习了贝叶斯学习方法,我们覆盖了一些核心的统计量,例如均值、中位数、众数和标准差。现在让我们扩展到更多的度量,例如方差、协方差、相关性和随机变量分布的第一和第二矩。

方差是标准差的平方。如果你还记得标准差是什么,它是一个平均度量,表示样本中每个测量值与均值偏离的程度。它也被称为均值的方差。我们可以从理论上计算众数和中位数的标准差。
范围定义为数据集分布的值域。范围通常表示为最小值和最大值。
四分位数、十分位数和百分位数将测量值分布细分,类似于中位数。众所周知,中位数将分布分为一半,而四分位数、十分位数和百分位数分别将分布分为 1/25、1/10 和 1/100。
第一四分位数(标记为 Q1)或下四分位数是第 25 个百分位数。
第三四分位数(标记为 Q3)或上四分位数是第 75 个百分位数。
四分位距 = 第三四分位数 - 第一四分位数
对称和偏斜数据:对称、正偏斜和负偏斜数据的均值、中位数和众数如下所示:

注意
对称分布具有相等的均值和中位数值。对于正偏斜分布,中位数大于均值,而对于负偏斜分布,均值值大于中位数值。
异常值是远离数据主要集群的观察值。它可能会以非常显著的方式影响如均值等度量。让我们通过一个例子来更好地理解这一点。我们想要了解五个人群的平均财富。比如说,个人资产估值分别为 100 万美元、120 万美元、90 万美元、110 万美元和 1200 万美元。
1+1.2+0.9+1.1+12=16.2
16.2/5=3.24
最后一个观察值对测量产生了不切实际的影响。现在让我们看看中位数是如何受到影响的。让我们按升序排列资产:900 万美元、1000 万美元、1100 万美元、1200 万美元和 1200 万美元。中位数是 1100 万美元。有两个重要概念我们必须理解。异常值对均值的影响比中位数大。
因此,在选择正确的统计量之前,你应该仔细检查数据。
均值代表变量的平均值,中位数代表平均变量的值。
协方差是指有两个或更多感兴趣变量(如公司股票、材料的物理性质等)的情况;了解它们之间是否存在任何关系变得很重要。精确地说,我们想要了解的是,如果一个变量在变化,另一个变量会如何变化。
在统计学中,有两个术语解释了这种行为:
第一个被称为协方差。对于一个包含两个变量 x 和 y 的 n 个数据点的数据集,以下方程描述了协方差的计算:

然而,协方差可能是一个非常大的数字。最好将其表示为介于 -1 和 1 之间的归一化数字,以了解这些量之间的关系。这是通过将协方差与两个变量的标准差(sx 和 sy)进行归一化来实现的。
这被称为 x 和 y 之间的相关系数。

相关系数衡量 X 和 Y 之间线性依赖的强度,介于 -1 和 1 之间。以下图表展示了相关系数如何影响线性依赖的视觉理解:

在我们深入研究各种回归模型的具体细节之前,让我们首先看看实现回归模型和分析结果的基本步骤。
均值和方差是随机变量概率分布函数的第一和第二矩。它们如下计算:

在计算给定随机变量的概率分布之后,我们将通过简单的积分计算均值方差。
让我们用一个现实世界的例子来计算所有这些度量。
以下是在 14 天期间三个公司(公司 A、公司 B 和公司 C)的股价数据。首先,使用以下公式计算回报率:
回报率 = (当天价格-前一天价格)/前一天价格
从这个回报中,计算平均值、中位数和成对相关系数。不要使用内置库。即使使用 Excel,也要使用基本公式。

首先,让我们使用之前给出的公式计算回报。

如果我们必须计算平均值,数值如下:

要找到中位数,我们首先将回报值按升序排序,然后标记中间值。

最后,让我们使用之前协方差部分给出的公式计算协方差和相关性。

期望、方差和协方差的性质
让我们结合前几章和本章的理解,得出结论。
一个变量的这种分布是取特定值的概率。期望是总体均值(这是加权平均的概率)。
我们可以定义均值的方差和标准差。
最后,如果我们观察两个不同的变量,我们可以定义协方差和相关性。现在,让我们了解如何计算两组的期望和方差。这在下一节中特别有用,我们将一起分析两个变量进行线性回归,如下所示:
E(x+y) = E(x) + E(y)
E(x+a) = E(x) + E(a) = a + E(x)
E(kx) = kE(x)
这里有一个非常有趣的规则:

实际上,这个规则表示,如果我们有一个给定比例的财产组合,那么总期望值是单个期望值的加权总和。这是分析组合中的一个关键概念。如果有一个 30%的公司 A、50%的公司 B 和 20%的公司 C 股票的组合,我们组合的预期回报是:
E (组合) = 0.3 E(公司 A) + 0.5 E(公司 B) + 0.2 E (公司 C)
方差的性质
给定X,一个随机变量:
Var(X+Y) = Var(X)+Var(Y)+2Cov(X,Y)
V(x+a) = V(x)(方差在加上常数时不会改变)
V(ax) = a² V(x)
让我们证明这一点,因为它并不明显:
例如,Y= aX
E(Y) = an E(X)(从之前的关系中得出)
Y-E(Y) = a(X-E(X))
对两边平方并取期望:
E(Y-E(Y))² = a² E(X-E(x))²
然而,左边是Y的方差,右边是X的方差:
Var (Y) = a²Var(X)
可以从上述内容推导出方差的一些有趣性质。直接得出以下结论:
Var (-y) = Var (y)
让我们现在看看投资组合的方差:

因此,如果你有一个包含三只股票的投资组合,你的投资组合的方差(或其平方根,即标准差)会像之前展示的那样变化。标准差通常被称为投资组合的风险。理想情况下,它需要尽可能低。从前一个公式中,可以通过两种方式实现:
-
通过选择方差非常低的元素
-
通过选择相关性非常负的元素
这是成功投资的关键方法。
协方差性质
以下是对协方差的性质:
cov(X, Y) = E[XY] − E[X]E[Y]
cov(x, a) = 0
cov(x, x) = var(x)
cov(y, x) = cov(x, y)
cov(ax, by) =abcov(x, y)
cov(X+a, Y+b) = cov (X, Y)
cov(aX+bY, cW+dV) = accov(X,W) + adcov(X,V) + bccov(Y,W) + bdcov(Y,V)
Cor(X,Y) = E[XY]/σXσY
现在我们用一个现实世界的例子来展示这一点。
示例
你的两位最好的朋友,安娜和丹尼尔,正在计划投资股票市场。作为你朋友圈中最有经验的投资者,他们向你寻求建议。你知道丹尼尔可以承受 10%的风险,而安娜希望风险尽可能低。显然,你希望最大化他们的回报。他们都希望投资于三项:黄金债券、顶级 IT 公司和顶级银行。

SD—标准差
相关系数可以按照以下方式计算:

现在,让我们系统地推导出建议。
让我们先创建一个所有可能权重的列表(假设你需要计算到小数点后一位),对于三种资产。大约有 66 个可能的值。这意味着我们的朋友必须从这些选择中挑选一个进行投资。现在,使用以下公式(再次使用你喜欢的任何语言)计算每个可能的投资组合(权重独特组合)的回报:
投资组合回报 = W[g] X R[g] + W[i] X R[i] + w[b] X R[b]W[g]
W[i], W[b] = 权重 和
R[i], R[g], R[b] = 回报
这是因为投资组合的期望是单个投资组合期望的总和,乘以各自的权重。
前五个投资组合的值如下:

计算所有其他值。
使用以下公式计算每个投资组合的风险:
回报 = Sqrt ((wgsdg)² + (Wisdi)² + (Wbsdb)² + (2WgsdgWisdirgi)+ (2WisdiWbsdbrib) + (2Wbsdbwgsdgrbg))
sdg, sdb, sdi = 风险和 rij = i 和 j 的相关性
这正是与之前章节中给出的投资组合方差的公式完全相同的公式。

现在,让我们计算所有其他值。
现在,所需做的就是为 Ana 和 Daniel 推荐平衡的投资组合,因为他们的风险偏好您是知道的。由于 Ana 偏好零风险,我们将选择对应于 17.2%回报和 0.87 风险的点。您可以在表中查找并确认这是通过 0.7、0.2 和 0.1(黄金、IT 和银行)的投资组合获得的。由于 Daniel 可以承担 10%的风险,我们将看到对应于 10%风险的投资组合,该组合回报最高。
再次,这可以读作 0.2、0.7 和 0.1。
ANOVA 和 F 统计量
在双变量和多变量分布的情况下,一个很好的理解量是方差在总体或组内以及组间是如何分布的。这是将数据分组到多个子集的过程。正如您所清楚看到的,在这种情况下,了解方差如何在它们之间分布是非常有帮助的。这种分析称为方差分析(ANOVA)。涉及的计算相当直接。
让我们取三个样本,它们有自己的均值和分布,如图所示:

以一个例子来说明,请看以下内容:
样本 1= {3, 2, 1}
样本 2= {5, 3, 4}
样本 3= {5, 6, 7}
样本 1 的均值 = 2
样本 2 的均值 = 4
样本 3 的均值 = 6
总体大均值 = (3+2+1+5+3+4+5+6+7) / 9 = 4
总均值(如果组覆盖整个总体,将是总体均值)等于均值均值。
三组均值是否来自同一总体?如果其中一个均值值与其它非常不同或远离其它,这意味着它们不是来自同一总体吗?或者,它们是否距离相等?
所有的前述样本都是关于相对于总体均值的相对距离度量。

现在,让我们计算整个样本集的平方和:
(3 − 4)² + (2 − 4)² + … = 30
我们可以通过将之前提到的量除以自由度 (nm-1)* 来计算方差:
n—每个样本中的元素数量
m—样本数量
我们试图建立的性质不会改变。因此,我们只需坚持使用平方和而不是方差。现在,让我们计算两个量:组的平方和以及组间的平方和。
-
组的平方和:让我们以第一个组(3, 2, 和 1)为例,其中均值为 2。组内的变异(我们称之为方差。但,它肯定是一个方差的度量)等于 (3-2)²+…=2。同样,组 2 和组 3 内的变异也等于 2 和 2。因此,组内贡献的总变异是 6。每个组内的自由度总数是 n-1。总的自由度是 (n-1)m*。在这种情况下是 6。
-
组间平方和:这是通过组均值与总体均值之间的距离来衡量的,这个距离乘以组内元素的数量。组 1 的组内均值为 2,总体均值为 4。因此,该组与总体均值之间的变异性为(2-4)² * 3 = 12。第二组的变异性为 0,第三组为 12。因此,组间变异性为 24。在这种情况下,自由度为m-1 = 2。
因此,让我们记录下来:

因此,我们看到在总变差 30 中,6 是由组内变差贡献的,而 24 是由组间变差贡献的。所以,很可能将它们分开是有意义的。现在,让我们在这里做一些推断统计。假设这些值是三个辅导中心获得的排名。我们想知道将人们放入辅导中心是否真的会影响他们的最终排名。
让我们从假设论证开始。
零假设是辅导中心对排名没有影响。备择假设是辅导中心对排名有影响。

如果我们观察,这个指标并不是关于值是否相等,而是检查样本是否来自同一更大的总体。这个指标被称为样本均值之间的变异性。
简而言之,方差分析(ANOVA)是一个变异性比率,表示如下:
ANOVA = 组间变差 / 组内变差 = 总均值之间的距离 / 内部扩散
总变差 = 组间变差 + 组内变差
将总变差分为两个组成部分的过程称为分解:
-
如果均值之间的变差大于均值内的变差,这意味着变异性比率大于 1。因此,我们可以得出结论,样本不属于同一总体。
-
如果均值之间的变差和均值内的变差相似,那么比率几乎变为 1,这表明有重叠。
-
如果均值之间的变差小于均值内的变差,这意味着样本接近总体均值或分布melt在一起。
因此,当我们处理多个变量时,可能会有许多因素影响结果。每个变量都需要评估其对变量之间关系的独立影响。在下一节中,将解释混杂和效应修饰这两个概念,说明不同类型的影响因素对结果的影响。
混杂
我们将通过一个例子开始理解什么是混淆。假设我们正在进行一项研究,我们想确定发展心脏病的风险是否与吸烟有关。当对混合吸烟者和非吸烟者以及那些在一段时间内被检测出患有心脏病的人的样本数据进行研究时,进行了一个关联性测量的指标,如风险比,结果为 2.0。这可以解释为吸烟者发展心脏病的风险是非吸烟者的两倍。现在,当我们仔细观察数据时,假设我们发现吸烟者和非吸烟者的年龄分布不同,并且样本中吸烟者的年龄远高于非吸烟者的年龄。如果我们必须将这条信息联系起来,发展心脏病的结局与老年、吸烟还是两者都有关?
测量吸烟对发展心脏病定量效应的理想方式是取一组人,观察他们在一段时间内吸烟,收集心脏病发展的数据,使用同一组人,并在他们不吸烟时回到过去进行相同的评估。这将有助于测量反事实结果。同一组人代表吸烟者和非吸烟者。由于这不可能实现,我们需要假设存在可交换性。非吸烟者描述吸烟者如果他们曾经吸烟,反之亦然。换句话说,这意味着两组在所有方面都是可比的。在数据样本不可比的情况下,这种情况被称为混淆,导致这种情况的属性(在这种情况下,年龄)被称为混杂因素。如果我们必须用例子来解释这一点,那么所有非吸烟者都较年轻的事实,如果他们不吸烟,非吸烟者将低估老年吸烟者的结果。
这种情况可以表示如下:

我们观察到存在一个后门路径(通过年龄属性)。因此,混淆可以定义得更加简单,即存在一个后门路径。
注意
混淆是指暴露和结果之间的效应或关联因另一个变量的存在而被扭曲的情况。
效应修饰
效应修饰是指暴露在不同组别中有不同值的情况。当关联性测量的指标,如比值比、率比和风险比值非常接近特定组别估计的加权平均值时,可以观察到这种情况。
效应修饰变量是那个不同地(这可能意味着正面或负面)修改观察到的结果效应的变量。
让我们来看一个例子。乳腺癌可以发生在男性和女性身上;在男性和女性中的比率是相同的,但女性发生乳腺癌的比率是男性的 800 倍,性别因素是一个明显的区分因素。
如果效应修饰因子没有被正确识别,这可能会导致错误的粗略估计,从而错失了解风险因素与结果之间关系的机会。
研究数据效应修饰以分析数据需要遵循以下步骤:
-
收集有关潜在效应修饰因子的信息。
-
研究效应修饰因子的效应,测量差异,并保持对匹配值的控制。
-
根据潜在效应修饰因子对数据进行分层,并计算风险对结果效应的估计。确定是否存在效应修饰。如果存在,可以展示/使用这些估计。
回顾一下,混杂因素会掩盖真实效应,而效应修饰因子意味着不同群体有不同的效应。
回归分析方法
正如我们所学的,回归分析使我们能够根据多个自变量来建模两个或更多变量之间的关系,尤其是在预测连续因变量时。回归分析中使用的自变量可以是连续的或二分的。在因变量为二分的情况下,应用逻辑回归。在因变量两个水平之间的分割相等时,则线性回归和逻辑回归都会得到相同的结果。

回归分析的假设(大多数适用于线性回归模型家族)
-
样本案例大小:为了应用回归模型,案例与自变量(IVs)的比例理想情况下应该是 20:1(对于模型中的每个自变量,需要有 20 个案例),至少应该是 5:1(模型中的每个自变量有 5 个案例)。
-
数据准确性:回归分析假设数据的基本有效性,并在运行回归方法之前进行基本数据验证。例如,如果一个变量可以具有 1-5 之间的值,那么任何不在该范围内的值都需要进行修正。
-
异常值:正如我们所学的,异常值通常是具有极端值的数据点,它们看起来并不自然地属于总体的一部分。回归分析假设异常值已经得到处理。
-
缺失数据:寻找缺失数据并解决这些问题很重要。如果一个特定变量有很多缺失值,可能最好删除该变量,除非有太多变量具有许多缺失值。一旦运行了回归过程,没有值的变量可以成为排除的候选者。为了避免通过排除丢失数据的风险,需要应用缺失值技术。
-
正态分布:检查数据以确保数据是正态分布的。在直方图上绘制数据是检查数据是否正态分布的一种方法。以下直方图是正态分布的一个例子:
![回归方法]()
-
线性行为:简单来说,线性行为是指因变量和自变量之间存在直线关系。任何非线性关系都会被忽略。使用双变量散点图来检验线性关系。
-
同方差性:同方差性是指因变量变化时自变量的恒定变化。以下散点图是同方差数据的例子,我们可以看到绘图集中在中心:
![回归方法]()
与线性假设类似,违反同方差性假设不会使回归无效,但会削弱它。
- 多重共线性与奇异性:多重共线性是指自变量高度相关的情况。在奇异性情况下,自变量完全相关,通常一个自变量是其他一个或多个自变量的组合。多重共线性与奇异性都可以通过自变量之间的相关性轻松识别。
从以下部分开始,我们将深入探讨概念图中列出的每个回归方法:

简单回归或简单线性回归
在这种情况下,我们将只处理两个变量;一个因变量和一个自变量。简单线性回归就是比较两个模型;一个是没有自变量,最佳拟合线是通过因变量形成的,另一个是使用最佳拟合回归线。现在让我们通过一个例子来了解最佳拟合线和回归线的定义。
我们将从现实世界的例子开始。假设有一个房地产经纪人,每次他完成一笔房地产交易,他都会得到一笔佣金。很明显,佣金金额取决于交易的价值;交易价值越高,佣金就越高。因此,在这种情况下,佣金成为因变量,交易金额成为自变量。为了预测可能的下一笔佣金金额,让我们考虑以下最后六次交易的样本数据:

假设我们没有整体交易金额的数据。如果我们想要预测之前数据中给出的下一笔佣金,我们首先将其绘制在图中,如图所示:

我们用来识别数据中下一个佣金金额的选项之一是计算平均值,这是样本的最佳预测。

让我们在图上绘制这个点,这将成为最佳拟合。在之前的图上绘制平均值:

计算每个点到平均值的距离给出了下一图中显示的值。这种距离度量称为误差或残差。所有点的误差总和始终为零,这是拟合优度的度量。

在图上绘制距离。

我们在前面章节中学习了关于SSE(平方和误差)值的内容。误差被平方是因为它使值变为正值,并强调更大的偏差。以下表格显示了为样本数据计算出的 SSE 值:

简单线性回归的整体目标是构建一个模型,最大限度地减少 SSE 值。到目前为止,我们已经看到了使用单个变量(即因变量)的最佳拟合。现在,让我们假设我们得到了我们例子中的另一个自变量的数据。实际上,这给我们带来了一条新的回归线,这条线与我们之前得到的最佳拟合线不同。预期新的自变量将显著减少 SSE 值。换句话说,这条新的回归线应该是对给定数据的更好拟合。
如果早期最佳拟合线和回归线之间没有差异,这意味着所确定的独立变量对结果没有影响。总的来说,简单线性回归旨在使用具有最小 SSE 值的数据找到最佳拟合线。
现在我们将独立变量数据添加到我们的分析中——正如表格中所示的不动产交易价值:

我们将在因变量和自变量之间绘制散点图。

在这种情况下可能有多个线/方程,如下一图所示。如果数据似乎呈线性分布,我们可以继续。如果数据点散布在各个地方,这表明数据中没有线性关系,我们可以选择停止推导回归线。我们可以选择在这里计算相关系数,如下所示:
r = 0.866
这表明两个变量之间的关系很强,我们可以继续构建回归模型。

现在计算x轴和y轴的平均值;以下是这些值:

然后将这些平均值绘制为质心到散点图上,如图所示:

最佳拟合回归线必须通过包含x和y变量平均值的质心。计算如下:




最终的回归线方程看起来是这样的:

在散点图上绘制前一个方程看起来是这样的:

多元回归
多元回归是简单线性回归的扩展,有一个重要的区别,即可以使用两个或更多独立变量来预测或解释一个因变量的方差。增加更多的独立变量并不一定使回归更好。可能存在两个潜在问题,其中一个就是过拟合。我们已经在前面的章节中讨论过这个问题。过多的独立变量可能会增加方差,但在现实中,它们对模型没有任何贡献,从而造成过拟合。此外,增加更多的独立变量会增加更多的关系。不仅独立变量可能相关于因变量,而且独立变量之间也可能存在依赖关系。这种情况被称为多重共线性。理想的期望是独立变量与因变量相关,但彼此之间不相关。
由于过拟合和多重共线性问题,在开始进行多元回归分析之前需要进行准备工作。准备工作可能包括计算相关性、绘制散点图映射和运行简单线性回归等。
假设我们有一个因变量和四个自变量,存在多重共线性风险。这意味着四个自变量与一个因变量之间存在四个关系,而在自变量之间,还可能有六个关系。所以,共有 10 个关系需要考虑,如图所示。DV 代表因变量,IV 代表自变量。

一些独立变量比其他变量更适合预测因变量,而一些可能对预测没有任何贡献。需要决定考虑哪个因变量。
在多元回归中,每个系数被解释为变量变化一个单位时,y的估计变化量,同时假设其他变量保持不变。
以下为多元回归方程。

假设我们想将一个独立变量拟合为许多变量(x、y和x²)的函数。我们可以遵循一个简单的程序来获取所有变量的系数。这适用于线性、二次和三次函数。
以下为逐步过程:
-
将每个变量的所有点按顺序排列在单独的列中。
-
将所有要表示为矩阵的独立变量列合并。
-
在矩阵的起始位置添加一列。
-
将此矩阵命名为 X 矩阵。
-
为所有独立变量制作一个单独的列矩阵,并称其为 Y 矩阵。
-
使用此处提供的公式计算系数(这是最小二乘回归):
B = (XT*X)*(-1)X^TY
这是一个矩阵运算,结果向量是系数。
在进行多元回归之前,需要做大量的准备工作。有必要退后一步,对考虑中的变量进行分析。可以绘制一些基本的散点图来检查是否存在任何相关性,并分析因变量之间的关系。可以使用散点图、相关性分析和单个或分组回归等技术。如果有任何定性或分类变量,我们需要使用虚拟变量来构建回归模型。
多项式(非线性)回归
虽然线性回归模型 y = Xβ + ε 是一个通用模型,可以拟合未知参数 β 中的任何线性关系,但在分析师知道真实响应函数中存在曲线效应的情况下,多项式模型适用。多项式模型也被用作未知且可能非常复杂的非线性关系的近似函数。多项式模型是未知函数的泰勒级数展开。
如果两个变量呈线性相关,散点图看起来如下所示:

从先前的双变量散点图可以看出,朋友和幸福之间存在线性关系。图表显示“朋友越多,幸福越多”。如果我们谈论变量之间曲线关系,即朋友数量和幸福之间的关系呢?这意味着随着朋友数量的增加,幸福也会增加,但仅限于某个点。以下图表显示了数据中的这种行为:

如果数据不是线性的,那么过程就是通过转换自变量或因变量使其之间有线性关系,从而使数据线性化。这种转换并不总是有效,因为数据和行为可能存在真正的非线性。在这种情况下,我们需要在回归中包含独立变量的平方。这也被称为多项式/二次回归。最小二乘法用于拟合多项式回归模型,因为它最小化了系数估计中的方差。
广义线性模型(GLM)
让我们看看为什么线性回归模型不起作用的原因。
简单线性回归是一个定量变量预测另一个,多重回归。它是扩展的简单线性回归,但具有更多的自变量,最后,非线性或多项式回归是存在两个定量变量但数据是曲线的情况。
现在,以同样的方式运行典型的线性回归,有一些问题。二元数据不具有正态分布。这就是需要其他回归模型的原因。其次,因变量的预测值可能超出 0 和 1,这与概率的概念相悖。最后,概率通常是非线性的,并且在极端情况下可能取到极低或极高的值。
GLM 是线性回归的推广,支持独立变量可以具有除正态分布以外的分布误差模型的情况。GLM 通过允许线性模型通过链接函数与自变量相关联,并允许每个测量的方差程度是其预测值的函数,从而推广了线性回归。
简而言之,GLM(广义线性模型)概括了线性、逻辑和泊松回归模型。
逻辑回归(logit 链接)
逻辑回归是线性回归的扩展,其中因变量是一个分类变量,负责对观测值的分类。
例如,如果 Y 表示某个客户是否可能购买产品(1)或不太可能购买(0),我们有一个具有两个类别或类(0 和 1)的分类变量。逻辑回归可以解决一个分类问题,其中类别是未知的。这是通过使用预测值来分类一个新观测值,其中类别是未知的,基于变量将其分类到某个类别中。
以下是一些例子:
-
将客户分类为回头客(1)或非回头客(0)
-
根据信用评分预测贷款是否会被批准或拒绝
其中一个重要的用途可以是在预测值之间找到相似性。
在我们开始深入研究逻辑回归之前,让我们回顾一下在早期章节中提到的概率和赔率的概念。
概率 = 关注的结果 / 所有可能的结果。
例如,当掷公平硬币时,P(正面) = ½ = 0.5。当掷骰子时,P(1 或 2) = 2/6 = 1/3 = 0.33。在一副扑克牌中,P(方块牌) = 13/52 = ¼ = 0.25。
比率 = P(某事发生)/P(某事不发生) = p/(1-p)
例如,当掷硬币时,odds(正面 = 0.5/0.5= 1)。当掷骰子时,odds(1 或 2) = 0.333/0.666 = ½ = 0.5。在一副扑克牌中,odds(方块牌) = 0.25/0.75 = 1/3 = 0.333。
比率比是两个概率之比。
例如,当掷硬币时,在公平掷币的情况下:
P(正面) = ½= 0.5 且 odds(正面) = 0.5/0.5 = 1 = 1:1
在掷出有偏硬币的情况下:
P(正面) = 0.7 且 odds(正面) = 0.7/0.3 = 2.333
比率比 = odds1/odds0 = 2.333/1 = 2.333
这意味着掷出正面的概率是公平硬币的 2.333 倍。
总体而言,逻辑回归旨在:
-
模型事件发生的概率取决于独立变量的值,这些变量可以是分类的或数值的
-
估计事件发生与不发生的概率
-
预测一组变量对二元响应变量的影响
-
分类观察结果属于特定类别,基于概率估计
逻辑回归中的比率比
逻辑回归中变量的比率比表示当该变量的单位增加时,该变量的几率如何变化,同时保持其他变量不变。
让我们通过一个例子来理解这一点——体重是否依赖于睡眠呼吸暂停。假设体重变量的比率比为 1.07。这意味着体重增加一磅可能会使患有睡眠呼吸暂停的几率增加 1.07 倍。这可能并不显著。在体重增加 10 磅的情况下,几率增加到 1.98,是患有睡眠呼吸暂停的人的几率的两倍。重要的是我们要区分概率和比率的度量。例如,尽管体重增加 20 磅使患有睡眠呼吸暂停的人的几率增加了 4 倍,但体重可能增加 20 磅的概率可能非常低。
在逻辑回归中,有两个重要的步骤:
-
找到属于特定类别的概率。因此,如果 Y = 0 或 1,属于 类别 1 的概率是 P(Y=1)。
-
我们需要使用概率的截断值来确保每个案例都进入一个类别。在二元截断的情况下,P(Y=1) > 0.5 将被分类为 1,而 P(Y=0) < 0.5 将被分类为 0。
模型
y[i] 是正态分布的,对于 i = 0,1,…,n,其值为 0 或 1。
y[i] 等于 {0, 1},其中 P(y[i]= 1) = p,P(y[i]= 0) = 1-p
Y = a + bx for P(y[i]= 1)
p[i] = a + bx[i]
注意,p[i] 不会在 (0, 1) 之间取值。这是通过使用预测变量的非线性函数来固定的,例如:

显然,当x从-∞变化到∞时,这个值介于 0 和 1 之间。据此,可以得到a+bx[i]如下:

下面的曲线显示了函数的变化情况:

Poisson 回归
在广义线性模型(GLM)的背景下,Poisson 回归是指具有泊松分布的自变量下的数据计数,并且应用了响应的对数链接函数,该函数可以用未知参数的线性组合来建模。
实现线性回归和逻辑回归
请参考本章提供的源代码以实现线性回归。(源代码路径.../chapter10/...位于每个技术文件夹下)
使用 Mahout
请参考文件夹.../mahout/chapter10/linearregressionexample/。
请参考文件夹.../mahout/chapter10/logisticregressionexample/。
使用 R
请参考文件夹.../r/chapter10/linearregressionexample/。
请参考文件夹.../r/chapter10/logisticregressionexample/。
使用 Spark
请参考文件夹.../spark/chapter10/linearregressionexample/。
请参考文件夹.../spark/chapter10/logisticregressionexample/。
使用 scikit-learn
请参考文件夹.../python-scikit-learn/chapter10/linearregressionexample/
请参考文件夹.../python-scikit-learn/chapter10/logisticregressionexample/
使用 Julia
请参考文件夹.../julia/chapter10/linearregressionexample/。
请参考文件夹.../julia/chapter10/logisticregressionexample/。
摘要
在本章中,你学习了基于回归分析的机器学习,特别是如何使用 Mahout、R、Python、Julia 和 Spark 实现线性回归和逻辑回归模型。此外,我们还涵盖了其他相关统计概念,如方差、协方差和方差分析等。我们通过实例深入探讨了回归模型,以了解如何将它们应用于实际问题。在下一章中,我们将介绍深度学习方法。
第十一章:深度学习
到目前为止,我们介绍了一些监督学习、半监督学习、无监督学习和强化学习的技术和算法。在本章中,我们将介绍神经网络及其与深度学习实践的关系。传统的学习方法涉及编写告诉计算机做什么的程序,但神经网络是关于学习和使用观察数据来寻找解决方案,这些数据是输入的主要来源。这种技术的成功取决于神经网络是如何训练的(即观察数据的质量)。深度学习指的是学习先前提到的神经网络的方法。
技术的进步将这些技术提升到了新的高度,在这些技术中,它们展示了卓越的性能,并被用于解决计算机视觉、语音识别和自然语言处理(NLP)中的一些关键非平凡需求。Facebook 和 Google 等大型公司以及其他许多公司已经在很大程度上采用了深度学习实践。
本章的主要目的是在概念上掌握神经网络和相关深度学习技术。借助一个复杂的模式识别问题,本章涵盖了开发典型神经网络的步骤,这将使你能够使用它来解决类似复杂性的问题。以下表示展示了本书涵盖的所有学习方法,突出了本章学习的主要主题——深度学习。

本章深入探讨了以下主题:
-
快速回顾机器学习的目的、学习类型以及深度学习的背景,特别是它解决的一个特定问题。
-
神经网络的概述:
-
人类大脑作为神经网络的主要灵感来源
-
神经网络架构的类型和一些神经元的基本模型
-
一个简单的学习示例(数字识别)
-
感知器概述,神经网络的第一代及其所能做到的和不能做到的事情
-
-
线性和逻辑输出神经元的概述。介绍反向传播算法以及应用反向传播算法的导数来解决一些实际问题
-
认知科学的概念、softmax 输出函数以及处理多输出场景
-
应用卷积网络和对象或数字识别的问题
-
循环神经网络(RNN)和梯度下降法
-
信号处理作为成分分析和自编码器的原理;深度和浅度自编码器的类型
-
使用 Apache Mahout、R、Julia、Python(scikit-learn)和 Apache Spark 进行练习的动手实现
背景
让我们先回顾一下机器学习的先决条件,并加强学习方法的宗旨和背景。正如我们所学的,机器学习是通过构建模型来训练机器,使用观察数据,而不是直接编写定义数据模型的特定指令,以解决特定的分类或预测问题。在这个背景下,“模型”这个词不过是一个“系统”。
程序或系统是使用数据构建的,因此看起来与手写的程序非常不同。如果数据发生变化,程序也会适应它以进行新数据的下一级训练。所以它所需要的只是处理大规模数据的能力,而不是让熟练的程序员为所有可能仍然证明是严重错误的条件编写代码。
我们有一个机器学习系统的例子,称为垃圾邮件检测器。这个系统的首要目的是识别哪些邮件是垃圾邮件,哪些不是。在这种情况下,垃圾邮件检测器并没有被编码来处理所有类型的邮件;相反,它是从数据中学习的。因此,这些模型的精确度始终取决于观察数据的好坏。换句话说,从原始数据中提取的特征通常应该覆盖数据模型的所有状态,以便模型准确。特征提取器被构建出来,用于从给定的数据样本中提取标准特征,这些特征被分类器或预测器使用。
一些其他例子包括识别模式,如语音识别、物体识别、人脸检测等。
深度学习是一种机器学习方法,它试图从给定数据中学习显著特征,因此试图减少为每个数据类别(例如,图像、声音等)构建特征提取器的任务。对于人脸检测的需求,深度学习算法记录或学习特征,如鼻子的长度、眼睛之间的距离、眼球的颜色等。这些数据被用来解决分类或预测问题,显然与传统的浅层学习算法非常不同。
人类大脑
人类大脑被认为是人体中最不可思议的器官之一。大脑本质上是我们人类智能的源泉。它负责根据我们关于触觉、嗅觉、视觉、听觉等方面的体验来构建我们的感知。这些体验被收集并存储为记忆和情感。本质上,大脑是我们智能的来源,没有它,我们可能只是世界上的原始生物。
新生儿的脑部能够解决任何复杂且强大的机器都无法解决的问题。实际上,就在出生后的几天内,婴儿就开始识别他/她父母的脸和声音,并在他们不在时表现出渴望见到他们的表情。在一段时间内,他们开始将声音与物体联系起来,甚至可以在看到物体时识别它。那么他们是如何做到这一点的呢?如果他们遇到一只狗,他们是如何识别它为狗的;他们是否将吠声与之联系起来并模仿同样的声音?
它很简单。每次婴儿遇到一只狗时,他/她的父母都会将其定义为狗,这加强了孩子的模型。如果他们判定孩子是错误的,孩子的模型就会吸收这些信息。因此,狗有长长的耳朵、长长的鼻子、四条腿、长长的尾巴,可以是黑色、白色或棕色等不同颜色,并发出吠声。这些特征是通过婴儿大脑记录的视觉和声音来识别的。因此收集到的观察数据驱动了此后对新物体的识别。
现在,假设婴儿第一次看到狼;他/她会通过观察其特征相似性将狼识别为狗。现在,如果父母在第一次看到时就指出明显的差异,例如,狼发出的声音不同,那么这将成为一种新的体验,并存储在记忆中,用于下一次的观察。随着越来越多此类例子的同化,孩子的模型变得越来越准确;这个过程是非常无意识的。
几年来,我们一直在努力构建具有人类大脑智能的机器。我们谈论的是可以像人类一样行为并能够以类似人类的效率完成特定工作的机器人,例如开车、打扫房子等等。现在,要构建这样的机器人需要什么?我们可能需要构建一些超级复杂的计算系统,这些系统能够迅速解决我们大脑可以解决的问题。这个致力于构建人工智能系统的领域被称为深度学习。
以下是一些深度学习的正式定义:
根据维基百科,深度学习是一组机器学习算法,它试图通过使用由多个非线性变换组成的模型架构来模拟数据中的高级抽象。
根据deeplearning.net/,深度学习是机器学习研究的新领域,其目标是使机器学习更接近其最初目标之一——人工智能。
这个主题已经演变了数年;以下表格列出了这些年的研究领域:
| 研究领域 | 年份 |
|---|---|
| 神经网络 | 1960 |
| 多层感知器 | 1985 |
| 限制性玻尔兹曼机 | 1986 |
| 支持向量机 | 1995 |
| 辛顿提出深度信念网络(DBN)对深度学习和 RBM 的新兴趣,以及最先进的 MNIST | 2005 |
| 深度循环神经网络 | 2009 |
| 卷积深度信念网络 | 2010 |
| 最大池化卷积深度信念网络 | 2011 |
在众多贡献者中,这个领域的几位关键贡献者包括杰弗里·辛顿(Geoffrey Hinton)、杨立昆(Yann LeCun)、洪乐克·李(Honglak Lee)、安德鲁·杨(Andrew Y. Ng)和约书亚·本吉奥(Yoshua Bengio)。
以下的概念模型涵盖了深度学习的不同领域,以及本章涵盖的主题范围:

让我们来看一个简单的问题;要求是识别这里给出的手写脚本中的数字:

对于人类大脑来说,这非常简单,因为我们能将数字识别为 287635。我们大脑解释数字的简单性是感知的,它削弱了这一过程中涉及的复杂性。由于视觉皮层的存在,我们的大脑被训练成逐步拦截不同的视觉,每个皮层包含超过 1.4 亿个神经元,它们之间有数十亿个连接。简而言之,我们的大脑不亚于一个经过数百万年演化的超级计算机,并且已知能够很好地适应视觉世界。
如果一个计算机程序需要破解数字识别,应该遵循什么规则来识别和区分一个数字与另一个数字?
神经网络是多年来一直在研究的一个领域,并且已知可以解决多层学习的需求。整体的想法是输入大量手写的数字;以下图像展示了这些数据(训练)的一个例子,并且可以从这些例子中学习。这意味着规则是从提供的训练数据中自动推断出来的。因此,训练数据集越大,预测的准确性就越高。如果我们面临一个问题,需要区分数字 1 和数字 7,或者数字 6 和数字 0,就需要学习一些细微的差异。对于一个零,起点和终点之间的距离是最小或没有。

差异基本上是因为这些学习方法的目标是模仿人类大脑。让我们看看是什么使得这个问题难以解决。
总结来说,深度学习作为机器学习的一个子集,我们知道这涉及到提供示例和评估模式以在出错时进行演化的模型。因此,在一段时间内,这个模型将以最佳可能的准确性解决问题。
如果这需要用数学来表示,让我们定义我们的模型为一个函数 f(x,θ)。
在这里,x 是作为值向量提供的输入,而 θ 是模型用来预测或分类 x 的参考向量。因此,我们需要将 θ 暴露给最大数量的示例,以提高准确性。
让我们举一个例子;如果我们想根据两个因素预测一家餐厅的访客是否会再次光临——一个是账单金额(x[1]),另一个是访客的年龄(x[2])。当我们收集一段时间内的数据并分析其输出值时,这个值可以是 1(如果访客回来了)或-1(如果访客没有回来)。当数据被绘制出来时,可以呈现任何形式——从线性关系到任何其他复杂形式,如图所示:

看起来像线性关系的东西看起来很简单,而更复杂的关系则使模型动态复杂化。参数 θ 是否真的有一个最优值?我们可能需要应用优化技术,在接下来的章节中,我们将介绍这些技术,例如感知器和梯度下降法等。如果我们想开发一个执行此操作的程序,我们需要知道大脑是如何识别这些数字的,即使我们知道了,这些程序也可能非常复杂。
神经网络
神经计算一直是研究的主要兴趣,旨在了解神经元(灵活连接的概念)中的并行计算是如何工作的,以及如何像人类大脑一样解决实际问题。现在让我们看看人类大脑的核心基本单元——神经元:

神经元
人类大脑就是由神经元和连接组成的。神经元是大脑的最小部分,如果我们取一小块大脑,其大小与一小粒米饭粒相当,已知至少包含 10000 个神经元。平均每个神经元与其他神经元有大约 6000 个连接。如果我们观察神经元的总体结构,它看起来如下。
我们人类经历的所有感觉,无论是思考还是情感,都是因为这些被称为神经元的数百万个细胞在大脑中的活动。这些神经元通过传递信息相互沟通,使人类能够感受、行动和形成感知。此处所示的图解描绘了生物神经结构和其组成部分:

每个神经元都有一个中央细胞体;像任何细胞一样,它有一个负责与其他神经元发送和接收信息的轴突和树突。轴突连接到树突的地方称为突触。突触本身有一个有趣的结构。它们包含触发传递的传递分子,这种传递可以是正的或负的。
神经元的输入被汇总,当它们超过阈值时,就会向下一个神经元传递一个电脉冲。
突触
以下图表展示了突触模型,描述了从轴突到树突的消息流动。突触的工作不仅仅是传输消息,实际上,它还会根据信号流动进行适应,并具有从过去活动中学习的能力。

作为机器学习领域的类比,输入连接的强度是根据其被使用的频率来确定的,因此其影响神经元输出的程度也随之确定。这就是人类潜意识中学习新概念的方式。
此外,还可能有外部因素,如药物或身体化学成分,可能会影响这一学习过程。
现在我们将最终通过以下列表总结大脑内部的学习过程:
-
神经元与其他神经元或有时受体进行通信。皮层神经元使用尖峰进行通信。
-
神经元之间的连接强度可以改变。它们可以通过建立和移除神经元之间的连接,或者根据神经元对其他神经元可能产生的影响来加强连接,从而取正值或负值。一个称为长期增强(LTP)的过程发生,从而产生这种长期影响。
-
大约有 10¹¹ 个神经元,它们的权重使得人类大脑的计算比工作站更有效率。
-
最后,大脑是模块化的;大脑皮层的不同部分负责做不同的事情。某些任务在某个区域比其他区域注入更多的血流,从而确保不同的结果。
在将神经元模型 schematizing 到人工神经网络(ANN)之前,让我们首先看看神经元的不同类型、类别或方面,特别是人工神经元或感知器,这是生物神经元的深度学习等效物。这种方法已知在我们在上一节中列出的某些用例中产生了极其高效的结果。ANN 也被称为前馈神经网络、多层感知器(MLP),以及最近,深度网络或学习。其中一个重要特征是需要特征工程,而深度学习则代表需要最少特征工程的应用,学习通过多个学习的神经元层发生。
人工神经元或感知器
很明显,人工神经元是从生物神经元那里获得灵感的,正如之前所展示的那样。人工神经元的特点如下:
-
从其他神经元接收一组输入,这些输入激活了神经元
-
有一个输出传输器,用于传输信号或激活其他神经元
-
最后,核心处理单元负责从输入激活中产生输出激活
理想化神经元是一个应用于构建模型的过程。简而言之,它是一个简化过程。一旦简化,就可以应用数学和建立类比。在这种情况下,我们可以轻松地增加复杂性,并在已识别的条件下使模型更加健壮。在简化过程中,需要特别注意不要删除任何显著贡献的方面。
线性神经元
线性神经元是神经元的最简单形式;它们可以表示如下:

输出 y 是输入 x[i] 和其权重 w[i] 的乘积之和。这可以用以下方式在数学上表示:

这里,b 是偏置。
之前方程的图形表示如下:

矩形线性神经元/线性阈值神经元
矩形线性神经元与线性神经元类似,如前所述,只是在输出参数值小于(<)零(0)时将其设置为零,而在输出值大于(>)零(0)时,它继续作为输入的线性加权和:

二元阈值神经元
二元阈值神经元由 McCulloch 和 Pitts 于 1943 年引入。这类神经元首先计算输入的加权总和,类似于线性神经元。如果这个值超过一个定义的阈值,就会发送一个固定大小的脉冲到活动状态。这个脉冲被称为命题的真值。另一个重要点是输出。在任何给定时间点的输出是二进制的(0 或 1)。
展示这种行为的方程如下:

并且
y = 1 如果 z ≥ θ,
y = 0 否则
这里 θ = -b (偏置)
(或者)

并且
y = 1 如果 z ≥ 0,
y = 0 否则
此外,之前方程的图形表示如下:

Sigmoid 神经元
Sigmoid 神经元在人工神经网络中得到了广泛的应用。这些神经元因其提供平滑、实值输出而闻名,因此是所有输入的有界函数。与迄今为止我们所看到的神经元类型不同,这些神经元使用对数函数。
对数函数因其易于计算的导数而闻名,这使得学习变得容易。这个导数值用于计算权重。以下是 sigmoid 神经元的输出方程:


图形表示如下:

随机二元神经元
随机二进制神经元使用与逻辑单元相同的方程,但有一个重要区别,即输出测量的是概率值,该值衡量在短时间内产生尖峰的概率。因此,方程看起来是这样的:


此外,该方程的图形表示如下:

总体而言,我们可以观察到每个神经元接受了一组输入的加权和,并应用了非线性激活函数。对于解决回归问题,通常应用修正线性函数;对于分类问题,应用逻辑函数。这种通用的表示可以如下给出:

现在,这些输入可以被输入到一系列的神经元层中。让我们看看接下来会发生什么以及它是如何发生的。输入层推动输入值;然后神经元隐藏层将这些值作为输入。在这些隐藏层中可能有多个层,其中一层输出作为下一层的输入。每一层都可以负责专门的学习。此外,最后,隐藏层的最后一个输入到最终输出层。以下图展示了人工神经网络(ANN)的典型结构。下一个图中的每个圆圈代表一个神经元。信用分配路径(CAP)的概念指的是从输入到输出的路径。在前馈网络中,路径的长度是总隐藏层数量加上输出层。以下图显示了一个具有单个隐藏层和层间连接的前馈神经网络:

这里展示了具有两个隐藏层的案例:

神经网络大小
计算神经元或参数的数量如下所示:
-
对于单层网络:
神经元总数 = 4 + 2 = 6(输入不计入)
总权重 = [3 x 4] + [4 x 2] = 20
总偏差 = 4 + 2 = 6,对于 26 个可学习的参数。
-
对于双层网络:
神经元总数 = 4 + 4 + 1 = 9(输入不计入)
总权重 = [3 x 4] + [4 x 4] + [4 x 1] = 12 + 16 + 4 = 32
总偏差 = 4 + 4 + 1 = 9,对于 41 个可学习的参数
那么,神经网络的理想大小是什么?识别每个层的可能大小以及隐藏层的数量非常重要。这些决策决定了网络的能力。更高的值有助于支持更高的能力。
让我们举一个例子,我们将通过获取以下分类器来尝试三种不同大小的隐藏层:

显然,随着神经元数量的增加,可以表达更复杂的函数,这是好事,但我们需要注意过拟合的情况。因此,对于更简单的数据,较小的网络效果较好。随着数据复杂性的增加,需要更大的网络。这种权衡总是在处理模型的复杂性与过拟合之间。深度学习通过应用复杂模型来解决极复杂问题,并通过采取额外措施来处理过拟合。
一个例子
下一个示例展示了使用多层感知器方法进行的人脸识别案例:

多层将此图像作为输入,最终创建并存储分类器定义。

给定一张照片,每一层专注于学习照片的特定部分,最终存储输出像素。
关于权重和误差度量的一些关键点如下:
-
训练数据是学习神经元权重的来源
-
错误度量或损失函数与回归和分类问题不同。对于分类,应用对数函数,而对于回归,使用最小二乘度量。
-
这些方法通过使用凸优化技术(如梯度下降法)更新权重来帮助控制这些误差度量。
神经网络类型
在本节中,我们将介绍一些关键类型的神经网络。以下概念图列出了几种主要的神经网络类型:

多层全连接前馈网络或多层感知器(MLP)
如神经网络简介部分所述,MLP 有多个层,其中一层的输出作为下一层的输入。多层感知器如图所示:

Jordan 网络
Jordan 网络是部分循环网络。这些网络是当前的前馈网络,不同之处在于输入层内部有额外的上下文神经元。这些上下文神经元是自我强制的,并使用来自输入神经元的直接反馈创建。在 Jordan 网络中,上下文神经元的数量始终等于输入神经元。以下图显示了输入层的差异:

Elman 网络
Elman 网络,就像 Jordan 网络一样,是部分递归的前馈网络。这些网络也有上下文神经元,但在这个情况下,主要区别在于上下文神经元接收来自输出神经元的输入,而不是来自隐藏层。上下文神经元的数量与输入神经元的数量之间没有直接关联;相反,上下文神经元的数量与隐藏神经元的数量相同。这反过来使得这个模型更加灵活,就像隐藏神经元的数量在具体情况下一样:

径向偏置函数(RBF)网络
径向偏置函数网络也是前馈神经网络。这些网络有一个特殊的隐藏层,包含称为径向对称神经元的特殊神经元。这些神经元用于使用高斯度量将输入向量与中心之间的距离值进行转换。这个额外层的好处是它提供了确定所需层数的能力,而无需人工干预。线性函数的选择决定了最优输出层。因此,在这些网络中,学习过程相对较快,甚至与反向传播相比也是如此。
这种方法的唯一缺点是处理大型输入向量的能力。下面的图示展示了径向对称神经元的隐藏层。

跳时网络
跳时网络围绕一个称为“网络能量”的概念进行工作。这实际上就是网络的最优局部最小值,它定义了功能性的平衡状态。跳时网络的目标是达到这个平衡状态。平衡状态是指某一层的输出等于前一层的输出。以下图示展示了如何在跳时网络中检查和管理输入和输出状态:

动态学习向量量化(DLVQ)网络
动态学习向量量化(DLVQ)网络模型是神经网络的一种变体,它从较少的隐藏层开始,并动态生成这些隐藏层。对于属于同一类的模式具有相似性是很重要的;因此,这个算法最适合分类问题,如模式识别、数字识别等。
梯度下降法
在本节中,我们将探讨优化神经网络最流行的一种方法之一,即最小化成本函数、最小化错误并提高神经网络准确性的方法:梯度下降法。这里的图表显示了实际值与预测值之间的差异,以及预测不准确的情况:

反向传播算法
在继续讨论网络训练的话题时,梯度下降算法帮助神经网络学习权重和偏置。此外,为了计算损失函数的梯度,我们使用一个称为反向传播的算法。反向传播首次在 20 世纪 70 年代被讨论,直到 20 世纪 80 年代才在应用方面变得突出。已经证明,当使用反向传播算法时,神经网络学习速度更快。
在本章的早期部分,我们看到了基于矩阵的算法是如何工作的;反向传播算法使用了类似的符号。对于一个给定的权重w和偏置b,损失函数 C 有两个偏导数,分别是∂C/∂w和∂C/∂b。
关于反向传播的损失函数的一些关键假设在此处陈述。让我们假设损失函数由以下方程定义:

其中,n = 训练示例的数量
x = 对单个训练集求和
y = y(x)是期望输出
L = 神经网络中的总层数
a^L = a^L(x)是输出激活向量
假设 1:整体损失函数可以是单个损失函数的平均值。对于x个单独的训练集,损失函数现在可以表述如下:

此外,单个训练集的损失函数可以如下所示:

基于这个假设,由于我们可以计算每个训练集x的偏导数∂[x]C/∂w 和∂[x]C/∂b,所以整体偏导数函数∂C/∂w 和∂C/∂b 可以是每个训练集偏导数的平均值。
假设 2:这个假设是关于损失函数C,即C可以是神经网络输出的函数,如图所示:

将损失函数的先前方程式扩展,每个训练示例集x的二次损失函数现在可以写成如下形式。我们可以看到它如何作为输出激活的函数。

反向传播是关于权重和偏置对整体损失函数值的影响。
首先,我们计算第l层的第j个神经元的误差δl[j]*,然后使用这个值来计算与这个误差*δl[j]相关的偏导数:

第l层的第j个神经元的误差函数δ^l[j]可以定义为:

因此,层L的误差δ^L也可以计算。这反过来又帮助计算损失函数的梯度。
反向传播算法按顺序使用以下方程,如图所示:
方程式 1:给定位置 j 的神经元,层 L 的计算误差 δ^L。

方程式 2:给定下一层的误差 δ^(L+1),层 L 的计算误差 δ^L。

注意
Hadamard 积是一种矩阵乘法技术,用于逐元素矩阵乘法,如下所示:

符号
用于表示此方法。
方程式 3:此方程衡量对成本的影响,并给出偏差的变化:

此外,我们还可以从方程式 1 和 2 得到以下内容:

这是因为误差值与偏导数的改变率相同。
方程式 4:此方程用于计算成本变化率与权重的关系。

在这些算法的每个阶段,都有某种学习影响网络的总体输出。
这里解释了编译后的最终反向传播算法:
-
输入层 x,对于 x =1 设置激活为 a¹。
-
对于其他每一层 L = 2, 3, 4 … L,计算激活如下:
![反向传播算法]()
-
使用方程式 1 和 2 计算误差 δ^L。
-
使用方程式 3 反向传播误差 l = L-1, L-2, … 2, 1。
-
最后,使用方程式 4 计算成本函数的梯度。
如果我们观察算法,错误向量 δ^l 是从输出层开始反向计算的。这是事实,因为成本是网络输出的函数。为了理解早期权重对成本的影响,需要应用链式法则,该方法通过所有层反向工作。
Softmax 回归技术
Softmax 回归也称为多项式逻辑回归。本节不深入探讨逻辑回归的概念,因为它在本书中关于回归的章节中已有涉及。相反,我们将具体探讨如何将这种技术在深度学习用例中的数字识别相关问题上应用。
这种技术是逻辑回归的一个特例,适用于多类别。正如我们所学的,逻辑回归的结果是一个二进制值 {0,1}。Softmax 回归便于处理 y(i)<--{1,…,n},其中 n 是类别的数量,相对于二进制分类。在 MNIST 数字识别案例中,n 的值是 10,代表 10 个不同的类别。例如,在 MNIST 数字识别任务中,我们会遇到 K=10 个不同的类别。
由于其处理多个类别的能力,这项技术在基于神经网络的解决问题领域中得到了积极的应用。
深度学习分类法
这里展示了深度学习案例的特征学习分类法:

这里列出了用于实现神经网络应用的一些框架:
-
Theano 是一个 Python 库
-
Torch 是 Lua 编程语言
-
Deeplearning4J 是一个开源的基于 Java 的框架,与 Spark 和 Hadoop 一起工作
-
Caffe 是一个基于 C++ 的框架
卷积神经网络 (CNN/ConvNets)
CNN,也称为卷积网(ConvNets),是常规神经网络的变体。
让我们回顾一下常规神经网络的函数。常规神经网络有一个基于向量的单个输入,它通过一系列隐藏层进行转换,其中每一层的神经元与其相邻层的神经元相连。这个系列中的最后一层提供输出。这个层被称为输出层。
当神经网络输入是一个图像,并且不仅仅适合单个向量结构时,复杂性会增加。CNN 有这种轻微的变化,其中输入被假定为具有深度(D)、高度(H)和宽度(W)的三维向量。这种假设改变了神经网络的组织方式和功能方式。以下图比较了标准三层神经网络与 CNN。

如我们所见,前面展示的卷积网以三维方式排列神经元;网络中的每一层都将这些转换为神经元激活的 3D 输出。
卷积网络架构包含一组用于特定功能的固定层。其中最关键的层如下:
-
卷积层 (CONV)
-
池化层 (POOL)
-
全连接 (FC) 层
在某些情况下,激活函数被写成另一个层(RELU);全连接层转换可能存在一个独特的归一化层。
卷积层 (CONV)
卷积层是卷积网的核心。这个层负责以三维格式保持神经元,因此负责三维输出。以下是一个具有 32 x 32 x 3 维度的输入体积的示例。如图所示,每个神经元都连接到特定的输入区域。在深度方向上可以有多个神经元;在示例中我们可以看到五个神经元。

此图展示了网络卷积函数在神经元函数表示中的工作方式:

也就是说,神经元的核心理念保持不变,负责计算权重和输入的乘积,然后观察非线性行为。唯一的区别是对局部区域的连接限制。
池化层 (POOL)
可以有多个卷积层,在这些卷积层之间,可以有池化层。池化层负责通过减少输入体积的空间大小来降低过拟合的可能性。空间大小的减少意味着减少网络中的参数数量或计算量。MAX 函数有助于减少空间大小。池化层使用 MAX 函数,并在三维表示的每个切片上应用它,切片是按深度进行的。通常,池化层应用 2 X 2 大小的过滤器,沿宽度和高度应用。这可以丢弃大约 75%的激活。
总体来说,池化层具有以下特点:
-
总是考虑一个体积大小为 W1×H1×D1 作为输入
-
应用步长 S 和空间范围 F,生成 W2×H2×D2 输出,其中:
W2=(W1−F)/S+1
H2=(H1−F)/S+1
D2=D1
全连接层(FC)
全连接层与常规或传统神经网络非常相似,负责与前一层激活建立广泛的连接。连接激活是通过矩阵乘法技术计算的。更多细节可以参考本章前面的部分。
循环神经网络(RNNs)
RNNs 是神经网络的一种特殊情况,已知在记住信息方面非常高效,因为隐藏状态是以分布式方式存储的,因此它可以存储更多关于经验的信息。这些网络还应用非线性函数来更新隐藏状态。以下图表描述了 RNNs 中隐藏状态是如何连接的:

在大多数现实世界的例子中,输入和输出并不是相互独立的。例如,如果我们必须预测下一个单词,那么了解它之前的单词对我们来说很重要。正如其名所示,“循环”神经网络一次又一次地执行相同的任务,其中一次执行的输入是前一次执行的输出。通常,RNNs 只回溯过去的一步或几步,而不是总是通过所有迭代。以下图表描述了 RNNs 的工作原理;它显示了 RNNs 如何在迭代中展开:

在上一个例子中,要求预测下一个单词,如果输入有五个单词,那么 RNN 展开到五层。
受限玻尔兹曼机(RBMs)
RBMs 的出现是为了解决训练 RNNs 的困难。受限循环模型的出现简化了问题背景,并且还应用了学习算法来解决问题。Hopfield 神经网络是解决之前描述问题的受限模型的一个例子。
作为第一步,玻尔兹曼机出现了。这些模型是具有随机元素的 Hopfield 神经网络的特例。在这种情况下,神经元分为两类:一类产生可见状态,另一类产生隐藏状态。这也类似于隐藏马尔可夫模型。RBM 是玻尔兹曼机的特例,主要区别在于同一层神经元之间没有连接。因此,对于一组神经元的给定状态,另一组神经元的状态是独立的。以下图展示了典型的 RBN 结构和之前的定义:

进一步从这个定义进行深入解释,一些神经元的可见状态是可观察的,还有一些神经元的隐藏状态是不可见的或不能直接看到。基于可用的可见状态,对隐藏状态做出一些概率推断,这就是训练模型形成的方式。
在 RBM 中,连接是受限的,这反过来又简化了推理和学习。通常只需一步就能达到一个平衡状态,其中可见状态被固定。以下公式显示了在提供可见状态信息的情况下,如何计算隐藏状态的概率:

深度玻尔兹曼机 (DBMs)
DBMs 是具有许多缺失连接的传统玻尔兹曼机的特例,并且与顺序随机更新不同,允许并行更新以确保模型效率。
DBMs 限制了隐藏变量之间的连接,主要使用未标记数据来训练模型。标记数据用于微调模型。以下图展示了三层 DBM 的一般结构:

自动编码器
在我们了解自动编码器之前,让我们先了解自联想器(AA)。AA 的目标是以尽可能高的精度接收输入。
AA(自动编码器)的目的是尽可能精确地将输出作为输入图像。AA 分为两大类:一类是生成 AA,另一类是合成 AA。上一节中提到的 RBMs 属于生成 AA,而自动编码器则是合成 AA。
自动编码器是一种具有单个开放层的神经网络。应用反向传播和无监督学习技术,自动编码器从假设目标值等于输入值开始,y = x。以下图展示了一个学习函数h[W,b] (x) ≈ x的自动编码器:

中间层是开放的,如图中所示,为了获得最佳输出,这个层的神经元数量必须少于输入层的神经元数量。这个模型的目标是学习一个近似于恒等函数的函数,使得层 L[3]的值等于层 L[1]的值。
数据在通过输入到输出层时被压缩。当将某个像素图像(例如 100 像素,10 X 10 像素)输入到具有 50 个神经元的隐藏层时,网络试图通过保持像素配置不变来压缩图像。这种压缩只有在存在隐藏的互连和其他可以减少输入数据的特征相关性时才可能实现。
自编码器的另一种变体是降噪自编码器(DA)。这种自编码器变体的不同之处在于它具有额外的能力,可以恢复和恢复受损坏输入数据影响的原始状态。
实现 ANN 和深度学习方法
请参考本章提供的源代码来实现本章中涵盖的人工神经网络和其他深度学习方法(源代码路径为.../chapter11/...,位于每个技术文件夹下)。
使用 Mahout
请参考文件夹.../mahout/chapter11/annexample/。
请参考文件夹.../mahout/chapter11/dlexample/。
使用 R
请参考文件夹.../r/chapter11/annexample/。
请参考文件夹.../r/chapter11/dlexample/。
使用 Spark
请参考文件夹.../spark/chapter11/annexample/。
请参考文件夹.../spark/chapter11/dlexample/。
使用 Python(Scikit-learn)
请参考文件夹.../python-scikit-learn/chapter11/annexample/。
请参考文件夹.../python-scikit-learn/chapter11/dlexample/。
使用 Julia
请参考文件夹.../julia/chapter11/annexample/。
请参考文件夹.../julia/chapter11/dlexample/。
摘要
在本章中,我们介绍了生物神经元的模型以及人工神经元如何与其功能相关。你学习了神经网络的核心概念,以及全连接层是如何工作的。我们还探讨了与矩阵乘法结合使用的一些关键激活函数。
第十二章。强化学习
我们在第五章基于决策树的学习中深入探讨了监督学习和无监督学习方法,并介绍了各种算法。在本章中,我们将介绍一种不同于监督学习和无监督学习的新学习技术,称为强化学习(RL)。强化学习是一种特定的机器学习方法,其学习过程由环境的反馈驱动,学习技术是迭代和自适应的。强化学习被认为更接近人类学习。强化学习的主要目标是决策,其核心是马尔可夫决策过程(MDP)。在本章中,我们将介绍一些基本的强化学习方法,如时间差分(TD)、确定性等价、策略梯度、动态规划等。以下图展示了本章将涵盖的不同数据架构范例:

本章将深入探讨以下主题:
-
监督学习、半监督学习和无监督学习的回顾,以及强化学习的背景。
-
理解马尔可夫决策过程(MDP)对于强化学习至关重要。关于这一点,本章将涵盖以下主题:
-
MDP 代表什么,关键属性,状态,奖励,动作和转移(折扣)
-
MDP 的底层过程以及它如何帮助决策过程
-
策略和价值函数(也称为效用,如在奖励组中)以及我们如何对无限序列的奖励进行赋值
-
贝尔曼方程——值迭代和政策迭代
-
-
关于强化学习,我们将涵盖以下内容:
-
在 MDP 中的规划和学习
-
强化学习中的连接规划和功能逼近
-
不同的强化学习方法和对强化学习的不同方法,例如简单的决策理论、时间差分(TD)、动态规划、策略梯度、确定性等价和资格痕迹
-
如 Q-learning、Sarsa 等关键算法
-
强化学习应用
-
强化学习(RL)
让我们回顾一下监督学习、半监督学习和无监督学习,并为强化学习设定背景。在第一章机器学习简介中,我们介绍了监督学习、半监督学习和无监督学习的基本定义。归纳学习是一种推理过程,它使用一个实验的结果来运行下一组实验,并从具体信息中迭代地进化模型。
以下图展示了机器学习的各个子领域。这些子领域是机器学习算法分类的一种方式:

监督学习主要涉及根据已知期望进行操作,在这种情况下,需要从定义的数据中进行分析。在此背景下,输入数据集也被称为标记数据集。属于这一类别的算法专注于建立输入和输出属性之间的关系,并利用这种关系推测性地为新输入数据点生成输出。在前一节中,为分类问题定义的示例也是监督学习的一个例子。标记数据有助于构建可靠的模型,通常成本高昂且有限。以下图表展示了监督学习的工作流程:

因此,这是一个函数逼近,给定 x 和 y 对,我们的目标是找到将新的 x 映射到适当的 y 的函数 f:
y = f(x)
在一些学习问题中,我们并没有特定的目标来解决;这种学习被称为无监督分析或学习。在这种情况下,目标是解析数据中的结构,而不是在数据的输入和输出属性之间建立映射,实际上,输出属性并未定义。这些学习算法由于这个原因在无标记数据集上操作。

因此,给定一系列 x,这里的目的是定义一个函数 f,它可以对一组 x 提供简洁的描述。因此,这被称为聚类:
f(x)
半监督学习涉及使用标记和无标记数据来学习更好的模型。对于无标记数据,必须存在适当的假设,因为任何错误的假设都可能使模型无效。半监督学习从人类的学习方式中汲取灵感。
强化学习的背景
强化学习关注的是最大化结果带来的奖励。例如,在教导幼儿新习惯时,每次幼儿遵循指示就给予奖励非常有效。事实上,他们发现哪些行为有助于他们获得奖励。这正是强化学习所做的事情,它也被称为信用评估学习。
强化学习最重要的地方在于,模型还需要负责做出决策,而这些决策会收到周期性的奖励。在这种情况下,与监督学习不同,结果不是立即的,可能需要执行一系列步骤才能看到最终结果。理想情况下,算法将生成一系列决策,以帮助实现最高的奖励或效用。

这种学习技术的目标是通过对数据和利用进行探索来有效地衡量权衡。例如,当一个人需要从点 A 到点 B 旅行时,会有许多方式,包括空中、水上、路上或步行,考虑这些选项的权衡数据具有很大的价值。另一个重要方面是,奖励的延迟意味着什么?此外,它会如何影响学习?例如,在象棋等游戏中,奖励识别的任何延迟都可能改变或影响结果。
因此,表示与监督学习非常相似,区别在于输入不是 x、y 对,而是 x、z 对。目标是找到一个函数 f,给定 x 和 z 识别一个 y。在接下来的章节中,我们将进一步探讨 z 是什么。目标函数的定义方程如下:
y = f(x) 给定 z。
强化学习的一个正式定义如下:
| *"强化学习被定义为通过奖励和惩罚来编程代理的方法,而不需要指定如何完成任务。" | ||
|---|---|---|
| --凯尔宾、利特曼、摩尔,96 |
因此,总的来说,强化学习既不是一种神经网络类型,也不是神经网络的替代品,而是一种正交的机器学习方法,重点在于学习反馈,用于评估学习者的表现,没有标准的行为目标来衡量表现,例如学习骑自行车。
让我们现在看看正式或基本的强化学习模型,并了解动作中的不同元素。作为第一步,让我们了解一些基本术语。

-
代理:代理是一个既是学习者又是决策者的实体,在这种情况下通常是一个智能程序。
-
环境:环境是一个实体,负责在代理执行动作后产生新的情况。它为动作提供奖励或反馈。所以,简而言之,环境是除了代理之外的一切。
-
状态:状态是动作使实体所处的情形。
-
动作:动作是代理执行的一步,导致状态的变化。
-
政策:政策是在特定时间点代理行为的定义。它阐述了状态和动作之间的映射,通常是一个简单的业务规则或函数。
-
奖励:奖励规定了动作的短期利益,有助于达到目标。
-
价值:在强化学习中还有一个重要的元素,那就是价值函数。虽然奖励函数是关于动作的短期或即时利益,但价值函数是关于长期的好处。这个价值是代理从世界开始时预期获得的奖励的累积。
强化学习的例子
理解强化学习的最简单方法之一是看看它的实际和现实世界应用。在本节中,我们将列出并理解其中的一些。
-
棋类游戏:在棋类游戏中,玩家进行一步棋;这一步棋是由一个经过信息选择的动作驱动的,该动作伴随着对手玩家的反制动作。玩家的下一步动作取决于对手采取了哪些动作。
-
电梯调度:让我们以一栋有许多楼层和许多电梯的建筑为例。这里的关键优化需求是选择哪个电梯应该被派往哪个楼层,这被归类为一个控制问题。这里的输入是一组楼层上(电梯内外)按下的按钮、电梯的位置和一组楼层。在这种情况下,奖励是最少等待时间,即想要使用电梯的人的等待时间。在这里,系统通过在建筑模拟中的学习,再次学习如何控制电梯;通过从过去动作的价值估计中学习。
-
网络数据包路由:这是一个为动态变化的网络定义路由策略的案例。Q 学习技术(在本章稍后部分将简要介绍)用于确定数据包应该路由到哪个相邻节点。在这种情况下,每个节点都有一个队列,并且一次只发送一个数据包。
-
移动机器人行为:移动机器人需要根据它过去能够多快找到充电点的速度来决定是前往充电点还是下一个垃圾点。
评估反馈
强化学习与其他学习类型的关键区别之一在于,它使用信息来评估特定动作的影响,而不是盲目地指示需要采取哪些动作。一方面,评估反馈表明采取的动作有多好,另一方面,指导反馈则表明正确的动作是什么,无论动作是否被采取。尽管这两种机制在方式上有所不同,但在某些情况下,会同时采用一些技术。在本节中,我们将探讨一些评估反馈方法,这将为本章的其余部分奠定基础。
n 臂老丨虎丨机问题
这个问题的正式定义,与原始的赌徒类比如下:
注意
根据维基百科,n 臂老丨虎丨机问题是一个“赌徒”决定玩哪个机器、游戏的顺序和持续时间的问题,然后他开始玩并收集奖励,以最大化总奖励的问题。
让我们考虑一个有数千个动作可以采取的情况。每个动作都会获得一个奖励,我们的目标是确保我们以这种方式采取动作,使得在一段时间内奖励的总和最大化。选择特定动作的行为被称为 play。
一个解释 n-Armed Bandit 问题类比案例的例子是一位医生需要从一系列选项中选择来治疗严重疾病,其中患者的生存成为选择动作(在这种情况下,治疗)的奖励。在这个问题中,每个动作都与选择动作的预期奖励相关联;这被称为 价值。如果我们知道每个动作的价值,解决 n-Armed Bandit 问题就很容易,我们将选择那些具有最大价值的动作。只有可能的是,我们有价值的估计,而不是实际的价值。
现在我们来看一下探索和利用之间的区别。
假设我们保持对价值的估计,如果我们选择具有最大价值的动作(这种动作被称为贪婪动作),这种情况被称为利用,因为我们正在最好地使用手头的当前知识。此外,所有选择任何非贪婪动作的情况,更多的是探索,这有助于提高非贪婪动作的估计。虽然利用有助于最大化预期奖励,但探索有助于在长期内增加总奖励。在探索的情况下,短期奖励较低,而长期总奖励可能会更好。对于每个动作,可以选择探索或利用的方法,而有效的方法是这两种技术的良好平衡。
因此,有了这个,我们现在将探讨一些最佳估计动作值和选择最适合动作的技术。
动作值方法
如果动作 a 的值是 Q(a),那么第 t 次游戏的评估值是 Q[t](a) I*,即在选择了该动作的情况下给出的奖励的平均值,以下方程表示这一点:
Q[t](a) = (r1+r2+ … r[ka] ) / ka,其中 r 是奖励,ka 是动作 a 被选择的次数。这是估计动作值的一种方法,但不一定是最好的方法。让我们接受这一点,现在来看看选择动作的方法。
最简单的动作选择规则是选择一个动作或动作之一,即 a,它具有最高的估计动作值。所以,对于给定的游戏 t,选择贪婪动作 a 可以表示如下:
Qt = max[a] Qt
这种方法根据定义利用了当前的知识,同时稍微关注一下动作是否是一个更好的选择。作为这种方法的替代,我们可以选择大多数时候采取贪婪策略,偶尔选择一个与价值估计无关的动作。以概率 ԑ,这种方法被称为 ԑ-贪婪方法。
强化比较方法
在大多数选择方法中,我们看到具有最大奖励的动作比具有较小奖励的动作更有可能被选中。重要的问题是如何判断奖励是大还是小。我们始终需要有一个参考数字来判断奖励是高值还是低值。这个参考值被称为参考奖励。首先,参考奖励可以是之前收到的奖励的平均值。使用这个想法的学习方法被称为比较强化方法。这些方法比 actor-value 方法更有效,是我们将在后续章节中讨论的 actor-critic 方法的基础。
强化学习问题 – 世界网格示例
我们将尝试使用一个著名的例子来理解强化学习问题:网格世界。这个特定的网格世界是一个 3X4 网格,如下面的截图所示,是对世界复杂性的近似:

这个例子假设世界是一种游戏,你从一个称为起始状态的状态(从位置 1,1)开始。让我们假设可以采取四种动作,包括向左、向右、向上和向下移动。目标是确保使用这些动作,我们能够移动到表示在位置 4,3 的目标。我们需要避免像下一张图片中显示的那样在位置 4,2 显示的红框。
-
起始状态:位置 (1,1) --> 世界从这里开始。
-
成功状态:位置 (4,3) --> 世界在这里以成功状态结束。
-
失败状态:位置 (4,2) --> 世界在这里以失败状态结束。
-
当世界结束时,我们需要重新开始。
-
墙壁:在位置 (2,2) 显示了一个障碍物或墙壁。这个位置无法通过:
![强化学习问题 – 世界网格示例]()
-
要从起点 (1,1) 达到目标 (4,3),可以采取以下方向的步骤:
![强化学习问题 – 世界网格示例]()
-
每个方向的每一步都会将你从一个位置移动到另一个位置(这里的“位置”只是状态)。例如,从位置 (1,1) 向上移动将带你到位置 (1,2),依此类推。
-
从一个给定的位置不能采取所有方向。让我们考虑以下截图中的示例。从位置 (3,2),只能采取上、下和右。左移动会撞到墙壁,因此不能采取。话虽如此,只有上和下的移动是有意义的,因为右会将你移动到危险位置,导致无法达到目标。
![强化学习问题 – 世界网格示例]()
-
类似地,网格边界上的任何位置都将有限制,例如,位置 (1,3) 允许 向右 和 向下 移动,其他任何移动都不会改变位置。
![强化学习问题 – 世界网格示例]()
-
现在我们来看从 起点 (1,1) 到 目标 (4,3) 的最短路径。有两种解决方案:
-
解决方案 1:向右 --> 向右 --> 向上 --> 向上 --> 向右 (5 步)
![强化学习问题 – 世界网格示例]()
-
解决方案 2:向上 --> 向上 --> 向右 --> 向右 --> 向右 (5 步)
![强化学习问题 – 世界网格示例]()
-
-
在现实世界中,并非所有动作都能按预期执行。存在一个可靠性因素,它会影响性能,或者说,存在不确定性。如果我们对示例稍作修改,并说每次从一位置移动到另一位置的动作,移动正确的概率是 0.8。这意味着有 80% 的可能性移动会按预期执行。在这种情况下,如果我们想测量解决方案 1 (R-->R-->U-->U-->R) 成功的概率:
行为发生的预期概率 + 行为未按预期发生的概率
= 0.8 x 0.8 x 0.8 x 0.8 x 0.8 + 0.1 x 0.1 x 0.1 x 0.1 x 0.8
= 0.32768 + 0.00008 = 0.32776
-
如我们所见,不确定性的元素确实会改变结果。在下一节中,我们将讨论捕捉这些不确定性的决策过程框架。
马尔可夫决策过程 (MDP)
马尔可夫决策过程是做出决策的一个基本框架或过程,我们将在后续的强化学习章节中多次提到它。
马尔可夫属性是马尔可夫决策过程的核心,它指出重要的是当前或当前状态,并且情况是稳定的,这意味着规则不会改变。
MDP 尝试捕捉我们在前面章节中讨论的世界,它具有以下特征:

-
状态:在前面的例子中,每个网格位置代表一个状态
-
模型(转移函数):转移函数包括三个属性:给定状态、动作和目标状态。它描述了在当前状态 s 和动作 a 下,结束状态 s 的概率:
T (s, a,s') ~ P(s'/s, a)
-
动作:A(s),A 在前面的例子中,A (1, 2) = 向上 在 向上、向上 向右、向右、向右 解决方案中
-
奖励:R(s),R(s,a),R(s,a,s1) 奖励告诉我们进入状态的有用性
R(s):进入状态 s 的奖励
R(s, a):打开状态 s 的动作 a 的奖励
R(s, a,s1):在状态 s 下执行动作 a 打开状态 s1 的奖励
-
状态、动作、模型和奖励构成了 MDP 的问题陈述
-
策略:它是对问题的解决方案;它说明了在给定状态下应该采取什么行动:
π(s) --> a
基本强化学习模型 – 代理-环境接口
正如我们所发现的,强化学习问题是一种直接从交互中学习以实现目标的方法。代理是学习者或决策者,它与环境互动,而这个环境中的所有外部因素都会产生奖励。它与交互的事物,包括代理之外的所有事物,被称为环境。环境的完整规范定义为任务——强化学习问题的单个实例。
以下模型描述了代理-环境接口:

在这里,环境模型意味着一个代理使用任何东西来预测给定动作的环境行为的上下文。这个环境模型根据动作和当前状态产生对下一个状态和奖励的预测。如果模型是随机的,则可能存在多个下一个状态奖励。再次强调,这些模型可以是分布式的或基于样本的。分布式模型识别所有潜在的概率,而基于样本的模型在给定样本的情况下产生概率。
最后,强化学习的目标可以定义为以下内容:
-
在一个每个动作都会导致新情况出现的环境中,强化学习(RL)关注的是如何采取行动。以下是一些可能的动作:
-
定义一个策略,将动作和结果情况映射
-
确定导致最高奖励的策略
-
强化学习的步骤如下:
-
代理观察输入状态。
-
通过应用策略,这是一个决策函数,可以确定一个动作。
-
执行动作导致状态变化。
-
由于这个动作,代理从环境中获得了一个显著的奖励。
-
根据状态的变化记录奖励的详细信息。
延迟奖励
区分强化学习与监督学习的一个方面是奖励。在本节中,我们将探讨延迟奖励的含义。正如我们所知,每个导致特定状态变化的动作都会产生奖励。在某些情况下,这种奖励的实现并不是立即的。让我们看看一个棋盘游戏的例子。假设棋盘游戏需要 65 步才能结束,只有在第 65 步或移动结束时,我们才能知道我们是否赢得了游戏或输了。哪一步或移动导致了成功或失败在这里是复杂的。因此,奖励直到游戏结束或动作序列结束时才可知。技术上,我们正在寻找识别哪个动作序列导致了所看到的奖励。这个过程被称为时间信用分配。
现在,在这个实现最终奖励(成功+1 或失败-1)的旅程中,每一步或移动或行动都会获得奖励。假设网格世界问题解决方案 1 中的每一步都获得奖励-0.4。导致成功或失败的总奖励将决定长期奖励。
策略
最佳策略是一种最大化预期长期奖励的策略或解决方案,可以用以下公式表示:

现在,让我们衡量一个特定状态(s)的效用,这取决于策略(π):

进入状态(s)的奖励(这是一种即时利益)不等于该状态的效用(这是进入该状态的长远利益)。
现在,我们可以使用状态价值的效用来定义最佳策略:

现在,如果我们必须定义处于状态(s)的效用,它等于进入该状态的奖励,减去从该点开始获得的奖励:

这被称为贝尔曼方程。
V 是策略的价值函数,以下是将最优策略的价值与该状态的最佳预期回报相等的贝尔曼最优方程:

强化学习 – 关键特性
强化学习不是一系列技术,而是一系列问题,它关注的是任务本身,而不是如何处理任务。
强化学习被视为一种工具,机器可以通过更多基于试错法的奖励和惩罚来学习。
强化学习采用评估反馈。评估反馈衡量采取的行动的有效性,而不是衡量该行动是否为最佳或最差。(注意,监督学习更侧重于指导性学习,并确定行动的正确性,而不考虑执行的行动。)
强化学习中的任务更多的是相关任务。关联任务依赖于情况,其中识别并执行最适合给定情况的动作。非关联任务是指独立于特定情况的任务,当任务处于静止状态时,学习者找到最佳动作。
强化学习解决方案方法
在本节中,我们将详细讨论解决强化学习问题的一些方法。特别是动态规划(DP)、蒙特卡洛方法和时序差分(TD)学习。这些方法也解决了延迟奖励的问题。
动态规划(DP)
动态规划(DP)是一组算法,用于在给定环境模型(如马尔可夫决策过程)的情况下计算最优策略。动态规划模型在计算上昂贵,并假设完美模型;因此,它们的采用或效用较低。从概念上讲,DP 是以下章节中使用的许多算法或方法的基础:
-
评估策略:可以通过迭代方式计算策略的价值函数来评估策略。计算策略的价值函数有助于找到更好的策略。
-
改进策略:策略改进是一个使用其价值函数信息计算修订策略的过程。
-
值迭代和策略迭代:策略评估和改进同时推导出值和策略迭代。这些是两种最流行的动态规划方法,用于在完全了解马尔可夫决策过程(MDPs)的情况下计算最优策略和价值函数。
以下算法描述了迭代策略过程:

值迭代结合了坚实的策略改进和过程评估。以下涉及到的步骤:

广义策略迭代(GPI)
GPI 是一种对动态规划(DP)方法进行分类的方法。GPI 涉及两个过程之间的交互——一个围绕近似策略,另一个围绕近似价值。
在第一种情况下,过程直接选择策略并执行策略评估以确定与策略相关联的真实或确切的价值函数。另一种过程以价值函数作为输入,并使用它来改变策略,以便改进策略,即其总奖励。如果你观察,每个过程都改变了另一个过程的基础,并且它们协同工作以找到导致最优策略和价值函数的联合解决方案。
蒙特卡洛方法
在强化学习中,蒙特卡洛方法通过经验样本学习策略和价值。由于以下原因,蒙特卡洛方法在动态规划方法之上具有额外的优势:
-
直接从与环境交互中学习最优行为,而不需要任何模拟模型动态的模型。
-
这些方法可以用于模拟数据或样本模型;这一特性在现实世界的应用中变得至关重要。
-
使用蒙特卡洛方法,我们可以轻松地关注更小的状态集,并且可以在不必要进入完整状态集的情况下探索感兴趣的区域。
-
蒙特卡洛方法对于任何违反马尔可夫属性的情况影响最小,因为价值的估计不是使用任何后续状态来更新的。这也意味着它们不需要自举。
蒙特卡洛方法是由广义策略迭代(GPI)方法设计的。这些方法提供了一种评估策略的替代方法。对于每个状态,而不是独立计算价值,取从该状态开始返回的平均值,这可以很好地近似该状态的价值。重点是应用动作值函数来改进策略,因为这不需要环境转换的变化。蒙特卡洛方法混合了策略评估和改进方法,可以逐步实现。
探索多少是足够的?这是蒙特卡洛方法中需要回答的关键问题。仅仅根据价值选择最佳动作是不够的;了解这些动作中有多少有助于结束奖励也很重要。
在这种情况下可以使用两种方法——在策略或离策略方法。在在策略方法中,智能体负责使用探索技术找到最优策略;而在离策略方法中,智能体的探索不是核心,但与之学习一个确定的最优策略,这个策略不必与遵循的策略相关。简而言之,离策略学习方法都是关于通过行为学习行为。
时序差分(TD)学习
TD 学习是强化学习中的独特技术之一。时序差分学习是蒙特卡洛方法和动态规划方法的结合。在强化学习中讨论最多的技术是时序差分(TD)、动态规划(DP)和蒙特卡洛方法之间的关系:
-
评估一个包含估计给定策略π的价值函数 Vπ的策略。
-
选择一个最优策略。对于策略选择,所有 DP、TD 和蒙特卡洛方法都使用广义策略迭代(GPI)的变体。因此,这三者之间的区别不过是 GPI 中的这些变体。
TD 方法遵循自举技术来得出估计;它们会回退到后续状态和类似的估计。
现在我们来看看 TD 方法相对于 DP 和蒙特卡洛方法的优点。我们将简要介绍,而不深入复杂性。以下是一些关键好处:
-
TD 方法不需要环境模型以及下一状态和奖励的概率分布
-
TD 方法可以轻松优雅地以在线和增量方式运行
Sarsa - 在策略 TD
让我们看看如何使用 TD 方法来解决控制问题。我们将继续使用 GPI 技术,但现在结合 TD 方法进行评估和预测。虽然我们需要在探索和利用选项之间保持平衡,但我们有选择在策略或离策略学习方法中的选项。我们将坚持使用在策略方法:
-
学习与状态值函数相关的动作值函数。我们将为策略 π 定义 Q^π(s, a):
![Sarsa - on-Policy TD]()
-
学习从一个状态-动作对转换到另一个状态-动作对的值。这通过以下方式迭代计算:
![Sarsa - on-Policy TD]()
这被定义为 Sarsa 预测方法,并且是 on-policy 的,因为智能体使用识别的策略来完成这个任务。
Sarsa 算法表述如下:

Q-Learning – off-Policy TD
使用离策略学习方法的 Q-Learning 技术是 TD 的突破性策略之一。这种称为 Q-learning 的控制算法(Watkins,1989)以简单形式定义如下:

我们可以看到最优动作值函数 Q* 是直接使用学习到的动作值函数 Q 近似,而不考虑它遵循的策略。这使得它成为一个 off-policy 方法。
由于策略值函数被使用和更新,因此对策略仍有一定的影响。此外,对所有对的勤奋标记标志着收敛。
基于这种理解,Q-learning 算法可以描述如下:

Actor-critic methods (on-policy)
Actor-critic 方法是时间差分学习方法,它使用单独的记忆结构确保策略和值的独立性。在这种情况下,策略结构被称为 actor,值结构被称为 critic。名称 critic 来自于它批评策略的价值。由于这个 critic 总是批评策略的价值,它也被称为 TD 错误。以下截图显示了 actor-critic 方法流程:

R Learning (Off-policy)
R-learning 是一种高级强化学习技术,用于没有折扣且有确定和有限回报的情况。算法如下:

实现强化学习算法
请参考本章提供的源代码来实现强化学习算法。(源代码路径 .../chapter12/... 在每个技术文件夹下。)
使用 Mahout
请参考文件夹 .../mahout/chapter12/rlexample/。
使用 R
请参考文件夹 .../r/chapter12/rlexample/。
使用 Spark
请参考文件夹 .../spark/chapter12/rlexample/。
使用 Python (Scikit-learn)
请参考文件夹 .../python-scikit-learn/chapter12/rlexample/。
使用 Julia
请参考文件夹 .../julia/chapter12/rlexample/。
摘要
在本章中,我们探索了一种名为强化学习的新学习技术。我们看到了它与传统的监督学习和无监督学习技术的不同之处。强化学习的目标是决策,其核心是马尔可夫决策过程(MDP)。我们探讨了 MDP 的要素,并通过一个例子来了解它。然后,我们介绍了强化学习的某些基本技术,包括策略学习和非策略学习,其中一些是间接和直接的学习方法。我们涵盖了动态规划(DP)方法、蒙特卡洛方法,以及一些关键的时序差分(TD)方法,如 Q 学习、Sarsa、R 学习和演员-评论家方法。最后,我们使用为本书确定的标准技术栈对这些算法进行了一些实际应用。在下一章中,我们将介绍集成学习方法。
第十三章。集成学习
本章是所有从第五章基于决策树的学习中学到的学习方法的总结章节。将本章作为学习方法的结尾章节是恰当的,因为这种学习方法解释了如何有效地将这些方法结合起来以最大化学习者的成果。集成方法在监督和无监督解决方案中具有有效、强大的技术,以实现高精度。不同的模型在选定的业务案例中效率高且表现良好。找到一种将竞争模型组合成委员会的方法很重要,在这方面已经进行了大量研究,并取得了相当程度的成功。此外,由于不同的观点产生了大量数据,关键是要巩固不同的概念以进行智能决策。推荐系统和基于流的文本挖掘应用广泛使用集成方法。
在监督学习和无监督学习小组中已经进行了许多独立研究。观察到的共同主题是,当许多混合模型结合在一起时,它们增强了弱模型,并带来了整体更好的性能。本章的一个重要目标是对不同的集成技术进行了系统比较,这些技术结合了监督和无监督技术,并介绍了一种合并结果的方法。

本章涵盖了以下主题:
-
集成方法学习的概述——群体智慧的概念和关键属性。
-
核心集成方法分类、现实世界示例和集成学习应用
-
集成方法类别和多种代表性方法:
-
监督集成方法概述和详细介绍了诸如袋装、提升、梯度提升方法和随机决策树和随机森林等概念。
-
无监督集成方法概述了包括聚类集成在内的生成、直接和间接方法。
-
-
使用 Apache Mahout、R、Julia、Python(scikit-learn)和 Apache Spark 进行动手实现练习
集成学习方法
集成,一般而言,意味着一组通常被视为整体而不是单个价值的事物。集成遵循分而治之的方法,用于提高性能。

我们将从介绍著名的群体智慧概念开始,来理解具体的算法。
群体智慧
当以正确的方式汇总时,不完美的判断会导致集体智慧,从而产生更优越的结果。群体智慧就是关于这种集体智慧。
通常,群体一词通常与不合理性和普遍观念有关,即存在某种影响,在暴民和教派的情况下影响群体的行为。然而,事实并非总是如此负面,并且在与智力汇总合作时效果很好。群体智慧的关键概念是,一群人做出的决策总是比个人做出的决策更稳健和准确。机器学习的集成学习方法有效地利用了这个想法,以产生效率和准确的结果。
“群体智慧”这个术语是由高尔顿在 1906 年提出的。他参加了一个农民集市,那里有一个比赛,猜测被宰杀和加工的牛的重量。最接近猜测的获胜者从 800 名参赛者中赢得了奖品。他选择收集所有响应并进行分析。当他计算猜测的平均值时,他惊讶地发现它们非常接近实际值。这个集体猜测不仅比获奖者更准确,而且与牲畜专家的猜测相比也证明是最好的。思想的民主是明显的赢家。对于这样一个有用的输出,重要的是每个参赛者都有他/她的强有力信息来源。参赛者提供的独立猜测不应受他/她邻居猜测的影响,而且,还有一个无错误的机制来整合整个群体的猜测。所以简而言之,这不是一个容易的过程。另一个重要的方面是,这些猜测比任何个别专家的猜测都要优越。
一些基本的日常例子包括:
-
Google 搜索结果通常将最受欢迎的页面列在顶部
-
在像“谁想成为亿万富翁”这样的游戏中,观众投票用于回答参赛者不知道的问题。通常,大多数投票的答案是正确的。
群体智慧方法的结果并不保证。以下是使用此方法获得最佳结果的基本标准:
-
聚合:需要有一种万无一失的方法将个别响应整合成集体响应或判断。没有这个,集体观点或响应的核心目的就会落空。
-
独立性:在人群中,需要对控制来自一个实体对其他人的响应进行纪律约束。任何影响都会扭曲响应,从而影响准确性。
-
去中心化:个别响应有其来源,并依赖于有限的知识。
-
意见多样性:重要的是每个人都有一个独立的响应;响应的异常性仍然是可接受的。
术语“ensemble”意味着分组。要构建集成分类器,我们首先需要从训练数据中构建一组分类器,汇总这些分类器做出的预测,并使用这些数据预测新记录的类别标签。
下面的图解展示了这个过程:

技术上,核心构建块包括训练集、诱导器和集成生成器。诱导器负责为每个样本训练数据集定义分类器。集成生成器创建分类器以及一个组合器或聚合器,该组合器或聚合器整合组合器之间的响应。有了这些构建块及其之间的关系,我们将使用以下属性来分类集成方法。下一节将介绍这些方法:
-
组合器的使用:这个属性定义了集成生成器和组合器之间的关系
-
分类器之间的依赖性:这个属性定义了分类器相互依赖的程度
-
生成多样性:这个属性定义了确保组合器之间多样性的程序
-
集成的大小:这个属性表示集成中使用的分类器数量
-
交叉诱导器:这个属性定义了分类器如何利用诱导器。有些情况下,分类器被构建成与特定的诱导器集一起工作
总结来说,构建模型集成首先涉及构建专家并让他们提供响应/投票。预期的收益是预测性能的提高,并产生一个单一的全球结构。尽管如此,产生的任何中间结果可能最终难以分析。
让我们全面地看看聚合/组合分类器的性能如何表现得更好。
让我们考虑三个错误率为 0.35(ε)或准确率为 0.65 的分类器。对于每个分类器,分类器预测错误的概率是 35%。

这里给出的是真值表,表示错误率为 0.35(35%)和准确率为 0.65(65%):

在三个分类器组合后,通过在组合器之间使用多数投票过程来预测测试实例的类别标签,计算集成分类器犯错的概率。这在下述公式中给出。

此外,准确率为 71.83%。很明显,当在分类器之间汇总时,错误率会降低。现在,如果我们扩展到 25 个分类器,根据错误率(6%)的计算,准确率会上升到 94%。

因此,集成工作得很好,因为它们提供了更大的视角。
在前一个章节中,我们已经讨论了群体智慧工作的标准。现在,让我们看看我们之前提到的 25 个基分类器的情况,看看集成分类器的准确率如何随着基分类器不同错误率的变化而变化。

小贴士
当基分类器的错误率超过 0.5 时,集成分类器的性能会下降,并且比基分类器表现差得多。
在下一节中,我们将介绍一些应用集成方法的现实世界用例。
关键用例
本节详细讨论了集成学习方法在现实世界中的关键应用。
推荐系统
推荐系统的目的是向可能感兴趣的用户社区产生有意义的推荐。一些例子包括与决策过程相关的建议,例如在亚马逊上阅读哪些书籍,在 Netflix 上观看哪些电影,或在新闻网站上阅读哪些新闻。业务领域,或业务属性的设计的上下文和特征是推荐系统设计的主要输入。用户为每部电影提供的评分(在 1-5 的范围内)是一个重要的输入,因为它记录了用户与系统的互动程度。此外,用户的详细信息(如人口统计和其他个人或配置文件属性)也被推荐系统用于识别项目与潜在用户之间的潜在匹配。
以下截图是 Netflix 上推荐系统结果的示例:

异常检测
异常检测或离群值检测是集成学习方法最流行的用例或应用之一。这全部关于在数据中寻找异常或不寻常的模式。识别异常很重要,因为它可能导致采取任何决定性行动。一些著名的例子包括(许多其他例子中):
-
信用卡欺诈检测
-
医疗保健中的罕见疾病检测
-
飞机发动机中的异常检测
让我们现在扩展关于飞机发动机异常检测的例子。以下是一些用于验证飞机发动机是否异常的特征:
-
产生的热量(x[1])
-
振动的强度 (x[2])
-
在数据集 = x[(1)],x[(2)] … x[(m)] 标记的情况下,以下是对异常和非异常案例的描述:
![异常检测]()
迁移学习
传统上,所有机器学习算法都假设每个新的学习问题都需要从头开始学习。这个假设是没有任何先前的学习会被利用。在学习问题的领域相关的情况下,将有一些从过去可以获取并使用的经验。一些常见的例子包括:
-
法语的知识可以帮助学生学习西班牙语
-
数学知识可以帮助学生学习物理
-
驾驶汽车的知识可以帮助驾驶员学习驾驶卡车
在机器学习领域,这指的是从相关领域的新任务中识别和应用先前任务积累的知识。这里的关键是识别领域之间的共性。强化学习和分类与回归问题应用迁移学习。迁移学习的过程流程如图所示:

流式挖掘或分类
随着技术进步和社交媒体的兴起,流式数据挖掘已成为众多应用的关键需求。
与传统学习的主要区别在于,随着流数据的到来,训练和测试数据集以分布式方式演变。预测的目标现在变得稍微复杂一些,因为随着时间戳的变化,概率也在不断变化,这使得应用集成学习方法成为理想的环境。下一个图表显示了 P(y) 如何随时间戳和 P(x) 以及 P (y|x) 的变化而变化:

使用集成学习方法,单个模型产生的方差减少,随着分布的演变,预测或结果更加准确或鲁棒。
集成方法
如前几节所述,集成方法现在已被证明是提高监督学习、半监督学习和无监督学习解决方案的准确性和鲁棒性的强大方法。此外,我们也看到了随着不同来源开始持续产生大量数据,决策动态正变得越来越复杂。有效的整合现在是成功和智能决策的关键。
监督学习和无监督集成方法遵循相同的原理,涉及结合多样化的基础模型以增强弱模型。在接下来的章节中,我们将独立且详细地探讨监督、半监督和无监督技术。
下面的模型描述了各种学习类别以及涵盖结合学习和共识方法的各种算法:

来源:关于集成方法的力量:监督学习和无监督方法达成一致(it.engineering.illinois.edu/ews/)
在我们深入探讨每种集成技术之前,让我们了解通过学习结合与通过共识结合之间的区别:
| 优点 | 缺点 | |
|---|---|---|
| 通过学习结合 |
-
使用标记数据作为反馈机制
-
有潜力提高准确性
|
-
仅适用于标记数据
-
存在过拟合的风险
|
| 通过共识结合 |
|---|
-
不需要标记数据
-
具有提高性能的潜力
|
-
标签数据的宝贵反馈信息缺失
-
基于共识是好事的假设
|
监督集成方法
在监督学习方法的情况下,输入始终是标记数据。通过学习组合的方法包括 Boosting 堆叠泛化和规则集成技术。通过共识组合的方法包括 Bagging、随机森林和随机决策树技术。以下展示了通过学习组合的过程流程,随后是另一个通过共识组合的模型:


监督集成方法的问题陈述如下:
-
输入数据集是 D={x[1], x[2], …, x[n]},相应的标签是 L={l[1],l[2],…,l[n]}
-
集成方法现在生成了一组分类器 C = {f[1],f[2],…,f[k]}
-
最后,分类器的组合 f* 通过以下公式最小化泛化误差:f(x)= ω[1]f[1](x)+ ω[2]f[2](x)+ ….+ ω[k]f[k](x)*
Boosting
Boosting 是一种相当直接的方法,通过应用多个模型生成的所有输出的加权平均来计算输出。它是一个弱学习者的框架。通过使用强大的加权公式,可以调整应用的权重,从而得出一个强大的预测模型,该模型解决了这些方法的缺陷,并且适用于更广泛的输入数据,使用不同的狭窄调整模型。
Boosting 在解决二元分类问题方面取得了成功。这项技术是由 Freund 和 Scaphire 在 20 世纪 90 年代通过著名的 AdaBoost 算法引入的。以下是该框架的一些关键特性:
-
它结合了多个基分类器,与基分类器相比,表现出改进的性能
-
弱学习器是按顺序训练的
-
训练每个基分类器所使用的数据基于先前分类器的性能
-
每个分类器投票并贡献于结果
-
该框架工作并使用在线算法策略
-
对于每一次迭代,权重都会重新计算或重新分配,其中错误的分类器将开始减少其权重
-
正确的分类器获得更多的权重,而错误的分类器则减少权重
-
Boosting 方法,虽然最初是为解决分类问题而设计的,但也被扩展到处理回归问题
Boosting 算法如下所述:

-
训练一组弱假设:h[1], …, h[T].
-
将假设 H 作为 T 个较弱假设的加权多数投票组合。
![Boosting]()
-
每次迭代都专注于错误分类,并重新计算权重 D[t](i)。
AdaBoost
AdaBoost 是一个线性分类器,它将更弱的功能h[t](x)作为线性组合构建了一个更强的分类器H(x)。

下面的图示展示了提升框架是如何工作的:
-
所有数据点都被标记为两个类别+1和-1,权重相等—1。
![AdaBoost]()
-
应用一个p (错误)并按以下方式对数据点进行分类:
![AdaBoost]()
-
重新计算权重。
![AdaBoost]()
-
让弱分类器再次参与一个新的问题集。
![AdaBoost]()
![AdaBoost]()
-
通过迭代地使用弱分类器构建了一个强大的非线性分类器。
![AdaBoost]()
Bagging
Bagging 也称为自助聚合。这种集成学习方法结合了共识方法。该技术中有三个重要步骤:
-
构建包含大约 63.2%原始记录的自助样本。
-
使用每个自助样本对训练数据进行分类。
-
使用多数投票并识别集成分类器的类别标签。
通过生成基于原始数据集的额外数据生成,结合相同大小的数据集的重复组合,这个过程减少了预测方差。随着方差的减少,模型的准确性增加,而不是通过增加数据集的大小。以下为 Bagging 算法:

根据前面的算法步骤,这里展示了 Bagging 算法的流程和过程示例:
-
训练步骤:对于每个迭代t, t=1,…T,从训练集中创建N个样本(这个过程称为自助抽样),选择一个基模型(例如,决策树、神经网络等),并使用这些样本进行训练。
-
测试步骤:对于每个测试周期,通过结合所有T个训练模型的结果进行预测。在分类问题中,应用多数投票方法,而在回归中,则应用平均方法。
一些错误计算如下:

在以下条件下,Bagging 在过拟合和欠拟合情况下都有效:
-
对于欠拟合:高偏差和低方差情况
-
对于过拟合:小偏差和大方差情况
下面是 Bagging 的一个例子:

Wagging
Wagging是 Bagging 的另一种变体。使用整个数据集来训练每个模型。此外,权重是随机分配的。所以简而言之,Wagging 是带有基于泊松或指数分布的额外权重的 Bagging。以下为 Wagging 算法:

随机森林
随机森林是另一种集成学习方法,它结合了多个决策树。以下图表表示了随机森林集成:

来源:citizennet.com/blog/2012/11/10/random-forests-ensembles-and-performance-metrics/
对于具有 T 个树的随机森林,决策树分类器的训练如下:
-
与标准的 Bagging 技术类似,定义了一个随机替换的 N 个案例样本,以创建大约 62-66%的全面数据集的子集。
-
对于每个节点,执行以下操作:
-
以一种方式选择 m 个预测变量,使得识别的变量给出最佳的分割(二分分割)
-
在下一个节点,选择其他 m 个变量,它们执行相同的操作
-
-
m 的值可以变化
-
对于随机分割选择—m=1
-
对于 Breiman 的袋装器:m=预测变量总数
-
对于随机森林,m 小于预测变量的数量,它可以取三个值:½√m,√m 和 2√m
-
现在,对于随机森林预测的每个新输入,新值会通过所有树运行,并使用平均值、加权平均值或投票多数来获取预测值。
小贴士
在第五章中,我们详细介绍了基于决策树的学习。
梯度提升机(GBM)
GBM 是高度采用的机器学习算法之一。它们用于解决分类和回归问题。GBM 的基础是决策树,它们应用提升技术,其中多个弱算法通过算法组合产生强学习器。它们是随机和梯度提升的,这意味着它们迭代地解决残差。
它们因其可以使用各种损失函数而闻名,可以高度定制。我们已经看到,随机森林集成技术使用简单的平均方法与 GBM 相比,GBM 使用的是实用的集成形成策略。在这个策略中,新模型迭代地添加到集成中,其中每个迭代都训练弱模型以识别下一步。
GBM 灵活且比其他集成学习方法相对更高效。以下表格详细说明了 GBM 算法:

梯度提升回归树(GBRT)与遵循回归技术的 GBM 类似。
无监督集成方法
作为无监督集成学习方法的一部分,基于共识的集成之一是聚类集成。以下图表描述了基于聚类的集成的工作原理:

对于给定的未标记数据集 D={x[1],x[2],…,x[n]}),聚类集成计算一组聚类 C = { C[1],C[2],…,C[k]}),每个聚类将数据映射到一个聚类。形成一个基于共识的统一聚类。以下图表描述了此流程:

实现集成方法
请参考本章节提供的源代码以实现集成学习方法(仅限于监督学习技术)。(源代码路径 .../chapter13/... 位于每个技术文件夹下)。
使用 Mahout
请参考文件夹 .../mahout/chapter13/ensembleexample/。
使用 R
请参考文件夹 .../r/chapter13/ensembleexample/。
使用 Spark
请参考文件夹 .../spark/chapter13/ensembleexample/。
使用 Python (Scikit-learn)
请参考文件夹 .../python (scikit-learn)/chapter13/ensembleexample/。
使用 Julia
请参考文件夹 .../julia/chapter13/ensembleexample/。
摘要
在本章中,我们介绍了机器学习的集成学习方法。我们讨论了“群体智慧”的概念,以及如何在机器学习的背景下应用它,以及如何提高学习者的准确性和性能。具体来说,我们通过一些实际案例研究了某些监督集成学习技术。最后,本章提供了使用 R、Python (scikit-learn)、Julia 和 Spark 机器学习工具以及使用 Mahout 库的推荐引擎的梯度提升算法的源代码示例。
本章涵盖了所有机器学习方法,在接下来的最后一章中,我们将介绍一些机器学习的先进和新兴架构和技术策略。
第十四章:新一代机器学习数据架构
这是我们的最后一章,我们将从我们通常的学习主题中偏离,来涵盖一些机器学习的解决方案方面。这是尝试完成实践者对机器学习解决方案实施方面的看法,涵盖更多关于不同业务案例平台选择的内容。让我们超越 Hadoop、NoSQL 和其他相关解决方案。新范式肯定是一个统一的平台架构,它关注机器学习的所有方面,从数据收集和准备到可视化,重点关注所有关键架构驱动因素,如数据量、来源、吞吐量、延迟、可扩展性、数据质量、可靠性、安全性、自助服务和成本。
以下流程图展示了本章将涵盖的不同数据架构范例:

本章深入探讨了以下主题:
-
传统数据架构是如何实施以及为什么在大数据和分析的当前背景下被认为是可取的简要历史。
-
在机器学习背景下,包括提取、转换和加载(ETL)、存储、处理和报告、分发以及洞察展示的新时代数据架构要求概述。
-
Lambda 架构的介绍,这些架构统一了批处理和实时处理策略,并附带一些示例。
-
Polyglot Persistence 和 Polymorphic 数据库的介绍,这些数据库统一了包括结构化、非结构化和半结构化数据存储的数据存储策略,并集中了跨数据存储的查询方法。以下是如何 Greenplum 数据库支持这些策略以及它如何与 Hadoop 无缝集成的示例。
-
语义数据架构包括本体论演变、目的、用例和技术。
数据架构演变
我们将从了解数据架构传统上是如何遵循的,然后详细说明在大数据背景下现代机器学习或分析平台的需求。
观察一——数据存储始终有目的
传统上,数据架构有明确的目的分隔,OLTP(在线事务处理),通常用于交易需求,以及OLAP(在线分析处理)数据存储,通常用于报告和分析需求。以下表格详细说明了一般差异:
| OLTP 数据库 | OLAP 数据库 | |
|---|---|---|
| 定义 | 这涉及许多小的在线事务(INSERT、UPDATE 和 DELETE)。快速查询处理是核心要求;通过每秒事务数来衡量数据完整性、并发性和有效性。它通常以高度规范化为特征。 | 这涉及相对较小的事务量。复杂查询涉及数据的切片和切块。存储的数据通常是聚合的、历史性的,并且主要存储在多维模式中(通常是星型模式)。 |
| 数据类型 | 运营数据 | 集成/整合/聚合数据 |
| 来源 | OLTP 数据库通常是数据的实际来源 | OLAP 数据库从各种 OLTP 数据库中整合数据 |
| 主要用途 | 这涉及日常业务流程/任务的执行 | 这用于决策支持 |
| CUD | 这是由用户发起的简短、快速的插入和更新 | 定期运行的长作业正在刷新数据 |
| 查询 | 这通常在较小的数据量上工作,并执行简单的查询 | 这通常包括涉及聚合和多维结构切片和切块的复杂查询 |
| 吞吐量 | 由于数据量相对较小且查询运行速度快,这通常非常快 | 这通常以批量方式运行,在更高数据量下可能需要几个小时 |
| 存储容量 | 由于历史数据归档,相对较小 | 由于涉及的数据量较大,这需要更大的存储空间 |
| 模式设计 | 高度规范化,有许多表 | 这通常是去规范化,表较少,并使用星型和/或雪花模式 |
| 备份和恢复 | 这需要虔诚地进行适当的备份;运营数据对业务运营至关重要。数据丢失可能导致重大经济损失和法律责任 | 相比于常规备份,某些环境可能考虑仅重新加载 OLTP 数据作为恢复方法 |
观察二——数据架构是共享磁盘
共享磁盘数据架构指的是一种架构,其中有一个数据磁盘存储所有数据,集群中的每个节点都可以访问这些数据进行处理。所有数据操作都可以由任意节点在特定时间点执行,如果两个节点同时尝试持久化/写入一个元组,为了确保一致性,会传递基于磁盘的锁或预期的锁通信,从而影响性能。随着节点数量的增加,数据库级别的争用增加。这些架构是写入受限的,因为需要处理集群中节点间的锁。
即使在读取的情况下,也应该有效地实施分区以避免完整表扫描。所有传统的 RDBMS 数据库都是共享磁盘数据架构。

观察结果 3——传统 ETL 架构存在局限性。以下列表提供了这些局限性的详细信息:
-
上线和整合数据既缓慢又昂贵。今天存在的许多 ETL 逻辑都是定制编码的,并且与数据库紧密耦合。这种紧密耦合也导致了一个问题,即现有的逻辑代码无法重用。分析和报告需求需要应用不同的调整技术。分析优化既耗时又昂贵。
-
数据来源通常记录不佳。数据含义在翻译中丢失。上线后的维护和分析成本通常非常高。重建数据血缘是手动、耗时且易出错的。没有强大的审计或记录数据转换,通常在电子表格中跟踪。
-
目标数据难以消费。优化倾向于已知分析,但并不适合新需求。使用的是一刀切的标准视图,而不是适合目的的视图,或者缺乏一个易于消费目标数据的概念模型。很难确定哪些数据可用,如何获取访问权限,以及如何整合数据来回答问题。
观察结果 4——数据通常是结构化的
大多数时候,数据库的设计是为了适应关系数据库管理系统(RDBMS)模型。如果传入的数据实际上没有结构,ETLs 就会构建一个结构以便存储在标准的 OLTP 或 OLAP 存储中。
观察结果 5——性能和可扩展性
在给定基础设施的情况下,数据存储或查询的优化在某种程度上是可能的,但超过一定点,就需要重新设计。
新兴的数据架构视角与驱动因素
驱动因素 1——大数据干预。
我们在第二章“机器学习和大规模数据集”中定义了大数据和大型数据集的概念。现在正在被摄取并需要处理的数据通常具有以下特征:
-
来源:根据信息的性质,来源可能是一个实时数据流(例如,交易交易),或者自上次同步以来包含更新的数据批次
-
内容:数据可能代表不同类型的信息。通常,这些信息与其他数据相关,需要连接
以下截图显示了需要支持的数据类型和不同来源:
![新兴的数据架构视角与驱动因素]()
-
体积:根据数据的性质,正在处理的数据量可能不同。例如,主数据或证券定义数据相对固定,而交易数据与其他两种相比是巨大的。
-
生命周期:主数据有固定的生命周期,很少更新(例如,缓慢变化的维度)。然而,事务数据生命周期非常短,但需要长时间可用于分析、审计等。
-
结构:虽然大部分数据是有结构的,但在金融行业中出现了非结构化数据的新趋势。对于金融系统来说,将非结构化数据纳入其 IT 架构中变得越来越关键。
下一个图表展示了每个数据源的复杂性、速度、体积和各个方面:

来源:SoftServe
驱动因素 2——数据平台需求高级
新时代数据平台需求的地貌正在急剧扩张,统一平台是当前的热点。下一张概念图将详细解释这一点。数据架构的核心元素包括 ETL(提取、转换和加载)、存储、报告、分析、可视化和数据分发。

驱动因素 3——机器学习和分析平台现在有了新的目的和定义
以下图表展示了分析的发展及其自我重塑:
-
历史上,重点仅在于报告。汇总或预处理过的数据被加载到仓库中,以了解发生了什么。这被称为描述性分析,主要是向后一步。
-
随着临时数据包含的出现,需要理解某些行为发生的原因。这被称为诊断分析,其重点是理解行为背后的根本原因,这又基于历史数据。
-
现在,需求已经转变,需要理解将要发生什么。这被称为预测分析,其重点是根据历史行为预测事件。
-
随着实时数据的出现,现在的重点是是否能够实现它?这超越了预测分析,其中补救措施是某个部分的一部分。最终的重点是随着实时事件访问的出现,实现它!以下图表展示了分析在价值及其相关复杂性方面的演变:

下一个表格区分了传统分析(BI)和新时代分析:
| 区域 | 传统分析(BI) | 新时代分析 |
|---|---|---|
| 范围 | 描述性分析诊断分析 | 预测分析数据科学 |
| 数据 | 有限/受控的量预处理/验证基本模型 | 大量数据多种格式和多样性预处理/验证过的数据增长模型复杂性 |
| 结果 | 这里,重点是回顾和根本原因分析 | 这里,重点是预测/洞察力和分析的准确性 |
驱动因素 4—不仅仅关乎历史和批量,还有实时和即时洞察
输入数据量小、速度高是定义 实时 的关键。新一代分析系统预计将处理实时、批量以及近实时处理请求(这些是计划好的,被称为微批量)。以下图表描述了实时和批量数据特性在体积、速度和多样性保持恒定的情况下的属性。

驱动因素 5—传统的 ETL 无法应对 大数据
目标是能够制定一个 ETL 架构策略,以解决以下问题区域:
-
促进实施标准化—处理一个标准的需求
-
支持构建可重用组件
-
构建无差别的函数
-
使用并行处理技术提高性能和可扩展性
-
降低总体拥有成本(TCO)
-
构建专门的技能库
以下表格提供了关键数据加载模式的比较分析:
| ETL 提取、转换和加载 | ELT 提取、加载和转换 | ETLT 提取、转换、加载和转换 | |
|---|---|---|---|
| 概述 | 这是一个传统的数据移动和转换技术,其中 ETL 引擎要么与源数据库分离,要么目标 DBMS 执行数据转换。 | 这是一个将数据从一处移动和转换到另一实例和格式的技术。在这种集成风格中,目标 DBMS 成为转换引擎。 | 在这种技术中,转换部分由 ETL 引擎完成,部分推送到目标 DBMS。 |
| 高亮 | 在 ETL 引擎中进行了大量的转换工作。它使用集成的转换函数。转换逻辑可以通过 GUI 进行配置。这是由 Informatica 支持的。 | 转换工作被委托给 DBMS 层。转换逻辑运行得更接近数据。这是由 Informatica 支持的。 | 转换工作在 ETL 引擎和 DBMS 之间分配。这是由 Informatica 支持的。 |
| 好处 | 这是一个基于图形用户界面的简单配置。转换逻辑独立,位于数据库之外,且可重用。这对于粒度细、简单、面向功能的转换非常有效,这些转换不需要任何数据库调用。可以在 SMP 或 MPP 硬件上运行。 | 这利用了 RDBMS 引擎硬件以实现可扩展性。它始终将所有数据保留在 RDBMS 中。根据数据集进行并行化,并且通常在引擎级别优化磁盘 I/O 以实现更快的吞吐量。只要硬件和 RDBMS 引擎可以继续扩展,它就可以扩展。在适当调整的 MPP RDBMS 平台上可以实现 3 倍到 4 倍的吞吐量。 | 它可以平衡工作负载或与 RDBMS 共享工作负载。 |
| 风险 | 这需要在 ETL 侧有更高的处理能力。成本更高。它包括需要参考数据的复杂转换,这将减慢处理过程。 | 转换逻辑与数据库相关联。涉及较小体积和简单性质的转换不会带来很多好处。 | 这仍将在数据库内部包含一部分转换逻辑。 |
事实 6——没有“一个”数据模型适合高级或复杂的数据处理需求;需要多数据模型平台
不同的数据库被设计用来解决不同的问题。通常使用单个数据库引擎来满足所有需求会导致性能不佳的解决方案。RDBMS 在事务操作方面表现良好,OLAP 数据库用于报告,NoSQL 用于高容量数据处理和存储。一些解决方案统一了这些存储,并为跨这些存储的查询提供了抽象。
适用于机器学习的现代数据架构
从本节开始,我们将详细介绍一些新兴的数据架构、导致这种实现架构的挑战、一些相关的技术堆栈以及这些架构适用的用例(如有相关)。
语义数据架构
在上一节中提到的新兴观点中涵盖的一些事实引发了以下核心架构驱动因素,以构建语义数据模型驱动的数据湖,这些数据湖能够无缝集成更广泛的数据范围,并且为分析做好准备。分析的未来是语义化的。此处的目标是创建一个大规模、灵活、标准驱动的 ETL 架构框架,借助工具和其他架构资产进行建模,以实现以下功能:
-
使一个可以成为标准架构的通用数据架构。
-
与未来基于本体驱动的数据架构和数据湖相结合(重要的是要将此架构策略与数据聚合参考架构相结合)。这将确保有一个单一的数据策略来处理数据质量和数据集成。
-
使产品团队能够快速集成到数据架构中,并将数据存入和从公共数据存储库中提取。
-
根据需要启用即席分析。
-
减少实施新的数据聚合、摄取和转换所需的时间。
-
启用“任何格式到任何格式”的模式(一种涉及数据规范化的格式无关方法)。
-
遵守新兴的语义标准。这将带来灵活性。
-
使共同的 IT 管理成为可能并降低 TCO。
-
为 Broadridge 主业务数据存储库启用一个统一的云(这可能是一个专有的)。
-
使所有应用程序和产品能够“使用一种共同的语言”并构建 Broadridge 数据格式。
-
减少,在某些情况下消除,过多许可证、数据库、实施、堆栈等的泛滥。
-
数据语义化:分析底层架构以从中提取意义是很重要的。语义化过程始终是迭代的,并随着时间的推移而发展。在此过程中,元数据定义将被详细阐述或扩展。
![语义数据架构]()
在企业范围内建立聚合数据集市并不是解决之前提出问题的方案。即使建立了这样的数据集市,保持其更新并与其他项目保持一致将是一个主要问题。正如之前所述,需要制定一个系统,该系统能够从多个来源积累数据,而不对数据的使用方式、地点或时间做出任何假设。
我们利用该领域的两个不同进展来解决架构层面的问题。这些是数据湖作为架构模式的演变,以及语义网的兴起及其在电子商务中的日益相关性。
业务数据湖
企业数据湖为数据仓库的概念带来了全新的维度。虽然数据仓库的方法一直是设计一个单一架构并汇总满足该架构所需的最少信息,但数据湖颠覆了传统数据仓库架构的这两个前提。传统的数据仓库是为了特定的目的而设计的(例如,分析、报告和运营洞察)。架构相应设计,所需的最少信息被汇总。这意味着如果使用这个仓库实现其他目标,那只是偶然的,而不是其设计目的。
商业数据湖促进了适当模式的概念——仓库不受固定、预定的模式的约束。这允许数据湖在组织内信息可用时吸收信息。这一重要直接影响是,而不是吸收最少的信息——数据湖可以吸收组织产生的所有信息。由于没有对数据是什么的假设,未来可以使用信息进行任何目的的选项仍然开放。这使得数据湖能够通过提供数据湖中已有的数据来支持新想法,从而提高业务敏捷性。
商业数据湖解决了以下问题:
-
如何处理非结构化数据?
-
如何链接内部和外部数据?
-
如何适应业务变化的速度?
-
如何消除重复的 ETL 周期?
-
如何根据不同的业务需求支持不同层次的数据质量和治理?
-
如何让本地业务单元采取主动?
-
如何确保平台的交付并使其被采用?
语义网技术
当使用在网络上最常找到的外部数据时,最重要的要求是理解数据的精确语义。没有这一点,结果无法信任。在这里,语义网技术提供了帮助,因为它们允许为任何可用的资源指定从非常简单到非常复杂的语义。语义网技术不仅支持捕获被动的语义,还支持对数据进行主动的推理和推理。
语义网技术允许数据被附加额外的元数据(作为 RDF)。这种能力添加的最基本的能力之一是语义计算的AAA 原则——任何人都可以在任何时候添加关于任何事物的任何内容。由于信息由元数据组成,因此可以随时添加更多元数据来丰富信息。
使用 SPARQL 查询 RDF 数据,它允许导航复杂的关系图,从数据存储中提取有意义的信息。推理器(或推理引擎)与 RDF 元数据一起工作,在数据顶部提供推理。这允许系统提取原本在传入数据中不可用的新的见解。
现在,大量的信息正在通过互联网和公司及监管网络变得可用。然而,只要信息被分别存储,没有简单的方法将它们从不同的来源组合起来,对所有可用信息的访问仍然有限。
这加剧了对合适方法的需求,以结合来自各种来源的数据。这被称为“信息系统的合作”。这被定义为能够在透明的方式下,在最终用户之间共享、组合和交换异构源信息的能力。这些异构源通常被认为是始终在孤岛中处理数据,因此它们是不可访问的。为了实现数据互操作性,需要消除数据异质性提出的问题。数据源可以以下方式异构:
-
句法:句法异质性是由使用不同的模型或语言引起的
-
模式:模式异质性源于结构差异
-
语义学:语义异质性是由不同语境中数据的不同含义或解释所引起的
![语义网技术]()
数据集成提供了在多个数据源之间透明地操作数据的能力。基于架构,存在两种系统:
-
中央数据集成:中央数据集成系统通常具有全局模式,它为用户提供了一个统一的接口来访问存储在数据源中的信息。
-
对等网络:相比之下,在对等网络数据集成系统中,数据源(或对等点)上没有一般性的控制点。相反,任何对等点都可以接受用户对整个系统中分布的信息的查询。
信息系统的合作是指能够从多个信息源共享、组合和/或交换信息,以及最终接收者能够透明地访问集成信息的能力。阻碍信息系统合作的主要问题是信息源的自主性、分布、异质性和不稳定性。特别是,我们对可以在几个层面上识别的异质性问题感兴趣:系统、句法、结构和语义异质性。信息系统的合作已被广泛研究,并提出了几种方法来弥合异构信息系统之间的差距,例如:数据库转换、标准化、联邦、调解和 Web 服务。这些方法为句法和基本层面的异质性问题提供了适当的解决方案。
然而,为了实现异构信息系统之间的语义互操作性,交换信息的含义必须在系统中被理解。每当两个语境不使用对信息的相同解释时,就会发生语义冲突。
因此,为了处理语义异构性,需要更多语义专业化的方法,例如本体。在本章中,我们的重点是展示信息系统如何使用语义进行合作。在下一节中,让我们看看语义数据架构的构成。
本体和数据集成
此图表示基于语义数据架构的参考架构:

语义数据架构的关键特性如下:
-
元数据表示:每个来源都可以表示为支持元数据字典以解释术语的本地本体。
-
全局概念化:将有一个全局本体定义,它映射本地本体,并为共同视图提供单一视图或术语。
-
通用查询:将根据消费者/客户端的需求和目的,在本地或全局本体级别提供查询支持。
-
物化视图:一种高级查询策略,用于隐藏术语和同源之间的查询。
-
映射:将支持定义本体属性和值之间的术语表映射。
供应商
| 类型 | 产品/框架 | 供应商 |
|---|---|---|
| 开源和商业版本 | MarkLogic 8 是支持存储和处理 RDF 数据格式的 NoSQL 图存储,可以作为三元组存储。 | MarkLogic |
| 开源和商业版本 | Stardog 是最简单且功能最强大的图数据库:在轻量级、纯 Java 系统中进行搜索、查询、推理和约束。 | Stardog |
| 开源 | 4Store 是一个高效、可扩展且稳定的 RDF 数据库。 | Garlik Ltd. |
| 开源 | Jena 是一个用于构建语义网和链接数据应用的免费开源 Java 框架。 | Apache |
| 开源 | Sesame 是一个强大的 Java 框架,用于处理和操作 RDF 数据。这包括创建、解析、存储、推理和查询此类数据。它提供了一个易于使用的 API,可以连接到所有领先的 RDF 存储解决方案。 | GPL v2 |
| 开源 | Blazegraph 是 SYSTAP 的旗舰图数据库。它专门设计用于支持大型图,提供语义网(RDF/SPARQL)和图数据库(TinkerPop、blueprints 和以顶点为中心)API。 | GPL v2 |
多模型数据库架构/多语言持久性
即使五年前,我们也无法想象关系数据库只会成为数据库技术的一种,而不是数据库技术本身。互联网规模的数据处理改变了我们处理数据的方式。
新一代架构,如 Facebook、Wikipedia、SalesForce 等,在原则和范例上与当前数据管理技术发展的既定理论基础截然不同。
这些架构的主要架构挑战可以概括如下:
-
信息商品化:
苹果应用商店、SaaS、通用计算、移动性和基于云的多租户架构在商业术语上释放了商品化信息交付的能力。这种模型几乎改变了所有的架构决策,因为我们现在需要考虑的是可以提供并作为服务计费的信息“单元”,而不是考虑解决方案的总拥有成本(TCO)。
-
关系型数据库管理系统(RDBMS)的理论局限性:
影响力巨大的数据库理论家迈克尔·斯坦利布雷克(Michael Stonebraker)最近在互联网规模架构的核心所撰写的,是一个新的数据处理和管理理论模型。数据库管理的理论现在已有三十多年历史,当时它们是为大型机类型的计算环境和非常不可靠的电子组件而设计的。自然和系统以及应用的能力已经发生了显著变化。随着可靠性成为底层环境的质量属性,系统由并行处理核心组成,数据创建和使用的性质也发生了巨大变化。为了概念化这些新环境下的解决方案,我们需要从计算的角度来设计解决方案架构,而不仅仅是工程角度。
六大主要力量正在推动今天的数据革命。它们如下:
-
大规模并行处理
-
信息交付商品化
-
通用计算和移动设备
-
非 RDBMS 和语义数据库
-
社区计算
-
云计算
Hadoop 和 MapReduce 在很大程度上释放了数据的并行处理能力,并在程序化平台上实现了复杂的计算算法。这永远地改变了分析和商业智能。同样,基于 Web 服务和 API 驱动的架构在很大基础上实现了信息交付的商品化。如今,可以以这种方式构建极其庞大的系统,使得每个子系统或组件本身就是一个完整的平台,由完全不同的实体托管和管理。
之前的创新已经完全改变了传统的数据架构。特别是,语义计算和基于本体论的信息建模已经彻底颠覆了数据设计。
从哲学上讲,数据架构正在经历事实基础。在传统的数据模型中,我们首先设计数据模型——对世界及其未来的固定、设计时理解。数据模型将数据的含义永远固定在固定的结构中。
表不过是一个类别,一组事物。因此,数据只有在理解它所属的集合/类别时才有意义。例如,如果我们把汽车处理系统设计成一些类别,如四轮车、两轮车、商用车辆等,这种划分本身就包含了一些重要的意义。存储在每个类别中的数据并不能揭示设计嵌入的方式中的设计目的。例如,另一个系统可能会从驱动方式的角度来看待汽车世界——电动、石油驱动、核驱动等。这种分类本身以某种方式揭示了系统的目的,这是无法从任何单个记录的属性中获得的。
“多语言”这个术语通常用来定义能够说多种语言的人。在大数据背景下,这个术语指的是一组使用多种数据库技术的应用程序,其中每种数据库技术解决特定的问题。这种数据架构的基本前提是不同的数据库技术解决各种问题,因为复杂的应用程序有很多问题,选择一个选项来解决特定问题比试图用一个选项解决所有问题更好。当我们谈论数据系统时,它被定义为负责数据存储和查询的系统,其运行时间可达数年,并需要解决所有可能的硬件和维护复杂性。
当遇到复杂问题时,会采用多语言持久化数据架构,将问题分解成更小的部分,并通过应用不同的数据库模型来解决。随后将结果汇总到一个混合数据存储平台,并进行分析。影响数据库选择的一些因素如下:
因素 1—数据模型:
-
我们希望整合哪些类型的数据源?
-
我们希望如何操作/分析数据?
-
数据的量、种类和速度是多少?
-
例子—关系型、键值型、列式、文档型、图等。
因素 2—一致性、可用性和分区(CAP):
-
一致性:每个客户端的对象只有一个值(原子性)
-
可用性:所有对象始终可用(低延迟)
-
分区容错性:数据被分割成多个网络分区(聚类)
CAP 定理要求我们在这两个特性中选择任何一个:

以下图表是一个示例系统,该系统具有多个应用程序,并为其目的构建了数据模型:

来源:ThoughtWorks
影响此解决方案的一些重要方面如下:
-
确保提出的混合环境被清楚地理解,以确保它有助于做出关于数据集成、分析、数据可见性等方面的正确决策,从而确定解决方案如何融入整个大数据和数据分析实施框架。
-
由于存在多个数据模型,因此将需要一个能够与为解决方案和聚合而指定的所有数据库接口的统一平台。这个平台应该解决一些大数据平台的基本期望,如:容错性、高可用性、事务完整性、数据敏捷性和可靠性、可扩展性和性能。
-
根据具体要求,了解/理解哪种数据模型既适用于特定问题,也适用于整体解决方案,这一点非常重要。
-
数据摄取策略解决实时和批量数据更新,以及如何在多模型数据库的上下文中使其工作。由于将会有各种数据存储,系统记录(SOR)将是什么?我们如何确保所有数据源中的数据保持同步或是最新的?
因此,这可能是最好的大数据挑战。需要收集、集成和分析多个来源的、结构非常不同的数据,以解决特定的商业问题。然后,关键是确定数据是否需要按需或实时推送到客户端。显然,这种类型的问题不能简单地或以成本效益的方式使用一种数据库技术来解决。在某些情况下,直接使用 RDBMS 可能可行,但在存在非关系型数据的情况下,需要不同的持久化引擎,如 NoSQL。同样,对于电子商务业务问题,我们还需要一个高度可用和可扩展的数据存储,用于购物车功能。然而,要找到特定群体购买的产品,同一个存储无法提供帮助。这里的需求是采用混合方法,并使用多个数据存储联合使用,这被称为多语言持久化。
供应商
| 类型 | 产品/框架 | 供应商 |
|---|---|---|
| 商业 | FoundationDB 是一个坚如磐石的数据库,提供 NoSQL(键值存储)和 SQL 访问。 | FoundationDB |
| 开源 | ArangoDB 是一个开源的 NoSQL 解决方案,具有灵活的数据模型,适用于文档、图和键值。 | GPL v2 |
Lambda 架构(LA)
Lambda 架构解决了机器学习的一个重要方面;即提供一个统一平台,用于实时和批量分析。我们至今所见的大多数框架都支持批量架构(例如,Hadoop),以便支持与特定框架(例如,Storm)的实时处理集成。
Nathan Marz 提出了 Lambda 架构的概念,这是一个通用的、可扩展的、容错的数据处理架构,它将实时流处理和批量处理作为一个统一的解决方案。
Lambda 架构促进了一个高度容错的数据架构,既对抗硬件故障,也对抗人为错误。同时,它服务于广泛的用途和工作负载,在这些用途和工作负载中,需要低延迟的读取和更新。结果系统应该是线性可扩展的,并且应该向外扩展而不是向上扩展。
从高层次来看,它看起来是这样的:

-
数据层:进入系统的所有数据都被分配到批量层和速度层进行处理。
-
批量层:此层管理主数据,并负责批量预计算。它处理大量数据。
-
速度层:速度层负责处理最近的数据,并补偿服务层更新的高延迟。平均而言,这一层不处理大量数据。
-
服务层:服务层处理批量视图的索引,并促进低延迟的即席查询。
-
查询函数:此函数结合了批量视图和实时视图的结果。
Vendors
| 类型 | 产品/框架 | 供应商 |
|---|---|---|
| 开源和商业 | Spring XD 是一个针对碎片化 Hadoop 生态系统的统一平台。它建立在经过实战检验的开源项目之上,极大地简化了大数据工作负载和数据管道的编排。 | Pivotal (Spring Source) |
| 开源 | Apache Spark 是一个快速的传统大数据处理引擎,内置流、SQL、机器学习和图处理模块。 | Apache |
| 开源 | Oryx 是一个简单、实时和大规模的机器学习基础设施。 | Apache (Cloudera) |
| 开源 | Storm 是一个用于实时处理流数据的系统。 | Apache (Hortonworks) |
摘要
在本章的结尾,我们的重点是机器学习的实现方面。我们已经了解了传统分析平台是什么,以及它们如何无法满足现代数据需求。您还学习了推动新数据架构范式(如 Lambda 架构和多语言持久性[多模型数据库架构])的架构驱动因素,以及语义架构如何帮助实现无缝数据集成。通过本章,您可以假设您已经准备好为任何领域实施机器学习解决方案,并且不仅能够识别出解决学习问题所需应用哪些算法或模型,而且还能找到最佳的平台解决方案。

































































浙公网安备 33010602011771号