Mahout-分类学习指南-全-

Mahout 分类学习指南(全)

原文:zh.annas-archive.org/md5/d0f8a395f43b0f470e91dce63808a709

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

由于硬件行业取得的进步,我们的存储容量增加了,因此许多组织都希望为了分析目的存储所有类型的事件。这催生了一个新的机器学习时代。机器学习领域非常复杂,编写这些算法并非易事。Apache Mahout 为我们提供了机器学习领域的现成算法,并使我们免于复杂的算法实现任务。

这本书的目的是涵盖 Apache Mahout 中可用的分类算法。无论你已经使用其他工具工作过分类算法,还是对这个领域完全陌生,这本书都会帮助你。因此,开始阅读这本书,探索最受欢迎的开源项目之一,Apache Mahout 中的分类算法,该项目享有强大的社区支持。

本书涵盖的内容

第一章, 数据分析中的分类,介绍了数据分析中的分类概念。本章将涵盖分类的基础知识、相似度矩阵以及该领域可用的算法。

第二章, Apache Mahout,介绍了 Apache Mahout 及其安装过程。此外,本章将讨论为什么它是进行分类的好选择。

第三章, 使用 Mahout 学习逻辑回归/SGD,讨论了逻辑回归和随机梯度下降,以及开发者如何使用 Mahout 实现 SGD。

第四章, 使用 Mahout 学习朴素贝叶斯分类,讨论了贝叶斯定理、朴素贝叶斯分类以及我们如何使用 Mahout 构建朴素贝叶斯分类器。

第五章, 使用 Mahout 学习隐马尔可夫模型,涵盖了 HMM 以及如何使用 Mahout 的 HMM 算法。

第六章, 使用 Mahout 学习随机森林,详细讨论了随机森林算法,以及如何使用 Mahout 的随机森林实现。

第七章, 使用 Mahout 学习多层感知器,讨论了 Mahout 作为神经网络早期实现的工具。本章我们将讨论多层感知器。此外,我们将使用 Mahout 的 MLP 实现。

第八章, 即将发布的 Mahout 变化,讨论了 Mahout 作为一个正在进行中的工作。我们将讨论即将发布的 Mahout 版本中的新主要变化。

第九章, 使用 Apache Mahout 构建电子邮件分类系统,提供了两个电子邮件分类的使用案例——垃圾邮件分类和基于邮件所属项目的电子邮件分类。我们将创建模型,并在一个模拟真实工作环境的程序中使用此模型。

您需要为此书准备的内容

要使用本书中的示例,您应该在您的系统上安装以下软件:

  • Java 1.6 或更高版本

  • Eclipse

  • Hadoop

  • Mahout;我们将在本书的第二章 Apache Mahout 中讨论其安装

  • Maven,根据您如何安装 Mahout

本书面向的对象

如果您是一位对 Hadoop 生态系统和机器学习方法有一定经验的 数据科学家,并想尝试使用 Mahout 在大型数据集上进行分类,这本书非常适合您。Java 知识是必需的。

规范

在本书中,您将找到许多文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。

文本中的代码词汇、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称将如下所示:“提取源代码并确保文件夹包含pom.xml文件。”

代码块将以如下方式设置:

    public static Map<String, Integer> readDictionary(Configuration conf, Path dictionaryPath) {
        Map<String, Integer> dictionary = new HashMap<String, Integer>();
        for (Pair<Text, IntWritable> pair : new SequenceFileIterable<Text, IntWritable>(dictionaryPath, true, conf)) {
            dictionary.put(pair.getFirst().toString(), pair.getSecond().get());
        }
        return dictionary;
    }

当我们希望将您的注意力引向代码块中的特定部分时,相关的行或项目将以粗体显示:

    public static Map<String, Integer> readDictionary(Configuration conf, Path dictionaryPath) {
 Map<String, Integer> dictionary = new HashMap<String, Integer>();
        for (Pair<Text, IntWritable> pair : new SequenceFileIterable<Text, IntWritable>(dictionaryPath, true, conf)) {
            dictionary.put(pair.getFirst().toString(), pair.getSecond().get());
        }
        return dictionary;
    }

任何命令行输入或输出都将如下所示:

hadoop fs -mkdir /user/hue/KDDTrain 
hadoop fs -mkdir /user/hue/KDDTest
hadoop fs –put /tmp/KDDTrain+_20Percent.arff  /user/hue/KDDTrain
hadoop fs –put /tmp/KDDTest+.arff  /user/hue/KDDTest

新术语重要词汇将以粗体显示。你在屏幕上看到的单词,例如在菜单或对话框中,将以如下方式显示:“现在,导航到mahout-distribution-0.9的位置并点击完成。”

注意

警告或重要注意事项将以如下方框显示。

小贴士

小贴士和技巧将以如下方式显示。

读者反馈

我们欢迎读者的反馈。告诉我们您对这本书的看法——您喜欢或不喜欢什么。读者反馈对我们很重要,因为它帮助我们开发出您真正能从中获得最大收益的标题。

要向我们发送一般反馈,请简单地发送电子邮件至 <feedback@packtpub.com>,并在邮件主题中提及书籍标题。

如果您在某个主题上具有专业知识,并且您有兴趣撰写或为书籍做出贡献,请参阅我们的作者指南www.packtpub.com/authors

客户支持

现在,您已经是 Packt 图书的骄傲拥有者,我们有一些事情可以帮助您从您的购买中获得最大收益。

下载示例代码

您可以从www.packtpub.com上下载您购买的所有 Packt Publishing 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

下载本书的彩色图像

我们还为您提供了一个包含本书中使用的截图/图表彩色图像的 PDF 文件。这些彩色图像将帮助您更好地理解输出的变化。您可以从www.packtpub.com/sites/default/files/downloads/4959OS_ColoredImages.pdf下载此文件。

勘误

尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在我们的书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以避免其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入您的勘误详情来报告它们。一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误部分下的现有勘误列表中。

要查看之前提交的勘误,请访问www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将出现在勘误部分下。

盗版

互联网上对版权材料的盗版是一个持续存在的问题,涉及所有媒体。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上发现任何形式的非法复制我们的作品,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。

请通过mailto:copyright@packtpub.com copyright@packtpub.com>与我们联系,并提供疑似盗版材料的链接。

我们感谢您在保护我们的作者和我们为您提供有价值内容的能力方面的帮助。

问题

如果您对本书的任何方面有问题,您可以通过mailto:questions@packtpub.com questions@packtpub.com>与我们联系,我们将尽力解决问题。

第一章. 数据分析中的分类

在过去十年中,我们见证了社交网络和电子商务网站的大幅增长。我确信你一定在 Facebook、Twitter 或其他网站上看到过这本书的信息。你也很可能在手机或*板电脑上订购后阅读了这本书的电子版。

这必须让你意识到我们每天在互联网上生成多少数据。现在,为了从数据中获得所有必要的信息,我们不仅创建数据,还存储这些数据。这些数据对于获得对业务的某些重要见解极为有用。对这些数据的分析可以增加客户群并为企业创造利润。以电子商务网站为例。你访问网站购买书籍。你会得到关于相关主题或同一主题、出版社或作者的书籍信息,这有助于你做出更好的决定,同时也帮助网站更多地了解其客户。这最终将导致销售额的增加。

寻找相关项目或向用户推荐新项目都是数据分析的一部分,我们分析数据并试图获取有用的模式。

数据分析是检查历史数据并创建模型以获取有助于决策的有用信息的流程。它在许多行业中都有帮助,例如电子商务、银行、金融、医疗保健、电信、零售、海洋学等等。

让我们以天气预报系统为例。这是一个可以预测特定地点大气状态的系统。在这个过程中,科学家收集该地点的大气历史数据,并试图基于这些数据创建一个模型,以预测大气在一段时间内的演变。

在机器学习中,分类是从过去的例子中学习并自动模拟这些决策的决策过程自动化。自动模拟决策是预测分析的核心概念。在本章中,我们将探讨以下要点:

  • 理解分类

  • 分类系统的工作原理

  • 分类算法

  • 模型评估方法

介绍分类

每当我们提到“分类”这个词时,总会让我们想起生物学课程,在那里我们学习了动物分类。我们学习了不同类别的动物,如哺乳动物、爬行动物、鸟类、两栖动物等等。

如果你记得这些类别是如何定义的,你就会意识到科学家在现有的动物中发现了某些特性,并且基于这些特性,他们对新的动物进行了分类。

其他分类的实际例子可以是,例如,当你去看医生时。他会问你一些问题,然后根据你的回答,他能够判断你是否患有某种疾病。

分类是将潜在答案进行分类的过程,在机器学习中,我们希望自动化这个过程。生物分类是多类分类的一个例子,而发现疾病是二元分类的一个例子。

在数据分析中,我们希望使用机器学习概念。为了分析数据,我们希望构建一个系统,帮助我们找出单个项目属于哪个类别。通常,这些类别是互斥的。这个领域的一个相关问题是要找出单个属于某个特定类别的概率。

分类是一种监督学习技术。在这种技术中,机器——基于历史数据——学习和获得预测未知的能力。在机器学习中,另一种流行的技术是无监督学习。在监督学习中,我们已经知道输出类别,但在无监督学习中,我们一无所知。让我们用一个快速例子来理解这一点:假设我们有一个水果篮,我们想要对水果进行分类。当我们说分类时,意味着在训练数据中,我们已经有输出变量,如大小和颜色,我们知道颜色是红色,大小在 2.3"到 3.7"之间。我们将该水果分类为苹果。与此相反,在无监督学习中,我们想要将不同的水果分开,在训练数据集中我们没有任何输出信息,因此学习算法将根据数据集中存在的不同特征来分离不同的水果,但它无法对它们进行标记。换句话说,它无法告诉哪个是苹果,哪个是香蕉,尽管它能够将它们分开。

分类系统的应用

分类用于预测。在电子邮件分类的情况下,它用于将电子邮件分类为垃圾邮件或非垃圾邮件。如今,Gmail 还将电子邮件分类为主要邮件、社交邮件和促销邮件。分类在预测信用卡欺诈、为贷款资格分类客户等方面非常有用。它也用于预测保险和电信行业的客户流失。在医疗保健行业也非常有用。基于历史数据,它有助于对疾病的特定症状进行分类,以提前预测疾病。分类可以用于分类热带气旋。因此,它在所有行业中都有用。

分类系统的运作原理

让我们更详细地了解分类过程。在分类过程中,我们使用给定的数据集,试图找到信息变量,通过这些变量我们可以减少不确定性并对某事物进行分类。这些信息变量被称为解释变量或特征。

我们感兴趣的最后类别被称为目标变量或标签。解释变量可以是以下任何一种形式:

  • 连续的(数值类型)

  • 分类别

  • 类似于单词的

  • 类似于文本的

注意

如果数值类型对任何数学函数都没有用,那么这些将被视为分类数据(如邮政编码、街道号码等)。

例如,我们有一个客户贷款申请的数据集,我们想要构建一个分类器来找出新客户是否有资格获得贷款。在这个数据集中,我们可以有以下字段:

  • 客户年龄

  • 客户收入(PA

  • 客户账户余额

  • 贷款批准

从这些字段中,客户年龄客户收入(PA)和客户账户余额将作为解释变量,贷款批准将是目标变量,如下截图所示:

分类系统的工作原理

为了理解分类器的创建,我们需要了解一些术语,如下面的图所示:

分类系统的工作原理

  • 训练数据集:从给定的数据集中,一部分数据被用来创建训练数据集(可能是给定数据的 70%)。这个数据集用于构建分类器。在这个数据集中使用了所有的特征集。

  • 测试数据集:在训练数据集被使用后剩下的数据集用于测试创建的模型。使用这些数据,仅使用特征集,并使用模型来预测目标变量或标签。

  • 模型:这是用来理解生成目标变量的算法。

在构建分类器时,我们遵循以下步骤:

  • 收集历史数据

  • 清洗数据(这里涉及许多活动,如空格删除等)

  • 定义目标变量

  • 定义解释变量

  • 选择算法

  • 训练模型(使用训练数据集)

  • 运行测试数据

  • 评估模型

  • 调整解释变量

  • 重新运行测试

在准备模型时,应注意异常值检测。异常值检测是一种找出数据集中不符合预期模式的项目的方法。输入数据集中的异常值可能会误导算法的训练过程。这可能会影响模型精度。有一些算法可以找出数据集中的这些异常值。基于距离的技术和基于模糊逻辑的方法通常用于找出数据集中的异常值。让我们通过一个例子来了解异常值。

我们有一组数字,我们想要找出这些数字的*均值:

10, 75, 10, 15, 20, 85, 25, 30, 25

只需绘制这些数字,结果将如以下截图所示:

分类系统的工作原理

显然,数字 75 和 85 是异常值(在图中远离其他数字)。

*均值 = 值的总和/值的数量 = 32.78

去除异常值后的*均值:= 19.29

因此,现在你可以理解异常值如何影响结果。

在创建模型时,我们可能会遇到两个主要问题——过拟合欠拟合

当算法捕捉到数据的噪声,并且算法拟合数据过于完美时,就会发生过拟合。通常,如果我们使用所有给定数据通过纯记忆来构建模型时,会发生过拟合。模型不是找出泛化模式,而是仅仅记住模式。通常,在过拟合的情况下,模型变得更加复杂,并且允许它选择虚假的相关性。这些相关性仅针对训练数据集,并不代表整个数据集的一般特征。

以下图表是过拟合的一个例子。存在一个异常值,算法考虑了这一点,并创建了一个完美分类训练集的模型,但由于这一点,测试数据被错误分类(测试数据中的两个矩形都被分类为星星):

分类系统的工作原理

没有一种单一的方法可以避免过拟合;然而,我们有一些方法,例如减少特征数量和将一些特征进行正则化。另一种方法是使用一些数据集来训练模型,并使用剩余的数据集进行测试。一种常用的方法称为交叉验证,用于生成多个性能指标。这样,单个数据集被分割并用于创建性能指标。

当算法无法捕捉数据中的模式,并且数据拟合得不好时,就会发生欠拟合。欠拟合也称为高偏差。这意味着你的算法对其假设有如此强烈的偏差,以至于它无法很好地拟合数据。对于欠拟合错误,更多的数据不会有所帮助。它可能会增加训练错误。更多的解释变量可以帮助处理欠拟合问题。更多的解释字段会扩展假设空间,并有助于克服这个问题。

无论是过拟合还是欠拟合,在使用新数据集时都会产生较差的结果。

分类算法

我们现在将讨论本书中由 Apache Mahout 支持的以下算法:

  • 逻辑回归 / 随机梯度下降(SGD):我们通常将回归与分类一起阅读,但实际上,两者之间是有区别的。分类涉及分类目标变量,而回归涉及数值目标变量。分类预测某事是否会发生,而回归预测某事会发生多少。我们将介绍这个算法在第三章 学习逻辑回归/随机梯度下降使用 Mahout 中。Mahout 支持通过随机梯度下降训练的逻辑回归。

  • 朴素贝叶斯分类:这是文本分类中非常流行的一个算法。朴素贝叶斯使用概率的概念来分类新项目。它基于贝叶斯定理。我们将在第四章,使用 Mahout 学习朴素贝叶斯分类中讨论这个算法。在这一章中,我们将看到 Mahout 在文本分类方面的应用,这在数据分析领域是必需的。我们将讨论向量化、词袋、n-gram 以及文本分类中使用的其他术语。

  • 隐马尔可夫模型(HMM):它在各种领域都有应用,如语音识别、词性标注、基因预测、时间序列分析等。在 HMM 中,我们观察到一系列的发射序列,但没有模型使用的状态序列来生成发射。在第五章,使用 Mahout 学习隐马尔可夫模型中,我们将讨论另一个由 Mahout 支持的算法。我们将详细讨论 HMM,并了解 Mahout 如何支持这个算法。

  • 随机森林:这是分类中最广泛使用的算法。随机森林由一组简单的树预测器组成,每个预测器都能在给定一组解释变量时产生响应。在第六章,使用 Mahout 学习随机森林中,我们将详细讨论这个算法,并讨论如何使用 Mahout 实现这个算法。

  • 多层感知器(MLP):在第七章,使用 Mahout 学习多层感知器中,我们将讨论 Mahout 中新实现的这个算法。MLP 由一个有向图中的多个层节点组成,每一层都与下一层完全连接。它是神经网络实现的基础。我们将在详细讨论 Mahout 中的 MLP 之后,简要讨论神经网络。

我们将在本书中讨论 Apache Mahout 支持的所有的分类算法,并检查 Apache Mahout 提供的模型评估技术。

模型评估技术

我们不能有一个单一的评估指标来适应所有的分类器模型,但我们可以找出评估中的一些常见问题,并且我们有技术来处理这些问题。我们将在 Mahout 中使用以下技术进行讨论:

  • 混淆矩阵

  • ROC 图

  • AUC

  • 熵矩阵

混淆矩阵

混淆矩阵为我们提供了模型与数据中实际结果(目标值)相比所做出的正确和错误预测的数量。混淆矩阵是一个 N*N 矩阵,其中 N 是标签(类别)的数量。每一列是预测类中的一个实例,每一行是实际类中的一个实例。使用这个矩阵,我们可以找出一个类别是如何与其他类别混淆的。假设我们有一个将三种水果分类的分类器:草莓、樱桃和葡萄。假设我们有 24 个水果的样本:7 个草莓,8 个樱桃和 9 个葡萄,得到的混淆矩阵如下表所示:

模型预测的类别
实际类别
草莓
樱桃
葡萄

因此,在这个模型中,从 8 个草莓中,有 3 个被分类为樱桃。从 8 个樱桃中,有 2 个被分类为草莓,1 个被分类为葡萄。从 9 个葡萄中,有 1 个被分类为樱桃。从这个矩阵中,我们将创建混淆表格。混淆表格有两行两列,报告关于真阳性、真阴性、假阳性和假阴性的信息。

因此,如果我们为特定类别构建这个表格,比如说草莓,它会是这样的:

真阳性4(正确分类的实际草莓)(a) 假阳性2(被分类为草莓的樱桃)(b)
假阴性3(错误分类为樱桃的草莓)(c) 真阴性15(所有其他水果正确地没有被分类为草莓)(d)

使用这个混淆表格,我们可以找出以下术语:

  • 准确率:这是正确分类的总预测数与预测总数的比例。它计算为(真阳性 + 真阴性)/ 阳性 + 阴性。因此,准确率 = (a+d)/(a+b+c+d)

  • 精确率或阳性预测值:这是正确分类的阳性案例的比例。它计算为(真阳性)/(真阳性 + 假阳性)。因此,精确率 = a/(a+b)

  • 阴性预测值:这是正确分类的阴性案例的比例。它计算为真阴性/(真阴性 + 假阴性)。因此,阴性预测值 = d/(c+d)

  • 灵敏度/真阳性率/召回率:这是正确识别的实际阳性案例的比例。它计算为真阳性/(真阳性 + 假阴性)。因此,灵敏度 = a/(a+c)

  • 特异性:这是实际阴性案例的比例。它计算为 真阴性/(假阳性 + 真阴性)。因此,特异性 = d/(b+d)

  • F1 分数:这是测试准确度的度量,其计算如下:F1 = 2.((阳性预测值(精确度) 灵敏度(召回率))/(阳性预测值(精确度)+ 灵敏度(召回率)))*。

接收者操作特征(ROC)图

ROC 是分类器的二维图,其假阳性率在 x 轴上,真阳性率在 y 轴上。图中的低点(0,0)表示从不发出阳性分类。点(0,1)表示完美分类。从(0,0)到(1,1)的对角线将 ROC 空间分割。对角线以上的点表示好的分类结果,而对角线以下的点表示差的结果,如下面的图所示:

接收者操作特征(ROC)图

ROC 曲线下的面积

这是 ROC 曲线下的面积,也称为 AUC。它用于衡量分类模型的质量。在实践中,大多数分类模型的 AUC 值介于 0.5 和 1 之间。该值越接* 1,你的分类器就越强大。

熵矩阵

在深入了解熵矩阵之前,我们首先需要理解。信息论中熵的概念是由香农提出的。

熵是应用于集合的混乱度度量。它被定义为:

熵 = -p1log(p1) – p2log(p2)- …….

每个 p 是该集合中特定属性的概率。让我们回顾一下我们的客户贷款申请数据集。例如,假设我们有 10 个客户,其中 6 个有资格贷款,4 个没有。在这里,我们有两个属性(类别):合格或不合格。

P(合格) = 6/10 = 0.6

P(不合格) = 4/10 = 0.4

因此,数据集的熵将是:

熵 = -[0.6log2(0.6)+0.4log2(0.4)]

= -[0.6-0.74 +0.4-1.32]

= 0.972

熵在获取信息增益知识方面很有用。信息增益衡量由于在模型创建过程中添加任何新信息而导致的熵的变化。因此,如果熵由于新信息而减少,这表明模型现在表现良好。信息增益的计算如下:

IG (类别,子类别) = 熵(类别) –(p(子类别 1)熵(子类别 1)+ p(子类别 2)熵(子类别 2) + …)

熵矩阵基本上与之前定义的混淆矩阵相同;唯一的区别是矩阵中的元素是每个真实或估计类别组合的概率得分的对数*均。一个好的模型将对角线上的数字将是小的负数,而在对角线位置将有大的负数。

摘要

我们已经讨论了分类及其应用,以及 Mahout 支持哪些算法和分类器评估技术。我们讨论了如混淆矩阵、ROC 图、AUC 和熵矩阵等技术。

现在,我们将进入下一章,设置 Apache Mahout 和开发环境。我们还将讨论 Apache Mahout 的架构,并找出为什么 Mahout 是分类的一个好选择。

第二章:Apache Mahout

在上一章中,我们讨论了分类,并探讨了 Mahout 在该领域提供的算法。在探讨这些算法之前,我们需要了解 Mahout 及其安装。在本章中,我们将探讨以下主题:

  • 什么是 Apache Mahout?

  • Mahout 支持的算法

  • 为什么它是分类问题的好选择?

  • 设置 Mahout 开发环境

介绍 Apache Mahout

Mahout 是指骑乘和控制大象的人。Apache Mahout 中的大多数算法都是在 Hadoop 之上实现的,Hadoop 是另一个 Apache 许可的项目,并以大象为标志 (hadoop.apache.org/)。由于 Apache Mahout 在 Hadoop 上运行,这个名字是合理的。

Apache Mahout 是 Apache 软件基金会的一个项目,它实现了机器学习算法。Mahout 于 2008 年作为 Apache Lucene 项目的子项目启动。经过一段时间,一个名为 Taste 的开源项目,该项目是为了协同过滤而开发的,后来被纳入 Mahout。Mahout 使用 Java 编写,并提供可扩展的机器学习算法。当数据太大而无法适应单个机器时,Mahout 是机器学习问题的默认选择。Mahout 提供了 Java 库,但不提供任何用户界面或服务器。它是一个开发者可以使用和适应的工具框架。

介绍 Apache Mahout

总结来说,Mahout 为你在分类、聚类和推荐领域的常用机器学习算法提供了实现。它不是让我们花时间编写算法,而是提供了现成的解决方案。

Mahout 使用 Hadoop 来实现其算法,但其中一些算法也可以在没有 Hadoop 的情况下运行。目前,Mahout 支持以下用例:

  • 推荐:这会根据用户数据尝试预测用户可能喜欢的项目。在这个用例中,你可以看到所有向用户销售商品的网站。基于你的先前行为,他们会尝试找出可能有用的未知项目。一个例子可以是:当你从亚马逊选择一些书籍时,网站会显示一系列其他书籍,标题为 Customers Who Bought This Item Also Bought。它还会显示标题,What Other Items Do Customers Buy After Viewing This Item? 推荐的另一个例子是在 YouTube 上播放视频时,根据你的选择推荐你听一些其他视频。Mahout 提供了完整的 API 支持来开发你自己的基于用户或基于项目的推荐引擎。

  • 分类:如前一章所述,分类决定一个项目属于特定类别多少。用于过滤垃圾邮件的电子邮件分类是分类的一个经典例子。Mahout 提供了一套丰富的 API 来构建自己的分类模型。例如,可以使用 Mahout 构建文档分类器或电子邮件分类器。

  • 聚类:这是一种试图根据某种相似性将项目分组的技术。在这里,我们根据某些属性找到不同的项目簇,我们事先不知道簇的名称。聚类与分类的主要区别在于,在分类中,我们知道最终类别的名称。聚类在找出不同的客户细分市场时很有用。Google News 使用聚类技术来分组新闻。对于聚类,Mahout 已经实现了该领域最流行的算法,如 k-means、模糊 k-means、canopy 等。

  • 降维:正如我们在上一章所讨论的,特征被称为维度。降维是减少考虑的随机变量数量的过程。这使得数据易于使用。Mahout 提供了降维算法。奇异值分解和 Lanczos 是 Mahout 提供的算法示例。

  • 主题建模:主题建模用于捕捉文档的抽象思想。主题模型是一种将概率分布与每个文档的主题相关联的模型。鉴于一个文档是关于特定主题的,人们会期望某些词在文档中出现频率较高或较低。"足球"和"进球"将在关于体育的文档中出现的频率更高。潜在狄利克雷分配LDA)是主题建模的一个强大学习算法。在 Mahout 中,实现了 LDA 的塌陷变分贝叶斯。

Mahout 支持的算法

Mahout 中算法的实现可以分为两组:

  • 顺序算法:这些算法是顺序执行的,不使用 Hadoop 可扩展处理。它们通常是来自 Taste 的算法。例如:基于用户的协同过滤、逻辑回归、隐马尔可夫模型、多层感知器、奇异值分解。

  • 并行算法:这些算法可以使用 Hadoop 的 map 支持 PB 级的数据,从而减少并行处理。例如,随机森林、朴素贝叶斯、canopy 聚类、k-means 聚类、谱聚类等。

选择 Mahout 进行分类的原因

在机器学习系统中,您使用的数据越多,构建的系统就越准确。使用 Hadoop 进行可扩展性的 Mahout 在处理大型数据集方面远远领先于其他系统。随着训练集数量的增加,Mahout 的性能也会提高。如果训练示例的输入大小从 100 万增加到 1000 万,那么 Mahout 是一个很好的选择。

对于分类问题,增加训练数据是有益的,因为它可以提高模型的准确性。通常,随着数据集数量的增加,内存需求也会增加,算法会变慢,但 Mahout 的可扩展和并行算法在处理时间方面表现更好。每增加一台新机器都会减少训练时间并提供更高的性能。

安装 Mahout

现在我们来尝试这本书的稍微有点挑战性的部分:Mahout 的安装。根据常见经验,我总结出以下用户在安装前可能会遇到的问题或疑虑:

  • 我对 Maven 一无所知。我该如何编译 Mahout 构建?

  • 我该如何设置 Eclipse 以在 Mahout 中编写自己的程序?

  • 如何在 Windows 系统上安装 Mahout?

因此,我们将通过以下步骤安装 Mahout。每个步骤都是独立的。您可以选择以下任何一个:

  • 使用 Maven 构建 Mahout 代码

  • 使用 Eclipse 设置开发环境

  • 为 Windows 用户设置 Mahout

在任何步骤之前,以下是一些先决条件:

使用 Maven 从源代码构建 Mahout

Mahout 的构建和发布系统基于 Maven。

安装 Maven

  1. 创建文件夹/usr/local/maven,如下所示:

    mkdir /usr/local/maven
    
    
  2. 从 Maven 网站下载发行版apache-maven-x.y.z-bin.tar.gzmaven.apache.org/download.cgi),并将其移动到/usr/local/maven,如下所示:

    mv apache-maven-x.y.z-bin.tar.gz /usr/local/maven
    
  3. 解压到/usr/local/maven位置,如下所示:

    tar –xvf apache-maven-x.y.z-bin.tar.gz
    
  4. 编辑.bashrc文件,如下所示:

    export M2_HOME=/usr/local/apache-maven-x.y.z
    export M2=$M2_HOME/bin
    export PATH=$M2:$PATH
    
    

注意

对于 Eclipse IDE,转到帮助并选择安装新软件。点击添加按钮,在弹出的窗口中输入名称M2Eclipse,提供链接download.eclipse.org/technology/m2e/releases,然后点击确定

构建 Mahout 代码

默认情况下,Mahout 假定系统上已经安装了 Hadoop。Mahout 使用HADOOP_HOMEHADOOP_CONF_DIR环境变量来访问 Hadoop 集群配置。为了设置 Mahout,执行以下步骤:

  1. archive.apache.org/dist/mahout/0.9/位置下载 Mahout 分发文件 mahout-distribution-0.9-src.tar.gz

  2. 选择 Mahout 的安装目录(/usr/local/Mahout),并将下载的源文件放置在该文件夹中。解压源代码并确保文件夹包含 pom.xml 文件。以下是源代码的确切位置:

    tar -xvf  mahout-distribution-0.9-src.tar.gz
    
    
  3. 安装 Mahout Maven 项目,并在安装时跳过测试用例,操作如下:

    mvn install -Dmaven.test.skip=true
    
    
  4. ~/.bashrc 文件中设置 MAHOUT_HOME 环境变量,并更新 PATH 变量以包含 Mahout bin 目录:

    export MAHOUT_HOME=/user/local/mahout/mahout-distribution-0.9
    export PATH=$PATH:$MAHOUT_HOME/bin
    
    
  5. 要测试 Mahout 安装,执行命令:mahout。这将列出分发包内的可用程序,如下截图所示:

构建 Mahout 代码

使用 Eclipse 设置开发环境

对于此设置,您应该在系统上安装 Maven 和 Eclipse 的 Maven 插件。参考前面章节中解释的 安装 Maven 步骤。此设置可以按以下步骤完成:

  1. archive.apache.org/dist/mahout/0.9/位置下载 Mahout 分发文件 mahout-distribution-0.9-src.tar.gz 并解压:

    tar xzf mahout-distribution-0.9-src.tar.gz
    
    
  2. /usr/local/workspace 下创建一个名为 workspace 的文件夹,操作如下:

    mkdir /usr/local/workspace
    
    
  3. 将下载的分发文件移动到该文件夹(从下载文件夹),操作如下:

    mv mahout-distribution-0.9 /usr/local/workspace/
    
    
  4. 移动到 /usr/local/workspace/mahout-distribution-0.9 文件夹并创建一个 Eclipse 项目(此命令可能需要一个小时):

    mvn eclipse:eclipse
    
    
  5. .bashrc 文件中设置 Mahout home,如前面 构建 Mahout 代码 部分所述。

  6. 现在,打开 Eclipse。选择文件,导入 Maven,并选择 Existing Maven Projects。现在,导航到 mahout-distribution-0.9 的位置并点击 Finish使用 Eclipse 设置开发环境

为 Windows 用户设置 Mahout

Windows 用户可以使用 Cygwin(一个包含大量 GNU 和开源工具的集合,在 Windows 上提供类似于 Linux 分发的功能)来设置他们的环境。还有另一种简单易用的方式,如下步骤所示:

  1. hortonworks.com/products/hortonworks-sandbox/#install位置下载适用于虚拟盒子的 Hortonworks Sandbox。您的系统上的 Hortonworks Sandbox 将是 Hadoop 的伪分布式模式。

  2. 登录到控制台。使用 Alt + F5 或作为替代,下载 Putty 并提供 127.0.0.1 作为主机名和 2222 作为端口号,如图所示。使用用户名 root 和密码 -hadoop 登录。为 Windows 用户设置 Mahout

  3. 输入以下命令:

    yum install mahout
    
    

    现在,您将看到如下屏幕:

    为 Windows 用户设置 Mahout

  4. 输入y,你的 Mahout 将开始安装。一旦完成,你可以通过输入命令mahout来测试,这将显示与之前看到的使用 Eclipse 设置开发环境食谱中相同的屏幕。

摘要

在本章中,我们详细讨论了 Apache Mahout。我们涵盖了在系统上安装 Mahout 的过程,以及设置一个准备好执行 Mahout 算法的开发环境。我们还探讨了为什么 Mahout 被认为是分类的良好选择的原因。现在,我们将进入下一部分,我们将了解逻辑回归,并学习在 Mahout 中执行第一个算法需要遵循的过程。

第三章。使用 Mahout 学习逻辑回归/SGD

在直接跳入逻辑回归之前,让我们先尝试理解其几个概念。在本章中,我们将探讨以下主题:

  • 介绍回归

  • 理解线性回归

  • 成本函数

  • 梯度下降

  • 逻辑回归

  • 理解 SGD

  • 使用 Mahout 进行逻辑回归

介绍回归

回归分析用于预测和预测。它用于找出解释变量和目标变量之间的关系。本质上,它是一个用于找出数据集中变量之间关系的统计模型。为了更好地理解这个术语,你可以参考以下例子:确定特定行业中工人的收入。在这里,我们将试图找出影响工人工资的因素。这些因素可以是年龄、教育、工作经验年数、特定的技能组合、位置等等。我们将尝试构建一个模型,考虑所有这些变量,并尝试预测工资。在回归分析中,我们描述目标变量围绕回归函数的变化,这可以通过一个也是感兴趣的概率分布来描述。有许多回归分析技术可供选择。例如,线性回归、普通最小二乘回归、逻辑回归等等。

理解线性回归

在线性回归中,我们创建一个模型,通过解释变量来预测目标变量的值。为了更好地理解这一点,让我们来看一个例子。

一家名为 X 的公司从事咖啡销售,注意到在雨季期间,他们的销售额大幅增加。因此,他们提出了一种公式来找出雨量和每杯咖啡销售额之间的关系,如下所示:

C = 1.5R+800

因此,对于 2 毫米的降雨量,咖啡的需求量为 803 杯。现在,如果你深入到细节中,你会意识到我们有了降雨量和每杯咖啡销售额的数据,我们正在尝试构建一个模型,可以根据降雨量预测咖啡的需求。我们的数据形式为 (R1, C1), (R2, C2)…. (Ri, Ci)。在这里,我们将以使实际值和预测值之间的误差最小化的方式构建模型。

成本函数

在方程 C = 1.5R+800 中,两个值 1.5 和 800 是参数,这些值会影响最终结果。我们可以将此方程写成 C= p0+p1R。正如我们之前讨论的,我们的目标是减少实际值和预测值之间的差异,这取决于 p0p1 的值。让我们假设预测值为 Cp,实际值为 C,这样差异将是 (Cp-C)。为了最小化这个误差,我们定义了一个误差函数,这也就是所谓的成本函数

成本函数可以用以下公式定义:

成本函数

在这里,i是第 i 个样本,N是训练样本的数量。我们计算不同组p0p1的成本,并最终选择成本最低的p0p1C)。这是将用于对新输入进行预测的模型。

梯度下降

梯度下降从一组初始参数值开始,p0p1,并通过迭代移动到一组使成本函数最小化的参数值。我们可以通过图形化地可视化这个误差函数,其中宽度和长度可以被认为是参数p0p1,高度是成本函数。我们的目标是找到p0p1的值,使得我们的成本函数最小。我们以p0p1的一些值开始算法,并通过迭代工作以达到最小值。确保梯度下降正确工作的一种好方法是确保成本函数在每次迭代中都会降低。在这种情况下,成本函数表面是凸的,我们将尝试找到最小值。这可以在以下图中看到:

梯度下降

逻辑回归

逻辑回归用于确定事件发生的概率。通常,逻辑回归指的是结果为二元的概率问题,例如,在构建基于客户收入、旅行用途、性别和其他特征的模型来预测他或她是否会购买特定汽车的问题。因此,答案将是简单的“是”或“否”。当结果由多个类别组成时,这被称为多项式逻辑回归

逻辑回归基于sigmoid 函数。预测变量与线性权重结合后传递到该函数,该函数生成 0 到 1 范围内的输出。输出接* 1 表示某个项目属于某个特定类别。让我们首先了解 sigmoid 或逻辑函数。它可以由以下公式定义:

F (z) = 1/(1+e^(-z))

对于一个解释变量z,它将被定义为z = β0 + β1x*。这个方程可以这样解释:

  • z: 这被称为因变量。这是我们想要预测的变量。在创建模型的过程中,我们在训练集中拥有这个变量,并构建模型来预测这个变量。z 的已知值被称为观测值。

  • x: 这是指解释变量或独立变量。这些变量用于预测因变量 z。例如,为了预测在特定地点新推出的产品的销售额,我们可能包括解释变量,如产品的价格、该地点人们的*均收入等。

  • β0:这被称为回归截距。如果所有解释变量都为零,则此参数等于因变量 z。

  • β1:这些是每个解释变量的值。

对数逻辑函数的图像如下:

逻辑回归

通过一点数学,我们可以将此方程式修改如下:

ln(F(x)/(1-F(x))) = β0 + β1x*

在线性回归的情况下,成本函数图是凸的,但在这里,它将不会是凸的。以使我们的预测输出接*实际值的方式找到参数的最小值将很困难。在成本函数中,计算逻辑回归时,我们将线性回归的Cp值替换为函数F(z)。为了使对数逻辑回归成本函数凸,我们将(p0+p1Ri-Ci)2替换为以下之一:

  • log (1/1+e (-(β0 + β1x)))* 如果事件的实际发生为 1,此函数将表示成本。

  • log (1-(1/1+e (-(β0 + β1x))))* 如果事件的实际发生为 0,此函数将表示成本。

我们必须记住,在逻辑回归中,我们计算类概率。因此,如果事件发生的概率(客户购买汽车、被骗等)为p,则不发生的概率为1-p

随机梯度下降

梯度下降法最小化成本函数。对于非常大的数据集,梯度下降是一个非常昂贵的程序。随机梯度下降(SGD)是对梯度下降算法的一种修改,用于处理大型数据集。梯度下降使用整个数据集来计算梯度,而 SGD 使用单个样本来计算梯度。因此,梯度下降加载整个数据集并试图在图上找到局部最小值,然后再次重复整个过程,而 SGD 则逐个调整每个样本的成本函数。SGD 相对于梯度下降的一个主要优势是其计算速度要快得多。在 RAM 中通常无法容纳大型数据集,因为存储是有限的。在 SGD 中,对 RAM 的负担减轻了,其中每个样本或样本批次被加载并处理,其结果被存储,等等。

使用 Mahout 进行逻辑回归

Mahout 提供了使用 SGD 进行逻辑回归的实现。它非常易于理解和使用。因此,让我们开始吧。

数据集

我们将使用威斯康星诊断乳腺癌WDBC)数据集。这是一个乳腺癌肿瘤数据集,数据从 1995 年开始可用。它有 569 个乳腺癌病例实例,有 30 个特征来预测诊断,这些诊断被分类为良性或恶性。

注意

关于前面数据集的更多详细信息,请参阅archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.names

准备训练和测试数据

您可以从archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data下载wdbc.data数据集。

现在,将其保存为 CSV 文件,并包含以下标题行:

ID_Number,Diagnosis,Radius,Texture,Perimeter,Area,Smoothness,Compactness,Concavity,ConcavePoints,Symmetry,Fractal_Dimension,RadiusStdError,TextureStdError,PerimeterStdError,AreaStdError,SmoothnessStdError,CompactnessStdError,ConcavityStdError,ConcavePointStdError,Symmetrystderror,FractalDimensionStderror,WorstRadius,worsttexture,worstperimeter,worstarea,worstsmoothness,worstcompactness,worstconcavity,worstconcavepoints,worstsymmentry,worstfractaldimensions

现在,我们必须执行以下步骤来准备这些数据,以便由 Mahout 逻辑回归算法使用:

  1. 我们将目标类别转换为数值。在这种情况下,第二个字段诊断是目标变量。我们将恶性标记为 0,良性标记为 1。使用以下代码片段介绍这些更改。对于小型数据集,我们可以使用这种策略,但对于大型数据集,我们有不同的策略,这些策略将在第四章中介绍,使用 Mahout 学习朴素贝叶斯分类

    public void convertTargetToInteger() throws IOException{
      //Read the data
      BufferedReader br = new BufferedReader(new FileReader("wdbc.csv"));
      String line =null;
      //Create the file to save the resulted data
      File wdbcData = new File("<Your Destination location for file.>");
      FileWriter fw = new FileWriter(wdbcData);
      //We are adding header to the new file
      fw.write("ID_Number"+","+"Diagnosis"+","+"Radius"+","+"Texture"+","+"Perimeter"+","+"Area"+","+"Smoothness"+","+"Compactness"+","+"Concavity"+","+"ConcavePoints"+","+"Symmetry"+","+"Fractal_Dimension"+","+"RadiusStdError"+","+"TextureStdError"+","+"PerimeterStdError"+","+"AreaStdError"+","+"SmoothnessStdError"+","+"CompactnessStdError"+","+"ConcavityStdError"+","+"ConcavePointStdError"+","+"Symmetrystderror"+","+"FractalDimensionStderror"+","+"WorstRadius"+","+"worsttexture"+","+"worstperimeter"+","+"worstarea"+","+"worstsmoothness"+","+"worstcompactness"+","+"worstconcavity"+","+"worstconcavepoints"+","+"worstsymmentry"+","+"worstfractaldimensions"+"\n");
    
      /*In the while loop we are reading line by line and checking the last field- parts[1] and changing it to numeric value accordingly*/
      while((line=br.readLine())!=null){
        String []parts = line.split(",");
        if(parts[1].equals("M")){
        fw.write(parts[0]+","+"0"+","+parts[2]+","+parts[3]+","+parts[4]+","+parts[5]+","+parts[6]+","+parts[7]+","+parts[8]+","+parts[9]+","+parts[10]+","+parts[11]+","+parts[12]+","+parts[13]+","+parts[14]+","+parts[15]+","+parts[16]+","+parts[17]+","+parts[18]+","+parts[19]+","+parts[20]+","+parts[21]+","+parts[22]+","+parts[23]+","+parts[24]+","+parts[25]+","+parts[26]+","+parts[27]+","+parts[28]+","+parts[29]+","+parts[30]+","+parts[31]+"\n");
        }
    
        if(parts[1].equals("B")){
          fw.write(parts[0]+","+"1"+","+parts[2]+","+parts[3]+","+parts[4]+","+parts[5]+","+parts[6]+","+parts[7]+","+parts[8]+","+parts[9]+","+parts[10]+","+parts[11]+","+parts[12]+","+parts[13]+","+parts[14]+","+parts[15]+","+parts[16]+","+parts[17]+","+parts[18]+","+parts[19]+","+parts[20]+","+parts[21]+","+parts[22]+","+parts[23]+","+parts[24]+","+parts[25]+","+parts[26]+","+parts[27]+","+parts[28]+","+parts[29]+","+parts[30]+","+parts[31]+"\n");
        }
      }
      fw.close();
      br.close();
    }
    

    提示

    下载示例代码

    您可以从您在www.packtpub.com的账户下载所有已购买的 Packt Publishing 书籍的示例代码文件。如果您在其他地方购买了此书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

  2. 我们必须将数据集拆分为训练集和测试集,然后对数据集进行洗牌,以便我们可以混合它们,这可以通过以下代码片段完成:

    public void dataPrepration() throws Exception {
      // Reading the dataset created by earlier method convertTargetToInteger and here we are using google guava api's.
      List<String> result = Resources.readLines(Resources.getResource("wdbc.csv"), Charsets.UTF_8);
      //This is to remove header before the randomization process. Otherwise it can appear in the middle of dataset.
      List<String> raw = result.subList(1, 570);
      Random random = new Random();
      //Shuffling the dataset.
      Collections.shuffle(raw, random);
      //Splitting dataset into training and test examples.
      List<String> train = raw.subList(0, 470);
      List<String> test = raw.subList(470, 569);
      File trainingData = new File("<your Location>/ wdbcTrain.csv");
      File testData = new File("<your Location>/ wdbcTest.csv");
      writeCSV(train, trainingData);
      writeCSV(test, testData);
    }
    //This method is writing the list to desired file location.
    public void writeCSV(List<String> list, File file) throws IOException{
      FileWriter fw = new FileWriter(file);
      fw.write("ID_Number"+","+"Diagnosis"+","+"Radius"+","+"Texture"+","+"Perimeter"+","+"Area"+","+"Smoothness"+","+"Compactness"+","+"Concavity"+","+"ConcavePoints"+","+"Symmetry"+","+"Fractal_Dimension"+","+"RadiusStdError"+","+"TextureStdError"+","+"PerimeterStdError"+","+"AreaStdError"+","+"SmoothnessStdError"+","+"CompactnessStdError"+","+"ConcavityStdError"+","+"ConcavePointStdError"+","+"Symmetrystderror"+","+"FractalDimensionStderror"+","+"WorstRadius"+","+"worsttexture"+","+"worstperimeter"+","+"worstarea"+","+"worstsmoothness"+","+"worstcompactness"+","+"worstconcavity"+","+"worstconcavepoints"+","+"worstsymmentry"+","+"worstfractaldimensions"+"\n");
      for(int i=0;i< list.size();i++){
        fw.write(list.get(i)+"\n");
      }
      fw.close();
    }
    

训练模型

我们将使用训练数据集和 trainlogistic 算法来准备模型。使用以下命令创建模型:

mahout trainlogistic --input /tmp/wdbcTrain.csv --output /tmp//model --target Diagnosis --categories 2 --predictors Radius Texture Perimeter Area Smoothness Compactness Concavity ConcavePoints Symmetry Fractal_Dimension RadiusStdError TextureStdError PerimeterStdError AreaStdError SmoothnessStdError CompactnessStdError ConcavityStdError ConcavePointStdError Symmetrystderror FractalDimensionStderror WorstRadius worsttexture worstperimeter worstarea worstsmoothness worstcompactness worstconcavity worstconcavepoints worstsymmentry worstfractaldimensions  --types numeric --features 30 --passes 90 --rate 300

此命令将给出以下输出:

使用 Mahout 进行逻辑回归

让我们了解此命令中使用的参数:

  • trainlogistic:这是 Mahout 提供的算法,用于使用您的输入参数构建模型。

  • input:这是输入文件的位置。

  • output:这是模型文件的位置。

  • target:这是我们想从数据集中预测的目标变量的名称。

  • categories:这是预测类别的数量。

  • predictors:这是数据集中用于预测目标变量的特征。

  • types:这是一系列预测变量类型。(这里所有都是数值型,但也可能是单词或文本。)

  • features:这是构建模型使用的特征向量的大小。

  • passes: 这指定了在训练过程中输入数据应该被重新检查的次数。小输入文件可能需要检查数十次。非常大的输入文件甚至可能不需要完全检查。

  • rate: 这设置初始学习率。如果你有很多数据或使用了多次遍历,它可能很大,因为它随着数据的检查而逐渐减少。

现在我们模型已经准备好进入评估的下一步。为了进一步评估模型,我们可以使用相同的数据集并检查混淆和 AUC 矩阵。此命令如下:

mahout runlogistic --input /tmp/wdbcTrain.csv --model /tmp//model  --auc --confusion

  • runlogistic: 这是运行逻辑回归模型在输入数据集上的算法

  • model: 这是模型文件的位置

  • auc: 在读取数据后,这会打印模型与输入数据的 AUC 分数

  • confusion: 这将打印特定阈值下的混淆矩阵

上一条命令的输出显示在下图中:

使用 Mahout 进行逻辑回归

现在,这些矩阵显示模型表现不错。AUC 的值为 0.88 是好的,但我们也会在测试数据上检查这一点。混淆矩阵告诉我们,在 172 个恶性肿瘤中,它正确分类了 151 个实例,并且 34 个良性肿瘤也被错误地分类为恶性。在良性肿瘤的情况下,在 298 个中,它正确分类了 264 个。

如果模型没有提供良好的结果,我们有多种选择。

改变特征向量的参数,如果我们正在选择少量特征,则增加它们。这应该一次只做一次,并且我们应该用每个生成的模型再次测试结果。我们应该得到一个 AUC 接* 1 的模型。

让我们在测试数据上也运行相同的算法:

mahout runlogistic --input /tmp/wdbcTest.csv --model /tmp//model  --auc –confusion

使用 Mahout 进行逻辑回归

因此,这个模型在测试数据上也几乎表现相同。它正确分类了 40 个恶性肿瘤中的 34 个。

摘要

在本章中,我们讨论了逻辑回归以及我们如何使用 Apache Mahout 中可用的此算法。我们使用了威斯康星诊断乳腺癌数据集,并将其随机分为两个数据集:一个用于训练,另一个用于测试。我们使用 Mahout 创建了逻辑回归模型,并在此模型上运行了测试数据。现在,我们将进入下一章,你将学习关于朴素贝叶斯分类以及最常用的分类技术:文本分类。

第四章:使用 Mahout 学习朴素贝叶斯分类

在本章中,我们将使用朴素贝叶斯分类算法对一组文档进行分类。由于涉及到的数据准备步骤,对文本文档进行分类有点棘手。在本章中,我们将探讨以下主题:

  • 条件概率和贝叶斯定理

  • 理解朴素贝叶斯算法

  • 理解文本分类中使用的术语

  • 在 Apache Mahout 中使用朴素贝叶斯算法

介绍条件概率和贝叶斯定理

在学习朴素贝叶斯算法之前,你应该了解条件概率和贝叶斯定理。

简单来说,条件概率是在已知另一件事情已经发生的情况下,某件事情发生的概率。它表示为 P(A/B),可以读作在 B 的条件下 A 的概率,它找出在事件 B 已经发生的情况下事件 A 发生的概率。

从数学上定义如下:

介绍条件概率和贝叶斯定理

例如,如果你从一副标准的扑克牌中抽取一张牌,如果有人问你这张牌是红桃的概率,你会很快回答 13/52 或 0.25,因为牌中有 13 张红桃牌。然而,如果你然后查看这张牌并宣布它是红色的,那么我们将把这张牌的可能性缩小到 26 张可能的牌,这张牌是红桃的概率现在是 13/26 = 0.5。所以,如果我们定义 A 为红桃牌,B 为红牌,那么 P(A/B) 将是已知这张牌是红色的条件下,这张牌是红桃的概率。

有时,对于给定的一对事件,条件概率难以计算,而贝叶斯定理通过给出两个条件概率之间的关系来帮助我们。

贝叶斯定理定义为如下:

介绍条件概率和贝叶斯定理

公式中的术语定义如下:

  • P(A): 这被称为先验概率或先验

  • P(B/A): 这被称为条件概率或似然

  • P(B): 这被称为边缘概率

  • P(A/B): 这被称为后验概率或后验

以下公式仅从条件概率公式推导而来。我们可以定义 P(B/A) 如下:

介绍条件概率和贝叶斯定理

重新排列后,公式变为:

介绍条件概率和贝叶斯定理

现在,从先前的条件概率公式中,我们得到以下:

介绍条件概率和贝叶斯定理

让我们举一个例子,这个例子将帮助我们理解贝叶斯定理是如何应用的。

当患者确实受到癌症影响时,癌症测试以 97%的概率给出阳性结果,而当患者未受到影响时,以 99%的概率给出阴性结果。如果从一个人群中随机抽取一个患者,该人群中 0.2%的人受到癌症影响,并且他被发现是阳性的,那么他或她确实受到癌症影响的概率是多少?在概率论中,我们关于这个问题的了解可以定义为以下内容:

P (阳性|癌症) = 0.97

P (阳性|无癌症) = 1-0.99 = 0.01

P (癌症) = 0.002

P (无癌症) = 1-0.002= 0.998

P (阳性) = P (阳性|癌症) P (癌症) + P (阳性|无癌症) P (无癌症)

= 0.970.002 + 0.010.998

= 0.01192

现在 P (癌症|阳性) = (0.970.002)/0.01192 = 0.1628*

因此,即使发现阳性,在这个例子中,患者受到癌症影响的概率大约是 16%。

理解朴素贝叶斯算法

在贝叶斯定理中,我们了解到结果仅基于一个证据,但在分类问题中,我们有多个证据,并且我们必须预测结果。在朴素贝叶斯中,我们解耦多个证据,并独立地处理每一个。它定义如下:

P (结果 | 多个证据) ) = P (证据 1|结果) P (证据 2|结果)* P (证据 3|结果) …… /P (证据)*

对每个可能的结果运行这个公式。由于我们正在尝试分类,每个结果都将被称为一个类别。我们的任务是查看证据(特征)以考虑它属于特定类别的可能性,然后相应地分配。具有最高概率的类别将被分配给该组合的证据。让我们用一个例子来理解这一点。

假设我们有关于 1000 件水果的数据。它们可能是香蕉、苹果或其他水果。我们知道每件水果的三个特征:

  • 大小:它们要么是长,要么不是长

  • 味道:它们要么是甜的,要么不是甜的

  • 颜色:它们要么是黄色,要么不是黄色

假设我们有一个如下所示的数据集:

水果类型 味道 – 甜 味道 – 不甜 颜色 – 黄色 颜色 – 非黄色 大小 – 长 大小 – 非长 总计
香蕉 350 150 450 50 400 100 500
苹果 150 150 100 200 0 300 300
其他 150 50 50 150 100 100 200
总计 650 350 600 400 500 500 1000

现在我们来看看我们拥有的东西:

P (香蕉) = 500/1000 = 0.5

P (苹果) = 300/1000 = 0.3

P (其他) = 200/1000 = 0.2

让我们看看特征的概率:

P (甜) = 650/1000 = 0.65

P (黄色) = 600/1000 = 0.6

P (长) = 500/1000 = 0.5

P (非甜) = 350/1000 = 0.35

P (非黄色) = 400/1000= 0.4

P (非长) = 500/1000 = 0.5

现在我们想知道如果它既不黄也不长也不甜,我们将有什么水果。它成为苹果的概率如下:

P (Apple| sweet, not long, not yellow) = P (sweet | Apple) P (not long | Apple)* P (not yellow | Apple)P (Apple)/P (sweet) P (not long) P (not yellow)

= 0.510.670.3/P (证据)*

= 0.1005/P (证据)

它成为香蕉的概率如下:

P (banana| sweet, not long, not yellow) = P (sweet | banana) P (not long | banana)* P (not yellow | banana)P (banana)/P (sweet) P (not long) P (not yellow)

= 0.70.20.10.5/P (证据)*

= 0.007/P (证据)

它成为任何其他水果的概率如下:

P (other fruit| sweet, not long, not yellow) = P (sweet | other fruit) P (not long | other fruit)* P (not yellow | other fruit) P (other fruit)/P (sweet) P (not long) P (not yellow)

= 0.750.50.750.2/P (证据)*

= 0.05625/ P (证据)

因此,从结果中,你可以看到如果水果是甜的、不长的、不是黄色的,那么最高的概率是它将是一个苹果。所以找出最高的概率,并将未知项分配到那个类别。

Naïve Bayes 是文本分类的一个非常好的选择。在我们继续在 Mahout 中使用 Naïve Bayes 进行文本分类之前,让我们了解一些对文本分类非常有用的术语。

理解文本分类中使用的术语

准备数据以便它可以被分类器使用是一个复杂的过程。从原始数据中,我们可以收集解释变量和目标变量并将它们编码为 向量,这是分类器的输入。

向量是有序的值列表,如定义在二维空间中。你也可以从坐标几何中得到线索。点 (3, 4) 是 x 和 y *面上的一个点。在 Mahout 中,情况不同。在这里,一个向量可以有 (3, 4) 或 10,000 个维度。

Mahout 提供了创建向量的支持。在 Mahout 中有两种类型的向量实现:稀疏向量和密集向量。对于文本分类,我们需要了解一些术语:

  • 词袋模型:这把每个文档视为单词的集合。它忽略了单词顺序、语法和标点符号。因此,如果每个单词都是一个特征,那么计算文档单词的特征值就表示为一个标记。如果存在,则赋予其值 1,如果不存在,则赋予其值 0。

  • 词频:这考虑了文档中的单词计数而不是 0 和 1。因此,单词的重要性随着它在文档中出现的次数而增加。考虑以下示例句子:

    苹果已经推出了 iPhone,它将继续推出类似的产品。其他竞争对手也在计划推出类似 iPhone 的产品。

以下表示词频的表格:

术语 数量
Apple 1
启动 3
iPhone 2
产品 2
计划 1

以下技术通常用于生成此类表格:

  • 词干提取:这样,从单词中移除了后缀,所以"launched"、"launches"和"launch"都被视为"launch"。

  • 案例归一化:这样,每个术语都被转换为小写。

  • 停用词去除:有一些词几乎出现在每个文档中。我们称这些词为停用词。在从文档中提取重要特征时,这些词会被考虑,但它们对整体计算没有帮助。这些词的例子有"是、有、这、那个、等等"。所以,在提取时,我们将忽略这类词。

  • 逆文档频率:这被认为是术语因罕见而获得的提升。一个术语不应该太常见。如果一个术语出现在每个文档中,它对分类并不好。一个术语出现在的文档越少,它对其出现的文档的重要性可能就越大。对于一个术语 t,逆文档频率的计算如下:

    IDF(t) = 1 + log(总文档数/包含 t 的文档数)

  • 词频和逆文档频率:这是文本的流行表示之一。它是词频和逆文档频率的乘积,如下所示:

    TFIDF(t, d) = TF(t, d) * IDF(t)

每个文档都是一个特征向量,文档的集合是一组这些特征向量,这组向量作为分类的输入。现在我们已经了解了文本文档向量创建的基本概念,让我们继续到下一节,我们将使用朴素贝叶斯算法对文本文档进行分类。

在 Apache Mahout 中使用朴素贝叶斯算法

我们将使用 20 个新闻组的数据集来完成这个练习。20 个新闻组数据集是一个标准数据集,通常用于机器学习研究。数据来自 20 个 Usenet 新闻组在 20 世纪 90 年代初发布的几个月的帖子记录。这个数据集由消息组成,每个文件一个消息。每个文件以标题行开始,指定了诸如谁发送了消息、消息有多长、使用了什么软件以及主题等信息。随后是一个空行,然后是消息体,作为未格式化的文本。

qwone.com/~jason/20Newsgroups/下载20news-bydate.tar.gz数据集。以下步骤用于使用 Mahout 构建朴素贝叶斯分类器:

  1. 创建一个20newsdata目录并将数据解压到这里:

    mkdir /tmp/20newsdata
    cd /tmp/20newsdata
    tar –xzvf /tmp/20news-bydate.tar.gz
    
    
  2. 20newsdata: 20news-bydate-test20news-bydate-train下你会看到两个文件夹。现在创建另一个名为20newsdataall的目录,并将 20 个新闻组的训练数据和测试数据合并。

  3. 退出目录并移动到home目录,然后执行以下操作:

    mkdir /tmp/20newsdataall
    cp –R /20newsdata/*/* /tmp/20newsdataall
    
    
  4. 在 Hadoop 中创建一个目录并将这些数据以 HDFS 格式保存:

    hadoop fs –mkdir /user/hue/20newsdata
    hadoop fs –put /tmp/20newsdataall /user/hue/20newsdata
    
    
  5. 将原始数据转换为序列文件。seqdirectory命令将从目录生成序列文件。序列文件用于 Hadoop。序列文件是一个由二进制键/值对组成的*面文件。我们将文件转换为序列文件,以便在 Hadoop 中处理,可以使用以下命令完成:

    bin/mahout seqdirectory -i /user/hue/20newsdata/20newsdataall  -o /user/hue/20newsdataseq-out
    
    

    以下截图显示了前一个命令的输出:

    在 Apache Mahout 中使用 Naïve Bayes 算法

  6. 使用以下命令将序列文件转换为稀疏向量:

    bin/mahout seq2sparse -i /user/hue/20newsdataseq-out/part-m-00000 -o /user/hue/20newsdatavec -lnorm -nv -wt tfidf
    
    

    前一个命令中使用的术语如下:

    • lnorm:这表示输出向量要进行对数归一化

    • nv:这指的是命名向量

    • wt:这指的是要使用的权重类型;在这里,我们使用tfidf

    以下截图显示了在控制台上执行前一个命令的输出:

    在 Apache Mahout 中使用 Naïve Bayes 算法

  7. 将向量集分为训练集和测试集:

    bin/mahout split -i /user/hue/20newsdatavec/tfidf-vectors --trainingOutput /user/hue/20newsdatatrain --testOutput /user/hue/20newsdatatest --randomSelectionPct 40 --overwrite --sequenceFiles -xm sequential
    
    

    前一个命令中使用的术语如下:

    • randomSelectionPct:这会将数据百分比分为测试集和训练集。在这里,60%用于测试,40%用于训练。

    • xm:这指的是要使用的执行方法:顺序或 mapreduce。默认为mapreduce

    在 Apache Mahout 中使用 Naïve Bayes 算法

  8. 现在训练模型:

    bin/mahout trainnb -i /user/hue/20newsdatatrain -el -o /user/hue/model -li /user/hue/labelindex -ow -c
    
    
  9. 使用以下命令测试模型:

    bin/mahout testnb -i /user/hue/20newsdatatest -m /user/hue/model/ -l  /user/hue/labelindex -ow -o /user/hue/results
    
    

    以下截图显示了在控制台上执行前一个命令的输出:

    在 Apache Mahout 中使用 Naïve Bayes 算法

我们得到了针对 20 个新闻组的 Naïve Bayes 分类器的结果。

摘要

在本章中,我们讨论了 Naïve Bayes 算法。这是一种简单但备受推崇的统计模型,在工业和学术界都得到了广泛应用,并且在许多场合都产生了良好的结果。我们最初讨论了条件概率和贝叶斯定理。然后,我们看到了 Naïve Bayes 算法的一个示例。你学习了将文本转换为向量格式的各种方法,这是分类器的输入。最后,我们使用 20 个新闻组数据集,在 Mahout 中使用 Naïve Bayes 算法构建了一个分类器。在下一章中,我们将继续探索在 Mahout 中使用隐马尔可夫模型实现分类算法的旅程。

第五章. 使用 Mahout 学习隐马尔可夫模型

在本章中,我们将介绍分类技术中最有趣的主题之一:隐马尔可夫模型HMM)。为了理解 HMM,我们将在本章中介绍以下主题:

  • 确定性和非确定性模式

  • 马尔可夫过程

  • 介绍 HMM

  • 使用 Mahout 进行 HMM

确定性和非确定性模式

在确定性系统中,每个状态仅依赖于它之前的状态。例如,让我们以一组交通信号灯为例。灯光的序列是红色→绿色→黄色→红色。所以,在这里我们知道当前状态之后将是什么状态。一旦确定了转换,确定性系统就很容易理解。

对于非确定性模式,考虑一个名叫鲍勃的人,他每天下午 4:00 吃零食的例子。假设他从菜单上的三个选项中任选其一:冰淇淋、果汁或蛋糕。即使我们知道他今天吃什么,我们也无法确定他明天会吃什么。这是一个非确定性模式的例子。

马尔可夫过程

在马尔可夫过程中,下一个状态依赖于前面的状态。如果我们假设我们有一个n状态系统,那么下一个状态将依赖于前面的n个状态。这个过程被称为n阶模型。在马尔可夫过程中,我们以概率的方式选择下一个状态。所以,考虑到我们之前的例子,如果鲍勃今天喝了果汁,他明天可以喝果汁、冰淇淋或蛋糕。同样,我们可以从上一个状态达到系统中的任何状态。马尔可夫过程如下图中所示:

马尔可夫过程

如果一个过程中有n个状态,那么我们可以通过 n² 个转换达到任何状态。我们移动到任何状态的概率,因此我们将有 n² 个这样做概率。对于马尔可夫过程,我们将有以下三个项目:

  • 状态:这指的是系统中的状态。在我们的例子中,让我们假设有三个状态:状态 1、状态 2 和状态 3。

  • 转移矩阵:这将包含从一个状态移动到任何其他状态的概率。以下截图显示了转移矩阵的示例:马尔可夫过程

    这个矩阵显示,如果系统昨天处于状态 1,那么它今天保持同一状态的概率将是 0.1。

  • 初始状态向量:这是系统的初始状态向量。(在这个向量中,任何一个状态将有 1 的概率,其余状态将有 0 的概率。)马尔可夫过程

介绍隐马尔可夫模型

隐马尔可夫模型HMM)是一种分类技术,通过观察结果来预测系统的状态,而不需要访问实际的州本身。它是一个状态是隐藏的马尔可夫模型。

让我们继续之前看到的鲍勃的零食例子。现在假设我们有一个直接可观察的事件集。我们知道鲍勃吃了什么午餐,他的零食摄入量与他的午餐有关。因此,我们有一个观察状态,即鲍勃的午餐,以及隐藏状态,即他的零食摄入量。我们想要构建一个算法,可以根据鲍勃的午餐预测他选择的零食。

介绍隐马尔可夫模型

除了隐马尔可夫模型中的转移概率矩阵外,我们还有一个称为发射矩阵的矩阵。这个矩阵包含在分配了一个隐藏状态的情况下,可观察状态的概率。发射矩阵如下:

P (可观察状态 | 一个状态)

因此,隐马尔可夫模型具有以下属性:

  • 状态向量:这包含隐藏模型在开始时处于特定状态的概率

  • 转移矩阵:这包含给定前一个隐藏状态时隐藏状态的概率

  • 发射矩阵:给定隐藏模型处于特定隐藏状态,这包含观察特定可观察状态的概率

  • 隐藏状态:这指的是可以由隐马尔可夫模型定义的系统状态

  • 可观察状态:在过程中可见的状态

使用隐马尔可夫模型可以解决三种类型的问题。前两种与模式识别问题相关,第三种类型的问题是在给定一系列观察的情况下生成一个隐马尔可夫模型。让我们看看这三种类型的问题:

  • 评估:这是在给定一个隐马尔可夫模型(HMM)的情况下,找出观察序列的概率。从描述不同系统和一系列观察的不同隐马尔可夫模型的数量,我们的目标将是找出哪个 HMM 最有可能生成所需的序列。我们使用前向算法来计算当给定一个特定的 HMM 时观察序列的概率,并找出最可能的 HMM。

  • 解码:这是从某些观察中找到最可能的隐藏状态序列。当你有一系列观察和一个隐马尔可夫模型(HMM)时,我们使用维特比算法来确定最可能的隐藏状态序列。

  • 学习:学习是从一系列观察中生成 HMM。所以,如果我们有这样的序列,我们可能会想知道哪个模型最有可能生成这个序列。前向-后向算法在解决这个问题时很有用。

隐马尔可夫模型被用于不同的应用,如语音识别、手写字母识别、基因组分析、词性标注、客户行为建模等。

使用 Mahout 进行隐马尔可夫模型

Apache Mahout 有隐马尔可夫模型的实现。它位于 org.apache.mahout.classifier.sequencelearning.hmm 包中。

整体实现由八个不同的类提供:

  • HMMModel: 这是定义隐马尔可夫模型的主要类。

  • HmmTrainer: 这个类有用于训练隐马尔可夫模型的算法。主要算法包括监督学习、无监督学习和无监督 Baum-Welch。

  • HmmEvaluator: 这个类提供了评估 HMM 模型的不同方法。以下用例包含在这个类中:

    • 从模型(预测)生成输出状态的序列

    • 计算给定模型生成给定输出状态序列的概率(模型似然)

    • 计算给定模型和给定观察序列的最可能隐藏序列(解码)

  • HmmAlgorithms: 这个类包含三个主要 HMM 算法的实现:前向、后向和维特比。

  • HmmUtils: 这是一个实用类,提供处理 HMM 模型对象的方法。

  • RandomSequenceGenerator: 这是一个命令行工具,可以根据给定的 HMM 生成序列。

  • BaumWelchTrainer: 这是一个从控制台训练 HMM 的类。

  • ViterbiEvaluator: 这也是一个用于维特比评估的命令行工具。

现在,让我们用鲍勃的例子来操作。

以下是一个给定的矩阵和初始概率向量:

冰淇淋 蛋糕 果汁
0.36 0.51 0.13

以下将是状态转移矩阵:

冰淇淋 蛋糕 果汁
冰淇淋 0.365 0.500 0.135
蛋糕 0.250 0.125 0.625
果汁 0.365 0.265 0.370

以下将是发射矩阵:

辣食 正常食物 没有食物
冰淇淋 0.1 0.2 0.7
蛋糕 0.5 0.25 0.25
果汁 0.80 0.10 0.10

现在,我们将执行这个问题的基于命令行的示例。鲍勃吃零食的三个隐藏状态:冰淇淋、蛋糕或果汁。然后,我们有三个可观察状态,即他在午餐时吃什么:辣食、正常食物或完全不吃。现在,以下是从命令行执行的步骤:

  1. 创建一个名为hmm的目录:mkdir /tmp/hmm。进入此目录并创建观察状态的样本输入文件。这将包括鲍勃午餐习惯的序列:辣食(状态 0)、正常食物(状态 1)和没有食物(状态 2)。执行以下命令:

    echo "0 1 2 2 2 1 1 0 0 2 1 2 1 1 1 1 2 2 2 0 0 0 0 0 0 2 2 2 0 0 0 0 0 0 1 1 1 1 2 2 2 2 2 0 2 1 2 0 2 1 2 1 1 0 0 0 1 0 1 0 2 1 2 1 2 1 2 1 1 0 0 2 2 0 2 1 1 0" > hmm-input
    
    
  2. 使用以下命令运行 BaumWelch 算法来训练模型:

    mahout baumwelch -i /tmp/hmm/hmm-input -o /tmp/hmm/hmm-model -nh 3 -no 3 -e .0001 -m 1000
    
    

    在前面的命令中使用的参数如下:

    • i: 这是输入文件的位置

    • o: 这是模型的输出位置

    • nh: 这是隐藏状态的数量。在我们的例子中,它是三个(冰淇淋、果汁或蛋糕)

    • no: 这是可观察状态的数量。在我们的例子中,它是三个(辣的、正常的或没有食物)

    • e: 这是 epsilon 数值。这是收敛阈值值

    • m: 这是最大迭代次数

    以下截图显示了执行上一个命令的输出:

    使用 Mahout 进行隐马尔可夫模型

  3. 现在我们有一个 HMM 模型,可以用来构建预测序列。我们将运行该模型,使用以下命令预测可观测序列的下一个 15 个状态:

    mahout hmmpredict -m /tmp/hmm/hmm-model -o /tmp/hmm/hmm-predictions -l 10
    
    

    上述命令中使用的参数如下:

    m:这是 HMM 模型的路径

    o:这是输出目录路径

    l:这是生成的序列长度

  4. 要查看下一个 10 个可观测状态的预测,请使用以下命令:

    mahout hmmpredict -m /tmp/hmm/hmm-model -o /tmp/hmm/hmm-predictions -l 10
    
    

    上述命令的输出如下截图所示:

    使用 Mahout 进行隐马尔可夫模型

    从输出中,我们可以得出结论,Bob 的午餐下一个可观测状态将是辣的,辣的,辣的,正常,正常,没有食物,没有食物,没有食物,没有食物,以及没有食物。

  5. 现在,我们将使用另一个算法来预测隐藏状态。我们将使用 Viterbi 算法来预测给定观测状态序列的隐藏状态。我们将首先使用以下命令创建观测状态的序列:

    echo "0 1 2 0 2 1 1 0 0 1 1 2" > /tmp/hmm/hmm-viterbi-input
    
    
  6. 我们将使用 Viterbi 命令行选项来生成具有生成此序列似然值的输出:

    mahout viterbi --input /tmp/hmm/hmm-viterbi-input --output tmp/hmm/hmm-viterbi-output --model /tmp/hmm/hmm-model --likelihood
    
    

    上述命令中使用的参数如下:

    • input:这是文件的输入位置

    • output:这是 Viterbi 算法输出的输出位置

    • model:这是我们之前创建的 HMM 模型位置

    • likelihood:这是计算出的观测序列的似然值

    以下截图显示了执行上述命令的输出:

    使用 Mahout 进行隐马尔可夫模型

  7. Viterbi 的预测结果保存在输出文件中,可以使用 cat 命令查看:

    cat /tmp/hmm/hmm-viterbi-output
    
    

    以下输出显示了隐藏状态的预测:

    使用 Mahout 进行隐马尔可夫模型

摘要

在本章中,我们讨论了另一种分类技术:隐马尔可夫模型。你学习了确定性和非确定性模式。我们还简要介绍了马尔可夫过程和隐马尔可夫过程。我们检查了 Mahout 中实现以支持隐马尔可夫模型的类。我们举了一个例子来创建 HMM 模型,并进一步使用此模型来预测观测状态序列。我们使用了 Mahout 中实现的 Viterbi 算法来预测系统中的隐藏状态。

现在,在下一章中,我们将介绍分类领域中使用的另一个有趣的算法:随机森林。

第六章. 使用 Mahout 学习随机森林

随机森林是分类中最受欢迎的技术之一。它从一个称为决策树的机器学习技术开始。在本章中,我们将探讨以下主题:

  • 决策树

  • 随机森林

  • 使用 Mahout 进行随机森林

决策树

决策树用于分类和回归问题。简单来说,它是一个使用二元规则计算目标变量的预测模型。在决策树中,我们使用迭代过程将数据分割成分区,然后在分支上进一步分割。与其他分类模型创建过程一样,我们从定义目标变量或类标签的训练数据集开始。算法试图根据一个解释变量将训练数据集中的所有记录分成两部分。然后将分区应用于每个新的分区,这个过程一直持续到不能再进行分区为止。算法的核心是找出决定初始分割的规则。有创建决策树的算法,例如迭代二分器 3ID3)、分类和回归树CART)、卡方自动交互检测器CHAID)等。可以在www.cse.unsw.edu.au/~billw/cs9414/notes/ml/06prop/id3/id3.html找到对 ID3 的良好解释。

在节点中选择最佳分割器的解释变量形成过程中,算法依次考虑每个变量。考虑并尝试了所有可能的分割,最佳分割是产生每个分区中分类标签多样性最大减少的那个分割。这个过程对所有变量重复进行,胜出的变量被选为该节点的最佳分割器。这个过程在下一个节点中继续,直到我们达到一个可以做出决策的节点。

我们从训练数据集中创建决策树,因此它可能会出现过拟合问题。这种行为在真实数据集中造成问题。为了改善这种情况,使用了一个称为剪枝的过程。在这个过程中,我们移除树的分支和叶子来提高性能。用于构建树的算法在起始或根节点上效果最好,因为那里有所有信息。随后,随着每次分割,数据越来越少,到树的末端,特定的节点可能会显示出与用于分割的数据集相关的模式。这些模式在用于预测真实数据集时会产生问题。剪枝方法允许树生长并移除无法泛化的较小分支。现在举一个例子来理解决策树。

考虑我们有一个鸢尾花数据集。这个数据集在机器学习领域非常流行。它是由罗纳德·费舍尔爵士引入的。它包含来自三种鸢尾花物种(鸢尾花、Iris virginica 和 Iris versicolor)的 50 个样本。四个解释变量是萼片和花瓣的长度和宽度(以厘米为单位),目标变量是花朵所属的类别。

决策树

如前图所示,所有组最初都被认为是 Sentosa 物种,然后进一步使用解释变量和花瓣长度来划分组。在每一步,也会进行误分类项的计算,这显示了有多少项被错误分类。此外,还考虑了花瓣宽度变量。通常,叶节点上的项目被正确分类。

随机森林

随机森林算法是由 Leo Breiman 和 Adele Cutler 开发的。随机森林生长出许多分类树。它们是用于分类和回归的集成学习方法,在训练时构建多个决策树,并输出由单个树输出的类别的众数。

单个决策树显示了偏差-方差权衡。因此,它们通常具有高方差或高偏差。以下是算法中的参数:

  • 偏差: 这是由学习算法中的错误假设引起的误差

  • 方差: 这是一种误差,它从对训练集中微小波动的敏感性到较大的波动

随机森林试图通过*均来减轻这个问题,以在两个极端之间找到自然的*衡。随机森林基于袋装的思想,即*均噪声和无偏模型以创建一个低方差模型。随机森林算法作为一个大量 decorrelated 决策树的集合工作。为了理解随机森林算法的概念,让我们通过一个例子来操作。

考虑我们有一个包含大量特征(解释变量)和目标变量或类别的训练数据集:

随机森林

我们从给定的数据集中创建一个样本集:

随机森林

为了创建随机子数据集,考虑了不同的一组随机特征。现在,从这些子数据集中,将创建不同的决策树。所以实际上我们已经创建了一个不同决策树的森林。使用这些不同的树,我们将为所有分类器创建一个排名系统。为了预测一个新未知项的类别,我们将使用所有决策树并分别找出这些树预测的类别。参见以下图表以更好地理解这个概念:

随机森林

用于预测未知项类别的不同决策树

在这个特定案例中,我们有四个不同的决策树。我们使用每个树来预测未知数据集的类别。根据前面的图示,第一个决策树预测类别 2,第二个决策树预测类别 5,第三个决策树预测类别 5,第四个决策树预测类别 3。现在,随机森林将为每个类别投票。因此,类别 2 和类别 3 各获得一票,类别 5 获得两票。因此,它决定对于新的未知数据集,预测的类别是类别 5。所以,获得更高投票的类别被决定用于新的数据集。随机森林在分类中有许多优点,以下列举了一些:

  • 学习模型的组合增加了分类的准确性

  • 在大型数据集上也能有效运行

  • 生成的森林可以保存并用于其他数据集

  • 可以处理大量的解释变量

现在我们已经从理论上了解了随机森林,让我们继续使用 Mahout,并使用 Apache Mahout 中可用的随机森林算法。

使用 Mahout 进行随机森林

Mahout 对随机森林算法有实现。它非常容易理解和使用。所以,让我们开始吧。

数据集

我们将使用 NSL-KDD 数据集。自 1999 年以来,KDD'99 已经成为评估异常检测方法最广泛使用的数据集。这个数据集由 S. J. Stolfo 准备,并基于在 DARPA'98 IDS 评估计划中捕获的数据构建(R. P. Lippmann, D. J. Fried, I. Graf, J. W. Haines, K. R. Kendall, D. McClung, D. Weber, S. E. Webster, D. Wyschogrod, R. K. Cunningham, and M. A. Zissman, "Evaluating intrusion detection systems: The 1998 darpa off-line intrusion detection evaluation," discex, vol. 02, p. 1012, 2000)。

DARPA'98 是关于 7 周网络流量的约 4 GB 压缩原始(二进制)tcp 捕包数据,可以处理成约 500 万个连接记录,每个记录大约有 100 字节。两周的测试数据大约有 200 万个连接记录。KDD 训练数据集由大约 4,900,000 个单独的连接向量组成,每个向量包含 41 个特征,并标记为正常或攻击,具体为一种特定的攻击类型。

NSL-KDD 是一个数据集,建议解决 KDD'99 数据集的一些固有问题。您可以从 nsl.cs.unb.ca/NSL-KDD/ 下载此数据集。

我们将下载 KDDTrain+_20Percent.ARFFKDDTest+.ARFF 数据集。

使用 Mahout 进行随机森林

注意

KDDTrain+_20Percent.ARFFKDDTest+.ARFF 文件中,删除前 44 行(即所有以 @attribute 开头的行)。如果不这样做,我们将无法生成描述符文件。

使用 Mahout 进行随机森林

在 Mahout 中使用随机森林算法的步骤

在 Apache Mahout 中实现随机森林算法的步骤如下:

  1. 使用以下命令将测试和训练数据集传输到 hdfs

    hadoop fs -mkdir /user/hue/KDDTrain
    hadoop fs -mkdir /user/hue/KDDTest
    hadoop fs –put /tmp/KDDTrain+_20Percent.arff  /user/hue/KDDTrain
    hadoop fs –put /tmp/KDDTest+.arff  /user/hue/KDDTest
    
    
  2. 生成描述符文件。在基于 KDDTrain+.arff 中的训练数据构建随机森林模型之前,需要一个描述符文件。这是因为训练数据集中的所有信息都需要标记。从标记的数据集中,算法可以理解哪些是数值的,哪些是分类的。使用以下命令生成描述符文件:

    hadoop jar  $MAHOUT_HOME/core/target/mahout-core-xyz.job.jar 
    org.apache.mahout.classifier.df.tools.Describe 
    -p /user/hue/KDDTrain/KDDTrain+_20Percent.arff 
    -f /user/hue/KDDTrain/KDDTrain+.info 
    -d N 3 C 2 N C 4 N C 8 N 2 C 19 N L
    
    

    Jar: Mahout 核心 jar (xyz 代表版本)。如果你直接安装了 Mahout,它可以在 /usr/lib/mahout 文件夹下找到。这里使用的主类是 Describe,它接受三个参数:

    p 代表要描述的数据的路径。

    f 代表生成的描述符文件的位置。

    d 是数据属性上的信息。N 3 C 2 N C 4 N C 8 N 2 C 19 N L 定义了数据集以数值 (N) 开头,后面跟着三个分类属性,等等。最后,L 定义了标签。

    上一条命令的输出如下所示:

    在 Mahout 中使用随机森林算法的步骤

  3. 使用以下命令构建随机森林:

    hadoop jar $MAHOUT_HOME/examples/target/mahout-examples-xyz-job.jar org.apache.mahout.classifier.df.mapreduce.BuildForest 
    -Dmapred.max.split.size=1874231 -d /user/hue/KDDTrain/KDDTrain+_20Percent.arff 
    -ds /user/hue/KDDTrain/KDDTrain+.info 
    -sl 5 -p -t 100 –o /user/hue/ nsl-forest
    
    

    Jar: Mahout 示例 jar (xyz 代表版本)。如果你直接安装了 Mahout,它可以在 /usr/lib/mahout 文件夹下找到。主类 build forest 用于构建森林,其他参数如下所示:

    Dmapred.max.split.size 通知 Hadoop 每个分区的最大大小。

    d 代表数据路径。

    ds 代表描述符文件的位置。

    sl 是在每个树节点随机选择的变量。在这里,每个树节点使用五个随机选择的属性来构建。

    p 使用部分数据实现。

    t 代表要生长的树的数量。在这里,使用部分实现构建了 100 棵树。

    o 代表包含决策森林的输出路径。

    在 Mahout 中使用随机森林算法的步骤

    最后,过程将显示以下结果:

    在 Mahout 中使用随机森林算法的步骤

  4. 使用此模型对新数据集进行分类:

    hadoop jar $MAHOUT_HOME/examples/target/mahout-examples-xyz-job.jar org.apache.mahout.classifier.df.mapreduce.TestForest 
    -i /user/hue/KDDTest/KDDTest+.arff 
    -ds /user/hue/KDDTrain/KDDTrain+.info -m /user/hue/nsl-forest -a –mr
     -o /user/hue/predictions
    
    

    Jar: Mahout 示例 jar (xyz 代表版本)。如果你直接安装了 Mahout,它可以在 /usr/lib/mahout 文件夹下找到。用于测试森林的类有以下参数:

    I 表示测试数据的路径

    ds 代表描述符文件的位置

    m 代表上一条命令生成的森林的位置

    a 通知运行分析器以计算混淆矩阵

    mr 通知 Hadoop 分发分类

    o 代表存储预测结果的存储位置

    在 Mahout 中使用随机森林算法的步骤

    该作业提供了以下混淆矩阵:

在 Mahout 中使用随机森林算法的步骤

因此,从混淆矩阵中可以清楚地看出,有 9,396 个实例被正确分类,315 个正常实例被错误地分类为异常。准确率百分比为 77.7635(模型正确分类的实例数 / 分类实例数)。预测文件夹中的输出文件包含一个列表,其中 0 和 1。0 表示正常数据集,1 表示异常。

摘要

在本章中,我们讨论了随机森林算法。我们首先通过理解决策树开始我们的讨论,然后继续理解随机森林。我们使用了 NSL-KDD 数据集,该数据集用于构建网络安全预测系统。我们使用 Mahout 构建随机森林树,并用测试数据集进行测试,生成了混淆矩阵和其他统计数据。

在下一章中,我们将探讨 Apache Mahout 中可用的最终分类算法。所以请保持关注!

第七章. 使用 Mahout 学习多层感知器

要理解多层感知器MLP),我们首先将探索一种更流行的机器学习技术:神经网络。在本章中,我们将探讨以下主题:

  • 神经网络和神经元

  • MLP

  • 使用 Mahout 进行 MLP 实现

神经网络和神经元

神经网络是一个古老的算法,它的开发目标是给计算机提供大脑。神经网络受到人类大脑生物结构的启发,其中多个神经元连接并形成列和层。神经元是一个电可兴奋的细胞,通过电和化学信号处理和传输信息。感知输入通过我们的感官器官进入神经网络,然后进一步处理到更高层次。让我们了解神经元在我们大脑中的工作方式。

神经元是大脑中的计算单元,它们从输入神经(称为树突)收集输入。它们对这些输入信息进行计算,并通过输出神经(称为轴突)发送输出。请参见以下图示 (vv.carleton.ca/~neil/neural/neuron-a.html):

神经网络和神经元

同样地,我们在计算机中开发神经网络。我们可以在以下图中表示我们的算法中的神经元:

神经网络和神经元

在这里,x1x2x3是特征向量,它们被分配给一个函数f,该函数将进行计算并提供输出。这个激活函数通常从 S 形函数家族中选择(如第三章中定义,第三章,使用 Mahout 学习逻辑回归 / SGD)。在分类问题的情况下,使用 softmax 激活函数。在分类问题中,我们希望输出是目标类别的概率。因此,输出应介于 0 和 1 之间,总和接* 1。softmax 函数强制执行这些约束。它是逻辑函数的推广。有关 softmax 函数的更多详细信息,请参阅 www.faqs.org/faqs/ai-faq/neural-nets/part2/section-12.html

多层感知器

神经网络或人工神经网络通常指的是 MLP 网络。我们在上一节中定义了神经元为计算机中的实现。MLP 网络由多个层的这些神经元单元组成。让我们了解一个三层感知器网络,如图所示。MLP 的第一层代表输入,除了将输入路由到每个连接单元的前馈方式外,没有其他目的。第二层被称为隐藏层,最后一层具有确定输出的特殊目的。隐藏层中神经元的激活可以定义为所有输入权重的总和。第 2 层的第 1 个神经元定义如下:

Y12 = g(w110x0 +w111x1+w112x2+w113x3)

第一部分,其中x0 = 0,被称为偏置,可以用作偏移,与输入无关。第 2 层的第 2 个神经元定义如下:

Y22 = g(w120x0 +w121x1+w122x2+w123x3)

多层感知器

第 2 层的第 3 个神经元定义如下:

Y32 = g (w130x0 +w131x1+w132x2+w133x3)

在这里,g 是 sigmoid 函数,如第三章中定义的,使用 Mahout 学习逻辑回归/SGD。函数如下:

g(z) = 1/1+e (-z)

在这个 MLP 网络输出中,从每个输入和隐藏层,神经元单元分布到其他节点,这就是为什么这种网络被称为全连接网络。在这个网络中,没有值被反馈到前一层。(前馈是另一种策略,也称为反向传播。有关详细信息,请参阅home.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html。)

MLP 网络可以有多于一个的隐藏层。为了得到权重值,以便我们能够将预测值尽可能接*实际值,这是一个 MLP 的训练过程。为了构建一个有效的网络,我们考虑了许多项目,例如隐藏层的数量和每层的神经元单元数,最小化预测值和实际值之间误差的成本函数,等等。

现在我们来讨论在创建 MLP 网络时出现的两个更重要且具有挑战性的问题:

  • 应该使用多少个隐藏层来构建网络?

  • 在隐藏层中应该使用多少个隐藏单元(神经元单元)?

对于线性可分的数据,不需要隐藏层。假设你的数据确实需要通过非线性技术进行分离,始终从一个隐藏层开始。几乎可以肯定,这将是所有你需要的东西。如果你的数据可以使用 MLP 进行分离,那么这个 MLP 可能只需要一个隐藏层。为了选择不同层的单元数,以下是一些指导原则:

  • 输入层:这指的是模型中的解释变量数量加上一个偏置节点。

  • 输出层:在分类的情况下,这指的是目标变量的数量,而在回归的情况下,这显然是一个。

  • 隐藏层:从单个隐藏层开始构建你的网络,并使用与输入层单元数量相当的神经元单元数量。最好的方法是训练几个具有不同隐藏层和隐藏神经元数量的神经网络,并使用交叉验证来衡量这些网络的性能。你可以坚持使用产生最佳性能网络的数字。需要两个隐藏层的问题很少遇到。然而,具有多个隐藏层的神经网络可以表示任何形状的函数。目前还没有理论来证明使用超过两个隐藏层的神经网络是合理的。实际上,对于许多实际问题,没有必要使用超过一个隐藏层。没有隐藏层的网络只能表示线性可分函数。单层网络可以逼*任何包含从一个有限空间到另一个连续映射的函数,而具有两个隐藏层的网络可以使用有理激活函数以任意精度表示任意决策边界,并且可以逼*任何*滑映射以任意精度(Java 神经网络入门第五章)。

  • 神经元或隐藏单元的数量:使用与输入层单元数量相当的神经元单元数量。隐藏单元的数量应小于输入层单元数量的两倍。另一种计算方法是 (输入单元数量 + 输出单元数量) 2/3。

进行泛化误差、训练误差、偏差和方差的测试。当泛化误差下降时,通常在它开始再次增加之前,会发现节点数量在此点达到完美。

现在让我们继续到下一节,探讨如何使用 Mahout 进行 MLP。

Mahout 中的 MLP 实现

MLP 实现基于一个更通用的神经网络类。它被实现为在单个机器上使用随机梯度下降运行,其中权重是使用每个数据点一次进行更新的。

可以手动指定层数和每层的单元数,这决定了整个拓扑结构,每个单元都与前一层的每个单元完全连接。每个层的输入自动添加一个偏差单元。偏差单元有助于将激活函数向左或向右移动。它就像给线性函数添加一个系数一样。

目前,逻辑 Sigmoid 函数被用作每个隐藏层和输出层的压缩函数。

命令行版本不会在小数据集上导致不良结果的迭代。另一个限制是,MLP 的 CLI 版本仅支持分类,因为当在命令行中执行实现时,必须明确给出标签。

可以使用 --update 标志存储和更新学习模型,并使用新的训练实例。分类结果的输出保存为 .txt 文件,并且仅包含分配的标签。除了命令行界面外,还可以使用 mrlegacy 包中的 API 和接口构建和编译更专业的神经网络。(核心包已重命名为 mrlegacy。)

在命令行中,我们使用 TrainMultilayerPerceptronRunMultilayerPerceptron 类,这些类在 mrlegacy 包中可用,与另外三个类一起使用:Neural network.javaNeuralNetworkFunctions.javaMultilayerPerceptron.java。对于这个特定的实现,用户可以自由控制 MLP 的拓扑结构,包括以下内容:

  • 输入层的大小

  • 隐藏层的数量

  • 每个隐藏层的大小

  • 输出层的大小

  • 成本函数

  • 挤压函数

模型以在线学习的方式进行训练,其中 MLP 中的神经元权重使用 Rumelhart, D. E.、Hinton, G. E. 和 Williams, R. J.(1986)提出的反向传播算法进行更新和增加。(Rumelhart, D. E., Hinton, G. E., and Williams, R. J. (1986), Learning representations by back-propagating errors. Nature, 323, 533-536。)

使用 Mahout 进行 MLP

Mahout 为 MLP 网络提供了实现。MLP 实现目前位于 Map-Reduce-Legacy 包中。与其他分类算法一样,实现了两个分离的类来训练和使用这个分类器。用于训练分类器的类是 org.apache.mahout.classifier.mlp.TrainMultilayerPerceptron,用于运行分类器的类是 org.apache.mahout.classifier.mlp.RunMultilayerPerceptron。定义了多个参数,这些参数与这些类一起使用,但我们将在我们对数据集运行示例后讨论这些参数。

数据集

在本章中,我们将训练一个 MLP 来对鸢尾花数据集进行分类。鸢尾花数据集包含三种花卉物种的数据,每个数据点由四个特征组成。这个数据集是由罗纳德·费舍尔爵士引入的。它包括来自三种鸢尾花物种的 50 个样本。这些物种是 Iris setosa、Iris virginica 和 Iris versicolor。从每个样本测量了四个特征:

  • 萼片长度

  • 花瓣宽度

  • 花瓣长度

  • 花瓣宽度

所有测量值都以厘米为单位。您可以从 archive.ics.uci.edu/ml/machine-learning-databases/iris/ 下载此数据集,并将其保存为 .csv 文件,如下截图所示:

使用 Mahout 进行 MLP

这个数据集看起来如下截图所示:

使用 Mahout 进行 MLP

在 Mahout 中使用 MLP 算法的步骤

在 Mahout 中使用 MLP 算法的步骤如下:

  1. 创建 MLP 模型。

    要创建 MLP 模型,我们将使用 TrainMultilayerPerceptron 类。使用以下命令生成模型:

    bin/mahout org.apache.mahout.classifier.mlp.TrainMultilayerPerceptron -i /tmp/irisdata.csv -labels Iris-setosa Iris-versicolor Iris-virginica -mo /tmp/model.model -ls 4 8 3 -l 0.2 -m 0.35 -r 0.0001
    
    

    您也可以使用核心 jar 运行:Mahout 核心 jar(xyz 代表版本)。如果您直接安装了 Mahout,它可以在 /usr/lib/mahout 文件夹下找到。执行以下命令:

    Java –cp /usr/lib/mahout/ mahout-core-xyz-job.jar org.apache.mahout.classifier.mlp.TrainMultilayerPerceptron -i /tmp/irisdata.csv -labels Iris-setosa Iris-versicolor Iris-virginica -mo /user/hue/mlp/model.model -ls 4 8 3 -l 0.2 -m 0.35 -r 0.0001
    
    

    这里使用 TrainMultilayerPerceptron 类,它接受不同的参数。此外,i 是输入数据集的路径。在这里,我们将数据集放在了 /tmp 文件夹下(本地文件系统)。此外,数据集中还定义了标签。以下是我们定义的标签:

    • mo 是创建的模型的输出位置。

    • ls 是每层的单元数,包括输入层、隐藏层和输出层。此参数指定了网络的拓扑结构。在这里,我们使用 4 作为输入特征,8 作为隐藏层,3 作为输出类别数。

    • l 是用于权重更新的学习率。默认值为 0.5。为了*似梯度下降,神经网络通过算法进行训练。学习可以通过批量或在线方法进行。在批量训练中,权重变化在整个训练数据展示(一个 epoch)之后才会应用,而在在线训练中,在每个训练示例(实例)展示后更新权重。更多详情请参阅 axon.cs.byu.edu/papers/Wilson.nn03.batch.pdf

    • m 是用于梯度下降的动量权重。这个值必须在 0–1.0 的范围内。

    • r 是权重向量的正则化值。这个值必须在 0–0.1 的范围内。它用于防止过拟合。

    使用 Mahout 中的 MLP 算法的步骤

  2. 要测试/运行训练模型的 MLP 分类,我们可以使用以下命令:

    bin/mahout org.apache.mahout.classifier.mlp.RunMultilayerPerceptron -i /tmp/irisdata.csv -cr 0 3 -mo /tmp/model.model -o /tmp/labelResult.txt
    
    

    您也可以使用 Mahout 核心 jar 运行(xyz 代表版本)。如果您直接安装了 Mahout,它可以在 /usr/lib/mahout 文件夹下找到。执行以下命令:

    Java –cp /usr/lib/mahout/ mahout-core-xyz-job.jar org.apache.mahout.classifier.mlp.RunMultilayerPerceptron -i /tmp/irisdata.csv -cr 0 3 -mo /tmp/model.model -o /tmp/labelResult.txt
    
    

    这里使用 RunMultilayerPerceptron 类来使用模型。此类也接受不同的参数,如下所示:

    • i 表示输入数据集的位置

    • cr 是从输入文件中使用的列的范围,从 0 开始(即 -cr 0 5 仅包括前六列)

    • mo 是先前构建的模型的位置

    • o 是存储模型运行结果的标签化结果的路径

    使用 Mahout 中的 MLP 算法的步骤

摘要

在本章中,我们讨论了 Mahout 中新实施的一个算法:MLP。我们通过理解神经网络和神经元单元开始了我们的讨论,并进一步讨论以理解 MLP 网络算法。我们讨论了如何选择不同的层单元。然后我们转向 Mahout,并使用 iris 数据集来测试和运行 Mahout 中实现的 MLP 算法。至此,我们已经完成了对 Apache Mahout 中可用的分类算法的讨论。

现在我们继续进入这本书的下一章节,我们将讨论新发布的 Mahout 版本中的新变化。

第八章:即将发布的 Mahout 变更

Mahout 是一个社区驱动的项目,其社区非常强大。这个社区决定了一些即将在 1.0 版本中发布的重大变更。在本章中,我们将探讨 Apache Mahout 即将到来的变更和发展。我们将简要介绍以下主题:

  • Mahout 1.0 中的新变更

  • Apache Spark

  • Apache Mahout 中的 H20-platform 相关工作

Mahout 的新变更

Mahout 之前使用 MapReduce 编程模型来处理大数据集。从 2014 年 4 月底开始,社区决定停止实施新的 MapReduce 算法。这个决定有合理的理由。Mahout 的代码库将迁移到提供更丰富编程模型和比 Hadoop MapReduce 更高效执行的现代数据处理系统。

Mahout 已经开始在 领域特定语言DSL)的顶部实现线性代数操作。用这种 DSL 编写的程序将自动优化并在 Apache Spark 上并行执行。Scala DSL 和代数优化器是 Mahout 的 Scala 和 Spark 绑定。

Mahout Scala 和 Spark 绑定

通过 Mahout Scala 绑定和 Mahout Spark 绑定线性代数子程序,Mahout 中的开发者试图将语义明确性引入 Mahout 的内存和内存外线性代数子程序。他们在添加 Scala 强大编程环境的好处的同时,利用 Spark 和 GraphX 的可扩展性优势。Scala 绑定用于提供对 Scala DSL 的支持,这将使编写机器学习程序变得更加容易。

Mahout 的 Scala 和 Spark 绑定是旨在为 Mahout 的内存和内存外 Spark 支持的线性代数提供类似 R 语言外观和感觉的包。Spark 绑定的重要组成部分是表达式优化器。这个优化器会查看整个表达式,并决定如何简化它以及应该选择哪些物理操作符。绑定堆栈的高级图示如下所示(issues.apache.org/jira/secure/attachment/12638098/BindingsStack.jpg):

Mahout Scala 和 Spark 绑定

Mahout 1.0 中也实现了 Spark 绑定 shell。让我们首先了解 Apache Spark 项目,然后我们将重新审视 Mahout 中的 Spark 绑定 shell。

Apache Spark

Apache Spark 是一个开源的、内存中的通用计算系统。Spark 的内存技术提供了比传统基于磁盘的计算快 100 倍的性能。Spark 不同于 Hadoop 类似的基于磁盘的计算,它使用集群内存将所有数据上传到内存中,并且这些数据可以被重复查询。

Apache Spark 提供了 Java、Python 和 Scala 的高级 API 以及支持通用执行图的高级优化引擎。它提供了以下高级工具:

  • Spark SQL:这是用于 SQL 和结构化数据处理的功能。

  • MLib:这是 Spark 的可扩展机器学习库,包括常见的学习算法和实用工具,如分类、回归、聚类、协同过滤、降维以及底层的优化原语。

  • GraphX:这是 Spark 的新图和图并行计算 API。

  • Spark streaming:这可以从多个来源收集数据,在处理这些数据后,它使用复杂算法并将数据推送到文件系统、数据库和实时仪表板。

随着 Spark 在数据科学家中的流行,Mahout 社区也在迅速努力使 Mahout 算法在 Spark 的执行引擎上运行,以加快其计算速度 10 到 100 倍。Mahout 提供了几个重要的构建块,用于使用 Spark 创建推荐。Spark-item 相似度可以用于创建 其他人也喜欢这些内容 类型的推荐,并且当与搜索引擎配合使用时,可以为单个用户个性化推荐。Spark-row 相似度可以根据推荐提供非个性化内容,并且当与搜索引擎配合使用时,可以用于根据推荐个性化内容 (comments.gmane.org/gmane.comp.apache.mahout.scm/6513)).

使用 Mahout 的 Spark shell

您可以通过以下步骤使用 Mahout 的 Spark shell:

  1. spark.apache.org/downloads.html 下载 Spark。

  2. 使用以下命令创建一个名为 spark 的新文件夹,并将下载的文件移动到该文件夹中:

    mkdir /tmp/spark
    mv ~/Downloads/spark-1.1.1.tgz/tmp/spark
    
    
  3. 使用以下命令在文件夹中解压归档文件:

    cd /tmp/spark
    tar xzf spark-1.1.1.tgz
    
    
  4. 这将解压 under/tmp/spark/spark-1.1.1 中的文件。现在,移动到新创建的文件夹并运行以下命令:

    cd /spark-1.1.1
    sbt/sbt assembly
    
    

    这将在您的系统上构建 Spark,如下截图所示:

    使用 Mahout 的 Spark shell

  5. 现在创建一个 Mahout 目录,并使用以下命令将文件移动到该目录:

    mkdir /tmp/Mahout
    
    
  6. 使用以下命令从 GitHub 检出 Mahout 的主分支:

    git clone https://github.com/apache/mahout mahout
    
    

    前一个命令的输出如下截图所示:

    使用 Mahout 的 Spark shell

  7. 将您的目录切换到新创建的 Mahout 目录,并构建 Mahout:

    cd mahout
    mvn -DskipTests clean install
    
    

    前一个命令的输出如下截图所示:

    使用 Mahout 的 Spark shell

  8. 移动到您解压 Spark 的目录,并输入以下命令以在本地启动 Spark:

    cd /tmp/spark/spark-1.1.1
    sbin/start-all-sh
    
    

    前一个命令的输出如下截图所示:

    使用 Mahout 的 Spark shell

  9. 打开浏览器;将其指向 http://localhost:8080/ 以检查 Spark 是否已成功启动。复制页面顶部 Spark 主机的 URL(以 spark:// 开头)。

  10. 定义以下环境变量:

    export MAHOUT_HOME=[directory into which you checked out Mahout]
    export SPARK_HOME=[directory where you unpacked Spark]
    export MASTER=[url of the Spark master]
    
    
  11. 最后,切换到您解压 Mahout 的目录,并输入bin/mahout spark-shell;您应该看到 shell 启动并出现mahout>提示符。

现在您的 Mahout Spark shell 已经准备好了,您可以从数据处理开始。有关此主题的更多信息,请参阅mahout.apache.org/users/sparkbindings/play-with-shell.html中的实现部分。

H2O *台集成

如前所述,将 Mahout 和 H2O *台集成的实验性工作也在进行中。该集成为 Mahout 代数 DSL 提供了 H2O 后端。

H2O 让 Hadoop 做数学!H2O 在大数据上扩展统计、机器学习和数学。它是可扩展的,用户可以使用核心中的简单数学积木构建块。H2O 保留了熟悉的接口,如 R、Excel 和 JSON,以便大数据爱好者和专业人员可以使用一系列简单到高级的算法来探索、处理、建模和评分数据集。数据收集容易,而决策困难。H2O 通过更快、更好的预测建模使从数据中提取见解变得快速且简单。它还拥有在线评分和建模的单*台愿景(0xdata.com/download/)。

H2O 本质上是一个对等网络系统。H2O 节点联合起来形成一个云,可以在其上执行高性能分布式数学运算。每个节点加入一个具有特定名称的云。只要它们的名称不同,同一网络中可以同时存在多个云。同样,同一服务器上也可以存在多个节点(它们甚至可以属于同一个云)。

Mahout H2O 集成通过具有 N-1 个工作节点和一个驱动节点,所有节点都属于同一个云名称来适应此模型。用于集成的默认云名称是mah2out。云必须根据其任务/作业启动。

更多详细信息可以在issues.apache.org/jira/browse/MAHOUT-1500中找到。

摘要

在本章中,我们讨论了即将发布的 Mahout 1.0 版本,以及目前正在进行的更改。我们还简要介绍了 Spark、Scala 绑定和 Apache Spark。我们还讨论了 H2O Mahout 集成的概述。

现在让我们继续到这本书的最后一章,我们将开发一个生产就绪的分类器。

第九章:使用 Apache Mahout 构建电子邮件分类系统

在本章中,我们将使用 Mahout 创建一个分类器系统。为了构建这个系统,我们将涵盖以下主题:

  • 获取数据集

  • 数据集准备

  • 准备模型

  • 训练模型

在本章中,我们将针对创建两个不同的分类器。第一个将是一个简单的分类器,因为你可以在一个伪分布式 Hadoop 安装上创建和测试它。对于第二个分类器,我将提供所有细节,以便你可以使用你的完全分布式 Hadoop 安装来运行它。我将把第二个分类器视为本书读者的实践练习。

首先,让我们了解第一个用例的问题陈述。如今,在大多数电子邮件系统中,我们看到电子邮件被分类为垃圾邮件或非垃圾邮件。非垃圾邮件直接进入我们的收件箱,而垃圾邮件则存储在名为 Spam 的文件夹中。通常,基于某些模式,如消息主题、发件人的电子邮件地址或消息体中的某些关键词,我们将 incoming 电子邮件分类为垃圾邮件。我们将使用 Mahout 创建一个分类器,将电子邮件分类为垃圾邮件或非垃圾邮件。我们将使用 SpamAssassin,一个 Apache 开源项目数据集来完成这项任务。

对于第二个用例,我们将创建一个分类器,它可以预测一组 incoming 电子邮件。作为一个开源项目,Apache 软件基金会下有许多项目,例如 Apache Mahout、Apache Hadoop、Apache Solr 等。我们将使用 Apache 软件基金会 (ASF) 的电子邮件数据集,并使用这个数据集来创建和训练我们的模型,以便我们的模型可以预测新的 incoming 电子邮件。因此,基于某些特征,我们将能够预测新 incoming 电子邮件属于哪个组。

在 Mahout 的分类问题中,我们将在数据集中识别一个模式,以帮助我们预测新电子邮件的组别。我们已经有了一个数据集,它被项目名称分开。我们将使用 ASF 公共电子邮件存档数据集来处理这个用例。

现在,让我们考虑我们的第一个用例:垃圾邮件检测分类器。

垃圾邮件数据集

正如我提到的,我们将使用 Apache SpamAssassin 项目数据集。Apache SpamAssassin 是一个开源的垃圾邮件过滤器。从 spamassassin.apache.org/publiccorpus/ 下载 20021010_easy_ham.tar20021010_spam.tar,如下截图所示:

垃圾邮件数据集

使用 Assassin 数据集创建模型

我们可以通过以下步骤创建模型:

  1. tmp 目录下创建一个名为 dataset 的文件夹,然后点击该文件夹,使用以下命令解压数据集:

    mkdir /tmp/assassin/dataset
    tar –xvf  /tmp/assassin/ 20021010_easy_ham.tar.bz2 
    tar –xvf /tmp/assassin/ 20021010_spam.tar.bz2
    
    

    这将在 dataset 文件夹下创建两个文件夹,easy _hamspam,如下截图所示:

    使用刺客数据集创建模型

  2. Hdfs中创建一个文件夹并将此数据集移动到 Hadoop 中:

    hadoop fs  -mkdir /user/hue/assassin/
    hadoop fs –put /tmp/assassin/dataset  /user/hue/assassin 
    tar –xvf /tmp/assassin/ 20021010_spam.tar.bz2
    
    

    现在我们已完成数据准备。我们已经下载了数据并将这些数据移动到hdfs中。让我们继续下一步。

  3. 将此数据转换为序列文件,以便我们可以使用 Hadoop 进行处理:

    bin/mahout seqdirectory –i /user/hue/assassin/dataset –o /user/hue/assassinseq-out
    
    

    使用刺客数据集创建模型

  4. 使用以下命令将sequence文件转换为稀疏向量(Mahout 算法接受向量格式的输入,因此我们需要将sequence文件转换为稀疏向量):

    bin/mahout seq2sparse -i /user/hue/assassinseq-out/part-m-00000 -o /user/hue/assassinvec -lnorm -nv -wt tfidf
    
    

    使用刺客数据集创建模型

    上一张截图中的命令解释如下:

    • lnorm: 这个命令用于输出向量的对数归一化。

    • nv: 这个命令用于命名向量。

    • wt: 这个命令用于确定要使用的权重类型。在这里我们使用tf-idf

  5. 按以下方式拆分向量集以训练和测试模型:

    bin/mahout split -i /user/hue/assassinvec/tfidf-vectors --trainingOutput /user/hue/assassindatatrain --testOutput /user/hue/assassindatatest --randomSelectionPct 20 --overwrite --sequenceFiles -xm sequential
    
    

    上一条命令可以这样解释:

    • randomSelectionPct 参数将数据百分比分为测试集和训练集。在这种情况下,测试集为 80%,训练集为 20%。

    • xm 参数指定了要使用的tf (tf-idf)向量的部分,以标准差倍数表示。

    • 符号σ指定了这些向量的文档频率。它可以用来移除真正高频的术语。它以双精度值表示。一个合适的值是 3.0。如果值小于0,则不会过滤掉任何向量。

    使用刺客数据集创建模型

  6. 现在,使用以下命令训练模型:

    bin/mahout trainnb -i /user/hue/assassindatatrain -el -o /user/hue/prodmodel -li /user/hue/prodlabelindex -ow -c
    
    

    使用刺客数据集创建模型

  7. 现在,使用以下命令测试模型:

    bin/mahout testnb -i /user/hue/assassindatatest -m /user/hue/prodmodel/ -l  /user/hue/prodlabelindex -ow -o /user/hue/prodresults
    
    

    使用刺客数据集创建模型

您可以从结果中看到,输出显示在控制台上。根据矩阵,系统正确分类了 99.53%的实例。

我们可以使用这个创建的模型来对新文档进行分类。为此,我们可以使用 Java 程序或创建一个可以部署到我们服务器上的 servlet。

让我们以这个练习的例子来分析一个 Java 程序。

使用分类模型模型的程序

我们将创建一个 Java 程序,该程序将使用我们的模型来对新电子邮件进行分类。该程序将接受模型、标签索引、字典文件、文档频率和文本文件作为输入,并为类别生成分数。类别将根据较高的分数来决定。

让我们一步一步地看看这个程序:

  • 制作此程序所需的.jar文件如下:

    • Hadoop-core-x.y.x.jar

    • Mahout-core-xyz.jar

    • Mahout-integration-xyz.jar

    • Mahout-math-xyz.jar

  • import 语句列表如下。我们讨论这个问题是因为 Mahout 的版本中有很多变化,人们通常发现很难找到正确的类。

    • import java.io.BufferedReader;

    • import java.io.FileReader;

    • import java.io.StringReader;

    • import java.util.HashMap;

    • import java.util.Map;

    • import org.apache.hadoop.conf.Configuration;

    • import org.apache.hadoop.fs.Path;

    • import org.apache.lucene.analysis.Analyzer;

    • import org.apache.lucene.analysis.TokenStream;

    • import org.apache.lucene.analysis.standard.StandardAnalyzer;

    • import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;

    • import org.apache.lucene.util.Version;

    • import org.apache.mahout.classifier.naivebayes.BayesUtils;

    • import org.apache.mahout.classifier.naivebayes.NaiveBayesModel;

    • import org.apache.mahout.classifier.naivebayes.StandardNaiveBayesClassifier;

    • import org.apache.mahout.common.Pair;

    • import org.apache.mahout.common.iterator.sequencefile.SequenceFileIterable;

    • import org.apache.mahout.math.RandomAccessSparseVector;

    • import org.apache.mahout.math.Vector;

    • import org.apache.mahout.math.Vector.Element;

    • import org.apache.mahout.vectorizer.TFIDF;

    • import org.apache.hadoop.io.*;

    • import com.google.common.collect.ConcurrentHashMultiset;

    • import com.google.common.collect.Multiset;

  • 读取字典的支持方法如下:

    public static Map<String, Integer> readDictionary(Configuration conf, Path dictionaryPath) {
      Map<String, Integer> dictionary = new HashMap<String, Integer>();
      for (Pair<Text, IntWritable> pair : new SequenceFileIterable<Text, IntWritable>(dictionaryPath, true, conf)) {
        dictionary.put(pair.getFirst().toString(), pair.getSecond().get());
      }
      return dictionary;
    }
    
  • 读取文档频率的支持方法如下:

    public static Map<Integer, Long> readDocumentFrequency(Configuration conf, Path documentFrequencyPath) {
      Map<Integer, Long> documentFrequency = new HashMap<Integer, Long>();
      for (Pair<IntWritable, LongWritable> pair : new SequenceFileIterable<IntWritable, LongWritable>(documentFrequencyPath, true, conf)) {
        documentFrequency.put(pair.getFirst().get(), pair.getSecond().get());
      }
      return documentFrequency;
    }
    
  • main 方法的第一部分用于执行以下操作:

    • 获取输入

    • 加载模型

    • 使用我们创建的模型初始化 StandardNaiveBayesClassifier

    • 读取在创建向量时从数据集创建的 labelindex、文档频率和字典

      以下代码可用于执行前面的操作:

      public static void main(String[] args) throws Exception {
        if (args.length < 5) {
          System.out.println("Arguments: [model] [labelindex] [dictionary] [documentfrequency] [new file] ");
          return;
        }
        String modelPath = args[0];
        String labelIndexPath = args[1];
        String dictionaryPath = args[2];
        String documentFrequencyPath = args[3];
        String newDataPath = args[4];
        Configuration configuration = new Configuration(); // model is a matrix (wordId, labelId) => probability score
        NaiveBayesModel model = NaiveBayesModel.materialize(new Path(modelPath), configuration); 
        StandardNaiveBayesClassifier classifier = new StandardNaiveBayesClassifier(model); 
        // labels is a map label => classId
        Map<Integer, String> labels = BayesUtils.readLabelIndex(configuration, new Path(labelIndexPath));
        Map<String, Integer> dictionary = readDictionary(configuration, new Path(dictionaryPath));
        Map<Integer, Long> documentFrequency = readDocumentFrequency(configuration, new Path(documentFrequencyPath));
      
  • main 方法的第二部分用于从电子邮件中提取单词:

    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
    
    int labelCount = labels.size();
    int documentCount = documentFrequency.get(-1).intValue();
    
    System.out.println("Number of labels: " + labelCount);
    System.out.println("Number of documents in training set: " + documentCount);
    BufferedReader reader = new BufferedReader(new FileReader(newDataPath));
    while(true) {
      String line = reader.readLine();
      if (line == null) {
        break;
      }
    
      ConcurrentHashMultiset<Object> words = ConcurrentHashMultiset.create(); 
      // extract words from mail
      TokenStream ts = analyzer.tokenStream("text", new StringReader(line));
      CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class);
      ts.reset();
      int wordCount = 0;
      while (ts.incrementToken()) {
        if (termAtt.length() > 0) {
          String word = ts.getAttribute(CharTermAttribute.class).toString();
          Integer wordId = dictionary.get(word);
          // if the word is not in the dictionary, skip it
          if (wordId != null) {
            words.add(word);
            wordCount++;
          }
        }
      }
      ts.close();
    
  • main 方法的第三部分用于创建 id 单词的向量和 tf-idf 权重:

    Vector vector = new RandomAccessSparseVector(10000);
    TFIDF tfidf = new TFIDF();
    for (Multiset.Entry entry:words.entrySet()) {
      String word =  (String)entry.getElement();
      int count = entry.getCount();
      Integer wordId = dictionary.get(word);
      Long freq = documentFrequency.get(wordId);
      double tfIdfValue = tfidf.calculate(count, freq.intValue(), wordCount, documentCount);
      vector.setQuick(wordId, tfIdfValue);
    }
    
  • main 方法的第四部分,使用 classifier 获取每个标签的分数,并将电子邮件分配给得分较高的标签:

      Vector resultVector = classifier.classifyFull(vector);
        double bestScore = -Double.MAX_VALUE;
        int bestCategoryId = -1;          
        for(int i=0 ;i<resultVector.size();i++) {
          Element e1  = resultVector.getElement(i);
          int categoryId = e1.index();
          double score = e1.get();
          if (score > bestScore) {
            bestScore = score;
            bestCategoryId = categoryId;
          }
          System.out.print("  " + labels.get(categoryId) + ": " + score);
        }
        System.out.println(" => " + labels.get(bestCategoryId));
      }
    }
    

现在,将这些代码放在一个类中,并创建这个类的 .jar 文件。我们将使用这个 .jar 文件来测试我们新的电子邮件。

测试程序

要测试程序,请执行以下步骤:

  1. 在本地目录中创建一个名为 assassinmodeltest 的文件夹,如下所示:

    mkdir /tmp/assassinmodeltest
    
    
  2. 要使用此模型,从 hdfs 获取以下文件到 /tmp/assassinmodeltest

    • 对于之前创建的模型,使用以下命令:

      hadoop fs –get /user/hue/prodmodel /tmp/assassinmodeltest
      
      
    • 对于 labelindex,使用以下命令:

      hadoop fs –get /user/hue/prodlabelindex  /tmp/assassinmodeltest
      
      
    • 对于 assassinvec 文件夹中的 df-counts(将 part-00000 文件名更改为 df-count),使用以下命令:

      hadoop fs –get /user/hue/assassinvec/df-count  /tmp/assassinmodeltest
      dictionary.file-0 from the same assassinvec folder
      hadoop fs –get /user/hue/assassinvec/dictionary.file-0  /tmp/assassinmodeltest
      
      
  3. /tmp/assassinmodeltest 目录下创建一个文件,其内容如以下截图所示:测试程序

  4. 现在,使用以下命令运行程序:

    Java –cp /tmp/assassinmodeltest/spamclassifier.jar:/usr/lib/mahout/* com.packt.spamfilter.TestClassifier /tmp/assassinmodeltest /tmp/assassinmodeltest/prodlabelindex /tmp/assassinmodeltest/dictionary.file-0 /tmp/assassinmodeltest/df-count /tmp/assassinmodeltest/testemail
    
    

    测试程序

  5. 现在,更新test电子邮件文件,使用以下截图中的消息:测试程序

  6. 再次使用步骤 4 中给出的相同命令运行程序,并查看以下结果:测试程序

现在,我们有一个程序可以用来使用我们的分类器模型并预测未知项。让我们继续我们的第二个用例。

作为练习的第二个用例

如本章开头所述,我们现在将处理第二个用例,在这个用例中,我们将预测一封新电子邮件的类别。

ASF 电子邮件数据集

Apache 软件基金会电子邮件数据集按项目分区。此电子邮件数据集可在aws.amazon.com/datasets/7791434387204566找到。

ASF 电子邮件数据集

可以在files.grantingersoll.com/ibm.tar.gz找到较小的数据集。(参考lucidworks.com/blog/scaling-mahout/)。使用这些数据执行以下步骤:

  1. 将这些数据移动到您选择的文件夹(/tmp/asfmail)并解压文件夹:

    mkdir /tmp/asfmail
    tar –xvf  ibm.tar
    
    
  2. 将数据集移动到hdfs

    hadoop fs -put /tmp/asfmail/ibm/content /user/hue/asfmail
    
    
  3. 使用 Mahout 的SequenceFilesFromMailArchivesmbox文件转换为 Hadoop 的SequenceFile格式,如下所示:

    mahout  org.apache.mahout.text.SequenceFilesFromMailArchives --charset "UTF-8" --body --subject --input /user/hue/asfmail/content --output /user/hue/asfmailout
    
    

    ASF 电子邮件数据集

  4. sequence文件转换为稀疏向量:

    mahout  seq2sparse --input /user/hue/asfmailout --output /user/hue/asfmailseqsp --norm 2 --weight TFIDF --namedVector --maxDFPercent 90 --minSupport 2 --analyzerName org.apache.mahout.text.MailArchivesClusteringAnalyzer
    
    

    ASF 电子邮件数据集

  5. 修改标签:

    mahout  org.apache.mahout.classifier.email.PrepEmailDriver --input /user/hue/asfmailseqsp --output /user/hue/asfmailseqsplabel --maxItemsPerLabel 1000
    
    

现在,接下来的三个步骤与我们之前执行的操作类似:

  1. 使用以下命令将数据集拆分为trainingtest数据集:

    mahout  split --input /user/hue/asfmailseqsplabel --trainingOutput /user/hue/asfmailtrain --testOutput /user/hue/asfmailtest  --randomSelectionPct 20 --overwrite --sequenceFiles
    
    
  2. 使用以下方式使用training数据集训练模型:

    mahout trainnb -i /user/hue/asfmailtrain -o /user/hue/asfmailmodel -extractLabels --labelIndex /user/hue/asfmaillabels
    
    
  3. 使用test数据集测试模型:

    mahout testnb -i /user/hue/asfmailtest -m /user/hue/asfmailmodel --labelIndex /user/hue/asfmaillabels
    
    

如您可能已经注意到的,所有步骤都与我们之前执行的操作完全相同。因此,我将这个主题留作练习,让您使用此模型创建自己的分类器系统。您可以使用提供的提示来创建垃圾邮件过滤器分类器。我们现在将讨论调整我们的分类器。让我们简要概述一下该领域的最佳实践。

分类器调整

我们已经在第一章 数据分析中的分类 中讨论了分类器的评估技术。仅作为提醒,我们使用混淆矩阵、熵矩阵、曲线下面积等技术来评估我们的模型。

从解释变量中,我们创建特征向量。为了检查特定模型的工作情况,这些特征向量需要被调查。在 Mahout 中,有一个用于此目的的类,ModelDissector。它需要以下三个输入:

  • 特征:这个类接受一个要使用的特征向量(破坏性)

  • TraceDictionary:这个类接受一个包含变量及其在特征向量中受影响的位置的跟踪字典

  • 学习者:这个课程采用我们正在探查的模型来寻找特征权重

ModelDissector 调整特征向量并观察模型输出的变化。通过取示例数量的*均值,我们可以确定不同解释变量的影响。

ModelDissector 有一个摘要方法,它返回最重要的特征及其权重、最重要的类别以及它们影响的几个顶级类别。

ModelDissector 的输出有助于解决错误创建的模型中的问题。

有关代码的更多细节可以在github.com/apache/mahout/blob/master/mrlegacy/src/main/java/org/apache/mahout/classifier/sgd/ModelDissector.java找到。

在提高分类器输出时,应该注意两个常见问题:目标泄露和损坏的特征提取。

如果模型显示的结果太好以至于不真实或超出预期,我们可能存在目标泄露问题。这种错误发生在目标变量的信息被包含在用于训练分类器的解释变量中时。在这种情况下,分类器对 test 数据集的表现会太好。

另一方面,当特征提取失败时,会发生损坏的特征提取。这种类型的分类器会显示与目标泄露分类器相反的结果。在这里,模型提供的结果比预期更差。

要调整分类器,我们可以使用新的解释变量、解释变量的变换,也可以消除一些变量。我们还应该尝试不同的学习算法来创建模型,并选择一个在性能、训练时间和速度方面都好的算法。

更多关于调整的细节可以在《Mahout in Action》一书的第十六章“部署分类器”中找到。

摘要

在本章中,我们讨论了创建我们自己的生产就绪分类器模型。我们在这里提出了两个用例,一个是电子邮件垃圾邮件过滤器,另一个是根据项目对电子邮件进行分类。我们使用了 Apache SpamAssassin 的数据集用于电子邮件过滤器,以及 ASF 用于电子邮件分类器。

我们还看到了如何提高模型性能的方法。

因此,你现在可以准备好使用 Apache Mahout 实现分类器,用于你自己的实际用例。祝学习愉快!

posted @ 2025-10-09 13:24  绝不原创的飞龙  阅读(8)  评论(0)    收藏  举报