R-机器学习秘籍-全-

R 机器学习秘籍(全)

原文:annas-archive.org/md5/167951e4c9873bc214756c25a63518c8

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

大数据已成为许多行业中的热门词汇。越来越多的人接触到了这个术语,并正在寻找如何在他们的业务中利用大数据,以提高销售额和盈利能力。然而,收集、聚合和可视化数据只是方程的一部分。能够从数据中提取有用信息是另一项任务,而且更具挑战性。

传统上,大多数研究人员使用历史数据样本进行统计分析。这个过程的主要缺点是,从统计分析中得出的结论是有限的。事实上,研究人员通常很难从目标数据中揭示隐藏的模式和未知的相关性。除了应用统计分析外,机器学习已成为一种替代方案。这个过程通过将数据插入学习算法,产生了一个更准确的预测模型。通过机器学习,对商业运营和流程的分析不再局限于人类规模的思考。机器规模的分杂数析使企业能够发现大数据中的隐藏价值。

机器学习和数据分析最广泛使用的工具是 R 语言。除了是数据科学家最流行的语言外,R 是开源的,对所有用户都是免费的。R 编程语言提供了各种学习包和可视化函数,使用户能够实时分析数据。任何用户都可以轻松地在自己的数据集上使用 R 进行机器学习,而无需了解分析背后的数学模型的每一个细节。

《使用 R 的机器学习食谱》采用了一种实用的方法来教授您如何使用 R 进行机器学习。每一章都通过将这个主题分为几个简单的食谱向您介绍。通过每个食谱中提供的逐步说明,读者可以使用各种机器学习包构建一个预测模型。

在本书中,读者首先被指导如何设置 R 环境并使用简单的 R 命令来探索数据。接下来,我们将讨论如何使用机器学习分析进行统计分析以及评估创建的模型,这些内容将在本书的后续部分详细讨论。此外,本书还包含如何将 R 和 Hadoop 集成以创建大数据分析平台的内容。详细的插图提供了开始将机器学习应用于个人项目所需的所有信息。

使用《使用 R 的机器学习食谱》,用户会感觉到机器学习从未如此简单。

本书涵盖的内容

第一章,《实践中的 R 语言机器学习》,描述了如何创建一个现成的 R 环境。此外,我们还涵盖了所有基本的 R 操作,从将数据读入 R,操作数据,到执行简单的统计,再到数据可视化。

第二章, 使用 RMS 泰坦尼克号进行数据探索,为你提供了一个在 R 中进行探索性分析的机会。在本章中,我们将带你了解如何对 RMS 泰坦尼克号数据进行转换、分析和可视化。我们通过创建一个预测模型来识别泰坦尼克号悲剧的可能幸存者来结束本章。

第三章, R 和统计学,首先强调数据抽样和概率分布。随后,本章展示了如何在数据上执行描述性统计和推断性统计。

第四章, 理解回归分析,分析了因变量(响应变量)与一个或多个自变量(预测变量)集合之间的线性关系。你将学习如何使用不同的回归模型来理解数值关系,并将拟合的模型应用于数据以进行连续值预测。

第五章, 分类(I)- 树、懒惰、概率,教你如何将数据拟合到基于树的分类器、k 近邻分类器、逻辑回归分类器或朴素贝叶斯分类器。为了理解分类是如何工作的,我们提供了一个例子,目的是从电信数据集中识别可能的客户流失。

第六章, 分类(II)- 神经网络、SVM,介绍了两种复杂但强大的分类方法:神经网络和支持向量机。尽管这些方法性质复杂,但本章展示了如何在 R 中使用这些算法进行准确预测是多么容易。

第七章, 模型评估,揭示了你可以用来评估拟合模型性能的一些度量。有了这些度量,我们可以选择最优模型,该模型能够准确预测未来主题的响应。

第八章, 集成学习,介绍了如何使用集成学习者的力量来产生比单个学习者更好的分类和回归结果。由于集成学习者经常在许多数据预测竞赛中获胜,你应该知道如何将集成学习者应用于你的项目中。

第九章, 聚类,探讨了不同的聚类方法。聚类可以将相似的数据点分组在一起。在本章中,我们展示了如何应用聚类技术来细分客户,并进一步比较不同聚类方法之间的差异。

第十章, 关联分析和序列挖掘,向您展示了从交易数据中发现关联项目和潜在频繁模式所使用的常用方法。对于那些对了解研究人员如何发现顾客购买啤酒与购买尿布之间的著名关联感兴趣的人来说,本章是必读的。

第十一章, 降维,教您如何从原始变量中选择和提取特征。使用这种技术,我们可以消除冗余特征的影响,并降低计算成本以避免过拟合。为了更具体的例子,本章揭示了如何使用降维方法压缩和恢复图像。

第十二章"), 大数据分析 (R 和 Hadoop),揭示了如何使用 RHadoop,它允许 R 利用 Hadoop 的可扩展性,以便处理和分析大数据。我们涵盖了从设置 RHadoop 环境到实际的大数据处理和大数据机器学习的所有步骤。最后,我们探讨了如何使用 Amazon EC2 部署 RHadoop 集群。

附录 A, R 和机器学习资源,将为您提供 R 和机器学习的所有资源。

附录 B, 数据集 – 泰坦尼克号乘客生存数据,展示了泰坦尼克号乘客生存数据集。

您需要为本书准备的条件

要跟随本书的示例,您需要一个可以访问互联网并能安装 R 环境的计算机。您可以从 www.cran.r-project.org/ 下载 R。详细的安装说明可在第一章找到。

本书提供的示例使用 R 版本 3.1.2 编码并在安装了 Microsoft Windows 的计算机上进行了测试。这些示例也应该适用于安装在 MAC OSX 或类似 Unix 操作系统上的任何最新版本的 R。

本书面向的对象

本书非常适合那些想学习如何使用 R 进行机器学习并从数据中获得洞察力的人。无论您的经验水平如何,本书都涵盖了通过高级技术将 R 应用于机器学习的基础知识。虽然如果您熟悉基本的编程或机器学习概念会有所帮助,但您不需要先前的经验就能从本书中受益。

部分

在这本书中,您将找到一些频繁出现的标题(准备、如何做、如何工作、更多内容、相关内容)。

为了清楚地说明如何完成食谱,我们使用以下这些部分:

准备工作

本部分告诉您在食谱中可以期待什么,并描述了如何设置任何软件或任何为食谱所需的初步设置。

如何做…

本部分包含遵循食谱所需的步骤。

如何工作…

本部分通常包含对上一部分发生事件的详细解释。

更多内容…

本部分包含有关食谱的附加信息,以便让读者对食谱有更深入的了解。

相关内容

本部分提供了对其他有用信息的链接,以帮助读者更好地了解食谱。

惯例

本书包含多种文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。

文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称的显示方式如下:“使用rpart函数构建分类树模型。”

代码块设置如下:

> churn.rp = rpart(churn ~ ., data=trainset)

任何命令行输入或输出都按以下方式编写:

$ sudo R CMD INSTALL rmr2_3.3.0.tar.gz

新术语重要词汇以粗体显示。您在屏幕上看到的单词,例如在菜单或对话框中,将以以下格式显示:“在 R 中,缺失值用符号NA(不可用)表示,不可能的值是NaN(非数字)。”

注意

警告或重要提示会以这样的框出现。

小贴士

小技巧和窍门看起来像这样。

读者反馈

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

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

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

客户支持

现在您已经是 Packt 图书的骄傲拥有者,我们有一些事情可以帮助您充分利用您的购买。

下载示例代码

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

勘误

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

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

盗版

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

请通过 <copyright@packtpub.com> 联系我们,并提供涉嫌盗版材料的链接。

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

问题

如果您在这本书的任何方面遇到问题,您可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决问题。

第一章:使用 R 进行实用机器学习

在本章中,我们将涵盖以下主题:

  • 下载和安装 R

  • 下载和安装 RStudio

  • 安装和加载包

  • 读取和写入数据

  • 使用 R 操作数据

  • 应用基本统计

  • 可视化数据

  • 获取机器学习数据集

简介

机器学习的目的是从数据中揭示隐藏的模式、未知的相关性,并找到有用的信息。除此之外,通过结合数据分析,机器学习可以用于执行预测分析。使用机器学习,对商业运营和流程的分析不仅限于人类规模的思考;机器规模的分束能够使企业捕捉到大数据中的隐藏价值。

机器学习与人类推理过程有相似之处。与传统的分析不同,生成的模型不能随着数据的积累而进化。机器学习可以从处理和分析的数据中学习。换句话说,处理的数据越多,它就能学到的越多。

R,作为 GNU-S 方言的一种,是一种强大的统计语言,可以用来操作和分析数据。此外,R 提供了许多机器学习包和可视化函数,使用户能够即时分析数据。最重要的是,R 是开源的且免费的。

使用 R 极大地简化了机器学习。您需要知道的是每个算法如何解决您的问题,然后您只需简单地使用一个编写的包,通过几条命令行快速生成数据上的预测模型。例如,您可以对垃圾邮件过滤执行朴素贝叶斯,对客户细分执行 k-means 聚类,使用线性回归预测房价,或者实现一个隐马尔可夫模型来预测股市,如下面的截图所示:

介绍

使用 R 进行股票市场预测

此外,您还可以执行非线性降维来计算图像数据的相似度,并可视化聚类图,如下面的截图所示。您需要做的只是遵循本书中提供的菜谱。

介绍

面部图像数据的聚类图

本章作为机器学习和 R 的整体介绍;前几道菜谱介绍了如何设置 R 环境和集成开发环境 RStudio。在设置环境之后,接下来的菜谱介绍了包的安装和加载。为了理解如何使用 R 进行数据分析,接下来的四个菜谱涵盖了使用 R 进行数据读取/写入、数据处理、基本统计和数据可视化。本章的最后一道菜谱列出了有用的数据来源和资源。

下载和安装 R

要使用 R,您必须首先在您的计算机上安装它。这道菜谱提供了如何下载和安装 R 的详细说明。

准备工作

如果您是 R 语言的初学者,您可以在官方网站上找到详细介绍、语言历史和功能(www.r-project.org)。当您准备好下载和安装 R 时,请访问以下链接:cran.r-project.org/

如何操作...

请按照以下步骤下载和安装适用于 Windows 和 Mac 用户版本的 R:

  1. 前往 R CRAN 网站,www.r-project.org/,并点击 下载 R 链接,即 cran.r-project.org/mirrors.html):如何操作...

  2. 您可以选择离您最近的镜像位置:如何操作...

    CRAN 镜像

  3. 根据您的操作系统选择正确的下载链接:如何操作...

    根据您的操作系统点击下载链接

由于 Windows 和 Mac 安装 R 的步骤不同,因此为每个操作系统提供了安装 R 所需的步骤。

对于 Windows 用户:

  1. 点击 下载 R for Windows,如图所示,然后点击 基础版如何操作...

    前往“下载 Windows 版 R”并点击“基础版”

  2. 点击 下载 R 3.x.x for Windows如何操作...

    点击“下载 R 3.x.x for Windows”

  3. 安装文件应该已下载。下载完成后,您可以双击安装文件并开始安装 R:如何操作...

  4. Windows 版 R 的安装相当简单;安装 GUI 可能会逐步指导您如何安装程序(公共许可协议、目标位置、选择组件、启动选项、启动菜单文件夹以及选择附加任务)。如果您不想进行任何更改,请保留所有安装选项为默认设置。

  5. 安装完成后,R 应用程序的快捷方式将出现在您的开始菜单中,这将打开 R 控制台:如何操作...

    Windows R 控制台

对于 Mac OS X 用户:

  1. 前往 下载 (Mac) OS X 版 R,如图所示。

  2. 根据您的 Mac OS 版本点击最新版本(.pkg 文件扩展名):如何操作...

  3. 双击下载的安装文件(.pkg 扩展名)并开始安装 R。如果您不想进行任何更改,请保留所有安装选项为默认设置:如何操作...

  4. 按照屏幕上的说明,简介阅读我许可协议目标选择安装类型安装摘要,并点击 继续 以完成安装。

  5. 文件安装完成后,您可以使用 Spotlight 搜索 或转到应用程序文件夹来查找 R:如何操作...

    使用“Spotlight 搜索”查找 R

  6. 点击 R 打开 R 控制台如何操作...

作为下载 Mac .pkg 文件安装 R 的替代方案,Mac 用户也可以使用 Homebrew 安装 R:

  1. xquartz.macosforge.org/landing/ 下载 XQuartz-2.X.X.dmg

  2. 双击 .dmg 文件以挂载它。

  3. 使用以下命令行更新 brew:

    $ brew update
    
    
  4. 克隆仓库并将所有公式链接到 homebrew/science

    $ brew tap homebrew/science
    
    
  5. 安装 gfortran:

    $ brew install gfortran
    
    
  6. 安装 R:

    $ brew install R
    
    

对于 Linux 用户,有预编译的二进制文件适用于 Debian、Red Hat、SUSE 和 Ubuntu。或者,您也可以从源代码安装 R。除了下载预编译的二进制文件外,您还可以通过包管理器安装 R。以下是 CentOS 和 Ubuntu 的安装步骤。

在 Ubuntu 上下载和安装 R:

  1. 将条目添加到 /etc/apt/sources.list 文件中:

    $ sudo sh -c "echo 'deb http:// cran.stat.ucla.edu/bin/linux/ubuntu precise/' >> /etc/apt/sources.list"
    
    
  2. 然后,更新仓库:

    $ sudo apt-get update
    
    
  3. 使用以下命令安装 R:

    $ sudo apt-get install r-base
    
    
  4. 在命令行中启动 R:

    $ R
    
    

在 CentOS 5 上下载和安装 R:

  1. 获取 rpm CentOS5 RHEL EPEL 仓库的 CentOS5:

    $ wget http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
    
    
  2. 安装 CentOS5 RHEL EPEL 仓库:

    $ sudo rpm -Uvh epel-release-5-4.noarch.rpm
    
    
  3. 更新已安装的软件包:

    $ sudo yum update
    
    
  4. 通过仓库安装 R:

    $ sudo yum install R
    
    
  5. 在命令行中启动 R:

    $ R
    
    

在 CentOS 6 上下载和安装 R:

  1. 获取 rpm CentOS5 RHEL EPEL 仓库的 CentOS6:

    $ wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
    
    
  2. 安装 CentOS5 RHEL EPEL 仓库:

    $ sudo rpm -Uvh epel-release-6-8.noarch.rpm
    
    
  3. 更新已安装的软件包:

    $ sudo yum update
    
    
  4. 通过仓库安装 R:

    $ sudo yum install R
    
    
  5. 在命令行中启动 R:

    $ R
    
    

它是如何工作的...

CRAN 为 Linux、Mac OS X 和 Windows 提供预编译的二进制文件。对于 Mac 和 Windows 用户,安装过程很简单。您通常可以遵循屏幕上的说明来完成安装。对于 Linux 用户,您可以使用每个平台提供的包管理器安装 R 或从源代码构建 R。

参见

下载和安装 RStudio

要编写 R 脚本,可以使用 R 控制台、R 命令行或任何文本编辑器(EMACS、VIM 或 sublime)。然而,使用 R 的集成开发环境(IDE)RStudio 的帮助可以使开发变得更加容易。

RStudio 提供了全面的软件开发工具。内置功能,如语法高亮、代码补全和智能缩进,有助于最大化生产力。为了使 R 编程更易于管理,RStudio 还将主界面集成到一个四面板布局中。它包括一个交互式 R 控制台、一个标签页式的源代码编辑器、一个用于当前活动对象/历史的面板,以及一个标签页式的面板用于文件浏览器/绘图窗口/包安装窗口/R 帮助窗口。此外,RStudio 是开源的,适用于许多平台,如 Windows、Mac OS X 和 Linux。本食谱展示了如何下载和安装 RStudio。

准备工作

RStudio 需要一个有效的 R 安装;当 RStudio 加载时,它必须能够定位到一个 R 版本。因此,您必须在安装 RStudio 之前完成之前步骤,确保您的操作系统上已安装 R。

如何操作...

对于 Windows 和 Mac 用户,请按照以下步骤下载和安装 RStudio:

  1. 通过以下网址访问 RStudio 的官方网站:www.rstudio.com/products/RStudio/.如何操作...

  2. 对于桌面版本安装,点击 下载 RStudio 桌面版 (www.rstudio.com/products/rstudio/download/) 并选择适合您系统的 RStudio。下载相关包:如何操作...

  3. 双击下载的包来安装 RStudio。对于 Windows 用户,请按照屏幕上的说明安装应用程序:如何操作...

  4. 对于 Mac 用户,只需将 RStudio 图标拖到 应用程序 文件夹:如何操作...

  5. 启动 RStudio:如何操作...

    RStudio 控制台

对于 Ubuntu/Debian 和 RedHat/Centos 用户,请按照以下步骤下载和安装 RStudio:

对于 Debian(6+)/Ubuntu(10.04+) 32 位系统:

$ wget http://download1.rstudio.org/rstudio-0.98.1091-i386.deb
$ sudo gdebi rstudio-0.98\. 1091-i386.deb

对于 Debian(6+)/Ubuntu(10.04+) 64 位系统:

$ wget http://download1.rstudio.org/rstudio-0.98\. 1091-amd64.deb
$ sudo gdebi rstudio-0.98\. 1091-amd64.deb

对于 RedHat/CentOS(5,4+) 32 位系统:

$ wget http://download1.rstudio.org/rstudio-0.98\. 1091-i686.rpm
$ sudo yum install --nogpgcheck rstudio-0.98\. 1091-i686.rpm

对于 RedHat/CentOS(5,4+) 64 位系统:

$ wget http://download1.rstudio.org/rstudio-0.98\. 1091-x86_64.rpm
$ sudo yum install --nogpgcheck rstudio-0.98\. 1091-x86_64.rpm

工作原理

RStudio 程序可以在桌面或通过网页浏览器运行。桌面版本适用于 Windows、Mac OS X 和 Linux 平台,所有平台上的操作类似。对于 Windows 和 Mac 用户,在下载 RStudio 的预编译包后,按照屏幕上的说明(如前所述步骤),完成安装。Linux 用户可以使用提供的包管理系统进行安装。

参见

  • 除了桌面版本外,用户还可以安装服务器版本,以便为多个用户提供访问权限。服务器版本提供了一个用户可以访问以使用 RStudio 资源的 URL。要安装 RStudio,请参阅以下链接:www.rstudio.com/ide/download/server.html。此页面提供了以下 Linux 发行版的安装说明:Debian (6+)、Ubuntu (10.04+)、RedHat 和 CentOS (5.4+)。

  • 对于其他 Linux 发行版,您可以从源代码构建 RStudio。

安装和加载包

在成功安装 R 之后,用户可以从存储库中下载、安装和更新包。由于 R 允许用户创建自己的包,因此提供了官方和非官方的存储库来管理这些用户创建的包。CRAN是官方的 R 包存储库。目前,CRAN 包存储库有 6,379 个可用的包(截至 2015 年 2 月 27 日)。通过使用 CRAN 上提供的包,用户可以扩展 R 的功能,用于机器学习、统计学和相关目的。CRAN 是一个全球范围内的 FTP 和 Web 服务器网络,存储着 R 的代码和文档的相同、最新版本。你可以选择离你位置最近的 CRAN 镜像来下载包。

准备工作

在你的主机计算机上启动一个 R 会话。

如何操作...

执行以下步骤来安装和加载 R 包:

  1. 要加载已安装包的列表:

    > library()
    
    
  2. 设置默认 CRAN 镜像:

    > chooseCRANmirror()
    
    

R 将返回 CRAN 镜像列表,然后询问用户是输入镜像 ID 来选择它,还是输入零来退出:

  1. 从 CRAN 安装一个包;以包 e1071 为例:

    > install.packages("e1071")
    
    
  2. 从 CRAN 更新一个包;以包 e1071 为例:

    > update.packages("e1071")
    
    
  3. 加载包:

    > library(e1071)
    
    
  4. 如果你想要查看包的文档,你可以使用help函数:

    > help(package ="e1071")
    
    
  5. 如果你想要查看函数的文档,你可以使用help函数:

    > help(svm, e1071)
    
    
  6. 或者,你可以使用帮助快捷键?来查看该函数的帮助文档:

    > ?e1071::svm
    
    
  7. 如果函数没有提供任何文档,你可能需要搜索提供的文档中与给定关键字相关的文档。例如,如果你想要搜索与svm相关的文档:

    > help.search("svm")
    
    
  8. 或者,你可以使用??作为help.search的快捷键:

    > ??svm
    
    
  9. 要查看函数所接受的参数,只需使用args函数。例如,如果你想知道lm函数所接受的参数:

    > args(lm)
    
    
  10. 一些包会提供示例和演示;你可以使用exampledemo来查看示例或演示。例如,可以通过输入以下命令来查看lm包的示例和graphics包的演示:

    > example(lm)
    > demo(graphics)
    
    
  11. 要查看所有可用的演示,你可以使用demo函数来列出它们:

    > demo()
    
    

它是如何工作的

本食谱首先介绍了如何查看已加载的包、从 CRAN 安装包以及加载新包。在安装包之前,对 CRAN 包列表感兴趣的读者可以参考cran.r-project.org/web/packages/available_packages_by_name.html

当安装包时,也会提供与包相关的文档。因此,你可以查看已安装包和函数的文档或相关帮助页面。此外,一些包还提供了演示和示例,可以帮助用户了解已安装包的功能。

参见

  • 除了从 CRAN 安装包外,还有其他 R 包仓库,包括 Crantastic,这是一个用于评分和评论 CRAN 包的社区网站,以及 R-Forge,这是一个 R 包协作开发的中心平台。此外,Bioconductor 提供用于基因组数据分析的 R 包。

  • 如果您想查找相关的函数和包,请访问任务视图列表 cran.r-project.org/web/views/,或搜索关键词 rseek.org

读写数据

在开始探索数据之前,您必须将数据加载到 R 会话中。本食谱将介绍从文件中加载数据到内存或使用 R 中的预定义数据的方法。

准备工作

首先,在您的机器上启动一个 R 会话。由于本食谱涉及文件 I/O 步骤,如果用户没有指定完整路径,读写活动将在当前工作目录中进行。

您可以直接在 R 会话中输入 getwd() 以获取当前工作目录位置。但是,如果您想更改当前工作目录,可以使用 setwd("<path>"),其中 <path> 可以替换为您希望指定的路径,以指定工作目录。

如何操作...

执行以下步骤以使用 R 读写数据:

  1. 要查看 R 的内置数据集,请输入以下命令:

    > data()
    
    
  2. R 将返回 dataset 包中的数据集列表,列表包括每个数据集的名称和描述。

  3. 要将数据集 iris 加载到 R 会话中,请输入以下命令:

    > data(iris)
    
    
  4. iris 数据集现在已加载到数据框格式中,这是 R 中存储数据表的常见数据结构。

  5. 要查看 iris 的数据类型,只需使用 class 函数:

    > class(iris)
    [1] "data.frame"
    
    
  6. data.frame 控制台打印显示,iris 数据集是以数据框的结构存在的。

  7. 使用 save 函数将对象存储到文件中。例如,要将加载的 iris 数据保存到 myData.RData,请使用以下命令:

    > save(iris, file="myData.RData")
    
    
  8. 使用 load 函数将保存的对象读入 R 会话。例如,要从 myData.RData 加载 iris 数据,请使用以下命令:

    > load("myData.RData")
    
    
  9. 除了使用内置数据集外,R 还提供了一个函数,可以将文本数据导入到数据框中。例如,read.table 函数可以将给定的文本格式化为数据框:

    > test.data = read.table(header = TRUE, text = "
    + a b
    + 1 2
    + 3 4
    + ")
    
    
  10. 您还可以使用 row.namescol.names 来指定列和行的名称:

    > test.data = read.table(text = "
    + 1 2
    + 3 4", 
    + col.names=c("a","b"),
    + row.names = c("first","second"))
    
    
  11. 查看 test.data 变量的类:

    > class(test.data)
    [1] "data.frame"
    
    
  12. class 函数显示 test.data 变量包含一个数据框。

  13. 除了使用 read.table 函数导入数据外,您还可以使用 write.table 函数将数据导出到文本文件:

    > write.table(test.data, file = "test.txt" , sep = " ")
    
    
  14. write.table 函数将 test.data 的内容写入 test.txt(写入路径可以通过输入 getwd() 查找),以空格作为分隔符。

  15. write.table 类似,write.csv 也可以将数据导出到文件。但是,write.csv 使用逗号作为默认分隔符:

    > write.csv(test.data, file = "test.csv")
    
    
  16. 使用 read.csv 函数,可以将 csv 文件导入为数据框。然而,最后一个示例将数据框的列名和行名写入 test.csv 文件。因此,在函数中指定 header 为 TRUE 并将行名作为第一列可以确保读取的数据框不会将标题和第一列视为值:

    > csv.data = read.csv("test.csv", header = TRUE, row.names=1)
    > head(csv.data)
     a b
    1 1 2
    2 3 4
    
    

工作原理

通常,收集的数据可能存在于多个文件和不同的格式中。为了在文件和 RData 之间交换数据,R 提供了许多内置函数,例如 saveloadread.csvread.tablewrite.csvwrite.table

此示例首先演示了如何将内置数据集 iris 载入 R 会话。iris 数据集是机器学习领域中最为著名和常用的数据集。在此,我们使用 iris 数据集作为示例。食谱展示了如何使用 saveload 函数保存 RData 并加载它。此外,示例解释了如何使用 read.tablewrite.tableread.csvwrite.csv 从文件交换数据到数据框。使用 R IO 函数读取和写入数据非常重要,因为大多数数据源都是外部的。因此,你必须使用这些函数将数据加载到 R 会话中。

相关内容

对于 loadread.tableread.csv 函数,要读取的文件也可以是一个完整的 URL(对于支持的 URL,使用 ?url 获取更多信息)。

在某些情况下,数据可能存在于 Excel 文件中而不是平面文本文件中。WriteXLS 包允许将对象写入 Excel 文件,其中第一个参数是给定的变量,第二个参数是要写入的文件:

  1. 安装 WriteXLS 包:

    > install.packages("WriteXLS")
    
    
  2. 载入 WriteXLS 包:

    > library("WriteXLS")
    
    
  3. 使用 WriteXLS 函数将数据框 iris 写入名为 iris.xls 的文件:

    > WriteXLS("iris", ExcelFileName="iris.xls")
    
    

使用 R 操作数据

本食谱将讨论如何使用内置的 R 函数来操作数据。由于数据操作是大多数分析过程中最耗时的部分,你应该了解如何应用这些函数于数据。

准备工作

确保你已经完成了之前的食谱,通过在你的操作系统上安装 R 来完成。

如何操作...

执行以下步骤以使用 R 操作数据。

使用花括号表示法对数据进行子集化:

  1. 将数据集 iris 载入 R 会话:

    > data(iris)
    
    
  2. 要选择值,你可以使用括号表示法来指定数据集的索引。第一个索引用于行,第二个用于列:

    > iris[1,"Sepal.Length"]
    [1] 5.1
    
    
  3. 你也可以使用 c() 选择多个列:

    > Sepal.iris = iris[, c("Sepal.Length", "Sepal.Width")]
    
    
  4. 然后,你可以使用 str() 来总结并显示 Sepal.iris 的内部结构:

    > str(Sepal.iris)
    'data.frame':  150 obs. of  2 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ..
    
    
  5. 要使用给定索引的行来子集化数据,你可以在第一个索引处使用括号表示法指定索引。在这个例子中,我们向你展示如何使用Sepal.Length列和选定的Sepal.Width来子集化数据的前五条记录:

    > Five.Sepal.iris = iris[1:5, c("Sepal.Length", "Sepal.Width")]
    > str(Five.Sepal.iris)
    'data.frame':	5 obs. of  2 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6
    
    
  6. 还可以设置条件来过滤数据。例如,要过滤返回包含所有五个变量的 setosa 数据,以下示例中,第一个索引指定返回标准,第二个索引指定返回变量的索引范围:

    > setosa.data = iris[iris$Species=="setosa",1:5]
    > str(setosa.data)
    'data.frame':	50 obs. of  5 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
     $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
     $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
     $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
    
    
  7. 或者,which函数返回满足条件的数据的索引。以下示例返回包含物种等于setosa的鸢尾花数据的索引:

    > which(iris$Species=="setosa")
     [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18
    [19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
    [37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50
    
    
  8. 操作返回的索引可以应用于选择包含 setosa 物种的鸢尾花。以下示例返回包含所有五个变量的 setosa:

    > setosa.data = iris[which(iris$Species=="setosa"),1:5]
    > str(setosa.data)
    'data.frame':	50 obs. of  5 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
     $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
     $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
     $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
    
    

使用subset函数进行数据子集化:

  1. 除了使用括号表示法外,R 还提供了一个subset函数,允许用户通过逻辑语句对数据框进行子集化。

  2. 首先,从鸢尾花数据中子集化物种、花瓣长度和花瓣宽度。要选择鸢尾花数据中的花瓣长度和宽度,应在select参数中指定要子集化的列:

    > Sepal.data = subset(iris, select=c("Sepal.Length", "Sepal.Width"))
    > str(Sepal.data)
    'data.frame': 150 obs. of  2 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
    
    

这表明Sepal.data包含 150 个对象,具有Sepal.Length变量和Sepal.Width

  1. 另一方面,你可以使用子集参数来获取仅包含 setosa 的数据子集。在subset函数的第二参数中,你可以指定子集标准:

    > setosa.data = subset(iris, Species =="setosa")
    > str(setosa.data)
    'data.frame': 50 obs. of  5 variables:
     $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
     $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
     $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
     $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
     $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
    
    
  2. 大多数时候,在子集化数据时,你可能想要应用一个并集或交集条件。为此,可以进一步使用 OR 和 AND 操作。例如,如果你想检索Petal.Width >=0.2 and Petal.Length <= 1.4的数据:

    > example.data= subset(iris, Petal.Length <=1.4 & Petal.Width >= 0.2, select=Species )
    > str(example.data)
    'data.frame': 21 obs. of  1 variable:
     $ Species: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
    
    

合并数据:合并数据涉及通过公共列或行名将两个数据框合并到一个合并的数据框中。以下示例显示了如何通过Species列中的公共行名将flower.type数据框和鸢尾花的头三行合并:

> flower.type = data.frame(Species = "setosa", Flower = "iris")
> merge(flower.type, iris[1:3,], by ="Species")
 Species Flower Sepal.Length Sepal.Width Petal.Length Petal.Width
1  setosa   iris          5.1         3.5          1.4         0.2
2  setosa   iris          4.9         3.0          1.4         0.2
3  setosa   iris          4.7         3.2          1.3         0.2

排序数据order函数将返回一个按指定列排序的数据框的索引。以下示例显示了按花瓣长度排序(从大到小)的鸢尾花数据的前六条记录的结果

> head(iris[order(iris$Sepal.Length, decreasing = TRUE),])
 Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
132          7.9         3.8          6.4         2.0 virginica
118          7.7         3.8          6.7         2.2 virginica
119          7.7         2.6          6.9         2.3 virginica
123          7.7         2.8          6.7         2.0 virginica
136          7.7         3.0          6.1         2.3 virginica
106          7.6         3.0          6.6         2.1 virginica

工作原理

在进行数据分析之前,将收集到的数据组织成结构化格式非常重要。因此,我们可以简单地使用 R 数据框来子集化、合并和排序数据集。本食谱首先介绍了两种子集化数据的方法:一种使用括号表示法,另一种使用subset函数。你可以使用这两种方法通过选择列和根据给定标准过滤数据来生成子集数据。然后,本食谱介绍了merge函数来合并数据框。最后,本食谱介绍了如何使用order来排序数据。

还有更多...

subgsub 函数允许使用正则表达式来替换字符串。subgsub 函数分别执行第一次和所有其他匹配的替换:

> sub("e", "q", names(iris))
[1] "Sqpal.Length" "Sqpal.Width"  "Pqtal.Length" "Pqtal.Width"  "Spqcies" 
> gsub("e", "q", names(iris))
[1] "Sqpal.Lqngth" "Sqpal.Width"  "Pqtal.Lqngth" "Pqtal.Width"  "Spqciqs"

应用基本统计

R 提供了广泛的统计函数,使用户能够获取数据的汇总统计信息,生成频率和列联表,生成相关系数,并进行统计推断。本食谱涵盖了可以应用于数据集的基本统计方法。

准备工作

确保您已经通过在操作系统上安装 R 完成了前面的食谱。

如何操作...

执行以下步骤以在数据集上应用统计:

  1. 将 iris 数据加载到 R 会话中:

    > data(iris)
    
    
  2. 观察数据的格式:

    > class(iris)
     [1] "data.frame"
    
    
  3. iris 数据集是一个包含四个数值属性的数据框:花瓣长度花瓣宽度萼片宽度萼片长度。对于数值值,可以执行描述性统计,如 meansdvarminmaxmedianrangequantile。这些可以应用于数据集中的任意四个属性:

    > mean(iris$Sepal.Length)
    [1] 5.843333
    > sd(iris$Sepal.Length)
    [1] 0.8280661
    > var(iris$Sepal.Length)
    [1] 0.6856935
    > min(iris$Sepal.Length)
    [1] 4.3
    > max(iris$Sepal.Length)
    [1] 7.9
    > median(iris$Sepal.Length)
    [1] 5.8
    > range(iris$Sepal.Length)
    [1] 4.3 7.9
    > quantile(iris$Sepal.Length)
     0%  25%  50%  75% 100% 
     4.3  5.1  5.8  6.4  7.9
    
    
  4. 上述示例演示了如何对一个单一变量应用描述性统计。为了获取数据框中每个数值属性的汇总统计信息,可以使用 sapply。例如,为了在 iris 数据框的前四个属性上应用均值,通过将 na.rm 设置为 TRUE 来忽略 na 值:

    > sapply(iris[1:4], mean, na.rm=TRUE)
    Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
     5.843333     3.057333     3.758000     1.199333 
    
    
  5. 作为使用 sapply 在给定属性上应用描述性统计的替代方法,R 提供了 summary 函数,该函数提供了全面的描述性统计。在以下示例中,summary 函数提供了每个 iris 数据集数值属性的均值、中位数、第 25 和第 75 分位数、最小值和最大值:

    > summary(iris)
    Sepal.Length    Sepal.Width     Petal.Length    Petal.Width    Species 
     Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100   setosa    :50 
     1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300   versicolor:50 
     Median :5.800   Median :3.000   Median :4.350   Median :1.300   virginica :50 
     Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199 
     3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800 
     Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500
    
    
  6. 上述示例展示了如何输出单一变量的描述性统计。R 还提供了相关系数,供用户研究变量之间的关系。以下示例通过计算 iris 数据集中每个属性对的相关性来生成一个 4x4 矩阵:

    > cor(iris[,1:4])
     Sepal.Length Sepal.Width Petal.Length Petal.Width
    Sepal.Length    1.0000000  -0.1175698    0.8717538   0.8179411
    Sepal.Width    -0.1175698   1.0000000   -0.4284401  -0.3661259
    Petal.Length    0.8717538  -0.4284401    1.0000000   0.9628654
    Petal.Width     0.8179411  -0.3661259    0.9628654   1.0000000
    
    
  7. R 还提供了一个函数来计算 iris 数据集中每个属性对的协方差:

    > cov(iris[,1:4])
     Sepal.Length Sepal.Width Petal.Length Petal.Width
    Sepal.Length    0.6856935  -0.0424340    1.2743154   0.5162707
    Sepal.Width    -0.0424340   0.1899794   -0.3296564  -0.1216394
    Petal.Length    1.2743154  -0.3296564    3.1162779   1.2956094
    Petal.Width     0.5162707  -0.1216394    1.2956094   0.5810063
    
    
  8. 通过进行统计测试来评估结果的显著性;在此示例中,我们演示了如何使用 t-test 来确定两个样本之间的统计差异。在此示例中,我们对 setosa 或 versicolor 物种中 iris 的花瓣宽度进行了 t.test。如果我们获得小于 0.5 的 p 值,我们可以确信 setosa 和 versicolor 之间的花瓣宽度将会有显著差异:

    > t.test(iris$Petal.Width[iris$Species=="setosa"], 
    +        iris$Petal.Width[iris$Species=="versicolor"])
    
     Welch Two Sample t-test
    
    data:  iris$Petal.Width[iris$Species == "setosa"] and iris$Petal.Width[iris$Species == "versicolor"]
    t = -34.0803, df = 74.755, p-value < 2.2e-16
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -1.143133 -1.016867
    sample estimates:
    mean of x mean of y 
     0.246     1.326
    
    
  9. 或者,您可以对 iris 的萼片长度与萼片宽度进行相关性测试,然后检索两个变量之间的相关性得分。正相关越强,值越接近 1。负相关越强,值越接近 -1:

    > cor.test(iris$Sepal.Length, iris$Sepal.Width)
    
     Pearson's product-moment correlation
    
    data:  iris$Sepal.Length and iris$Sepal.Width
    t = -1.4403, df = 148, p-value = 0.1519
    alternative hypothesis: true correlation is not equal to 0
    95 percent confidence interval:
     -0.27269325  0.04351158
    sample estimates:
     cor 
    -0.1175698 
    
    

工作原理...

R 有一个内置的统计函数,使用户能够对单个变量执行描述性统计。本食谱首先介绍了如何将 meansdvarminmaxmedianrangequantile 应用于单个变量。此外,为了将统计应用于所有四个数值变量,可以使用 sapply 函数。为了确定多个变量之间的关系,可以进行相关性和协方差分析。最后,本食谱展示了如何通过执行统计测试来确定两个给定样本的统计差异。

更多...

如果你需要针对不同组的数据计算汇总统计量,你可以使用 aggregatereshape 函数来计算数据子集的汇总统计量:

  1. 使用 aggregate 计算每个鸢尾花属性组的平均值,按物种分组:

    > aggregate(x=iris[,1:4],by=list(iris$Species),FUN=mean)
    
    
  2. 使用 reshape 计算每个鸢尾花属性组的平均值,按物种分组:

    >  library(reshape)
    >  iris.melt <- melt(iris,id='Species')
    >  cast(Species~variable,data=iris.melt,mean,
     subset=Species %in% c('setosa','versicolor'),
     margins='grand_row') 
    
    

关于 reshapeaggregate 的信息,请使用 ?reshape?aggregate 查看帮助文档。

数据可视化

可视化是通过图形手段传达信息的一种强大方式。视觉呈现使数据更容易理解。本食谱介绍了一些基本的绘图函数,并展示了可视化在数据探索中的帮助。

准备工作

确保你已经通过在操作系统上安装 R 完成了前面的食谱。

如何操作...

执行以下步骤以可视化数据集:

  1. 将鸢尾花数据加载到 R 会话中:

    > data(iris)
    
    
  2. 使用 table 命令计算鸢尾花中物种的频率:

    > table.iris = table(iris$Species)
    > table.iris
    
     setosa versicolor  virginica 
     50         50         50 
    
    
  3. 如表中的频率所示,每个物种代表鸢尾花数据的 1/3。我们可以绘制一个简单的饼图来表示鸢尾花中物种的分布:

    > pie(table.iris)
    
    

    如何操作...

    物种分布的饼图

  4. 直方图在 x-轴上创建一种频率图。以下示例生成花瓣长度的直方图:

    > hist(iris$Sepal.Length)
    
    

    如何操作...

    花瓣长度的直方图

  5. 在直方图中,x-轴表示花瓣长度,y-轴表示不同花瓣长度的计数。直方图显示,对于大多数鸢尾花,花瓣长度范围在 4 厘米到 8 厘米之间。

  6. 箱线图,也称为箱线图,允许你在一张简单的图表中传达大量信息。在这种图表中,线代表样本的中位数。箱子本身显示上四分位数和下四分位数。胡须显示范围:

    > boxplot(Petal.Width ~ Species, data = iris)
    
    

    如何操作...

    花瓣宽度的箱线图

  7. 前面的截图清楚地显示了 Setosa 的花瓣宽度中位数和上四分位数比 versicolor 和 virginica 短得多。因此,花瓣宽度可以用作区分鸢尾花物种的重要属性。

  8. 当有两个变量需要相互绘制时,会使用散点图。此例将花瓣长度与花瓣宽度绘制,并用颜色点表示它所属的物种:

    > plot(x=iris$Petal.Length, y=iris$Petal.Width, col=iris$Species)
    
    

    如何操作...

    萼片长度的散点图

  9. 上一张截图是花瓣长度与花瓣宽度的散点图。由于 iris 数据集中有四个属性,因此需要六次操作才能绘制所有组合。然而,R 提供了一个名为pairs的函数,可以在一个图中生成每个子图:

    > pairs(iris[1:4], main = "Edgar Anderson's Iris Data", pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)])
    
    

    如何操作...

    鸢尾花数据的成对散点图

工作原理...

R 提供了许多内置的绘图函数,使用户能够使用不同类型的图表可视化数据。本食谱演示了使用饼图来展示类别分布。等大小的饼图表明每种物种的数量相等。直方图绘制不同萼片长度的频率。箱线图可以传达大量的描述性统计信息,并表明可以使用花瓣宽度来区分鸢尾花物种。最后,我们介绍了散点图,它在一个图中绘制变量。为了快速生成包含所有鸢尾花数据对的散点图,可以使用pairs命令。

参考以下内容

  • ggplot2 是 R 的另一个绘图系统,基于 Leland Wilkinson 的图形语法实现。它允许用户以更高的抽象级别在图中添加、删除或更改组件。然而,与 lattice 图形相比,抽象级别的结果较慢。对于对 ggplot 感兴趣的用户,可以参考此网站:ggplot2.org/

获取机器学习数据集

虽然 R 有内置的数据集,但样本大小和应用领域有限。除了在模拟中生成数据外,另一种方法是获取外部数据仓库的数据。一个著名的数据仓库是 UCI 机器学习仓库,它包含人工和真实数据集。本食谱介绍了如何从 UCI 机器学习仓库获取样本数据集。

准备工作

确保您已通过在操作系统上安装 R 完成了前面的食谱。

如何操作...

执行以下步骤以检索机器学习数据:

  1. 访问 UCI 机器学习仓库:archive.ics.uci.edu/ml/如何操作...

    UCI 数据仓库

  2. 点击查看所有数据集。在这里,您将找到一个包含字段名称的数据集列表,例如名称数据类型默认任务属性类型实例数属性数年份如何操作...

  3. 使用Ctrl + F搜索Iris如何操作...

  4. 点击Iris。这将显示数据文件夹和数据集描述:如何操作...

  5. 点击数据文件夹,将显示包含鸢尾花数据集的目录:如何操作...

  6. 然后,您可以选择下载iris.data或使用read.csv函数读取数据集:

    > iris.data = read.csv(url("http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"), header = FALSE,  col.names = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species"))
    > head(iris.data)
     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
    1         5.1         3.5          1.4         0.2 Iris-setosa
    2         4.9         3.0          1.4         0.2 Iris-setosa
    3         4.7         3.2          1.3         0.2 Iris-setosa
    4         4.6         3.1          1.5         0.2 Iris-setosa
    5         5.0         3.6          1.4         0.2 Iris-setosa
    6         5.4         3.9          1.7         0.4 Iris-setosa
    
    

它是如何工作的...

在进行数据分析之前,收集您的数据集非常重要。然而,收集一个适合进一步探索和分析的适当数据集并不容易。因此,我们可以使用 UCI 存储库中的准备好的数据集作为我们的数据源。在这里,我们首先访问 UCI 数据集存储库,然后以鸢尾花数据集为例。我们可以通过使用浏览器的查找功能(Ctrl + F)找到鸢尾花数据集,然后进入文件目录。最后,我们可以下载数据集,并使用 R 的 IO 函数read.csv将鸢尾花数据集加载到 R 会话中。

参见

  • KDnuggets (www.kdnuggets.com/datasets/index.html) 提供了一个丰富的数据集列表,适用于数据挖掘和数据科学。您可以探索这个列表,以找到满足您要求的数据。

第二章:使用 RMS Titanic 进行数据探索

在本章中,我们将涵盖以下食谱:

  • 从 CSV 文件中读取 Titanic 数据集

  • 在字符变量上转换类型

  • 检测缺失值

  • 填充缺失值

  • 探索和可视化数据

  • 使用决策树预测乘客生存率

  • 使用混淆矩阵验证预测能力

  • 使用 ROC 曲线评估性能

简介

数据探索帮助数据消费者专注于搜索信息,目的是从收集到的信息中形成真正的分析。此外,在完成数据清洗、分析、建模和评估的步骤后,用户可以从他们专注的数据中生成见解和有价值的信息。

在一个真实的数据探索项目中,探索过程中涉及六个步骤。它们如下所示:

  1. 提出正确的问题。

  2. 数据收集。

  3. 数据清洗。

  4. 基本的数据探索分析。

  5. 高级数据探索分析。

  6. 模型评估。

这里提供了这六个步骤的更详细解释:

  1. 提出正确的问题:当用户提出问题,例如“探索完成后,我预期的发现是什么?”或“通过探索我可以提取哪些信息?”时,会得到不同的结果。因此,首先提出正确的问题是至关重要的,因为问题本身决定了探索的目标和对象。

  2. 数据收集:一旦确定了探索的目标,用户就可以开始从数据源收集或提取与探索目标相关的相关数据。大多数情况下,从不同的系统中收集的数据看起来是不规则的和格式多样的。显然,原始数据可能来自不同的来源,如文件、数据库或互联网。从这些来源检索数据需要文件 IO 函数、JDBC/ODBC、网络爬虫等的帮助。这种提取的数据被称为原始数据,因为它尚未经过处理,或经过任何其他操作。大多数原始数据不易被大多数分析工具或可视化程序消费。

  3. 数据清洗:下一个阶段是数据清洗(或整理),这是一个帮助将原始数据映射到更便于消费的格式的步骤。在这个阶段,有许多过程,如数据解析、排序、合并、过滤、缺失值补全以及其他转换和组织数据的过程,使其能够适应消费结构。随后,映射后的数据可以进一步用于数据聚合、分析或可视化。

  4. 基本探索性数据分析:在数据清洗阶段之后,用户可以进一步进行数据处理分析。最基本的分析是执行探索性数据分析。探索性数据分析涉及通过总结其特征来分析数据集。执行基本的统计、聚合和可视化方法对于帮助用户理解数据特征也是至关重要的任务,这有助于用户通过图表轻松捕捉到大多数、趋势和异常值。

  5. 高级探索性数据分析:到目前为止,描述性统计提供了数据特征的总体描述。然而,人们希望为用户提供一个基于输入参数预测数据特征的推理规则。因此,机器学习的应用使得用户能够生成一个推理模型,用户可以输入训练数据集以生成预测模型。之后,预测模型可以根据给定的参数预测输出值或标签。

  6. 模型评估:最后,为了评估生成的模型在给定问题的数据估计中是否表现最佳,必须进行模型选择。选择方法涉及许多步骤,包括数据预处理、调整参数,甚至切换机器学习算法。然而,有一点需要记住的是,最简单的模型通常在预测或探索能力方面取得最佳结果;而复杂的模型往往会导致过拟合。

对于以下示例,我们希望基于泰坦尼克号沉船幸存者数据集进行一次样本数据探索。我们在这里展示的步骤包括如何从在线资源 Kaggle 收集数据,通过数据清洗进行数据整理;执行基本的探索性数据分析以发现可能预测生存率的属性;使用分类算法进行高级探索性数据分析以预测给定数据的生存率;最后,执行模型评估以生成预测模型。

从 CSV 文件读取泰坦尼克号数据集

要开始探索,我们需要从 Kaggle(www.kaggle.com/)检索一个数据集。我们曾在第一章中查看了一些样本,实践机器学习与 R。在这里,我们介绍了处理现实世界问题的方法。

准备中

要从 Kaggle 检索数据,您首先需要注册一个 Kaggle 账户(www.kaggle.com/account/register)。然后,登录账户进行进一步探索:

准备中

Kaggle.com

如何操作...

执行以下步骤以从 CSV 文件读取泰坦尼克号数据集:

  1. 前往 www.kaggle.com/c/titanic-gettingStarted/data 获取数据列表。

  2. 您可以看到以下表格中列出的数据文件下载列表:

    文件名 可用格式
    train .csv (59.76 kb)
    genderclassmodel .py (4.68 kb)
    myfirstforest .csv (3.18 kb)
    myfirstforest .py (3.83 kb)
    gendermodel .csv (3.18 kb)
    genderclassmodel .csv (3.18 kb)
    test .csv (27.96 kb)
    gendermodel .py (3.58 kb)
  3. 将训练数据 (www.kaggle.com/c/titanic-gettingStarted/download/train.csv) 下载到本地磁盘。

  4. 然后,确保下载的文件放置在当前目录下。您可以使用 getwd 函数来检查当前工作目录。如果下载的文件不在工作目录中,请将文件移动到当前工作目录。或者,您可以使用 setwd() 将工作目录设置为下载文件所在的目录:

    > getwd()
    [1] "C:/Users/guest"
    
    
  5. 接下来,可以使用 read.csv 将数据加载到数据框中。在这里,可以使用 read.csv 函数读取 train.csv 并将数据框的变量名设置为 train.data。然而,为了将空白字符串视为 NA,可以指定 na.strings 等于 "NA" 或空字符串:

    > train.data = read.csv("train.csv", na.strings=c("NA", ""))
    
    
  6. 然后,使用 str 函数检查加载的数据:

    > str(train.data)
    'data.frame': 891 obs. of  12 variables:
     $ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
     $ Survived   : int  0 1 1 1 0 0 0 0 1 1 ...
     $ Pclass     : int  3 1 3 1 3 3 1 3 3 2 ...
     $ Name       : Factor w/ 891 levels "Abbing, Mr. Anthony",..: 109 191 358 277 16 559 520 629 417 581 ...
     $ Sex        : Factor w/ 2 levels "female","male": 2 1 1 1 2 2 2 2 1 1 ...
     $ Age        : num  22 38 26 35 35 NA 54 2 27 14 ...
     $ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
     $ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
     $ Ticket     : Factor w/ 681 levels "110152","110413",..: 524 597 670 50 473 276 86 396 345 133 ...
     $ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
     $ Cabin      : Factor w/ 148 levels "","A10","A14",..: 1 83 1 57 1 1 131 1 1 1 ...
     $ Embarked   : Factor w/ 4 levels "","C","Q","S": 4 2 4 4 4 3 4 4 4 2 ...
    
    

它是如何工作的...

要开始数据探索,我们首先从 Kaggle 下载了泰坦尼克号数据集,Kaggle 是一个包含许多数据竞赛和数据集的网站。为了将数据加载到数据框中,本食谱演示了如何使用 read.csv 函数并应用 na.strings 参数来加载数据集,目的是将空白字符串和 "NA" 转换为 NA 值。为了查看数据集的结构,我们使用了 str 函数来紧凑地显示 train.data;您可以看到数据集包含乘客的人口统计信息和生存标签。这里收集的数据对于初学者来说足够练习如何处理和分析数据。

还有更多...

在 Kaggle 上,大部分科学数据都与竞赛相关,这些竞赛大多涉及设计机器学习方法来解决现实世界问题。

Kaggle 上的大多数竞赛都是由学术界或企业机构举办的,例如亚马逊或 Facebook。实际上,他们创建这些竞赛并提供奖励,如奖金或就业前景(见 www.kaggle.com/competitions)。因此,许多数据科学家被吸引注册 Kaggle 账户以参加竞赛。一个在试点探索中的初学者可以参加这些竞赛之一,通过解决现实世界问题并运用他们的机器学习技能来获得经验。

为了创建一个更具挑战性的学习环境作为竞争对手,参与者需要提交他们的输出答案,并将收到评估分数,这样每个人都可以评估自己在排行榜上的排名。

在字符变量上转换类型

在 R 中,由于名义变量、有序变量、区间变量和比率变量在统计建模中被不同对待,我们必须将名义变量从字符类型转换为因子类型。

准备工作

您需要通过使用 read.csv 函数将泰坦尼克号训练数据加载到 R 会话中,并将 na.strings 参数设置为 NA 和空字符串 (""),然后,将加载的 train.csv 数据分配给 train.data 变量。

如何操作...

执行以下步骤以转换字符变量的类型:

  1. 使用 str 函数打印泰坦尼克号数据的概览:

    > str(train.data)
    'data.frame':  891 obs. of  12 variables:
     $ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
     $ Survived   : int  0 1 1 1 0 0 0 0 1 1 ...
     $ Pclass     : int  3 1 3 1 3 3 1 3 3 2 ...
     $ Name       : Factor w/ 891 levels "Abbing, Mr. Anthony",..: 109 191 358 277 16 559 520 629 417 581 ...
     $ Sex        : Factor w/ 2 levels "female","male": 2 1 1 1 2 2 2 2 1 1 ...
     $ Age        : num  22 38 26 35 35 NA 54 2 27 14 ...
     $ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
     $ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
     $ Ticket     : Factor w/ 681 levels "110152","110413",..: 524 597 670 50 473 276 86 396 345 133 ...
     $ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
     $ Cabin      : Factor w/ 147 levels "A10","A14","A16",..: NA 82 NA 56 NA NA 130 NA NA NA ...
     $ Embarked   : Factor w/ 3 levels "C","Q","S": 3 1 3 3 3 2 3 3 3 1 ...
    
    
  2. 要将变量从 int 数值类型转换为 factor 类别类型,你可以使用 factor 转换:

    > train.data$Survived = factor(train.data$Survived)
    > train.data$Pclass = factor(train.data$Pclass)
    
    
  3. 使用 str 函数打印变量,再次可以看到 PclassSurvived 已经转换为以下因子类型:

    > str(train.data)
    'data.frame':  891 obs. of  12 variables:
     $ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
     $ Survived   : Factor w/ 2 levels "0","1": 1 2 2 2 1 1 1 1 2 2 ...
     $ Pclass     : Factor w/ 3 levels "1","2","3": 3 1 3 1 3 3 1 3 3 2 ...
     $ Name       : Factor w/ 891 levels "Abbing, Mr. Anthony",..: 109 191 358 277 16 559 520 629 417 581 ...
     $ Sex        : Factor w/ 2 levels "female","male": 2 1 1 1 2 2 2 2 1 1 ...
     $ Age        : num  22 38 26 35 35 NA 54 2 27 14 ...
     $ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
     $ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
     $ Ticket     : Factor w/ 681 levels "110152","110413",..: 524 597 670 50 473 276 86 396 345 133 ...
     $ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
     $ Cabin      : Factor w/ 147 levels "A10","A14","A16",..: NA 82 NA 56 NA NA 130 NA NA NA ...
     $ Embarked   : Factor w/ 3 levels "C","Q","S": 3 1 3 3 3 2 3 3 3 1 ...
    
    

它是如何工作的...

谈论统计学,有四种度量:名义、有序、区间和比率。名义变量用于标记变量,例如性别和姓名;有序变量用于衡量非数值概念,例如满意度和幸福感。区间变量显示数值尺度,它不仅告诉我们顺序,还可以显示值之间的差异,例如摄氏度温度。比率变量显示连续量的量级与单位量级的比率。比率变量提供顺序、值之间的差异和真正的零值,例如体重和身高。在 R 中,不同的度量有不同的计算方式,因此在应用描述性或推理性分析之前,你应该先进行类型转换。

在这个菜谱中,我们首先使用 str 函数显示训练数据的结构。从数据结构中,您可以找到属性名称、数据类型以及每个属性中包含的前几个值。从 SurvivedPclass 属性中,您可以看到数据类型为 int。正如图表 1(前言)中列出的变量描述,您可以看到 Survived(0 = 否;1 = 是)和 Pclass(1 = 1 级;2 = 2 级;3 = 3 级)是分类变量。因此,我们通过 factor 函数将数据从字符类型转换为因子类型。

还有更多...

除了因子之外,还有更多类型转换函数。对于数值类型,有 is.numeric()as.numeric();对于字符类型,有:is.character()as.character()。对于向量,有:is.vector()as.vector();对于矩阵,有 is.matrix()as.matrix()。最后,对于数据框,有:is.data.frame()as.data.frame()

检测缺失值

缺失值会降低样本的代表性,并且还可能扭曲对总体的推断。本食谱将专注于检测泰坦尼克号数据集中的缺失值。

准备工作

您需要通过Pclass属性和Survived因子类型完成之前的食谱。

在 R 中,缺失值用NA不可用)符号表示,不可能的值是NaN不是数字)。

如何操作...

执行以下步骤来检测缺失值:

  1. 使用is.na函数来表示哪个属性索引包含 NA 值。在这里,我们首先将其应用于Age属性:

    > is.na(train.data$Age)
    
    
  2. is.na函数指示Age属性的缺失值。要得到一个大致的缺失值数量,您可以执行一个sum来计算这个值:

    > sum(is.na(train.data$Age) == TRUE)
    [1] 177
    
    
  3. 为了计算缺失值的百分比,采用的一种方法是计算缺失值与非缺失值的数量:

    > sum(is.na(train.data$Age) == TRUE) /  length(train.data$Age)
    [1] 0.1986532
    
    
  4. 要获取属性缺失值的百分比,您可以使用sapply来计算所有属性的百分比:

    > sapply(train.data, function(df) {
    +               sum(is.na(df)==TRUE)/ length(df);
    +           }) 
    PassengerId    Survived      Pclass        Name         Sex         Age 
    0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.198653199 
     SibSp       Parch      Ticket        Fare       Cabin    Embarked 
    0.000000000 0.000000000 0.000000000 0.000000000 0.771043771 0.002244669 
    
    
  5. 除了简单地查看缺失数据的百分比之外,还可以使用Amelia包来可视化缺失值。在这里,我们使用install.packagesrequire来安装Amelia并加载包。然而,在安装和加载Amelia包之前,您需要先安装Rcpp

    > install.packages("Amelia")
    > require(Amelia)
    
    
  6. 然后,使用missmap函数绘制缺失值地图:

    > missmap(train.data, main="Missing Map")
    
    

    如何操作...

    泰坦尼克号数据集的缺失值地图

工作原理...

在 R 中,缺失值通常用"NA"符号表示,代表不可用。大多数函数(如meansum)在数据集中遇到 NA 值时可能会输出 NA。尽管您可以分配一个如na.rm的参数来消除 NA 的影响,但最好是在数据集中插补或删除缺失数据,以防止缺失值的影响传播。要找出泰坦尼克号数据集中的缺失值,我们首先将所有 NA 值加起来,然后除以每个属性中的值数,然后我们使用sapply对具有所有属性进行计算。

此外,为了使用表格显示计算结果,您可以使用Amelia包在一张图表上绘制每个属性的缺失值地图。缺失值的可视化使用户能够更好地理解每个数据集中的缺失百分比。从前面的屏幕截图,您可能已经观察到缺失值是米色的,其观测值是深红色。x轴显示不同的属性名称,y轴显示记录的索引。显然,大多数船舱都显示缺失数据,并且它还显示在计算Age属性时大约有 19.87%的数据是缺失的,Embarked属性中缺失两个值。

还有更多...

为了处理缺失值,我们引入了Amelia来可视化它们。除了输入控制台命令外,您还可以使用AmeliaAmeliaView的交互式 GUI,它允许用户从窗口环境中加载数据集、管理选项和运行Amelia

要启动运行AmeliaView,只需在 R 控制台中输入AmeliaView()

> AmeliaView()

还有更多...

AmeliaView

缺失值插补

在检测到每个属性中的缺失值数量后,我们必须插补缺失值,因为它们可能会对从数据中得出的结论产生重大影响。

准备工作

此菜谱需要将train.data加载到 R 会话中,并且需要完成之前的菜谱,将PclassSurvived转换为因子类型。

如何操作...

执行以下步骤以插补缺失值:

  1. 首先,列出登船港口的分布情况。在这里,我们添加useNA = "always"参数以显示train.data中包含的 NA 值的数量:

    > table(train.data$Embarked, useNA = "always")
    
     C    Q    S <NA> 
     168   77  644    2 
    
    
  2. 将两个缺失值赋给一个更可能的港口(即计数最多的港口),在这种情况下是南安普顿:

    > train.data$Embarked[which(is.na(train.data$Embarked))] = 'S';
    > table(train.data$Embarked, useNA = "always")
    
     C    Q    S <NA> 
     168   77  646    0 
    
    
  3. 为了发现train.data名称中包含的标题类型,我们首先使用空白(正则表达式模式"\\s+")对train.data$Name进行分词,然后使用table函数计算出现的频率。在此之后,由于名称标题通常以句点结尾,我们使用正则表达式 grep 包含句点的单词。最后,按降序sort表格:

    > train.data$Name = as.character(train.data$Name)
    > table_words = table(unlist(strsplit(train.data$Name, "\\s+")))
    > sort(table_words [grep('\\.',names(table_words))], decreasing=TRUE)
    
     Mr.     Miss.      Mrs.   Master. 
     517       182       125        40 
     Dr.      Rev.      Col.    Major. 
     7         6         2            2 
     Mlle.     Capt. Countess.    Don. 
     2         1         1                1 
    Jonkheer.        L.     Lady .      Mme. 
     1         1         1         1 
     Ms.      Sir. 
     1         1 
    
    
  4. 要获取包含缺失值的标题,您可以使用stringr包提供的str_match函数获取包含句点的子串,然后使用cbind函数将列绑定在一起。最后,通过使用表格函数获取缺失值的统计信息,您可以逐个标题进行计数:

    > library(stringr) 
    > tb = cbind(train.data$Age, str_match(train.data$Name, " [a-zA-Z]+\\."))
    > table(tb[is.na(tb[,1]),2])
    
     Dr.  Master.    Miss.      Mr.     Mrs. 
     1        4            36       119       17 
    
    
  5. 对于包含缺失值的标题,一种数据插补的方法是将每个标题(不包含缺失值)的平均值赋值:

    > mean.mr = mean(train.data$Age[grepl(" Mr\\.", train.data$Name) & !is.na(train.data$Age)])
    > mean.mrs = mean(train.data$Age[grepl(" Mrs\\.", train.data$Name) & !is.na(train.data$Age)])
    > mean.dr = mean(train.data$Age[grepl(" Dr\\.", train.data$Name) & !is.na(train.data$Age)])
    > mean.miss = mean(train.data$Age[grepl(" Miss\\.", train.data$Name) & !is.na(train.data$Age)])
    > mean.master =  mean(train.data$Age[grepl(" Master\\.", train.data$Name) & !is.na(train.data$Age)])
    
    
  6. 然后,将缺失值赋值为每个标题的平均值:

    > train.data$Age[grepl(" Mr\\.", train.data$Name) & is.na(train.data$Age)] = mean.mr
    > train.data$Age[grepl(" Mrs\\.", train.data$Name) & is.na(train.data$Age)] = mean.mrs
    > train.data$Age[grepl(" Dr\\.", train.data$Name) & is.na(train.data$Age)] = mean.dr
    > train.data$Age[grepl(" Miss\\.", train.data$Name) & is.na(train.data$Age)] = mean.miss
    > train.data$Age[grepl(" Master\\.", train.data$Name) & is.na(train.data$Age)] = mean.master
    
    

它是如何工作的...

要插补Embarked属性的缺失值,我们首先使用table函数生成登船港口的统计信息。table函数在train.data中计算了两个 NA 值。从数据集描述中,我们识别出 C、Q 和 S(C = Cherbourg,Q = Queenstown,S = Southampton)。由于我们不知道这两个缺失值属于哪个类别,一种可能的方法是将缺失值赋给最可能的港口,即Southampton

对于另一个属性,年龄,尽管大约 20%的值是缺失的,但用户仍然可以通过每位乘客的头衔来推断缺失值。为了发现数据集中名称中包含多少个头衔,我们建议使用Name属性中分段单词的计数方法,这有助于计算每个给定头衔的缺失值数量。结果词表显示了常见的头衔,如MrMrsMissMaster。您可以参考维基百科上的英语敬语条目以获取每个头衔的描述。

考虑到缺失数据,我们将每个头衔的平均值重新分配给相应的缺失值。然而,对于船舱属性,缺失值太多,我们无法从任何引用属性中推断出值。因此,我们通过尝试使用此属性进行进一步分析,发现这种方法不起作用。

更多内容...

这里我们列出维基百科上的敬语条目供您参考。根据它(en.wikipedia.org/wiki/English_honorific):

  • 先生:此词用于男性,无论其婚姻状况如何

  • 先生:用于拥有第一专业学位的美国人士

  • 小姐:通常用于未婚女性,尽管已婚女性表演者也会使用

  • 夫人:用于已婚女性

  • 博士:用于拥有美国第一专业学位的人士

探索和可视化数据

在填充缺失值之后,应进行探索性分析,这包括使用可视化图表和聚合方法来总结数据特征。结果有助于用户更好地理解所使用的数据。以下食谱将介绍如何使用基本的绘图技术,以帮助用户进行探索性分析。

准备工作

本食谱需要先前的食谱通过填充年龄登船属性中的缺失值来完成。

如何操作...

执行以下步骤以探索和可视化数据:

  1. 首先,您可以使用条形图和直方图为每个属性生成描述性统计,从乘客生存开始:

    > barplot(table(train.data$Survived), main="Passenger Survival",  names= c("Perished", "Survived"))
    
    

    如何操作...

    乘客生存

  2. 我们可以生成乘客等级的条形图:

    > barplot(table(train.data$Pclass), main="Passenger Class",  names= c("first", "second", "third"))
    
    

    如何操作...

    乘客等级

  3. 接下来,我们使用条形图概述性别数据:

    > barplot(table(train.data$Sex), main="Passenger Gender")
    
    

    如何操作...

    乘客性别

  4. 然后,我们使用hist函数绘制不同年龄的直方图:

    > hist(train.data$Age, main="Passenger Age", xlab = "Age")
    
    

    如何操作...

    乘客年龄

  5. 我们可以绘制同辈乘客的条形图以获得以下结果:

    > barplot(table(train.data$SibSp), main="Passenger Siblings")
    
    

    如何操作...

    乘客同辈

  6. 接下来,我们可以获取乘客口渴度的分布:

    > barplot(table(train.data$Parch), main="Passenger Parch")
    
    

    如何操作...

    乘客口渴度

  7. 接下来,我们绘制乘客船票的直方图:

    > hist(train.data$Fare, main="Passenger Fare", xlab = "Fare")
    
    

    如何操作...

    乘客船票

  8. 最后,可以查看登船港口:

    > barplot(table(train.data$Embarked), main="Port of Embarkation")
    
    

    如何做...

    上船港口

  9. 使用 barplot 来找出在沉船事故中哪个性别更容易丧生:

    > counts = table( train.data$Survived, train.data$Sex)
    > barplot(counts,  col=c("darkblue","red"), legend = c("Perished", "Survived"), main = "Passenger Survival by Sex")
    
    

    如何做...

    按性别划分的乘客生存率

  10. 接下来,我们应该检查每个乘客的 Pclass 因素是否可能影响生存率:

    > counts = table( train.data$Survived, train.data$Pclass)
    > barplot(counts,  col=c("darkblue","red"), legend =c("Perished", "Survived"), main= "Titanic Class Bar Plot" )
    
    

    如何做...

    按舱位划分的乘客生存率

  11. 接下来,我们检查每个 Pclass 的性别构成:

    > counts = table( train.data$Sex, train.data$Pclass)
    > barplot(counts,  col=c("darkblue","red"), legend = rownames(counts), main= "Passenger Gender by Class")
    
    

    如何做...

    按舱位划分的乘客性别

  12. 此外,我们检查乘客年龄的直方图:

    > hist(train.data$Age[which(train.data$Survived == "0")], main= "Passenger Age Histogram", xlab="Age", ylab="Count", col ="blue", breaks=seq(0,80,by=2))
    > hist(train.data$Age[which(train.data$Survived == "1")], col ="red", add = T, breaks=seq(0,80,by=2))
    
    

    如何做...

    乘客年龄直方图

  13. 要检查年龄和生存率之间关系的更多细节,可以使用 boxplot

    > boxplot(train.data$Age ~ train.data$Survived, 
    +         main="Passenger Survival by Age",
    +         xlab="Survived", ylab="Age")
    
    

    如何做...

    按年龄划分的乘客生存率

  14. 要将不同年龄的人分类到不同的组中,例如儿童(13 岁以下)、青少年(13 至 19 岁)、成年人(20 至 65 岁)和老年人(65 岁以上),请执行以下命令:

    >train.child = train.data$Survived[train.data$Age < 13]
    > length(train.child[which(train.child == 1)] ) / length(train.child)
     [1] 0.5797101
    
    > train.youth = train.data$Survived[train.data$Age >= 15 & train.data$Age < 25]
    > length(train.youth[which(train.youth == 1)] ) / length(train.youth)
    [1] 0.4285714
    
    > train.adult  = train.data$Survived[train.data$Age >= 20 & train.data$Age < 65]
    > length(train.adult[which(train.adult == 1)] ) / length(train.adult)
     [1] 0.3659218
    
    > train.senior  = train.data$Survived[train.data$Age >= 65]
    > length(train.senior[which(train.senior == 1)] ) / length(train.senior)
    [1] 0.09090909
    
    

它是如何工作的...

在预测生存率之前,一个人应该首先使用聚合和可视化方法来检查每个属性如何影响乘客的命运。因此,我们开始通过生成每个属性的条形图和直方图来检查。

前面截图中的图表为泰坦尼克号数据集的每个属性提供了一个概述。根据第一张截图,在沉船事故中丧生的乘客比幸存的乘客多。在船上的三个舱位中,三等舱的乘客人数最多,这也反映了三等舱是泰坦尼克号上最经济的舱位(第 2 步)。至于性别分布,男性乘客比女性乘客多(第 3 步)。至于年龄分布,第 4 步的截图显示,大多数乘客的年龄在 20 至 40 岁之间。根据第 5 步的截图,大多数乘客有一个或一个以下的兄弟姐妹。第 6 步的截图显示,大多数乘客有 0 到 2 个孩子。

在第 7 步的截图显示,票价直方图显示了票价差异,这可能是由于泰坦尼克号上不同舱位的乘客造成的。最后,第 8 步的截图显示,这艘船停了三次来接乘客。

由于我们从 sex 属性开始探索,并且根据产生的条形图,它清楚地显示在沉船事故中女性乘客的生存率高于男性(第 9 步)。此外,维基百科上关于泰坦尼克号(en.wikipedia.org/wiki/RMS_Titanic)的条目解释说,“由于一些官员在装载救生艇时遵循了‘妇女和儿童优先’的协议,因此有不成比例的男性被留在船上”。因此,女性幸存者人数超过男性幸存者人数是合理的。换句话说,仅使用 sex 就可以以高精度预测一个人是否会幸存。

然后,我们考察了乘客等级是否影响了生存率(步骤 10)。在这里,根据Pclass的定义,每个等级的票价都相应地与质量定价;一等舱票价高,三等舱票价低。由于每个乘客的等级似乎表明了他们的社会和财务状况,因此可以合理地假设富裕的乘客可能更有机会幸存。

不幸的是,等级与生存率之间没有相关性,因此结果并没有显示出我们假设的现象。然而,在我们检查了pclass组成中的sex(步骤 11)之后,结果揭示出大多数三等舱乘客是男性;富裕的人更有可能幸存的假设可能并不那么具体。

接下来,我们通过直方图和箱线图(步骤 12)考察了年龄与乘客命运之间的关系。条形图显示了年龄分布,其中水平柱状图表示乘客的年龄,红色柱状图代表幸存者,蓝色柱状图代表遇难者。很难从不同年龄组的年龄中看出生存率的差异。我们创建的条形图并没有证明不同年龄组的乘客更有可能幸存。另一方面,这些图显示船上大多数人的年龄在 20 至 40 岁之间,但并没有显示出这个群体与老年人或年幼儿童相比是否更有可能幸存(步骤 13)。在这里,我们引入了箱线图,这是一种标准化的绘图技术,可以显示数据的分布,包括最小值、第一四分位数、中位数、第三四分位数、最大值和异常值。

后来,我们进一步考察了年龄组与乘客命运之间是否存在任何关系,通过将乘客年龄分为四个组别。统计数据显示,儿童组(13 岁以下)比青少年(13 至 20 岁)、成年人(20 至 65 岁)和老年人(65 岁以上)更有可能幸存。结果显示,年轻年龄组的人更有可能从海难中幸存。然而,我们注意到这可能是由“妇女和儿童优先”的协议导致的。

还有更多...

除了使用条形图、直方图和箱线图来可视化数据外,还可以在vcd包中应用mosaicplot来检查多个分类变量之间的关系。例如,当我们检查SurvivedPclass变量之间的关系时,应用过程如下:

> mosaicplot(train.data$Pclass ~ train.data$Survived, 
+           main="Passenger Survival Class", color=TRUE, 
+  xlab="Pclass", ylab="Survived")

还有更多...

乘客按等级的生存情况

参见

  • 关于海难的更多信息,可以阅读 RMS 泰坦尼克号的历史(请参阅维基百科中的条目RMS 泰坦尼克号的沉没 en.wikipedia.org/wiki/Sinking_of_the_RMS_Titanic),因为当时实施的某些协议可能极大地影响了乘客的生存率。

使用决策树预测乘客生存情况

探索性分析有助于用户了解单个或多个变量可能如何影响生存率。然而,它并不能确定哪些组合可以生成预测模型,以便预测乘客的生存。另一方面,机器学习可以从训练数据集中生成预测模型,从而用户可以将模型应用于预测给定属性的可能的标签。在本菜谱中,我们将介绍如何使用决策树从给定变量中预测乘客的生存率。

准备工作

我们将使用我们在之前的菜谱中已经使用过的数据,train.data

如何操作...

执行以下步骤来使用决策树预测乘客的生存情况:

  1. 首先,我们构建一个具有三个输入参数的数据拆分函数split.datadata参数表示输入数据集,p参数表示从输入数据集中生成的子集的比例,s参数表示随机种子:

    > split.data = function(data, p = 0.7, s = 666){
    +     set.seed(s)
    +     index = sample(1:dim(data)[1])
    +     train = data[index[1:floor(dim(data)[1] * p)], ]
    +     test = data[index[((ceiling(dim(data)[1] * p)) + 1):dim(data)[1]], ]
    +     return(list(train = train, test = test))
    + } 
    
    
  2. 然后,我们将数据分为训练集和测试集,其中 70%分配给训练集,剩余的 30%用于测试集:

    > allset= split.data(train.data, p = 0.7) 
    > trainset = allset$train 
    > testset = allset$test
    
    
  3. 对于条件树,必须使用party包中的ctree函数;因此,我们需要安装并加载party包:

    > install.packages('party')
    > require('party')
    
    
  4. 然后,我们将Survived用作标签来生成正在使用的预测模型。之后,我们将分类树模型分配给train.ctree变量:

    > train.ctree = ctree(Survived ~ Pclass + Sex + Age + SibSp + Fare + Parch + Embarked, data=trainset)
    > train.ctree
    
     Conditional inference tree with 7 terminal nodes
    
    Response:  Survived 
    Inputs:  Pclass, Sex, Age, SibSp, Fare, Parch, Embarked 
    Number of observations:  623 
    
    1) Sex == {male}; criterion = 1, statistic = 173.672
     2) Pclass == {2, 3}; criterion = 1, statistic = 30.951
     3) Age <= 9; criterion = 0.997, statistic = 12.173
     4) SibSp <= 1; criterion = 0.999, statistic = 15.432
     5)*  weights = 10 
     4) SibSp > 1
     6)*  weights = 11 
     3) Age > 9
     7)*  weights = 282 
     2) Pclass == {1}
     8)*  weights = 87 
    1) Sex == {female}
     9) Pclass == {1, 2}; criterion = 1, statistic = 59.504
     10)*  weights = 125 
     9) Pclass == {3}
     11) Fare <= 23.25; criterion = 0.997, statistic = 12.456
     12)*  weights = 85 
     11) Fare > 23.25
     13)*  weights = 23 
    
    
  5. 我们使用一个plot函数来绘制树形图:

    > plot(train.ctree, main="Conditional inference tree of Titanic Dataset")
    
    

    如何操作...

    泰坦尼克号数据集的条件推理树

工作原理...

本菜谱介绍了如何使用条件推理树ctree来预测乘客的生存情况。虽然条件推理树不是解决分类问题的唯一方法,但它是一种易于理解预测乘客生存决策路径的方法。

我们首先使用我们实现的函数split.data将数据分为训练集和测试集。这样,我们就可以使用训练集生成预测模型,然后在模型评估的菜谱中使用预测模型对测试集进行预测。然后,我们安装并加载party包,并使用ctree构建预测模型,其中Survived作为其标签。不考虑任何特定属性,我们将PclassSexAgeSibSpParchEmbarkedFare等属性作为训练属性,除了Cabin,因为该属性的大部分值都是缺失的。

构建预测模型后,我们可以以文本模式打印决策路径和节点,或者使用绘图函数绘制决策树。从决策树中,用户可以看到哪些变量的组合可能有助于预测生存率。根据前面的截图,用户可以找到一个 PclassSex 的组合,这作为一个好的决策边界(节点 9)来预测生存率。这表明大多数在头等舱和二等舱的女性乘客在船难中幸存。男性乘客,那些在二等舱和三等舱以及年龄超过九岁的乘客,在船难中几乎全部丧生。从树中,人们可能会发现属性如 EmbarkedParch 是缺失的。这是因为条件推断树在分类过程中将这些属性视为不太重要。

从决策树中,用户可以看到哪些变量的组合可能有助于预测生存率。此外,条件推断树在分类过程中选择重要属性时很有帮助;用户可以检查构建的树,以查看所选属性是否与假设相符。

还有更多...

本食谱涵盖了与分类算法和条件推断树相关的问题。由于我们不讨论适应算法的背景知识,因此用户最好在需要时使用 help 函数查看 party 包中与 ctree 相关的文档。

存在着一个类似的决策树包,名为 rpartpartyrpart 之间的区别在于,party 包中的 ctree 避免了 rpartparty 包中的 ctree 的以下变量选择偏差,倾向于选择具有许多可能分割或许多缺失值的变量。与其他方法不同,ctree 使用显著性检验程序来选择变量,而不是选择最大化信息量的变量。

除了 ctree 之外,还可以使用 svm 生成预测模型。要加载 svm 函数,首先加载 e1071 包,然后使用 svm 构建生成此预测:

> install.packages('e1071')
> require('e1071')
> svm.model = svm(Survived ~ Pclass + Sex + Age + SibSp + Fare + Parch + Embarked, data = trainset, probability = TRUE)

在这里,我们使用 svm 来展示当使用 R 时,如何轻松地将不同的机器学习算法立即应用于同一数据集。有关如何使用 svm 的更多信息,请参阅第六章,分类(II)——神经网络,SVM

使用混淆矩阵验证预测能力

构建预测模型后,验证模型在预测标签时的表现非常重要。在前面的食谱中,我们使用 ctree 构建了一个模型,并将数据预先分割为训练集和测试集。现在,用户将学习如何通过使用混淆矩阵来验证 ctree 在生存预测中的表现。

准备工作

在评估预测模型之前,首先确保生成的训练集和测试数据集在 R 会话中。

如何操作...

执行以下步骤以验证预测能力:

  1. 我们开始使用构建的train.ctree模型来预测测试集的生存率:

    > ctree.predict = predict(train.ctree, testset)
    
    
  2. 首先,我们安装caret包,然后加载它:

    > install.packages("caret")
    > require(caret)
    
    
  3. 在加载caret之后,可以使用混淆矩阵生成输出矩阵的统计信息:

    > confusionMatrix(ctree.predict, testset$Survived)
    Confusion Matrix and Statistics
    
     Reference
    Prediction   0   1
     0 160  25
     1  16  66
    
     Accuracy : 0.8464 
     95% CI : (0.7975, 0.8875)
     No Information Rate : 0.6592 
     P-Value [Acc > NIR] : 4.645e-12 
    
     Kappa : 0.6499 
     Mcnemar's Test P-Value : 0.2115 
    
     Sensitivity : 0.9091 
     Specificity : 0.7253 
     Pos Pred Value : 0.8649 
     Neg Pred Value : 0.8049 
     Prevalence : 0.6592 
     Detection Rate : 0.5993 
     Detection Prevalence : 0.6929 
     Balanced Accuracy : 0.8172 
    
     'Positive' Class : 0
    
    

它是如何工作的...

在前一个食谱中构建预测模型后,重要的是要衡量所构建模型的性能。性能可以通过预测结果是否与测试数据集中包含的原始标签匹配来评估。评估可以通过使用 caret 包提供的混淆矩阵来生成混淆矩阵来完成,这是衡量预测准确率的一种方法。

要生成混淆矩阵,用户首先需要安装并加载caret包。混淆矩阵显示,仅使用ctree可以达到高达 84%的准确率。可以通过调整使用的属性或替换分类算法为 SVM、glm或随机森林来生成更好的预测模型。

还有更多...

caret包(分类和回归训练)有助于使迭代和比较不同的预测模型变得非常方便。该包还包含几个函数,包括:

  • 数据拆分

  • 常见的预处理:创建虚拟变量、识别零和接近零方差预测变量、寻找相关预测变量、中心化、缩放等

  • 训练(使用交叉验证)

  • 常见的可视化(例如,特征图

使用 ROC 曲线评估性能

另一种测量方法是使用 ROC 曲线(这需要ROCR包),它根据其真正率与假正率绘制曲线。本食谱将介绍我们如何使用 ROC 曲线来衡量预测模型的性能。

准备工作

在将 ROC 曲线应用于评估预测模型之前,首先确保生成的训练集、测试数据集和构建的预测模型ctree.predict都在 R 会话中。

如何操作...

执行以下步骤以评估预测性能:

  1. 准备概率矩阵:

    > train.ctree.pred = predict(train.ctree, testset)
    > train.ctree.prob =  1- unlist(treeresponse(train.ctree, testset), use.names=F)[seq(1,nrow(testset)*2,2)]
    
    
  2. 安装并加载ROCR包:

    > install.packages("ROCR")
    > require(ROCR)
    
    
  3. 从概率创建ROCR预测对象:

    > train.ctree.prob.rocr = prediction(train.ctree.prob, testset$Survived)
    
    
  4. 准备 ROC 曲线(tpr为真正率,fpr为假正率)和曲线下面积(AUC)的 ROCR 性能对象:

    > train.ctree.perf = performance(train.ctree.prob.rocr, "tpr","fpr")
    > train.ctree.auc.perf =  performance(train.ctree.prob.rocr, measure = "auc", x.measure = "cutoff")
    
    
  5. 绘制 ROC 曲线,将颜色设置为TRUE,并将AUC作为标题:

    > plot(train.ctree.perf, col=2,colorize=T, main=paste("AUC:", train.ctree.auc.perf@y.values))
    
    

    如何操作...

    预测模型的 ROC

它是如何工作的...

在这里,我们首先从概率矩阵中创建预测对象,然后准备 ROC 曲线(tpr=true positive ratefpr=false positive rate)和 AUC 的 ROCR 性能对象。最后,我们使用绘图函数绘制 ROC 曲线。

前一截图中的结果可以这样解释:曲线下方的面积越大(完美的预测将使 AUC 等于 1),模型的预测精度就越好。我们的模型返回的值为 0.857,这表明简单的条件推理树模型足够强大,可以做出生存预测。

参考资料也

  • 要获取更多关于 ROCR 的信息,您可以阅读以下论文:Sing, T.Sander, O.Berenwinkel, N.,和Lengauer, T.(2005)。ROCR: 在 R 中可视化分类器性能。《生物信息学》,21(20),3940-3941。

第三章:R 和统计学

在本章中,我们将涵盖以下主题:

  • 理解 R 中的数据抽样

  • 在 R 中操作概率分布

  • 在 R 中使用单变量描述性统计

  • 执行相关性和多元分析

  • 操作线性回归和多元分析

  • 执行精确二项检验

  • 执行学生 t 检验

  • 执行 Kolmogorov-Smirnov 测试

  • 理解 Wilcoxon 秩和检验和符号秩检验

  • 使用 Pearson 的卡方检验进行操作

  • 执行单因素方差分析

  • 执行双因素方差分析

简介

R 语言作为统计语言 S 的后代,已成为统计学领域的首选计算语言。此外,由于其在该领域的活跃贡献者地位,如果发现新的统计方法,它很可能首先在 R 语言中实现。因此,通过应用 R 语言可以满足大量的统计方法。

要在 R 中应用统计方法,用户可以将实现方法分为描述性统计和推断性统计:

  • 描述性统计:这些用于总结数据的特征。用户可以使用平均值和标准差来描述数值数据,并使用频率和百分比来描述分类数据。

  • 推断性统计:基于样本数据中的模式,用户可以推断总体的特征。与推断性统计相关的方法包括假设检验、数据估计、数据相关性和关系建模。推断还可以进一步扩展到预测、预测和估计与被研究总体相关或未观察到的值。

在以下食谱中,我们将讨论数据抽样、概率分布、单变量描述性统计、相关性和多元分析、线性回归和多元分析、精确二项检验、学生 t 检验、Kolmogorov-Smirnov 检验、Wilcoxon 秩和检验和符号秩检验、Pearson 的卡方检验、单因素方差分析(ANOVA)和双因素方差分析(ANOVA)的示例。

理解 R 中的数据抽样

抽样是从统计总体中选择数据子集的一种方法,可以利用总体的特征来估计整个总体。以下食谱将演示如何在 R 中生成样本。

准备工作

确保您为以下食谱有一个 R 工作环境。

如何做...

执行以下步骤以了解 R 中的数据抽样:

  1. 为了生成给定总体的随机样本,用户可以简单地使用 sample 函数:

    > sample(1:10)
    
    
  2. 要指定返回的项目数,用户可以将分配的值设置为 size 参数:

    > sample(1:10, size = 5)
    
    
  3. 此外,通过指定 replace = TRUE(默认为 FALSE),样本还可以生成伯努利试验:

    > sample(c(0,1), 10, replace = TRUE)
    
    

它是如何工作的...

如前所示,sample 函数可以从指定的总体中生成随机样本。用户可以通过指定 size 参数来指定记录返回的数字。将 replace 参数赋值为 TRUE,可以生成伯努利试验(只有 01 的总体)。

参见

  • 在 R 中,默认包提供了一个另一个样本方法,sample.int,其中 n 和 size 都必须以整数形式提供:

    > sample.int(20, 12)
    
    

在 R 中操作概率分布

概率分布和统计分析密切相关。对于统计分析,分析师基于某个总体进行预测,该总体通常位于概率分布下。因此,如果您发现用于预测的数据在实验设计中并不遵循假设的概率分布,则可以反驳即将到来的结果。换句话说,概率为统计学提供了依据。以下示例将演示如何在 R 中生成概率分布。

准备工作

由于大多数分布函数都源自 stats 包,请确保已加载 stats 库。

如何做...

执行以下步骤:

  1. 对于正态分布,用户可以使用 dnorm,它将返回正态曲线在 0 处的高度:

    > dnorm(0)
    [1] 0.3989423
    
    
  2. 然后,用户可以在参数中更改均值和标准差:

    > dnorm(0,mean=3,sd=5)
    [1] 0.06664492
    
    
  3. 接下来,使用 curve 函数绘制正态分布的图形:

    > curve(dnorm,-3,3)
    
    

    如何做...

    标准正态分布

  4. 与返回正态曲线高度的 dnorm 相比,pnorm 函数可以返回给定值下的面积:

    > pnorm(1.5)
    [1] 0.9331928
    
    
  5. 或者,要获取某个值以上的面积,可以将选项 lower.tail 指定为 FALSE

    > pnorm(1.5, lower.tail=FALSE)
    [1] 0.0668072
    
    
  6. 要绘制 pnorm 的图形,用户可以使用 curve 函数:

    > curve(pnorm(x), -3,3)
    
    

    如何做...

    累积密度函数(pnorm)

  7. 要计算特定分布的分位数,可以使用 qnorm。函数 qnorm 可以被视为 pnorm 的逆函数,它返回给定概率的 Z 分数:

    > qnorm(0.5)
    [1] 0
    > qnorm(pnorm(0))
    [1] 0
    
    
  8. 要从正态分布生成随机数,可以使用 rnorm 函数并指定生成的数字数量。此外,还可以定义可选参数,例如均值和标准差:

    > set.seed(50)
    > x = rnorm(100,mean=3,sd=5)
    > hist(x)
    
    

    如何做...

    正态分布的直方图

  9. 要计算均匀分布,runif 函数会生成均匀分布的随机数。用户可以通过指定变量,如最小值和最大值,来指定生成的数字的范围。以下示例中,用户生成了从 05 的 100 个随机变量:

    > set.seed(50)
    > y = runif(100,0,5)
    > hist(y)
    
    

    如何做...

    均匀分布的直方图

  10. 最后,如果您想测试数据的正态性,最常用的测试方法是 Shapiro-Wilks 测试。在这里,我们演示如何分别对正态分布和均匀分布的样本进行正态性测试:

    > shapiro.test(x)
    
     Shapiro-Wilk normality test
    
    data:  x 
    W = 0.9938, p-value = 0.9319
    > shapiro.test(y)
    
     Shapiro-Wilk normality test
    
    data:  y 
    W = 0.9563, p-value = 0.002221
    
    

它是如何工作的...

在这个菜谱中,我们首先介绍 dnorm,这是一个概率密度函数,它返回正态曲线的高度。如果指定单个输入,则该输入值被称为标准分数或 z 分数。如果没有指定其他参数,则默认使用均值为零、标准差为一的正态分布。然后,我们介绍三种绘制标准正态分布的方法。

在此之后,我们介绍 pnorm,这是一个累积密度函数。该函数 pnorm 可以生成给定值下的面积。除此之外,pnorm 还可以用来从正态分布中计算 p 值。可以通过从数字中减去 1 或将 lower.tail 选项赋值为 True 来获取 p 值。同样,可以使用 plot 函数来绘制累积密度图。

pnorm 不同,qnorm 返回给定概率的 z 分数。因此,示例表明将 qnorm 函数应用于 pnorm 函数将产生确切的输入值。

接下来,我们向您展示如何使用 rnorm 函数从正态分布中生成随机样本,以及如何使用 runif 函数从均匀分布中生成随机样本。在 rnorm 函数中,必须指定生成的数字数量,我们还可以添加可选参数,如均值和标准差。然后,通过使用 hist 函数,应该能够在图 3 中找到一个钟形曲线。另一方面,对于 runif 函数,通过指定最小值和最大值,可以得到两个值之间的样本数字列表。然而,我们仍然可以使用 hist 函数来绘制样本。很明显,输出图(如前图所示)不是钟形,这表明样本不是来自正态分布。

最后,我们演示如何使用 Shapiro-Wilks 测试来测试数据正态性。在这里,我们对正态分布和均匀分布的样本分别进行正态性测试。在两个输出中,可以在每个测试结果中找到 p 值。p 值显示了变化,表明样本来自正态分布。如果 p 值高于 0.05,我们可以得出结论,样本来自正态分布。另一方面,如果值低于 0.05,我们得出结论,样本不是来自正态分布。

还有更多...

除了正态分布之外,您还可以通过使用 R 的内置函数来获得 t 分布、二项分布和卡方分布。您可以使用 help 函数来获取更多相关信息:

  • 对于 t 分布:

    > help(TDist)
    
    
  • 对于二项分布:

    >help(Binomial)
    
    
  • 对于卡方分布:

    >help(Chisquare)
    
    

要了解包中的分布,用户可以使用关键字distributions访问help函数,以找到所有相关文档:

> help(distributions)

在 R 中使用单变量描述性统计

单变量描述性统计描述了用于单元分析的单个变量,这也是定量分析的最简单形式。在本菜谱中,我们介绍了一些用于描述单个变量的基本函数。

准备工作

我们需要对样本数据进行描述性统计分析。在这里,我们使用内置的mtcars数据作为示例。

如何操作...

执行以下步骤:

  1. 首先,将mtcars数据加载到名为mtcars的数据框中:

    > data(mtcars)
    
    
  2. 要获取向量范围,range函数将返回向量的下界和上界:

    > range(mtcars$mpg)
    [1] 10.4 33.9
    
    
  3. 计算变量的长度:

    > length(mtcars$mpg)
    [1] 32
    
    
  4. 获取 mpg 的平均值:

    > mean(mtcars$mpg)
    [1] 20.09062
    
    
  5. 获取输入向量的中位数:

    > median(mtcars$mpg)
    [1] 19.2
    
    
  6. 要获取输入向量的标准差:

    > sd(mtcars$mpg)
    [1] 6.026948
    
    
  7. 要获取输入向量的方差:

    > var(mtcars$mpg)
    [1] 36.3241
    
    
  8. 方差也可以通过标准差的平方来计算:

    > sd(mtcars$mpg) ^ 2
    [1] 36.3241
    
    
  9. 要获取四分位距IQR):

    > IQR(mtcars$mpg)
    [1] 7.375
    
    
  10. 要获取分位数:

    > quantile(mtcars$mpg,0.67)
     67% 
    21.4
    
    
  11. 要获取输入向量的最大值:

    > max(mtcars$mpg)
    [1] 33.9
    
    
  12. 要获取输入向量的最小值:

    > min(mtcars$mpg)
    [1] 10.4
    
    
  13. 要获取包含累积最大值的向量:

    > cummax(mtcars$mpg)
     [1] 21.0 21.0 22.8 22.8 22.8 22.8 22.8 24.4 24.4 24.4 24.4 24.4 24.4 24.4 24.4 24.4
    [17] 24.4 32.4 32.4 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9 33.9
    
    
  14. 要获取包含累积最小值的向量:

    > cummin(mtcars$mpg)
     [1] 21.0 21.0 21.0 21.0 18.7 18.1 14.3 14.3 14.3 14.3 14.3 14.3 14.3 14.3 10.4 10.4
    [17] 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4 10.4
    
    
  15. 要总结数据集,你可以应用summary函数:

    > summary(mtcars)
    
    
  16. 要获取分类数据的频率计数,以mtcars中的cyl为例:

    > table(mtcars$cyl)
    
     4  6  8
    11  7 14
    
    
  17. 要获取数值数据的频率计数,你可以使用茎叶图来概述数据形状;stem生成给定值的茎叶图:

    > stem(mtcars$mpg)
    
     The decimal point is at the |
    
     10 | 44
     12 | 3
     14 | 3702258
     16 | 438
     18 | 17227
     20 | 00445
     22 | 88
     24 | 4
     26 | 03
     28 | 
     30 | 44
     32 | 49
    
    
  18. 你可以使用 ggplot 的直方图来绘制相同的茎叶图:

    > library(ggplot2)
    > qplot(mtcars$mpg, binwidth=2)
    
    

    如何操作...

    mtcars 中 mpg 的直方图

它是如何工作的...

单变量描述性统计生成数据集的频率分布。此外,它们可以用来识别数据中的明显模式和变量的特征,从而从整体视角更好地理解数据。此外,它们还可以提供关于个别案例的中心趋势和偏度描述符的信息。因此,在数据探索过程的开始阶段进行单变量分析是很常见的。

要开始探索数据,我们首先将数据集mtcars加载到 R 会话中。从数据中,我们应用rangelengthmeanmediansdvarIQRquantileminmaxcumincumax来获取属性mpg的描述性统计量。然后,我们使用summary函数来获取关于mtcars的摘要信息。

接下来,我们获取分类数据(cyl)的频率计数。为了获取数值数据的频率计数,我们使用茎叶图来概述数据形状。最后,我们使用带有binwidth参数的直方图,在2中生成一个类似于茎叶图的图表。

更多内容...

在单变量描述性统计中,一个常见的场景是找到一个向量的众数。在 R 中,没有内置的函数来帮助用户获取数据的众数。然而,可以通过以下代码实现众数函数:

> mode = function(x) {
+ temp = table(x)
+ names(temp)[temp == max(temp)]
+ }

通过对向量mtcars$mpg应用mode函数,您可以找到给定向量中最频繁出现的数值或类别:

> x = c(1,2,3,3,3,4,4,5,5,5,6)
> mode(x)
[1] "3" "5"

执行相关性和多元分析

要分析两个以上变量的关系,您需要进行多元描述性统计,这允许比较因素。此外,它防止单个变量的影响扭曲分析。在本菜谱中,我们将讨论如何使用相关性和协方差矩阵进行多元描述性统计。

准备工作

确保在 R 会话中已经将mtcars加载到数据框中。

如何做...

执行以下步骤:

  1. 在这里,您可以通过将mtcars中的前三个变量输入到cov函数中来获取协方差矩阵:

    > cov(mtcars[1:3])
     mpg        cyl       disp
    mpg    36.324103  -9.172379  -633.0972
    cyl    -9.172379   3.189516   199.6603
    disp -633.097208 199.660282 15360.7998
    
    
  2. 要获取数据集的相关矩阵,我们将mtcars的前三个变量输入到cor函数中:

    > cor(mtcars[1:3])
     mpg        cyl       disp
    mpg   1.0000000 -0.8521620 -0.8475514
    cyl  -0.8521620  1.0000000  0.9020329
    disp -0.8475514  0.9020329  1.0000000
    
    

它是如何工作的...

在本菜谱中,我们已经展示了如何应用相关性和协方差来发现多个变量之间的关系。

首先,我们计算前三个mtcars变量的协方差矩阵。协方差可以衡量变量之间的线性关系。因此,正协方差(例如,cylmpg)表示两个变量呈正线性相关。另一方面,负协方差(例如,mpgdisp)表示两个变量呈负线性相关。然而,由于不同数据集的方差不同,这些数据集的协方差分数是不可比较的。因此,如果您想比较不同数据集中两个变量之间线性关系的强度,您应该使用归一化分数,即相关系数,而不是协方差。

接下来,我们应用cor函数来获取mtcars数据集中三个变量的相关系数矩阵。在相关系数矩阵中,矩阵的数值元素表示两个变量之间关系的强度。如果一个变量与其自身的相关系数得分为1,则该变量与其自身有正相关关系。cylmpg变量的相关系数为-0.85,这意味着它们有强烈的负相关关系。另一方面,dispcyl变量的得分为 0.90,这可能表明它们有强烈的正相关关系。

另请参阅

  • 您可以使用ggplot绘制相关系数矩阵的热图:

    > library(reshape2)
    > qplot(x=Var1, y=Var2, data=melt(cor(mtcars[1:3])), fill=value, geom="tile")
    
    

    另请参阅

    相关系数矩阵热图

操作线性回归和多元分析

线性回归是一种评估因变量和自变量之间关联的方法。在本教程中,我们将介绍如何进行多元分析的线性回归。

准备工作

确保在 R 会话中已经将mtcars数据框加载到数据中。

如何操作...

执行以下步骤:

  1. 要将变量拟合到线性模型中,您可以使用lm函数:

    > lmfit = lm(mtcars$mpg ~ mtcars$cyl)
    > lmfit
    
    Call:
    lm(formula = mtcars$mpg ~ mtcars$cyl)
    
    Coefficients:
    (Intercept)   mtcars$cyl 
     37.885       -2.876 
    
    
  2. 要获取拟合模型的详细信息,您可以使用summary函数:

    > summary(lmfit)
    
    Call:
    lm(formula = mtcars$mpg ~ mtcars$cyl)
    
    Residuals:
     Min      1Q  Median      3Q     Max 
    -4.9814 -2.1185  0.2217  1.0717  7.5186 
    
    Coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept)  37.8846     2.0738   18.27  < 2e-16 ***
    mtcars$cyl   -2.8758     0.3224   -8.92 6.11e-10 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 3.206 on 30 degrees of freedom
    Multiple R-squared:  0.7262,  Adjusted R-squared:  0.7171 
    F-statistic: 79.56 on 1 and 30 DF,  p-value: 6.113e-10
    
    
  3. 要创建一个方差分析表,可以使用anova函数:

    > anova(lmfit)
    Analysis of Variance Table
    
    Response: mtcars$mpg
     Df Sum Sq Mean Sq F value    Pr(>F) 
    mtcars$cyl  1 817.71  817.71  79.561 6.113e-10 ***
    Residuals  30 308.33   10.28 
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    
  4. 要在两个变量的散点图上绘制回归线,您首先在图中绘制cylmpg,然后使用abline函数在图上添加回归线:

    > lmfit = lm(mtcars$mpg ~ mtcars$cyl)
    > plot(mtcars$cyl, mtcars$mpg)
    > abline(lmfit)
    
    

    如何操作...

    cyl 与 mpg 的回归图

工作原理...

在本教程中,我们应用线性模型函数lm,它构建两个变量的线性拟合模型并返回公式和系数。接下来,我们应用summary函数来检索模型的详细信息(包括 F 统计量和 P 值)。F 统计量的目的是测试模型的统计显著性。它产生一个 F 值,即模型均方与误差均方的比率。因此,大的 F 值表明回归模型解释了更多的总变异性。然后,我们可以使用 F 值来支持或拒绝所有回归系数都等于零的零假设。换句话说,如果 F 值大且显示回归模型具有预测能力,则拒绝零假设。另一方面,每个属性的 P 值测试系数等于零的零假设(对响应变量没有影响)。换句话说,低 P 值可以拒绝零假设,并表明预测变量的值的变化与响应变量的值有关。

接下来,我们将 anova 函数应用于拟合的模型以确定方差。该函数输出平方和,代表模型预测值的变异性。此外,为了可视化两个变量之间的线性关系,abline 函数可以在 mpgcyl 的散点图上添加回归线。从前面的图中可以看出,mpgcyl 变量呈负相关。

参考内容

  • 有关如何进行线性和非线性回归分析的更多信息,请参阅第四章理解回归分析,理解回归分析

进行精确的二项式检验

在做决策时,了解决策错误是否可以控制或衡量是很重要的。换句话说,我们希望证明形成的假设不太可能偶然发生,并且具有统计学意义。在假设检验中,有两种假设:零假设和备择假设(或研究假设)。假设检验的目的是验证实验结果是否具有显著性。然而,为了验证备择假设是否可接受,如果零假设被拒绝,则认为它是真实的。

在下面的食谱中,我们将讨论一些常见的统计检验方法。首先,我们将介绍如何在 R 中进行精确的二项式检验。

准备工作

由于 binom.test 函数来自 stats 包,请确保已加载 stats 库。

如何操作...

执行以下步骤:

  1. 假设有一个游戏,赌徒可以通过掷出骰子的六点来赢得游戏。作为规则的一部分,赌徒可以携带自己的骰子。如果一个赌徒试图在游戏中作弊,他会使用一个加重的骰子来增加他赢得游戏的几率。因此,如果我们观察到赌徒在 315 场游戏中赢了 92 场,我们可以通过进行精确的二项式检验来确定骰子是否公平:

    > binom.test(x=92, n=315, p=1/6)
    
     Exact binomial test
    
    data:  92 and 315
    number of successes = 92, number of trials = 315, p-value = 3.458e-08
    alternative hypothesis: true probability of success is not equal to 0.1666667
    95 percent confidence interval:
     0.2424273 0.3456598
    sample estimates:
    probability of success 
     0.2920635 
    
    

它是如何工作的...

二项式检验使用二项分布来确定在具有二元结果的 n 次试验中,真正的成功率是否可能是 P。概率 P 的公式可以定义为以下方程:

它是如何工作的...

在这里,X 表示随机变量,计算感兴趣的结果的数量;n 表示试验次数;k 表示成功的次数;p 表示成功的概率;q 表示失败的概率。

在我们计算出概率 P 之后,我们可以进行符号检验,以确定成功概率是否与我们预期的相似。如果概率不等于我们预期的,我们可以拒绝零假设。

根据定义,零假设是对将要测试的总体参数的怀疑观点或陈述。零假设用 H0 表示。备择假设表示一系列不包含在零假设中的总体值。备择假设用 H1 表示。在这种情况下,零假设和备择假设分别表示如下:

  • H0 (零假设): 成功的真实概率等于我们预期的

  • H1 (备择假设): 成功的真实概率不等于我们预期的

在本例中,我们演示如何使用二项检验来确定骰子被掷出的次数、掷出六的频率以及从无偏骰子掷出六的概率。t 检验的结果显示 p 值=3.458e-08(低于 0.05)。在 5%的显著性水平下,由于掷出了过多的六(成功概率=0.2920635),零假设(骰子无偏)被拒绝。

参见

  • 要了解更多关于精确二项检验的使用方法,请使用help函数查看相关文档:

    > ?binom.test
    
    

执行学生 t 检验

单样本 t 检验使我们能够测试两个均值是否显著不同;双样本 t 检验使我们能够测试两个独立组的均值是否不同。在本配方中,我们将讨论如何使用 R 进行单样本 t 检验和双样本 t 检验。

准备工作

确保在 R 会话中已经将mtcars加载到数据框中。由于t.test函数来自stats包,请确保已加载库stats

如何做...

执行以下步骤:

  1. 首先,我们使用箱线图可视化属性mpgam的关系:

    > boxplot(mtcars$mpg, mtcars$mpg[mtcars$am==0], ylab = "mpg", names=c("overall","automobile"))
    > abline(h=mean(mtcars$mpg),lwd=2, col="red")
    > abline(h=mean(mtcars$mpg[mtcars$am==0]),lwd=2, col="blue")
    
    

    如何做...

    总体和汽车 mpg 的箱线图

  2. 我们随后执行一个统计程序来验证汽车的平均mpg是否低于总体mpg的平均值:

    > mpg.mu = mean(mtcars$mpg)
    > mpg_am = mtcars$mpg[mtcars$am == 0]
    > t.test(mpg_am,mu = mpg.mu)
    
     One Sample t-test
    
    data:  mpg_am
    t = -3.3462, df = 18, p-value = 0.003595
    alternative hypothesis: true mean is not equal to 20.09062
    95 percent confidence interval:
     15.29946 18.99528
    sample estimates:
    mean of x 
     17.14737 
    
    
  3. 我们开始通过绘制箱线图来可视化数据:

    >boxplot(mtcars$mpg~mtcars$am,ylab='mpg',names=c('automatic','manual'))
    > abline(h=mean(mtcars$mpg[mtcars$am==0]),lwd=2, col="blue")
    > abline(h=mean(mtcars$mpg[mtcars$am==1]),lwd=2, col="red")
    
    

    如何做...

    自动和手动变速汽车的 mpg 箱线图

  4. 前面的图显示,自动变速汽车的均值 mpg 低于手动变速车辆的均值 mpg:

    > t.test(mtcars$mpg~mtcars$am)
    
     Welch Two Sample t-test
    
    data:  mtcars$mpg by mtcars$am
    t = -3.7671, df = 18.332, p-value = 0.001374
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -11.280194  -3.209684
    sample estimates:
    mean in group 0 mean in group 1 
     17.14737        24.39231 
    
    

它是如何工作的...

学生 t 检验是在零假设为真时,检验统计量遵循正态分布(学生 t 分布)的情况。它可以用来确定两个独立数据集之间是否存在差异。学生 t 检验最适合用于基于小样本推断的问题。

在本例中,我们讨论单样本学生 t 检验和双样本学生 t 检验。在单样本学生 t 检验中,常被提出的研究问题是,“总体均值是否与零假设不同?”因此,为了测试汽车的平均油耗是否低于总体平均油耗,我们首先使用箱线图来观察总体之间的差异,而不做任何假设。从前面的图中可以看出,汽车的平均油耗(蓝色线)低于总体平均油耗(红色线)。然后,我们应用单样本 t 检验;低 p 值 0.003595(< 0.05)表明我们应该拒绝零假设,即汽车的平均油耗低于总体平均油耗。

由于单样本 t 检验使我们能够测试两个均值是否有显著差异,双样本 t 检验则允许我们测试两个独立组的均值是否不同。与单样本 t 检验类似,我们首先使用箱线图来观察总体之间的差异,然后应用双样本 t 检验。测试结果显示 p 值为 0.01374(p< 0.05)。换句话说,测试提供了拒绝零假设的证据,表明自动挡汽车的均值油耗与手动挡汽车的均值油耗不同。

相关内容

  • 要了解更多关于学生 t 检验的使用方法,请使用 help 函数查看相关文档:

    > ?t.test
    
    

执行 Kolmogorov-Smirnov 测试

单样本 Kolmogorov-Smirnov 测试用于比较一个样本与参考概率。双样本 Kolmogorov-Smirnov 测试比较两个数据集的累积分布。在本例中,我们将展示如何使用 R 执行 Kolmogorov-Smirnov 测试。

准备工作

确保在 R 会话中已经将 mtcars 数据集加载到一个数据框中。由于 ks.test 函数源自 stats 包,请确保已加载 stats 库。

如何操作...

执行以下步骤:

  1. 使用单样本 Kolmogorov-Smirnov 测试验证数据集 x(使用 rnorm 函数生成)是否呈正态分布:

    > x = rnorm(50)
    > ks.test(x,"pnorm")
    
     One-sample Kolmogorov-Smirnov test
    
    data:  x
    D = 0.1698, p-value = 0.0994
    alternative hypothesis: two-sided
    
    
  2. 接下来,您可以生成均匀分布的样本数据:

    > set.seed(3)
    > x = runif(n=20, min=0, max=20)
    
    > y = runif(n=20, min=0, max=20)
    
    
  3. 我们首先绘制两个生成数据样本的 ecdf

    > plot(ecdf(x), do.points = FALSE, verticals=T, xlim=c(0, 20))
    > lines(ecdf(y), lty=3, do.points = FALSE, verticals=T)
    
    

    如何操作...

    两个生成数据样本的 ecdf 图

  4. 最后,我们对两组数据应用双样本 Kolmogorov-Smirnov 测试:

    > ks.test(x,y)
    
     Two-sample Kolmogorov-Smirnov test
    
    data:  x and y
    D = 0.3, p-value = 0.3356
    alternative hypothesis: two-sided
    
    

它是如何工作的...

Kolmogorov-Smirnov 测试K-S 测试)是一种非参数统计测试,用于检验连续概率分布的相等性。它可以用来比较一个样本与参考概率分布(单样本 K-S 测试),或者直接比较两个样本(双样本 K-S 测试)。该测试基于经验分布函数(ECDF)。设 如何工作... 为大小为 n 的随机样本;经验分布函数 如何工作...,定义为:

如何工作...

在这里,如何工作... 是指示函数。如果 如何工作...,则函数等于 1。否则,函数等于 0。

Kolmogorov-Smirnov 统计量(D)基于 F(x) 和 Fn(x) 之间最大的(其中 supx 表示上确界)垂直差异。它定义为:

如何工作...

H[0] 是样本遵循指定的分布。H[1] 是样本不遵循指定的分布。

如果 Dn 大于从表中获得的临界值,则我们在显著性水平 α 上拒绝 H[0]。

我们首先测试从正态分布生成的随机数是否正态分布。在 5% 的显著性水平下,p 值为 0.0994 表明输入是正态分布的。

然后,我们绘制一个经验累积分布函数(ecdf)图来展示双样本测试如何计算最大距离 D(显示为 0.3),并应用双样本 Kolmogorov-Smirnov 测试来发现两个输入数据集是否可能来自同一分布。

p 值大于 0.05,不拒绝零假设。换句话说,这意味着两个数据集可能来自同一分布。

参见

  • 想要了解更多关于 Kolmogorov-Smirnov 测试的用法,请使用 help 函数查看相关文档:

    > ?ks.test
    
    
  • 关于经验累积分布函数的定义,请参阅 ecdf 的帮助页面:

    > ?ecdf
    
    

理解 Wilcoxon 秩和检验和符号秩检验

Wilcoxon 秩和检验和符号秩检验(或 Mann-Whitney-Wilcoxon)是一种非参数的零假设检验,表明两个不同群体的总体分布是相同的,而不假设两个群体是正态分布的。本食谱将展示如何在 R 中进行 Wilcoxon 秩和检验和符号秩检验。

准备工作

确保在 R 会话中已经将 mtcars 数据集加载到一个数据框中。由于 wilcox.test 函数源自 stats 包,请确保已加载 stats 库。

如何操作...

执行以下步骤:

  1. 我们首先使用 boxplot 函数绘制 mtcars 的数据:

    > boxplot(mtcars$mpg~mtcars$am,ylab='mpg',names=c('automatic','manual'))
    
    

    如何操作...

    自动挡汽车和手动挡汽车的 mpg 箱线图

  2. 接下来,我们仍然执行 Wilcoxon 秩和检验,以验证自动变速汽车的分布是否与手动变速汽车相同:

    > wilcox.test(mpg ~ am, data=mtcars)
    
     Wilcoxon rank sum test with continuity correction
    
    data:  mpg by am
    W = 42, p-value = 0.001871
    alternative hypothesis: true location shift is not equal to 0
    
    Warning message:
    In wilcox.test.default(x = c(21.4, 18.7, 18.1, 14.3, 24.4, 22.8,  :
     cannot compute exact p-value with ties
    
    

它是如何工作的...

在本教程中,我们讨论了一种非参数检验方法,即 Wilcoxon 秩和检验(也称为 Mann-Whitney U 检验)。对于学生 t 检验,假设两个样本之间的差异是正态分布的(当两个样本都是正态分布时,效果最好)。然而,当正态性假设不确定时,可以采用 Wilcoxon 秩和检验来检验假设。

在这里,我们使用 Wilcoxon 秩和检验来确定数据集mtcars中自动和手动变速汽车的 mpg 是否分布相同。从测试结果来看,p 值=0.001871(<0.05)拒绝零假设,同时也表明自动和手动变速汽车的 mpg 分布并不相同。在执行此测试时,您可能会收到警告信息“无法计算具有重复值的精确 p 值”,这表明数据集中存在重复值。一旦删除重复值,警告信息将清除。

参见

  • 要了解更多关于 Wilcoxon 秩和检验和符号秩检验的使用方法,请使用help函数查看相关文档:

    > ? wilcox.test
    
    

使用皮尔逊卡方检验

在本教程中,我们介绍了皮尔逊卡方检验,该检验用于检验两组分类变量的分布是否不同。我们将讨论如何在 R 中执行皮尔逊卡方检验。

准备工作

确保在 R 会话中已经将mtcars加载到数据框中。由于chisq.test函数源自stats?包,请确保已加载库stats

如何操作

执行以下步骤:

  1. 要制作计数表,我们首先使用包含变速类型和前进档位数的输入构建的列联表:

    > ftable = table(mtcars$am, mtcars$gear)
    > ftable
    
     3  4  5
     0 15  4  0
     1  0  8  5
    
    
  2. 我们接着绘制列联表的 mosaic 图:

    > mosaicplot(ftable, main="Number of Forward Gears Within Automatic and Manual Cars", color = TRUE)
    
    

    如何操作

    自动和手动汽车前进档位数

  3. 接下来,我们对列联表执行皮尔逊卡方检验,以检验自动和手动变速汽车的档位数是否相同:

    > chisq.test(ftable)
    
     Pearson's Chi-squared test
    
    data:  ftable
    X-squared = 20.9447, df = 2, p-value = 2.831e-05
    
    Warning message:
    In chisq.test(ftable) : Chi-squared approximation may be incorrect
    
    

它是如何工作的...

皮尔逊卡方检验是一种统计检验,用于发现两个分类变量之间是否存在关系。它最适合用于来自大样本的非配对数据。如果您想进行皮尔逊卡方检验,需要确保输入样本满足两个假设:首先,两个输入变量应该是分类变量。其次,变量应包括两个或更多独立组。

在皮尔逊卡方检验中,假设我们有两个变量 A 和 B;我们可以在以下陈述中说明零假设和备择假设:

  • H[0]: 变量 A 和变量 B 是独立的

  • H[1]: 变量 A 和变量 B 不独立

为了测试零假设是否正确或错误,卡方检验采取以下步骤。

它计算卡方检验统计量,如何工作...

如何工作...

这里,r 是列联表的行数,c 是列联表的列数,O[i,j] 是观察到的频率计数,E[i,j] 是期望频率计数。

它确定该统计量的自由度,df。自由度等于:

如何工作...

这里,r 是一个变量的水平数,c 是另一个变量的水平数。

它将如何工作...与具有自由度的卡方分布的临界值进行比较。

在本菜谱中,我们使用列联表和镶嵌图来展示计数数的差异。很明显,自动变速汽车的档位数比手动变速汽车少。

然后,我们在列联表上执行皮尔逊卡方检验,以确定自动和手动变速汽车的齿轮是否相同。输出结果,p 值 = 2.831e-05(< 0.05),反驳了零假设,表明自动和手动变速汽车的档位数不同。然而,输出信息中包含一个警告信息,即卡方近似可能不正确,这是因为列联表中的样本数量少于五个。

更多...

要了解更多关于皮尔逊卡方检验的使用信息,请使用help函数查看相关文档:

> ? chisq.test

除了之前示例中提到的常见假设检验方法外,R 还提供了其他假设检验方法:

  • 比例检验(prop.test):它用于测试不同组之间的比例是否相同

  • Z 检验(UsingR包中的simple.z.test):它比较样本均值与总体均值和标准差

  • 巴特利特检验(bartlett.test):它用于测试不同组的方差是否相同

  • 克鲁斯卡尔-沃利斯秩和检验(kruskal.test):它用于测试不同组的分布是否相同,而不假设它们是正态分布的

  • 夏皮罗-威尔克检验(shapiro.test):它用于测试正态性

进行单因素方差分析

方差分析ANOVA)研究分类自变量与连续因变量之间的关系。它可以用来测试几个组的均值是否相等。如果只有一个分类变量作为自变量,则可以执行单因素方差分析。另一方面,如果有超过两个分类变量,则应执行双因素方差分析。在本菜谱中,我们讨论如何使用 R 进行单因素方差分析。

准备工作

确保在 R 会话中已经将mtcars数据集加载到一个数据框中。由于oneway.testTukeyHSD函数源自stats包,请确保已加载库stats

如何操作...

执行以下步骤:

  1. 我们开始通过使用箱线图可视化数据来探索:

    > boxplot(mtcars$mpg~factor(mtcars$gear),xlab='gear',ylab='mpg')
    
    

    如何操作...

    不同档位数量汽车 mpg 的比较

  2. 接下来,我们进行单因素 ANOVA 来检验mpg的平均值是否随着不同档位数量的变化而变化。我们使用函数oneway.test

    > oneway.test(mtcars$mpg~factor(mtcars$gear))
    
     One-way analysis of means (not assuming equal variances)
    
    data:  mtcars$mpg and factor(mtcars$gear)
    F = 11.2848, num df = 2.000, denom df = 9.508, p-value = 0.003085
    
    
  3. 除了标准函数oneway.test外,还使用aov函数进行 ANOVA 分析:

    > mtcars.aov = aov(mtcars$mpg ~ as.factor(mtcars$gear))
    > summary(mtcars.aov)
     Df Sum Sq Mean Sq F value   Pr(>F) 
    as.factor(mtcars$gear)  2  483.2  241.62    10.9 0.000295 ***
    Residuals              29  642.8   22.17 
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    
  4. aov函数生成的模型也可以生成一个拟合表格的摘要:

    > model.tables(mtcars.aov, "means")
    Tables of means
    Grand mean
    
    20.09062 
    
     as.factor(mtcars$gear) 
     3     4     5
     16.11 24.53 21.38
    rep 15.00 12.00  5.00
    
    
  5. 对于aov模型,可以使用TukeyHSD进行事后比较检验:

    > mtcars_posthoc =TukeyHSD(mtcars.aov)
    > mtcars_posthoc
     Tukey multiple comparisons of means
     95% family-wise confidence level
    
    Fit: aov(formula = mtcars$mpg ~ as.factor(mtcars$gear))
    
    $`as.factor(mtcars$gear)`
     diff        lwr       upr     p adj
    4-3  8.426667  3.9234704 12.929863 0.0002088
    5-3  5.273333 -0.7309284 11.277595 0.0937176
    5-4 -3.153333 -9.3423846  3.035718 0.4295874
    
    
  6. 此外,我们可以使用plot函数可视化平均水平的差异:如何操作...

    不同档位数量组的 Tukey 均值差异图

它是如何工作的...

为了了解不同档位数量的汽车在 mpg(每加仑英里数)上是否有不同的平均值,我们首先绘制了以档位数量为依据的 mpg 箱线图。这提供了一个简单的指示,如果不同档位数量的汽车在 mpg 的平均值上有所不同。然后,我们执行最基本形式的方差分析(ANOVA),即单因素 ANOVA,以检验总体是否有不同的平均值。

在 R 中,有两个函数可以执行 ANOVA 测试:oneway.testaovoneway.test的优点是该函数应用 Welch 校正来解决方差的非齐性。然而,它提供的信息不如aov多,并且不提供事后检验。接下来,我们对自变量gear和因变量mpg执行oneway.testaov。这两个测试的结果都显示了一个小的 p 值,这拒绝了不同档位数量的汽车在 mpg 均值之间没有差异的零假设。

由于 ANOVA 的结果仅表明总体均值之间存在显著差异,你可能不知道哪些总体在均值方面有所不同。因此,我们在 ANOVA 模型上应用TukeyHSD事后比较检验。结果显示,具有四个前进档位的汽车和具有三个档位的汽车之间的差异最大,因为它们的置信区间在图中最靠右。

更多内容...

ANOVA 依赖于 F 分布作为所有概率分布的基础。F 分数是通过将组间方差除以组内方差得到的。如果整体 F 检验是显著的,你可以进行事后检验(或多重比较检验)来衡量组之间的差异。最常用的事后检验方法是 Scheffé方法、Tukey-Kramer 方法和 Bonferroni 校正。

为了解释 ANOVA 的输出,您需要对某些术语有基本的了解,包括自由度、总平方和、组平方和、误差平方和、均方误差和 F 统计量。如果您需要更多关于这些术语的信息,您可以参考使用多元统计(Fidell, L. S. & Tabachnick, B. G. (2006) Boston: Allyn & Bacon),或者参考分析方差(en.wikipedia.org/wiki/Analysis_of_variance#cite_ref-31)的维基百科条目。

执行双向方差分析

双向方差分析可以看作是一元方差分析的扩展,因为分析覆盖了超过两个分类变量而不是一个。在本菜谱中,我们将讨论如何在 R 中执行双向方差分析。

准备工作

确保在 R 会话中已经将mtcars加载到数据框中。由于twoway.testTukeyHSDinteraction.plot函数源自stats包,请确保已加载库stats

如何做...

执行以下步骤:

  1. 首先,我们绘制了关于 mpg 的因子齿轮的两个箱线图,并将图表与传动类型分开:

    > par(mfrow=c(1,2))
    > boxplot(mtcars$mpg~mtcars$gear,subset=(mtcars$am==0),xlab='gear', ylab = "mpg",main='automatic')
    > boxplot(mtcars$mpg~mtcars$gear,subset=(mtcars$am==1),xlab='gear', ylab = "mpg", main='manual')
    
    

    如何做...

    根据齿轮组和传动类型绘制的 mpg 箱线图

  2. 此外,您可以使用boxplot函数中的*操作来根据前进档数*传动类型生成 mpg 的箱线图:

    > boxplot(mtcars$mpg~factor(mtcars$gear)* factor(mtcars$am),xlab='gear * transmission', ylab = "mpg",main='Boxplot of mpg by gear * transmission')
    
    

    如何做...

    根据齿轮和传动类型绘制 mpg 的箱线图

  3. 接下来,我们使用交互图来描述变量之间的关系:

    > interaction.plot(mtcars$gear, mtcars$am, mtcars$mpg, type="b", col=c(1:3),leg.bty="o", leg.bg="beige", lwd=2, pch=c(18,24,22), xlab="Number of Gears", ylab="Mean Miles Per Gallon", main="Interaction Plot")
    
    

    如何做...

    传动类型和齿轮数之间的交互作用以及主要效应 mpg

  4. 然后,我们对 mpg 执行双向方差分析,结合齿轮和传动类型因素:

    > mpg_anova2 = aov(mtcars$mpg~factor(mtcars$gear)*factor(mtcars$am))
    > summary(mpg_anova2) 
     Df Sum Sq Mean Sq F value   Pr(>F) 
    factor(mtcars$gear)  2  483.2  241.62  11.869 0.000185 ***
    factor(mtcars$am)    1   72.8   72.80   3.576 0.069001 . 
    Residuals           28  570.0   20.36 
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    
  5. 与一元方差分析类似,我们可以执行事后比较测试来查看双向方差分析模型的结果:

    > TukeyHSD(mpg_anova2)
     Tukey multiple comparisons of means
     95% family-wise confidence level
    
    Fit: aov(formula = mtcars$mpg ~ factor(mtcars$gear) * factor(mtcars$am))
    
    $`factor(mtcars$gear)`
     diff        lwr       upr     p adj
    4-3  8.426667  4.1028616 12.750472 0.0001301
    5-3  5.273333 -0.4917401 11.038407 0.0779791
    5-4 -3.153333 -9.0958350  2.789168 0.3999532
    
    $`factor(mtcars$am)`
     diff       lwr     upr     p adj
    1-0 1.805128 -1.521483 5.13174 0.2757926
    
    
  6. 然后,我们使用plot函数可视化均值水平的差异:

    > par(mfrow=c(1,2))
    > plot(TukeyHSD(mpg_anova2))
    
    

    如何做...

    通过传动类型和档位数比较均值水平的差异图

它是如何工作的...

在本菜谱中,我们执行双向方差分析来检验独立变量gearam对因变量mpg的影响。在第一步中,我们使用箱线图来检查齿轮数和传动类型下的 mpg 均值。其次,我们应用交互图来可视化通过不同数量的齿轮和传动类型分离的 mpg 变化。

结果图显示,齿轮数量确实对平均 mpg 值有影响,但并未显示出正相关关系。第三,我们使用aov函数进行双向方差分析。输出结果显示,gear因子的 p 值拒绝了零假设,而transmission type因子没有拒绝零假设。换句话说,不同齿轮数量的汽车更有可能具有不同的平均 mpg 值。最后,为了检验哪两个群体之间的差异最大,我们进行了事后分析,结果显示,四档和三档汽车的均值 mpg 差异最大。

参见

  • 对于多元方差分析,可以使用manova函数来检验多个自变量对多个因变量的影响。关于 MANOVA 的更多信息可以在 R 的help函数中找到:

    > ?MANOVA
    
    

第四章:理解回归分析

在本章中,我们将介绍以下食谱:

  • 使用 lm 函数拟合线性回归模型

  • 总结线性模型拟合结果

  • 使用线性回归预测未知值

  • 生成拟合模型的诊断图

  • 使用 lm 函数拟合多项式回归模型

  • 使用 rlm 函数拟合稳健线性回归模型

  • 研究 SLID 数据上的线性回归案例

  • 应用高斯模型进行广义线性回归

  • 应用泊松模型进行广义线性回归

  • 应用二项式模型进行广义线性回归

  • 将广义加性模型拟合到数据中

  • 可视化广义加性模型

  • 诊断广义加性模型

简介

回归是一种监督学习方法,用于建模和分析一个因变量(响应变量)与一个或多个自变量(预测变量)之间的关系。可以使用回归来构建预测模型,首先用于找到具有最小拟合值平方误差的最佳拟合模型。然后可以将拟合模型进一步应用于数据进行连续值预测。

有许多种类的回归。如果只有一个预测变量,响应变量和独立变量之间的关系是线性的,我们可以应用线性模型。然而,如果有多个预测变量,应使用多重线性回归方法。当关系是非线性的,可以使用非线性模型来模拟预测变量和响应变量之间的关系。

在本章中,我们介绍如何使用lm函数将线性模型拟合到数据中。接下来,对于非正态高斯模型(例如泊松或二项式)的分布,我们使用带有适当对应数据分布的链接函数的glm函数。最后,我们介绍如何使用gam函数将广义加性模型拟合到数据中。

使用 lm 函数拟合线性回归模型

回归中最简单的模型是线性回归,当只有一个预测变量,响应变量和独立变量之间的关系是线性的时,最适合使用。在 R 中,我们可以使用lm函数将线性模型拟合到数据中。

准备工作

我们需要准备一个预测变量和一个响应变量,以及两个变量之间的线性关系的数据。

如何做...

执行以下步骤以使用lm进行线性回归:

  1. 您应该安装car包并加载其库:

    > install.packages("car")
    > library(car)
    
    
  2. 从包中,您可以加载Quartet数据集:

    > data(Quartet)
    
    
  3. 您可以使用str函数来显示Quartet数据集的结构:

    > str(Quartet)
    'data.frame':   11 obs. of  6 variables:
     $ x : int  10 8 13 9 11 14 6 4 12 7 ...
     $ y1: num  8.04 6.95 7.58 8.81 8.33 ...
     $ y2: num  9.14 8.14 8.74 8.77 9.26 8.1 6.13 3.1 9.13 7.26 ...
     $ y3: num  7.46 6.77 12.74 7.11 7.81 ...
     $ x4: int  8 8 8 8 8 8 8 19 8 8 ...
     $ y4: num  6.58 5.76 7.71 8.84 8.47 7.04 5.25 12.5 5.56 7.91 ...
    
    
  4. 使用plot函数绘制 x 和 y 变量的散点图,并通过lmabline函数添加拟合线:

    > plot(Quartet$x, Quartet$y1)
    > lmfit = lm(y1~x, Quartet) 
    > abline(lmfit, col="red") 
    
    

    如何做...

    使用 lm 拟合的简单回归图

  5. 要查看拟合模型,执行以下操作:

    > lmfit
    
    Call:
    lm(formula = y1 ~ x, data = Quartet)
    
    Coefficients:
    (Intercept)            x 
     3.0001       0.5001 
    
    

它是如何工作的...

回归模型具有response ~ terms形式,其中response是响应向量,terms是一系列指定预测器的项。我们可以用一个简单的回归模型公式y=α+βx来表示,其中α是截距,而斜率β描述了x变化时y的变化。通过使用最小二乘法,我们可以估计如何工作...如何工作...(其中如何工作...表示y的平均值,如何工作...表示x的平均值)。

要执行线性回归,我们首先准备具有预测变量和响应变量之间线性关系的资料。在这个例子中,我们从 car 包中加载了 Anscombe 的四重奏数据集。在数据集中,xy1变量之间存在线性关系,我们为这些变量准备了一个散点图。为了生成回归线,我们使用 lm 函数生成两个变量的模型。进一步,我们使用abline在图上绘制回归线。根据前面的截图,回归线说明了xy1变量的线性关系。我们可以看到,拟合模型的系数显示了截距等于 3.0001,系数等于 0.5001。因此,我们可以使用截距和系数来推断响应值。例如,我们可以推断当x等于 3 时的响应值等于 4.5103(3 * 0.5001 + 3.0001)。

还有更多...

除了lm函数外,您还可以使用lsfit函数执行简单线性回归。例如:

> plot(Quartet$x, Quartet$y1)
> lmfit2 = lsfit(Quartet$x,Quartet$y1)
> abline(lmfit2, col="red")

还有更多...

使用 lsfit 函数拟合的简单回归。

总结线性模型拟合

summary函数可以用来获取拟合模型的格式化系数、标准误差、自由度和其他总结信息。本食谱介绍了如何通过使用summary函数来获取模型的整体信息。

准备工作

您需要完成之前的食谱,通过从四重奏中计算xy1变量的线性模型,并将拟合模型分配给lmfit变量。

如何做...

执行以下步骤以总结线性模型拟合:

  1. 计算拟合模型的详细总结:

    > summary(lmfit)
    
    Call:
    lm(formula = y1 ~ x)
    
    Residuals:
     Min       1Q   Median       3Q      Max 
    -1.92127 -0.45577 -0.04136  0.70941  1.83882 
    
    Coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept)   3.0001     1.1247   2.667  0.02573 * 
    Quartet$x     0.5001     0.1179   4.241  0.00217 **
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 1.237 on 9 degrees of freedom
    Multiple R-squared:  0.6665,    Adjusted R-squared:  0.6295 
    F-statistic: 17.99 on 1 and 9 DF,  p-value: 0.00217
    
    

如何工作...

summary函数是一个通用函数,用于生成总结统计量。在这种情况下,它计算并返回拟合线性模型的总结统计量列表。这里,它将输出诸如残差、系数标准误差、R 平方、f 统计量和自由度等信息。在Call部分,显示了用于生成拟合模型的函数。在Residuals部分,它提供了分布的快速总结(最小值、1Q、中位数、3Q、最大值)。

系数 部分,每个系数都是一个高斯随机变量。在此部分中,估计值 代表变量的均值分布;标准误差 显示变量的标准误差;t 值是 估计值 除以 标准误差,而 p 值表示得到大于 t 值的概率。在此样本中,截距(0.002573)和 x(0.00217)的 p 值都有 95% 的置信水平。

残差标准误差输出残差的方差,而自由度表示训练样本中的观测值与模型中使用的数量之间的差异。多重判定系数是通过除以平方和得到的。一个人可以使用判定系数来衡量数据与回归线拟合的接近程度。通常,判定系数越高,模型与数据的拟合度越好。然而,这并不一定意味着回归模型是充分的。这意味着您可能得到一个低判定系数的好模型,或者您可能得到一个高判定系数的差模型。由于多重判定系数忽略了自由度,计算出的分数是有偏的。为了使计算公平,调整判定系数(0.6295)使用无偏估计,并将略低于多重判定系数(0.6665)。F 统计量是通过在模型上执行 f 检验得到的。一个等于 0.00217(< 0.05)的 p 值拒绝零假设(变量之间没有线性相关性)并表明观察到的 F 值大于临界 F 值。换句话说,结果表明变量之间存在显著的线性正相关。

相关阅读

  • 要获取拟合模型参数的更多信息,您可以使用 help 函数或 ? 来查看帮助页面:

    > ?summary.lm
    
    
  • 或者,您可以使用以下函数来显示模型的属性:

    >  coefficients(lmfit) # Extract model coefficients
    >  confint(lmfit, level=0.95)  # Computes confidence intervals for model parameters.
    >  fitted(lmfit) # Extract model fitted values
    >  residuals(lmfit) # Extract model residuals 
    >  anova(lmfit) # Compute analysis of variance tables for fitted model object
    >  vcov(lmfit) # Calculate variance-covariance matrix for a fitted model object
    >  influence(lmfit) # Diagnose quality of regression fits
    
    

使用线性回归预测未知值

使用拟合的回归模型,我们可以将模型应用于预测未知值。对于回归模型,我们可以使用预测区间和置信区间来表示预测的精度。在下面的配方中,我们介绍如何在两种测量下预测未知值。

准备工作

您需要完成上一个配方,通过从 quartet 数据集中计算 xy1 变量的线性模型来完成。

如何操作...

按以下步骤使用线性回归预测值:

  1. 使用 xy1 变量拟合线性模型:

    > lmfit = lm(y1~x, Quartet)
    
    
  2. 将要预测的值分配到 newdata

    > newdata = data.frame(x = c(3,6,15))
    
    
  3. 使用置信水平设置为 0.95 的置信区间来计算预测结果:

    > predict(lmfit, newdata, interval="confidence", level=0.95)
     fit      lwr       upr
    1  4.500364 2.691375  6.309352
    2  6.000636 4.838027  7.163245
    3 10.501455 8.692466 12.310443
    
    
  4. 使用此预测区间来计算预测结果:

    > predict(lmfit, newdata, interval="predict")
     fit      lwr       upr
    1  4.500364 1.169022  7.831705
    2  6.000636 2.971271  9.030002
    3 10.501455 7.170113 13.832796
    
    

工作原理...

我们首先使用 xy1 变量构建一个线性拟合模型。接下来,我们将要预测的值分配到一个数据框 newdata 中。重要的是要注意,生成的模型形式为 y1 ~ x

接下来,我们通过在interval参数中指定confidence来使用置信区间计算预测结果。从第 1 行的输出中,我们得到x=3输入的拟合y1等于4.500364,以及x=3y1均值的 95%置信区间(在level参数中设置为 0.95)介于2.6913756.309352之间。此外,第 2 行和第 3 行给出了x=6x=15输入的y1预测结果。

接下来,我们通过在interval参数中指定prediction来使用预测区间计算预测结果。从第 1 行的输出中,我们可以看到x=3输入的拟合y1等于4.500364,以及x=3y1的 95%预测区间介于1.1690227.831705之间。第 2 行和第 3 行输出了x=6x=15输入的y1预测结果。

参考以下内容

生成拟合模型的诊断图

诊断是评估回归假设的方法,可用于确定拟合模型是否充分代表数据。在以下菜谱中,我们介绍如何通过使用诊断图来诊断回归模型。

准备工作

您需要通过从四元组中计算 x 和 y1 变量的线性模型来完成前面的菜谱,并将模型分配给lmfit变量。

如何操作...

执行以下步骤以生成拟合模型的诊断图:

  1. 绘制回归模型的诊断图:

    > par(mfrow=c(2,2))
    > plot(lmfit)
    
    

    如何操作...

    回归模型的诊断图

工作原理...

绘图函数生成回归模型的四个诊断图:

  • 左上角的图显示了残差与拟合值之间的关系。在图中,残差代表一个点到回归线的垂直距离。如果所有点都正好落在回归线上,所有残差都将正好落在虚线灰线上。图中的红色线是关于残差的光滑曲线,如果所有点都正好落在回归线上,红色线的位置应该正好与虚线灰线相匹配。

  • 右上角显示了残差的正态分布。此图验证了残差正态分布的假设。因此,如果残差是正态分布的,它们应该正好位于灰色虚线上。

  • 左下角的尺度-位置图用于测量标准化残差的平方根与拟合值之间的关系。因此,如果所有点都位于回归线上,则y的值应该接近零。由于假设残差的方差不会显著改变分布,如果假设正确,红色线应该相对平坦。

  • 右下角的图显示了标准化残差与杠杆作用的关系。杠杆作用是衡量每个数据点如何影响回归的度量。它是回归质心距离和隔离程度的度量(通过是否有邻居来衡量)。此外,您还可以找到受高杠杆和大量残差影响的 Cook 距离的轮廓。您可以使用此方法来衡量如果删除一个点,回归将如何改变。红色线在标准化残差方面很平滑。对于完美的拟合回归,红色线应该接近虚线,Cook 距离没有超过 0.5 的点。

还有更多...

要查看更多的诊断图功能,可以使用help函数获取更多信息:

> ?plot.lm

为了发现是否存在具有大 Cook 距离的点,可以使用cooks.distance函数计算每个点的 Cook 距离,并通过可视化分析距离的分布:

> plot(cooks.distance(lmfit))

还有更多...

Cook 距离图

在这种情况下,如果索引为 3 的点显示的 Cook 距离大于其他点,可以调查这个点是否可能是异常值。

使用 lm 拟合多项式回归模型

一些预测变量和响应变量可能存在非线性关系,它们的关系可以建模为n次多项式。在这个菜谱中,我们将介绍如何使用lmpoly函数处理多项式回归。

准备工作

准备包含可以建模为n次多项式的预测变量和响应变量之间关系的数据库。在这个菜谱中,我们将继续使用car包中的Quartet数据库。

如何操作...

执行以下步骤以使用lm拟合多项式回归模型:

  1. 首先,我们绘制xy2变量的散点图:

    > plot(Quartet$x, Quartet$y2)
    
    

    如何操作...

    变量 x 和 y2 的散点图

  2. 您可以通过指定参数中的2来应用poly函数:

    > lmfit = lm(Quartet$y2~poly(Quartet$x,2))
    > lines(sort(Quartet$x), lmfit$fit[order(Quartet$x)], col = "red")
    
    

    如何操作...

    变量 x 和 y2 的回归图的一个二次拟合示例

工作原理

我们可以在公式工作原理中说明二次多项式回归模型,其中α是截距,而β表示回归系数。

在前面的截图(步骤 1)中,xy2变量的散点图不呈线性关系,而是显示一个向下凹的曲线(或向上凸)的形状,转折点在 x=11。为了建模非线性关系,我们使用带有 2 作为参数的poly函数来拟合独立的x变量和依赖的y2变量。截图中的红线显示模型完美地拟合了数据。

更多...

您还可以使用一个独立变量等于一阶x变量和二阶x变量公式的二阶多项式模型:

> plot(Quartet$x, Quartet$y2)
> lmfit = lm(Quartet$y2~ I(Quartet$x)+I(Quartet$x²))

使用 rlm 拟合稳健线性回归模型

数据集中的异常值会将回归线从主流移动开去。除了移除它之外,我们还可以对包含异常值的数据集应用稳健线性回归。在本配方中,我们介绍了如何将rlm应用于对包含异常值的数据集进行稳健线性回归。

准备工作

准备一个可能将回归线从主流移动开去的异常值数据集。在这里,我们使用从先前配方中加载的Quartet数据集。

如何操作...

按照以下步骤使用rlm拟合稳健线性回归模型:

  1. 生成x变量对y3的散点图:

    > plot(Quartet$x, Quartet$y3)
    
    

    如何操作...

    变量 x 和 y3 的散点图

  2. 接下来,您应该首先导入MASS库。然后,您可以使用rlm函数来拟合模型,并使用abline函数可视化拟合的线:

    > library(MASS)
    > lmfit = rlm(Quartet$y3~Quartet$x)
    > abline(lmfit, col="red")
    
    

    如何操作...

    对变量 x 和 y3 的稳健线性回归

工作原理

根据前面的截图(步骤 1),您可能会遇到包含远离主流的异常值的数据集。为了消除异常值的影响,我们展示了如何应用稳健线性回归(rlm)来拟合数据。在第二个截图(步骤 2)中,稳健回归线忽略了异常值并匹配了主流。

更多...

为了看到异常值如何将回归线从主流移动开去,您可以将此配方中使用的rlm函数替换为lm,并重新绘制图形:

> plot(Quartet$x, Quartet$y3)
> lmfit = lm(Quartet$y3~Quartet$x)
> abline(lmfit, col="red")

更多...

变量 x 和 y3 的线性回归

显然,异常值(x=13)将回归线从主流移动开去。

研究 SLID 数据上的线性回归案例

为了总结上一节的内容,我们使用线性回归探索更复杂的数据。在本配方中,我们展示了如何将线性回归应用于分析劳动与收入动态调查SLID)数据集。

准备工作

检查是否已安装和加载car库,因为它需要访问 SLID 数据集。

如何操作...

按照以下步骤在 SLID 数据上执行线性回归:

  1. 您可以使用str函数来获取数据的概览:

    > str(SLID)
    'data.frame':  7425 obs. of  5 variables:
     $ wages    : num  10.6 11 NA 17.8 NA ...
     $ education: num  15 13.2 16 14 8 16 12 14.5 15 10 ...
     $ age      : int  40 19 49 46 71 50 70 42 31 56 ...
     $ sex      : Factor w/ 2 levels "Female","Male": 2 2 2 2 2 1 1 1 2 1 ...
     $ language : Factor w/ 3 levels "English","French",..: 1 1 3 3 1 1 1 1 1 1 ..
    
    
  2. 首先,我们将变量工资与语言、年龄、教育和性别可视化:

    > par(mfrow=c(2,2))
    > plot(SLID$wages ~ SLID$language)
    > plot(SLID$wages ~ SLID$age)
    > plot(SLID$wages ~ SLID$education)
    > plot(SLID$wages ~ SLID$sex)
    
    

    如何操作...

    工资与多种组合的绘图

  3. 然后,我们可以使用lm来拟合模型:

    > lmfit = lm(wages ~ ., data = SLID)
    
    
  4. 您可以通过summary函数检查拟合模型的摘要:

    > summary(lmfit)
    
    Call:
    lm(formula = wages ~ ., data = SLID)
    
    Residuals:
     Min      1Q  Median      3Q     Max 
    -26.062  -4.347  -0.797   3.237  35.908 
    
    Coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept)    -7.888779   0.612263 -12.885   <2e-16 ***
    education       0.916614   0.034762  26.368   <2e-16 ***
    age             0.255137   0.008714  29.278   <2e-16 ***
    sexMale         3.455411   0.209195  16.518   <2e-16 ***
    languageFrench -0.015223   0.426732  -0.036    0.972 
    languageOther   0.142605   0.325058   0.439    0.661 
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 6.6 on 3981 degrees of freedom
     (3438 observations deleted due to missingness)
    Multiple R-squared:  0.2973,	Adjusted R-squared:  0.2964 
    F-statistic: 336.8 on 5 and 3981 DF,  p-value: < 2.2e-16
    
    
  5. 删除language属性,并使用lm函数重新拟合模型:

    > lmfit = lm(wages ~ age + sex + education, data = SLID)
    > summary(lmfit)
    
    Call:
    lm(formula = wages ~ age + sex + education, data = SLID)
    
    Residuals:
     Min      1Q  Median      3Q     Max 
    -26.111  -4.328  -0.792   3.243  35.892 
    
    Coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept) -7.905243   0.607771  -13.01   <2e-16 ***
    age          0.255101   0.008634   29.55   <2e-16 ***
    sexMale      3.465251   0.208494   16.62   <2e-16 ***
    education    0.918735   0.034514   26.62   <2e-16 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 6.602 on 4010 degrees of freedom
     (3411 observations deleted due to missingness)
    Multiple R-squared:  0.2972,	Adjusted R-squared:  0.2967 
    F-statistic: 565.3 on 3 and 4010 DF,  p-value: < 2.2e-16
    
    
  6. 然后,我们可以绘制lmfit的诊断图:

    > par(mfrow=c(2,2))
    > plot(lmfit)
    
    

    如何操作...

    拟合模型的诊断图

  7. 接下来,我们对工资取对数并重新绘制诊断图:

    > lmfit = lm(log(wages) ~ age + sex + education, data = SLID)
    > plot(lmfit)
    
    

    如何操作...

    调整后拟合模型的诊断图

  8. 接下来,您可以使用vif函数诊断回归模型的多重共线性:

    > vif(lmfit)
     age       sex education 
     1.011613  1.000834  1.012179 
    > sqrt(vif(lmfit)) > 2
     age       sex education 
     FALSE     FALSE     FALSE
    
    
  9. 然后,您可以安装并加载lmtest包,并使用bptest函数诊断回归模型的异方差性:

    > install.packages("lmtest")
    > library(lmtest)
    > bptest(lmfit)
    
     studentized Breusch-Pagan test
    
    data:  lmfit
    BP = 29.0311, df = 3, p-value = 2.206e-06
    
    
  10. 最后,您可以安装并加载rms包。然后,您可以使用robcov来纠正标准误差:

    > install.packages("rms")
    > library(rms)
    > olsfit = ols(log(wages) ~ age + sex + education, data= SLID, x= TRUE, y= TRUE)
    > robcov(olsfit)
    
    Linear Regression Model
    
    ols(formula = log(wages) ~ age + sex + education, data = SLID, 
     x = TRUE, y = TRUE)
    
    Frequencies of Missing Values Due to Each Variable
    log(wages)        age        sex  education 
     3278          0          0        249 
    
     Model Likelihood     Discrimination 
     Ratio Test           Indexes 
    Obs     4014    LR chi2   1486.08    R2       0.309 
    sigma 0.4187    d.f.            3    R2 adj   0.309 
    d.f.    4010    Pr(> chi2) 0.0000    g        0.315 
    
    Residuals
    
     Min       1Q   Median       3Q      Max 
    -2.36252 -0.27716  0.01428  0.28625  1.56588 
    
     Coef   S.E.   t     Pr(>|t|)
    Intercept 1.1169 0.0387 28.90 <0.0001 
    age       0.0176 0.0006 30.15 <0.0001 
    sex=Male  0.2244 0.0132 16.96 <0.0001 
    education 0.0552 0.0022 24.82 <0.0001
    
    

它是如何工作的...

本菜谱演示了如何在 SLID 数据集上执行线性回归分析。首先,我们加载 SLID 数据并通过使用str函数显示其结构。从数据结构中,我们知道有四个独立变量将影响因变量工资。

接下来,我们通过可视化探索每个独立变量与因变量wages之间的关系;可视化结果如图所示(步骤 2)。在此截图的左上角,您可以找到三种不同语言与工资的箱线图;语言与工资之间的相关性不明显。截图右上角显示,年龄似乎与因变量wages呈正相关。在截图的左下角,显示教育似乎也与工资呈正相关。最后,截图右下角的箱线图显示,男性的工资略高于女性。

接下来,我们将除了wages以外的所有属性拟合到模型中作为预测变量。通过总结模型,可以看出教育、年龄和性别具有显著性(p-value < 0.05)。因此,我们删除了不显著的language属性(其 p 值大于 0.05),并在线性模型中将三个独立变量(教育、性别和年龄)与因变量(wages)拟合。这相应地将 f 统计量从 336.8 提高到 565.3。

接下来,我们生成拟合模型的诊断图。在诊断图中,所有四个图都表明回归模型遵循回归假设。然而,从残差与拟合值和尺度-位置图中可以看出,较小拟合值的残差偏向回归模型。由于工资跨越几个数量级,为了诱导对称性,我们对工资应用对数变换,并将数据重新拟合到回归模型中。现在,残差与拟合值图和尺度-位置图的红线与灰色虚线更接近。

接下来,我们想测试模型中是否存在多重共线性。当预测变量与其他变量高度相关时,就会发生多重共线性。如果模型中存在多重共线性,你可能会看到一些变量具有高的 R-squared 值,但显示为不显著的变量。为了检测多重共线性,我们可以使用vif函数计算线性模型和广义线性模型的方差膨胀因子和广义方差膨胀因子。如果存在多重共线性,我们应该找到方差膨胀因子平方根大于 2 的预测变量。然后,我们可以移除冗余预测变量或使用主成分分析将预测变量转换为较小的一组不相关成分。

最后,我们想测试模型中是否存在异方差性。在讨论异方差性的定义之前,我们首先要知道,在经典假设中,普通回归模型假设误差的方差在观测值之间是恒定的或同质的。相反,异方差性意味着方差在观测值之间是不等的。因此,异方差性可能会偏向我们估计的标准误差,从而误导假设的检验。为了检测和测试异方差性,我们可以在lmtest包中的bptest函数执行异方差性的Breusch-Pagan检验。在这种情况下,p 值显示为 2.206e-06(<0.5),这拒绝了同方差性的零假设(没有异方差性)。在这里,它意味着参数估计的标准误差是不正确的。然而,我们可以使用rms包中的robcov来使用稳健标准误差纠正标准误差(不消除异方差性)并提高真正显著参数的显著性。然而,由于它只接受rms系列中的拟合模型作为输入,我们必须先拟合普通最小二乘模型。

参考信息

  • 如需了解更多关于 SLID 数据集的信息,您可以使用help函数查看相关文档:

    >  ?SLID
    
    

应用高斯模型进行广义线性回归

广义线性模型GLM)是线性回归的推广,可以包括连接函数以进行线性预测。作为默认设置,glm 的家族对象是高斯,这使得 glm 函数的表现与 lm 完全相同。在本例中,我们首先演示如何使用 glm 函数将模型拟合到数据中,然后展示具有高斯模型的 glmlm 的表现完全相同。

准备工作

检查 car 库是否已安装并加载,因为我们需要从该包中获取 SLID 数据集。

如何操作...

执行以下步骤以拟合具有高斯模型的广义线性回归模型:

  1. 将独立变量 agesexeducation 以及因变量 wages 拟合到 glm

    > lmfit1 = glm(wages ~ age + sex + education, data = SLID, family=gaussian)
    > summary(lmfit1)
    
    Call:
    glm(formula = wages ~ age + sex + education, family = gaussian, 
     data = SLID)
    
    Deviance Residuals: 
     Min       1Q   Median       3Q      Max 
    -26.111   -4.328   -0.792    3.243   35.892 
    
    Coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept) -7.905243   0.607771  -13.01   <2e-16 ***
    age          0.255101   0.008634   29.55   <2e-16 ***
    sexMale      3.465251   0.208494   16.62   <2e-16 ***
    education    0.918735   0.034514   26.62   <2e-16 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    (Dispersion parameter for Gaussian family taken to be 43.58492)
    
     Null deviance: 248686  on 4013  degrees of freedom
    Residual deviance: 174776  on 4010  degrees of freedom
     (3411 observations deleted due to missingness)
    AIC: 26549
    
    Number of Fisher Scoring iterations: 2
    
    
  2. 将独立变量 agesexeducation 以及因变量 wages 拟合到 lm

    > lmfit2 = lm(wages ~ age + sex + education, data = SLID)
    > summary(lmfit2)
    
    Call:
    lm(formula = wages ~ age + sex + education, data = SLID)
    
    Residuals:
     Min      1Q  Median      3Q     Max 
    -26.111  -4.328  -0.792   3.243  35.892 
    
    Coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept) -7.905243   0.607771  -13.01   <2e-16 ***
    age          0.255101   0.008634   29.55   <2e-16 ***
    sexMale      3.465251   0.208494   16.62   <2e-16 ***
    education    0.918735   0.034514   26.62   <2e-16 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 6.602 on 4010 degrees of freedom
     (3411 observations deleted due to missingness)
    Multiple R-squared:  0.2972,	Adjusted R-squared:  0.2967 
    F-statistic: 565.3 on 3 and 4010 DF,  p-value: < 2.2e-16
    
    
  3. 使用 anova 比较两个拟合模型:

    > anova(lmfit1, lmfit2)
    Analysis of Deviance Table
    
    Model: gaussian, link: identity
    
    Response: wages
    
    Terms added sequentially (first to last)
    
     Df Deviance Resid. Df Resid. Dev
    NULL                       4013     248686
    age        1    31953      4012     216733
    sex        1    11074      4011     205659
    education  1    30883      4010     174776
    
    

工作原理...

glm 函数以与 lm 函数类似的方式拟合数据模型。唯一的区别是您可以在参数 family 中指定不同的连接函数(您可以在控制台中使用 ?family 来查找不同类型的连接函数)。在本例中,我们首先将独立变量 agesexeducation 以及因变量 wages 输入到 glm 函数中,并将构建的模型赋值给 lmfit1。您可以使用构建的模型进行进一步的预测。

接下来,为了确定具有高斯模型的 glm 是否与 lm 完全相同,我们将独立变量 agesexeducation 以及因变量 wages 拟合到 lm 模型中。通过将 summary 函数应用于两个不同的模型,它揭示了两个输出摘要的残差和系数完全相同。

最后,我们使用 anova 函数进一步比较两个拟合模型。anova 函数的结果显示,两个模型相似,具有相同的 残差自由度Res.DF)和 残差平方和RSS Df)。

参见

  • 对于广义线性模型与线性模型的比较,您可以参考 Venables, W. N., & Ripley, B. D. (2002). Modern applied statistics with S. Springer

应用泊松模型进行广义线性回归

广义线性模型允许响应变量具有除正态分布(高斯)之外的错误分布模型。在本例中,我们展示了如何将泊松作为 glm 中的家族对象应用于计数数据。

准备工作

本任务的先决条件是准备计数数据,所有输入数据值均为整数。

如何操作...

执行以下步骤以拟合具有泊松模型的广义线性回归模型:

  1. 加载 warpbreaks 数据,并使用 head 查看前几行:

    > data(warpbreaks)
    > head(warpbreaks)
     breaks wool tension
    1     26    A       L
    2     30    A       L
    3     54    A       L
    4     25    A       L
    5     70    A       L
    6     52    A       L
    
    
  2. 我们将泊松作为家族对象应用于独立变量 tension 和因变量 breaks

    > rs1 = glm(breaks ~ tension, data=warpbreaks, family="poisson")
    > summary(rs1)
    
    Call:
    glm(formula = breaks ~ tension, family = "poisson", data = warpbreaks)
    
    Deviance Residuals: 
     Min       1Q   Median       3Q      Max 
    -4.2464  -1.6031  -0.5872   1.2813   4.9366 
    
    Coefficients:
     Estimate Std. Error z value Pr(>|z|) 
    (Intercept)  3.59426    0.03907  91.988  < 2e-16 ***
    tensionM    -0.32132    0.06027  -5.332 9.73e-08 ***
    tensionH    -0.51849    0.06396  -8.107 5.21e-16 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    (Dispersion parameter for Poisson family taken to be 1)
    
     Null deviance: 297.37  on 53  degrees of freedom
    Residual deviance: 226.43  on 51  degrees of freedom
    AIC: 507.09
    
    Number of Fisher Scoring iterations: 4
    
    

工作原理...

在泊松分布的假设下,计数数据可以拟合到对数线性模型。在这个例子中,我们首先从warpbreaks数据集中加载了一个样本计数数据,其中包含了每台织机的断裂次数。接下来,我们使用glm函数,将断裂次数作为因变量,tension作为自变量,泊松作为家族对象。最后,我们使用摘要函数查看拟合的对数线性模型。

参考以下内容

  • 要了解更多关于泊松模型与计数数据的关系,您可以参考Cameron, A. C., & Trivedi, P. K. (2013). Regression analysis of count data (No. 53). Cambridge university press.

应用广义线性回归的二项模型

对于二元因变量,可以在glm函数中将二项模型作为家族对象应用。

准备工作

此任务的先决条件是准备一个二元因变量。在这里,我们使用vs变量(V 型发动机或直列发动机)作为因变量。

如何操作...

执行以下步骤以使用二项模型拟合广义线性回归模型:

  1. 首先,我们检查mtcars数据集中vs的前六个元素:

    > head(mtcars$vs)
    [1] 0 0 1 1 0 1
    
    
  2. 我们使用glm函数,将binomial作为家族对象应用:

    > lm1 = glm(vs ~ hp+mpg+gear,data=mtcars, family=binomial)
    > summary(lm1)
    
    Call:
    glm(formula = vs ~ hp + mpg + gear, family = binomial, data = mtcars)
    
    Deviance Residuals: 
     Min        1Q    Median        3Q       Max 
    -1.68166  -0.23743  -0.00945   0.30884   1.55688 
    
    Coefficients:
     Estimate Std. Error z value Pr(>|z|) 
    (Intercept) 11.95183    8.00322   1.493   0.1353 
    hp          -0.07322    0.03440  -2.129   0.0333 *
    mpg          0.16051    0.27538   0.583   0.5600 
    gear        -1.66526    1.76407  -0.944   0.3452 
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    (Dispersion parameter for binomial family taken to be 1)
    
     Null deviance: 43.860  on 31  degrees of freedom
    Residual deviance: 15.651  on 28  degrees of freedom
    AIC: 23.651
    
    Number of Fisher Scoring iterations: 7
    
    

工作原理...

在二元数据中,每个响应值的观测值被编码为01。将二元数据拟合到回归模型需要二项分布函数。在这个例子中,我们首先从mtcars数据集中加载二元因变量vsvs适合二项模型,因为它包含二元数据。接下来,我们使用glm函数通过指定binomial作为家族对象将模型拟合到二元数据。最后,通过查看摘要,我们可以获得拟合模型的描述。

参考以下内容

  • 如果您仅在参数中指定家族对象,您将使用默认的链接来拟合模型。但是,要使用替代链接函数,您可以添加一个链接参数。例如:

    > lm1 = glm(vs ~ hp+mpg+gear,data=mtcars, family=binomial(link="probit"))
    
    
  • 如果您想知道可以使用多少个替代链接,请通过帮助功能参考家族文档:

     > ?family
    
    

将广义加性模型拟合到数据中

广义加性模型GAM),用于拟合广义加性模型,可以被视为 GLM 的半参数扩展。虽然 GLM 假设因变量和自变量之间存在线性关系,但 GAM 根据数据的局部行为拟合模型。因此,GAM 具有处理因变量和自变量之间高度非线性关系的能力。在下面的步骤中,我们介绍如何使用广义加性模型拟合回归。

准备工作

我们需要准备一个包含变量的数据框,其中一个变量是响应变量,其他变量可能是预测变量。

如何操作...

执行以下步骤以将广义加性模型拟合到数据中:

  1. 首先,加载包含gam函数的mgcv包:

    > install.packages("mgcv")
    > library(mgcv)
    
    
  2. 然后,安装MASS包并加载Boston数据集:

    > install.packages("MASS")
    > library(MASS)
    > attach(Boston)
    > str(Boston)
    
    
  3. 使用gam拟合回归:

    > fit = gam(dis ~ s(nox))
    
    
  4. 获取拟合模型的摘要信息:

    > summary(fit)
    Family: gaussian 
    Link function: identity 
    
    Formula:
    dis ~ s(nox)
    
    Parametric coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept)  3.79504    0.04507   84.21   <2e-16 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Approximate significance of smooth terms:
     edf Ref.df   F p-value 
    s(nox) 8.434  8.893 189  <2e-16 ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    R-sq.(adj) =  0.768   Deviance explained = 77.2%
    GCV = 1.0472  Scale est. = 1.0277    n = 506
    
    

工作原理

GAM 旨在通过估计与因变量y通过链接函数连接的预测者的非参数函数来最大化从各种分布中预测因变量y。GAM 的概念工作原理,其中指定了指数族E用于y,以及g链接函数;f表示预测者的链接函数。

gam函数包含在mgcv包中,因此,首先安装此包并将其加载到 R 会话中。接下来,从MASS包中加载波士顿数据集(波士顿郊区的住房价值)。从数据集中,我们使用dis(到五个波士顿就业中心的加权平均距离)作为因变量,nox(氮氧化物浓度)作为自变量,然后将它们输入到gam函数中以生成拟合模型。

glm类似,gam允许用户总结gam拟合。从总结中,可以找到参数参数、平滑项的显著性以及其他有用信息。

相关内容

  • 除了gam之外,mgcv包还提供另一个用于大数据集的广义加性模型bambam包与gam非常相似,但使用更少的内存,效率相对更高。请使用help函数获取有关此模型的更多信息:

     > ? bam
    
    
  • 有关 R 中广义加性模型的更多信息,请参阅 Wood, S. (2006). 广义加性模型:R 语言导论. CRC 出版社

可视化广义加性模型

在这个配方中,我们演示了如何将gam拟合回归线添加到散点图中。此外,我们使用plot函数可视化gam拟合。

准备工作

通过将gam拟合模型分配给fit变量来完成前面的配方。

如何做...

执行以下步骤以可视化广义加性模型:

  1. 使用noxdis变量生成散点图:

    > plot(nox, dis)
    
    

    如何做...

    变量 nox 对 dis 的散点图

  2. 将回归添加到散点图:

    > x = seq(0, 1, length = 500)
    > y = predict(fit, data.frame(nox = x))
    > lines(x, y, col = "red", lwd = 2)
    
    

    如何做...

    散点图上的gam拟合回归

  3. 或者,您可以使用plot函数绘制拟合模型:

    > plot(fit)
    
    

    如何做...

    拟合gam的图

工作原理...

要可视化拟合回归,我们首先使用disnox变量生成散点图。然后,我们生成x轴的序列,并通过在拟合模型fit上使用predict函数来响应y。最后,我们使用lines函数将回归线添加到散点图中。

除了在散点图上使用线条添加拟合回归线外,gam还有一个plot函数来可视化包含置信区域的拟合回归线。为了阴影置信区域,我们在函数中指定shade = TRUE

更多...

vis.gam函数用于生成gam模型预测的透视或等高线图视图。这有助于观察响应变量如何与两个预测变量相互作用。以下是在Boston数据集上的等高线图示例:

> fit2=gam(medv~crim+zn+crim:zn, data=Boston)
> vis.gam(fit2)

更多...

由 vis.gam 生成的样本等高线图

诊断广义加性模型

GAM 还提供了关于拟合过程和广义加性模型结果的诊断信息。在这个菜谱中,我们展示了如何通过gam.check函数绘制诊断图。

准备工作

确保之前的菜谱已完成,并将gam拟合模型分配给fit变量。

如何做...

执行以下步骤以诊断广义加性模型:

  1. 使用gam.check在拟合模型上生成诊断图:

    > gam.check(fit)
    
    Method: GCV   Optimizer: magic
    Smoothing parameter selection converged after 7 iterations.
    The RMS GCV score gradient at convergence was 8.79622e-06 .
    The Hessian was positive definite.
    The estimated model rank was 10 (maximum possible: 10)
    Model rank =  10 / 10 
    
    Basis dimension (k) checking results. Low p-value (k-index<1) may
    indicate that k is too low, especially if edf is close to k'.
    
     k'   edf k-index p-value
    s(nox) 9.000 8.434   0.397       0
    
    

    如何做...

    拟合的 gam 诊断图

它是如何工作的...

gam.check 函数首先生成平滑参数估计收敛信息。在这个例子中,平滑参数,GCV/UBRE广义交叉验证/无偏风险估计器)得分在七次迭代后收敛。GCV/UBRE 函数在最小值处的平均绝对梯度为 8.79622e-06,估计的秩为10。维度检查是为了测试平滑函数的基函数维度是否足够。从这个例子中可以看出,低 p 值表明 k 设置得太低。可以通过指定参数 k,通过拟合gam到数据中来调整平滑的维度选择。

除了提供有关平滑参数估计收敛的信息外,该函数还返回四个诊断图。截图中的图的上左部分显示了一个分位数比较图。此图有助于识别异常值和重尾。图的右上部分显示了残差与线性预测器的对比,这在寻找非恒定误差方差时很有用。图的左下部分显示了残差的直方图,有助于检测非正态性。图的右下部分显示了响应值与拟合值的关系。

更多...

您可以通过help函数获取有关gam.check的更多信息。特别是,这包括平滑参数估计收敛的详细说明和四个返回的图:

> ?gam.check

此外,可以通过以下命令获取choose.k的更多信息:

> ?choose.k

第五章. 分类(I)- 树、懒惰和概率

在本章中,我们将介绍以下步骤:

  • 准备训练和测试数据集

  • 使用递归分区树构建分类模型

  • 可视化递归分区树

  • 测量递归分区树的预测性能

  • 剪枝递归分区树

  • 使用条件推断树构建分类模型

  • 可视化条件推断树

  • 测量条件推断树的预测性能

  • 使用 k 近邻分类器对数据进行分类

  • 使用逻辑回归对数据进行分类

  • 使用朴素贝叶斯分类器对数据进行分类

简介

分类用于根据从训练数据集构建的分类模型识别新观察值的类别(测试数据集),其中类别已经已知。与回归类似,分类被归类为监督学习方法,因为它使用训练数据集的已知答案(标签)来预测测试数据集的答案(标签)。回归和分类之间的主要区别在于,回归用于预测连续值。

与此相反,分类用于识别给定观察值的类别。例如,一个人可能使用回归来根据历史价格预测给定股票的未来价格。然而,应该使用分类方法来预测股票价格是上涨还是下跌。

在本章中,我们将说明如何使用 R 进行分类。我们首先从客户流失数据集中构建训练数据集和测试数据集,然后应用不同的分类方法对客户流失数据集进行分类。在下面的步骤中,我们将介绍使用传统分类树和条件推断树、基于懒惰的算法以及使用基于概率的方法(使用训练数据集构建分类模型),然后使用该模型预测测试数据集的类别(类别标签)。我们还将使用混淆矩阵来衡量性能。

准备训练和测试数据集

构建分类模型需要训练数据集来训练分类模型,并且需要测试数据来验证预测性能。在下面的步骤中,我们将演示如何将电信客户流失数据集分割成训练数据集和测试数据集。

准备工作

在这个步骤中,我们将使用电信客户流失数据集作为输入数据源,并将数据分割成训练数据集和测试数据集。

如何做...

执行以下步骤将客户流失数据集分割成训练数据集和测试数据集:

  1. 您可以从C50包中检索客户流失数据集:

    > install.packages("C50")
    > library(C50)
    > data(churn)
    
    
  2. 使用str读取数据集的结构:

    > str(churnTrain)
    
    
  3. 我们可以移除statearea_codeaccount_length属性,这些属性不适合作为分类特征:

    > churnTrain = churnTrain[,! names(churnTrain) %in% c("state", "area_code", "account_length") ]
    
    
  4. 然后,将 70%的数据分割为训练集,30%的数据分割为测试集:

    > set.seed(2)
    > ind = sample(2, nrow(churnTrain), replace = TRUE, prob=c(0.7, 0.3))
    > trainset = churnTrain[ind == 1,]
    > testset = churnTrain[ind == 2,]
    
    
  5. 最后,使用dim来探索训练集和测试集的维度:

    > dim(trainset)
    [1] 2315   17
    > dim(testset)
    [1] 1018   17
    
    

工作原理...

在本食谱中,我们使用电信流失数据集作为示例数据源。该数据集包含 20 个变量和 3,333 个观测值。我们希望构建一个分类模型来预测客户是否会流失,这对电信公司来说非常重要,因为获取新客户的成本显著高于保留现有客户。

在构建分类模型之前,我们首先需要预处理数据。因此,我们使用变量名churn将流失数据从C50包加载到 R 会话中。由于我们确定属性如statearea_codeaccount_length对于构建分类模型不是有用的特征,我们移除了这些属性。

在预处理数据后,我们将数据分别分割为训练集和测试集。然后,我们使用一个样本函数随机生成一个包含 70%训练集和 30%测试集的序列,其大小等于观测值的数量。然后,我们使用生成的序列将流失数据集分割为训练集trainset和测试集testset。最后,通过使用dim函数,我们发现 3,333 个观测值中有 2,315 个被归类到训练集trainset,而其他 1,018 个被归类到测试集testset

更多内容...

您可以将训练集和测试集的分割过程合并到split.data函数中。因此,您可以通过调用此函数并指定参数中的比例和种子来轻松地将数据分割成两个数据集:

> split.data = function(data, p = 0.7, s = 666){
+   set.seed(s)
+   index = sample(1:dim(data)[1])
+   train = data[index[1:floor(dim(data)[1] * p)], ]
+   test = data[index[((ceiling(dim(data)[1] * p)) + 1):dim(data)[1]], ]
+   return(list(train = train, test = test))
+ } 

使用递归分割树构建分类模型

分类树使用分割条件根据一个或多个输入变量预测类标签。分类过程从树的根节点开始;在每个节点,过程将检查输入值是否应该根据分割条件递归地继续到右子分支或左子分支,并在遇到决策树的任何叶(终端)节点时停止。在本食谱中,我们将介绍如何将递归分割树应用于客户流失数据集。

准备工作

您需要完成之前的食谱,将流失数据集分割为训练集(trainset)和测试集(testset),并且每个数据集应恰好包含 17 个变量。

如何操作...

执行以下步骤将流失数据集分割为训练集和测试集:

  1. 加载rpart包:

    > library(rpart)
    
    
  2. 使用rpart函数构建分类树模型:

    > churn.rp = rpart(churn ~ ., data=trainset)
    
    
  3. 输入churn.rp以检索分类树的节点细节:

    > churn.rp 
    
    
  4. 接下来,使用printcp函数来检查复杂度参数:

    > printcp(churn.rp)
    
    Classification tree:
    rpart(formula = churn ~ ., data = trainset)
    
    Variables actually used in tree construction:
    [1] international_plan            number_customer_service_calls
    [3] total_day_minutes             total_eve_minutes 
    [5] total_intl_calls              total_intl_minutes 
    [7] voice_mail_plan 
    
    Root node error: 342/2315 = 0.14773
    
    n= 2315 
    
     CP nsplit rel error  xerror     xstd
    1 0.076023      0   1.00000 1.00000 0.049920
    2 0.074561      2   0.84795 0.99708 0.049860
    3 0.055556      4   0.69883 0.76023 0.044421
    4 0.026316      7   0.49415 0.52632 0.037673
    5 0.023392      8   0.46784 0.52047 0.037481
    6 0.020468     10   0.42105 0.50877 0.037092
    7 0.017544     11   0.40058 0.47076 0.035788
    8 0.010000     12   0.38304 0.47661 0.035993
    
    
  5. 接下来,使用plotcp函数来绘制成本复杂度参数:

    > plotcp(churn.rp)
    
    

    如何操作...

    图 1:成本复杂度参数图

  6. 最后,使用summary函数来检查构建的模型:

    > summary(churn.rp)
    
    

它是如何工作的...

在这个菜谱中,我们使用rpart包中的递归分割树来构建基于树的分类模型。递归分割树包括两个过程:递归和分割。在决策诱导的过程中,我们必须考虑一个统计评估问题(或者简单地说是一个是/否问题),根据评估结果将数据分割成不同的分区。然后,当我们确定了子节点后,我们可以重复执行分割,直到满足停止标准。

例如,根节点中的数据(如下所示)可以根据f1是否小于X的问题分为两组。如果是,数据被分割到左侧。否则,它被分割到右侧。然后,我们可以继续使用f2是否小于Y的问题来分割左侧数据:

如何操作...

图 2:递归分割树

在第一步中,我们使用library函数加载rpart包。接下来,我们使用churn变量作为分类类别(类别标签)和剩余变量作为输入特征来构建分类模型。

模型构建完成后,你可以输入构建的模型变量名churn.rp来显示树节点细节。在打印的节点细节中,n表示样本大小,loss表示误分类成本,yval表示分类成员(在这种情况下为noyes),而yprob表示两个类的概率(左值表示达到标签no的概率,右值表示达到标签yes的概率)。

然后,我们使用printcp函数来打印构建的树模型的复杂度参数。从printcp的输出中,应该找到一个复杂度参数 CP 的值,它作为惩罚来控制树的大小。简而言之,CP 值越大,分割的数量(nsplit)就越少。输出值(rel误差)表示当前树的平均偏差除以空树的平均偏差。xerror值表示由 10 折分类估计的相对误差。xstd表示相对误差的标准误差。

为了使CP成本复杂度参数)表更易于阅读,我们使用plotcp生成 CP 表的信息图形。根据截图(步骤 5),底部 x 轴表示cp值,y 轴表示相对误差,上 x 轴显示树的大小。虚线表示标准差的上线。从截图可以确定,当树的大小为 12 时,最小交叉验证误差发生。

我们还可以使用summary函数显示函数调用、拟合树模型的复杂度参数表、变量重要性,这有助于识别对树分类最重要的变量(总和为 100),以及每个节点的详细信息。

使用决策树的优点在于它非常灵活且易于解释。它适用于分类和回归问题,以及更多;它是非参数的。因此,无需担心数据是否线性可分。至于使用决策树的缺点,它倾向于有偏差且过拟合。然而,你可以通过使用条件推断树来克服偏差问题,并通过随机森林方法或树剪枝来解决过拟合问题。

参见

  • 关于rpartprintcpsummary函数的更多信息,请使用help函数:

    > ?rpart
    > ?printcp
    > ?summary.rpart
    
    
  • C50是另一个提供决策树和基于规则的模型的包。如果你对这个包感兴趣,可以参考cran.r-project.org/web/packages/C50/C50.pdf文档。

可视化递归分割树

从最后一个配方中,我们学习了如何以文本格式打印分类树。为了使树更易于阅读,我们可以使用plot函数来获取已建分类树的图形显示。

准备工作

需要完成上一个配方,通过生成分类模型,并将模型分配给churn.rp变量。

如何做...

执行以下步骤以可视化分类树:

  1. 使用plot函数和text函数绘制分类树:

    > plot(churn.rp, margin= 0.1)
    > text(churn.rp, all=TRUE, use.n = TRUE)
    
    

    如何做...

    图 3:分类树的图形显示

  2. 你还可以指定uniformbranchmargin参数来调整布局:

    > plot(churn.rp, uniform=TRUE, branch=0.6, margin=0.1)
    > text(churn.rp, all=TRUE, use.n = TRUE)
    
    

    如何做...

    图 4:调整分类树的布局

它是如何工作的...

在这里,我们演示如何使用plot函数图形化显示分类树。plot函数可以简单地可视化分类树,然后你可以使用text函数向图中添加文本。

图 3中,我们将margin参数设置为 0.1,以在边界周围添加额外的空白,防止显示的文本被边界截断。它显示分支的长度表示偏差下降的相对幅度。然后我们使用文本函数为节点和分支添加标签。默认情况下,文本函数将在每个分割处添加一个分割条件,并在每个终端节点添加一个类别标签。为了在树图中添加更多信息,我们将参数设置为所有等于TRUE以添加所有节点的标签。此外,我们通过指定use.n = TRUE添加一个参数,以添加额外信息,这表明实际观测数分为两个不同的类别(是和否)。

图 4中,我们将分支选项设置为 0.6,为每个绘制的分支添加一个肩部。此外,为了显示等长的分支而不是偏差下降的相对幅度,我们将选项uniform设置为TRUE。因此,图 4显示了一个具有短肩部和等长分支的分类树。

参见

  • 您可以使用?plot.rpart来了解更多关于分类树绘制的相关信息。此文档还包括如何指定参数uniformbranchcompressnspacemarginminbranch以调整分类树布局的信息。

测量递归分割树的预测性能

由于我们在之前的配方中构建了一个分类树,我们可以用它来预测新观测的类别(类别标签)。在做出预测之前,我们首先验证分类树的预测能力,这可以通过在测试数据集上生成分类表来完成。在本配方中,我们将介绍如何使用predict函数和table函数生成预测标签与真实标签表,并解释如何生成混淆矩阵以衡量性能。

准备工作

您需要完成之前的配方,生成分类模型churn.rp。此外,您还需要准备训练数据集trainset和测试数据集testset,这些数据集是在本章第一节的第一个配方中生成的。

如何操作...

执行以下步骤以验证分类树的预测性能:

  1. 您可以使用predict函数为测试数据集生成预测标签:

    > predictions = predict(churn.rp, testset, type="class")
    
    
  2. 使用table函数为测试数据集生成分类表:

    > table(testset$churn, predictions)
     predictions
     yes  no
     yes 100  41
     no   18 859
    
    
  3. 可以进一步使用caret包中提供的confusionMatrix函数生成混淆矩阵:

    > library(caret)
    > confusionMatrix(table(predictions, testset$churn))
    Confusion Matrix and Statistics
    
    predictions yes  no
     yes 100  18
     no   41 859
    
     Accuracy : 0.942 
     95% CI : (0.9259, 0.9556)
     No Information Rate : 0.8615 
     P-Value [Acc > NIR] : < 2.2e-16 
    
     Kappa : 0.7393 
     Mcnemar's Test P-Value : 0.004181 
    
     Sensitivity : 0.70922 
     Specificity : 0.97948 
     Pos Pred Value : 0.84746 
     Neg Pred Value : 0.95444 
     Prevalence : 0.13851 
     Detection Rate : 0.09823 
     Detection Prevalence : 0.11591 
     Balanced Accuracy : 0.84435 
    
     'Positive' Class : yes 
    
    

工作原理...

在这个菜谱中,我们使用 predict 函数和构建的分类模型 churn.rp 来预测测试数据集 testset 的可能类别标签。预测的类别(类别标签)编码为是或否。然后,我们使用 table 函数在测试数据集上生成一个分类表。从表中,我们发现 859 个被正确预测为否,而 18 个被错误分类为是。100 个是的预测被正确预测,但有 41 个观测值被错误分类为否。进一步,我们使用来自 caret 包的 confusionMatrix 函数来产生分类模型的测量值。

相关内容

  • 你可以使用 ?confusionMatrix 了解更多关于使用混淆矩阵进行性能测量的信息

  • 对于那些对混淆矩阵定义输出感兴趣的人,请参阅维基百科条目,混淆矩阵 (en.wikipedia.org/wiki/Confusion_matrix)

修剪递归分割树

在之前的菜谱中,我们已经为 churn 数据集构建了一个复杂的决策树。然而,有时我们必须移除在分类实例中不起作用的部分,以避免过拟合,并提高预测精度。因此,在这个菜谱中,我们介绍了成本复杂度修剪方法来修剪分类树。

准备工作

你需要完成之前的菜谱,生成一个分类模型,并将模型分配给 churn.rp 变量。

如何做...

执行以下步骤来修剪分类树:

  1. 找到分类树模型的最低交叉验证误差:

    > min(churn.rp$cptable[,"xerror"])
    [1] 0.4707602
    
    
  2. 定位具有最低交叉验证误差的记录:

    > which.min(churn.rp$cptable[,"xerror"])
    7 
    
    
  3. 获取具有最低交叉验证误差的记录的成本复杂度参数:

    > churn.cp = churn.rp$cptable[7,"CP"]
    > churn.cp
    [1] 0.01754386
    
    
  4. 通过将 cp 参数设置为具有最低交叉验证误差的记录的 CP 值来修剪树:

    > prune.tree = prune(churn.rp, cp= churn.cp)
    
    
  5. 使用 plottext 函数可视化分类树:

    > plot(prune.tree, margin= 0.1)
    > text(prune.tree, all=TRUE , use.n=TRUE)
    
    

    如何做...

    图 5:修剪后的分类树

  6. 接下来,你可以根据修剪后的分类树模型生成一个分类表:

    > predictions = predict(prune.tree, testset, type="class")
    > table(testset$churn, predictions)
     predictions
     yes  no
     yes  95  46
     no   14 863
    
    
  7. 最后,你可以根据分类表生成一个混淆矩阵:

    > confusionMatrix(table(predictions, testset$churn))
    Confusion Matrix and Statistics
    
    predictions yes  no
     yes  95  14
     no   46 863
    
     Accuracy : 0.9411 
     95% CI : (0.9248, 0.9547)
     No Information Rate : 0.8615 
     P-Value [Acc > NIR] : 2.786e-16 
    
     Kappa : 0.727 
     Mcnemar's Test P-Value : 6.279e-05 
    
     Sensitivity : 0.67376 
     Specificity : 0.98404 
     Pos Pred Value : 0.87156 
     Neg Pred Value : 0.94939 
     Prevalence : 0.13851 
     Detection Rate : 0.09332 
     Detection Prevalence : 0.10707 
     Balanced Accuracy : 0.82890 
    
     'Positive' Class : yes 
    
    

它是如何工作的...

在本食谱中,我们讨论了剪枝分类树以避免过拟合并产生更健壮的分类模型。我们首先在cptable中找到具有最小交叉验证错误的记录,然后提取该记录的 CP 并将其值分配给churn.cp。接下来,我们使用prune函数以churn.cp作为参数剪枝分类树。然后,通过使用plot函数,我们图形化地显示了剪枝后的分类树。从图 5中可以看出,树的分割小于原始分类树(图 3)。最后,我们生成了一个分类表,并使用混淆矩阵来验证剪枝树的性能。结果显示,准确率(0.9411)略低于原始模型(0.942),同时也表明剪枝树可能不如原始分类树表现好,因为我们已经剪掉了一些分割条件(尽管如此,人们应该检查敏感性和特异性的变化)。然而,剪枝后的树模型更健壮,因为它去除了可能导致过拟合的一些分割条件。

相关内容

使用条件推理树构建分类模型

除了传统的决策树(rpart)之外,条件推理树(ctree)是另一种流行的基于树的分类方法。与传统决策树类似,条件推理树也通过对因变量进行单变量分割来递归地分割数据。然而,使条件推理树与传统决策树不同的地方在于,条件推理树将显著性检验程序适应于选择变量,而不是通过最大化信息度量(rpart使用基尼系数)来选择变量。在本食谱中,我们将介绍如何适应条件推理树以构建分类模型。

准备工作

您需要完成第一个步骤,通过生成训练数据集trainset和测试数据集testset

如何操作...

执行以下步骤以构建条件推理树:

  1. 首先,我们使用party包中的ctree构建分类模型:

    > library(party)
    > ctree.model = ctree(churn ~ . , data = trainset)
    
    
  2. 然后,我们检查构建的树模型:

    > ctree.model
    
    

它是如何工作的...

在这个菜谱中,我们使用条件推理树构建了一个分类树。ctree的使用与rpart类似。因此,在面临分类问题时,你可以轻松地使用传统的决策树或条件推理树来测试分类能力。接下来,我们通过检查构建的模型来获取分类树的节点细节。在模型中,我们发现ctree提供的信息类似于分割条件、标准(1 – p 值)、统计(测试统计量)和权重(与节点对应的案例权重)。然而,它提供的信息不如rpart通过使用summary函数提供的信息多。

参见

  • 你可以使用help函数查阅二叉树类的定义,并了解更多关于二叉树属性的信息:

     > help("BinaryTree-class")
    
    

可视化条件推理树

rpart类似,party包也为用户提供了一种可视化条件推理树的方法。在下面的菜谱中,我们将介绍如何使用plot函数来可视化条件推理树。

准备工作

你需要完成第一个菜谱,生成条件推理树模型ctree.model。此外,你还需要在 R 会话中加载trainsettestset

如何做...

执行以下步骤以可视化条件推理树:

  1. 使用plot函数绘制在上一菜谱中构建的ctree.model

    > plot(ctree.model)
    
    

    如何做...

    图 6:客户流失数据的条件推理树

  2. 要获得一个简单的条件推理树,可以通过减少输入特征来简化构建的模型,并重新绘制分类树:

    > daycharge.model = ctree(churn ~ total_day_charge, data = trainset)
    > plot(daycharge.model)
    
    

    如何做...

    图 7:使用 total_day_charge 变量作为唯一分割条件的条件推理树

工作原理...

要可视化条件推理树的节点细节,我们可以对构建的分类模型应用plot函数。输出图显示,每个中间节点都显示了因变量名称和 p 值。分割条件显示在左右分支上。终端节点显示了分类观察数的数量,n,以及类别标签为 0 或 1 的概率。

图 7为例,我们首先使用total_day_charge作为唯一特征,churn作为类别标签构建一个分类模型。构建的分类树显示,当total_day_charge超过 48.18 时,节点 9 中较浅的灰色区域大于较深的灰色区域,这表明日收费超过 48.18 的客户更有可能流失(标签=是)。

参见

  • 条件推理树的可视化来自plot.BinaryTree函数。如果你对调整分类树的布局感兴趣,可以使用help函数阅读以下文档:

    > ?plot.BinaryTree
    
    

测量条件推理树的预测性能

在构建条件推理树作为分类模型之后,我们可以使用treeresponsepredict函数来预测测试数据集testset的类别,并进一步通过分类表和混淆矩阵验证预测能力。

准备工作

您需要完成上一个菜谱,生成条件推理树模型ctree.model。此外,您还需要在 R 会话中加载trainsettestset

如何操作...

执行以下步骤以测量条件推理树的预测性能:

  1. 您可以使用predict函数来预测测试数据集testset的类别:

    > ctree.predict = predict(ctree.model ,testset)
    > table(ctree.predict, testset$churn)
    
    ctree.predict yes  no
     yes  99  15
     no   42 862
    
    
  2. 此外,您可以使用来自 caret 包的confusionMatrix函数来生成预测结果的性能度量:

    > confusionMatrix(table(ctree.predict, testset$churn))
    Confusion Matrix and Statistics
    
    ctree.predict yes  no
     yes  99  15
     no   42 862
    
     Accuracy : 0.944 
     95% CI : (0.9281, 0.9573)
     No Information Rate : 0.8615 
     P-Value [Acc > NIR] : < 2.2e-16 
    
     Kappa : 0.7449 
     Mcnemar's Test P-Value : 0.0005736 
    
     Sensitivity : 0.70213 
     Specificity : 0.98290 
     Pos Pred Value : 0.86842 
     Neg Pred Value : 0.95354 
     Prevalence : 0.13851 
     Detection Rate : 0.09725 
     Detection Prevalence : 0.11198 
     Balanced Accuracy : 0.84251 
    
     'Positive' Class : yes 
    
    
  3. 您还可以使用treeresponse函数,它将告诉您类概率列表:

    > tr = treeresponse(ctree.model, newdata = testset[1:5,])
    > tr
    [[1]]
    [1] 0.03497409 0.96502591
    
    [[2]]
    [1] 0.02586207 0.97413793
    
    [[3]]
    [1] 0.02586207 0.97413793
    
    [[4]]
    [1] 0.02586207 0.97413793
    
    [[5]]
    [1] 0.03497409 0.96502591
    
    

工作原理...

在本菜谱中,我们首先演示了如何使用prediction函数预测测试数据集testset的类别(类标签),然后使用table函数生成分类表。接下来,您可以使用内置在 caret 包中的confusionMatrix函数来确定性能度量。

除了predict函数外,treeresponse还可以估计类概率,这通常会将具有更高概率的标签分类。在本例中,我们演示了如何使用测试数据集testset的前五条记录来获取估计的类概率。treeresponse函数返回一个包含五个概率的列表。您可以使用该列表来确定实例的标签。

相关内容

  • 对于predict函数,您可以指定类型为responseprobnode。如果您在调用predict函数时指定类型为prob(例如,predict(… type="prob")),您将得到与treeresponse返回的完全相同的结果。

使用 k 近邻分类器对数据进行分类

K 近邻knn)是一种非参数的懒惰学习方法。从非参数的角度来看,它不对数据分布做出任何假设。在懒惰学习方面,它不需要一个显式的学习阶段来进行泛化。以下菜谱将介绍如何在流失数据集上应用 k 近邻算法。

准备工作

您需要完成上一个菜谱,生成训练和测试数据集。

如何操作...

执行以下步骤,使用 k 近邻算法对流失数据进行分类:

  1. 首先,必须安装class包并在 R 会话中加载它:

    > install.packages("class")
    > library(class)
    
    
  2. 将训练数据集和测试数据集中voice_mail_planinternational_plan属性的yesno替换为 1 和 0:

    > levels(trainset$international_plan) = list("0"="no", "1"="yes")
    > levels(trainset$voice_mail_plan) = list("0"="no", "1"="yes")
    > levels(testset$international_plan) = list("0"="no", "1"="yes")
    > levels(testset$voice_mail_plan) = list("0"="no", "1"="yes")
    
    
  3. 在训练数据集和测试数据集上使用 knn 分类方法:

    > churn.knn  = knn(trainset[,! names(trainset) %in% c("churn")], testset[,! names(testset) %in% c("churn")], trainset$churn, k=3)
    
    
  4. 然后,你可以使用 summary 函数检索预测标签的数量:

    > summary(churn.knn)
    yes  no
     77 941
    
    
  5. 接下来,你可以使用 table 函数生成分类矩阵:

    > table(testset$churn, churn.knn)
     churn.knn
     yes  no
     yes  44  97
     no   33 844
    
    
  6. 最后,你可以使用 confusionMatrix 函数生成混淆矩阵:

    > confusionMatrix(table(testset$churn, churn.knn))
    Confusion Matrix and Statistics
    
     churn.knn
     yes  no
     yes  44  97
     no   33 844
    
     Accuracy : 0.8723 
     95% CI : (0.8502, 0.8922)
     No Information Rate : 0.9244 
     P-Value [Acc > NIR] : 1 
    
     Kappa : 0.339 
     Mcnemar's Test P-Value : 3.286e-08 
    
     Sensitivity : 0.57143 
     Specificity : 0.89692 
     Pos Pred Value : 0.31206 
     Neg Pred Value : 0.96237 
     Prevalence : 0.07564 
     Detection Rate : 0.04322 
     Detection Prevalence : 0.13851 
     Balanced Accuracy : 0.73417 
    
     'Positive' Class : yes 
    
    

如何工作...

knn 通过训练所有样本并根据相似性(距离)度量对新实例进行分类。例如,相似性度量可以表示如下:

  • 欧几里得距离: 如何工作...

  • 曼哈顿距离: 如何工作...

在 knn 中,一个新的实例被分类到一个标签(类别),这个标签在 k 个最近邻中是共同的。如果 k = 1,那么新的实例将被分配到其最近邻所属的类别。算法的唯一输入是 k。如果我们给出小的 k 输入,可能会导致过拟合。另一方面,如果我们给出大的 k 输入,可能会导致欠拟合。为了选择合适的 k 值,可以依靠交叉验证。

knn 的优点是:

  • 学习过程没有成本

  • 它是非参数的,这意味着你不需要对数据分布做出假设。

  • 当你能找到给定实例的相似性度量时,你可以对任何数据进行分类

knn 的主要缺点是:

  • 解释分类结果很困难。

  • 对于大数据集来说,这是一个昂贵的计算。

  • 性能依赖于维数的数量。因此,对于高维问题,你应该首先降低维度以提高处理性能。

knn 的使用与之前菜谱中提到的基于树的算法应用没有显著差异。然而,虽然基于树的算法可能会展示决策树模型,但 knn 生成的输出仅揭示分类类别因素。然而,在构建分类模型之前,应该将属性从字符串类型替换为整数,因为 k 近邻算法需要计算观测之间的距离。然后,我们通过指定 k=3 来构建分类模型,这意味着选择最近的三个邻居。在分类模型构建完成后,我们可以使用预测因素和测试数据集标签作为输入生成分类表。最后,我们可以从分类表中生成混淆矩阵。混淆矩阵的输出显示准确率为 (0.8723),这表明之前菜谱中提到的基于树的算法在此情况下优于 k 近邻分类方法的准确率。尽管如此,我们无法仅根据准确率来确定哪个模型更好,还应该检查输出的特异性和敏感性。

参见

使用逻辑回归进行数据分类

逻辑回归是一种概率统计分类模型,可以用来根据一个或多个特征预测类别标签。分类是通过使用logit函数来估计结果概率来完成的。可以通过指定家族为二项式并使用glm函数来使用逻辑回归。在本菜谱中,我们将介绍如何使用逻辑回归进行数据分类。

准备工作

您需要完成第一个菜谱,通过生成训练集和测试集。

如何操作...

执行以下步骤以使用逻辑回归对流失数据进行分类:

  1. 在指定家族为二项式的情况下,我们通过使用glm函数对数据集trainset应用,以churn作为类别标签,其余变量作为输入特征:

    > fit = glm(churn ~ ., data = trainset, family=binomial)
    
    
  2. 使用summary函数来获取构建的逻辑回归模型的摘要信息:

    > summary(fit)
    
    Call:
    glm(formula = churn ~ ., family = binomial, data = trainset)
    
    Deviance Residuals: 
     Min       1Q   Median       3Q      Max 
    -3.1519   0.1983   0.3460   0.5186   2.1284 
    
    Coefficients:
     Estimate Std. Error z value Pr(>|z|)
    (Intercept)                    8.3462866  0.8364914   9.978  < 2e-16
    international_planyes         -2.0534243  0.1726694 -11.892  < 2e-16
    voice_mail_planyes             1.3445887  0.6618905   2.031 0.042211
    number_vmail_messages         -0.0155101  0.0209220  -0.741 0.458496
    total_day_minutes              0.2398946  3.9168466   0.061 0.951163
    total_day_calls               -0.0014003  0.0032769  -0.427 0.669141
    total_day_charge              -1.4855284 23.0402950  -0.064 0.948592
    total_eve_minutes              0.3600678  1.9349825   0.186 0.852379
    total_eve_calls               -0.0028484  0.0033061  -0.862 0.388928
    total_eve_charge              -4.3204432 22.7644698  -0.190 0.849475
    total_night_minutes            0.4431210  1.0478105   0.423 0.672367
    total_night_calls              0.0003978  0.0033188   0.120 0.904588
    total_night_charge            -9.9162795 23.2836376  -0.426 0.670188
    total_intl_minutes             0.4587114  6.3524560   0.072 0.942435
    total_intl_calls               0.1065264  0.0304318   3.500 0.000464
    total_intl_charge             -2.0803428 23.5262100  -0.088 0.929538
    number_customer_service_calls -0.5109077  0.0476289 -10.727  < 2e-16
    
    (Intercept)                   ***
    international_planyes         ***
    voice_mail_planyes            * 
    number_vmail_messages 
    total_day_minutes 
    total_day_calls 
    total_day_charge 
    total_eve_minutes 
    total_eve_calls 
    total_eve_charge 
    total_night_minutes 
    total_night_calls 
    total_night_charge 
    total_intl_minutes 
    total_intl_calls              ***
    total_intl_charge 
    number_customer_service_calls ***
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    (Dispersion parameter for binomial family taken to be 1)
    
     Null deviance: 1938.8  on 2314  degrees of freedom
    Residual deviance: 1515.3  on 2298  degrees of freedom
    AIC: 1549.3
    
    Number of Fisher Scoring iterations: 6
    
    
  3. 然后,我们发现构建的模型包含不显著的变量,这可能导致误分类。因此,我们只使用显著变量来训练分类模型:

    > fit = glm(churn ~ international_plan + voice_mail_plan+total_intl_calls+number_customer_service_calls, data = trainset, family=binomial)
    > summary(fit)
    
    Call:
    glm(formula = churn ~ international_plan + voice_mail_plan + 
     total_intl_calls + number_customer_service_calls, family = binomial, 
     data = trainset)
    
    Deviance Residuals: 
     Min       1Q   Median       3Q      Max 
    -2.7308   0.3103   0.4196   0.5381   1.6716 
    
    Coefficients:
     Estimate Std. Error z value
    (Intercept)                    2.32304    0.16770  13.852
    international_planyes         -2.00346    0.16096 -12.447
    voice_mail_planyes             0.79228    0.16380   4.837
    total_intl_calls               0.08414    0.02862   2.939
    number_customer_service_calls -0.44227    0.04451  -9.937
     Pr(>|z|) 
    (Intercept)                    < 2e-16 ***
    international_planyes          < 2e-16 ***
    voice_mail_planyes            1.32e-06 ***
    total_intl_calls               0.00329 ** 
    number_customer_service_calls  < 2e-16 ***
    ---
    Signif. codes: 
    0  es:    des:  **rvice_calls  < '.  es:    de
    
    (Dispersion parameter for binomial family taken to be 1)
    
     Null deviance: 1938.8  on 2314  degrees of freedom
    Residual deviance: 1669.4  on 2310  degrees of freedom
    AIC: 1679.4
    
    Number of Fisher Scoring iterations: 5
    
    
  4. 然后,您可以使用拟合模型fit来预测testset的结果。您也可以通过判断概率是否高于 0.5 来确定类别:

    > pred = predict(fit,testset, type="response")
    > Class = pred >.5
    
    
  5. 接下来,使用summary函数将显示二元结果计数,并揭示概率是否高于 0.5:

    > summary(Class)
     Mode   FALSE    TRUE    NA's 
    logical      29     989       0 
    
    
  6. 您可以根据测试数据集的标签和预测结果生成计数统计信息:

    > tb = table(testset$churn,Class)
    > tb
     Class
     FALSE TRUE
     yes    18  123
     no     11  866
    
    
  7. 您可以将上一步的统计信息转换为分类表,然后生成混淆矩阵:

    > churn.mod = ifelse(testset$churn == "yes", 1, 0)
    > pred_class = churn.mod
    > pred_class[pred<=.5] = 1- pred_class[pred<=.5]
    > ctb = table(churn.mod, pred_class)
    > ctb
     pred_class
    churn.mod   0   1
     0 866  11
     1  18 123
    > confusionMatrix(ctb)
    Confusion Matrix and Statistics
    
     pred_class
    churn.mod   0   1
     0 866  11
     1  18 123
    
     Accuracy : 0.9715 
     95% CI : (0.9593, 0.9808)
     No Information Rate : 0.8684 
     P-Value [Acc > NIR] : <2e-16 
    
     Kappa : 0.8781 
     Mcnemar's Test P-Value : 0.2652 
    
     Sensitivity : 0.9796 
     Specificity : 0.9179 
     Pos Pred Value : 0.9875 
     Neg Pred Value : 0.8723 
     Prevalence : 0.8684 
     Detection Rate : 0.8507 
     Detection Prevalence : 0.8615 
     Balanced Accuracy : 0.9488 
    
     'Positive' Class : 0 
    
    

它是如何工作的...

逻辑回归与线性回归非常相似;主要区别在于线性回归中的因变量是连续的,而逻辑回归中的因变量是二元的(或名义的)。逻辑回归的主要目标是使用 logit 来得出名义变量与测量变量相关的概率。我们可以用以下方程表示 logit:ln(P/(1-P)),其中 P 是某个事件发生的概率。

逻辑回归的优势在于它易于解释,它指导模型逻辑概率,并为结果提供置信区间。与难以更新模型的决策树不同,您可以在逻辑回归中快速更新分类模型以包含新数据。该算法的主要缺点是它受到多重共线性问题的影响,因此解释变量必须是线性独立的。glm 提供了一个广义线性回归模型,允许在选项中指定模型。如果将家族指定为二项逻辑,则可以将家族设置为二项以对分类因变量进行分类。

分类过程从使用训练数据集生成逻辑回归模型开始,指定 Churn 作为类标签,其他变量作为训练特征,并将家族设置为二项。然后我们使用 summary 函数生成模型的摘要信息。从摘要信息中,我们可能会发现一些不显著的变量(p 值 > 0.05),这可能导致误分类。因此,我们应该只考虑显著变量来构建模型。

接下来,我们使用 fit 函数来预测测试数据集 testset 的分类因变量。fit 函数输出一个类标签的概率,结果等于或低于 0.5 表示预测的标签与测试数据集的标签不匹配,而概率高于 0.5 则表示预测的标签与测试数据集的标签匹配。此外,我们可以使用 summary 函数来获取预测标签是否与测试数据集标签匹配的统计信息。最后,为了生成混淆矩阵,我们首先生成一个分类表,然后使用 confusionMatrix 生成性能度量。

参见

  • 有关如何使用 glm 函数的更多信息,请参阅第四章,理解回归分析,其中涵盖了如何解释 glm 函数的输出。

使用 Naïve Bayes 分类器进行数据分类

Naïve Bayes 分类器也是一种基于概率的分类器,它基于应用贝叶斯定理并假设强独立性。在本食谱中,我们将介绍如何使用 Naïve Bayes 分类器对数据进行分类。

准备工作

您需要完成第一个食谱,生成训练和测试数据集。

如何操作...

使用 Naïve Bayes 分类器对流失数据进行分类的以下步骤:

  1. 加载 e1071 库并使用 naiveBayes 函数构建分类器:

    > library(e1071) 
    > classifier=naiveBayes(trainset[, !names(trainset) %in% c("churn")], trainset$churn)
    
    
  2. 输入 classifier 以检查函数调用、先验概率和条件概率:

    > classifier
    
    Naive Bayes Classifier for Discrete Predictors
    
    Call:
    naiveBayes.default(x = trainset[, !names(trainset) %in% c("churn")], 
     y = trainset$churn)
    
    A-priori probabilities:
    trainset$churn
     yes        no 
    0.1477322 0.8522678 
    
    Conditional probabilities:
     international_plan
    trainset$churn         no        yes
     yes 0.70467836 0.29532164
     no  0.93512418 0.06487582
    
    
  3. 接下来,您可以生成测试数据集的分类表:

    > bayes.table = table(predict(classifier, testset[, !names(testset) %in% c("churn")]), testset$churn)
    > bayes.table
    
     yes  no
     yes  68  45
     no   73 832
    
    
  4. 最后,你可以从分类表中生成混淆矩阵:

    > confusionMatrix(bayes.table)
    Confusion Matrix and Statistics
    
     yes  no
     yes  68  45
     no   73 832
    
     Accuracy : 0.8841 
     95% CI : (0.8628, 0.9031)
     No Information Rate : 0.8615 
     P-Value [Acc > NIR] : 0.01880 
    
     Kappa : 0.4701 
     Mcnemar's Test P-Value : 0.01294 
    
     Sensitivity : 0.4823 
     Specificity : 0.9487 
     Pos Pred Value : 0.6018 
     Neg Pred Value : 0.9193 
     Prevalence : 0.1385 
     Detection Rate : 0.0668 
     Detection Prevalence : 0.1110 
     Balanced Accuracy : 0.7155 
    
     'Positive' Class : yes 
    
    

如何工作...

朴素贝叶斯假设特征在条件上是独立的,即预测变量(x)对类别(c)的影响独立于其他预测变量对类别(c)的影响。它计算后验概率 P(c|x),如下公式所示:

如何工作...

其中 P(x|c) 被称为似然,p(x) 被称为边缘似然,p(c) 被称为先验概率。如果有许多预测变量,我们可以将后验概率如下公式化:

如何工作...

朴素贝叶斯的优势在于它相对简单且易于使用。当训练集相对较小,可能包含一些噪声和缺失数据时,它很适用。此外,你可以轻松地获得预测的概率。朴素贝叶斯的缺点在于它假设所有特征都是独立的且同等重要,这在现实世界中是非常不可能的。

在这个配方中,我们使用来自 e1071 包的朴素贝叶斯分类器来构建分类模型。首先,我们将所有变量(不包括 churn 类标签)指定为第一个输入参数,并将 churn 类标签指定为 naiveBayes 函数调用中的第二个参数。然后,我们将分类模型分配给变量分类器。接下来,我们打印变量分类器以获取信息,例如函数调用、先验概率和条件概率。我们还可以使用 predict 函数获取预测结果,以及使用 table 函数检索测试数据集的分类表。最后,我们使用混淆矩阵来计算分类模型的性能度量。

最后,我们列出本章中提到的所有算法的比较表:

算法 优点 缺点
递归分割树
  • 非常灵活且易于解释

  • 适用于分类和回归问题

  • 非参数

|

  • 容易产生偏差和过拟合

|

条件推断树
  • 非常灵活且易于解释

  • 适用于分类和回归问题

  • 非参数

  • 比递归分割树更不容易产生偏差

|

  • 容易过拟合

|

K 最近邻分类器
  • 学习过程成本为零

  • 非参数方法

  • 当你能找到任何给定实例的相似度度量时,你可以对任何数据进行分类

|

  • 分类结果难以解释

  • 对于大数据集,计算成本高昂

  • 性能依赖于维度数量

|

逻辑回归
  • 易于解释

  • 提供模型逻辑概率

  • 提供置信区间

  • 你可以快速更新分类模型以包含新数据

|

  • 患有多重共线性

  • 无法处理连续变量的缺失值

  • 对连续变量的极端值敏感

|

朴素贝叶斯
  • 相对简单直观易用

  • 当训练集相对较小时适用

  • 可以处理一些噪声和缺失数据

  • 可以轻松获得预测的概率

|

  • 假设所有特征都是独立且同等重要的,这在现实世界中是非常不可能的

  • 当训练集数量增加时,容易出现偏差

|

参见

第六章. 分类(II)- 神经网络和 SVM

在本章中,我们将涵盖以下食谱:

  • 使用支持向量机对数据进行分类

  • 选择支持向量机的成本

  • 可视化支持向量机拟合

  • 基于由支持向量机训练的模型预测标签

  • 调整支持向量机

  • 使用 neuralnet 训练神经网络

  • 可视化由 neuralnet 训练的神经网络

  • 基于由 neuralnet 训练的模型预测标签

  • 使用 nnet 训练神经网络

  • 基于由 nnet 训练的模型预测标签

简介

大多数研究表明,支持向量机SVM)和神经网络NN)是强大的分类工具,可以应用于多个不同领域。与上一章中提到的基于树或基于概率的方法不同,支持向量机和神经网络从输入到输出的转换过程不太清晰,可能难以解释。因此,支持向量机和神经网络都被称为黑盒方法。

神经网络的发展灵感来源于人类大脑活动。因此,这类网络是一种模仿人类心智模式的计算模型。相比之下,支持向量机首先将输入数据映射到由核函数定义的高维特征空间,并找到通过最大间隔分离训练数据的最佳超平面。简而言之,我们可以将支持向量机视为高维空间中的线性算法。

这两种方法在解决分类问题时都有优点和缺点。例如,支持向量机解决方案是全局最优解,而神经网络可能会遭受多个局部最优解。因此,选择哪种方法取决于数据源的特征。在本章中,我们将说明以下内容:

  • 如何训练支持向量机

  • 观察成本选择如何影响支持向量机分类器

  • 可视化支持向量机拟合

  • 基于由 SVM 训练的模型预测测试数据集的标签

  • 调整 SVM

在神经网络部分,我们将涵盖以下内容:

  • 如何训练神经网络

  • 如何可视化神经网络模型

  • 基于由neuralnet训练的模型预测测试数据集的标签

  • 最后,我们将展示如何使用nnet训练神经网络,以及如何使用它来预测测试数据集的标签

使用支持向量机对数据进行分类

最知名且最受欢迎的支持向量机工具是libsvmSVMLite。对于 R 语言用户,你可以在e1071包中找到libsvm的实现,在klaR包中找到SVMLite。因此,你可以使用这两个包中实现的功能来训练支持向量机。在本例中,我们将重点关注使用来自e1071包的svm函数(libsvm实现版本)来训练基于电信客户流失数据训练数据集的支持向量机。

准备工作

在本例中,我们将继续使用电信客户流失数据集作为输入数据源来训练支持向量机。对于那些尚未准备数据集的用户,请参阅第五章,分类(I)-树、懒惰和概率性,以获取详细信息。

如何操作...

执行以下步骤来训练 SVM:

  1. 加载e1071包:

    > library(e1071)
    
    
  2. 使用svm函数并通过trainset作为输入数据集来训练支持向量机,并使用churn作为分类类别:

    > model  = svm(churn~., data = trainset, kernel="radial", cost=1, gamma = 1/ncol(trainset))
    
    
  3. 最后,你可以使用summary函数获取关于构建的模型的整体信息:

    > summary(model)
    
    Call:
    svm(formula = churn ~ ., data = trainset, kernel = "radial", cost = 1, gamma = 1/ncol(trainset))
    
    Parameters:
     SVM-Type:  C-classification 
     SVM-Kernel:  radial 
     cost:  1 
     gamma:  0.05882353 
    
    Number of Support Vectors:  691
    
     ( 394 297 )
    
    Number of Classes:  2 
    
    Levels: 
     yes no
    
    

它是如何工作的...

支持向量机构建一个超平面(或一组超平面),在多维空间中最大化两个类别之间的边缘宽度。在这些情况下,定义超平面的点是支持向量,如图所示:

它是如何工作的...

图 1:支持向量机

支持向量机从构建一个最大化边缘宽度的超平面开始。然后,它将定义扩展到非线性可分问题。最后,它将数据映射到一个高维空间,在那里数据可以更容易地用线性边界分离。

使用 SVM 的优势在于它通过一个面向工程问题的核函数构建了一个高度准确模型。此外,它利用正则化项来避免过拟合。它也不受局部最优和多重共线性影响。SVM 的主要局限性在于其训练和测试过程中的速度和大小。因此,它不适合或效率不足以构建大型数据集的分类模型。此外,由于 SVM 难以解释,核函数的确定是如何进行的?正则化是我们需要解决的问题之一。

在本菜谱中,我们继续使用电信 churn 数据集作为我们的示例数据源。我们开始使用 e1071 软件包中提供的 libsvm 训练支持向量机。在训练函数 svm 中,可以指定 kernel 函数、成本和 gamma 函数。对于 kernel 参数,默认值是径向的,可以将核指定为线性、多项式、径向基和 sigmoid。至于 gamma 参数,默认值等于(1/数据维度),它控制分离超平面的形状。增加 gamma 参数通常会增加支持向量的数量。

关于成本,默认值设置为 1,这表示正则化项是常数,值越大,边界越小。我们将在下一菜谱中进一步讨论成本如何影响 SVM 分类器。一旦构建了支持向量机,可以使用 summary 函数获取信息,例如调用次数、参数、类别数量和标签类型。

参见

另一个流行的支持向量机工具是 SVMLight。与提供 libsvm 完整实现的 e1071 软件包不同,klaR 软件包仅提供对 SVMLight 的接口。要使用 SVMLight,可以执行以下步骤:

  1. 安装 klaR 软件包:

    > install.packages("klaR")
    > library(klaR)
    
    
  2. svmlight.joachims.org/ 下载您平台上的 SVMLight 源代码和二进制文件。例如,如果您的虚拟操作系统是 Windows 64 位,您应该从 download.joachims.org/svm_light/current/svm_light_windows64.zip 下载文件。

  3. 然后,您应该解压文件并将可工作的二进制文件放入工作目录;您可以使用 getwd 函数检查您的工作目录:

    > getwd()
    
    
  4. 使用 svmlight 函数训练支持向量机:

    > model.light  = svmlight(churn~., data = trainset, kernel="radial", cost=1, gamma = 1/ncol(trainset))
    
    

选择支持向量机的成本

支持向量机通过最大边界创建一个最优的超平面来分离训练数据。然而,有时我们希望在分离类别时允许一些误分类。SVM 模型有一个成本函数,它控制训练错误和边界。例如,小的成本创建大的边界(软边界)并允许更多的误分类。另一方面,大的成本创建窄的边界(硬边界)并允许较少的误分类。在本菜谱中,我们将说明大成本和小成本如何影响 SVM 分类器。

准备工作

在本菜谱中,我们将使用 iris 数据集作为我们的示例数据源。

如何操作...

执行以下步骤以生成两个具有不同成本的不同的分类示例:

  1. 使用列名为 Sepal.LengthSepal.WidthSpeciesiris 数据集子集,其中物种为 setosavirginica

    > iris.subset = subset(iris, select=c("Sepal.Length", "Sepal.Width", "Species"), Species %in% c("setosa","virginica"))
    
    
  2. 然后,你可以生成一个散点图,其中Sepal.Length作为 x 轴,Sepal.Width作为 y 轴:

    > plot(x=iris.subset$Sepal.Length,y=iris.subset$Sepal.Width, col=iris.subset$Species, pch=19)
    
    

    如何操作...

    图 2:鸢尾花数据集子集的Sepal.LengthSepal.Width的散点图

  3. 接下来,你可以使用iris.subset训练成本为 1 的 SVM:

    > svm.model = svm(Species ~ ., data=iris.subset, kernel='linear', cost=1, scale=FALSE)
    
    
  4. 然后,我们可以用蓝色圆圈圈出支持向量:

    > points(iris.subset[svm.model$index,c(1,2)],col="blue",cex=2)
    
    

    如何操作...

    图 3:用蓝色圆圈圈出支持向量

  5. 最后,我们可以在图上添加分离线:

    > w = t(svm.model$coefs) %*% svm.model$SV
    > b = -svm.model$rho
    > abline(a=-b/w[1,2], b=-w[1,1]/w[1,2], col="red", lty=5)
    
    

    如何操作...

    图 4:在散点图上添加分离线

  6. 此外,我们创建另一个成本为10,000的 SVM 分类器:

    > plot(x=iris.subset$Sepal.Length,y=iris.subset$Sepal.Width, col=iris.subset$Species, pch=19)
    > svm.model = svm(Species ~ ., data=iris.subset, type='C-classification', kernel='linear', cost=10000, scale=FALSE)
    > points(iris.subset[svm.model$index,c(1,2)],col="blue",cex=2)
    > w = t(svm.model$coefs) %*% svm.model$SV
    > b = -svm.model$rho
    > abline(a=-b/w[1,2], b=-w[1,1]/w[1,2], col="red", lty=5)
    
    

    如何操作...

    图 5:大成本分类示例

工作原理...

在这个菜谱中,我们展示了不同的成本如何影响 SVM 分类器。首先,我们创建了一个包含物种setosavirginicaSepal.LengthSepal.WidthSpecies列的鸢尾花子集。然后,为了创建软边界并允许一些误分类,我们使用成本较小的 SVM(其中cost = 1)来训练支持向量机。接下来,我们用蓝色圆圈圈出支持向量并添加分离线。根据图 5,一个绿色点(virginica)由于成本选择较小而被误分类(被分类为setosa)到分离线的另一侧。

此外,我们还想确定大成本如何影响 SVM 分类器。因此,我们选择了一个大成本(其中cost = 10,000)。从图 5 中,我们可以看到创建的边界很窄(硬边界)且没有误分类案例。因此,这两个示例表明,不同成本的选择可能会影响创建的边界,并影响误分类的可能性。

参见

  • 允许误分类的软边界概念是由 Corinna Cortes 和 Vladimir N. Vapnik 在 1995 年以下论文中提出的:Cortes, C.,and Vapnik, V. (1995). 支持向量机. 机器学习,20(3),273-297。

可视化 SVM 拟合

为了可视化构建的模型,可以使用绘图函数首先生成数据输入和 SVM 拟合的散点图。在这个图中,支持向量和类别通过颜色符号突出显示。此外,还可以绘制类区域的填充轮廓图,以便从图中轻松识别误分类样本。

准备工作

在这个菜谱中,我们将使用两个数据集:iris数据集和电信churn数据集。对于电信churn数据集,需要完成之前的菜谱,通过训练 SVM 来训练支持向量机,并保存 SVM 拟合模型。

如何操作...

执行以下步骤以可视化 SVM 拟合对象:

  1. 使用基于鸢尾花数据集的 SVM 训练支持向量机,并使用plot函数可视化拟合的模型:

    > data(iris)
    > model.iris  = svm(Species~., iris)
    > plot(model.iris, iris, Petal.Width ~ Petal.Length, slice = list(Sepal.Width = 3, Sepal.Length = 4))
    
    

    如何操作...

    图 6:基于 iris 数据集训练的 SVM 分类图

  2. 使用plot函数,以total_day_minutestotal_intl_charge的维度可视化 SVM 拟合对象model

    > plot(model, trainset, total_day_minutes ~ total_intl_charge)
    
    

    如何操作...

    图 7:基于流失数据集训练的 SVM 分类图

工作原理...

在本配方中,我们展示了如何使用plot函数来可视化 SVM 拟合。在第一个图中,我们使用iris数据集训练了一个支持向量机。然后,我们使用plot函数来可视化拟合的 SVM。

在参数列表中,我们将拟合的模型指定为第一个参数,将数据集(这应该是用于构建模型的数据)作为第二个参数。第三个参数表示用于生成分类图的维度。默认情况下,plot函数只能根据两个维度(用于 x 轴和 y 轴)生成散点图。因此,我们选择变量Petal.LengthPetal.Width作为两个维度来生成散点图。

图 6中,我们发现Petal.Length被分配到 x 轴,Petal.Width被分配到 y 轴,带有XO符号的数据点散布在图上。在散点图中,X符号表示支持向量,O符号表示数据点。这两个符号可以通过配置svSymboldataSymbol选项来更改。支持向量和真实类别根据它们的标签(绿色代表 virginica,红色代表 versicolor,黑色代表 setosa)突出显示并着色。最后一个参数slice在存在多于两个变量时设置。因此,在这个例子中,我们使用额外的变量Sepal.widthSepal.length,通过分配常数34

接下来,我们采用相同的方法来绘制基于客户流失数据的 SVM 拟合。在这个例子中,我们使用total_day_minutestotal_intl_charge作为绘制散点图的两个维度。根据图 7,支持向量和红色、黑色数据点在图的中央区域紧密散布,没有简单的方法可以将它们分开。

参见

  • 还有其他参数,如fillgridsymbolPalette等,可以配置以改变图的布局。您可以使用help函数查看以下文档以获取更多信息:

    > ?svm.plot
    
    

基于支持向量机训练的模型预测标签

在前面的配方中,我们基于训练数据集训练了一个 SVM。训练过程通过最大间隔找到将训练数据分开的最优超平面。然后,我们可以利用 SVM 拟合来预测新观察值的标签(类别)。在本配方中,我们将演示如何使用predict函数根据 SVM 训练的模型预测值。

准备工作

你需要完成之前的菜谱,通过生成拟合 SVM,并将拟合模型保存在 model 中。

如何操作...

执行以下步骤以预测测试数据集的标签:

  1. 根据拟合的 SVM 和测试数据集的属性预测测试数据集的标签:

    > svm.pred = predict(model, testset[, !names(testset) %in% c("churn")])
    
    
  2. 然后,你可以使用table函数来生成一个包含测试数据集预测结果和标签的分类表:

    > svm.table=table(svm.pred, testset$churn)
    > svm.table
    
    svm.pred yes  no
     yes  70  12
     no   71 865
    
    
  3. 接下来,你可以使用classAgreement来计算与分类一致性相比的系数:

    > classAgreement(svm.table)
    $diag
    [1] 0.9184676
    
    $kappa
    [1] 0.5855903
    
    $rand
    [1] 0.850083
    
    $crand
    [1] 0.5260472
    
    
  4. 现在,你可以使用confusionMatrix来根据分类表衡量预测性能:

    > library(caret)
    > confusionMatrix(svm.table)
    Confusion Matrix and Statistics
    
    svm.pred yes  no
     yes  70  12
     no   71 865
    
     Accuracy : 0.9185 
     95% CI : (0.8999, 0.9345)
     No Information Rate : 0.8615 
     P-Value [Acc > NIR] : 1.251e-08 
    
     Kappa : 0.5856 
     Mcnemar's Test P-Value : 1.936e-10 
    
     Sensitivity : 0.49645 
     Specificity : 0.98632 
     Pos Pred Value : 0.85366 
     Neg Pred Value : 0.92415 
     Prevalence : 0.13851 
     Detection Rate : 0.06876 
     Detection Prevalence : 0.08055 
     Balanced Accuracy : 0.74139 
    
     'Positive' Class : yes 
    
    

它是如何工作的...

在这个菜谱中,我们首先使用predict函数获取测试数据集的预测标签。然后,我们使用table函数根据测试数据集的预测标签生成分类表。到目前为止,评估过程与上一章中提到的评估过程非常相似。

我们随后引入了一个新的函数,classAgreement,它计算了二维列联表中行和列之间的一致性系数。这些系数包括 diag、kappa、rand 和 crand。diag系数表示分类表主对角线上数据点的百分比,kappa指的是diag,它通过一个变化(随机一致性的概率)进行了校正,rand代表 Rand 指数,它衡量两个数据簇之间的相似性,而crand表示调整了元素随机分组机会的 Rand 指数。

最后,我们使用了caret包中的confusionMatrix来衡量分类模型的表现。准确率 0.9185 表明训练好的支持向量机可以正确分类大多数观测值。然而,准确率本身并不能很好地衡量一个分类模型。还应参考敏感性和特异性。

更多内容...

除了使用 SVM 来预测新观测值的类别外,你还可以使用 SVM 来预测连续值。换句话说,可以使用 SVM 进行回归分析。

在以下示例中,我们将展示如何基于指定为eps-regression类型的拟合 SVM 执行简单的回归预测:

执行以下步骤以使用 SVM 训练回归模型:

  1. 基于一个Quartet数据集训练支持向量机:

    > library(car)
    > data(Quartet)
    > model.regression = svm(Quartet$y1~Quartet$x,type="eps-regression")
    
    
  2. 使用predict函数获取预测结果:

    > predict.y = predict(model.regression, Quartet$x) 
    > predict.y
     1        2        3        4        5        6        7        8 
    8.196894 7.152946 8.807471 7.713099 8.533578 8.774046 6.186349 5.763689 
     9       10       11 
    8.726925 6.621373 5.882946 
    
    
  3. 在同一张图上绘制预测点为正方形,训练数据点为圆圈:

    > plot(Quartet$x, Quartet$y1, pch=19)
    > points(Quartet$x, predict.y, pch=15, col="red")
    
    

    更多内容...

    图 8:散点图包含预测数据点和训练数据点

调整支持向量机

除了使用不同的特征集和支持向量机中的kernel函数外,你可以调整配置在参数中的 gamma 和成本来调整其性能。测试不同 gamma 和成本组合值性能的一个可能方法是编写一个for循环来生成所有 gamma 和成本的组合,作为训练不同支持向量机的输入。幸运的是,SVM 提供了一个调整函数tune.svm,这使得调整变得容易得多。在这个配方中,我们将演示如何通过使用tune.svm来调整支持向量机。

准备工作

你需要完成之前的配方,准备一个训练数据集trainset

如何操作...

执行以下步骤来调整支持向量机:

  1. 首先,使用tune.svm调整支持向量机:

    > tuned = tune.svm(churn~., data = trainset, gamma = 10^(-6:-1), cost = 10^(1:2))
    
    
  2. 接下来,你可以使用summary函数获取调整结果:

    > summary(tuned)
    
    Parameter tuning of 'svm':
    
    - sampling method: 10-fold cross validation 
    
    - best parameters:
     gamma cost
     0.01  100
    
    - best performance: 0.08077885 
    
    - Detailed performance results:
     gamma cost      error dispersion
    1  1e-06   10 0.14774780 0.02399512
    2  1e-05   10 0.14774780 0.02399512
    3  1e-04   10 0.14774780 0.02399512
    4  1e-03   10 0.14774780 0.02399512
    5  1e-02   10 0.09245223 0.02046032
    6  1e-01   10 0.09202306 0.01938475
    7  1e-06  100 0.14774780 0.02399512
    8  1e-05  100 0.14774780 0.02399512
    9  1e-04  100 0.14774780 0.02399512
    10 1e-03  100 0.11794484 0.02368343
    11 1e-02  100 0.08077885 0.01858195
    12 1e-01  100 0.12356135 0.01661508
    
    
  3. 在调整结果中检索最佳性能参数后,你可以使用最佳性能参数重新训练支持向量机:

    > model.tuned = svm(churn~., data = trainset, gamma = tuned$best.parameters$gamma, cost = tuned$best.parameters$cost)
    > summary(model.tuned)
    
    Call:
    svm(formula = churn ~ ., data = trainset, gamma = 10^-2, cost = 100)
    
    Parameters:
     SVM-Type:  C-classification 
     SVM-Kernel:  radial 
     cost:  100 
     gamma:  0.01 
    
    Number of Support Vectors:  547
    
     ( 304 243 )
    
    Number of Classes:  2 
    
    Levels: 
     yes no
    
    
  4. 然后,你可以使用predict函数根据拟合的支持向量机预测标签:

    > svm.tuned.pred = predict(model.tuned, testset[, !names(testset) %in% c("churn")])
    
    
  5. 接下来,根据测试数据集的预测标签和原始标签生成一个分类表:

    > svm.tuned.table=table(svm.tuned.pred, testset$churn)
    > svm.tuned.table
    
    svm.tuned.pred yes  no
     yes  95  24
     no   46 853
    
    
  6. 此外,生成一个类一致性来衡量性能:

    > classAgreement(svm.tuned.table)
    $diag
    [1] 0.9312377
    
    $kappa
    [1] 0.691678
    
    $rand
    [1] 0.871806
    
    $crand
    [1] 0.6303615
    
    
  7. 最后,你可以使用混淆矩阵来衡量重新训练的模型性能:

    > confusionMatrix(svm.tuned.table)
    Confusion Matrix and Statistics
    
    svm.tuned.pred yes  no
     yes  95  24
     no   46 853
    
     Accuracy : 0.9312 
     95% CI : (0.9139, 0.946)
     No Information Rate : 0.8615 
     P-Value [Acc > NIR] : 1.56e-12 
    
     Kappa : 0.6917 
     Mcnemar's Test P-Value : 0.01207 
    
     Sensitivity : 0.67376 
     Specificity : 0.97263 
     Pos Pred Value : 0.79832 
     Neg Pred Value : 0.94883 
     Prevalence : 0.13851 
     Detection Rate : 0.09332 
     Detection Prevalence : 0.11690 
     Balanced Accuracy : 0.82320 
    
     'Positive' Class : yes 
    
    

它是如何工作的...

为了调整支持向量机,你可以使用试错法来找到最佳的 gamma 和成本参数。换句话说,必须生成各种 gamma 和成本的组合,以训练不同的支持向量机。

在这个例子中,我们生成从10-6*到*10-1的不同 gamma 值,以及值为 10 或 100 的成本。因此,你可以使用调整函数svm.tune生成 12 组参数。该函数然后进行 10 次交叉验证,并输出每个组合的错误分散度。结果,错误分散度最低的组合被认为是最佳参数集。从摘要表中,我们发现 gamma 值为 0.01 且成本值为 100 是 SVM 拟合的最佳参数。

在获得最佳参数后,我们可以使用 gamma 等于 0.01 且成本等于 100 的新支持向量机进行训练。此外,我们还可以根据预测标签和测试数据集的标签获得一个分类表。我们还可以从分类表中获得一个混淆矩阵。从混淆矩阵的输出中,你可以确定新训练的模型与原始模型相比的准确性。

参考信息

  • 关于如何使用svm.tune调整 SVM 的更多信息,你可以使用help函数访问此文档:

    > ?svm.tune
    
    

使用 neuralnet 训练神经网络

神经网络是由相互连接的节点组构建的,涉及输入、连接权重、处理元素和输出。神经网络可以应用于许多领域,如分类、聚类和预测。要在 R 中训练神经网络,您可以使用 neuralnet,它是在回归分析背景下构建的,用于训练多层感知器,并包含许多灵活的函数来训练前向神经网络。在这个菜谱中,我们将介绍如何使用 neuralnet 来训练神经网络。

准备工作

在这个菜谱中,我们将使用iris数据集作为我们的示例数据集。我们首先将iris数据集分为训练集和测试集。

如何操作...

执行以下步骤以使用 neuralnet 训练神经网络:

  1. 首先加载iris数据集并将数据分为训练集和测试集:

    > data(iris)
    > ind = sample(2, nrow(iris), replace = TRUE, prob=c(0.7, 0.3))
    > trainset = iris[ind == 1,]
    > testset = iris[ind == 2,]
    
    
  2. 然后,安装并加载neuralnet包:

    > install.packages("neuralnet")
    > library(neuralnet)
    
    
  3. 根据名称匹配值在Species列中添加 versicolor、setosa 和 virginica 列:

    > trainset$setosa = trainset$Species == "setosa"
    > trainset$virginica = trainset$Species == "virginica"
    > trainset$versicolor = trainset$Species == "versicolor"
    
    
  4. 接下来,使用具有每层三个隐藏神经元的neuralnet函数训练神经网络。请注意,每次训练的结果可能会有所不同,因此您可能不会得到相同的结果。然而,您可以在开始时使用 set.seed,这样您可以在每次训练过程中得到相同的结果。

    > network = neuralnet(versicolor + virginica + setosa~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, trainset, hidden=3)
    > network
    Call: neuralnet(formula = versicolor + virginica + setosa ~ Sepal.Length +     Sepal.Width + Petal.Length + Petal.Width, data = trainset,     hidden = 3)
    
    1 repetition was calculated.
    
     Error Reached Threshold Steps
    1 0.8156100175    0.009994274769 11063
    
    
  5. 现在,您可以通过访问构建的神经网络模型的result.matrix属性来查看summary信息:

    > network$result.matrix
     1
    error                        0.815610017474
    reached.threshold            0.009994274769
    steps                    11063.000000000000
    Intercept.to.1layhid1        1.686593311644
    Sepal.Length.to.1layhid1     0.947415215237
    Sepal.Width.to.1layhid1     -7.220058260187
    Petal.Length.to.1layhid1     1.790333443486
    Petal.Width.to.1layhid1      9.943109233330
    Intercept.to.1layhid2        1.411026063895
    Sepal.Length.to.1layhid2     0.240309549505
    Sepal.Width.to.1layhid2      0.480654059973
    Petal.Length.to.1layhid2     2.221435192437
    Petal.Width.to.1layhid2      0.154879347818
    Intercept.to.1layhid3       24.399329878242
    Sepal.Length.to.1layhid3     3.313958088512
    Sepal.Width.to.1layhid3      5.845670010464
    Petal.Length.to.1layhid3    -6.337082722485
    Petal.Width.to.1layhid3    -17.990352566695
    Intercept.to.versicolor     -1.959842102421
    1layhid.1.to.versicolor      1.010292389835
    1layhid.2.to.versicolor      0.936519720978
    1layhid.3.to.versicolor      1.023305801833
    Intercept.to.virginica      -0.908909982893
    1layhid.1.to.virginica      -0.009904635231
    1layhid.2.to.virginica       1.931747950462
    1layhid.3.to.virginica      -1.021438938226
    Intercept.to.setosa          1.500533827729
    1layhid.1.to.setosa         -1.001683936613
    1layhid.2.to.setosa         -0.498758815934
    1layhid.3.to.setosa         -0.001881935696
    
    
  6. 最后,您可以通过在网络上访问它来查看广义权重:

    > head(network$generalized.weights[[1]])
    
    

它是如何工作的...

神经网络是由人工神经元(或节点)组成的网络。网络中有三种类型的神经元:输入神经元、隐藏神经元和输出神经元。在网络中,神经元是相互连接的;神经元之间的连接强度称为权重。如果权重大于零,则处于兴奋状态。否则,处于抑制状态。输入神经元接收输入信息;输入值越高,激活度越大。然后,激活值根据图中的权重和传递函数在网络中传递。隐藏神经元(或输出神经元)随后将激活值相加,并使用传递函数修改总和值。激活值随后通过隐藏神经元流动,并在达到输出节点时停止。因此,可以使用输出神经元的输出值来分类数据。

它是如何工作的...

图 9:人工神经网络

神经网络的优点是:首先,它可以检测因变量和自变量之间的非线性关系。其次,可以使用并行架构高效地训练大型数据集。第三,它是一个非参数模型,因此可以消除参数估计中的误差。神经网络的主要缺点是它往往收敛到局部最小值而不是全局最小值。此外,当训练过程过长时,可能会出现过拟合。

在这个菜谱中,我们展示了如何训练一个神经网络。首先,我们将iris数据集分为训练集和测试集,然后安装neuralnet包并将库加载到 R 会话中。接下来,我们根据Species列中匹配的名称分别添加versicolorsetosavirginica列。然后,我们使用neuralnet函数来训练网络模型。在函数中指定标签(名称等于 versicolor、virginica 和 setosa 的列)和训练属性之外,我们还配置了每层的隐藏神经元(顶点)数量为三个。

然后,我们检查训练过程和保存在网络中的训练网络的基本信息。从输出信息中,可以看出训练过程需要 11,063 步才能使所有误差函数的绝对偏导数低于 0.01(指定在阈值中)。误差指的是计算赤池信息量准则AIC)的可能性。要查看详细信息,您可以访问构建的神经网络的result.matrix以查看估计的权重。输出显示估计的权重范围从-18 到 24.40;第一隐藏层的截距为 1.69、1.41 和 24.40,连接到第一隐藏神经元的两个权重估计为 0.95(Sepal.Length)、-7.22(Sepal.Width)、1.79(Petal.Length)和 9.94(Petal.Width)。我们最后可以确定训练的神经网络信息包括广义权重,这些权重表示每个协变量的影响。在这个菜谱中,模型生成了 12 个广义权重,这是四个协变量(Sepal.LengthSepal.WidthPetal.LengthPetal.Width)与三个响应(setosavirginicaversicolor)的组合。

参见

  • 对于神经网络的更详细介绍,可以参考以下论文:Günther, F. 和 Fritsch, S. (2010). neuralnet: 神经网络的训练. R 期刊, 2(1), 30-38。

可视化由 neuralnet 训练的神经网络

neuralnet包提供了plot函数来可视化构建的神经网络,以及gwplot函数来可视化广义权重。在接下来的菜谱中,我们将介绍如何使用这两个函数。

准备工作

您需要完成之前的菜谱,通过训练神经网络并保存所有基本信息到网络中。

如何操作...

执行以下步骤以可视化神经网络和广义权重:

  1. 您可以使用plot函数可视化训练好的神经网络:

    > plot(network)
    
    

    如何操作...

    图 10:训练好的神经网络的图示

  2. 此外,您还可以使用gwplot可视化广义权重:

    > par(mfrow=c(2,2))
    > gwplot(network,selected.covariate="Petal.Width")
    > gwplot(network,selected.covariate="Sepal.Width")
    > gwplot(network,selected.covariate="Petal.Length")
    > gwplot(network,selected.covariate="Petal.Width")
    
    

    如何操作...

    图 11:广义权重的图示

工作原理...

在本食谱中,我们展示了如何可视化训练好的神经网络以及每个训练属性的广义权重。根据图 10,该图显示了训练好的神经网络的网络拓扑结构。此外,该图还包括估计的权重、截距以及训练过程的基本信息。在图的下部,可以找到总体误差和收敛所需的步数。

图 11展示了与network$generalized.weights相关的广义权重图。图 11中的四个图显示了四个协变量:Petal.WidthSepal.WidthPetal.LengthPetal.Width,相对于 versicolor 响应。如果图上的所有广义权重都接近于零,这意味着协变量几乎没有影响。然而,如果整体方差大于一,这意味着协变量有非线性影响。

参见

  • 关于gwplot的更多信息,可以使用help函数访问以下文档:

    > ?gwplot
    
    

基于 neuralnet 模型训练预测标签

与其他分类方法类似,我们可以根据训练好的神经网络预测新观察值的标签。此外,我们可以通过使用混淆矩阵来验证这些网络的表现。在接下来的食谱中,我们将介绍如何使用神经网络中的compute函数获取测试数据集标签的概率矩阵,并使用表格和混淆矩阵来衡量预测性能。

准备工作

您需要通过生成训练数据集trainset和测试数据集testset来完成前面的食谱。训练好的神经网络需要保存在网络中。

如何操作...

执行以下步骤以衡量训练好的神经网络的预测性能:

  1. 首先,基于训练好的神经网络和测试数据集testset生成一个预测概率矩阵:

    > net.predict = compute(network, testset[-5])$net.result
    
    
  2. 然后,通过找到概率最大的列来获取其他可能的标签:

    > net.prediction = c("versicolor", "virginica", "setosa")[apply(net.predict, 1, which.max)]
    
    
  3. 根据预测标签和测试数据集的标签生成一个分类表:

    > predict.table = table(testset$Species, net.prediction)
    > predict.table
     prediction
     setosa versicolor virginica
     setosa         20          0         0
     versicolor      0         19         1
     virginica       0          2        16
    
    
  4. 接下来,从分类表中生成classAgreement

    > classAgreement(predict.table)
    $diag
    [1] 0.9444444444
    
    $kappa
    [1] 0.9154488518
    
    $rand
    [1] 0.9224318658
    
    $crand
    [1] 0.8248251737
    
    
  5. 最后,使用confusionMatrix来衡量预测性能:

    > confusionMatrix(predict.table)
    Confusion Matrix and Statistics
    
     prediction
     setosa versicolor virginica
     setosa         20          0         0
     versicolor      0         19         1
     virginica       0          2        16
    
    Overall Statistics
    
     Accuracy : 0.9482759 
     95% CI : (0.8561954, 0.9892035) 
     No Information Rate : 0.362069 
     P-Value [Acc > NIR] : < 0.00000000000000022204
    
     Kappa : 0.922252 
     Mcnemar's Test P-Value : NA 
    
    Statistics by Class:
    
     Class: setosa Class: versicolor Class: virginica
    Sensitivity              1.0000000         0.9047619        0.9411765
    Specificity              1.0000000         0.9729730        0.9512195
    Pos Pred Value           1.0000000         0.9500000        0.8888889
    Neg Pred Value           1.0000000         0.9473684        0.9750000
    Prevalence               0.3448276         0.3620690        0.2931034
    Detection Rate           0.3448276         0.3275862        0.2758621
    Detection Prevalence     0.3448276         0.3448276        0.3103448
    Balanced Accuracy        1.0000000         0.9388674        0.9461980
    
    

工作原理...

在本食谱中,我们展示了如何根据由 neuralnet 训练的模型预测标签。最初,我们使用compute函数根据训练好的神经网络和测试数据集创建输出概率矩阵。然后,为了将概率矩阵转换为类别标签,我们使用which.max函数通过选择行内概率最大的列来确定类别标签。接下来,我们使用一个表格根据测试数据集的标签和预测标签生成分类矩阵。由于我们已经创建了分类表,我们可以使用混淆矩阵来衡量构建的神经网络的预测性能。

参见

  • 在本食谱中,我们使用net.result函数,这是神经网络的总体结果,用于预测测试数据集的标签。除了通过访问net.result来检查总体结果之外,compute函数还生成了每一层的神经元输出。你可以检查神经元的输出,以更好地理解compute是如何工作的:

    > compute(network, testset[-5])
    
    

使用 nnet 训练神经网络

nnet包是另一个可以处理人工神经网络的包。此包提供了使用传统反向传播训练前馈神经网络的函数。正如你可以在neuralnet包中找到的大多数神经网络函数一样,在本食谱中,我们提供了一个简短的概述,说明如何使用nnet训练神经网络。

准备工作

在本食谱中,我们不使用从上一步生成的trainsettrainset;请重新加载iris数据集。

如何做...

执行以下步骤以使用nnet训练神经网络:

  1. 首先,安装并加载nnet包:

    > install.packages("nnet")
    > library(nnet)
    
    
  2. 接下来,将数据集分为训练集和测试集:

    > data(iris)
    > set.seed(2)
    > ind = sample(2, nrow(iris), replace = TRUE, prob=c(0.7, 0.3))
    > trainset = iris[ind == 1,]
    > testset = iris[ind == 2,]
    
    
  3. 然后,使用nnet训练神经网络:

    > iris.nn = nnet(Species ~ ., data = trainset, size = 2, rang = 0.1, decay = 5e-4, maxit = 200)
    # weights:  19
    initial  value 165.086674 
    iter  10 value 70.447976
    iter  20 value 69.667465
    iter  30 value 69.505739
    iter  40 value 21.588943
    iter  50 value 8.691760
    iter  60 value 8.521214
    iter  70 value 8.138961
    iter  80 value 7.291365
    iter  90 value 7.039209
    iter 100 value 6.570987
    iter 110 value 6.355346
    iter 120 value 6.345511
    iter 130 value 6.340208
    iter 140 value 6.337271
    iter 150 value 6.334285
    iter 160 value 6.333792
    iter 170 value 6.333578
    iter 180 value 6.333498
    final  value 6.333471 
    converged
    
    
  4. 使用summary获取已训练神经网络的详细信息:

    > summary(iris.nn)
    a 4-2-3 network with 19 weights
    options were - softmax modelling  decay=0.0005
     b->h1 i1->h1 i2->h1 i3->h1 i4->h1 
     -0.38  -0.63  -1.96   3.13   1.53 
     b->h2 i1->h2 i2->h2 i3->h2 i4->h2 
     8.95   0.52   1.42  -1.98  -3.85 
     b->o1 h1->o1 h2->o1 
     3.08 -10.78   4.99 
     b->o2 h1->o2 h2->o2 
     -7.41   6.37   7.18 
     b->o3 h1->o3 h2->o3 
     4.33   4.42 -12.16 
    
    

它是如何工作的...

在本食谱中,我们展示了使用nnet包训练神经网络模型的步骤。我们首先使用nnet来训练神经网络。通过这个函数,我们可以设置分类公式、数据源、size参数中的隐藏单元数量、rang参数中的初始随机权重、decay参数中的权重衰减参数以及maxit参数中的最大迭代次数。由于我们将maxit设置为 200,训练过程会反复运行,直到拟合准则值加上衰减项收敛。最后,我们使用summary函数获取构建的神经网络的详细信息,这表明模型使用 4-2-3 网络构建,共有 19 个权重。此外,模型在打印消息的底部显示了一个从节点到另一个节点的权重转换列表。

参见

对于对nnet的背景理论和其制作方式感兴趣的人,请参阅以下文章:

  • Ripley, B. D. (1996) Pattern Recognition and Neural Networks. Cambridge

  • Venables, W. N., and Ripley, B. D. (2002). Modern applied statistics with S. Fourth edition. Springer

基于 nnet 训练的模型进行标签预测

在前一个菜谱中,我们已经使用nnet训练了一个神经网络,现在我们可以根据训练好的神经网络预测测试数据集的标签。此外,我们可以使用来自caret包的混淆矩阵来评估模型。

准备工作

您需要完成上一个菜谱,通过从iris数据集中生成训练数据集trainset和测试数据集testset。训练好的神经网络也需要保存为iris.nn

如何做...

执行以下步骤以基于训练好的神经网络进行标签预测:

  1. 基于模型iris.nn生成测试数据集的预测:

    > iris.predict = predict(iris.nn, testset, type="class")
    
    
  2. 根据预测标签和测试数据集的标签生成分类表:

    > nn.table = table(testset$Species, iris.predict)
     iris.predict
     setosa versicolor virginica
     setosa         17          0         0
     versicolor      0         14         0
     virginica       0          1        14
    
    
  3. 最后,根据分类表生成混淆矩阵:

    > confusionMatrix(nn.table)
    Confusion Matrix and Statistics
    
     iris.predict
     setosa versicolor virginica
     setosa         17          0         0
     versicolor      0         14         0
     virginica       0          1        14
    
    Overall Statistics
    
     Accuracy : 0.9782609 
     95% CI : (0.8847282, 0.9994498) 
     No Information Rate : 0.3695652 
     P-Value [Acc > NIR] : < 0.00000000000000022204
    
     Kappa : 0.9673063 
     Mcnemar's Test P-Value : NA 
    
    Statistics by Class:
    
     Class: setosa Class: versicolor
    Sensitivity              1.0000000         0.9333333
    Specificity              1.0000000         1.0000000
    Pos Pred Value           1.0000000         1.0000000
    Neg Pred Value           1.0000000         0.9687500
    Prevalence               0.3695652         0.3260870
    Detection Rate           0.3695652         0.3043478
    Detection Prevalence     0.3695652         0.3043478
    Balanced Accuracy        1.0000000         0.9666667
     Class: virginica
    Sensitivity                 1.0000000
    Specificity                 0.9687500
    Pos Pred Value              0.9333333
    Neg Pred Value              1.0000000
    Prevalence                  0.3043478
    Detection Rate              0.3043478
    Detection Prevalence        0.3260870
    Balanced Accuracy           0.9843750
    
    

它是如何工作的...

与其他分类方法类似,也可以基于由nnet训练的神经网络进行标签预测。首先,我们使用predict函数根据测试数据集testset生成预测标签。在predict函数中,我们指定类的type参数,以便输出将是类标签而不是概率矩阵。接下来,我们使用table函数根据预测标签和测试数据集中的标签生成分类表。最后,由于我们已经创建了分类表,我们可以使用caret包中的混淆矩阵来衡量训练好的神经网络的预测性能。

参见

  • 对于predict函数,如果未指定classtype参数,默认情况下,它将生成一个概率矩阵作为预测结果,这与neuralnet包内compute函数生成的net.result非常相似:

    > head(predict(iris.nn, testset))
    
    

第七章:模型评估

在本章中,我们将涵盖以下主题:

  • 使用 k 折交叉验证估计模型性能

  • 使用 e1071 包进行交叉验证

  • 使用caret包进行交叉验证

  • 使用caret包对变量重要性进行排名

  • 使用rminer包对变量重要性进行排名

  • 使用caret包寻找高度相关的特征

  • 使用caret包选择特征

  • 测量回归模型的性能

  • 使用混淆矩阵测量预测性能

  • 使用 ROCR 测量预测性能

  • 使用caret包比较 ROC 曲线

  • 使用caret包测量模型之间的性能差异

简介

模型评估是为了确保拟合的模型能够准确预测未来或未知主体的响应。如果没有模型评估,我们可能会训练出在训练数据上过度拟合的模型。为了防止过度拟合,我们可以使用如caretrminerrocr等包来评估拟合模型的性能。此外,模型评估有助于选择最佳模型,该模型更稳健,并能准确预测未来主体的响应。

在下一章中,我们将讨论如何实现一个简单的 R 脚本或使用一个包(例如caretrminer)来评估拟合模型的性能。

使用 k 折交叉验证估计模型性能

k 折交叉验证技术是一种常用的技术,用于估计分类器的性能,因为它克服了过度拟合的问题。对于 k 折交叉验证,该方法不使用整个数据集来构建模型,而是将数据分割成训练数据集和测试数据集。因此,使用训练数据集构建的模型可以用来评估模型在测试数据集上的性能。通过执行 n 次 k 折验证,我们可以使用 n 个准确率的平均值来真正评估构建的模型性能。在本菜谱中,我们将说明如何执行 k 折交叉验证。

准备工作

在这个菜谱中,我们将继续使用 telecom churn数据集作为输入数据源来训练支持向量机。对于那些尚未准备数据集的人,请参阅第五章,分类(I)-树、懒惰和概率性,以获取详细信息。

如何操作...

执行以下步骤以交叉验证 telecom churn数据集:

  1. 使用cut函数将索引分割成 10 折:

    > ind = cut(1:nrow(churnTrain), breaks=10, labels=F)
    
    
  2. 接下来,使用for循环执行 10 折交叉验证,重复 10 次:

    > accuracies = c()
    > for (i in 1:10) {
    +   fit = svm(churn ~., churnTrain[ind != i,])
    +   predictions = predict(fit, churnTrain[ind == i, ! names(churnTrain) %in% c("churn")])
    +   correct_count = sum(predictions == churnTrain[ind == i,c("churn")])
    +   accuracies = append(correct_count / nrow(churnTrain[ind == i,]), accuracies)
    + }
    
    
  3. 你可以打印出准确率:

    > accuracies
     [1] 0.9341317 0.8948949 0.8978979 0.9459459 0.9219219 0.9281437 0.9219219 0.9249249 0.9189189 0.9251497
    
    
  4. 最后,你可以使用mean函数生成平均准确率:

    > mean(accuracies)
    [1] 0.9213852
    
    

它是如何工作的...

在本例中,我们实现了一个简单的脚本,执行 10 折交叉验证。我们首先使用cut函数生成 10 个折的索引。然后,我们实现一个for循环,执行 10 次 10 折交叉验证。在循环中,我们首先将svm应用于9个数据折作为训练集。然后,我们使用拟合的模型预测剩余数据(测试数据集)的标签。接下来,我们使用正确预测的标签总和来生成准确率。因此,循环存储了 10 个生成的准确率。最后,我们使用mean函数检索准确率的平均值。

还有更多...

如果您希望使用其他模型执行 k 折交叉验证,只需替换生成变量 fit 的行,以您偏好的分类器为准。例如,如果您想使用 10 折交叉验证来评估朴素贝叶斯模型,只需将调用函数从svm替换为naiveBayes

> for (i in 1:10) {
+   fit = naiveBayes(churn ~., churnTrain[ind != i,])
+   predictions = predict(fit, churnTrain[ind == i, ! names(churnTrain) %in% c("churn")])
+   correct_count = sum(predictions == churnTrain[ind == i,c("churn")])
+   accuracies = append(correct_count / nrow(churnTrain[ind == i,]), accuracies)
+ }

使用 e1071 包进行交叉验证

除了实现一个loop函数来执行 k 折交叉验证外,您还可以在e1071包中使用tuning函数(例如,tune.nnettune.randomForesttune.rparttune.svmtune.knn)来获取最小误差值。在本例中,我们将说明如何使用tune.svm执行 10 折交叉验证并获得最佳分类模型。

准备工作

在本例中,我们继续使用电信churn数据集作为输入数据源执行 10 折交叉验证。

如何操作...

执行以下步骤以使用交叉验证检索最小估计误差:

  1. 在训练数据集trainset上应用tune.svm,使用 10 折交叉验证作为调整控制。(如果您发现错误消息,例如could not find function predict.func,请清除工作区,重新启动 R 会话并重新加载e1071库):

    > tuned = tune.svm(churn~., data = trainset, gamma = 10^-2, cost = 10², tunecontrol=tune.control(cross=10))
    
    
  2. 接下来,您可以获取模型的摘要信息,调整:

    > summary(tuned)
    
    Error estimation of 'svm' using 10-fold cross validation: 0.08164651
    
    
  3. 然后,您可以访问调整后模型的性能细节:

    > tuned$performances
     gamma cost      error dispersion
    1  0.01  100 0.08164651 0.02437228
    
    
  4. 最后,您可以使用最佳模型生成分类表:

    > svmfit = tuned$best.model
    > table(trainset[,c("churn")], predict(svmfit))
    
     yes   no
     yes  234  108
     no    13 1960
    
    

工作原理...

e1071包提供了构建和评估模型的各种函数,因此,您无需重新发明轮子来评估拟合模型。在本例中,我们使用tune.svm函数使用给定的公式、数据集、gamma、成本和控制函数调整 svm 模型。在tune.control选项中,我们将选项配置为cross=10,在调整过程中执行 10 折交叉验证。调整过程最终将返回最小估计误差、性能细节以及调整过程中的最佳模型。因此,我们可以获得调整的性能指标,并进一步使用最佳模型生成分类表。

参考信息

  • e1071包中,tune函数使用网格搜索来调整参数。对于那些对其他调整函数感兴趣的人,请使用帮助函数查看tune文档:

    > ?e1071::tune
    
    

使用 caret 包进行交叉验证

Caret(分类和回归训练)包包含许多关于回归和分类问题训练过程的函数。类似于e1071包,它也包含一个执行 k 折交叉验证的函数。在本菜谱中,我们将演示如何使用caret包执行 k 折交叉验证。

准备工作

在本菜谱中,我们将继续使用电信churn数据集作为输入数据源来执行 k 折交叉验证。

如何操作...

执行以下步骤以使用caret包执行 k 折交叉验证:

  1. 首先,设置控制参数以进行 10 折交叉验证,重复 3 次:

    > control = trainControl(method="repeatedcv", number=10, repeats=3)
    
    
  2. 然后,你可以使用rpart在电信客户流失数据上训练分类模型:

    > model = train(churn~., data=trainset, method="rpart", preProcess="scale", trControl=control)
    
    
  3. 最后,你可以检查生成的模型的输出:

    > model
    CART 
    
    2315 samples
     16 predictor
     2 classes: 'yes', 'no' 
    
    Pre-processing: scaled 
    Resampling: Cross-Validated (10 fold, repeated 3 times) 
    
    Summary of sample sizes: 2084, 2083, 2082, 2084, 2083, 2084, ... 
    
    Resampling results across tuning parameters:
    
     cp      Accuracy  Kappa  Accuracy SD  Kappa SD
     0.0556  0.904     0.531  0.0236       0.155 
     0.0746  0.867     0.269  0.0153       0.153 
     0.0760  0.860     0.212  0.0107       0.141 
    
    Accuracy was used to select the optimal model using the largest value.
    The final value used for the model was cp = 0.05555556.
    
    

工作原理...

在本菜谱中,我们展示了使用caret包进行 k 折交叉验证是多么方便。在第一步中,我们设置了训练控制并选择了在三次重复中执行 10 折交叉验证的选项。重复 k 折验证的过程称为重复 k 折验证,用于测试模型的稳定性。如果模型稳定,应该得到相似的训练结果。然后,我们使用rpart在训练数据集上应用,并选择缩放数据以及使用之前步骤中配置的选项来训练模型。

训练过程完成后,模型输出三个重采样结果。在这些结果中,cp=0.05555556的模型具有最大的准确值(0.904),因此被选为分类的最佳模型。

参考以下内容

  • 你可以在trainControl中配置resampling函数,其中你可以指定bootboot632cvrepeatedcvLOOCVLGOCVnoneoobadaptive_cvadaptive_bootadaptive_LGOCV。要查看如何选择重采样方法的更详细信息,请查看trainControl文档:

    > ?trainControl
    
    

使用 caret 包对变量重要性进行排名

在构建监督学习模型后,我们可以估计特征的重要性。这种估计采用敏感性分析来衡量当输入变化时对给定模型输出的影响。在本菜谱中,我们将向您展示如何使用caret包对变量重要性进行排名。

准备工作

你需要完成之前的菜谱,并将拟合的rpart对象存储在model变量中。

如何操作...

执行以下步骤以使用caret包对变量重要性进行排名:

  1. 首先,你可以使用varImp函数估计变量重要性:

    > importance = varImp(model, scale=FALSE)
    > importance
    rpart variable importance
    
     Overall
    number_customer_service_calls 116.015
    total_day_minutes             106.988
    total_day_charge              100.648
    international_planyes          86.789
    voice_mail_planyes             25.974
    total_eve_charge               23.097
    total_eve_minutes              23.097
    number_vmail_messages          19.885
    total_intl_minutes              6.347
    total_eve_calls                 0.000
    total_day_calls                 0.000
    total_night_charge              0.000
    total_intl_calls                0.000
    total_intl_charge               0.000
    total_night_minutes             0.000
    total_night_calls               0.000
    
    
  2. 然后,您可以使用plot函数生成可变重要性图:

    > plot(importance)
    
    

    如何操作...

    图 1:使用 caret 包的可变重要性可视化

工作原理...

在本食谱中,我们首先使用varImp函数检索可变重要性并获取摘要。整体结果显示了每个属性的敏感性度量。接下来,我们按排名绘制可变重要性,这表明number_customer_service_calls属性在敏感性度量中是最重要的变量。

更多内容...

在某些分类包中,例如rpart,从训练模型生成的对象包含变量重要性。我们可以通过访问输出对象来检查变量重要性:

> library(rpart)
> model.rp = rpart(churn~., data=trainset)
> model.rp$variable.importance
 total_day_minutes              total_day_charge 
 111.645286                    110.881583 
number_customer_service_calls            total_intl_minutes 
 58.486651                     48.283228 
 total_intl_charge              total_eve_charge 
 47.698379                     47.166646 
 total_eve_minutes            international_plan 
 47.166646                     42.194508 
 total_intl_calls         number_vmail_messages 
 36.730344                     19.884863 
 voice_mail_plan             total_night_calls 
 19.884863                      7.195828 
 total_eve_calls            total_night_charge 
 3.553423                      1.754547 
 total_night_minutes               total_day_calls 
 1.754547                      1.494986 

使用 rminer 包对可变重要性进行排名

除了使用caret包生成可变重要性外,您还可以使用rminer包生成分类模型的可变重要性。在下面的食谱中,我们将说明如何使用rminer获取拟合模型的可变重要性。

准备工作

在本食谱中,我们将继续使用电信churn数据集作为输入数据源来对可变重要性进行排序。

如何操作...

执行以下步骤以使用rminer对可变重要性进行排名:

  1. 安装并加载包,rminer

    > install.packages("rminer")
    > library(rminer)
    
    
  2. 使用训练集拟合 svm 模型:

    > model=fit(churn~.,trainset,model="svm")
    
    
  3. 使用Importance函数获取可变重要性:

    > VariableImportance=Importance(model,trainset,method="sensv")
    
    
  4. 按方差绘制可变重要性图

    > L=list(runs=1,sen=t(VariableImportance$imp),sresponses=VariableImportance$sresponses)
    > mgraph(L,graph="IMP",leg=names(trainset),col="gray",Grid=10)
    
    

    如何操作...

    图 2:使用rminer包的可变重要性可视化

工作原理...

caret包类似,rminer包也可以生成分类模型的可变重要性。在本食谱中,我们首先使用fit函数在训练数据集trainset上训练 svm 模型。然后,我们使用Importance函数使用敏感性度量对可变重要性进行排名。最后,我们使用mgraph绘制可变重要性的排名。与使用caret包获得的结果相似,number_customer_service_calls是在敏感性度量中最重要的变量。

参见

  • rminer包提供许多分类模型供用户选择。如果您对使用 svm 以外的模型感兴趣,可以使用以下命令查看这些选项:

    > ?rminer::fit
    
    

使用 caret 包寻找高度相关的特征

在执行回归或分类时,如果移除高度相关的属性,某些模型的表现会更好。caret包提供了findCorrelation函数,可以用来查找彼此高度相关的属性。在本食谱中,我们将演示如何使用caret包查找高度相关的特征。

准备工作

在本食谱中,我们将继续使用电信churn数据集作为输入数据源来寻找高度相关的特征。

如何操作...

执行以下步骤以找到高度相关的属性:

  1. 移除未用数值字符编码的特征:

    > new_train = trainset[,! names(churnTrain) %in% c("churn", "international_plan", "voice_mail_plan")]
    
    
  2. 然后,你可以获得每个属性的关联性:

    >cor_mat = cor(new_train)
    
    
  3. 接下来,我们使用findCorrelation搜索截止值为 0.75 的高度相关属性:

    > highlyCorrelated = findCorrelation(cor_mat, cutoff=0.75)
    
    
  4. 然后,我们获得高度相关属性的名称:

    > names(new_train)[highlyCorrelated]
    [1] "total_intl_minutes"  "total_day_charge"    "total_eve_minutes"   "total_night_minutes"
    
    

它是如何工作的...

在本菜谱中,我们使用caret包搜索高度相关的属性。为了检索每个属性的关联性,首先应移除非数值属性。然后,我们执行关联性分析以获得关联矩阵。接下来,我们使用findCorrelation找到高度相关的属性,截止值为 0.75。我们最终获得高度相关(相关系数超过 0.75)的属性名称,分别是total_intl_minutestotal_day_chargetotal_eve_minutestotal_night_minutes。你可以考虑移除一些高度相关的属性,保留一个或两个属性以获得更好的准确性。

相关内容

  • 除了caret包外,你还可以使用subselect包中的leapsgeneticanneal函数达到相同的目的

使用 caret 包进行特征选择

特征选择方法搜索具有最小预测误差的特征子集。我们可以应用特征选择来识别构建准确模型所需的属性。caret包提供了一个递归特征消除函数rfe,可以帮助自动选择所需的特征。在下面的菜谱中,我们将演示如何使用caret包进行特征选择。

准备工作

在本菜谱中,我们将继续使用电信churn数据集作为特征选择的输入数据源。

如何操作...

执行以下步骤以选择特征:

  1. 将训练数据集trainset中名为international_plan的特征转换为intl_yesintl_no

    > intl_plan = model.matrix(~ trainset.international_plan - 1, data=data.frame(trainset$international_plan))
    > colnames(intl_plan) = c("trainset.international_planno"="intl_no", "trainset.international_planyes"= "intl_yes")
    
    
  2. 将训练数据集trainset中名为voice_mail_plan的特征转换为voice_yesvoice_no

    > voice_plan = model.matrix(~ trainset.voice_mail_plan - 1, data=data.frame(trainset$voice_mail_plan))
    > colnames(voice_plan) = c("trainset.voice_mail_planno" ="voice_no", "trainset.voice_mail_planyes"="voidce_yes")
    
    
  3. 移除international_planvoice_mail_plan属性,并将训练数据集trainset与数据框intl_planvoice_plan合并:

    > trainset$international_plan = NULL
    > trainset$voice_mail_plan = NULL
    > trainset = cbind(intl_plan,voice_plan, trainset)
    
    
  4. 将测试数据集testset中名为international_plan的特征转换为intl_yesintl_no

    > intl_plan = model.matrix(~ testset.international_plan - 1, data=data.frame(testset$international_plan))
    > colnames(intl_plan) = c("testset.international_planno"="intl_no", "testset.international_planyes"= "intl_yes")
    
    
  5. 将训练数据集trainset中名为voice_mail_plan的特征转换为voice_yesvoice_no

    > voice_plan = model.matrix(~ testset.voice_mail_plan - 1, data=data.frame(testset$voice_mail_plan))
    > colnames(voice_plan) = c("testset.voice_mail_planno" ="voice_no", "testset.voice_mail_planyes"="voidce_yes")
    
    
  6. 移除international_planvoice_mail_plan属性,并将测试数据集testset与数据框intl_planvoice_plan合并:

    > testset$international_plan = NULL
    > testset$voice_mail_plan = NULL
    > testset = cbind(intl_plan,voice_plan, testset)
    
    
  7. 然后,我们使用线性判别分析创建一个特征选择算法:

    > ldaControl = rfeControl(functions = ldaFuncs, method = "cv")
    
    
  8. 接下来,我们在训练数据集trainset上使用从 1 到 18 的子集进行向后特征选择:

    > ldaProfile = rfe(trainset[, !names(trainset) %in% c("churn")], trainset[,c("churn")],sizes = c(1:18), rfeControl = ldaControl)
    > ldaProfile
    
    Recursive feature selection
    
    Outer resampling method: Cross-Validated (10 fold) 
    
    Resampling performance over subset size:
    
     Variables Accuracy  Kappa AccuracySD KappaSD Selected
     1   0.8523 0.0000   0.001325 0.00000 
     2   0.8523 0.0000   0.001325 0.00000 
     3   0.8423 0.1877   0.015468 0.09787 
     4   0.8462 0.2285   0.016593 0.09610 
     5   0.8466 0.2384   0.020710 0.09970 
     6   0.8466 0.2364   0.019612 0.09387 
     7   0.8458 0.2315   0.017551 0.08670 
     8   0.8458 0.2284   0.016608 0.09536 
     9   0.8475 0.2430   0.016882 0.10147 
     10   0.8514 0.2577   0.014281 0.08076 
     11   0.8518 0.2587   0.014124 0.08075 
     12   0.8544 0.2702   0.015078 0.09208        *
     13   0.8544 0.2721   0.015352 0.09421 
     14   0.8531 0.2663   0.018428 0.11022 
     15   0.8527 0.2652   0.017958 0.10850 
     16   0.8531 0.2684   0.017897 0.10884 
     17   0.8531 0.2684   0.017897 0.10884 
     18   0.8531 0.2684   0.017897 0.10884 
    
    The top 5 variables (out of 12):
     total_day_charge, total_day_minutes, intl_no, number_customer_service_calls, total_eve_charge
    
    
  9. 接下来,我们可以绘制选择结果:

    > plot(ldaProfile, type = c("o", "g"))
    
    

    如何操作...

    图 3:特征选择结果

  10. 然后,我们可以检查变量的最佳子集:

    > ldaProfile$optVariables
     [1] "total_day_charge" 
     [2] "total_day_minutes" 
     [3] "intl_no" 
     [4] "number_customer_service_calls"
     [5] "total_eve_charge" 
     [6] "total_eve_minutes" 
     [7] "voidce_yes" 
     [8] "total_intl_calls" 
     [9] "number_vmail_messages" 
    [10] "total_intl_charge" 
    [11] "total_intl_minutes" 
    [12] "total_night_minutes" 
    
    
  11. 现在,我们可以检查拟合的模型:

    > ldaProfile$fit
    Call:
    lda(x, y)
    
    Prior probabilities of groups:
     yes        no 
    0.1477322 0.8522678 
    
    Group means:
     total_day_charge total_day_minutes   intl_no
    yes         35.00143          205.8877 0.7046784
    no          29.62402          174.2555 0.9351242
     number_customer_service_calls total_eve_charge
    yes                      2.204678         18.16702
    no                       1.441460         16.96789
     total_eve_minutes voidce_yes total_intl_calls
    yes          213.7269  0.1666667         4.134503
    no           199.6197  0.2954891         4.514445
     number_vmail_messages total_intl_charge
    yes              5.099415          2.899386
    no               8.674607          2.741343
     total_intl_minutes total_night_minutes
    yes           10.73684            205.4640
    no            10.15119            201.4184
    
    Coefficients of linear discriminants:
     LD1
    total_day_charge               0.715025524
    total_day_minutes             -0.130486470
    intl_no                        2.259889324
    number_customer_service_calls -0.421997335
    total_eve_charge              -2.390372793
    total_eve_minutes              0.198406977
    voidce_yes                     0.660927935
    total_intl_calls               0.066240268
    number_vmail_messages         -0.003529233
    total_intl_charge              2.315069869
    total_intl_minutes            -0.693504606
    total_night_minutes           -0.002127471
    
    
  12. 最后,我们可以计算跨样本的性能:

    > postResample(predict(ldaProfile, testset[, !names(testset) %in% c("churn")]), testset[,c("churn")])
    Accuracy     Kappa
    0.8605108 0.2672027
    
    

工作原理...

在这个菜谱中,我们使用caret包进行特征选择。由于数据集中存在因子编码的属性,我们首先使用一个名为model.matrix的函数将因子编码的属性转换为多个二元属性。因此,我们将international_plan属性转换为intl_yesintl_no。此外,我们将voice_mail_plan属性转换为voice_yesvoice_no

接下来,我们使用交叉验证方法cv和线性判别函数ldaFuncs设置训练的控制参数。然后,我们使用control函数ldaFuncs进行特征选择,使用递归特征消除rferfe函数生成特征选择摘要,其中包含对子集大小和顶级变量的重采样性能。

然后,我们可以使用获得模型信息来绘制变量数量与准确率的关系图。从图 3 中可以看出,使用 12 个特征可以获得最佳准确率。除此之外,我们还可以检索出拟合模型中最佳变量子集(总共有 12 个变量)。最后,我们可以计算跨样本的性能,得到准确率为 0.86 和 kappa 值为 0.27。

参见

  • 为了指定用于控制特征选择的算法,可以在rfeControl中更改指定的控制函数。以下是一些你可以使用的选项:

    caretFuncs      SVM (caret)
    lmFuncs     lm (base)
    rfFuncs         RF(randomForest)
    treebagFuncs     DT (ipred)
    ldaFuncs       lda(base)
    nbFuncs       NB(klaR)
    gamFuncs      gam(gam)
    
    

衡量回归模型的表现

为了衡量回归模型的表现,我们可以计算预测输出与实际输出之间的距离,作为模型性能的量化指标。在这里,我们通常使用均方根误差RMSE)、相对平方误差RSE)和 R-Square 作为常见的测量指标。在下面的菜谱中,我们将展示如何从一个构建的回归模型中计算这些测量值。

准备工作

在这个菜谱中,我们将使用包含四个回归数据集的Quartet数据集作为我们的输入数据源。

如何做...

执行以下步骤来衡量回归模型的表现:

  1. car包中加载Quartet数据集:

    > library(car)
    > data(Quartet)
    
    
  2. 使用lm函数将属性y3与 x 绘制出来:

    > plot(Quartet$x, Quartet$y3)
    > lmfit = lm(Quartet$y3~Quartet$x)
    > abline(lmfit, col="red")
    
    

    如何做...

    图 4:线性回归图

  3. 你可以使用predict函数检索预测值:

    > predicted= predict(lmfit, newdata=Quartet[c("x")])
    
    
  4. 现在,你可以计算均方根误差:

    > actual = Quartet$y3
    > rmse = (mean((predicted - actual)²))⁰.5
    > rmse
    [1] 1.118286
    
    
  5. 你可以计算相对平方误差:

    > mu = mean(actual)
    > rse = mean((predicted - actual)²) / mean((mu - actual)²) 
    > rse
    [1] 0.333676
    
    
  6. 此外,你还可以使用 R-Square 作为测量指标:

    > rsquare = 1 - rse
    > rsquare
    [1] 0.666324
    
    
  7. 然后,你可以使用 MASS 包中的rlm函数将属性 y3 与 x 绘制出来:

    > library(MASS)
    > plot(Quartet$x, Quartet$y3)
    > rlmfit = rlm(Quartet$y3~Quartet$x)
    > abline(rlmfit, col="red")
    
    

    如何做...

    图 5:Quartet 数据集上的稳健线性回归图

  8. 然后,你可以使用predict函数检索预测值:

    > predicted = predict(rlmfit, newdata=Quartet[c("x")])
    
    
  9. 接下来,你可以使用预测值和实际值之间的距离来计算根均方误差:

    > actual = Quartet$y3
    > rmse = (mean((predicted - actual)²))⁰.5
    > rmse
    [1] 1.279045
    
    
  10. 计算预测标签和实际标签之间的相对平方误差:

    > mu = mean(actual)
    > rse =mean((predicted - actual)²) / mean((mu - actual)²) 
    > rse
    [1] 0.4365067
    
    
  11. 现在,你可以计算 R-Square 值:

    > rsquare = 1 - rse
    > rsquare
    [1] 0.5634933
    
    

工作原理...

回归模型性能的测量使用预测值和实际值之间的距离。我们通常使用这三个度量,即均方根误差、相对平方误差和 R-Square,作为回归模型性能的量化指标。在这个菜谱中,我们首先从 car 包中加载 Quartet 数据。然后,我们使用 lm 函数拟合线性模型,并在 x 变量对 y3 变量的散点图上添加回归线。接下来,我们使用预测函数计算预测值,并开始计算构建模型的 均方根误差RMSE)、相对平方误差RSE)和 R-Square。

由于这个数据集在 x=13 处有一个异常值,我们希望量化异常值对性能测量的影响。为了实现这一点,我们首先使用 MASS 包中的 rlm 函数训练一个回归模型。类似于前面的步骤,然后我们生成根平方均方误差、相对误差和 R-Square 的性能测量。从输出测量来看,显然 lm 模型的均方误差和相对平方误差小于由 rlm 构建的模型,R-Square 的得分显示使用 lm 构建的模型具有更大的预测能力。然而,对于实际场景,我们应该移除 x=13 处的异常值。这个比较表明异常值可能偏向于性能测量,并可能导致我们选择错误的模型。

更多内容...

如果你想要对一个线性回归模型进行交叉验证,你可以在 e1071 包中使用 tune 函数:

> tune(lm, y3~x, data = Quartet)
Error estimation of 'lm' using 10-fold cross validation: 2.33754

除了 e1071 包之外,你还可以使用 caret 包中的 train 函数来进行交叉验证。此外,你还可以使用 DAAG 包中的 cv.lm 来达到相同的目的。

使用混淆矩阵衡量预测性能

为了衡量分类模型的性能,我们首先可以根据我们的预测标签和实际标签生成一个分类表。然后,我们可以使用混淆矩阵来获得性能度量,如精确度、召回率、特异性和准确率。在这个菜谱中,我们将演示如何使用 caret 包检索混淆矩阵。

准备工作

在这个菜谱中,我们将继续使用电信 churn 数据集作为我们的示例数据集。

如何做...

执行以下步骤以生成分类测量:

  1. 使用训练数据集训练 svm 模型:

    > svm.model= train(churn ~ .,
    +                   data = trainset,
    +                   method = "svmRadial")
    
    
  2. 然后,你可以使用拟合的模型 svm.model 来预测标签:

    > svm.pred = predict(svm.model, testset[,! names(testset) %in% c("churn")])
    
    
  3. 接下来,你可以生成一个分类表:

    > table(svm.pred, testset[,c("churn")])
    
    svm.pred yes  no
     yes  73  16
     no   68 861
    
    
  4. 最后,你可以使用预测结果和测试数据集中的实际标签生成一个混淆矩阵:

    > confusionMatrix(svm.pred, testset[,c("churn")])
    Confusion Matrix and Statistics
    
     Reference
    Prediction yes  no
     yes  73  16
     no   68 861
    
     Accuracy : 0.9175 
     95% CI : (0.8989, 0.9337)
     No Information Rate : 0.8615 
     P-Value [Acc > NIR] : 2.273e-08 
    
     Kappa : 0.5909 
     Mcnemar's Test P-Value : 2.628e-08 
    
     Sensitivity : 0.51773 
     Specificity : 0.98176 
     Pos Pred Value : 0.82022 
     Neg Pred Value : 0.92680 
     Prevalence : 0.13851 
     Detection Rate : 0.07171 
     Detection Prevalence : 0.08743 
     Balanced Accuracy : 0.74974 
    
     'Positive' Class : yes 
    
    

工作原理...

在这个菜谱中,我们展示了如何获取混淆矩阵来衡量分类模型的性能。首先,我们使用caret包中的train函数来训练 svm 模型。接下来,我们使用predict函数使用测试数据集提取 svm 模型的预测标签。然后,我们执行table函数以根据预测和实际标签获取分类表。最后,我们使用caret包中的confusionMatrix函数生成一个混淆矩阵来衡量分类模型的性能。

相关内容

使用 ROCR 测量预测性能

接收者操作特征(ROC)曲线是说明二元分类器系统性能的图表,它将不同截断点的真正例率和假正例率进行绘图。我们最常用这个图表来计算曲线下面积(AUC),以衡量分类模型的性能。在这个菜谱中,我们将展示如何绘制 ROC 曲线并计算 AUC 来衡量分类模型的性能。

准备工作

在这个菜谱中,我们将继续使用电信churn数据集作为我们的示例数据集。

如何操作...

执行以下步骤以生成具有不同成本的两种不同的分类示例:

  1. 首先,你应该安装并加载ROCR包:

    > install.packages("ROCR")
    > library(ROCR)
    
    
  2. 使用训练数据集并设置概率等于TRUE来训练 svm 模型:

    > svmfit=svm(churn~ ., data=trainset, prob=TRUE)
    
    
  3. 在测试数据集上基于训练模型进行预测,并将概率设置为TRUE

    >pred=predict(svmfit,testset[, !names(testset) %in% c("churn")], probability=TRUE)
    
    
  4. 使用yes标签获取概率:

    > pred.prob = attr(pred, "probabilities") 
    > pred.to.roc = pred.prob[, 2] 
    
    
  5. 使用prediction函数生成预测结果:

    > pred.rocr = prediction(pred.to.roc, testset$churn)
    
    
  6. 使用performance函数获取性能度量:

    > perf.rocr = performance(pred.rocr, measure = "auc", x.measure = "cutoff") 
    > perf.tpr.rocr = performance(pred.rocr, "tpr","fpr") 
    
    
  7. 使用plot函数可视化 ROC 曲线:

    > plot(perf.tpr.rocr, colorize=T,main=paste("AUC:",(perf.rocr@y.values)))
    
    

    如何操作...

    图 6:svm 分类器性能的 ROC 曲线

工作原理...

在本例中,我们展示了如何生成 ROC 曲线来展示二元分类器的性能。首先,我们应该安装并加载库,ROCR。然后,我们使用来自e1071包的 svm 来训练一个分类模型,并使用该模型对测试数据集进行预测。接下来,我们使用预测函数(来自ROCR包)生成预测结果。然后,我们将性能函数调整为获得真正例率对假正例率的性能测量。最后,我们使用plot函数可视化 ROC 图,并在标题上添加 AUC 值。在这个例子中,AUC 值是 0.92,这表明 svm 分类器在电信用户流失数据集的分类中表现良好。

参考内容

使用 caret 包比较 ROC 曲线

在前面的章节中,我们介绍了许多分类方法;每种方法都有其自身的优缺点。然而,当涉及到如何选择最佳拟合模型的问题时,您需要比较来自不同预测模型生成的所有性能指标。为了使比较变得容易,caret包允许我们生成并比较模型的性能。在本例中,我们将使用caret包提供的函数来比较在同一数据集上训练的不同算法模型。

准备工作

在这里,我们将继续使用 telecom 数据集作为我们的输入数据源。

如何做...

执行以下步骤以生成每个拟合模型的 ROC 曲线:

  1. 安装并加载库,pROC

    > install.packages("pROC")
    > library("pROC")
    
    
  2. 设置训练控制,使用 3 次重复的 10 折交叉验证:

    > control = trainControl(method = "repeatedcv",
    +                            number = 10,
    +                            repeats = 3,
    +                            classProbs = TRUE,
    +                            summaryFunction = twoClassSummary)
    
    
  3. 然后,您可以使用glm在训练数据集上训练一个分类器:

    > glm.model= train(churn ~ .,
    +                     data = trainset,
    +                     method = "glm",
    +                     metric = "ROC",
    +                     trControl = control)
    
    
  4. 此外,您还可以使用svm在训练数据集上训练一个分类器:

    > svm.model= train(churn ~ .,
    +                   data = trainset,
    +                   method = "svmRadial",
    +                   metric = "ROC",
    +                   trControl = control)
    
    
  5. 为了查看rpart在训练数据上的表现,我们使用rpart函数:

    > rpart.model= train(churn ~ .,
    +                   data = trainset,
    +                   method = "rpart",
    +                   metric = "ROC",
    +                   trControl = control)
    
    
  6. 您可以根据不同的训练模型分别进行预测:

    > glm.probs = predict(glm.model, testset[,! names(testset) %in% c("churn")], type = "prob")
    > svm.probs = predict(svm.model, testset[,! names(testset) %in% c("churn")], type = "prob")
    > rpart.probs = predict(rpart.model, testset[,! names(testset) %in% c("churn")], type = "prob")
    
    
  7. 您可以为每个模型生成 ROC 曲线,并在同一图上绘制曲线:

    > glm.ROC = roc(response = testset[,c("churn")],
    +                predictor =glm.probs$yes,
    +                levels = levels(testset[,c("churn")]))
    > plot(glm.ROC, type="S", col="red") 
    
    Call:
    roc.default(response = testset[, c("churn")], predictor = glm.probs$yes,     levels = levels(testset[, c("churn")]))
    
    Data: glm.probs$yes in 141 controls (testset[, c("churn")] yes) > 877 cases (testset[, c("churn")] no).
    Area under the curve: 0.82
    
    > svm.ROC = roc(response = testset[,c("churn")],
    +                predictor =svm.probs$yes,
    +                levels = levels(testset[,c("churn")]))
    > plot(svm.ROC, add=TRUE, col="green") 
    
    Call:
    roc.default(response = testset[, c("churn")], predictor = svm.probs$yes,     levels = levels(testset[, c("churn")]))
    
    Data: svm.probs$yes in 141 controls (testset[, c("churn")] yes) > 877 cases (testset[, c("churn")] no).
    Area under the curve: 0.9233
    
    > rpart.ROC = roc(response = testset[,c("churn")],
    +                predictor =rpart.probs$yes,
    +                levels = levels(testset[,c("churn")]))
    > plot(rpart.ROC, add=TRUE, col="blue")
    
    Call:
    roc.default(response = testset[, c("churn")], predictor = rpart.probs$yes,     levels = levels(testset[, c("churn")]))
    
    Data: rpart.probs$yes in 141 controls (testset[, c("churn")] yes) > 877 cases (testset[, c("churn")] no).
    Area under the curve: 0.7581
    
    

    如何做...

    图 7:三个分类器性能的 ROC 曲线

它是如何工作的...

在这里,我们通过展示如何在一张图上绘制它们的 ROC 曲线来说明我们如何比较拟合模型。首先,我们通过在twoClassSummary中进行性能评估,使用 10 折交叉验证和 3 次重复来设置训练过程的控制。在设置好训练过程的控制后,我们接着在训练数据集上应用glmsvmrpart算法来拟合分类模型。接下来,我们可以基于每个生成的模型进行预测并分别绘制 ROC 曲线。在生成的图中,我们发现由 svm 训练的模型具有最大的曲线下面积,为 0.9233(用绿色绘制),glm模型的 AUC 为 0.82,rpart模型的 AUC 为 0.7581。从图 7中可以看出,svm在此训练数据集上(无需调整)的所有拟合模型中表现最佳。

参见

  • 我们使用另一个 ROC 可视化包pROC,它可以用来显示和分析 ROC 曲线。如果您想了解更多关于这个包的信息,请使用help函数:

    > help(package="pROC")
    
    

使用 caret 包测量模型之间的性能差异

在之前的步骤中,我们介绍了如何为每个生成的模型生成 ROC 曲线,并将曲线绘制在同一张图上。除了使用 ROC 曲线外,还可以使用重采样方法来生成每个拟合模型在 ROC、敏感性和特异性指标中的统计数据。因此,我们可以使用这些统计数据来比较每个模型之间的性能差异。在接下来的步骤中,我们将介绍如何使用caret包来测量拟合模型之间的性能差异。

准备工作

需要完成之前的步骤,将glm拟合模型、svm拟合模型和rpart拟合模型分别存储到glm.modelsvm.modelrpart.model中。

如何做...

执行以下步骤来测量每个拟合模型之间的性能差异:

  1. 重采样三个生成的模型:

    > cv.values = resamples(list(glm = glm.model, svm=svm.model, rpart = rpart.model))
    
    
  2. 然后,您可以获得重采样结果的摘要:

    > summary(cv.values)
    
    Call:
    summary.resamples(object = cv.values)
    
    Models: glm, svm, rpart 
    Number of resamples: 30 
    
    ROC 
     Min. 1st Qu. Median   Mean 3rd Qu.   Max. NA's
    glm   0.7206  0.7847 0.8126 0.8116  0.8371 0.8877    0
    svm   0.8337  0.8673 0.8946 0.8929  0.9194 0.9458    0
    rpart 0.2802  0.7159 0.7413 0.6769  0.8105 0.8821    0
    
    Sens 
     Min. 1st Qu. Median   Mean 3rd Qu.   Max. NA's
    glm   0.08824  0.2000 0.2286 0.2194  0.2517 0.3529    0
    svm   0.44120  0.5368 0.5714 0.5866  0.6424 0.7143    0
    rpart 0.20590  0.3742 0.4706 0.4745  0.5929 0.6471    0
    
    Spec 
     Min. 1st Qu. Median   Mean 3rd Qu.   Max. NA's
    glm   0.9442  0.9608 0.9746 0.9701  0.9797 0.9949    0
    svm   0.9442  0.9646 0.9746 0.9740  0.9835 0.9949    0
    rpart 0.9492  0.9709 0.9797 0.9780  0.9848 0.9949    0
    
    
  3. 使用dotplot在 ROC 指标中绘制重采样结果:

    > dotplot(cv.values, metric = "ROC")
    
    

    如何做...

    图 8:ROC 指标中重采样结果的点图

  4. 此外,您还可以使用箱线图来绘制重采样结果:

    > bwplot(cv.values, layout = c(3, 1))
    
    

    如何做...

    图 9:重采样结果的箱线图

它是如何工作的...

在这个菜谱中,我们展示了如何使用重采样方法来衡量三个拟合模型之间的性能差异。首先,我们使用 resample 函数生成每个拟合模型(svm.modelglm.modelrpart.model)的统计数据。然后,我们可以使用 summary 函数获取这三个模型在 ROC、敏感性和特异性指标中的统计数据。接下来,我们可以在重采样结果上应用 dotplot 来查看 ROC 在不同模型之间的变化情况。最后,我们使用箱线图在重采样结果上展示不同模型在 ROC、敏感性和特异性指标上的箱线图。

参见

  • 除了使用 dotplotbwplot 来衡量性能差异外,还可以使用 densityplotsplomxyplot 来可视化每个拟合模型在 ROC、敏感性和特异性指标中的性能差异。

第八章:集成学习

在本章中,我们将涵盖以下主题:

  • 使用 Bagging 方法分类数据

  • 使用 Bagging 方法进行交叉验证

  • 使用 Boosting 方法分类数据

  • 使用 Boosting 方法进行交叉验证

  • 使用梯度提升分类数据

  • 计算分类器的边缘

  • 计算集成方法的误差演变

  • 使用随机森林分类数据

  • 估计不同分类器的预测误差

简介

集成学习是一种将不同学习器产生的结果组合成一种格式的方法,目的是产生更好的分类结果和回归结果。在前面的章节中,我们讨论了几种分类方法。这些方法采取不同的方法,但它们都有相同的目标,即找到最优的分类模型。然而,单个分类器可能是不完美的,它可能在某些类别中错误地分类数据。由于并非所有分类器都是不完美的,因此更好的方法是通过对结果进行平均投票。换句话说,如果我们对每个分类器相同的输入的预测结果进行平均,我们可能创建一个比使用单个方法更好的模型。

在集成学习中,Bagging、Boosting 和随机森林是三种最常用的方法:

  • Bagging 是一种投票方法,它首先使用 Bootstrap 生成不同的训练集,然后使用该训练集来制作不同的基础学习器。Bagging 方法采用基础学习器的组合来做出更好的预测。

  • Boosting 与 Bagging 方法类似。然而,使 Boosting 与众不同的地方在于它首先按顺序构建基础学习器,其中每个后续学习器都是为了构建前一个学习器的预测残差。通过创建互补学习者的手段,它使用先前学习者的错误来训练下一个基础学习器。

  • 随机森林使用来自许多分类树的投票结果。这个想法很简单;单个分类树将使用单个输入向量获得单个分类结果。然而,随机森林生长了许多分类树,从单个输入中获得多个结果。因此,随机森林将使用所有决策树中的多数投票来分类数据或使用平均输出进行回归。

在下面的菜谱中,我们将讨论如何使用 Bagging 和 Boosting 来分类数据。然后我们可以进行交叉验证来估计每个分类器的错误率。除此之外,我们还将介绍使用边缘来衡量模型确定性的方法。接下来,我们将介绍类似于 Bagging 和 Boosting 方法的随机森林,并介绍如何训练模型来分类数据以及如何使用边缘来估计模型确定性。最后,我们将演示如何估计每个分类器的错误率,并使用错误率来比较不同分类器的性能。

使用 bagging 方法对数据进行分类

adabag包实现了提升和 bagging 方法。对于 bagging 方法,该包实现了 Breiman 的 Bagging 算法,该算法首先生成多个分类器的多个版本,然后获得一个聚合分类器。在这个菜谱中,我们将说明如何使用adabag中的 bagging 方法来使用电信churn数据集生成分类模型。

准备工作

在这个菜谱中,我们继续使用电信churn数据集作为 bagging 方法的输入数据源。对于那些尚未准备数据集的人,请参阅第五章, 分类(I) – 树、懒惰和概率分类,获取详细信息。

如何操作...

执行以下步骤以生成电信churn数据集的分类模型:

  1. 首先,你需要安装并加载adabag包(安装adabag可能需要一段时间):

    > install.packages("adabag")
    > library(adabag)
    
    
  2. 接下来,你可以使用bagging函数来训练一个训练数据集(训练过程中结果可能会有所不同):

    > set.seed(2)
    > churn.bagging = bagging(churn ~ ., data=trainset, mfinal=10)
    
    
  3. 从 bagging 结果中获取变量重要性:

    > churn.bagging$importance
     international_plan number_customer_service_calls 
     10.4948380                    16.4260510 
     number_vmail_messages               total_day_calls 
     0.5319143                     0.3774190 
     total_day_charge             total_day_minutes 
     0.0000000                    28.7545042 
     total_eve_calls              total_eve_charge 
     0.1463585                     0.0000000 
     total_eve_minutes              total_intl_calls 
     14.2366754                     8.7733895 
     total_intl_charge            total_intl_minutes 
     0.0000000                     9.7838256 
     total_night_calls            total_night_charge 
     0.4349952                     0.0000000 
     total_night_minutes               voice_mail_plan 
     2.3379622                     7.7020671 
    
    
  4. 在生成分类模型后,你可以使用测试数据集的预测结果:

    > churn.predbagging= predict.bagging(churn.bagging, newdata=testset)
    
    
  5. 从预测结果中,你可以获得一个分类表:

    > churn.predbagging$confusion
     Observed Class
    Predicted Class yes  no
     no   35 866
     yes 106  11
    
    
  6. 最后,你可以检索 bagging 结果的平均误差:

    > churn.predbagging$error
    [1] 0.0451866
    
    

如何工作...

Bagging 来源于 Bootstrap aggregating(自助聚合)的名字,这是一种稳定、准确且易于实现的数据分类和回归模型。Bagging 的定义如下:给定一个大小为n的训练数据集,bagging 执行 Bootstrap 抽样并生成m个新的训练集,Di,每个大小为n。最后,我们可以将m个 Bootstrap 样本拟合到m个模型中,并通过平均输出(对于回归)或投票(对于分类)来组合结果:

如何工作...

bagging 方法的示意图

使用 bagging 的优点是它是一种强大的学习方法,易于理解和实现。然而,这种技术的缺点是结果难以分析。

在这个菜谱中,我们使用adabag中的提升方法对电信客户流失数据进行分类。类似于前面章节中讨论的其他分类方法,你可以使用公式和训练数据集来训练一个提升分类器。此外,你可以在mfinal参数中将迭代次数设置为 10。一旦构建了分类模型,你可以检查每个属性的重要性。按重要性对属性进行排序显示,客户服务电话的数量在分类模型中起着至关重要的作用。

接下来,使用拟合好的模型,您可以应用predict.bagging函数来预测测试数据集的标签。因此,您可以使用测试数据集的标签和预测结果来生成分类表并获取平均误差,在这个例子中为 0.045。

还有更多...

除了adabagipred包还提供了一个用于分类树的袋装方法。在这里,我们演示如何使用ipred包的袋装方法来训练一个分类模型:

  1. 首先,您需要安装并加载ipred包:

    > install.packages("ipred")
    > library(ipred)
    
    
  2. 然后,您可以使用bagging方法来拟合分类方法:

    > churn.bagging = bagging(churn ~ ., data = trainset, coob = T)
    > churn.bagging
    
    Bagging classification trees with 25 bootstrap replications 
    
    Call: bagging.data.frame(formula = churn ~ ., data = trainset, coob = T)
    
    Out-of-bag estimate of misclassification error:  0.0605 
    
    
  3. 获取错误分类的出袋估计:

    > mean(predict(churn.bagging) != trainset$churn)
    [1] 0.06047516
    
    
  4. 然后,您可以使用predict函数来获取测试数据集的预测标签:

    > churn.prediction = predict(churn.bagging, newdata=testset, type="class")
    
    
  5. 从测试数据集的标签和预测结果中获取分类表:

    > prediction.table = table(churn.prediction, testset$churn)
    
    churn.prediction yes  no
     no   31 869
     yes 110   8
    
    

使用袋装方法进行交叉验证

为了评估分类器的预测能力,您可以运行交叉验证方法来测试分类模型的鲁棒性。在这个菜谱中,我们将介绍如何使用bagging.cv来执行带有袋装方法的交叉验证。

准备工作

在这个菜谱中,我们继续使用 telecom churn数据集作为输入数据源,使用袋装方法进行 k 折交叉验证。

如何做...

通过使用袋装方法进行交叉验证来执行以下步骤以检索最小估计误差:

  1. 首先,我们使用bagging.cv在训练数据集上进行 10 次迭代的 10 折分类:

    > churn.baggingcv = bagging.cv(churn ~ ., v=10, data=trainset, mfinal=10)
    
    
  2. 然后,您可以从交叉验证结果中获取混淆矩阵:

    > churn.baggingcv$confusion
     Observed Class
    Predicted Class  yes   no
     no   100 1938
     yes  242   35
    
    
  3. 最后,您可以从交叉验证结果中检索最小估计误差:

    > churn.baggingcv$error
    [1] 0.05831533
    
    

工作原理...

adabag包提供了一个函数来执行带有袋装或提升方法的 k 折验证。在这个例子中,我们使用bagging.cv来使用袋装方法进行 k 折交叉验证。我们首先通过指定v=10mfinal=10进行 10 次迭代的 10 折交叉验证。请注意,由于迭代次数较多,这相当耗时。交叉验证过程完成后,我们可以从交叉验证结果中获得混淆矩阵和平均误差(在这种情况下为 0.058)。

参见

  • 对于那些想要调整bagging.cv参数的人来说,请使用help函数查看bagging.cv文档:

    > help(bagging.cv)
    
    

使用提升方法进行数据分类

与袋装法类似,提升法从简单或弱分类器开始,通过重新加权误分类样本逐渐改进它。因此,新的分类器可以从前一个分类器中学习。adabag包提供了AdaBoost.M1SAMME算法的实现。因此,可以使用adabag中的提升方法进行集成学习。在本菜谱中,我们将使用adabag中的提升方法对电信churn数据集进行分类。

准备工作

在本菜谱中,我们将继续使用电信churn数据集作为输入数据源,使用提升法进行分类。此外,在开始菜谱之前,您需要将adabag包加载到 R 中。

如何操作...

执行以下步骤,使用提升法对电信churn数据集进行分类:

  1. 您可以使用adabag包中的提升函数来训练分类模型:

    > set.seed(2)
    > churn.boost = boosting(churn ~.,data=trainset,mfinal=10, coeflearn="Freund", boos=FALSE , control=rpart.control(maxdepth=3))
    
    
  2. 然后,您可以根据提升模型和测试数据集进行预测:

    > churn.boost.pred = predict.boosting(churn.boost,newdata=testset)
    
    
  3. 接下来,您可以从预测结果中检索分类表:

    > churn.boost.pred$confusion
     Observed Class
    Predicted Class yes  no
     no   41 858
     yes 100  19
    
    
  4. 最后,您可以从预测结果中获得平均误差:

    > churn.boost.pred$error
    [1] 0.0589391
    
    

它是如何工作的...

提升法的思想是将弱学习器(例如单个决策树)提升为强学习器。假设我们的训练数据集中有n个点,我们可以为每个点分配一个权重,Wi(0 <= i < n)。然后,在迭代学习过程中(我们假设迭代次数为m),我们可以根据每次迭代的分类结果重新加权每个点。如果点被正确分类,我们应该减少权重。否则,我们增加该点的权重。当迭代过程完成后,我们可以获得m个拟合模型,fi(0 <= i < n)。最后,我们可以通过每个树的预测的加权平均获得最终预测,其中权重 b 基于每个树的质量:

如何工作...

提升法的示意图

无论是袋装法(bagging)还是提升法(boosting),它们都是集成方法,将每个单个学习器的预测能力结合成一个强大的学习器。袋装法和提升法之间的区别在于,袋装法结合了独立的模型,而提升法通过迭代过程,通过后续模型预测先前模型的错误来减少错误。

在这个菜谱中,我们展示了如何在提升方法内拟合分类模型。类似于袋装法,必须指定用于训练分类模型的公式和训练数据集。此外,还可以指定参数,例如迭代次数(mfinal)、权重更新系数(coeflearn)、每个观测值的权重(boos)以及rpart(单个决策树)的控制。在这个菜谱中,我们将迭代次数设置为 10,使用Freund(Adaboost.M1 算法实现的方法)作为coeflearn,将boos设置为 false,并将rpart配置的最大深度设置为3

我们使用提升方法拟合分类模型,并将其保存在churn.boost中。然后,我们可以使用prediction函数获取预测标签。此外,我们可以使用table函数根据预测标签和测试数据集标签检索分类表。最后,我们可以获取预测结果的平均误差。

更多...

除了在adabag包中使用提升函数外,还可以使用caret包通过提升方法进行分类:

  1. 首先,加载mboostpROC包:

    > library(mboost)
    > install.packages("pROC")
    > library(pROC)
    
    
  2. 然后,我们可以使用trainControl函数设置训练控制,并使用train函数使用 adaboost 训练分类模型:

    > set.seed(2)
    > ctrl = trainControl(method = "repeatedcv", repeats = 1, classProbs = TRUE, summaryFunction = twoClassSummary)
    > ada.train = train(churn ~ ., data = trainset, method = "ada", metric = "ROC", trControl = ctrl)
    
    
  3. 使用summary函数获取分类模型的详细信息:

    > ada.train$result
     nu maxdepth iter       ROC      Sens        Spec      ROCSD     SensSD      SpecSD
    1 0.1        1   50 0.8571988 0.9152941 0.012662155 0.03448418 0.04430519 0.007251045
    4 0.1        2   50 0.8905514 0.7138655 0.006083679 0.03538445 0.10089887 0.006236741
    7 0.1        3   50 0.9056456 0.4036134 0.007093780 0.03934631 0.09406015 0.006407402
    2 0.1        1  100 0.8550789 0.8918487 0.015705276 0.03434382 0.06190546 0.006503191
    5 0.1        2  100 0.8907720 0.6609244 0.009626724 0.03788941 0.11403364 0.006940001
    8 0.1        3  100 0.9077750 0.3832773 0.005576065 0.03601187 0.09630026 0.003738978
    3 0.1        1  150 0.8571743 0.8714286 0.016720505 0.03481526 0.06198773 0.006767313
    6 0.1        2  150 0.8929524 0.6171429 0.011654617 0.03638272 0.11383803 0.006777465
    9 0.1        3  150 0.9093921 0.3743697 0.007093780 0.03258220 0.09504202 0.005446136
    
    
  4. 使用plot函数在不同迭代中绘制 ROC 曲线:

    > plot(ada.train)
    
    

    更多...

    重复交叉验证图

  5. 最后,我们可以使用predict函数进行预测,并查看分类表:

    > ada.predict = predict(ada.train, testset, "prob")
    > ada.predict.result = ifelse(ada.predict[1] > 0.5, "yes", "no")
    
    > table(testset$churn, ada.predict.result)
     ada.predict.result
     no yes
     yes  40 101
     no  872   5
    
    

使用提升方法进行交叉验证

类似于bagging函数,adabag为提升方法提供了一个交叉验证函数,名为boosting.cv。在这个菜谱中,我们将演示如何使用adabag包中的boosting.cv进行交叉验证。

准备工作

在这个菜谱中,我们继续使用电信churn数据集作为输入数据源,使用boosting方法进行 k 折交叉验证。

如何做...

通过使用boosting方法进行交叉验证,执行以下步骤以检索最小估计误差:

  1. 首先,你可以使用boosting.cv对训练数据集进行交叉验证:

    > churn.boostcv = boosting.cv(churn ~ ., v=10, data=trainset, mfinal=5,control=rpart.control(cp=0.01))
    
    
  2. 然后,你可以从提升结果中获得混淆矩阵:

    > churn.boostcv$confusion
     Observed Class
    Predicted Class  yes   no
     no   119 1940
     yes  223   33
    
    
  3. 最后,你可以检索提升方法的平均误差:

    > churn.boostcv$error
    [1] 0.06565875
    
    

它是如何工作的...

类似于bagging.cv,我们可以使用boosting.cv在提升方法中进行交叉验证。如果将v设置为10,将mfinal设置为5,则提升方法将执行 10 次交叉验证,每次迭代 5 次。此外,还可以在参数内设置rpart拟合的控制。在这个例子中,我们可以将复杂性参数设置为 0.01。一旦训练完成,将获得提升结果的混淆矩阵和平均误差。

参见

  • 对于需要更多关于调整boosting.cv参数信息的人,请使用help函数查看boosting.cv文档:

    > help(boosting.cv)
    
    

使用梯度提升法分类数据

梯度提升集成弱学习器并创建一个与损失函数的负梯度最大相关的新基学习器。可以将此方法应用于回归或分类问题,并且在不同数据集上表现良好。在本菜谱中,我们将介绍如何使用gbm对电信churn数据集进行分类。

准备工作

在这个菜谱中,我们继续使用电信churn数据集作为bagging方法的输入数据源。对于那些尚未准备数据集的人,请参阅第五章,分类(I)-树、懒惰和概率性,以获取详细信息。

如何做

执行以下步骤以使用梯度提升法计算和分类数据:

  1. 首先,安装并加载gbm包:

    > install.packages("gbm")
    > library(gbm)
    
    
  2. gbm函数只使用从01的响应;因此,你应该将是/否响应转换为数值响应(0/1):

    > trainset$churn = ifelse(trainset$churn == "yes", 1, 0)
    
    
  3. 接下来,你可以使用gbm函数来训练一个训练数据集:

    > set.seed(2)
    > churn.gbm = gbm(formula = churn ~ .,distribution = "bernoulli",data = trainset,n.trees = 1000,interaction.depth = 7,shrinkage = 0.01, cv.folds=3)
    
    
  4. 然后,你可以从拟合模型中获取摘要信息:

    > summary(churn.gbm)
     var    rel.inf
    total_day_minutes          total_day_minutes 28.1217147
    total_eve_minutes                total_eve_minutes 16.8097151
    number_customer_service_calls number_customer_service_calls 12.7894464
    total_intl_minutes             total_intl_minutes  9.4515822
    total_intl_calls                   total_intl_calls  8.1379826
    international_plan               international_plan  8.0703900
    total_night_minutes             total_night_minutes  4.0805153
    number_vmail_messages         number_vmail_messages  3.9173515
    voice_mail_plan                  voice_mail_plan  2.5501480
    total_night_calls              total_night_calls  2.1357970
    total_day_calls                     total_day_calls  1.7367888
    total_eve_calls                     total_eve_calls  1.4398047
    total_eve_charge                 total_eve_charge  0.5457486
    total_night_charge              total_night_charge  0.2130152
    total_day_charge                total_day_charge  0.0000000
    total_intl_charge                 total_intl_charge  0.0000000
    
    

    如何做...

    拟合模型的相对影响图

  5. 你可以使用交叉验证获得最佳迭代次数:

    > churn.iter = gbm.perf(churn.gbm,method="cv")
    
    

    如何做...

    性能测量图

  6. 然后,你可以检索伯努利损失函数返回的对数中的奇数值:

    > churn.predict = predict(churn.gbm, testset, n.trees = churn.iter)
    > str(churn.predict)
     num [1:1018] -3.31 -2.91 -3.16 -3.47 -3.48 ...
    
    
  7. 接下来,你可以绘制 ROC 曲线并获取具有最大准确性的最佳截止值:

    > churn.roc = roc(testset$churn, churn.predict)
    > plot(churn.roc)
    Call:
    roc.default(response = testset$churn, predictor = churn.predict)
    Data: churn.predict in 141 controls (testset$churn yes) > 877 cases (testset$churn no).
    Area under the curve: 0.9393
    
    

    如何做...

    拟合模型的 ROC 曲线

  8. 你可以使用coords函数检索最佳截止值并使用此截止值来获取预测标签:

    > coords(churn.roc, "best")
     threshold specificity sensitivity 
     -0.9495258   0.8723404   0.9703535 
    > churn.predict.class = ifelse(churn.predict > coords(churn.roc, "best")["threshold"], "yes", "no")
    
    
  9. 最后,你可以从预测结果中获得分类表:

    > table( testset$churn,churn.predict.class)
     churn.predict.class
     no yes
     yes  18 123
     no  851  26
    
    

它是如何工作的...

梯度提升算法涉及的过程,首先计算每个分区的残差偏差,然后确定每个阶段的最佳数据分区。接下来,连续的模型将拟合前一阶段的残差并构建一个新的模型以减少残差方差(一个误差)。残差方差的减少遵循功能梯度下降技术,通过沿着其导数下降来最小化残差方差,如下所示:

它是如何工作的...

梯度下降法

在这个菜谱中,我们使用gbm中的梯度提升方法对电信客户流失数据集进行分类。为了开始分类,我们首先安装并加载gbm包。然后,我们使用gbm函数来训练分类模型。在这里,由于我们的预测目标是churn属性,这是一个二元结果,因此我们在distribution参数中将分布设置为bernoulli。此外,我们在n.tree参数中将 1000 棵树设置为拟合,在interaction.depth中将变量交互的最大深度设置为7,在shrinkage中将步长减少的学习率设置为 0.01,在cv.folds中将交叉验证的次数设置为3。模型拟合后,我们可以使用summary函数从表中获取每个变量的相对影响信息,并从图表中获取。相对影响显示了每个变量在平方误差和中的减少量。在这里,我们可以找到total_day_minutes是减少损失函数的最有影响力的一个变量。

接下来,我们使用gbm.perf函数找到最佳迭代次数。在这里,我们通过指定method参数为cv来进行交叉验证,以估计最佳迭代次数。该函数进一步生成两个图表,其中黑色线条表示训练误差,绿色线条表示验证误差。这里的误差测量是一个bernoulli分布,我们已经在训练阶段定义了它。图表上的蓝色虚线显示了最佳迭代的位置。

然后,我们使用predict函数从伯努利损失函数返回的每个测试案例中获取对数概率值。为了获得最佳的预测结果,可以将n.trees参数设置为最佳迭代次数。然而,由于返回值是对数概率值的奇数,我们仍然需要确定最佳的截止点来确定标签。因此,我们使用roc函数生成 ROC 曲线,并获取具有最大准确率的截止点。

最后,我们可以使用coords函数检索最佳截止阈值,并使用ifelse函数从对数概率值中确定类别标签。现在,我们可以使用table函数生成分类表,以查看分类模型的准确性。

还有更多...

除了在gbm包中使用提升函数外,还可以使用mboost包通过梯度提升方法进行分类:

  1. 首先,安装并加载mboost包:

    > install.packages("mboost")
    > library(mboost)
    
    
  2. mboost函数仅使用数值响应;因此,应将是/否响应转换为数值响应(0/1):

    > trainset$churn = ifelse(trainset$churn == "yes", 1, 0)
    
    
  3. 此外,还应删除非数值属性,例如voice_mail_planinternational_plan

    > trainset$voice_mail_plan = NULL
    > trainset$international_plan = NULL
    
    
  4. 然后,我们可以使用mboost来训练分类模型:

    > churn.mboost = mboost(churn ~ ., data=trainset,  control = boost_control(mstop = 10))
    
    
  5. 使用summary函数获取分类模型的详细信息:

    > summary(churn.mboost)
    
     Model-based Boosting
    
    Call:
    mboost(formula = churn ~ ., data = trainset, control = boost_control(mstop = 10))
    
     Squared Error (Regression) 
    
    Loss function: (y - f)² 
    
    Number of boosting iterations: mstop = 10 
    Step size:  0.1 
    Offset:  1.147732 
    Number of baselearners:  14 
    
    Selection frequencies:
     bbs(total_day_minutes) bbs(number_customer_service_calls) 
     0.6                                0.4 
    
    
  6. 最后,使用plot函数绘制每个属性的局部贡献图:

    > par(mfrow=c(1,2))
    > plot(churn.mboost)
    
    

    还有更多...

    重要属性的局部贡献图

计算分类器的边缘

边缘是分类确定性的度量。此方法计算正确类别的支持与错误类别的最大支持之间的差异。在本配方中,我们将演示如何计算生成的分类器的边缘。

准备工作

您需要完成前面的配方,将拟合的 bagging 模型存储在变量 churn.baggingchurn.predbagging 中。同时,将拟合的提升分类器放入 churn.boostchurn.boost.pred 中。

如何操作...

执行以下步骤以计算每个集成学习者的边缘:

  1. 首先,使用 margins 函数计算提升分类器的边缘:

    > boost.margins = margins(churn.boost, trainset)
    > boost.pred.margins = margins(churn.boost.pred, testset)
    
    
  2. 然后,您可以使用 plot 函数绘制提升分类器的边缘累积分布图:

    > plot(sort(boost.margins[[1]]), (1:length(boost.margins[[1]]))/length(boost.margins[[1]]), type="l",xlim=c(-1,1),main="Boosting: Margin cumulative distribution graph", xlab="margin", ylab="% observations", col = "blue")
    > lines(sort(boost.pred.margins[[1]]), (1:length(boost.pred.margins[[1]]))/length(boost.pred.margins[[1]]), type="l", col = "green")
    > abline(v=0, col="red",lty=2)
    
    

    如何操作...

    使用提升方法的边缘累积分布图

  3. 然后,您可以计算负边缘匹配训练错误的百分比和负边缘匹配测试错误的百分比:

    > boosting.training.margin = table(boost.margins[[1]] > 0)
    > boosting.negative.training = as.numeric(boosting.training.margin[1]/boosting.training.margin[2])
    > boosting.negative.training
     [1] 0.06387868
    
    > boosting.testing.margin = table(boost.pred.margins[[1]] > 0)
    > boosting.negative.testing = as.numeric(boosting.testing.margin[1]/boosting.testing.margin[2])
    > boosting.negative.testing
    [1] 0.06263048
    
    
  4. 此外,您还可以计算 bagging 分类器的边缘。您可能会看到显示 "no non-missing argument to min" 的警告信息。该信息仅表示 min/max 函数应用于长度为 0 的参数的数值:

    > bagging.margins = margins(churn.bagging, trainset)
    > bagging.pred.margins = margins(churn.predbagging, testset)
    
    
  5. 然后,您可以使用 plot 函数绘制 bagging 分类器的边缘累积分布图:

    > plot(sort(bagging.margins[[1]]), (1:length(bagging.margins[[1]]))/length(bagging.margins[[1]]), type="l",xlim=c(-1,1),main="Bagging: Margin cumulative distribution graph", xlab="margin", ylab="% observations", col = "blue")
    
    > lines(sort(bagging.pred.margins[[1]]), (1:length(bagging.pred.margins[[1]]))/length(bagging.pred.margins[[1]]), type="l", col = "green")
    > abline(v=0, col="red",lty=2)
    
    

    如何操作...

    bagging 方法的边缘累积分布图

  6. 最后,然后您可以计算负边缘匹配训练错误的百分比和负边缘匹配测试错误的百分比:

    > bagging.training.margin = table(bagging.margins[[1]] > 0)
    > bagging.negative.training = as.numeric(bagging.training.margin[1]/bagging.training.margin[2])
    > bagging.negative.training
    [1] 0.1733401
    
    > bagging.testing.margin = table(bagging.pred.margins[[1]] > 0)
    > bagging.negative.testing = as.numeric(bagging.testing.margin[1]/bagging.testing.margin[2])
    > bagging.negative.testing
    [1] 0.04303279
    
    

工作原理...

边缘是分类确定性的度量;它是通过正确类别的支持与错误类别的最大支持来计算的。边缘的公式可以表示为:

工作原理...

在这里,xi 样本的边缘等于正确分类样本的支持(c 表示正确类别)减去被分类到类别 j 的样本的最大支持(其中 j≠cj=1…k)。因此,正确分类的示例将具有正边缘,错误分类的示例将具有负边缘。如果边缘值接近 1,则表示正确分类的示例具有高度的置信度。另一方面,不确定分类的示例将具有较小的边缘。

margins函数计算 AdaBoost.M1、AdaBoost-SAMME 或袋装分类器的边缘,并返回一个边缘向量。为了可视化边缘分布,可以使用边缘累积分布图。在这些图中,x 轴表示边缘,y 轴表示边缘小于或等于 x 轴边缘值的观测值的百分比。如果每个观测值都被正确分类,则图表将在边缘等于 1 的位置显示一条垂直线(其中边缘=1)。

对于提升分类器的边缘累积分布图,我们可以看到图上有两条线,其中绿色线表示测试数据集的边缘,蓝色线表示训练集的边缘。图显示大约 6.39%的负边缘与训练错误匹配,6.26%的负边缘与测试错误匹配。另一方面,我们可以在袋装分类器的边缘累积分布图中找到,17.33%的负边缘与训练错误匹配,4.3%的负边缘与测试错误匹配。通常,匹配训练错误的负边缘百分比应该接近匹配测试错误的负边缘百分比。因此,我们应该检查为什么匹配训练错误的负边缘百分比远高于匹配测试错误的负边缘百分比。

参考内容

  • 如果您对边缘分布图有更多细节感兴趣,请参阅以下来源:Kuncheva LI (2004), Combining Pattern Classifiers: Methods and Algorithms, John Wiley & Sons

计算集成方法的错误演化

adabag包提供了一个errorevol函数,用户可以根据迭代次数估计集成方法错误。在这个配方中,我们将演示如何使用errorevol来展示每个集成分类器错误的演化。

准备工作

您需要完成上一个配方,将拟合的袋装模型存储在变量churn.bagging中。同时,将拟合的提升分类器放入churn.boost

如何做...

执行以下步骤来计算每个集成学习者的错误演化:

  1. 首先,使用errorevol函数来计算提升分类器的错误演化:

    > boosting.evol.train = errorevol(churn.boost, trainset)
    > boosting.evol.test = errorevol(churn.boost, testset)
    > plot(boosting.evol.test$error, type = "l", ylim = c(0, 1),
    +       main = "Boosting error versus number of trees", xlab = "Iterations",
    +       ylab = "Error", col = "red", lwd = 2)
    > lines(boosting.evol.train$error, cex = .5, col = "blue", lty = 2, lwd = 2)
    > legend("topright", c("test", "train"), col = c("red", "blue"), lty = 1:2, lwd = 2)
    
    

    如何做...

    提升错误与树的数量对比

  2. 接下来,使用errorevol函数来计算袋装分类器的错误演化:

    > bagging.evol.train = errorevol(churn.bagging, trainset)
    > bagging.evol.test = errorevol(churn.bagging, testset)
    > plot(bagging.evol.test$error, type = "l", ylim = c(0, 1),
    +       main = "Bagging error versus number of trees", xlab = "Iterations",
    +       ylab = "Error", col = "red", lwd = 2)
    > lines(bagging.evol.train$error, cex = .5, col = "blue", lty = 2, lwd = 2)
    > legend("topright", c("test", "train"), col = c("red", "blue"), lty = 1:2, lwd = 2)
    
    

    如何做...

    袋装错误与树的数量对比

它是如何工作的...

errorest函数计算 AdaBoost.M1、AdaBoost-SAMME 或袋装分类器的错误演化,并返回一个错误演化的向量。在这个配方中,我们使用提升和袋装模型生成错误演化向量,并绘制错误与树的数量对比图。

生成的图表揭示了每次迭代的错误率。错误率的变化趋势可以帮助衡量错误减少的速度,同时迭代次数增加。此外,图表可能显示模型是否过拟合。

相关内容

  • 如果集成模型过拟合,你可以使用predict.baggingpredict.boosting函数来修剪集成模型。更多信息,请使用帮助函数参考predict.baggingpredict.boosting

    > help(predict.bagging)
    > help(predict.boosting)
    
    

使用随机森林进行数据分类

随机森林是另一种有用的集成学习方法,在训练过程中会生成多个决策树。每个决策树将输出其对应的输入预测结果。森林将使用投票机制来选择得票最多的类别作为预测结果。在本教程中,我们将说明如何使用randomForest包进行数据分类。

准备工作

在本教程中,我们将继续使用电信churn数据集作为输入数据源,使用随机森林方法进行分类。

如何操作...

执行以下步骤以使用随机森林进行数据分类:

  1. 首先,你必须安装并加载randomForest包;

    > install.packages("randomForest")
    > library(randomForest)
    
    
  2. 然后,你可以使用训练集拟合随机森林分类器:

    > churn.rf = randomForest(churn ~ ., data = trainset, importance = T)
    > churn.rf
    
    Call:
     randomForest(formula = churn ~ ., data = trainset, importance = T) 
     Type of random forest: classification
     Number of trees: 500
    No. of variables tried at each split: 4
    
     OOB estimate of  error rate: 4.88%
    Confusion matrix:
     yes   no class.error
    yes 247   95 0.277777778
    no   18 1955 0.009123163
    
    
  3. 接下来,根据拟合模型和测试数据集进行预测:

    > churn.prediction = predict(churn.rf, testset)
    
    
  4. 与其他分类方法类似,你可以获得分类表:

    > table(churn.prediction, testset$churn)
    
    churn.prediction yes  no
     yes 110   7
     no   31 870
    
    
  5. 你可以使用plot函数绘制森林对象的均方误差:

    > plot(churn.rf)
    
    

    如何操作...

    随机森林的均方误差

  6. 然后,你可以检查拟合分类器中每个属性的重要性:

    > importance(churn.rf)
     yes         no
    international_plan            66.55206691 56.5100647
    voice_mail_plan               19.98337191 15.2354970
    number_vmail_messages         21.02976166 14.0707195
    total_day_minutes             28.05190188 27.7570444
    
    
  7. 接下来,你可以使用varImpPlot函数获取变量重要性的绘图:

    > varImpPlot(churn.rf)
    
    

    如何操作...

    变量重要性的可视化

  8. 你还可以使用margin函数来计算边缘并绘制边缘累积分布图:

    > margins.rf=margin(churn.rf,trainset)
    > plot(margins.rf)
    
    

    如何操作...

    随机森林方法的边缘累积分布图

  9. 此外,你可以使用直方图来可视化随机森林的边缘分布:

    > hist(margins.rf,main="Margins of Random Forest for churn dataset")
    
    

    如何操作...

    边缘分布的直方图

  10. 你还可以使用boxplot通过类别可视化随机森林的边缘:

    > boxplot(margins.rf~trainset$churn, main="Margins of Random Forest for churn dataset by class")
    
    

    如何操作...

    随机森林的类别边缘

工作原理...

随机森林的目的是将弱学习器(例如单个决策树)集成到强学习器中。开发随机森林的过程与袋装法非常相似,假设我们有一个包含N个样本和M个特征的训练集。这个过程首先进行自助采样,随机抽取N个案例,作为每个单个决策树的训练数据集。接下来,在每个节点中,过程首先随机选择m个变量(其中m << M),然后找到在 m 个变量中提供最佳分割的预测变量。接下来,过程在不剪枝的情况下生长完整的树。最后,我们可以从每棵树中获得示例的预测结果。因此,我们可以通过对输出取平均或加权平均(对于回归)或取多数投票(对于分类)来获得预测结果:

如何工作...

随机森林使用两个参数:ntree(树的数量)和mtry(用于找到最佳特征的特性数量),而袋装法只使用 ntree 作为参数。因此,如果我们设置 mtry 等于训练数据集中的特性数量,那么随机森林就等同于袋装法。

随机森林的主要优点是它易于计算,可以高效地处理数据,并且对缺失或不平衡数据具有容错性。随机森林的主要缺点是它不能预测超出训练数据集范围的值。此外,它容易对噪声数据进行过拟合。

在这个菜谱中,我们使用来自randomForest包的随机森林方法来拟合分类模型。首先,我们在 R 会话中安装并加载randomForest。然后,我们使用随机森林方法训练分类模型。我们设置importance = T,这将确保评估预测变量的重要性。

与袋装法和提升法类似,一旦模型拟合完成,就可以在测试数据集上使用拟合的模型进行预测,并且还可以获得分类表。

为了评估每个属性的重要性,randomForest包提供了重要性和varImpPlot函数,既可以列出拟合模型中每个属性的重要性,也可以使用平均降低准确度或平均降低gini来可视化重要性。

与包含计算袋装法和提升法边缘方法的adabag类似,randomForest提供了margin函数来计算森林对象的边缘。使用plothistboxplot函数,你可以从不同方面可视化正确分类观察值的比例。

还有更多...

除了randomForest包之外,party包还提供了一个随机森林的实现。在以下步骤中,我们将展示如何在party包中使用cforest函数来进行分类:

  1. 首先,安装并加载party包:

    > install.packages("party")
    > library(party)
    
    
  2. 然后,你可以使用cforest函数来拟合分类模型:

    > churn.cforest = cforest(churn ~ ., data = trainset, controls=cforest_unbiased(ntree=1000, mtry=5))
    > churn.cforest
    
     Random Forest using Conditional Inference Trees
    
    Number of trees:  1000 
    
    Response:  churn 
    Inputs:  international_plan, voice_mail_plan, number_vmail_messages, total_day_minutes, total_day_calls, total_day_charge, total_eve_minutes, total_eve_calls, total_eve_charge, total_night_minutes, total_night_calls, total_night_charge, total_intl_minutes, total_intl_calls, total_intl_charge, number_customer_service_calls 
    Number of observations:  2315 
    
    
  3. 你可以根据构建的模型和测试数据集进行预测:

    > churn.cforest.prediction = predict(churn.cforest, testset, OOB=TRUE, type = "response")
    
    
  4. 最后,从预测标签和测试数据集的标签中获取分类表:

    > table(churn.cforest.prediction, testset$churn)
    
    churn.cforest.prediction yes  no
     yes  91   3
     no   50 874
    
    

估计不同分类器的预测误差

在本章开头,我们讨论了为什么使用集成学习以及它如何与仅使用单个分类器相比提高预测性能。我们现在通过比较每种方法的性能来验证集成模型是否比单个决策树表现更好。为了比较不同的分类器,我们可以对每种分类方法进行 10 折交叉验证,使用ipred包中的erroreset来估计测试误差。

准备工作

在这个菜谱中,我们将继续使用电信churn数据集作为输入数据源来估计不同分类器的预测误差。

如何操作...

执行以下步骤来估计每种分类方法的预测误差:

  1. 你可以估计袋装模型的错误率:

    > churn.bagging= errorest(churn ~ ., data = trainset, model = bagging)
    > churn.bagging
    
    Call:
    errorest.data.frame(formula = churn ~ ., data = trainset, model = bagging)
    
     10-fold cross-validation estimator of misclassification error 
    
    Misclassification error:  0.0583 
    
    
  2. 然后,你可以估计提升方法的错误率:

    > install.packages("ada")
    > library(ada)
    > churn.boosting= errorest(churn ~ ., data = trainset, model = ada)
    > churn.boosting
    
    Call:
    errorest.data.frame(formula = churn ~ ., data = trainset, model = ada)
    
     10-fold cross-validation estimator of misclassification error 
    
    Misclassification error:  0.0475 
    
    
  3. 接下来,估计随机森林模型的错误率:

    > churn.rf= errorest(churn ~ ., data = trainset, model = randomForest)
    > churn.rf
    
    Call:
    errorest.data.frame(formula = churn ~ ., data = trainset, model = randomForest)
    
     10-fold cross-validation estimator of misclassification error 
    
    Misclassification error:  0.051 
    
    
  4. 最后,使用churn.predict创建一个预测函数,然后使用该函数估计单个决策树的错误率:

    > churn.predict = function(object, newdata) {predict(object, newdata = newdata, type = "class")}
    > churn.tree= errorest(churn ~ ., data = trainset, model = rpart,predict = churn.predict)
    > churn.tree
    
    Call:
    errorest.data.frame(formula = churn ~ ., data = trainset, model = rpart, 
     predict = churn.predict)
    
     10-fold cross-validation estimator of misclassification error 
    
    Misclassification error:  0.0674 
    
    

工作原理...

在这个菜谱中,我们使用ipred包中的errorest函数来估计四种不同分类器的错误率。我们比较了提升、袋装和随机森林方法,以及单个决策树分类器。errorest函数对每个分类器进行 10 折交叉验证,并计算误分类误差。四个选择模型的估计结果显示,提升方法具有最低的错误率(0.0475)。随机森林方法具有第二低的错误率(0.051),而袋装方法的错误率为 0.0583。单个决策树分类器rpart在四种方法中表现最差,错误率等于 0.0674。这些结果表明,提升、袋装和随机森林这三种集成学习方法都优于单个决策树分类器。

相关内容

  • 在这个菜谱中,我们提到了ada包,它包含一个执行随机提升的方法。对那些对这个包感兴趣的人,请参阅:Friedman 等(2000)的《加性逻辑回归:提升的统计视角》

第九章。聚类

在本章中,我们将涵盖以下主题:

  • 使用层次聚类聚类数据

  • 将树木切割成簇

  • 使用 k-means 方法聚类数据

  • 绘制双变量簇图

  • 比较聚类方法

  • 从聚类中提取轮廓信息

  • 获取 k-means 的最佳簇

  • 使用基于密度的方法聚类数据

  • 使用基于模型的方法聚类数据

  • 可视化差异矩阵

  • 外部验证簇

简介

聚类是一种用于将相似对象(在距离上接近)分组到同一组(簇)中的技术。与前面章节中涵盖的监督学习方法(例如,分类和回归)不同,聚类分析不使用任何标签信息,而是简单地使用数据特征之间的相似性将它们分组到簇中。

聚类可以广泛应用于商业分析。例如,营销部门可以使用聚类根据个人属性对客户进行细分。因此,可以设计针对不同类型客户的差异化营销活动。

最常见的四种聚类方法为层次聚类、k-means 聚类、基于模型聚类和基于密度的聚类:

  • 层次聚类:它创建簇的层次结构,并以树状图的形式展示。这种方法在开始时不需要指定簇的数量。

  • k-means 聚类:也称为平面聚类。与层次聚类不同,它不创建簇的层次结构,并且需要一个输入的簇数量。然而,它的性能比层次聚类快。

  • 基于模型聚类:层次聚类和 k-means 聚类都使用启发式方法构建簇,并且不依赖于正式模型。基于模型聚类假设数据模型,并应用 EM 算法来找到最可能的模型组件和簇的数量。

  • 基于密度的聚类:它根据密度测量构建簇。这种方法中的簇比数据集的其余部分具有更高的密度。

在下面的菜谱中,我们将讨论如何使用这四种聚类技术来聚类数据。我们讨论了如何使用簇内平方和、平均轮廓宽度和外部真实情况来内部验证簇。

使用层次聚类聚类数据

层次聚类采用聚合或划分方法来构建簇的层次结构。无论采用哪种方法,两者首先都使用距离相似度度量来合并或分割簇。递归过程持续进行,直到只剩下一个簇或无法再分割簇。最终,我们可以使用树状图来表示簇的层次结构。在这个菜谱中,我们将演示如何使用层次聚类对客户进行聚类。

准备工作

在这个菜谱中,我们将对客户数据进行层次聚类,这涉及到将客户分割成不同的组。您可以从这个 GitHub 页面下载数据:github.com/ywchiu/ml_R_cookbook/tree/master/CH9

如何做...

执行以下步骤将客户数据聚类到簇的层次结构中:

  1. 首先,您需要从customer.csv加载数据并将其保存到customer中:

    > customer= read.csv('customer.csv', header=TRUE)
    > head(customer)
     ID Visit.Time Average.Expense Sex Age
    1  1          3             5.7   0  10
    2  2          5            14.5   0  27
    3  3         16            33.5   0  32
    4  4          5            15.9   0  30
    5  5         16            24.9   0  23
    6  6          3            12.0   0  15
    
    
  2. 然后,您可以检查数据集的结构:

    > str(customer)
    'data.frame':  60 obs. of  5 variables:
     $ ID             : int  1 2 3 4 5 6 7 8 9 10 ...
     $ Visit.Time     : int  3 5 16 5 16 3 12 14 6 3 ...
     $ Average.Expense: num  5.7 14.5 33.5 15.9 24.9 12 28.5 18.8 23.8 5.3 ...
     $ Sex            : int  0 0 0 0 0 0 0 0 0 0 ...
     $ Age            : int  10 27 32 30 23 15 33 27 16 11 ...
    
    
  3. 接下来,您应该将客户数据归一化到相同的尺度:

    > customer = scale(customer[,-1])
    
    
  4. 您可以使用聚合层次聚类对客户数据进行聚类:

    > hc = hclust(dist(customer, method="euclidean"), method="ward.D2")
    > hc
    
    Call:
    hclust(d = dist(customer, method = "euclidean"), method = "ward.D2")
    
    Cluster method   : ward.D2 
    Distance         : euclidean 
    Number of objects: 60
    
    
  5. 最后,您可以使用plot函数绘制树状图:

    > plot(hc, hang = -0.01, cex = 0.7)
    
    

    如何做...

    使用"ward.D2"的层次聚类树状图

  6. 此外,您可以使用单方法进行层次聚类,并查看生成的树状图与之前的区别:

    > hc2 = hclust(dist(customer), method="single")
    > plot(hc2, hang = -0.01, cex = 0.7)
    
    

    如何做...

    使用"single"的层次聚类树状图

如何工作...

层次聚类是一种聚类技术,它试图通过迭代构建簇的层次结构。通常,有两种方法来构建层次簇:

  • 聚合层次聚类:这是一种自下而上的方法。每个观测值最初都在自己的簇中。然后我们可以计算每个簇之间的相似度(或距离),并在每次迭代中将两个最相似的簇合并,直到只剩下一个簇。

  • 划分层次聚类:这是一种自上而下的方法。所有观测值最初都在一个簇中,然后我们递归地将簇分割成两个最不相似的簇,直到每个观测值对应一个簇:如何工作...

    层次聚类的示意图

在执行层次聚类之前,我们需要确定两个簇之间的相似度。在这里,我们列出了一些常用的相似度测量距离函数:

  • 单连接:这指的是每个簇中两点之间的最短距离:如何工作...

  • 完全连接:这指的是每个簇中两点之间的最长距离:如何工作...

  • 平均链接:这指的是每个簇中两点之间的平均距离(其中如何工作...是簇如何工作...的大小,而如何工作...是簇如何工作...的大小):如何工作...

  • 沃德方法:这指的是每个点到合并簇均值的平方距离之和(其中如何工作...如何工作...的均值向量):如何工作...

在本菜谱中,我们对客户数据进行层次聚类。首先,我们从customer.csv加载数据,然后将其加载到客户数据框中。在数据中,我们找到五个客户账户信息的变量,它们是 ID、访问次数、平均消费、性别和年龄。由于每个变量的尺度不同,我们使用尺度函数来归一化尺度。

在对所有属性的尺度进行归一化后,我们使用hclust函数执行层次聚类。我们使用欧几里得距离作为距离度量,并使用沃德的最小方差方法进行聚合聚类。

最后,我们使用plot函数绘制层次簇的树状图。我们指定hang以在树状图的底部显示标签,并使用cex将标签缩小到正常大小的 70%。为了比较使用ward.D2single方法生成的簇层次结构,我们在前面的图中使用single绘制另一个树状图(步骤 6)。

还有更多...

在执行层次聚类时,您可以选择不同的距离度量和方法。有关更多详细信息,您可以参考disthclust的文档:

> ? dist
> ? hclust

在本菜谱中,我们使用hclust执行聚合层次聚类;如果您想执行分裂层次聚类,可以使用diana函数:

  1. 首先,您可以使用diana执行分裂层次聚类:

    > dv = diana(customer, metric = "euclidean")
    
    
  2. 然后,您可以使用summary获取摘要信息:

    > summary(dv)
    
    
  3. 最后,您可以使用plot函数绘制树状图和横幅:

    > plot(dv)
    
    

如果您想绘制水平树状图,可以使用dendextend包。使用以下步骤生成水平树状图:

  1. 首先,安装并加载dendextendmagrittr包(如果您的 R 版本是 3.1 及以上,您不需要安装和加载magrittr包):

    > install.packages("dendextend")
    > library(dendextend)
    > install.packages("margrittr")
    > library(magrittr)
    
    
  2. 设置树状图:

    > dend = customer %>% dist %>% hclust %>% as.dendrogram
    
    
  3. 最后,绘制水平树状图:

    dend %>% plot(horiz=TRUE, main = "Horizontal Dendrogram")
    
    

    还有更多...

    水平树状图

将树切割成簇

在树状图中,我们可以看到簇的层次结构,但我们还没有将数据分组到不同的簇中。然而,我们可以确定树状图中有多少簇,并在某个树高切割树状图以将数据分离到不同的组中。在这个菜谱中,我们展示了如何使用cutree函数将数据分离成给定的簇数。

准备工作

为了执行cutree函数,你需要完成之前的步骤,通过生成 hclust 对象hc

如何做...

执行以下步骤将簇的层次结构切割成给定的簇数:

  1. 首先,将数据分类为四个组:

    > fit = cutree(hc, k = 4)
    
    
  2. 然后,你可以检查数据的簇标签:

    > fit
     [1] 1 1 2 1 2 1 2 2 1 1 1 2 2 1 1 1 2 1 2 3 4 3 4 3 3 4 4 3 4
    [30] 4 4 3 3 3 4 4 3 4 4 4 4 4 4 4 3 3 4 4 4 3 4 3 3 4 4 4 3 4
    [59] 4 3
    
    
  3. 计算每个簇内的数据数量:

    > table(fit)
    fit
     1  2  3  4 
    11  8 16 25 
    
    
  4. 最后,你可以使用红色矩形边框可视化数据的聚类情况:

    > plot(hc)
    > rect.hclust(hc, k = 4 , border="red")
    
    

    如何做...

    使用红色矩形边框来区分树状图中不同的簇

它是如何工作的...

我们可以从前一个图中的树状图中确定簇的数量。在这个菜谱中,我们确定树中应该有四个簇。因此,我们在cutree函数中将簇数指定为4。除了使用簇数来切割树,你还可以指定height作为切割树的参数。

接下来,我们可以输出数据的簇标签,并使用table函数计算每个簇内的数据数量。从计数表中,我们发现大部分数据都在簇 4 中。最后,我们可以使用rect.hclust函数在簇周围绘制红色矩形,以显示数据如何被分类到四个簇中。

还有更多...

除了在所有层次簇周围绘制矩形,你还可以在某个簇周围放置红色矩形:

> rect.hclust(hc, k = 4 , which =2, border="red")

还有更多...

在某个簇周围绘制红色矩形。

此外,你可以使用dendextend包通过在簇周围添加红色矩形以不同颜色着色簇。你必须完成前一个菜谱中还有更多部分中概述的说明,并执行以下步骤:

  1. 根据所属的簇给分支上色:

    > dend %>% color_branches(k=4) %>% plot(horiz=TRUE, main = "Horizontal Dendrogram")
    
    
  2. 然后,你可以在簇周围添加红色矩形:

    > dend %>% rect.dendrogram(k=4,horiz=TRUE)
    
    

    还有更多...

    在水平树状图中绘制簇周围的红色矩形

  3. 最后,你可以添加一条线来显示树木切割的位置:

    > abline(v = heights_per_k.dendrogram(dend)["4"] + .1, lwd = 2, lty = 2, col = "blue")
    
    

    还有更多...

    在水平树状图中绘制切割线

使用 k-means 方法聚类数据

k-means 聚类是一种平面聚类技术,它只产生一个包含 k 个聚类的分区。与不需要用户在开始时确定聚类数量的层次聚类不同,k-means 方法需要首先确定这一点。然而,由于构建层次树非常耗时,k-means 聚类比层次聚类快得多。在本食谱中,我们将演示如何在客户数据集上执行 k-means 聚类。

准备工作

在本食谱中,我们将继续使用客户数据集作为输入数据源来执行 k-means 聚类。

如何操作...

按以下步骤使用 k-means 方法对 customer 数据集进行聚类:

  1. 首先,您可以使用 kmeans 对客户数据进行聚类:

    > set.seed(22)
    > fit = kmeans(customer, 4)
    > fit
    K-means clustering with 4 clusters of sizes 8, 11, 16, 25
    
    Cluster means:
     Visit.Time Average.Expense        Sex        Age
    1  1.3302016       1.0155226 -1.4566845  0.5591307
    2 -0.7771737      -0.5178412 -1.4566845 -0.4774599
    3  0.8571173       0.9887331  0.6750489  1.0505015
    4 -0.6322632      -0.7299063  0.6750489 -0.6411604
    
    Clustering vector:
     [1] 2 2 1 2 1 2 1 1 2 2 2 1 1 2 2 2 1 2 1 3 4 3 4 3 3 4 4 3
    [29] 4 4 4 3 3 3 4 4 3 4 4 4 4 4 4 4 3 3 4 4 4 3 4 3 3 4 4 4
    [57] 3 4 4 3
    
    Within cluster sum of squares by cluster:
    [1]  5.90040 11.97454 22.58236 20.89159
     (between_SS / total_SS =  74.0 %)
    
    Available components:
    
    [1] "cluster"      "centers"      "totss" 
    [4] "withinss"     "tot.withinss" "betweenss" 
    [7] "size"         "iter"         "ifault
    
    
  2. 您可以使用 barplot 检查每个聚类的中心:

    > barplot(t(fit$centers), beside = TRUE,xlab="cluster", ylab="value")
    
    

    如何操作...

    四个聚类中不同属性的中心的条形图

  3. 最后,您可以在数据上绘制散点图,并根据聚类对点进行着色:

    > plot(customer, col = fit$cluster)
    
    

    如何操作...

    显示数据根据其聚类标签着色的散点图

工作原理...

k-means 聚类是一种分区聚类方法。算法的目标是将 n 个对象划分为 k 个聚类,其中每个对象属于最近的均值所在的聚类。算法的目标是最小化 聚类内平方和WCSS)。假设 x 是给定的观察值集合,S = 工作原理... 表示 k 个分区,而 工作原理...工作原理... 的均值,那么我们可以将 WCSS 函数表述如下:

工作原理...

k-means 聚类的过程可以通过以下五个步骤来表示:

  1. 指定 k 个聚类的数量。

  2. 随机创建 k 个分区。

  3. 计算分区中心。

  4. 将对象与聚类中心最接近的关联起来。

  5. 重复步骤 2、3 和 4,直到 WCSS 变化很小(或是最小化)。

在本食谱中,我们展示了如何使用 k-means 聚类对客户数据进行聚类。与层次聚类不同,k-means 聚类需要用户输入 K 的数量。在本例中,我们使用 K=4。然后,拟合模型的输出显示了每个聚类的规模、四个生成聚类的聚类均值、每个数据点的聚类向量、聚类内的平方和以及其他可用组件。

此外,您可以在条形图中绘制每个聚类的中心,这将提供更多关于每个属性如何影响聚类的细节。最后,我们在散点图中绘制数据点,并使用拟合的聚类标签根据聚类标签分配颜色。

相关内容

  • 在 k-means 聚类中,您可以指定用于执行聚类分析的算法。您可以指定 Hartigan-Wong、Lloyd、Forgy 或 MacQueen 作为聚类算法。有关更多详细信息,请使用help函数参考kmeans函数的文档:

    >help(kmeans)
    
    

绘制双变量聚类图

在上一个配方中,我们使用了 k-means 方法将数据拟合到聚类中。然而,如果有超过两个变量,就无法在二维中显示数据的聚类方式。因此,您可以使用双变量聚类图首先将变量降低为两个成分,然后使用轴和圆等成分作为聚类来显示数据的聚类方式。在本配方中,我们将说明如何创建双变量聚类图。

准备工作

在本配方中,我们将继续使用customer数据集作为输入数据源来绘制双变量聚类图。

如何做...

执行以下步骤以绘制双变量聚类图:

  1. 安装并加载聚类包:

    > install.packages("cluster")
    > library(cluster)
    
    
  2. 然后,您可以绘制双变量聚类图:

    > clusplot(customer, fit$cluster, color=TRUE, shade=TRUE)
    
    

    如何做...

    客户数据集的双变量聚类图

  3. 您还可以放大双变量聚类图:

    > par(mfrow= c(1,2))
    > clusplot(customer, fit$cluster, color=TRUE, shade=TRUE)
    > rect(-0.7,-1.7, 2.2,-1.2, border = "orange", lwd=2)
    > clusplot(customer, fit$cluster, color = TRUE, xlim = c(-0.7,2.2), ylim = c(-1.7,-1.2))
    
    

    如何做...

    双变量聚类图的放大

它是如何工作的...

在本配方中,我们绘制双变量聚类图以显示数据的聚类方式。要绘制双变量聚类图,我们首先需要安装cluster包并将其加载到 R 中。然后,我们使用clusplot函数从客户数据集中绘制双变量聚类图。在clustplot函数中,我们可以将shade设置为TRUE,将color设置为TRUE以显示带有颜色和阴影的聚类。根据前面的图(步骤 2),我们发现双变量使用两个成分作为 x 轴和 y 轴,这两个成分解释了 85.01%的点变异性。然后,数据点根据成分 1 和成分 2 在图上散布。同一聚类内的数据以相同颜色和阴影的圆圈表示。

除了在单个图中绘制四个聚类外,您还可以使用rect在给定 x 轴和 y 轴范围内的特定区域内添加一个矩形。然后,您可以使用clusplot函数中的xlimylim来放大图表,以检查每个聚类内的数据。

更多内容

clusplot函数使用princompcmdscale将原始特征维度降低到主成分。因此,可以看到数据如何在这两个成分作为 x 轴和 y 轴的单个图中聚类。要了解更多关于princompcmdscale的信息,可以使用help函数查看相关文档:

> help(cmdscale)
> help(princomp)

对于那些对如何使用cmdscale进行降维感兴趣的人,请执行以下步骤:

> mds = cmdscale(dist(customer), k = 2)
> plot(mds, col = fit$cluster)

更多内容

关于缩放维度的数据散点图

比较聚类方法

使用不同的聚类方法将数据拟合到簇中后,您可能希望测量聚类的准确性。在大多数情况下,您可以使用簇内或簇间指标作为测量标准。我们现在介绍如何使用fpc包中的cluster.stat比较不同的聚类方法。

准备工作

为了执行聚类方法比较,需要完成前面的配方,生成customer数据集。

如何操作...

执行以下步骤以比较聚类方法:

  1. 首先,安装并加载fpc包:

    > install.packages("fpc")
    > library(fpc)
    
    
  2. 然后,您需要使用single方法进行层次聚类以聚类客户数据并生成对象hc_single

    > single_c =  hclust(dist(customer), method="single")
    > hc_single = cutree(single_c, k = 4)
    
    
  3. 使用complete方法进行层次聚类以聚类客户数据并生成对象hc_complete

    > complete_c =  hclust(dist(customer), method="complete")
    > hc_complete =  cutree(complete_c, k = 4)
    
    
  4. 然后,您可以使用 k-means 聚类将客户数据进行聚类并生成对象km

    > set.seed(22)
    > km = kmeans(customer, 4)
    
    
  5. 接下来,检索任何聚类方法的聚类验证统计信息:

    > cs = cluster.stats(dist(customer), km$cluster)
    
    
  6. 通常,我们关注使用within.cluster.ssavg.silwidth来验证聚类方法:

    > cs[c("within.cluster.ss","avg.silwidth")]
    $within.cluster.ss
    [1] 61.3489
    
    $avg.silwidth
    [1] 0.4640587
    
    
  7. 最后,我们可以生成每种聚类方法的聚类统计信息并将它们列在表中:

    > sapply(list(kmeans = km$cluster, hc_single = hc_single, hc_complete = hc_complete), function(c) cluster.stats(dist(customer), c)[c("within.cluster.ss","avg.silwidth")])
     kmeans    hc_single hc_complete
    within.cluster.ss 61.3489   136.0092  65.94076
    avg.silwidth      0.4640587 0.2481926 0.4255961
    
    

如何工作...

在本配方中,我们展示了如何验证聚类。为了验证聚类方法,我们通常采用两种技术:簇间距离和簇内距离。在这些技术中,簇间距离越高,越好;簇内距离越低,越好。为了计算相关统计信息,我们可以将fpc包中的cluster.stat应用于拟合的聚类对象。

从输出中,within.cluster.ss测量表示簇内平方和,而avg.silwidth表示平均轮廓宽度。within.cluster.ss测量表示簇内对象的相关性;值越小,簇内相关对象越紧密。另一方面,轮廓是一个考虑簇内对象的相关性和簇之间分离程度的测量。数学上,我们可以定义每个点x的轮廓宽度如下:

如何工作...

在前面的公式中,a(x)x与簇内所有其他点的平均距离,而b(x)x与其他簇中点的平均距离的最小值。轮廓值通常在01之间;接近1的值表明数据聚类得更好。

最后一步生成的摘要表显示,完全层次聚类方法在within.cluster.ssavg.silwidth方面优于单一层次聚类方法和 k-means 聚类。

相关内容

  • kmeans函数也输出统计信息(例如,withinssbetweenss),供用户验证聚类方法:

    > set.seed(22)
    > km = kmeans(customer, 4)
    > km$withinss
    [1]  5.90040 11.97454 22.58236 20.89159
    > km$betweenss
    [1] 174.6511
    
    

从聚类中提取轮廓信息

轮廓信息是用于验证数据聚类的测量指标。在之前的步骤中,我们提到聚类的测量涉及计算数据在每个聚类内聚类的紧密程度,以及衡量不同聚类之间的距离。轮廓系数结合了簇内和簇间距离的测量。输出值通常在 01 之间;越接近 1,聚类越好。在本步骤中,我们将介绍如何计算轮廓信息。

准备工作

为了从聚类中提取轮廓信息,你需要完成之前的步骤,通过生成 customer 数据集。

如何操作...

执行以下步骤来计算轮廓信息:

  1. 使用 kmeans 生成一个 k-means 对象,km

    > set.seed(22)
    > km = kmeans(customer, 4)
    
    
  2. 然后,你可以计算轮廓信息:

    > kms = silhouette(km$cluster,dist(customer))
    > summary(kms)
    Silhouette of 60 units in 4 clusters from silhouette.default(x = km$cluster, dist = dist(customer)) :
     Cluster sizes and average silhouette widths:
     8        11        16        25 
    0.5464597 0.4080823 0.3794910 0.5164434 
    Individual silhouette widths:
     Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     0.1931  0.4030  0.4890  0.4641  0.5422  0.6333 
    
    
  3. 接下来,你可以绘制轮廓信息图:

    > plot(kms)
    
    

    如何操作...

    k-means 聚类结果的轮廓图

它是如何工作的...

在本步骤中,我们展示了如何使用轮廓图来验证聚类。你可以首先检索轮廓信息,它显示了聚类大小、平均轮廓宽度和个体轮廓宽度。轮廓系数是一个介于 01 之间的值;越接近 1,聚类质量越好。

最后,我们使用 plot 函数绘制轮廓图。图的左侧显示了水平线的数量,代表聚类的数量。图的右侧列显示了其自身聚类图与下一个相似聚类图平均相似度的差值。平均轮廓宽度在图的底部显示。

相关内容

  • 对于那些对如何计算轮廓感兴趣的人,请参考维基百科上的轮廓值条目:[zh.wikipedia.org/wiki/轮廓 _%28 聚类%29](http://zh.wikipedia.org/wiki/轮廓 _%28 聚类%29)

获取 k-means 的最佳聚类数量

虽然 k-means 聚类速度快且易于使用,但它需要在开始时输入 k 值。因此,我们可以使用平方和来确定哪个 k 值最适合找到 k-means 的最佳聚类数量。在下面的步骤中,我们将讨论如何找到 k-means 聚类方法的最佳聚类数量。

准备工作

为了找到最佳聚类数量,你需要完成之前的步骤,通过生成 customer 数据集。

如何操作...

执行以下步骤以找到 k-means 聚类最佳聚类数量:

  1. 首先,计算不同数量聚类的内部平方和 (withinss):

    > nk = 2:10
    > set.seed(22)
    > WSS = sapply(nk, function(k) {
    +     kmeans(customer, centers=k)$tot.withinss
    + })
    > WSS
    [1] 123.49224  88.07028  61.34890  48.76431  47.20813
    [6]  45.48114  29.58014  28.87519  23.21331
    
    
  2. 然后,你可以使用线图绘制不同 k 值的内部平方和:

    > plot(nk, WSS, type="l", xlab= "number of k", ylab="within sum of squares")
    
    

    如何操作...

    关于不同 k 值的内部平方和的线图

  3. 接下来,你可以计算不同数量聚类的平均轮廓宽度(avg.silwidth):

    > SW = sapply(nk, function(k) {
    +   cluster.stats(dist(customer), kmeans(customer, centers=k)$cluster)$avg.silwidth
    + })
    > SW
    [1] 0.4203896 0.4278904 0.4640587 0.4308448 0.3481157
    [6] 0.3320245 0.4396910 0.3417403 0.4070539
    
    
  4. 然后,你可以使用线图来绘制不同k值的平均轮廓宽度:

    > plot(nk, SW, type="l", xlab="number of clusers", ylab="average silhouette width")
    
    

    如何操作...

    与不同数量的 k 相关的平均轮廓宽度的线图

  5. 获取最大聚类数量:

    > nk[which.max(SW)]
    [1] 4
    
    

它是如何工作的...

在这个配方中,我们通过迭代地获取平方和与平均轮廓值之和来演示如何找到最佳聚类数量。对于平方和,较低的值表示质量更好的聚类。通过绘制不同数量k的平方和,我们发现图表的肘部在k=4

另一方面,我们使用cluster.stats根据不同数量的聚类计算平均轮廓宽度。我们还可以使用线图来绘制不同数量聚类对应的平均轮廓宽度。前面的图(步骤 4)显示最大平均轮廓宽度出现在k=4。最后,我们使用which.max来获取 k 的值,以确定最大平均轮廓宽度的位置。

参考信息

使用基于密度的方法进行聚类

作为距离测量的替代,你可以使用基于密度的测量来聚类数据。这种方法找到一个比剩余区域密度更高的区域。最著名的方法之一是 DBSCAN。在下面的配方中,我们将演示如何使用 DBSCAN 进行基于密度的聚类。

准备工作

在这个配方中,我们将使用由mlbench包生成的模拟数据。

如何操作...

执行以下步骤以执行基于密度的聚类:

  1. 首先,安装并加载fpcmlbench包:

    > install.packages("mlbench")
    > library(mlbench)
    > install.packages("fpc")
    > library(fpc)
    
    
  2. 然后,你可以使用mlbench库绘制 Cassini 问题图:

    > set.seed(2)
    > p = mlbench.cassini(500)
    > plot(p$x)
    
    

    如何操作...

    Cassini 问题图

  3. 接下来,你可以根据密度的测量来对数据进行聚类:

    > ds = dbscan(dist(p$x),0.2, 2, countmode=NULL, method="dist")
    > ds
    dbscan Pts=500 MinPts=2 eps=0.2
     1   2   3
    seed  200 200 100
    total 200 200 100
    
    
  4. 以不同的聚类标签作为颜色绘制散点图中的数据:

    > plot(ds, p$x)
    
    

    如何操作...

    根据聚类标签着色的数据散点图

  5. 你还可以使用dbscan来预测数据点属于哪个聚类。在这个例子中,首先在矩阵p中输入三个输入:

    > y = matrix(0,nrow=3,ncol=2)
    > y[1,] = c(0,0)
    > y[2,] = c(0,-1.5)
    > y[3,] = c(1,1)
    > y
     [,1] [,2]
    [1,]    0  0.0
    [2,]    0 -1.5
    [3,]    1  1.0
    
    
  6. 然后,你可以预测数据属于哪个聚类:

    > predict(ds, p$x, y)
    [1] 3 1 2
    
    

它是如何工作的...

基于密度的聚类利用密度可达性和密度连通性的概念,这使得它在发现非线性形状的聚类中非常有用。在讨论基于密度的聚类过程之前,必须解释一些重要的背景概念。基于密度的聚类考虑两个参数:epsMinPtseps代表邻域的最大半径;MinPts表示eps邻域内点的最小数量。有了这两个参数,我们可以定义核心点为在eps邻域内有超过MinPts个点的点。此外,我们还可以定义边界点为点数少于MinPts,但位于核心点邻域内的点。然后,我们可以定义核心对象为如果点peps邻域内的点数超过MinPts

此外,我们必须定义两点之间的可达性。我们可以这样说,如果点q位于点peps邻域内,并且p是一个核心对象,那么点p是直接从点q密度可达的。然后,我们可以定义,如果存在一个点的链,p[1],p[2],...,p[n],其中 p[1] = q,p[n] = p,并且对于 1 <= i <= n,p[i]+1 相对于 Eps 和MinPts直接从 pi 密度可达,那么点p是通用且从点q密度可达的:

工作原理...

点 p 和 q 是密度可达的

在对基于密度的聚类有一个初步概念之后,我们可以通过以下步骤来阐述最流行的基于密度的聚类算法 DBSCAN 的过程,如图所示:

  1. 随机选择一个点,p

  2. 根据EpsMinPts检索所有从p密度可达的点。

  3. 如果p是一个核心点,那么就形成了一个簇。否则,如果它是边界点,并且没有点从p密度可达,则过程将标记该点为噪声,并继续访问下一个点。

  4. 重复此过程,直到所有点都被访问。

在这个菜谱中,我们展示了如何使用基于密度的 DBSCAN 方法来聚类客户数据。首先,我们必须安装和加载mlbenchfpc库。mlbench包提供了许多方法来生成不同形状和大小的模拟数据。在这个例子中,我们生成一个 Cassini 问题图。

接下来,我们在 Cassini 数据集上执行dbscan以聚类数据。我们指定可达距离为 0.2,点的最小可达数为 2,进度报告为 null,并使用距离作为测量标准。聚类方法成功地将数据聚为三个大小分别为 200、200 和 100 的簇。通过在图上绘制点和簇标签,我们看到 Cassini 图的三部分被不同颜色分开。

fpc包还提供了一个predict函数,您可以使用此函数预测输入矩阵的聚类标签。点 c(0,0)被分类到聚类 3,点 c(0, -1.5)被分类到聚类 1,点 c(1,1)被分类到聚类 2。

参见

  • fpc包包含灵活的聚类过程,并具有有用的聚类分析函数。例如,您可以使用plotcluster函数生成判别投影图。有关更多信息,请参阅以下文档:

    > help(plotcluster)
    
    

使用基于模型的方法进行聚类数据

与使用启发式方法且不依赖于正式模型的层次聚类和 k-means 聚类相比,基于模型聚类技术假设各种数据模型,并应用 EM 算法以获得最可能的模型,并进一步使用该模型推断最可能的聚类数量。在本配方中,我们将演示如何使用基于模型的方法来确定最可能的聚类数量。

准备工作

为了执行基于模型的方法对客户数据进行聚类,您需要完成之前的配方,生成客户数据集。

如何操作...

执行以下步骤以执行基于模型聚类:

  1. 首先,请安装并加载库mclust

    > install.packages("mclust")
    > library(mclust)
    
    
  2. 然后,您可以在customer数据集上执行基于模型聚类:

    > mb = Mclust(customer)
    > plot(mb)
    
    
  3. 然后,您可以按 1 键获取 BIC 与组件数量的关系:如何操作...

    BIC 与组件数量的关系图

  4. 然后,您可以按 2 键显示关于不同特征组合的分类:如何操作...

    根据不同特征组合的分类图

  5. 按 3 键显示关于不同特征组合的分类不确定性:如何操作...

    根据不同特征组合的分类不确定性图

  6. 接下来,按 4 键绘制密度估计:如何操作...

    密度估计图

  7. 然后,您可以按 0 键绘制密度并退出绘图菜单。

  8. 最后,使用summary函数获取最可能的模型和聚类数量:

    > summary(mb)
    ----------------------------------------------------
    Gaussian finite mixture model fitted by EM algorithm 
    ----------------------------------------------------
    
    Mclust VII (spherical, varying volume) model with 5 components:
    
     log.likelihood  n df       BIC       ICL
     -218.6891 60 29 -556.1142 -557.2812
    
    Clustering table:
     1  2  3  4  5
    11  8 17 14 10
    
    

如何工作...

与基于启发式方法构建聚类不同,基于模型聚类使用基于概率的方法。基于模型聚类假设数据是由潜在的概率分布生成的,并试图从数据中恢复分布。一种常见的基于模型的方法是使用有限混合模型,它为概率分布的分析提供了一个灵活的建模框架。有限混合模型是组件概率分布的线性加权总和。假设数据y=(y[1],y[2]…y[n])包含 n 个独立的多变量观测值;G 是组件数量;有限混合模型的似然可以表示为:

如何工作...

如何工作...如何工作... 是混合模型中第 k 个成分的密度和参数,而 如何工作... (![如何工作...] 和 如何工作...) 是观察属于第 k 个成分的概率。

基于模型的聚类过程有几个步骤:首先,过程选择组件概率分布的数量和类型。然后,它拟合一个有限混合模型并计算组件成员的后验概率。最后,它将每个观察的成员分配给概率最大的组件。

在这个菜谱中,我们展示了如何使用基于模型的聚类方法对数据进行聚类。我们首先在 R 中安装并加载Mclust库。然后,我们使用Mclust函数将客户数据拟合到基于模型的方法中。

数据拟合到模型后,我们根据聚类结果绘制模型。有四种不同的图:BIC 图、分类图、不确定性和密度图。BIC 图显示了 BIC 值,人们可以使用这个值来选择簇的数量。分类图显示了数据如何根据不同的维度组合进行聚类。不确定图显示了根据不同维度组合的分类不确定性。密度图显示了轮廓中的密度估计。

你也可以使用summary函数来获取最可能的模型和最可能的簇数量。对于这个例子,最可能的簇数量是五个,BIC 值为-556.1142。

参见

  • 对于那些对Mclust如何工作感兴趣的人,请参阅以下来源:C. Fraley, A. E. Raftery, T. B. Murphy 和 L. Scrucca (2012). mclust Version 4 for R: Normal Mixture Modeling for Model-Based Clustering, Classification, and Density Estimation. 技术报告第 597 号,华盛顿大学统计学系。

可视化相似性矩阵

相似性矩阵可以用作衡量聚类质量的一个指标。为了可视化矩阵,我们可以在距离矩阵上使用热图。在图中,低相似性(或高相似性)的条目以较深的颜色绘制,这有助于识别数据中的隐藏结构。在这个菜谱中,我们将讨论一些可视化相似性矩阵的有用技术。

准备工作

为了可视化相似性矩阵,你需要完成之前的菜谱,生成客户数据集。此外,还需要生成并存储在变量km中的 k-means 对象。

如何操作...

执行以下步骤以可视化相似性矩阵:

  1. 首先,安装并加载seriation包:

    > install.packages("seriation")
    > library(seriation)
    
    
  2. 然后,你可以使用dissplot在热图上可视化相似性矩阵:

    > dissplot(dist(customer), labels=km$cluster, options=list(main="Kmeans Clustering With k=4"))
    
    

    如何操作...

    k-means 聚类的相似性图

  3. 接下来,在热图中应用dissplot于层次聚类:

    > complete_c =  hclust(dist(customer), method="complete")
    > hc_complete =  cutree(complete_c, k = 4)
    > dissplot(dist(customer), labels=hc_complete, options=list(main="Hierarchical Clustering"))
    
    

    如何做...

    层次聚类的相似度图

它是如何工作的...

在这个菜谱中,我们使用不相似度图来可视化不相似度矩阵。我们首先安装并加载seriation包,然后对 k-means 聚类输出应用dissplot函数,生成前面的图(步骤 2)。

这显示,相似度高的聚类用较深的颜色表示,而不同组合的聚类用较浅的颜色表示。因此,我们可以看到对应聚类(如聚类 4 到聚类 4)是斜对角且颜色较深的。另一方面,彼此不相似的聚类用较浅的颜色表示,并且远离对角线。

同样,我们可以在层次聚类的输出上应用dissplot函数。图中的生成图(步骤 3)显示了每个聚类的相似性。

还有更多...

除了使用dissplot来可视化不相似度矩阵外,还可以使用distimage函数来可视化距离矩阵。在生成的图中,密切相关项用红色表示。不太相关项则更接近白色:

> image(as.matrix(dist(customer)))

还有更多...

客户数据集的距离矩阵图

为了绘制树状图和热图以显示数据的聚类方式,您可以使用heatmap函数:

> cd=dist(customer)
> hc=hclust(cd)
> cdt=dist(t(customer))
> hcc=hclust(cdt)
> heatmap(customer, Rowv=as.dendrogram(hc), Colv=as.dendrogram(hcc))

还有更多...

列和行侧带有树状图的热图

外部验证聚类

除了生成统计信息来验证生成的聚类的质量外,您还可以使用已知的数据聚类作为基准来比较不同的聚类方法。在这个菜谱中,我们将演示聚类方法在已知聚类数据上的差异。

准备工作

在这个菜谱中,我们将继续使用手写数字作为聚类输入;您可以在作者的 GitHub 页面上找到该图:github.com/ywchiu/ml_R_cookbook/tree/master/CH9

如何做...

执行以下步骤以使用不同的聚类技术对数字进行聚类:

  1. 首先,您需要安装并加载png包:

    > install.packages("png")
    > library(png)
    
    
  2. 然后,请从handwriting.png读取图像,并将读取的数据转换为散点图:

    > img2 = readPNG("handwriting.png", TRUE)
    > img3 = img2[,nrow(img2):1]
    > b = cbind(as.integer(which(img3 < -1) %% 28), which(img3 < -1) / 28)
    > plot(b, xlim=c(1,28), ylim=c(1,28))
    
    

    如何做...

    手写数字的散点图

  3. 对手写数字执行 k-means 聚类方法:

    > set.seed(18)
    > fit = kmeans(b, 2)
    > plot(b, col=fit$cluster)
    > plot(b, col=fit$cluster,  xlim=c(1,28), ylim=c(1,28))
    
    

    如何做...

    手写数字的 k-means 聚类结果

  4. 接下来,对手写数字执行dbscan聚类方法:

    > ds = dbscan(b, 2)
    > ds
    dbscan Pts=212 MinPts=5 eps=2
     1   2
    seed  75 137
    total 75 137
    > plot(ds, b,  xlim=c(1,28), ylim=c(1,28))
    
    

如何做...

手写数字的 DBSCAN 聚类结果

它是如何工作的...

在这个菜谱中,我们展示了不同的聚类方法在处理手写数据集时的效果。聚类的目的是将 1 和 7 分离到不同的簇中。我们执行不同的技术来观察数据在 k-means 和 DBSCAN 方法下的聚类情况。

为了生成数据,我们使用 Windows 应用程序 paint.exe 创建一个 28 x 28 像素的 PNG 文件。然后我们使用 readPNG 函数读取 PNG 数据,并将读取的 PNG 数据点转换为散点图,该图显示了 17 中的手写数字。

在数据读取之后,我们对手写数字进行聚类技术处理。首先,我们在数据集上执行 k-means 聚类,其中 k=2。由于 k-means 聚类使用距离度量,构建的簇覆盖了 1 和 7 数字区域。然后我们对数据集执行 DBSCAN。由于 DBSCAN 是一种基于密度的聚类技术,它成功地将数字 1 和数字 7 分离到不同的簇中。

参见

  • 如果你对如何在 R 中读取各种图形格式感兴趣,你可以参考以下文档:

    > help(package="png")
    
    

第十章. 关联分析和序列挖掘

在本章中,我们将涵盖以下主题:

  • 将数据转换为交易

  • 显示交易和关联

  • 使用 Apriori 规则挖掘关联

  • 剪枝冗余规则

  • 可视化关联规则

  • 使用 Eclat 算法挖掘频繁项集

  • 创建具有时间信息的交易

  • 使用 cSPADE 挖掘频繁顺序模式

简介

企业从日常运营中积累大量交易数据(例如,来自零售商的销售订单、发票和运输文件),发现数据中的隐藏关系可能很有用,例如,“哪些产品经常一起购买?”或“购买手机后的后续购买是什么?”为了回答这两个问题,我们需要在事务数据集上执行关联分析和频繁顺序模式挖掘。

关联分析是一种在事务数据集中寻找有趣关系的方法。一个著名的关于产品的关联是购买尿布的客户也会购买啤酒。虽然这种关联听起来可能有些不寻常,但如果零售商能够利用这类信息或规则向客户交叉销售产品,那么他们提高销售额的可能性很高。

关联分析用于寻找项集之间的相关性,但如果你想知道频繁购买的项目顺序,该怎么办?为了实现这一点,你可以采用频繁顺序模式挖掘,从具有时间信息的事务数据集中找到频繁子序列。然后,你可以使用挖掘出的频繁子序列来预测客户购物顺序、网页点击流、生物序列以及其他应用中的使用情况。

在本章中,我们将涵盖创建和检查事务数据集的配方,使用 Apriori 算法执行关联分析,以各种图形格式可视化关联,以及使用 Eclat 算法查找频繁项集。最后,我们将创建具有时间信息的交易,并使用 cSPADE 算法发现频繁顺序模式。

将数据转换为交易

在创建挖掘关联规则之前,您需要将数据转换为交易。在下面的配方中,我们将介绍如何将列表、矩阵或数据框转换为交易。

准备工作

在这个配方中,我们将在一个列表、矩阵或数据框中生成三个不同的数据集。然后,我们可以将生成的数据集转换为交易。

如何操作...

执行以下步骤将不同格式的数据转换为交易:

  1. 首先,您必须安装并加载arule包:

    > install.packages("arules")
    > library(arules)
    
    
  2. 您可以创建一个包含三个向量的购买记录列表:

    > tr_list = list(c("Apple", "Bread", "Cake"),
    +                c("Apple", "Bread", "Milk"),
    +                c("Bread", "Cake", "Milk"))
    > names(tr_list) = paste("Tr",c(1:3), sep = "")
    
    
  3. 接下来,您可以使用as函数将数据框转换为交易:

    > trans = as(tr_list, "transactions")
    > trans
    transactions in sparse format with
     3 transactions (rows) and
     4 items (columns)
    
    
  4. 您还可以将矩阵格式的数据转换为交易:

    > tr_matrix = matrix(
    +   c(1,1,1,0,
    +     1,1,0,1,
    +     0,1,1,1), ncol = 4)
    > dimnames(tr_matrix) =  list(
    +   paste("Tr",c(1:3), sep = ""),
    +   c("Apple","Bread","Cake", "Milk")
    +   )
    > trans2 =  as(tr_matrix, "transactions")
    > trans2
    transactions in sparse format with
     3 transactions (rows) and
     4 items (columns)
    
    
  5. 最后,你可以将数据框格式的数据集转换为事务:

    > Tr_df = data.frame(
    +   TrID= as.factor(c(1,2,1,1,2,3,2,3,2,3)),
    +   Item = as.factor(c("Apple","Milk","Cake","Bread",
    +                      "Cake","Milk","Apple","Cake",
    +                      "Bread","Bread")) 
    + )
    > trans3 = as(split(Tr_df[,"Item"], Tr_df[,"TrID"]), "transactions")
    > trans3
    transactions in sparse format with
     3 transactions (rows) and
     4 items (columns)
    
    

它是如何工作的...

在挖掘频繁项集或使用关联规则之前,通过事务类别准备数据集非常重要。在本菜谱中,我们演示如何将数据集从列表、矩阵和数据框格式转换为事务。在第一步中,我们生成一个包含三个购买记录向量的列表格式的数据集。然后,在为每个交易分配交易 ID 之后,我们使用 as 函数将数据转换为事务。

接下来,我们将演示如何将矩阵格式中的数据转换为事务。为了表示项目的购买情况,应使用二元发生矩阵来记录每个交易相对于不同购买项目的购买行为。同样,我们可以使用 as 函数将数据集从矩阵格式转换为事务。

最后,我们将展示如何将数据集从数据框格式转换为事务。数据框包含两个因子类型的向量:一个是名为 TrID 的交易 ID,另一个显示不同交易中的购买项目(命名为 Item)。此外,可以使用 as 函数将数据框格式的数据转换为事务。

参考内容

  • transactions 类用于表示规则或频繁模式挖掘的事务数据。它是 itemMatrix 类的扩展。如果您对如何使用这两个不同的类来表示事务数据感兴趣,请使用 help 函数参考以下文档:

    > help(transactions)
    > help(itemMatrix)
    
    

显示事务和关联

arule 包使用其自己的 transactions 类来存储事务数据。因此,我们必须使用 arule 提供的通用函数来显示事务和关联规则。在本菜谱中,我们将展示如何通过 arule 包中的各种函数显示事务和关联规则。

准备工作

确保您已通过生成事务并将这些存储在变量 trans 中完成前面的菜谱。

如何做到这一点...

执行以下步骤以显示事务和关联:

  1. 首先,您可以获取事务数据的 LIST 表示:

    > LIST(trans)
    $Tr1
    [1] "Apple" "Bread" "Cake" 
    
    $Tr2
    [1] "Apple" "Bread" "Milk" 
    
    $Tr3
    [1] "Bread" "Cake"  "Milk"
    
    
  2. 接下来,您可以使用 summary 函数显示事务的统计和详细摘要:

    > summary(trans)
    transactions as itemMatrix in sparse format with
     3 rows (elements/itemsets/transactions) and
     4 columns (items) and a density of 0.75 
    
    most frequent items:
     Bread   Apple    Cake    Milk (Other) 
     3       2       2       2       0 
    
    element (itemset/transaction) length distribution:
    sizes
    3 
    3 
    
     Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     3       3       3       3       3       3 
    
    includes extended item information - examples:
     labels
    1  Apple
    2  Bread
    3   Cake
    
    includes extended transaction information - examples:
     transactionID
    1           Tr1
    2           Tr2
    3           Tr3
    
    
  3. 然后,您可以使用 inspect 函数显示事务:

    > inspect(trans)
     items   transactionID
    1 {Apple, 
     Bread, 
     Cake}            Tr1
    2 {Apple, 
     Bread, 
     Milk}            Tr2
    3 {Bread, 
     Cake, 
     Milk}            Tr3
    
    
  4. 此外,您还可以根据大小筛选事务:

    > filter_trains = trans[size(trans) >=3]
    > inspect(filter_trains)
     items   transactionID
    1 {Apple, 
     Bread, 
     Cake}            Tr1
    2 {Apple, 
     Bread, 
     Milk}            Tr2
    3 {Bread, 
     Cake, 
     Milk}            Tr3
    
    
  5. 此外,您还可以使用图像函数来直观检查事务:

    > image(trans)
    
    

    如何做到这一点...

    事务的可视检查

  6. 为了直观地显示频率/支持条形图,可以使用 itemFrequenctPlot

    > itemFrequencyPlot (trans)
    
    

    如何做到这一点...

    事务项目频率条形图

它是如何工作的...

由于事务数据是挖掘关联和频繁模式的基石,我们必须学习如何显示关联以获得洞察力并确定关联是如何构建的。arules包提供了各种方法来检查事务。首先,我们使用LIST函数获取事务数据的列表表示。然后,我们可以使用summary函数获取信息,例如基本描述、最频繁的项以及事务长度分布。

接下来,我们使用inspect函数显示事务。除了显示所有事务外,您还可以首先通过大小过滤事务,然后使用inspect函数显示关联。此外,我们可以使用image函数对事务进行视觉检查。最后,我们说明如何使用频率/支持条形图显示每个项目的相对频率。

相关内容

  • 除了使用itemFrequencyPlot显示频率/条形图外,您还可以使用itemFrequency函数显示支持分布。有关更多详细信息,请使用help函数查看以下文档:

    > help(itemFrequency)
    
    

使用 Apriori 规则挖掘关联

关联挖掘是一种技术,可以挖掘出隐藏在事务数据集中的有趣关系。这种方法首先找到所有频繁项集,然后从频繁项集中生成强关联规则。Apriori 是最著名的关联挖掘算法,它首先识别频繁的个体项,然后执行广度优先搜索策略,将个体项扩展到更大的项集,直到无法找到更大的频繁项集。在本食谱中,我们将介绍如何使用 Apriori 规则进行关联分析。

准备工作

在本食谱中,我们将使用内置的事务数据集Groceries,演示如何在arules包中使用 Apriori 算法进行关联分析。请确保首先安装并加载arules包。

如何操作...

执行以下步骤以分析关联规则:

  1. 首先,您需要加载数据集Groceries

    > data(Groceries)
    
    
  2. 您可以检查Groceries数据集的摘要:

    > summary(Groceries)
    
    
  3. 接下来,您可以使用itemFrequencyPlot检查项集的相对频率:

    > itemFrequencyPlot(Groceries, support = 0.1, cex.names=0.8, topN=5)
    
    

    如何操作...

    食物事务的前五项频率条形图

  4. 使用apriori发现支持率超过 0.001 且置信度超过 0.5 的规则:

    > rules = apriori(Groceries, parameter = list(supp = 0.001, conf = 0.5, target= "rules"))
    > summary(rules)
    set of 5668 rules
    
    rule length distribution (lhs + rhs):sizes
     2    3    4    5    6 
     11 1461 3211  939   46 
    
     Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     2.00    3.00    4.00    3.92    4.00    6.00 
    
    summary of quality measures:
     support           confidence          lift 
     Min.   :0.001017   Min.   :0.5000   Min.   : 1.957 
     1st Qu.:0.001118   1st Qu.:0.5455   1st Qu.: 2.464 
     Median :0.001322   Median :0.6000   Median : 2.899 
     Mean   :0.001668   Mean   :0.6250   Mean   : 3.262 
     3rd Qu.:0.001729   3rd Qu.:0.6842   3rd Qu.: 3.691 
     Max.   :0.022267   Max.   :1.0000   Max.   :18.996 
    
    mining info:
     data ntransactions support confidence
     Groceries          9835   0.001        0.5
    
    
  5. 然后,我们可以检查前几条规则:

    > inspect(head(rules))
     lhs                    rhs              support confidence     lift
    1 {honey}             => {whole milk} 0.001118454  0.7333333 2.870009
    2 {tidbits}           => {rolls/buns} 0.001220132  0.5217391 2.836542
    3 {cocoa drinks}      => {whole milk} 0.001321810  0.5909091 2.312611
    4 {pudding powder}    => {whole milk} 0.001321810  0.5652174 2.212062
    5 {cooking chocolate} => {whole milk} 0.001321810  0.5200000 2.035097
    6 {cereals}           => {whole milk} 0.003660397  0.6428571 2.515917
    
    
  6. 您可以根据置信度对规则进行排序并检查前几条规则:

    > rules=sort(rules, by="confidence", decreasing=TRUE)
    > inspect(head(rules))
     lhs                     rhs                    support confidence     lift
    1 {rice, 
     sugar}              => {whole milk}       0.001220132          1 3.913649
    2 {canned fish, 
     hygiene articles}   => {whole milk}       0.001118454          1 3.913649
    3 {root vegetables, 
     butter, 
     rice}               => {whole milk}       0.001016777          1 3.913649
    4 {root vegetables, 
     whipped/sour cream, 
     flour}              => {whole milk}       0.001728521          1 3.913649
    5 {butter, 
     soft cheese, 
     domestic eggs}      => {whole milk}       0.001016777          1 3.913649
    6 {citrus fruit, 
     root vegetables, 
     soft cheese}        => {other vegetables} 0.001016777          1 5.168156
    
    

工作原理...

关联挖掘的目的是从事务数据库中挖掘项目之间的关联。通常,关联挖掘的过程是通过查找支持度大于最小支持度的项集来进行的。接下来,过程使用频繁项集生成具有大于最小置信度的强规则(例如,milk => bread;购买牛奶的客户很可能也会购买面包)。根据定义,关联规则可以表示为 X=>Y 的形式,其中 X 和 Y 是不相交的项集。我们可以衡量两个术语之间的关联强度:支持度和置信度。支持度表示规则在数据集中适用的百分比,而置信度表示 X 和 Y 同时出现在同一交易中的概率:

  • 支持度 = 如何工作...

  • 置信度 = 如何工作...

在这里,如何工作... 指的是特定项集的频率;N 表示人口数量。

由于支持度和置信度是衡量规则强度的指标,你仍然可能会获得许多具有高支持度和置信度的冗余规则。因此,我们可以使用第三个度量,即提升度,来评估规则的质量(排名)。根据定义,提升度表明规则相对于 X 和 Y 的随机共现的强度,因此我们可以以下形式制定提升度:

升力 = 如何工作...

Apriori 是挖掘关联规则最著名的算法,它执行一种按层级的广度优先算法来计数候选项集。Apriori 的过程从按层级查找频繁项集(具有最小支持度的项集集合)开始。例如,过程从查找频繁的 1-项集开始。然后,过程继续使用频繁的 1-项集来查找频繁的 2-项集。过程迭代地从频繁的 k-项集中发现新的频繁 k+1-项集,直到没有找到频繁项集。

最后,过程利用频繁项集生成关联规则:

如何工作...

Apriori 算法示意图(其中支持度 = 2)

在这个菜谱中,我们使用 Apriori 算法在事务中查找关联规则。我们使用内置的 Groceries 数据集,它包含来自典型杂货店的现实世界一个月的销售额交易数据。然后,我们使用 summary 函数来获取 Groceries 数据集的摘要统计信息。摘要统计显示,数据集包含 9,835 笔交易,分为 169 个类别。此外,摘要还显示了数据集中的信息,例如最频繁的项、项集分布以及数据集中的示例扩展项信息。然后,我们可以使用 itemFrequencyPlot 来可视化支持率超过 0.1 的五个最频繁项。

接下来,我们应用 Apriori 算法来搜索支持度超过 0.001 且置信度超过 0.5 的规则。然后,我们使用 summary 函数来检查生成规则的详细信息。从输出摘要中,我们发现 Apriori 算法生成了 5,668 条支持度超过 0.001 且置信度超过 0.5 的规则。进一步,我们可以找到规则长度分布、质量度量摘要和挖掘信息。在质量度量摘要中,我们发现三个度量(支持度、置信度和提升度)的描述性统计。支持度是包含特定项集的交易比例。置信度是规则的正确百分比。提升度是响应目标关联规则除以平均响应。

要探索一些生成的规则,我们可以使用 inspect 函数来查看 5,668 条生成规则中的前六条规则。最后,我们可以根据置信度对规则进行排序,并列出置信度最高的规则。因此,我们发现与 whole milk 相关的 rich sugar 是置信度最高的规则,其支持度为 0.001220132,置信度为 1,提升度为 3.913649。

参考以下内容

对于对使用 Groceries 数据集的研究结果感兴趣的人,以及支持度、置信度和提升度测量是如何定义的,您可以参考以下论文:

  • Michael Hahsler,Kurt Hornik 和 Thomas Reutterer(2006)概率数据建模对挖掘关联规则的影响在 M. Spiliopoulou,R. Kruse,C. Borgelt,A

  • Nuernberger 和 W. Gaul 编著,从数据和信息分析到知识工程,分类研究,数据分析与知识组织,第 598-605 页Springer-Verlag

此外,除了使用 summaryinspect 函数来检查关联规则外,您还可以使用 interestMeasure 获取额外的兴趣度量:

> head(interestMeasure(rules, c("support", "chiSquare", "confidence", "conviction","cosine", "coverage", "leverage", "lift","oddsRatio"), Groceries))

剪枝冗余规则

在生成的规则中,我们有时会发现重复或冗余的规则(例如,一条规则是另一条规则的超级规则或子集)。在这个菜谱中,我们将向您展示如何剪枝(或删除)重复或冗余的规则。

准备工作

在这个菜谱中,您必须通过生成规则并存储在变量 rules 中来完成前面的菜谱。

如何做...

执行以下步骤以剪枝冗余规则:

  1. 首先,按照以下步骤查找冗余规则:

    > rules.sorted = sort(rules, by="lift")
    > subset.matrix = is.subset(rules.sorted, rules.sorted)
    > subset.matrix[lower.tri(subset.matrix, diag=T)] = NA
    > redundant = colSums(subset.matrix, na.rm=T) >= 1
    
    
  2. 然后,您可以移除冗余规则:

    > rules.pruned = rules.sorted[!redundant]
    > inspect(head(rules.pruned))
     lhs                        rhs                  support confidence     lift
    1 {Instant food products, 
     soda}                  => {hamburger meat} 0.001220132  0.6315789 18.99565
    2 {soda, 
     popcorn}               => {salty snack}    0.001220132  0.6315789 16.69779
    3 {flour, 
     baking powder}         => {sugar}          0.001016777  0.5555556 16.40807
    4 {ham, 
     processed cheese}      => {white bread}    0.001931876  0.6333333 15.04549
    5 {whole milk, 
     Instant food products} => {hamburger meat} 0.001525165  0.5000000 15.03823
    6 {other vegetables, 
     curd, 
     yogurt, 
     whipped/sour cream}    => {cream cheese }  0.001016777  0.5882353 14.83409
    
    

它是如何工作的...

关联挖掘的两个主要约束是在支持度和置信度之间进行选择。例如,如果你使用高的支持度阈值,你可能会移除稀有的项目规则,而不考虑这些规则是否具有高的置信度值。另一方面,如果你选择使用低的支持度阈值,关联挖掘可能会产生大量的冗余关联规则,这使得这些规则难以利用和分析。因此,我们需要剪枝冗余规则,以便从这些生成的规则中找到有意义的信息。

在这个菜谱中,我们演示了如何剪枝冗余规则。首先,我们搜索冗余规则。我们根据提升度对规则进行排序,然后使用is.subset函数找到排序规则的子集,这将生成一个itemMatrix对象。然后,我们可以将矩阵的下三角设置为 NA。最后,我们计算生成的矩阵的colSums,其中colSums >=1表示该特定规则是冗余的。

在我们找到冗余规则后,我们可以从排序规则中剪除这些规则。最后,我们可以使用inspect函数检查剪枝规则。

参见

  • 为了找到规则的子集或超集,你可以在关联规则上使用is.supersetis.subset函数。这两种方法可能会生成一个itemMatrix对象来显示哪个规则是其他规则的子集或超集。你可以参考help函数获取更多信息:

    > help(is.superset)
    > help(is.subset)
    
    

关联规则的可视化

除了以文本形式列出规则外,你还可以可视化关联规则,这有助于找到项目集之间的关系。在下面的菜谱中,我们将介绍如何使用aruleViz包来可视化关联规则。

准备工作

在这个菜谱中,我们将继续使用Groceries数据集。你需要完成上一个菜谱,生成剪枝规则rules.pruned

如何操作...

执行以下步骤以可视化关联规则:

  1. 首先,你需要安装并加载arulesViz包:

    > install.packages("arulesViz")
    > library(arulesViz)
    
    
  2. 然后,你可以从剪枝规则中制作散点图:

    > plot(rules.pruned)
    
    

    如何操作...

    剪枝关联规则的散点图

  3. 此外,为了防止重叠,你可以在散点图中添加抖动:

    > plot(rules.pruned, shading="order", control=list(jitter=6))
    
    

    如何操作...

    关联规则剪枝散点图带有抖动

  4. 然后,我们使用 Apriori 算法在左侧使用soda生成新规则:

    > soda_rule=apriori(data=Groceries, parameter=list(supp=0.001,conf = 0.1, minlen=2), appearance = list(default="rhs",lhs="soda"))
    
    
  5. 接下来,你可以在图形图中绘制soda_rule

    > plot(sort(soda_rule, by="lift"), method="graph", control=list(type="items"))
    
    

    如何操作...

    关联规则的图形图

  6. 此外,关联规则还可以在气球图中可视化:

    > plot(soda_rule, method="grouped")
    
    

    如何操作...

    关联规则的气球图

工作原理...

除了以文本形式呈现关联规则之外,还可以使用arulesViz来可视化关联规则。arulesVizarules的扩展包,它提供了许多可视化技术来探索关联规则。要开始使用arulesViz,首先安装并加载arulesViz包。然后我们使用前一个菜谱中生成的剪枝规则制作散点图。根据步骤 2 中的图,我们发现规则在散点图中显示为点,x 轴表示支持度,y 轴表示置信度。颜色的深浅显示了规则的提升度;颜色越深,提升度越高。接下来,为了防止点重叠,我们可以在控制列表中包含 jitter 作为参数。添加了 jitter 的图在步骤 3 中的图中提供。

除了在散点图中绘制规则之外,arulesViz还允许您在图中和分组矩阵中绘制规则。我们不是在单个图中打印所有规则,而是选择使用soda在左侧生成新规则。然后我们使用提升排序规则,并在步骤 4 中的图中可视化规则。从图中可以看出,左侧的soda到右侧的全脂牛奶的规则具有最大的支持度,因为节点的大小最大。此外,该规则显示左侧的soda到右侧的瓶装水具有最大的提升度,因为圆圈的颜色最深。然后我们可以使用左侧带有soda的相同数据生成一个分组矩阵,这是一个在步骤 5 中的图中显示的气球图,左侧规则作为列标签,右侧作为行标签。类似于步骤 4 中的图中的图,步骤 5 中的图中的气球大小显示了规则的支持度,气球的颜色显示了规则的提升度。

另请参阅

  • 在这个菜谱中,我们介绍了三种可视化方法来绘制关联规则。然而,arulesViz也提供了绘制平行坐标图、双层图、马赛克图和其他相关图表的功能。对于那些对如何实现这些图表感兴趣的人,您可以参考:Hahsler, M. 和 Chelluboina, S. (2011). 可视化关联规则:R 扩展包 arulesViz 的介绍。R 项目模块

  • 除了生成静态图之外,您可以通过以下步骤通过将交互设置为 TRUE 来生成交互式图:

    > plot(rules.pruned,interactive=TRUE)
    
    

    另请参阅

    交互式散点图

使用 Eclat 挖掘频繁项集

除了 Apriori 算法外,您还可以使用 Eclat 算法来生成频繁项集。由于 Apriori 算法执行广度优先搜索以扫描整个数据库,支持度计数相当耗时。如果数据库可以放入内存中,您可以使用 Eclat 算法,它执行深度优先搜索来计数支持度。因此,Eclat 算法比 Apriori 算法运行得更快。在这个食谱中,我们将介绍如何使用 Eclat 算法生成频繁项集。

准备工作

在这个食谱中,我们将继续使用数据集Groceries作为我们的输入数据源。

如何操作...

执行以下步骤以使用 Eclat 算法生成频繁项集:

  1. 与 Apriori 方法类似,我们可以使用eclat函数来生成频繁项集:

    > frequentsets=eclat(Groceries,parameter=list(support=0.05,maxlen=10))
    
    
  2. 然后,我们可以从生成的频繁项集中获取汇总信息:

    > summary(frequentsets)
    set of 31 itemsets
    
    most frequent items:
     whole milk other vegetables           yogurt 
     4                2                2 
     rolls/buns      frankfurter          (Other) 
     2                1               23 
    
    element (itemset/transaction) length distribution:sizes
     1  2 
    28  3 
    
     Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     1.000   1.000   1.000   1.097   1.000   2.000 
    
    summary of quality measures:
     support 
     Min.   :0.05236 
     1st Qu.:0.05831 
     Median :0.07565 
     Mean   :0.09212 
     3rd Qu.:0.10173 
     Max.   :0.25552 
    
    includes transaction ID lists: FALSE 
    
    mining info:
     data ntransactions support
     Groceries          9835    0.05
    
    
  3. 最后,我们可以检查前十个支持度最高的频繁项集:

    > inspect(sort(frequentsets,by="support")[1:10])
     items                 support
    1  {whole milk}       0.25551601
    2  {other vegetables} 0.19349263
    3  {rolls/buns}       0.18393493
    4  {soda}             0.17437722
    5  {yogurt}           0.13950178
    6  {bottled water}    0.11052364
    7  {root vegetables}  0.10899847
    8  {tropical fruit}   0.10493137
    9  {shopping bags}    0.09852567
    10 {sausage}          0.09395018
    
    

工作原理...

在这个食谱中,我们介绍另一个算法,Eclat,用于执行频繁项集生成。尽管 Apriori 是一种简单易懂的关联挖掘方法,但该算法的缺点是生成巨大的候选集,在支持度计数方面效率低下,因为它需要多次扫描数据库。相比之下,Eclat 使用等价类、深度优先搜索和集合交集,这大大提高了支持度计数的速度。

在 Apriori 算法中,算法使用水平数据布局来存储事务。另一方面,Eclat 使用垂直数据布局来存储每个项目的交易 ID 列表(tid)。然后,Eclat 通过交集两个 k-item 集的 tid 列表来确定任何 k+1-item 集的支持度。最后,Eclat 利用频繁项集来生成关联规则:

工作原理...

Eclat 算法的说明

与使用 Apriori 算法的食谱类似,我们可以使用eclat函数来生成具有给定支持度(本例中假设支持度为 2)和最大长度的频繁项集。

工作原理...

生成频繁项集

然后,我们可以使用summary函数来获取汇总统计信息,包括:最频繁的项目、项集长度分布、质量度量摘要和挖掘信息。最后,我们可以按支持度对频繁项集进行排序,并检查前十个支持度最高的频繁项集。

相关内容

  • 除了 Apriori 和 Eclat,另一个流行的关联挖掘算法是FP-Growth。与 Eclat 类似,它也采用深度优先搜索来计数支持度。然而,目前没有可以从 CRAN 下载的 R 包包含此算法。但是,如果您对在事务数据集中应用 FP-growth 算法感兴趣,您可以参考 Christian Borgelt 的页面www.borgelt.net/fpgrowth.html以获取更多信息。

创建带有时间信息的交易

除了在事务数据库中挖掘有趣的关联之外,我们还可以使用带有时间信息的交易挖掘有趣的序列模式。在下面的菜谱中,我们展示了如何创建带有时间信息的交易。

准备工作

在这个菜谱中,我们将生成带有时间信息的交易。我们可以使用生成的交易作为频繁序列模式挖掘的输入源。

如何操作...

执行以下步骤以创建带有时间信息的交易:

  1. 首先,你需要安装并加载包arulesSequences

    > install.packages("arulesSequences")
    > library(arulesSequences)
    
    
  2. 你可以先创建一个包含购买记录的列表:

    > tmp_data=list(c("A"),
    +                c("A","B","C"),
    +                c("A","C"),
    +                c("D"),
    +                c("C","F"),
    +                c("A","D"),
    +                c("C"),
    +                c("B","C"),
    +                c("A","E"),
    +                c("E","F"),
    +                c("A","B"),
    +                c("D","F"),
    +                c("C"),
    +                c("B"),
    +                c("E"),
    +                c("G"),
    +                c("A","F"),
    +                c("C"),
    +                c("B"),
    +                c("C"))
    
    
  3. 然后,你可以将列表转换为交易并添加时间信息:

    >names(tmp_data) = paste("Tr",c(1:20), sep = "")
    >trans =  as(tmp_data,"transactions")
    >transactionInfo(trans)$sequenceID=c(1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4,4)
    >transactionInfo(trans)$eventID=c(10,20,30,40,50,10,20,30,40,10,20,30,40,50,10,20,30,40,50,60)
    > trans
    transactions in sparse format with
     20 transactions (rows) and
     7 items (columns)
    
    
  4. 接下来,你可以使用inspect函数来检查交易:

    > inspect(head(trans))
     items transactionID sequenceID eventID
    1 {A}             Tr1          1      10
    2 {A, 
     B, 
     C}             Tr2          1      20
    3 {A, 
     C}             Tr3          1      30
    4 {D}             Tr4          1      40
    5 {C, 
     F}             Tr5          1      50
    6 {A, 
     D}             Tr6          2      10
    
    
  5. 然后,你可以获取带有时间信息的交易的摘要信息:

    > summary(trans)
    transactions as itemMatrix in sparse format with
     20 rows (elements/itemsets/transactions) and
     7 columns (items) and a density of 0.2214286 
    
    most frequent items:
     C       A       B       F       D (Other) 
     8       7       5       4       3       4 
    
    element (itemset/transaction) length distribution:
    sizes
     1  2  3 
    10  9  1 
    
     Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     1.00    1.00    1.50    1.55    2.00    3.00 
    
    includes extended item information - examples:
     labels
    1      A
    2      B
    3      C
    
    includes extended transaction information - examples:
     transactionID sequenceID eventID
    1           Tr1          1      10
    2           Tr2          1      20
    3           Tr3          1      30
    
    
  6. 你也可以以篮子格式读取事务数据:

    > zaki=read_baskets(con = system.file("misc", "zaki.txt", package = "arulesSequences"), info = c("sequenceID","eventID","SIZE"))
    > as(zaki, "data.frame")
     transactionID.sequenceID transactionID.eventID transactionID.SIZE     items
    1                         1                    10                  2     {C,D}
    2                         1                    15                  3   {A,B,C}
    3                         1                    20                  3   {A,B,F}
    4                         1                    25                  4 {A,C,D,F}
    5                         2                    15                  3   {A,B,F}
    6                         2                    20                  1       {E}
    7                         3                    10                  3   {A,B,F}
    8                         4                    10                  3   {D,G,H}
    9                         4                    20                  2     {B,F}
    10                        4                    25                  3   {A,G,H}
    
    

工作原理...

在挖掘频繁序列模式之前,你必须创建带有时间信息的事务。在这个菜谱中,我们介绍了两种获取带有时间信息的事务的方法。在第一种方法中,我们创建一个事务列表,并为每个事务分配一个事务 ID。我们使用as函数将列表数据转换为事务数据集。然后我们添加eventIDsequenceID作为时间信息;sequenceID是事件所属的序列,eventID表示事件发生的时间。在生成带有时间信息的交易后,可以使用这个数据集进行频繁序列模式挖掘。

除了创建自己的带有时间信息的交易之外,如果你已经有一个存储在文本文件中的数据,你可以使用arulesSequences中的read_basket函数将事务数据读取到篮子格式。我们还可以读取事务数据集以进行进一步的频繁序列模式挖掘。

相关内容

  • arulesSequences函数提供了两个额外的数据结构,sequencestimedsequences,用于表示纯序列数据和带时间信息的序列数据。对于对这些两个集合感兴趣的人,请使用帮助函数查看以下文档:

    > help("sequences-class")
    > help("timedsequences-class")
    
    

使用 cSPADE 挖掘频繁序列模式

与仅发现项集之间关系的关联挖掘不同,我们可能对探索在一系列项集按顺序发生的事务中共享的模式感兴趣。

最著名的频繁序列模式挖掘算法之一是使用等价类的序列模式发现SPADE)算法,该算法利用垂直数据库的特性在 ID 列表上执行高效格搜索,并允许我们对挖掘的序列施加约束。在本食谱中,我们将演示如何使用 cSPADE 来挖掘频繁序列模式。

准备工作

在本食谱中,您必须通过生成带有时间信息的交易并存储在变量trans中来完成前面的食谱。

如何操作...

执行以下步骤以挖掘频繁序列模式:

  1. 首先,您可以使用cspade函数生成频繁序列模式:

    > s_result=cspade(trans,parameter = list(support = 0.75),control = list(verbose = TRUE))
    
    
  2. 然后,您可以检查频繁序列模式的摘要:

    > summary(s_result)
    set of 14 sequences with
    
    most frequent items:
     C       A       B       D       E (Other) 
     8       5       5       2       1       1 
    
    most frequent elements:
     {C}     {A}     {B}     {D}     {E} (Other) 
     8       5       5       2       1       1 
    
    element (sequence) size distribution:
    sizes
    1 2 3 
    6 6 2 
    
    sequence length distribution:
    lengths
    1 2 3 
    6 6 2 
    
    summary of quality measures:
     support 
     Min.   :0.7500 
     1st Qu.:0.7500 
     Median :0.7500 
     Mean   :0.8393 
     3rd Qu.:1.0000 
     Max.   :1.0000 
    
    includes transaction ID lists: FALSE 
    
    mining info:
     data ntransactions nsequences support
     trans            20          4    0.75
    
    
  3. 将生成的序列格式数据转换回数据框:

    > as(s_result, "data.frame")
     sequence support
    1          <{A}>    1.00
    2          <{B}>    1.00
    3          <{C}>    1.00
    4          <{D}>    0.75
    5          <{E}>    0.75
    6          <{F}>    0.75
    7      <{A},{C}>    1.00
    8      <{B},{C}>    0.75
    9      <{C},{C}>    0.75
    10     <{D},{C}>    0.75
    11 <{A},{C},{C}>    0.75
    12     <{A},{B}>    1.00
    13     <{C},{B}>    0.75
    14 <{A},{C},{B}>    0.75
    
    

它是如何工作的...

序列模式挖掘的目标是在事务中发现序列关系或模式。您可以使用模式挖掘结果来预测未来事件,或向用户推荐项目。

序列模式挖掘的一种流行方法是 SPADE。SPADE 使用垂直数据布局来存储 ID 列表。在这些列表中,数据库中的每个输入序列被称为 SID,给定输入序列中的每个事件被称为 EID。SPADE 的过程是通过按层次生成 Apriori 候选来进行的。具体来说,SPADE 通过从 ID 列表的交集生成(n-1)-序列来生成后续的 n-序列。如果序列的数量大于最小支持度minsup),我们可以认为序列足够频繁。算法停止,直到无法找到更多频繁序列为止:

它是如何工作的...

SPADE 算法的说明

在本食谱中,我们说明了如何使用频繁序列模式挖掘算法 cSPADE 来挖掘频繁序列模式。首先,由于我们已经将带有时间信息的交易加载到变量trans中,我们可以使用cspade函数,支持度超过 0.75,以sequences格式生成频繁序列模式。然后我们可以获取总结信息,例如最频繁的项目、序列大小分布、质量度量摘要和挖掘信息。最后,我们可以将生成的sequence信息转换回数据框格式,这样我们就可以检查支持度超过 0.75 的频繁序列模式的序列和支持度。

参考内容

  • 如果您对 SPADE 算法的概念和设计感兴趣,您可以参考原始发表的论文:M. J. Zaki. (2001). SPADE: An Efficient Algorithm for Mining Frequent Sequences. Machine Learning Journal, 42, 31–60。

第十一章. 降维

在本章中,我们将涵盖以下主题:

  • 使用 FSelector 进行特征选择

  • 使用 PCA 进行降维

  • 使用 scree 测试确定主成分的数量

  • 使用 Kaiser 方法确定主成分的数量

  • 使用双图可视化多元数据

  • 使用 MDS 进行降维

  • 使用奇异值分解(SVD)降维

  • 使用 SVD 压缩图像

  • 使用 ISOMAP 进行非线性降维

  • 使用局部线性嵌入进行非线性降维

简介

大多数数据集都包含高度冗余的特征(如属性或变量)。为了去除无关和冗余的数据,以降低计算成本并避免过拟合,你可以将特征减少到较小的子集,而不会造成信息损失。减少特征的数学过程称为降维。

特征的减少可以提高数据处理效率。因此,降维在模式识别、文本检索和机器学习等领域得到广泛应用。降维可以分为两个部分:特征提取和特征选择。特征提取是一种使用低维空间来表示高维空间中数据的技巧。特征选择用于找到原始变量的子集。

特征选择的目的是选择一组相关特征来构建模型。特征选择的技术可以分为特征排名和特征选择。特征排名根据一定标准对特征进行排名,然后选择超过定义阈值的特征。另一方面,特征选择从特征子集空间中搜索最优子集。

在特征提取中,问题可以分为线性或非线性。线性方法搜索一个最佳解释数据分布变化的仿射空间。相比之下,非线性方法对于分布在高度非线性曲面上数据的处理是一个更好的选择。在此,我们列出一些常见的线性和非线性方法。

这里有一些常见的线性方法:

  • PCA:主成分分析将数据映射到低维空间,使得低维表示中的数据方差最大化。

  • MDS:多维尺度分析是一种方法,它允许你可视化对象之间的接近程度(模式邻近性),并且可以使用低维空间表示你的数据。如果 MDS 中使用的距离测量等于数据的协方差,则 PCA 可以被视为 MDS 的最简单形式。

  • SVD:奇异值分解从线性代数的角度移除了线性相关的冗余特征。PCA 也可以被视为 SVD 的特例。

这里有一些常见的非线性方法:

  • ISOMAP:ISOMAP 可以看作是多维尺度分析(MDS)的扩展,它使用测地距离的距离度量。在此方法中,测地距离是通过绘制最短路径距离来计算的。

  • LLE:局部线性嵌入(Locally linear embedding)执行局部 PCA 和全局特征分解。LLE 是一种局部方法,它涉及为每个类特征类别选择特征。相比之下,ISOMAP 是一种全局方法,它涉及为所有特征选择特征。

在本章中,我们将首先讨论如何进行特征排名和选择。接下来,我们将聚焦于特征提取的主题,并涵盖使用线性和非线性方法进行降维的食谱。对于线性方法,我们将介绍如何执行主成分分析(PCA),确定主成分的数量及其可视化。然后,我们将继续介绍多维尺度分析(MDS)和奇异值分解(SVD)。此外,我们将介绍 SVD 在图像压缩中的应用。对于非线性方法,我们将介绍如何使用 ISOMAP 和 LLE 进行降维。

使用 FSelector 进行特征选择

FSelector包提供了两种从原始特征集中选择最具影响力的特征的方法。首先,根据某些标准对特征进行排名,并选择那些高于定义阈值的特征。其次,从一个特征子集的空间中搜索最佳特征子集。在本食谱中,我们将介绍如何使用FSelector包进行特征选择。

准备工作

在这个食谱中,我们将继续使用电信churn数据集作为输入数据源来训练支持向量机。对于那些尚未准备数据集的人,请参阅第五章, 分类(I) – 树、懒惰和概率,以获取详细信息。

如何操作...

执行以下步骤以在churn数据集上执行特征选择:

  1. 首先,安装并加载包,FSelector

    > install.packages("FSelector")
    > library(FSelector)
    
    
  2. 然后,我们可以使用random.forest.importance计算每个属性的权重,我们将重要性类型设置为 1:

    > weights = random.forest.importance(churn~., trainset, importance.type = 1)
    > print(weights)
     attr_importance
    international_plan                 96.3255882
    voice_mail_plan                    24.8921239
    number_vmail_messages              31.5420332
    total_day_minutes                  51.9365357
    total_day_calls                    -0.1766420
    total_day_charge                   53.7930096
    total_eve_minutes                  33.2006078
    total_eve_calls                    -2.2270323
    total_eve_charge                   32.4317375
    total_night_minutes                22.0888120
    total_night_calls                   0.3407087
    total_night_charge                 21.6368855
    total_intl_minutes                 32.4984413
    total_intl_calls                   51.1154046
    total_intl_charge                  32.4855194
    number_customer_service_calls     114.2566676
    
    
  3. 接下来,我们可以使用cutoff函数获取前五个权重的属性:

    > subset = cutoff.k(weights, 5)
    > f = as.simple.formula(subset, "Class")
    > print(f)
    Class ~ number_customer_service_calls + international_plan + 
     total_day_charge + total_day_minutes + total_intl_calls
    <environment: 0x00000000269a28e8>
    
    
  4. 接下来,我们可以创建一个评估器来选择特征子集:

    > evaluator = function(subset) {
    +   k = 5 
    +   set.seed(2)
    +   ind = sample(5, nrow(trainset), replace = TRUE)
    +   results = sapply(1:k, function(i) {
    +     train = trainset[ind ==i,]
    +     test  = trainset[ind !=i,]
    +     tree  = rpart(as.simple.formula(subset, "churn"), trainset)
    +     error.rate = sum(test$churn != predict(tree, test, type="class")) / nrow(test)
    +     return(1 - error.rate)
    +   })
    +   return(mean(results))
    + }
    
    
  5. 最后,我们可以使用爬山搜索找到最佳特征子集:

    > attr.subset = hill.climbing.search(names(trainset)[!names(trainset) %in% "churn"], evaluator)
    > f = as.simple.formula(attr.subset, "churn")
    > print(f)
    churn ~ international_plan + voice_mail_plan + number_vmail_messages + 
     total_day_minutes + total_day_calls + total_eve_minutes + 
     total_eve_charge + total_intl_minutes + total_intl_calls + 
     total_intl_charge + number_customer_service_calls
    <environment: 0x000000002224d3d0>
    
    

工作原理...

在这个示例中,我们展示了如何使用FSelector包来选择最有影响力的特征。我们首先演示了如何使用特征排名方法。在特征排名方法中,算法首先使用一个权重函数为每个特征生成权重。在这里,我们使用随机森林算法,以平均准确度下降(其中importance.type = 1)作为重要性度量来获取每个属性的权重。除了随机森林算法之外,您还可以从FSelector包中选择其他特征排名算法(例如,chi.squaredinformation.gain)。然后,该过程按权重对属性进行排序。最后,我们可以使用cutoff函数从排序的特征列表中获得前五个特征。在这种情况下,number_customer_service_callsinternational_plantotal_day_chargetotal_day_minutestotal_intl_calls是五个最重要的特征。

接下来,我们将说明如何搜索最佳特征子集。首先,我们需要创建一个五折交叉验证函数来评估特征子集的重要性。然后,我们使用爬山搜索算法从原始特征集中找到最佳特征子集。除了爬山法之外,您还可以从FSelector包中选择其他特征选择算法(例如,forward.search)。最后,我们可以发现international_plan + voice_mail_plan + number_vmail_messages + total_day_minutes + total_day_calls + total_eve_minutes + total_eve_charge + total_intl_minutes + total_intl_calls + total_intl_charge + number_customer_service_calls是最佳特征子集。

参考内容

  • 您也可以使用caret包来进行特征选择。正如我们在模型评估章节中讨论了相关食谱,您可以参考第七章,模型评估,以获取更详细的信息。

  • 对于特征排名和最佳特征选择,您可以探索FSelector包以获取更多相关函数:

    > help(package="FSelector")
    
    

使用 PCA 进行降维

主成分分析PCA)是处理降维问题中最广泛使用的线性方法。当数据包含许多特征,并且这些特征之间存在冗余(相关性)时,它非常有用。为了去除冗余特征,PCA 通过将特征减少到更少的、解释原始特征大部分方差的主成分,将高维数据映射到低维。在这个示例中,我们将介绍如何使用 PCA 方法进行降维。

准备工作

在这个示例中,我们将使用swiss数据集作为我们的目标来执行 PCA。swiss数据集包括来自瑞士 47 个法语省份大约 1888 年的标准化生育指标和社会经济指标。

如何操作...

执行以下步骤以对swiss数据集进行主成分分析:

  1. 首先,加载swiss数据集:

    > data(swiss)
    
    
  2. 排除swiss数据的第一列:

    > swiss = swiss[,-1]
    
    
  3. 然后,你可以对swiss数据进行主成分分析:

    > swiss.pca = prcomp(swiss,
    + center = TRUE,
    + scale  = TRUE)
    > swiss.pca
    Standard deviations:
    [1] 1.6228065 1.0354873 0.9033447 0.5592765 0.4067472
    
    Rotation:
     PC1         PC2          PC3        PC4         PC5
    Agriculture      0.52396452 -0.25834215  0.003003672 -0.8090741  0.06411415
    Examination  -0.57185792 -0.01145981 -0.039840522 -0.4224580 -0.70198942
    Education       -0.49150243  0.19028476  0.539337412 -0.3321615  0.56656945
    Catholic            0.38530580  0.36956307  0.725888143 0.1007965 -0.42176895
    Infant.Mortality 0.09167606 0.87197641 -0.424976789 -0.2154928 0.06488642
    
    
  4. 从 PCA 结果中获取摘要:

    > summary(swiss.pca)
    Importance of components:
     PC1    PC2    PC3     PC4     PC5
    Standard deviation     1.6228 1.0355 0.9033 0.55928 0.40675
    Proportion of Variance 0.5267 0.2145 0.1632 0.06256 0.03309
    Cumulative Proportion  0.5267 0.7411 0.9043 0.96691 1.00000
    
    
  5. 最后,你可以使用predict函数输出数据第一行的主成分值:

    > predict(swiss.pca, newdata=head(swiss, 1))
     PC1       PC2        PC3      PC4       PC5
    Courtelary -0.9390479 0.8047122 -0.8118681 1.000307 0.4618643
    
    

它是如何工作的...

由于特征选择方法可能会移除一些相关但具有信息量的特征,你必须考虑使用特征提取方法将这些相关特征组合成一个单一的特征。PCA 是特征提取方法之一,它通过正交变换将可能相关的变量转换为主成分。此外,你可以使用这些主成分来识别方差的方向。

PCA 的过程通过以下步骤进行:首先,找到均值向量,它是如何工作的...,其中它是如何工作的...表示数据点,n表示点的数量。其次,通过方程计算协方差矩阵,它是如何工作的...。第三,计算特征向量,它是如何工作的...,以及相应的特征值。在第四步,我们按顺序选择前k个特征向量。在第五步,我们构建一个d x k维的特征向量矩阵,U。在这里,d是原始维度的数量,k是特征向量的数量。最后,我们可以在方程中变换数据样本到新的子空间,它是如何工作的...

在以下图中,说明了我们可以使用两个主成分,它是如何工作的...它是如何工作的...,将数据点从二维空间转换到新的二维子空间:

它是如何工作的...

PCA 的一个示例说明

在这个菜谱中,我们使用stats包中的prcomp函数对swiss数据集进行 PCA。首先,我们移除标准化的生育率指标,并将剩余的预测变量作为输入传递给函数prcomp。此外,我们将swiss作为输入数据集;变量应通过指定center=TRUE移至零中心;通过选项scale=TRUE将变量缩放到单位方差,并将输出存储在变量swiss.pca中。

然后,当我们打印出存储在 swiss.pca 中的值时,我们可以找到主成分的标准差和旋转。标准差表示协方差/相关矩阵的特征值的平方根。另一方面,主成分的旋转显示了输入特征的线性组合的系数。例如,PC1 等于 Agriculture * 0.524 + Examination * -0.572 + Education * -0.492 + Catholic 0.385 + Infant.Mortality * 0.092*。在这里,我们可以发现属性 Agriculture 对 PC1 的贡献最大,因为它具有最高的系数。

此外,我们可以使用 summary 函数获取成分的重要性。第一行显示每个主成分的标准差,第二行显示每个成分解释的方差比例,第三行显示解释的方差累积比例。最后,你可以使用 predict 函数从输入特征中获取主成分。在这里,我们输入数据集的第一行,并检索五个主成分。

还有更多...

另一个主成分分析函数是 princomp。在这个函数中,计算是通过在相关或协方差矩阵上使用特征值而不是 prcomp 函数中使用的单一值分解来进行的。在一般实践中,使用 prcomp 是首选的;然而,我们在这里介绍了如何使用 princomp

  1. 首先,使用 princomp 执行主成分分析(PCA):

    > swiss.princomp = princomp(swiss,
    + center = TRUE,
    + scale  = TRUE)
    > swiss.princomp
    Call:
    princomp(x = swiss, center = TRUE, scale = TRUE)
    
    Standard deviations:
     Comp.1    Comp.2    Comp.3    Comp.4    Comp.5 
    42.896335 21.201887  7.587978  3.687888  2.721105 
    
     5 variables and 47 observations.
    
    
  2. 然后,你可以获取摘要信息:

    > summary(swiss.princomp)
    Importance of components:
     Comp.1     Comp.2     Comp.3      Comp.4      Comp.5
    Standard deviation     42.8963346 21.2018868 7.58797830 3.687888330 2.721104713
    Proportion of Variance  0.7770024  0.1898152 0.02431275 0.005742983 0.003126601
    Cumulative Proportion   0.7770024  0.9668177 0.99113042 0.996873399 1.000000000
    
    
  3. 你可以使用 predict 函数从输入特征中获取主成分:

    > predict(swiss.princomp, swiss[1,])
     Comp.1    Comp.2   Comp.3   Comp.4   Comp.5
    Courtelary -38.95923 -20.40504 12.45808 4.713234 -1.46634
    
    

除了 stats 包中的 prcompprincomp 函数外,你还可以使用 psych 包中的 principal 函数:

  1. 首先,安装并加载 psych 包:

    > install.packages("psych")
    > install.packages("GPArotation")
    > library(psych)
    
    
  2. 然后,你可以使用 principal 函数检索主成分:

    > swiss.principal = principal(swiss, nfactors=5, rotate="none")
    > swiss.principal
    Principal Components Analysis
    Call: principal(r = swiss, nfactors = 5, rotate = "none")
    Standardized loadings (pattern matrix) based upon correlation matrix
     PC1   PC2   PC3   PC4   PC5 h2       u2
    Agriculture      -0.85 -0.27  0.00  0.45 -0.03  1 -6.7e-16
    Examination       0.93 -0.01 -0.04  0.24  0.29  1  4.4e-16
    Education         0.80  0.20  0.49  0.19 -0.23  1  2.2e-16
    Catholic         -0.63  0.38  0.66 -0.06  0.17  1 -2.2e-16
    Infant.Mortality -0.15  0.90 -0.38  0.12 -0.03  1 -8.9e-16
    
     PC1  PC2  PC3  PC4  PC5
    SS loadings           2.63 1.07 0.82 0.31 0.17
    Proportion Var        0.53 0.21 0.16 0.06 0.03
    Cumulative Var        0.53 0.74 0.90 0.97 1.00
    Proportion Explained  0.53 0.21 0.16 0.06 0.03
    Cumulative Proportion 0.53 0.74 0.90 0.97 1.00
    
    Test of the hypothesis that 5 components are sufficient.
    
    The degrees of freedom for the null model are 10 and the objective function was 2.13
    The degrees of freedom for the model are -5  and the objective function was  0 
    The total number of observations was  47  with MLE Chi Square =  0  with prob <  NA 
    
    Fit based upon off diagonal values = 1
    
    

使用斯皮尔曼测试确定主成分的数量

由于我们只需要保留解释原始特征大部分方差的主成分,我们可以使用凯撒方法、斯皮尔曼测试或解释的方差百分比作为选择标准。斯皮尔曼测试的主要目的是将成分分析结果以斯皮尔曼图的形式绘制出来,并找到斜率(肘部)发生明显变化的位置。在这个菜谱中,我们将演示如何使用斯皮尔曼图确定主成分的数量。

准备工作

确保你已经完成了前面的菜谱,通过生成主成分对象并将其保存在变量 swiss.pca 中。

如何操作...

执行以下步骤以使用斯皮尔曼图确定主成分的数量:

  1. 首先,你可以使用 screeplot 生成条形图:

    > screeplot(swiss.pca, type="barplot")
    
    

    如何操作...

    以条形图形式展示的斯皮尔曼图

  2. 你也可以使用 screeplot 生成线形图:

    > screeplot(swiss.pca, type="line")
    
    

    如何操作...

    以线形图形式展示的斯皮尔曼图

工作原理...

在本菜谱中,我们展示了如何使用碎石图来确定主成分的数量。在碎石图中,有两种类型的图形,即柱状图和线形图。正如生成的碎石图所揭示的,斜率(所谓的拐点或膝部)的明显变化发生在第 2 个成分处。因此,我们应该保留第 1 个成分,在第 2 个成分之前,该成分处于陡峭的曲线,这是平坦线趋势开始的地方。然而,由于这种方法可能存在歧义,您可以使用其他方法(如凯撒方法)来确定成分的数量。

更多内容...

默认情况下,如果您在生成的主成分对象上使用plot函数,您也可以检索碎石图。有关screeplot的更多详细信息,请参阅以下文档:

> help(screeplot)

您还可以使用nfactors进行并行分析和 Cattell 碎石测试的非图形解决方案:

> install.packages("nFactors")
> library(nFactors)
> ev = eigen(cor(swiss))
> ap = parallel(subject=nrow(swiss),var=ncol(swiss),rep=100,cent=.05)
> nS = nScree(x=ev$values, aparallel=ap$eigen$qevpea)
> plotnScree(nS)

更多内容...

碎石测试的非图形解决方案

使用凯撒方法确定主成分的数量

除了碎石测试外,您还可以使用凯撒方法来确定主成分的数量。在此方法中,选择标准是保留大于1的特征值。在本菜谱中,我们将展示如何使用凯撒方法确定主成分的数量。

准备工作

确保您已经完成了前面的菜谱,通过生成主成分对象并将其保存在变量swiss.pca中。

如何操作...

按照以下步骤使用凯撒方法确定主成分的数量:

  1. 首先,您可以从swiss.pca中获取标准差:

    > swiss.pca$sdev 
    [1] 1.6228065 1.0354873 0.9033447 0.5592765 0.4067472
    
    
  2. 接着,您可以从swiss.pca中获取方差:

    > swiss.pca$sdev ^ 2
    [1] 2.6335008 1.0722340 0.8160316 0.3127902 0.1654433
    
    
  3. 选择方差大于 1 的成分:

    > which(swiss.pca$sdev ^ 2> 1)
    [1] 1 2
    
    
  4. 您还可以使用碎石图来选择方差大于 1 的成分:

    > screeplot(swiss.pca, type="line")
    > abline(h=1, col="red", lty= 3)
    
    

    如何操作...

    选择方差大于 1 的成分

工作原理...

您还可以使用凯撒方法来确定成分的数量。由于计算出的主成分对象包含每个成分的标准差,我们可以将方差计算为标准差,即方差的平方根。从计算出的方差中,我们发现第 1 个和第 2 个成分的方差都大于 1。因此,我们可以确定主成分的数量为 2(第 1 个和第 2 个成分)。此外,我们可以在碎石图上画一条红线(如图所示)来表示在这种情况下我们需要保留第 1 个和第 2 个成分。

参考资料也

为了确定要保留哪些主成分,请参考以下内容:

  • Ledesma, R. D. 和 Valero-Mora, P. (2007). 在 EFA 中确定要保留的因素数量:一个用于执行并行分析的易于使用的计算机程序. 实用评估、研究和评估, 12(2), 1-11.

使用双图可视化多元数据

为了找出数据变量如何映射到主成分上,您可以使用biplot,它将数据以及原始特征在第一两个成分上的投影绘制出来。在这个菜谱中,我们将演示如何使用biplot在同一张图上绘制变量和数据。

准备工作

确保您已经完成了之前的菜谱,通过生成主成分对象并将其保存在变量swiss.pca中。

如何操作...

执行以下步骤以创建 biplot:

  1. 您可以使用成分 1 和 2 创建散点图:

    >  plot(swiss.pca$x[,1], swiss.pca$x[,2], xlim=c(-4,4))
    > text(swiss.pca$x[,1], swiss.pca$x[,2], rownames(swiss.pca$x), cex=0.7, pos=4, col="red")
    
    

    如何操作...

    PCA 结果的前两个成分的散点图

  2. 如果您想在图上添加特征,您可以使用生成的主成分对象创建 biplot:

    > biplot(swiss.pca)
    
    

    如何操作...

    使用 PCA 结果的 biplot

工作原理...

在这个菜谱中,我们演示了如何使用biplot绘制数据和原始特征在第一两个成分上的投影。在第一步中,我们演示了实际上我们可以使用前两个成分来创建散点图。此外,如果您想在同一张图上添加变量,您可以使用biplot。在biplot中,您可以看到在农业变量中指标较高的省份,在教育变量中指标较低的省份,以及在 PC1 中得分较高的考试变量。另一方面,婴儿死亡率指标较高且农业指标较低的省份在 PC2 中得分较高。

还有更多...

除了stats包中的biplot,您还可以使用ggbiplot。但是,您可能无法从 CRAN 找到这个包;您必须首先安装devtools,然后从 GitHub 安装ggbiplot

> install.packages("devtools")

> library(ggbiplot)
> g = ggbiplot(swiss.pca, obs.scale = 1, var.scale = 1, 
+ ellipse = TRUE, 
+ circle = TRUE)
> print(g)

还有更多...

使用 PCA 结果的 ggbiplot

使用 MDS 进行降维

多维尺度分析MDS)是一种创建多个对象相似性或差异性(距离)的视觉表示的技术。前缀表示可以在一维、二维或更多维度中创建一个表示图。然而,我们最常使用 MDS 来展示一维或二维数据点之间的距离。

在 MDS 中,您可以使用度量或非度量解决方案。两种解决方案之间的主要区别在于,度量解决方案试图重现原始度量,而非度量解决方案假设距离的排名是已知的。在这个菜谱中,我们将说明如何在swiss数据集上执行 MDS。

准备工作

在这个菜谱中,我们将继续使用swiss数据集作为我们的输入数据源。

如何操作...

执行以下步骤以使用度量方法执行多维尺度分析:

  1. 首先,您可以使用最多两个维度执行度量 MDS:

    > swiss.dist =dist(swiss)
    > swiss.mds = cmdscale(swiss.dist, k=2)
    
    
  2. 然后,您可以将swiss数据绘制在二维散点图中:

    > plot(swiss.mds[,1], swiss.mds[,2], type = "n", main = "cmdscale (stats)")
    > text(swiss.mds[,1], swiss.mds[,2], rownames(swiss), cex = 0.9, xpd = TRUE)
    
    

    如何操作...

    从 cmdscale 对象得到的二维散点图

  3. 此外,您可以使用isoMDS执行非度量 MDS:

    > library(MASS)
    > swiss.nmmds = isoMDS(swiss.dist, k=2)
    initial  value 2.979731 
    iter   5 value 2.431486
    iter  10 value 2.343353
    final  value 2.338839 
    converged
    
    
  4. 你也可以在二维散点图上绘制数据点:

    > plot(swiss.nmmds$points, type = "n", main = "isoMDS (MASS)")
    > text(swiss.nmmds$points, rownames(swiss), cex = 0.9, xpd = TRUE)
    
    

    如何操作...

    从 isoMDS 对象生成的二维散点图

  5. 你还可以在二维散点图上绘制数据点:

    > swiss.sh = Shepard(swiss.dist, swiss.mds)
    > plot(swiss.sh, pch = ".")
    > lines(swiss.sh$x, swiss.sh$yf, type = "S")
    
    

    如何操作...

    从 isoMDS 对象生成的谢泼德图

如何工作...

MDS 通过提供一组对象之间相似性的视觉表示来揭示数据的结构。更详细地说,MDS 将一个对象放置在 n 维空间中,其中点对之间的距离对应于对象对之间的相似性。通常,维空间是二维欧几里得空间,但它可能是非欧几里得空间,并且具有超过两个维度。根据输入矩阵的意义,MDS 可以主要分为两种类型:度量 MDS,其中输入矩阵基于度量,非度量 MDS,其中输入矩阵基于非度量。

度量 MDS 也称为主坐标分析,它首先将距离转换为相似性。在最简单的情况下,该过程通过在相似性上执行主成分分析,将原始数据点线性投影到子空间。另一方面,该过程也可以通过最小化应力值如何工作...对相似性进行非线性投影,其中如何工作...是两点之间的距离测量,如何工作...如何工作...,而如何工作...是两个投影点的相似性度量,如何工作...如何工作...。因此,我们可以在欧几里得空间中表示对象之间的关系。

与使用基于度量的输入矩阵的度量 MDS 相比,当数据在序数级别测量时,使用基于非度量的 MDS。由于只有向量之间距离的秩序是有意义的,非度量 MDS 在原始距离上应用单调递增函数 f,并将距离投影到新的值,以保留秩序。归一化方程可以表示为如何工作...

在这个菜谱中,我们展示了如何在swiss数据集上执行度量和非度量 MDS。要执行度量 MDS,我们首先需要从swiss数据中获得距离度量。在这个步骤中,你可以将距离度量替换为任何度量,只要它产生数据点的相似性/不相似性度量。你可以使用cmdscale来执行度量多维度缩放。在这里,我们指定k = 2,因此生成的最大维度等于2。你还可以在二维散点图上直观地表示数据点的距离。

接下来,你可以使用isoMDS执行非度量 MDS。在非度量 MDS 中,我们不匹配距离,而只是按顺序排列它们。我们还将swiss设置为输入数据集,最大维度为两个。与度量 MDS 示例类似,我们可以在二维散点图上绘制数据点之间的距离。然后,我们使用谢泼德图,它显示了投影距离与距离矩阵中的距离匹配得有多好。根据步骤 4 中的图,投影距离在距离矩阵中匹配得很好。

还有更多...

另一种可视化方法是将以图形的形式表示 MDS 对象。以下是一个示例代码:

> library(igraph)
> swiss.sample = swiss[1:10,]

> g = graph.full(nrow(swiss.sample))
> V(g)$label = rownames(swiss.sample)
> layout = layout.mds(g, dist = as.matrix(dist(swiss.sample)))
> plot(g, layout = layout, vertex.size = 3)

还有更多...

MDS 对象的图形表示

你还可以比较 MDS 和 PCA 生成的结果之间的差异。你可以通过在同一散点图上绘制投影维度来比较它们的差异。如果你在 MDS 中使用欧几里得距离,则投影维度与从 PCA 投影的维度完全相同:

> swiss.dist = dist(swiss)
> swiss.mds = cmdscale(swiss.dist, k=2)
> plot(swiss.mds[,1], swiss.mds[,2], type="n")
> text(swiss.mds[,1], swiss.mds[,2], rownames(swiss), cex = 0.9, xpd = TRUE)
> swiss.pca = prcomp(swiss)
> text(-swiss.pca$x[,1],-swiss.pca$x[,2], rownames(swiss), 
+      ,col="blue", adj = c(0.2,-0.5),cex = 0.9, xpd = TRUE)

还有更多...

MDS 与 PCA 的比较

使用 SVD 降维

奇异值分解SVD)是一种矩阵分解(分解)类型,可以将矩阵分解为两个正交矩阵和对角矩阵。你可以使用这三个矩阵将原始矩阵乘回。从线性代数的角度来看,SVD 可以减少线性相关的冗余数据。因此,它可以应用于特征选择、图像处理、聚类以及许多其他领域。在这个菜谱中,我们将说明如何使用 SVD 进行降维。

准备工作

在这个菜谱中,我们将继续使用数据集swiss作为我们的输入数据源。

如何操作...

执行以下步骤以使用 SVD 进行降维:

  1. 首先,你可以在swiss数据集上执行svd

    > swiss.svd = svd(swiss)
    
    
  2. 然后,你可以根据 SVD 列绘制解释的方差百分比和累积解释的方差百分比:

    > plot(swiss.svd$d²/sum(swiss.svd$d²), type="l", xlab=" Singular vector", ylab = "Variance explained")
    
    

    如何操作...

    解释的方差百分比

    > plot(cumsum(swiss.svd$d²/sum(swiss.svd$d²)), type="l", xlab="Singular vector", ylab = "Cumulative percent of variance explained")
    
    

    如何操作...

    累积方差百分比

  3. 接下来,你可以使用仅一个奇异向量来重建数据:

    > swiss.recon = swiss.svd$u[,1] %*% diag(swiss.svd$d[1], length(1), length(1)) %*% t(swiss.svd$v[,1])
    
    
  4. 最后,你可以在图像中比较原始数据集与构建的数据集:

    > par(mfrow=c(1,2))
    > image(as.matrix(swiss), main="swiss data Image")
    > image(swiss.recon,  main="Reconstructed Image")
    
    

    如何操作...

    原始数据集与重建数据集之间的比较

如何工作...

SVD 是实数或复数矩阵的分解。具体来说,m x n 矩阵 A 的 SVD 是将 A 分解为三个矩阵的乘积如何工作...。在这里,U 是一个 m x m 的正交矩阵,D 包含奇异值,是一个 m x n 的对角矩阵,V^T 是一个 n x n 的正交矩阵。

在这个食谱中,我们展示了如何使用 SVD 进行降维。首先,你可以在swiss数据集上应用svd函数以获得分解矩阵。然后你可以生成两个图表:一个显示了根据奇异向量解释的方差,另一个显示了根据奇异向量解释的累积方差。

前面的图表明第一个奇异向量可以解释 80%的方差。我们现在想比较原始数据集和仅使用一个奇异向量重建的数据集之间的差异。因此,我们使用单个奇异向量重建数据,并使用image函数将原始和重建的数据集并排展示,以查看它们之间的差异。下一个图显示这两个图像非常相似。

参考阅读

  • 如我们之前提到的,PCA 可以被视为 SVD 的一个特例。在这里,我们从 SVD 生成的swiss数据的正交向量,并从prcomp获得旋转。我们可以看到这两个生成的矩阵是相同的:

    > svd.m = svd(scale(swiss))
    > svd.m$v
     [,1]        [,2]         [,3]       [,4]        [,5]
    [1,]  0.52396452 -0.25834215  0.003003672 -0.8090741  0.06411415
    [2,] -0.57185792 -0.01145981 -0.039840522 -0.4224580 -0.70198942
    [3,] -0.49150243  0.19028476  0.539337412 -0.3321615  0.56656945
    [4,]  0.38530580  0.36956307  0.725888143  0.1007965 -0.42176895
    [5,]  0.09167606  0.87197641 -0.424976789 -0.2154928  0.06488642
    > pca.m = prcomp(swiss,scale=TRUE)
    > pca.m$rotation
     PC1         PC2          PC3        PC4         PC5
    Agriculture      0.52396452 -0.25834215  0.003003672 -0.8090741  0.06411415
    Examination  -0.57185792 -0.01145981 -0.039840522 -0.4224580 -0.70198942
    Education       -0.49150243  0.19028476  0.539337412 -0.3321615  0.56656945
    Catholic          0.38530580  0.36956307  0.725888143  0.1007965 -0.42176895
    Infant.Mortality 0.09167606 0.87197641 -0.424976789 -0.2154928 0.06488642
    
    

使用 SVD 压缩图像

在上一个食谱中,我们展示了如何使用 SVD 分解矩阵,然后通过乘以分解矩阵来重建数据集。此外,矩阵分解的应用可以应用于图像压缩。在这个食谱中,我们将展示如何对经典图像处理材料 Lenna 执行 SVD。

准备工作

在这个食谱中,你应该事先下载 Lenna 的图像(参考www.ece.rice.edu/~wakin/images/lena512.bmp),或者你可以准备你自己的图像来查看图像压缩是如何工作的。

如何操作...

执行以下步骤以使用 SVD 压缩图像:

  1. 首先,安装并加载bmp

    > install.packages("bmp")
    > library(bmp)
    
    
  2. 你可以使用read.bmp函数将 Lenna 的图像读取为一个数值矩阵。当读取器下载图像时,默认名称是lena512.bmp

    > lenna = read.bmp("lena512.bmp")
    
    
  3. 旋转并绘制图像:

    > lenna = t(lenna)[,nrow(lenna):1]
    > image(lenna) 
    
    

    如何操作...

    Lenna 的图片

  4. 接下来,你可以对读取的数值矩阵执行 SVD 并绘制解释方差的百分比:

    > lenna.svd = svd(scale(lenna))
    > plot(lenna.svd$d²/sum(lenna.svd$d²), type="l", xlab=" Singular vector", ylab = "Variance explained")
    
    

    如何操作...

    解释方差的百分比

  5. 接下来,你可以获得重建图像所需的维度数:

    > length(lenna.svd$d)
    [1] 512
    
    
  6. 获得奇异向量可以解释超过 90%方差的点:

    > min(which(cumsum(lenna.svd$d²/sum(lenna.svd$d²))> 0.9))
    [1] 18
    
    
  7. 你也可以将代码封装成一个函数,lenna_compression,然后你可以使用这个函数来绘制压缩后的 Lenna:

    > lenna_compression = function(dim){
    +     u=as.matrix(lenna.svd$u[, 1:dim])
    +     v=as.matrix(lenna.svd$v[, 1:dim])
    +     d=as.matrix(diag(lenna.svd$d)[1:dim, 1:dim])
    +     image(u%*%d%*%t(v))
    + }
    
    
  8. 此外,你可以使用 18 个向量来重建图像:

    > lenna_compression(18)
    
    

    如何操作...

    由 18 个组件重建的图像

  9. 你可以获得奇异向量可以解释超过 99%方差的点;

    > min(which(cumsum(lenna.svd$d²/sum(lenna.svd$d²))> 0.99))
    [1] 92
    > lenna_compression(92)
    
    

    如何操作...

    由 92 个组件重建的图像

它是如何工作的...

在本菜谱中,我们展示了如何使用 SVD 压缩图像。在第一步中,我们使用bmp包将图像 Lenna 加载到 R 会话中。然后,由于读取的图像已旋转,我们可以将图像旋转回来并使用plot函数在 R 中绘制 Lenna(如图 3 步中的图所示)。接下来,我们对图像矩阵进行 SVD 分解,然后绘制与奇异向量数量相关的方差解释百分比。

此外,我们发现可以使用 18 个成分解释 90%的方差,因此我们使用这 18 个成分来重建 Lenna。因此,我们创建了一个名为lenna_compression的函数,其目的是通过矩阵乘法重建图像。结果,我们将 18 作为函数的输入,返回一个相当模糊的 Lenna 图像(如图 8 步中的图所示)。然而,我们至少可以看到图像的轮廓。为了获得更清晰的图像,我们发现可以使用 92 个成分解释 99%的方差。因此,我们将函数lenna_compression的输入设置为 92。第 9 步中的图显示,这比仅使用 18 个成分构建的图像更清晰。

参见

  • Lenna 图片是压缩算法最广泛使用的标准测试图像之一。有关 Lenna 图片的更多详细信息,请参阅www.cs.cmu.edu/~chuck/lennapg/

使用 ISOMAP 进行非线性降维

ISOMAP 是流形学习的一种方法,它将线性框架推广到非线性数据结构。与 MDS 类似,ISOMAP 创建了一系列对象相似性或差异性(距离)的视觉表示。然而,由于数据以非线性格式结构化,MDS 的欧几里得距离度量在 ISOMAP 中被数据流形的地形距离所取代。在本菜谱中,我们将说明如何使用 ISOMAP 进行非线性降维。

准备工作

在本菜谱中,我们将使用来自RnavGraphImageDatadigits数据作为我们的输入源。

如何操作...

执行以下步骤以使用 ISOMAP 进行非线性降维:

  1. 首先,安装并加载RnavGraphImageDatavegan包:

    > install.packages("RnavGraphImageData")
    > install.packages("vegan")
    > library(RnavGraphImageData)
    > library(vegan)
    
    
  2. 然后,你可以加载数据集digits

    > data(digits)
    
    
  3. 旋转并绘制图像:

    > sample.digit = matrix(digits[,3000],ncol = 16, byrow=FALSE)
    > image(t(sample.digit)[,nrow(sample.digit):1])
    
    

    如何操作...

    来自数字数据集的一个示例图像

  4. 接下来,你可以从总体中随机抽取 300 个数字:

    > set.seed(2)
    > digit.idx = sample(1:ncol(digits),size = 600)
    > digit.select = digits[,digit.idx]
    
    
  5. 将选定的数字数据转置,然后使用vegdist计算对象之间的差异:

    > digits.Transpose = t(digit.select)
    > digit.dist = vegdist(digits.Transpose, method="euclidean")
    
    
  6. 接下来,你可以使用isomap进行降维:

    > digit.isomap = isomap(digit.dist,k = 8, ndim=6, fragmentedOK = TRUE)
    > plot(digit.isomap)
    
    

    如何操作...

    ISOMAP 对象的一个二维散点图

  7. 最后,你可以将散点图与红色标记的最小生成树叠加;

    > digit.st = spantree(digit.dist)
    > digit.plot = plot(digit.isomap, main="isomap k=8")
    > lines(digit.st, digit.plot, col="red")
    
    

    如何操作...

    二维散点图与最小生成树的叠加

它是如何工作的...

ISOMAP 是一种非线性降维方法,也是等距映射方法的代表。ISOMAP 可以被视为度量 MDS 的扩展,其中数据点之间的成对欧几里得距离被由邻域图诱导的测地距离所取代。

ISOMAP 算法的描述分为四个步骤。首先,确定每个点的邻居。其次,构建一个邻域图。第三,计算两个节点之间的最短距离路径。最后,通过执行 MDS 找到数据的一个低维嵌入。

在这个菜谱中,我们展示了如何使用 ISOMAP 进行非线性降维。首先,我们从 RnavGraphImageData 加载数字数据。然后,在我们选择一个数字并绘制其旋转图像后,我们可以看到一个手写数字的图像(第 3 步中的图中的数字 3)。

接下来,我们随机抽取 300 个数字作为我们的输入数据给 ISOMAP。然后我们将数据集转置以计算每个图像对象之间的距离。一旦数据准备就绪,我们计算每个对象之间的距离并进行降维。在这里,我们使用 vegdist 通过欧几里得度量计算每个对象之间的不相似性。然后我们使用 ISOMAP 对 digits 数据进行非线性降维,维度设置为 6,保留一个点的最短不相似性数量为 8,并确保通过指定 fragmentedOKTRUE 来分析最大的连通组。

最后,我们可以使用生成的 ISOMAP 对象制作一个二维散点图(第 6 步中的图),并在散点图上用红色线条叠加最小生成树(第 7 步中的图)。

还有更多...

你还可以使用 RnavGraph 包通过图形作为导航基础设施来可视化高维数据(在这个例子中是数字)。有关更多信息,请参阅 www.icesi.edu.co/CRAN/web/packages/RnavGraph/vignettes/RnavGraph.pdf

这里是关于如何使用 RnavGraph 在图中可视化高维数据的描述:

  1. 首先,安装并加载 RnavGraphgraph 包:

    > install.packages("RnavGraph")
    > source("http://bioconductor.org/biocLite.R")
    > biocLite("graph")
    > library(RnavGraph)
    
    
  2. 然后,你可以从 digit 数据创建一个 NG_data 对象:

    > digit.group = rep(c(1:9,0), each = 1100)
    > digit.ng_data = ng_data(name = "ISO_digits",
    + data = data.frame(digit.isomap$points),
    + shortnames = paste('i',1:6, sep = ''),
    + group = digit.group[digit.idx],
    + labels = as.character(digits.group[digit.idx]))
    
    
  3. NG_data 创建一个 NG_graph 对象:

    >  V = shortnames(digit.ng_data)
    >  G = completegraph(V)
    >  LG =linegraph(G)
    >  LGnot = complement(LG)
    >  ng.LG = ng_graph(name = "3D Transition", graph = LG)
    > ng.LGnot = ng_graph(name = "4D Transition", graph = LGnot)
    
    
  4. 最后,你可以在 tk2d 绘图中可视化图形:

    > ng.i.digits = ng_image_array_gray('USPS Handwritten Digits',
    + digit.select,16,16,invert = TRUE,
    + img_in_row = FALSE)
    > vizDigits1 = ng_2d(data = digit.ng_data, graph = ng.LG, images = ng.i.digits)
    > vizDigits2 = ng_2d(data = digit.ng_data, graph = ng.LGnot, images = ng.i.digits)
    > nav = navGraph(data = digit.ng_data, graph = list(ng.LG, ng.LGnot), viz = list(vizDigits1, vizDigits2))
    
    

    还有更多...

    一个三维转换图

  5. 还可以查看一个四维转换图:还有更多...

    一个四维转换图

使用局部线性嵌入进行非线性降维

局部线性嵌入LLE)是 PCA 的扩展,它将嵌入在高维空间中的流形上的数据降低到低维空间。与 ISOMAP 不同,ISOMAP 是一种用于非线性降维的全局方法,LLE 是一种局部方法,它使用 k 近邻的线性组合来保留数据的局部属性。在本菜谱中,我们将简要介绍如何在 s 曲线数据上使用 LLE。

准备工作

在本菜谱中,我们将使用 lle 包中的 lle_scurve_data 中的数字数据作为我们的输入源。

如何操作...

执行以下步骤以使用 LLE 进行非线性降维:

  1. 首先,您需要安装并加载包,lle

    > install.packages("lle")
    > library(lle)
    
    
  2. 您可以从 lle 中加载 ll_scurve_data

    > data( lle_scurve_data )
    
    
  3. 然后,对 lle_scurve_data 执行 lle

    > X = lle_scurve_data
    > results = lle( X=X , m=2, k=12,  id=TRUE)
    finding neighbours
    calculating weights
    intrinsic dim: mean=2.47875, mode=2
    computing coordinates
    
    
  4. 使用 strplot 函数检查结果:

    > str( results )
    List of 4
     $ Y     : num [1:800, 1:2] -1.586 -0.415 0.896 0.513 1.477 ...
     $ X     : num [1:800, 1:3] 0.955 -0.66 -0.983 0.954 0.958 ...
     $ choise: NULL
     $ id    : num [1:800] 3 3 2 3 2 2 2 3 3 3 ...
    >plot( results$Y, main="embedded data", xlab=expression(y[1]), ylab=expression(y[2]) )
    
    

    如何操作...

    嵌入数据的 2-D 散点图

  5. 最后,您可以使用 plot_lle 来绘制 LLE 结果:

    > plot_lle( results$Y, X, FALSE, col="red", inter=TRUE )
    
    

    如何操作...

    LLE 结果的 LLE 图

如何工作...

LLE 是一种非线性降维方法,它计算高维数据的低维、邻域保留嵌入。LLE 的算法可以按以下步骤说明:首先,LLE 计算每个数据点的 k 个邻居,如何工作...。其次,它为每个点计算一组权重,这些权重最小化了残差误差之和,可以从其邻居中最佳地重建每个数据点。残差误差之和可以描述为 如何工作...,其中 如何工作... 如果 如何工作... 不是 如何工作... 的 k 个最近邻之一,并且对于每个 i,如何工作...。最后,找到由权重 W 最佳重建的向量 Y。成本函数可以表示为 如何工作...,约束条件为 如何工作...,和 如何工作...

在本菜谱中,我们展示了如何使用 LLE 进行非线性降维。首先,我们从 lle 中加载 lle_scurve_data。然后,我们使用两个维度和 12 个邻居执行 lle,并通过指定 id = TRUE 列出每个数据点的维度。LLE 有三个步骤,包括:为数据中的每个点构建邻域,找到在该邻域中线性逼近数据的权重,以及找到低维坐标。

接下来,我们可以使用 strplot 函数来检查数据。str 函数返回 X、Y、choice 和 ID。在这里,X 代表输入数据,Y 表示嵌入数据,choice 表示保留数据的索引向量,而子集选择和 ID 显示每个数据输入的维度。plot 函数返回嵌入数据的散点图。最后,我们使用 plot_lle 来绘制结果。在这里,我们通过将交互模式设置为 TRUE 来启用交互模式。

参见

  • 另一个用于非线性降维的有用软件包是 RDRToolbox,这是一个包含 ISOMAP 和 LLE 的非线性降维软件包。您可以使用以下命令安装 RDRToolbox

    > source("http://bioconductor.org/biocLite.R")
    > biocLite("RDRToolbox")
    > library(RDRToolbox)
    
    

第十二章:大数据分析(R 和 Hadoop)

在本章中,我们将涵盖以下主题:

  • 准备 RHadoop 环境

  • 安装 rmr2

  • 安装 rhdfs

  • 使用 rhdfs 操作 HDFS

  • 使用 RHadoop 实现词频统计问题

  • 比较 R MapReduce 程序和标准 R 程序的性能

  • 测试和调试 rmr2 程序

  • 安装 plyrmr

  • 使用 plyrmr 操作数据

  • 使用 RHadoop 进行机器学习

  • 在 Amazon EMR 上配置 RHadoop 集群

简介

RHadoop 是一组 R 包,使用户能够使用 Hadoop 处理和分析大数据。在了解如何设置 RHadoop 并将其付诸实践之前,我们必须知道为什么我们需要使用机器学习来处理大数据规模。

在前面的章节中,我们提到了 R 在进行数据分析和机器学习时的有用性。在传统的统计分析中,重点是分析历史样本(小数据),这可能会忽略很少发生但很有价值的事件和结果,导致不确定的结论。

云技术的出现使得客户与业务之间的实时互动变得更加频繁;因此,机器学习的重点现在已转向为各种客户开发准确的预测。例如,企业可以通过使用实时预测模型,根据个人行为提供实时个性化推荐或在线广告。

然而,如果数据(例如,所有在线用户的行为)太大,无法适应单台机器的内存,你就不得不使用超级计算机或其他可扩展的解决方案。最流行的可扩展大数据解决方案是 Hadoop,它是一个开源框架,能够在集群之间存储和执行并行计算。因此,你可以使用 RHadoop,它允许 R 利用 Hadoop 的可扩展性,帮助处理和分析大数据。在 RHadoop 中,有五个主要包,它们是:

  • rmr:这是 R 和 Hadoop MapReduce 之间的接口,通过调用 Hadoop 流式 MapReduce API 在 Hadoop 集群中执行 MapReduce 作业。要开发 R MapReduce 程序,你只需要关注 map 和 reduce 函数的设计,其余的可扩展性问题将由 Hadoop 本身处理。

  • rhdfs:这是 R 和 HDFS 之间的接口,通过调用 HDFS API 来访问存储在 HDFS 中的数据。使用rhdfs的方式与使用 Hadoop shell 非常相似,它允许用户从 R 控制台轻松地操作 HDFS。

  • rhbase:这是 R 和 HBase 之间的接口,通过 Thrift 服务器在集群中访问 HBase。你可以使用rhbase来读写数据并操作存储在 HBase 中的表。

  • plyrmr:这是 MapReduce 的高级抽象,允许用户以 plyr-like 语法执行常见的数据操作。这个包大大降低了大数据操作的学习曲线。

  • ravro:这允许用户在 R 中读取avro文件或写入avro文件。它允许 R 与 HDFS 交换数据。

在本章中,我们将首先准备 Hadoop 环境,以便你可以安装 RHadoop。然后,我们将介绍三个主要包的安装:rmrrhdfsplyrmr。接下来,我们将介绍如何使用rmr从 R 执行 MapReduce,通过rhdfs操作 HDFS 文件,并使用plyrmr执行常见的数据操作。进一步,我们将探讨如何使用 RHadoop 进行机器学习。最后,我们将介绍如何在 Amazon EC2 上部署多个 RHadoop 集群。

准备 RHadoop 环境

由于 RHadoop 需要一个 R 和 Hadoop 集成环境,我们必须首先准备一个安装了 R 和 Hadoop 的环境。我们不必构建一个新的 Hadoop 系统,可以使用Cloudera QuickStart VM(该 VM 免费),它包含一个节点 Apache Hadoop 集群和 R。在这个菜谱中,我们将演示如何下载 Cloudera QuickStart VM。

准备工作

要使用 Cloudera QuickStart VM,建议你准备一个 64 位虚拟机操作系统,安装 VMWare 或 VirtualBox,或者安装 KVM。

如果你选择使用 VMWare,你应该准备一个与 WorkStation 8.x 或更高版本兼容的播放器:4.x 或更高版本,ESXi 5.x 或更高版本,或者 Fusion 4.x 或更高版本。

注意,启动 VM 需要 4 GB 的 RAM,至少有 3 GB 的可用磁盘空间。

如何操作...

使用 Cloudera QuickStart VM 设置 Hadoop 环境的以下步骤:

  1. 访问 Cloudera QuickStart VM 下载站点(你可能需要更新链接,因为 Cloudera 升级了其 VMs,当前 CDH 版本为 5.3),请参阅www.cloudera.com/content/cloudera/en/downloads/quickstart_vms/cdh-5-3-x.html如何操作...

    Cloudera QuickStart VM 下载站点的截图

  2. 根据你操作系统上安装的虚拟机平台,选择适当的链接(你可能需要更新链接,因为 Cloudera 升级了其 VMs)以下载 VM 文件:

  3. 接下来,您可以使用安装在您的操作系统上的虚拟机平台启动 QuickStart 虚拟机。您应该在几分钟内看到 Centos 6.2 的桌面。如何操作...

    Cloudera QuickStart 虚拟机的截图。

  4. 您可以打开一个终端并输入 hadoop,这将显示可以操作 Hadoop 集群的一组功能。如何操作...

    输入 hadoop 后的终端截图

  5. 打开一个终端并输入 R。访问 R 会话并检查版本 3.1.1 是否已在 Cloudera QuickStart 虚拟机中安装。如果您在虚拟机中找不到已安装的 R,请使用以下命令安装 R:

    $ yum install R R-core R-core-devel R-devel
    
    

它是如何工作的...

您不必自己构建 Hadoop 系统,可以使用 Cloudera 提供的 Hadoop VM 应用程序(虚拟机是免费的)。QuickStart 虚拟机在 CentOS 6.2 上运行,包含单个节点 Apache Hadoop 集群、Hadoop 生态系统模块和已安装的 R。这可以帮助您节省时间,而不是需要您学习如何安装和使用 Hadoop。

QuickStart 虚拟机要求您拥有一个具有 64 位客户操作系统的计算机,至少 4 GB 的 RAM、3 GB 的磁盘空间,并且已安装 VMWare、VirtualBox 或 KVM。因此,您可能无法在某些计算机上使用此版本的虚拟机。作为替代方案,您可以考虑使用 Amazon 的 Elastic MapReduce。我们将在本章的最后一个小节中说明如何在 EMR 中准备 RHadoop 环境。

设置 Cloudera QuickStart 虚拟机很简单。从下载站点下载虚拟机,然后使用 VMWare、VirtualBox 或 KVM 打开构建的镜像。一旦您可以看到 CentOS 的桌面,您就可以访问终端并输入 hadoop 来查看 Hadoop 是否正在运行;然后,输入 R 来查看 R 是否在 QuickStart 虚拟机中运行。

参见

安装 rmr2

rmr2 包允许您通过 Hadoop 集群上的 MapReduce 执行大数据处理和分析。要在 Hadoop 集群上执行 MapReduce,您必须在每个任务节点上安装 R 和 rmr2。在本菜谱中,我们将说明如何在 Hadoop 集群的单个节点上安装 rmr2

准备工作

确保您已完成了前面的菜谱,通过启动 Cloudera QuickStart 虚拟机并将其连接到互联网,以便您可以继续下载和安装 rmr2 包。

如何操作...

执行以下步骤在 QuickStart 虚拟机上安装 rmr2

  1. 首先,在 Cloudera QuickStart 虚拟机内部打开终端。

  2. 使用 root 权限进入 R 会话:

    $ sudo R
    
    
  3. 您可以在安装 rmr2 之前安装依赖包:

    > install.packages(c("codetools", "Rcpp", "RJSONIO", "bitops", "digest", "functional", "stringr", "plyr", "reshape2", "rJava", "caTools"))
    
    
  4. 退出 R 会话:

    > q()
    
    
  5. 接下来,您可以将 rmr-3.3.0 下载到 QuickStart VM 上。如果 Revolution Analytics 升级了 rmr2 的版本,您可能需要更新链接:

    $ wget --no-check-certificate https://raw.githubusercontent.com/RevolutionAnalytics/rmr2/3.3.0/build/rmr2_3.3.0.tar.gz
    
    
  6. 然后,您可以将 rmr-3.3.0 安装到 QuickStart VM 上:

    $ sudo R CMD INSTALL rmr2_3.3.0.tar.gz
    
    
  7. 最后,您可以进入 R 会话并使用 library 函数来测试库是否已成功安装:

    $ R
    > library(rmr2)
    
    

它是如何工作的...

为了在 Hadoop 集群上执行 MapReduce,您必须在每个任务节点上安装 R 和 RHadoop。在此,我们将说明如何在 Hadoop 集群的单个节点上安装 rmr2。首先,打开 Cloudera QuickStart VM 的终端。在安装 rmr2 之前,我们首先以 root 权限访问 R 会话并安装依赖的 R 包。

接下来,在所有依赖包安装完成后,退出 R 会话,并在 Linux shell 中使用 wget 命令从 GitHub 下载 rmr-3.3.0 到本地文件系统。然后,您可以开始安装 rmr2。最后,您可以通过 R 会话使用库函数来验证包是否已安装。

参考信息

安装 rhdfs

rhdfs 包是 R 和 HDFS 之间的接口,它允许用户从 R 控制台访问 HDFS。类似于 rmr2,应该在每个任务节点上安装 rhdfs,以便可以通过 R 控制台访问 HDFS 资源。在本菜谱中,我们将介绍如何在 Cloudera QuickStart VM 上安装 rhdfs

准备工作

确保您已通过启动 Cloudera QuickStart VM 并将其连接到互联网来完成前面的菜谱,这样您就可以继续下载和安装 rhdfs 包。

如何操作...

执行以下步骤来安装 rhdfs

  1. 首先,您可以从 GitHub 下载 rhdfs 1.0.8。如果 Revolution Analytics 升级了 rhdfs 的版本,您可能需要更新链接:

    $wget --no-check-certificate https://raw.github.com/RevolutionAnalytics/rhdfs/master/build/rhdfs_1.0.8.tar.gz
    
    
  2. 接下来,您可以在命令行模式下安装 rhdfs

    $ sudo HADOOP_CMD=/usr/bin/hadoop  R CMD INSTALL rhdfs_1.0.8.tar.gz
    
    
  3. 然后,您可以设置 JAVA_HOMEJAVA_HOME 的配置取决于 VM 内安装的 Java 版本:

    $ sudo JAVA_HOME=/usr/java/jdk1.7.0_67-cloudera R CMD javareconf
    
    
  4. 最后,您可以设置系统环境和初始化 rhdfs。如果您使用的是不同版本的 QuickStart VM,可能需要更新环境设置:

    $ R
    > Sys.setenv(HADOOP_CMD="/usr/bin/hadoop")
    > Sys.setenv(HADOOP_STREAMING="/usr/lib/hadoop-mapreduce/hadoop-
    streaming-2.5.0-cdh5.2.0.jar")
    > library(rhdfs)
    > hdfs.init()
    
    

它是如何工作的...

rhdfs 提供了函数,使用户可以使用 R 管理 HDFS。类似于 rmr2,您应该在每个任务节点上安装 rhdfs,以便可以通过 R 控制台访问 HDFS。

要安装 rhdfs,您首先应从 GitHub 下载 rhdfs。然后,您可以通过指定 HADOOP_CMD 的位置来在 R 中安装 rhdfs。您必须通过命令 javareconf 配置 R 以支持 Java。

接下来,您可以访问 R 并配置 HADOOP_CMDHADOOP_STREAMING 的位置。最后,您可以通过 rhdfs.init 函数初始化 rhdfs,这允许您通过 rhdfs 开始操作 HDFS。

参见

  • 要查找 HADOOP_CMD 的位置,您可以在 Linux shell 中使用 which hadoop 命令。在大多数 Hadoop 系统中,HADOOP_CMD 位于 /usr/bin/hadoop

  • 对于 HADOOP_STREAMING 的位置,流 JAR 文件通常位于 /usr/lib/hadoop-mapreduce/。但是,如果您在 Linux 系统中找不到 /usr/lib/Hadoop-mapreduce 目录,您可以使用 locate 命令搜索流 JAR。例如:

    $ sudo updatedb
    $ locate streaming | grep jar | more
    
    

使用 rhdfs 操作 HDFS

rhdfs 包是 Hadoop 和 R 之间的接口,可以在后端调用 HDFS API 来操作 HDFS。因此,您可以通过使用 rhdfs 包轻松地从 R 控制台操作 HDFS。在下面的菜谱中,我们将演示如何使用 rhdfs 函数操作 HDFS。

准备工作

要继续本菜谱,您需要完成之前的菜谱,将 rhdfs 安装到 R 中,并验证您可以通过 hdfs.init 函数初始化 HDFS。

如何做...

执行以下步骤以操作存储在 HDFS 上的文件:

  1. 初始化 rhdfs 包:

    > Sys.setenv(HADOOP_CMD="/usr/bin/hadoop")
    > Sys.setenv(HADOOP_STREAMING="/usr/lib/hadoop-mapreduce/hadoop-streaming-2.5.0-cdh5.2.0.jar")
    > library(rhdfs)
    > hdfs.init ()
    
    
  2. 然后,您可以按照以下方式操作存储在 HDFS 上的文件:

    • hdfs.put: 从本地文件系统复制文件到 HDFS:

      > hdfs.put('word.txt', './')
      
      
    • hdfs.ls: 读取 HDFS 中的目录列表:

      > hdfs.ls('./')
      
      
    • hdfs.copy: 将文件从一个 HDFS 目录复制到另一个目录:

      > hdfs.copy('word.txt', 'wordcnt.txt')
      
      
    • hdfs.move:将文件从一个 HDFS 目录移动到另一个目录:

      > hdfs.move('wordcnt.txt', './data/wordcnt.txt')
      
      
    • hdfs.delete: 从 R 删除 HDFS 目录:

      > hdfs.delete('./data/')
      
      
    • hdfs.rm: 从 R 删除 HDFS 目录:

      > hdfs.rm('./data/')
      
      
    • hdfs.get: 从 HDFS 下载文件到本地文件系统:

      > hdfs.get(word.txt', '/home/cloudera/word.txt')
      
      
    • hdfs.rename: 重命名 HDFS 上存储的文件:

      hdfs.rename('./test/q1.txt','./test/test.txt')
      
      
    • hdfs.chmod: 更改文件或目录的权限:

      > hdfs.chmod('test', permissions= '777')
      
      
    • hdfs.file.info: 读取 HDFS 文件的元信息:

      > hdfs.file.info('./')
      
      
  3. 此外,您还可以将流写入 HDFS 文件:

    > f = hdfs.file("iris.txt","w")
    > data(iris)
    > hdfs.write(iris,f)
    > hdfs.close(f)
    
    
  4. 最后,您还可以从 HDFS 文件中读取流:

    > f = hdfs.file("iris.txt", "r")
    > dfserialized = hdfs.read(f)
    > df = unserialize(dfserialized)
    > df
    > hdfs.close(f)
    
    

工作原理...

在本菜谱中,我们演示如何使用 rhdfs 包操作 HDFS。通常,您可以使用 Hadoop shell 操作 HDFS,但如果您想从 R 访问 HDFS,则可以使用 rhdfs 包。

在开始使用 rhdfs 之前,您必须使用 hdfs.init() 初始化 rhdfs。初始化后,您可以通过 rhdfs 包中提供的函数操作 HDFS。

除了操作 HDFS 文件外,您还可以通过 hdfs.readhdfs.write 将流交换到 HDFS。因此,我们将演示如何使用 hdfs.write 将 R 中的数据框写入 HDFS 文件,iris.txt。最后,您可以使用 hdfs.read 函数和 unserialize 函数将写入的文件恢复到数据框。

参见

  • 要初始化rhdfs,您必须在系统环境中设置HADOOP_CMDHADOOP_STREAMING。您不必每次使用rhdfs时都设置配置,可以将配置放在.rprofile文件中。因此,每次您启动一个 R 会话时,配置将自动加载。

使用 RHadoop 实现单词计数问题

为了演示 MapReduce 是如何工作的,我们以单词计数为例,它计算给定输入集中每个单词的出现次数。在这个菜谱中,我们将演示如何使用rmr2实现单词计数问题。

准备工作

在这个菜谱中,我们需要一个输入文件作为我们的单词计数程序输入。您可以从github.com/ywchiu/ml_R_cookbook/tree/master/CH12下载示例输入文件。

如何做...

执行以下步骤以实现单词计数程序:

  1. 首先,您需要配置系统环境,然后将rmr2rhdfs加载到一个 R 会话中。如果您使用的是不同版本的 QuickStart VM,可能需要更新 JAR 文件的使用:

    > Sys.setenv(HADOOP_CMD="/usr/bin/hadoop")
    > Sys.setenv(HADOOP_STREAMING="/usr/lib/hadoop-mapreduce/hadoop-streaming-2.5.0-cdh5.2.0.jar ")
    > library(rmr2)
    > library(rhdfs)
    > hdfs.init()
    
    
  2. 您可以在 HDFS 上创建一个目录并将输入文件放入新创建的目录中:

    > hdfs.mkdir("/user/cloudera/wordcount/data")
    > hdfs.put("wc_input.txt", "/user/cloudera/wordcount/data")
    
    
  3. 接下来,您可以创建一个map函数:

    > map = function(.,lines) { keyval(
    +   unlist(
    +     strsplit(
    +       x = lines, 
    +       split = " +")),
    +   1)}
    
    
  4. 创建一个reduce函数:

    > reduce = function(word, counts) { 
    +   keyval(word, sum(counts)) 
    + }
    
    
  5. 调用 MapReduce 程序来计数文档中的单词:

    > hdfs.root = 'wordcount' > hdfs.data = file.path(hdfs.root, 'data')
    > hdfs.out = file.path(hdfs.root, 'out')
    > wordcount = function (input, output=NULL) { 
    +  mapreduce(input=input, output=output, input.format="text", map=map, 
    +  reduce=reduce) 
    + } 
    > out = wordcount(hdfs.data, hdfs.out)
    
    
  6. 最后,您可以检索文档中出现的最频繁的 10 个单词:

    > results = from.dfs(out) 
    > results$key[order(results$val, decreasing = TRUE)][1:10]
    
    

它是如何工作的...

在这个菜谱中,我们演示了如何使用rmr2包实现单词计数。首先,我们需要配置系统环境并将rhdfsrmr2加载到 R 中。然后,我们通过hdfs.put函数将我们的单词计数程序的输入从本地文件系统指定到 HDFS 目录/user/cloudera/wordcount/data

接下来,我们开始实现 MapReduce 程序。通常,我们可以将 MapReduce 程序分为mapreduce函数。在map函数中,我们首先使用strsplit函数将每一行拆分成单词。然后,由于strsplit函数返回一个单词列表,我们可以使用unlist函数将字符向量转换为列表。最后,我们可以返回键值对,其中每个单词作为键,值为一。由于reduce函数接收来自map函数生成的键值对,reduce函数将计数求和并返回每个单词(或键)的出现次数。

在我们实现了mapreduce函数之后,我们可以通过mapreduce函数提交我们的作业。通常,mapreduce函数需要四个输入,分别是 HDFS 输入路径、HDFS 输出路径、map 函数和 reduce 函数。在这种情况下,我们指定输入为wordcount/data,输出为wordcount/out,mapfunction 为map,reduce function 为reduce,并将mapreduce调用封装在wordcount函数中。最后,我们调用函数wordcount并将输出路径存储在变量out中。

我们可以使用from.dfs函数将 HDFS 数据加载到results变量中,该变量包含单词和出现次数的映射。然后我们可以从results变量中生成出现次数最多的前 10 个单词。

参见

比较 R MapReduce 程序和标准 R 程序的性能

对于不熟悉 Hadoop 工作原理的人来说,他们可能会经常将 Hadoop 视为大数据处理的一种补救措施。有些人可能认为 Hadoop 可以在几毫秒内为任何大小的数据返回处理结果。在这个菜谱中,我们将比较 R MapReduce 程序和标准 R 程序的性能,以证明 Hadoop 的运行速度并不像一些人认为的那样快。

准备工作

在这个菜谱中,你应该通过将rmr2安装到 R 环境中来完成之前的菜谱。

如何做...

执行以下步骤来比较标准 R 程序和 R MapReduce 程序的性能:

  1. 首先,你可以实现一个标准 R 程序来将所有数字平方:

    > a.time = proc.time() 
    > small.ints2=1:100000 
    > result.normal = sapply(small.ints2, function(x) x²) 
    > proc.time() - a.time
    
    
  2. 为了比较性能,你可以实现一个 R MapReduce 程序来将所有数字平方:

    > b.time = proc.time() 
    > small.ints= to.dfs(1:100000) 
    > result = mapreduce(input = small.ints, map = function(k,v)       cbind(v,v²)) 
    > proc.time() - b.time
    
    

它是如何工作的...

在这个菜谱中,我们实现了两个程序来平方所有数字。在第一个程序中,我们使用标准的 R 函数``sapply来平方从 1 到 100,000 的序列。为了记录程序执行时间,我们在执行前首先记录处理时间到a.time,然后从执行后的当前处理时间中减去a.time。通常,执行时间不超过 10 秒。在第二个程序中,我们使用rmr2`包在 R MapReduce 版本中实现程序。在这个程序中,我们也记录了执行时间。通常,这个程序需要几分钟来完成一个任务。

性能比较显示,当处理少量数据时,标准 R 程序的性能优于 MapReduce 程序。这是因为 Hadoop 系统通常需要时间来启动守护进程,守护进程之间的作业协调,以及从数据节点获取数据。因此,MapReduce 程序通常需要几分钟到几个小时来完成执行。因此,如果你可以将你的数据放入内存中,你应该编写一个标准 R 程序来解决问题。否则,如果数据太大而无法放入内存,你可以实现一个 MapReduce 解决方案。

参见

  • 为了检查一个作业在 Hadoop 中是否能够顺利高效地运行,你可以运行一个 MapReduce 基准测试,MRBench,来评估作业的性能:

    $ hadoop jar /usr/lib/hadoop-0.20-mapreduce/hadoop-test.jar mrbench -numRuns 50
    
    

测试和调试 rmr2 程序

由于运行 MapReduce 程序将需要相当多的时间,从几分钟到几小时不等,因此测试和调试变得非常重要。在这个菜谱中,我们将展示您可以用来调试 R MapReduce 程序的一些技术。

准备工作

在这个菜谱中,您应该通过将 rmr2 安装到 R 环境中来完成前面的菜谱。

如何操作...

执行以下步骤以测试和调试 R MapReduce 程序:

  1. 首先,您可以在 rmr.options 中将后端配置为本地:

    > rmr.options(backend = 'local')
    
    
  2. 再次,您可以执行前面菜谱中提到的数字平方 MapReduce 程序:

    > b.time = proc.time() 
    > small.ints= to.dfs(1:100000) 
    > result = mapreduce(input = small.ints, map = function(k,v)       cbind(v,v²)) 
    > proc.time() - b.time
    
    
  3. 此外,如果您想在 MapReduce 程序中打印任何变量的结构信息,您可以使用 rmr.str 函数:

    > out = mapreduce(to.dfs(1), map = function(k, v) rmr.str(v))
    Dotted pair list of 14
     $ : language mapreduce(to.dfs(1), map = function(k, v) rmr.str(v))
     $ : language mr(map = map, reduce = reduce, combine = combine, vectorized.reduce, in.folder = if (is.list(input)) {     lapply(input, to.dfs.path) ...
     $ : language c.keyval(do.call(c, lapply(in.folder, function(fname) {     kv = get.data(fname) ...
     $ : language do.call(c, lapply(in.folder, function(fname) {     kv = get.data(fname) ...
     $ : language lapply(in.folder, function(fname) {     kv = get.data(fname) ...
     $ : language FUN("/tmp/Rtmp813BFJ/file25af6e85cfde"[[1L]], ...)
     $ : language unname(tapply(1:lkv, ceiling((1:lkv)/(lkv/(object.size(kv)/10⁶))), function(r) {     kvr = slice.keyval(kv, r) ...
     $ : language tapply(1:lkv, ceiling((1:lkv)/(lkv/(object.size(kv)/10⁶))), function(r) {     kvr = slice.keyval(kv, r) ...
     $ : language lapply(X = split(X, group), FUN = FUN, ...)
     $ : language FUN(X[[1L]], ...)
     $ : language as.keyval(map(keys(kvr), values(kvr)))
     $ : language is.keyval(x)
     $ : language map(keys(kvr), values(kvr))
     $ :length 2 rmr.str(v)
     ..- attr(*, "srcref")=Class 'srcref'  atomic [1:8] 1 34 1 58 34 58 1 1
     .. .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x3f984f0> 
    v
     num 1
    
    

它是如何工作的...

在这个菜谱中,我们介绍了一些在实现 MapReduce 程序时可以使用的调试和测试技术。首先,我们介绍了在本地模式下测试 MapReduce 程序的技术。如果您想以伪分布式或完全分布式模式运行 MapReduce 程序,这将花费您几分钟到几小时的时间来完成,这将在调试您的 MapReduce 程序时造成大量时间的浪费。因此,您可以在 rmr.options 中将后端设置为本地模式,这样程序将以本地模式执行,执行时间更短。

另一种调试技术是在 mapreduce 函数中列出变量的内容。在 R 程序中,您可以使用 str 函数显示单个变量的紧凑结构。在 rmr2 中,该包还提供了一个名为 rmr.str 的函数,允许您将单个变量的内容打印到控制台。在这个例子中,我们使用 rmr.str 来打印 MapReduce 程序中变量的内容。

参考以下内容

  • 对于那些对 rmr2 包的 option 设置感兴趣的人,您可以参考 rmr.options 的帮助文档:

    > help(rmr.options)
    
    

安装 plyrmr

plyrmr 包为用户提供了一些常见操作(如在 plyrreshape2 中找到的操作),以便用户能够通过 MapReduce 框架轻松进行数据处理。在这个菜谱中,我们将介绍如何在 Hadoop 系统上安装 plyrmr

准备工作

通过启动 Cloudera QuickStart 虚拟机并将其连接到互联网,确保您已经完成了前面的菜谱。此外,您需要事先安装 rmr2 包。

如何操作...

执行以下步骤在 Hadoop 系统上安装 plyrmr

  1. 首先,您应该在 Linux 命令行中安装 libxml2-develcurl-devel

    $ yum install libxml2-devel
    $ sudo yum install curl-devel
    
    
  2. 然后,您可以访问 R 并安装依赖包:

    $ sudo R
    > Install.packages(c(" Rcurl", "httr"),  dependencies = TRUE
    > Install.packages("devtools", dependencies = TRUE)
    > library(devtools)
    > install_github("pryr", "hadley")
    > install.packages(c(" R.methodsS3", "hydroPSO"),  dependencies = TRUE)
    > q()
    
    
  3. 接下来,您可以在 Hadoop 虚拟机上下载 plyrmr 0.5.0 并安装它。如果 Revolution Analytics 升级了 plyrmr 的版本,您可能需要更新链接:

    $ wget -no-check-certificate https://raw.github.com/RevolutionAnalytics/plyrmr/master/build/plyrmr_0.5.0.tar.gz
    $ sudo R CMD INSTALL plyrmr_0.5.0.tar.gz
    
    
  4. 最后,验证安装:

    $ R
    > library(plyrmr)
    
    

它是如何工作的...

除了使用rmr2包编写 R MapReduce 程序外,您还可以使用plyrmr来操作数据。plyrmr包类似于 Hadoop 生态系统中的 hive 和 pig,它是 MapReduce 程序的高级抽象。因此,我们可以以plyr风格实现 R MapReduce 程序,而不是实现mapreduce函数。

要安装plyrmr,首先使用yum install命令安装libxml2-develcurl-devel包。然后,进入 R 并安装依赖包。最后,从 GitHub 下载文件并在 R 中安装plyrmr

参考以下内容

  • 要获取有关plyrmr的更多信息,您可以使用help函数参考以下文档:

    > help(package=plyrmr) 
    
    

使用 plyrmr 操作数据

虽然使用rmr2编写 MapReduce 程序比编写原生 Java 版本要容易得多,但对于非开发者来说,编写 MapReduce 程序仍然很困难。因此,您可以使用plyrmr,它是 MapReduce 程序的高级抽象,这样您就可以使用类似于 plyr 的操作来操作大数据。在本菜谱中,我们将介绍一些您可以用来操作数据的操作。

准备工作

在本菜谱中,您应该已经通过在 R 中安装plyrmrrmr2来完成之前的菜谱。

如何操作...

按照以下步骤使用plyrmr操作数据:

  1. 首先,您需要将plyrmrrmr2都加载到 R 中:

    > library(rmr2)
    > library(plyrmr)
    
    
  2. 然后,您可以将执行模式设置为本地模式:

    > plyrmr.options(backend="local")
    
    
  3. 接着,将泰坦尼克号数据集加载到 R 中:

    > data(Titanic)
    > titanic = data.frame(Titanic)
    
    
  4. 通过过滤数据开始操作:

    > where(
    +    Titanic, 
    + Freq >=100)
    
    
  5. 您还可以使用管道操作符过滤数据:

    > titanic %|% where(Freq >=100)
    
    
  6. 将泰坦尼克号数据放入 HDFS,并将数据路径加载到变量tidata中:

    > tidata = to.dfs(data.frame(Titanic), output = '/tmp/titanic')
    > tidata
    
    
  7. 接下来,您可以从泰坦尼克号数据中生成频率的汇总:

    > input(tidata) %|% transmute(sum(Freq))
    
    
  8. 您还可以按性别分组频率:

    > input(tidata) %|% group(Sex) %|% transmute(sum(Freq))
    
    
  9. 您可以从总体中抽取 10 条记录作为样本:

    > sample(input(tidata), n=10)
    
    
  10. 此外,您还可以使用 plyrmr 将两个数据集连接起来:

    > convert_tb = data.frame(Label=c("No","Yes"), Symbol=c(0,1))
    ctb = to.dfs(convert_tb, output = 'convert')
    > as.data.frame(plyrmr::merge(input(tidata), input(ctb), by.x="Survived", by.y="Label"))
    > file.remove('convert')
    
    

工作原理...

在本菜谱中,我们介绍如何使用plyrmr操作数据。首先,我们需要将plyrmr包加载到 R 中。然后,类似于rmr2,您必须将plyrmr的后端选项设置为本地模式。否则,如果plyrmr在 Hadoop 模式下运行(默认设置),您可能需要等待几分钟到几个小时。

接下来,我们可以开始使用数据过滤进行数据操作。您可以选择在步骤 4 中调用嵌套在其他函数调用中的函数。另一方面,您可以使用管道操作符%|%来链式执行多个操作。因此,我们可以在步骤 5 中使用管道操作符执行类似于步骤 4 的数据过滤。

接下来,你可以使用to.dfs根据当前运行模式将数据集输入到 HDFS 或本地文件系统。该函数将生成数据集的路径并将其保存在变量tidata中。通过知道路径,你可以使用input函数访问数据。接下来,我们将展示如何使用transmutesum函数从泰坦尼克号数据集中生成频率的总和。此外,plyrmr允许用户按性别汇总频率。

此外,为了从总体中采样数据,你也可以使用sample函数从泰坦尼克号数据集中选择 10 条记录。最后,我们演示了如何使用plyrmrmerge函数合并两个数据集。

参见

这里我们列出了一些可以使用plyrmr来操作数据的函数。你可以参考help函数以获取它们的使用和功能的更多详细信息:

  • 数据操作:

    • bind.cols: 这用于添加新列

    • select: 这用于选择列

    • where: 这用于选择行

    • transmute: 这使用上述所有内容及其汇总

  • reshape2

    • meltdcast:它将长宽数据框进行转换
  • 摘要:

    • count

    • quantile

    • sample

  • 提取:

    • top.k

    • bottom.k

使用 RHadoop 进行机器学习

在前面的章节中,我们已经展示了当使用 R 解决机器学习问题时,R 是多么强大。我们还展示了使用 Hadoop 可以使 R 并行处理大数据。此时,有些人可能认为使用 RHadoop 可以通过现有的许多机器学习包轻松解决大数据的机器学习问题。然而,你不能使用其中大多数来解决机器学习问题,因为它们不能在 MapReduce 模式下执行。在下面的菜谱中,我们将展示如何实现线性回归的 MapReduce 版本,并将其与使用lm函数的版本进行比较。

准备工作

在这个菜谱中,你应该通过将rmr2安装到 R 环境中来完成之前的菜谱。

如何操作...

执行以下步骤以在 MapReduce 中实现线性回归:

  1. 首先,从MASS包中加载cats数据集:

    > library(MASS)
    > data(cats)
    > X = matrix(cats$Bwt)
    > y = matrix(cats$Hwt)
    
    
  2. 你可以通过调用lm函数来生成线性回归模型:

    > model = lm(y~X)
    > summary(model)
    
    Call:
    lm(formula = y ~ X)
    
    Residuals:
     Min      1Q  Median      3Q     Max 
    -3.5694 -0.9634 -0.0921  1.0426  5.1238 
    
    Coefficients:
     Estimate Std. Error t value Pr(>|t|) 
    (Intercept)  -0.3567     0.6923  -0.515    0.607 
    X             4.0341     0.2503  16.119   <2e-16 ***
    ---
    Signif. codes: 
    0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    Residual standard error: 1.452 on 142 degrees of freedom
    Multiple R-squared:  0.6466,  Adjusted R-squared:  0.6441 
    F-statistic: 259.8 on 1 and 142 DF,  p-value: < 2.2e-16
    
    
  3. 你现在可以使用给定的数据点和模型制作回归图:

    > plot(y~X)
    > abline(model, col="red")
    
    

    如何操作...

    cats 数据集的线性回归图

  4. rmr2加载到 R 中:

    > Sys.setenv(HADOOP_CMD="/usr/bin/hadoop")
    > Sys.setenv(HADOOP_STREAMING="/usr/lib/hadoop-mapreduce/hadoop-> streaming-2.5.0-cdh5.2.0.jar")
    > library(rmr2)
    > rmr.options(backend="local")
    
    
  5. 你可以设置Xy的值:

    > X = matrix(cats$Bwt)
    > X.index = to.dfs(cbind(1:nrow(X), X))
    > y = as.matrix(cats$Hwt)
    
    
  6. 创建一个Sum函数来汇总值:

    > Sum = 
    +   function(., YY) 
    +     keyval(1, list(Reduce('+', YY)))
    
    
  7. 在 MapReduce 的Job1中计算Xtx

    > XtX = 
    +    values(
    +      from.dfs(
    +        mapreduce(
    +          input = X.index,
    +          map = 
    +            function(., Xi) {
    +              Xi = Xi[,-1]
    +              keyval(1, list(t(Xi) %*% Xi))},
    +          reduce = Sum,
    +          combine = TRUE)))[[1]]
    
    
  8. 你可以在 MapReduce 的Job2中计算Xty

    Xty = 
    +    values(
    +      from.dfs(
    +        mapreduce(
    +          input = X.index,
    +          map = function(., Xi) {
    +            yi = y[Xi[,1],]
    +            Xi = Xi[,-1]
    +            keyval(1, list(t(Xi) %*% yi))},
    +          reduce = Sum,
    +          combine = TRUE)))[[1]]
    
    
  9. 最后,你可以从XtXXty中推导出系数:

    > solve(XtX, Xty)
     [,1]
    [1,] 3.907113
    
    

它是如何工作的...

在这个菜谱中,我们展示了如何在 R 中用 MapReduce 风格实现线性逻辑回归。在我们开始实现之前,我们回顾了传统线性模型是如何工作的。我们首先从MASS包中检索cats数据集。然后我们将X作为体重(Bwt)和y作为心脏重量(Hwt)加载。

接下来,我们开始使用lm函数将数据拟合到线性回归模型中。然后我们可以计算拟合模型并获得模型的摘要。摘要显示系数为 4.0341,截距为-0.3567。此外,我们根据给定的数据点绘制散点图,然后在图上绘制回归线。

由于我们不能在 MapReduce 形式中使用lm函数进行线性回归,我们必须以 MapReduce 风格重写回归模型。在这里,我们希望分三步实现线性回归的 MapReduce 版本,这些步骤是:使用 MapReduce 计算Xtx值,任务 1,使用 MapReduce 计算Xty值,任务 2,然后推导出系数值:

  • 在第一步中,我们将矩阵X作为输入传递给map函数。然后map函数计算转置矩阵XX的叉积。然后reduce函数执行之前定义的求和操作。

  • 在第二步中,计算Xty的过程与计算XtX的过程类似。这个过程计算了转置矩阵Xy的叉积。然后reduce函数执行之前定义的求和操作。

  • 最后,我们使用solve函数推导出系数,其值为 3.907113。

如结果所示,lm和 MapReduce 计算出的系数略有差异。一般来说,lm模型计算出的系数比 MapReduce 计算出的更准确。然而,如果你的数据太大而无法适应内存,你不得不选择在 MapReduce 版本中实现线性回归。

参考信息

在 Amazon EMR 上配置 RHadoop 集群

到目前为止,我们只演示了如何在单个 Hadoop 节点上运行 RHadoop 程序。为了在多节点集群上测试我们的 RHadoop 程序,你需要做的唯一一件事是在 Hadoop 集群的所有任务节点(无论是 mapreduce 版本 1 的任务跟踪器还是 map reduce 版本 2 的节点管理器)上安装 RHadoop。然而,部署和安装是耗时的。另一方面,你可以选择在 Amazon EMR 上部署你的 RHadoop 程序,这样你就可以在几分钟内部署多节点集群和 RHadoop 到每个任务节点。在下面的菜谱中,我们将演示如何在 Amazon EMR 服务上配置 RHadoop 集群。

准备工作

在这个菜谱中,你必须注册并创建 AWS 账户,并且在使用 Amazon EMR 之前,你必须知道如何生成 EC2 密钥对。

对于那些寻求如何开始使用 AWS 的更多信息的人,请参阅亚马逊提供的教程docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html

如何操作...

在 Amazon EMR 上配置 RHadoop 的以下步骤

  1. 首先,你可以访问亚马逊网络服务的控制台(参考us-west-2.console.aws.amazon.com/console/),在分析部分找到 EMR。然后,点击EMR。如何操作...

    从 AWS 控制台访问 EMR 服务。

  2. 你应该发现自己处于 EMR 仪表板的集群列表中(参考us-west-2.console.aws.amazon.com/elasticmapreduce/home?region=us-west-2#cluster-list::);点击创建集群。如何操作...

    EMR 集群列表

  3. 然后,你应该发现自己处于创建集群页面(参考us-west-2.console.aws.amazon.com/elasticmapreduce/home?region=us-west-2#create-cluster:)。

  4. 接下来,你应在集群配置中指定集群名称日志文件夹 S3 位置。如何操作...

    创建集群页面中的集群配置

  5. 然后,你可以在软件配置中配置 Hadoop 发行版。如何操作...

    配置软件和应用程序

  6. 接下来,你可以在 Hadoop 集群内配置节点数量。如何操作...

    配置 Hadoop 集群内的硬件

  7. 然后,你可以指定用于主节点登录的 EC2 密钥对。如何操作...

    EMR 集群主节点的安全和访问

  8. 要设置 RHadoop,必须在每个任务节点上执行引导操作来安装 RHadoop。请创建一个名为 bootstrapRHadoop.sh 的文件,并在文件中插入以下行:

    echo 'install.packages(c("codetools", "Rcpp", "RJSONIO", "bitops", "digest", "functional", "stringr", "plyr", "reshape2", "rJava", "caTools"), repos="http://cran.us.r-project.org")' > /home/hadoop/installPackage.R
    sudo Rscript /home/hadoop/installPackage.R
    wget --no-check-certificate https://raw.githubusercontent.com/RevolutionAnalytics/rmr2/master/build/rmr2_3.3.0.tar.gz
    sudo R CMD INSTALL rmr2_3.3.0.tar.gz
    wget --no-check-certificate https://raw.github.com/RevolutionAnalytics/rhdfs/master/build/rhdfs_1.0.8.tar.gz
    sudo HADOOP_CMD=/home/hadoop/bin/hadoop R CMD INSTALL rhdfs_1.0.8.tar.gz
    
  9. 你应该将 bootstrapRHadoop.sh 上传到 S3

  10. 现在,你需要使用自定义操作添加引导操作,并在 S3 位置添加 s3://<location>/bootstrapRHadoop.sh。如何操作...

    设置引导操作

  11. 接下来,你可以点击创建集群来启动 Hadoop 集群。如何操作...

    创建集群

  12. 最后,当集群准备就绪时,你应该看到主节点的公共 DNS。现在,你可以使用你的 EC2 密钥对访问主节点的终端:如何操作...

    创建集群的截图

它是如何工作的...

在这个菜谱中,我们展示了如何在 Amazon EMR 上设置 RHadoop。这样做的好处是,您只需点击几下,在几分钟内就可以快速创建一个可扩展的、按需的 Hadoop。这有助于节省您构建和部署 Hadoop 应用程序的时间。然而,您必须为每个实例的运行时间付费。在使用 Amazon EMR 之前,您应该创建一个 AWS 账户,并了解如何设置 EC2 密钥对和 S3。然后,您可以在 Amazon EMR 上开始安装 RHadoop。

在第一步中,访问 EMR 集群列表并点击 创建集群。您可以在 创建集群 页面上看到配置列表。然后,您应该在集群配置中的 S3 位置设置集群名称和日志文件夹。

接下来,您可以设置软件配置并选择您想要安装的 Hadoop 发行版。亚马逊提供自己的发行版和 MapR 发行版。通常情况下,除非您对默认的 Hadoop 发行版有顾虑,否则您会跳过这一部分。

然后,通过指定主节点、核心节点和任务节点来配置硬件。默认情况下,只有一个主节点和两个核心节点。如果您愿意,可以添加更多核心节点和任务节点。然后,您应该设置密钥对以登录主节点。

接下来,创建一个包含所有启动脚本名为 bootstrapRHadoop.sh 的文件。文件创建后,您应该将其保存在 S3 存储中。然后,您可以在 引导操作 中指定 custom action,并将 bootstrapRHadoop.sh 作为引导脚本。最后,您可以点击 创建集群 并等待集群就绪。一旦集群就绪,您可以看到主节点的公共 DNS,并可以使用 EC2 密钥对访问主节点的终端。

警告!如果您不想继续使用 EMR 服务,请终止正在运行的实例。否则,您将按实例每小时收费。

参见

  • Google 也提供了自己的云解决方案,即 Google 计算引擎。如果您想了解更多信息,请参阅 cloud.google.com/compute/

附录 A. R 和机器学习资源

以下表格列出了 R 和机器学习的所有资源:

R 简介
标题
《R 动作》
《R 编程艺术:统计软件设计之旅》
《R 简介》
Quick-R
在线课程
标题
使用 R 进行数据分析(含 R)
数据分析
数据分析与统计推断
机器学习
标题
为黑客的机器学习
使用 R 进行机器学习
在线博客
标题
R 博客
R 杂志
CRAN 任务视图
标题
CRAN 任务视图:机器学习和统计学习

附录 B. 数据集 – 泰坦尼克号乘客的生存情况

在探索过程之前,我们想介绍这里采用的例子。它是关于 RMS 泰坦尼克号上乘客的人口统计信息,由 Kaggle 提供(www.kaggle.com/,一个数据预测竞赛的平台)。我们正在考察的结果是乘客是否能在船难中幸存。

应用这个数据集有两个原因:

  • RMS 泰坦尼克号被认为是历史上最臭名昭著的船难,死亡人数高达 1,502 人,占 2,224 名乘客和船员的近三分之二。然而,在船沉没后,乘客的生存机会并不仅仅取决于运气;实际上,舱位等级、性别、年龄和其他因素也可能影响了他们的生存机会。

  • 该数据集相对简单;你不需要花大部分时间在数据处理上(除非处理一些缺失值),但你可以专注于探索性分析的应用。

下面的图表是目标数据集的变量描述:

数据集 – 泰坦尼克号乘客的生存情况

从变量的描述来看,人们可能会有一些疑问,例如,“这个数据集中是否有缺失值?”、“泰坦尼克号乘客的平均年龄是多少?”、“有多少比例的乘客在灾难中幸存?”、“船上大多数乘客属于哪个社会阶层?”在这里提出的所有这些问题都将在 第二章 《使用 RMS 泰坦尼克号进行数据探索》 中得到解答。

除了与描述性统计相关的问题之外,第二章 《使用 RMS 泰坦尼克号进行数据探索》 的最终目标是生成一个模型,用以预测给定输入参数下的生存概率。除此之外,我们还将评估所生成模型的性能,以确定该模型是否适合该问题。

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