大数据分析实践指南-全-

大数据分析实践指南(全)

原文:zh.annas-archive.org/md5/622C4EC47FAAB3CE38900F0C3C942E11

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

本书介绍了与企业中使用的大数据相关的广泛主题。大数据是一个广阔的领域,涵盖了技术、统计、可视化、商业智能以及许多其他相关学科的要素。为了从数据中获得真正的价值,通常由于数据量或技术限制而无法访问,公司必须在软件和硬件层面上利用适当的工具。

因此,本书不仅涵盖了大数据的理论和实践方面,还通过高层次的主题,如企业中的大数据使用、大数据和数据科学计划以及资源、硬件/软件堆栈等关键考虑因素,补充了信息。这些讨论对计划实施或升级组织大数据和/或数据科学平台的组织的 IT 部门将是有用的。

本书重点关注三个主要领域:

1. 大规模数据集上的数据挖掘

今天,大数据是无处不在的,就像不久前的“数据仓库”一样无所不在。行业中有无数的解决方案。特别是 Hadoop 及其生态系统中的产品已经在企业中变得受欢迎且越来越普遍。此外,更近期的创新,如 Apache Spark,也在企业中找到了永久的存在——Hadoop 客户意识到他们可能不需要 Hadoop 框架的复杂性,已经大量转向 Spark。最后,NoSQL 解决方案,如 MongoDB、Redis、Cassandra 以及 Teradata、Vertica 和 kdb+等商业解决方案已经取代了更传统的数据库系统。

本书将以相当深度涵盖这些领域。已经涵盖了 Hadoop 及其相关产品,如 Hive、HBase、Pig Latin 等。我们还涵盖了 Spark,并解释了 Spark 中的关键概念,如操作和转换。还涵盖了诸如 MongoDB 和 KDB+等 NoSQL 解决方案,并提供了实际操作的教程。

2. 机器学习和预测分析

已涵盖的第二个主题是机器学习,也被称为预测分析、统计学习等其他各种名称。提供了使用 R 和 R 中的机器学习包编写的相应机器学习代码的详细解释。已讨论了诸如随机森林、支持向量机、神经网络、随机梯度提升、决策树等算法。此外,还涵盖了机器学习中的关键概念,如偏差和方差、正则化、特征选择、数据预处理等。

3. 企业中的数据挖掘

一般来说,涵盖理论主题的书籍很少讨论大数据的更高层次方面,比如成功的大数据计划的关键要求。本书包括 IT 高管的调查结果,并突出了行业共同的需求。本书还包括了如何根据大型 IT 部门部署生产解决方案的经验教训,逐步指南选择正确的用例,无论是用于大数据还是基于机器学习的内容。

我们相信,凭借对这三个领域的扎实基础知识,任何从业者都可以成功交付大数据和/或数据科学项目。这是本书整体结构和内容的主要意图。

这本书适合谁

本书面向各种受众群体。特别是那些渴望全面了解大数据、数据科学和/或机器学习概念的读者,即它们如何相互关联,将从本书中获益最多。

技术受众:对于技术方面的读者,本书包含了大数据和机器学习的关键行业工具的详细解释。涵盖了使用 Hadoop 进行实践练习,使用 R 编程语言开发机器学习用例,以及使用 R Shiny 构建全面的生产级仪表板。还包括了 Spark 和 NoSQL 的其他教程。除了实践方面,还解释了这些关键技术的理论基础。

商业受众:对大数据的广泛理论和实践处理已经补充了围绕在工作场所部署和实施强大大数据解决方案的微妙问题的高层主题。IT 管理、CIO 组织、业务分析和其他负责定义围绕数据的企业战略的团体将发现这些信息非常有用和直接适用。

本书内容

第一章《大数据的初步介绍》涵盖了大数据和机器学习的基本概念以及使用的工具,并对大数据分析的一般理解进行了介绍。

第二章《大数据挖掘入门》介绍了企业大数据挖掘的概念,并介绍了企业大数据的软件和硬件架构堆栈。

第三章《分析工具包》讨论了用于大数据和机器学习的各种工具,并提供了关于用户可以下载和安装工具(如 R、Python 和 Hadoop)的逐步说明。

第四章《使用 Hadoop 的大数据》介绍了 Hadoop 的基本概念,并深入探讨了 Hadoop 生态系统的详细技术方面。解释了 Hadoop 的核心组件,如 Hadoop 分布式文件系统(HDFS)、Hadoop Yarn、Hadoop MapReduce 以及 Hadoop 2 中的概念,如 ResourceManager、NodeManger、Application Master。该章节还包括了使用 Cloudera Distribution of Hadoop(CDH)通过 Hive 的逐步教程。

第五章《使用 NoSQL 进行大数据分析》介绍了各种新兴和独特的数据库解决方案,通常被称为 NoSQL,它颠覆了关系数据库的传统模型。我们将讨论 NoSQL 的核心概念和技术方面。本节涵盖了各种类型的 NoSQL 系统,如内存型、列式、基于文档、键值、图形等。还包括了与 MongoDB 和 MongoDB Compass 界面相关的教程,以及一个关于使用 kdb+创建生产级 R Shiny 仪表板的非常全面的教程。

第六章《大数据分析的 Spark》介绍了如何使用 Spark 进行大数据分析。涵盖了高层概念和技术主题。涵盖了 SparkContext、有向无环图、操作和转换等关键概念。还提供了关于在 Databricks 上使用 Spark 的完整教程,这是一个用户可以利用 Spark 的平台。

第七章《机器学习概念的初步介绍》介绍了机器学习的基本概念。此外,还讨论了监督学习与无监督学习、分类、回归、特征工程、数据预处理和交叉验证等核心概念。该章节以使用 R 库进行神经网络的简要教程结束。

第八章《机器学习深入探讨》深入探讨了机器学习的一些更深入的方面。算法、偏差、方差、正则化以及机器学习中的各种其他概念都得到了深入讨论。该章还包括了随机森林、支持向量机、决策树等算法的解释。该章以创建基于 Web 的机器学习应用程序的全面教程结束。

第九章《企业数据科学》讨论了部署企业级数据科学和大数据解决方案的技术考虑因素。我们还将讨论全球企业实施大数据战略的各种方式,包括基于云的解决方案。该章还提供了使用 AWS - 亚马逊网络服务的分步教程。

第十章《关于大数据的结束思考》讨论了企业大数据和数据科学战略,并以一些关于如何使大数据相关项目成功的指针结束。

附录 A《大数据进一步阅读》包含了更广泛理解大数据的链接。

为了充分利用本书

  1. 对 Unix 的一般知识将非常有帮助,尽管不是强制性的

  2. 需要使用连接到互联网的计算机才能下载练习中使用的必要工具和软件

  3. 没有假设先前对主题领域的知识

  4. 所有软件和工具的安装说明都在第三章《分析工具包》中提供。

下载示例代码文件

您可以从www.packtpub.com的帐户中下载本书的示例代码文件。如果您在其他地方购买了本书,可以访问www.packtpub.com/support并注册,文件将直接发送到您的邮箱。

您可以按照以下步骤下载代码文件:

  1. 登录或注册www.packtpub.com

  2. 选择“支持”选项卡。

  3. 单击“代码下载和勘误”。

  4. 在搜索框中输入书名,然后按照屏幕上的说明操作。

下载文件后,请确保使用最新版本的解压缩或提取文件夹:

  • Windows 上的 WinRAR/7-Zip

  • Mac 上的 Zipeg/iZip/UnRarX

  • Linux 上的 7-Zip/PeaZip

该书的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Practical-Big-Data-Analytics。我们还有其他代码包来自我们丰富的图书和视频目录,可以在github.com/PacktPublishing/上找到。去看看吧!

下载彩色图片

我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图片。您可以在这里下载:www.packtpub.com/sites/default/files/downloads/PracticalBigDataAnalytics_ColorImages.pdf

使用的约定

本书中使用了许多文本约定。

CodeInText:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。例如:“结果存储在 HDFS 的/user/cloudera/output下。”

代码块设置如下:

   "_id" : ObjectId("597cdbb193acc5c362e7ae97"), 
   "firstName" : "Nina", 
   "age" : 53, 
   "frequentFlyer" : [ 
          "Delta", 
          "JetBlue", 
          "Delta" 

任何命令行输入或输出都以以下形式书写:

$ cd Downloads/ # cd to the folder where you have downloaded the zip file 

粗体:表示新术语、重要词汇或屏幕上看到的词语。例如,菜单或对话框中的词语会在文本中以这种方式出现。例如:“这种额外开销可以通过使用虚拟机VMs)轻松减轻。”

警告或重要说明会以这种形式出现。

提示和技巧会出现在这样。

第一章:太大还是不太大

大数据分析包括与大规模数据集的挖掘、分析和预测建模相关的各种功能。信息的快速增长和技术发展为世界各地的个人和企业提供了独特的机会,以利润和开发新能力,利用大规模分析重新定义传统的商业模式。本章旨在提供大数据显著特征的简要概述,为后续章节打下基础,后续章节将更深入地探讨大数据分析的各个方面。

总的来说,本书将提供行业中使用的大数据分析系统的理论和实践经验。本书以讨论大数据和大数据相关平台(如 Hadoop、Spark 和 NoSQL 系统)开始,然后是机器学习,其中将涵盖实际和理论主题,并最后对行业中大数据和更一般地数据科学的使用进行彻底分析。本书将包括以下主题:

  • 大数据平台:Hadoop 生态系统和 Spark NoSQL 数据库,如 Cassandra 高级平台,如 KDB+

  • 机器学习:基本算法和概念 使用 R 和 Python 中的 scikit-learn C/C++和 Unix 中的高级工具 现实世界中的神经网络机器学习 大数据基础设施

  • AWS(亚马逊网络服务)企业云架构 企业内架构 高性能计算用于高级分析 大数据分析和机器学习的商业和企业用例 构建世界一流的大数据分析解决方案

为了进一步讨论,我们将在本章中澄清以下概念:

  • 大数据的定义

  • 如果数据一直存在,为什么我们现在谈论大数据?

  • 大数据的简史

  • 大数据的类型

  • 您应该从哪里开始寻找大数据解决方案?

什么是大数据?

术语“大”是相对的,通常在不同情况下可以具有不同的意义,无论是在数量还是应用方面。大数据的一个简单,尽管天真的定义是大量信息的集合,无论是存储在个人笔记本电脑上的数据还是存储在大型企业服务器上的数据,使用现有或传统工具进行分析都是非平凡的。

今天,行业通常将以太字节或拍字节及更大规模的数据视为大数据。在本章中,我们将讨论大数据范式的出现及其广泛特征。随后,我们将详细探讨不同领域。

数据的简史

计算的历史是一个迷人的故事,从查尔斯·巴贝奇在 19 世纪 30 年代中期发明的分析引擎到现代超级计算机,计算技术引领了全球变革。由于空间限制,不可能涵盖所有领域,但提供了有关数据和数据存储的高层介绍,以提供历史背景。

信息时代的黎明

大数据一直存在。美国国会图书馆是世界上最大的图书馆,收藏了 1.64 亿件物品,包括 2,400 万本书和 1.25 亿件非分类收藏品。[来源:www.loc.gov/about/general-information/]。

机械数据存储可以说最早始于由赫尔曼·霍勒里斯于 1880 年发明的穿孔卡。这些穿孔卡基本上是基于巴西尔·布什翁的先前工作,他在 1725 年发明了用于控制织机的穿孔带,霍勒里斯的穿孔卡提供了一个接口,用于进行制表和甚至打印聚合物。

IBM 开创了穿孔卡的工业化,并很快成为存储信息的事实选择。

艾伦·图灵博士和现代计算

穿孔卡建立了强大的存在,但仍然缺少一个元素——这些机器,尽管设计复杂,但不能被认为是计算设备。一个正式的通用机器,足够多样化地解决各种问题,尚未被发明。

1936 年,图灵从剑桥大学毕业后,发表了一篇开创性的论文,题为《论可计算数及对决策问题的应用》,在这篇论文中,他在库尔特·哥德尔的不完备定理基础上,形式化了我们今天的数字计算概念。

存储程序计算机的出现

存储程序计算机的第一个实现是曼彻斯特小型实验机(SSEM),该设备可以在内存中保存程序,于 1948 年在曼彻斯特大学开发[来源:en.wikipedia.org/wiki/Manchester_Small-Scale_Experimental_Machine]。这引入了 RAM,随机存取存储器(或更一般地说,内存)的概念,这是今天计算机中的内存。在 SSEM 之前,计算机具有固定存储;也就是说,所有功能都必须预先布线到系统中。能够在 RAM 等临时存储设备中动态存储数据的能力意味着机器不再受存储设备容量的限制,而是可以容纳任意数量的信息。

从磁性设备到固态硬盘

20 世纪 50 年代初,IBM 推出了磁带,基本上使用金属磁带上的磁化来存储数据。随后,于 1956 年快速相继推出了硬盘驱动器,它们使用磁盘盘片而不是磁带来存储数据。

最早的硬盘模型容量不到 4MB,占据了大约两个中等大小的冰箱的空间,成本超过 36,000 美元——与今天的硬盘相比贵了 3 亿倍。磁化表面很快成为二次存储的标准,迄今为止,它们的变体已经在各种可移动设备上实现,例如 90 年代末的软盘、CD 和 DVD。

固态硬盘(SSD),硬盘的继任者,最早由 IBM 于 20 世纪 50 年代中期发明。与硬盘相比,SSD 磁盘使用非易失性存储器存储数据,该存储器使用带电硅基底存储数据。由于没有机械运动部件,检索存储在 SSD 中的数据的时间(寻道时间)相对于硬盘等设备快了一个数量级。

如果数据一直存在,为什么我们现在谈论大数据

到了 21 世纪初,计算和存储等技术的快速进步使用户能够以前所未有的效率收集和存储数据。互联网进一步推动了这一进程,提供了一个具有全球规模无限交换信息能力的平台。技术以惊人的速度发展,并引发了由社交媒体、智能手机等连接设备以及宽带连接和用户参与等工具推动的主要范式转变,甚至在世界偏远地区也是如此。

总的来说,这些数据的大部分是由基于网络的来源生成的,例如 Facebook 等社交网络和 YouTube 等视频分享网站。在大数据术语中,这也被称为非结构化数据;也就是说,不是固定格式的数据,例如电子表格中的数据,也不是可以轻松存储在传统数据库系统中的数据。

计算能力的同时进步意味着尽管数据生成的速率非常高,但仍然可以在计算上进行分析。机器学习算法曾经被认为由于数据量和算法复杂性而难以处理,现在可以使用各种新的范例,如集群或多节点处理,以一种比以前需要专用机器更简单的方式进行分析。

每分钟生成的数据图表。来源:DOMO Inc.

大数据的定义

总体而言,生成的数据量被称为大数据,包括从基本数据挖掘到高级机器学习等各种能力的分析被称为大数据分析。由于量化什么样的数据足够大以满足将任何特定用例分类为大数据分析的标准是相对的,因此并没有确切的定义。相反,在一般意义上,对大规模数据集进行分析,例如十几或数百吉字节到皮字节的数据,可以被称为大数据分析。这可以是简单的查找大型数据集中的行数,也可以是对其应用机器学习算法。

大数据分析的构建模块

从根本上说,大数据系统可以被认为有四个主要层,每一层都是不可或缺的。在各种教科书和文献中都有许多这样的层,因此可能存在歧义。尽管如此,在高层次上,这里定义的层是直观和简单的:

大数据分析层

各个层次如下所示:

  • 硬件:提供计算骨干、存储数据的服务器以及跨不同服务器组件的网络连接的设备是定义硬件堆栈的一些元素。实质上,提供计算和存储能力的系统以及支持这些设备互操作性的系统形成了构建模块的基础层。

  • 软件:在硬件层托管的数据集上进行分析的软件资源,如 Hadoop 和 NoSQL 系统,代表了大数据堆栈中的下一个层次。分析软件可以分为各种子类。用于促进的两个主要高级分类的分析软件工具是:

  • 数据挖掘:提供对大型数据集进行聚合、数据集之间的连接和数据透视表的软件属于这一类别。标准的 NoSQL 平台,如 Cassandra、Redis 等,是大数据分析的高级数据挖掘工具。

  • 统计分析:提供超出简单数据挖掘的分析能力的平台,例如运行从简单回归到高级神经网络的算法,如 Google TensorFlow 或 R,属于这一类别。

  • 数据管理:数据加密、治理、访问、合规性等功能对于任何企业和生产环境来说都是非常重要的,以管理和在某种程度上减少操作复杂性形成了下一个基本层。虽然它们不如硬件或软件那么具体,但数据管理工具提供了一个明确定义的框架,组织可以在其中履行其安全和合规性等义务。

  • 最终用户:分析软件的最终用户构成了大数据分析的最终方面。毕竟,数据平台的价值取决于它能够被有效利用的程度,并且能够解决特定于业务的用例。这就是实践者的角色,他们利用分析平台来获取价值。术语“数据科学家”通常用来表示实施基础大数据分析能力的个人,而业务用户则获得了比传统系统中更快的访问和分析能力。

大数据类型

数据可以被广泛分类为结构化、非结构化或半结构化。尽管这些区别一直存在,但随着大数据的出现,将数据分类到这些类别中变得更加突出。

结构化

结构化数据,顾名思义,表示具有定义的组织结构的数据集,例如 Microsoft Excel 或 CSV 文件。在纯数据库术语中,数据应该可以使用模式来表示。例如,以下表格代表了联合国在其 2017 年世界幸福指数排名中发布的世界上前五个最幸福国家的典型表示。

我们可以清楚地定义列的数据类型——排名、得分、人均国内生产总值、社会支持、健康预期寿命、信任、慷慨和乌托邦都是数值列,而国家则使用字母,或更具体地说是字符串

有关更多清晰的信息,请参考以下表格:

排名 国家 得分 人均国内生产总值 社会支持 健康预期寿命 慷慨 信任 乌托邦
1 挪威 7.537 1.616 1.534 0.797 0.362 0.316 2.277
2 丹麦 7.522 1.482 1.551 0.793 0.355 0.401 2.314
3 冰岛 7.504 1.481 1.611 0.834 0.476 0.154 2.323
4 瑞士 7.494 1.565 1.517 0.858 0.291 0.367 2.277
5 芬兰 7.469 1.444 1.54 0.809 0.245 0.383 2.43

2017 年世界幸福报告[来源:en.wikipedia.org/wiki/World_Happiness_Report#cite_note-4]

商业数据库,如 Teradata、Greenplum 以及开源领域中的 Redis、Cassandra 和 Hive,都是提供管理和查询结构化数据能力的技术的例子。

非结构化

非结构化数据包括任何没有预定义组织结构的数据集,就像前一节中的表格一样。口头语言、音乐、视频,甚至书籍,包括这本书,都被认为是非结构化。这绝不意味着内容没有组织。事实上,一本书有目录、章节、子章节和索引——在这个意义上,它遵循着明确的组织。

然而,将每个单词和句子表示为严格的一组规则是徒劳的。一个句子可以由单词、数字、标点符号等组成,并且不像电子表格那样具有预定义的数据类型。要结构化,这本书需要在每个句子中具有一组确切的特征,这既不合理也不切实际。

来自社交媒体的数据,例如 Twitter 上的帖子、Facebook 上朋友的消息和 Instagram 上的照片,都是非结构化数据的例子。

非结构化数据可以以各种格式存储。它们可以是二进制大对象,或者在文本数据的情况下,是保存在数据存储介质中的自由文本。对于文本数据,通常使用 Lucene/Solr、Elasticsearch 等技术进行查询、索引和其他操作。

半结构化

半结构化数据是指既具有组织架构元素又具有任意方面的数据。个人电话日记(如今越来越少见!)包括姓名、地址、电话号码和备注的列,可以被视为半结构化数据集。用户可能不知道所有个人的地址,因此一些条目可能只有电话号码,反之亦然。

同样,备注栏可能包含额外的描述性信息(如传真号码、与个人相关的亲属姓名等)。这是一个任意的字段,允许用户添加补充信息。因此,姓名、地址和电话号码的列可以被视为结构化的,因为它们可以以表格格式呈现,而备注部分在这种意义上是非结构化的,因为它可能包含一组无法在日记的其他列中表示的描述性信息。

在计算中,半结构化数据通常由可以封装结构化和无模式或任意关联的格式(如 JSON)表示,通常使用键值对。更常见的例子可能是电子邮件,它既有一个结构化部分,如发件人姓名、接收邮件的时间等,这对所有电子邮件都是共同的,也有一个由电子邮件的正文或内容表示的非结构化部分。

像 Mongo 和 CouchDB 这样的平台通常用于存储和查询半结构化数据集。

大数据的来源

今天的技术使我们能以惊人的速度收集数据--无论是在数量还是种类上。有各种各样的数据来源,但在大数据的背景下,主要的来源如下:

  • 社交网络:可以说,我们今天所知的所有大数据的主要来源是过去 5-10 年里蓬勃发展的社交网络。这基本上是由数百万社交媒体帖子和通过用户在全球范围内的网络互动每秒生成的其他数据所代表的非结构化数据。全球范围内对互联网的访问增加已经成为社交网络数据增长的自我实现行为。

  • 媒体:在很大程度上是社交网络增长的结果,媒体代表了每天发生的数百万甚至数十亿的音频和视觉上传。在 YouTube 上传的视频、在 SoundCloud 上的音乐录音以及在 Instagram 上发布的图片是媒体的主要例子,其数量继续以不受限制的方式增长。

  • 数据仓库:公司长期以来一直在投资于专门的数据存储设施,通常被称为数据仓库。数据仓库本质上是公司希望维护和目录化以便轻松检索的历史数据的集合,无论是用于内部使用还是监管目的。随着行业逐渐转向将数据存储在 Hadoop 和 NoSQL 等平台上的做法,越来越多的公司正在将数据从现有的数据仓库转移到一些新技术上。公司的电子邮件、会计记录、数据库和内部文件是一些现在正在转移到 Hadoop 或类似 Hadoop 平台的半结构化数据的例子。

  • 传感器:大数据领域最近的一个现象是从传感器设备收集数据。虽然传感器一直存在,像石油和天然气等行业几十年来一直在使用钻井传感器测量油井的数据,但可穿戴设备的出现,也被称为物联网,如 Fitbit 和 Apple Watch,意味着现在每个人都可以以与十年前几个油井相同的速度传输数据。

可穿戴设备可以在任何时候从个人身上收集数百个测量数据。虽然还不是一个大数据问题,但随着行业的不断发展,传感器相关的数据很可能会变得更类似于通过社交网络活动在网络上生成的那种即时数据。

大数据的 4V

在大数据的背景下,4V 的话题已经被过度使用,开始失去了一些最初的魅力。尽管如此,为了了解这些 V 代表的背景情况,它有助于记住这些 V 的意义,以便进行对话。

总的来说,4V 表示以下内容:

  • 体积:正在生成的数据量

  • 多样性:不同类型的数据,如文本、媒体和传感器或流数据

  • 速度:数据生成的速度,比如在任何时候通过社交网络交换的数百万条消息

  • 真实性:这是对 3V 中的一个较新的补充,表示数据中固有的噪音,比如记录信息中的不一致之处,需要额外的验证

你如何知道你有一个大数据问题,以及你从哪里开始寻找大数据解决方案?

最后,大数据分析是指将数据投入实际运作的实践--换句话说,通过使用适当的技术从大量数据中提取有用信息的过程。对于许多用于表示不同类型分析的术语,没有确切的定义,因为它们可以以不同的方式解释,因此意义可能是主观的。

尽管如此,这里提供了一些作为参考或起点的术语,以帮助您形成初步印象:

  • 数据挖掘:数据挖掘是指通过运行查询或基本汇总方法(如聚合)从数据集中提取信息的过程。从包含一百万个产品的所有销售记录的数据集中找出销售量前十的产品,就是挖掘的过程:也就是从数据集中提取有用信息。Cassandra、Redis 和 MongoDB 等 NoSQL 数据库是具有强大数据挖掘能力的典型工具。

  • 商业智能:商业智能是指诸如 Tableau、Spotfire、QlikView 等工具,提供前端仪表板,使用户能够使用图形界面查询数据。随着用户寻求提取信息,仪表板产品在数据增长的同时也变得更加突出。易于使用的界面,具有查询和可视化功能,可以被技术和非技术用户普遍使用,为数据分析的民主化访问奠定了基础。

  • 可视化:数据可以通过易于理解的可视化结果简洁直观地表达。可视化在更深入的分析之前,在理解数据的性质和分布方面发挥了关键作用。JavaScript 的发展,如 D3.js 和百度的 ECharts,在长期的沉寂后又出现了,是开源领域可视化包的典型例子。大多数商业智能工具都包含先进的可视化功能,因此它已经成为任何成功分析产品的不可或缺的资产。

  • 统计分析:统计分析是指允许最终用户在数据集上运行统计操作的工具或平台。这些工具传统上已经存在了很多年,但随着大数据的出现以及大量数据在进行高效统计操作方面所带来的挑战,它们已经开始受到关注。R 语言和 SAS 等产品是计算统计领域常见的工具。

  • 机器学习:机器学习,通常被称为预测分析、预测建模等各种名称,实质上是应用超越传统统计领域的先进算法的过程。这些算法不可避免地涉及数百甚至数千次迭代。这些算法不仅本质上复杂,而且计算密集。

技术的进步是机器学习在分析中增长的关键驱动因素,以至于它现在已经成为行业中常用的术语。自动驾驶汽车、根据交通模式调整地图上的交通数据以及 Siri 和 Cortana 等数字助手的创新是机器学习在实际产品中的商业化的例子。

摘要

大数据无疑是一个庞大的主题,乍一看似乎过于复杂。熟能生巧,对大数据的研究也是如此——你越是参与其中,就越熟悉其中的话题和术语,对这个主题也就越感到舒适。

对大数据分析主题的各个方面进行深入研究将帮助您对这一主题形成直观的感觉。本书旨在全面概述这一主题,并将涵盖广泛的领域,如 Hadoop、Spark、NoSQL 数据库以及基于硬件设计和云基础设施的主题。在下一章中,我们将介绍大数据挖掘的概念,并讨论大数据技术的技术要素以及选择标准。

第二章:大规模数据挖掘

在企业环境中实施一个满足特定业务需求的大数据挖掘平台并不是一件简单的事情。虽然构建一个大数据平台相对简单,但是这些工具的新颖性在于对传统数据挖掘方法习惯的面向业务的用户的采用方面提出了挑战。这最终是衡量平台在组织内部变得多成功的一个标准。

本章介绍了与大数据分析相关的一些显着特征,适用于分析工具的从业者和最终用户。这将包括以下主题:

  • 什么是大数据挖掘?

  • 企业中的大数据挖掘:

  • 构建用例

  • 解决方案的利益相关者

  • 实施生命周期

  • 大数据挖掘的关键技术:

  • 选择硬件堆栈:

  • 单/多节点架构

  • 基于云的环境

  • 选择软件堆栈:

  • Hadoop、Spark 和 NoSQL

  • 基于云的环境

什么是大数据挖掘?

大数据挖掘是大数据分析的两个广泛类别中的第一个,另一个是预测分析,我们将在后面的章节中介绍。简单来说,大数据挖掘指的是处理大规模数据集的整个生命周期,从采购到实施相应工具进行分析。

接下来的几章将阐述在组织中进行的任何大数据项目的一些高层特征。

企业中的大数据挖掘

在中大型企业中实施大数据解决方案可能是一项具有挑战性的任务,因为考虑因素的范围极其动态和多样化,其中之一是确定解决方案将解决哪些具体的业务目标。

为大数据战略建立案例

大数据挖掘最重要的方面也许是确定平台将解决的适当用例和需求。任何大数据平台的成功很大程度上取决于在业务单位中找到相关问题,这些问题将为部门或组织提供可衡量的价值。用于收集大量传感器或流数据的解决方案的硬件和软件堆栈将与用于分析大量内部数据的解决方案有实质性的不同。

以下是一些建议的步骤,根据我的经验,这些步骤在构建和实施企业大数据战略方面被发现特别有效:

  • 谁需要大数据挖掘:确定哪些业务团队将最显著地受益于大数据挖掘解决方案是这个过程的第一步。这通常涉及已经使用大型数据集、对业务至关重要,并且对日常工作流程的数据访问或信息分析时间进行优化将产生直接收入影响的团队。

例如,在制药组织中,这可能包括商业研究、流行病学、卫生经济学和结果。在金融服务组织中,这可能包括算法交易台、定量研究,甚至后勤部门。

  • 确定用例:在前一步骤中确定的部门可能已经有一个能够满足团队需求的平台。在多个用例和部门(或它们的集合)之间进行优先排序需要对各自业务团队的工作有个人熟悉度。

大多数组织遵循分层结构,业务同事之间的互动可能主要沿着等级线进行。确定有影响力的分析用例需要在从业者和利益相关者之间进行密切合作;即对部门进行监督的管理层以及进行实际分析的员工。业务利益相关者可以阐明他或她的业务的哪些方面将从更高效的数据挖掘和分析环境中获益最大。从业者提供有关操作层面存在的挑战的见解。巩固操作和管理方面的渐进改进,以确定最佳结果,必然会带来更快和更好的结果。

  • 利益相关者的支持:在着手处理用例之前,应确立利益相关者的支持,换句话说,应在决策者和能够独立做出预算决策的人员之间形成共识。一般来说,应该获得多方支持,以确保有一组主要和次要来源,可以为任何早期成功的扩展提供适当的支持和资金。支持过程不必是确定性的,在大多数情况下可能不可能。相反,对某个特定用例将带来的价值达成一般共识有助于建立一个基准,可以在成功执行用例的基础上加以利用。

  • 早期成功和投入-回报比:一旦确定了适当的用例,找到具有最佳投入-回报比的用例至关重要。在较小的预算内,可以在较短时间内实施的相对较小的用例,以优化特定的业务关键功能,有助于展示早期成功,从而增加了所讨论的大数据解决方案的可信度。我们无法精确量化这些无形属性,但我们可以假设:

在这种情况下,“投入”是实施用例所需的时间和工作。这包括诸如采购与解决方案相关的硬件和/或软件需要多长时间,实施解决方案需要多少资源或等效的“人时”,以及整体运营开销等方面。相对于实施可能需要组织进行漫长采购和风险分析的商业解决方案,开源工具可能具有较低的准入门槛。同样,跨部门跨项目需要多个资源的时间的项目可能比只需单个部门员工执行的项目持续时间更长。如果净投入足够低,也可以并行运行多个练习,只要不影响项目的质量。

  • 利用早期成功:在早期成功阶段成功实施一个或多个项目通常为发展大数据分析平台的更大战略奠定了基础,这超出了单个部门的需求,并具有更广泛的组织级影响。因此,早期成功作为建立大数据价值的第一步,但至关重要,以展示给可能对其可行性和相关性持怀疑态度的观众。

实施生命周期

正如前文所述,实施过程可能涉及多个步骤。这些步骤通常是迭代的,需要采用试错方法。这将需要相当多的毅力和坚持,因为大多数工作将以不同程度的成功和失败为特征。

在实践中,大数据战略将包括多个利益相关者,合作方法通常会产生最佳结果。业务赞助商、业务支持和 IT & 分析是三个广泛的利益相关者类别,共同创建一个适当的统一解决方案,满足业务需求,同时受到预算和 IT 能力的限制。

解决方案的利益相关者

大数据解决方案的利益相关者的确切性质是主观的,并且会根据使用案例和问题领域而变化。一般来说,以下可以被认为是这方面的高级代表:

  • 业务赞助商:为项目提供支持和/或资金的个人或部门。在大多数情况下,这个实体也将成为解决方案的受益者。

  • 实施组:从实际操作的角度实施解决方案的团队。这通常是大多数公司的 IT 或分析部门,负责平台的设计和部署。

  • IT 采购:大多数组织的采购部门负责审查解决方案,以评估其竞争定价和组织视角下的可行性。遵守内部 IT 政策和评估其他方面,如许可成本等,是采购提供的一些服务,特别是对于商业产品。

  • 法律:所有产品,除非是内部开发的,都一定会有关联的使用条款和条件。开源产品可能具有一系列属性,定义了使用的可允许性和限制性。相对于 GNU GPL通用公共许可证),开源软件许可证,如 Apache 2.0、MIT 和 BSD,通常更具有可允许性。对于商业解决方案,这个过程更加复杂,因为它需要分析供应商特定的协议,并且根据许可条款和条件的性质,可能需要很长时间来评估和获得批准。

实施解决方案

解决方案的最终实施是实施组、业务受益者和辅助部门之间合作的结果。从开始到结束进行项目的时间可能会因项目规模而异,对于大多数小型项目来说,可能需要 3-6 个月,正如在早期成果部分所解释的那样。更大的努力可能需要几个月到几年的时间来完成,并且在实施和部署期间,会采用敏捷的产品管理框架逐步增加能力。

以下截图让我们对概念有了很好的理解:

显示工作流程的高级图像

这些图像和图标来自:

大数据平台的技术要素

到目前为止,我们的讨论集中在企业环境中设计和部署大数据解决方案的高级特征上。现在我们将把注意力转向这些工作的技术方面。我们将不时地在讨论的主题中加入高层次的信息,除了技术方面的基础知识。

在技术层面上,主要有两个考虑因素:

  • 硬件堆栈的选择

  • 软件和BI(商业智能)平台的选择

在过去的 2-3 年中,公司将其流程转移到基于云的环境作为内部基础设施的补充解决方案变得越来越普遍。因此,基于云的部署变得非常普遍,因此,增加了一个关于内部部署与基于云的额外部分。请注意,术语On-premises可以与In-houseOn-site和其他类似的术语互换使用。

你经常会听到On-premise这个术语被用作On-premises的替代。正确的术语是On-premises。Chambers 词典将premise定义为premise 名词 1(也称为 premises)假定为真的东西,作为陈述更进一步的基础。另一方面,premises是用来表示建筑物(等等)的术语,这可能更有意义。

硬件堆栈的选择

硬件的选择通常取决于所选择的解决方案类型以及硬件的位置。正确的选择取决于诸多关键指标,如数据类型(结构化、非结构化或半结构化)、数据大小(千兆字节、千兆字节、百万兆字节)以及在一定程度上数据更新的频率。最佳选择需要对这些变量进行正式评估,这将在本书的后面讨论。在高层次上,我们可以总结出三种硬件架构模型:

  • 多节点架构:这通常涉及多个相互连接的节点(或服务器),并且遵循多节点或分布式计算的原则。多节点架构的一个典型例子是 Hadoop,其中多个服务器维护双向通信以协调作业。其他技术,如 Cassandra 这样的 NoSQL 数据库和 Elasticsearch 这样的搜索和分析平台,也是基于多节点计算架构原则运行的。它们大多利用商品服务器,这是企业标准下相对低端机器的另一个名称,它们协同工作以提供大规模数据挖掘和分析能力。多节点架构适用于托管在千兆字节及以上范围内的数据。

  • 单节点架构:单节点是指在单个服务器上进行计算。随着多节点计算工具的出现,这种情况相对较少,但仍然比分布式计算架构具有巨大优势。分布式计算的谬论概述了一组关于分布式系统实现的断言或假设,如网络的可靠性、延迟成本、带宽和其他考虑因素。

如果数据集是结构化的,主要包含文本数据,并且在 1-5 TB 的范围内,在当今的计算环境中,完全有可能使用特定技术在单节点机器上托管这样的数据集,就像后面的章节中所展示的那样。

  • 基于云的架构:在过去几年中,行业中出现了许多基于云的解决方案。这些解决方案通过提供一个平台,极大地降低了大数据分析的准入门槛,使得根据手头任务的需求轻松提供硬件资源成为可能。这在采购、管理和维护物理硬件以及在内部数据中心设施中托管它们方面大大减少了重大的开销。

云平台,如亚马逊网络服务、微软的 Azure 和谷歌计算环境,允许企业按小时每个实例低至 1 美分的成本提供 10 到 1000 个节点。

随着云供应商对传统的实体托管设施的日益主导地位,出现了几种用于管理客户云环境的互补服务。

例如,云管理公司,如提供大数据服务解决方案的 Altiscale 和促进选择和管理多个基于云的解决方案的 IBM Cloud Brokerage。

硬件成本的指数级下降:过去几年,硬件成本呈指数级下降。以 Statistic Brain 的研究为例,2013 年硬盘存储的成本约为每 GB 4 美分。与 2000 年的每 GB 7 美元以及 80 年代初期每 GB 超过 10 万美元相比。考虑到商业软件的高昂许可成本,这往往超过了硬件成本,因此有必要分配足够的预算来采购能力强大的硬件解决方案。软件需要适当的硬件才能提供最佳性能,对硬件选择的重视程度与选择适当的软件一样重要。

软件堆栈的选择

数据挖掘软件堆栈的选择因个人情况而异。特定于数据挖掘的最流行的选项以及一些不那么知名但同样能够处理大规模数据集的替代方案都显示在下面:

  • Hadoop 生态系统:大数据术语可以说是随着 Hadoop 的出现在流行领域中得到了发展。Hadoop 生态系统包括在 Apache 软件基金会的支持下运行的多个项目。Hadoop 支持几乎所有大数据领域中已知的各种类型的数据集,如结构化、非结构化和半结构化。其繁荣的辅助工具生态系统增加了新功能,以及一个快速发展的市场,公司们正在竞相展示大数据领域的下一个大事件,这意味着 Hadoop 将在可预见的未来仍然存在。除了大型生态系统中存在的项目外,Hadoop 有四个主要组件。它们如下:

  • Hadoop Common:支持其他 Hadoop 模块的通用实用程序

  • Hadoop 分布式文件系统(HDFS™):提供对应用程序数据的高吞吐量访问的分布式文件系统。

  • Hadoop YARN:用于作业调度和集群资源管理的框架

  • Hadoop MapReduce:基于 YARN 的用于大型数据集的并行处理系统

  • Apache Spark™:Apache Spark 最初是在加州大学伯克利分校的 AMPLab 首次构想的一个多节点计算框架项目,作为一个提供无缝接口来运行并行计算并克服 Hadoop MapReduce 框架局限性的平台。特别是,Spark 内部利用了一种称为DAG(有向无环图)的概念,该概念将一组操作优化为更小或更高效的一组操作。此外,Spark 公开了几个API(应用程序编程接口),用于常用语言,如 Python(PySpark)和 Scala(本地可用接口)。这消除了进入 Hadoop 领域的一个障碍,即需要掌握 Java 的知识。

最后,Spark 引入了一种称为弹性分布式数据集RDD)的数据结构,它提供了一种将数据存储在内存中的机制,从而显着提高了数据检索和随后处理的时间:

    • 集群管理器:构成 Spark 集群的节点使用集群管理器进行通信,集群管理器管理集群中的节点之间的整体协调。截至目前,集群管理器可以是独立的 Spark 集群管理器、Apache Mesos 或 YARN。还有一个额外的功能,即使用 spark-ec2 在 AWS EC2 实例上运行 Spark,它会自动设置一个运行 Spark 程序的环境。
    • 分布式 存储:Spark 可以从各种基础分布式存储系统中访问数据,如 HDFS、S3(AWS 存储)、Cassandra、HBase、Hive、Tachyon 和任何 Hadoop 数据源。需要注意的是,Spark 可以作为独立产品使用,需要 Hadoop 进行操作。对于 Spark 的新手,他们常常误以为 Spark 操作需要 Hadoop,或者更具体地说需要 HDFS 文件系统。这是不正确的。Spark 可以支持多种类型的集群管理器以及后端存储系统,如本节所示。
  • NoSQL 和传统数据库:在选择软件堆栈方面的第三个考虑是 NoSQL 数据库。最近出现的 NoSQL 一词旨在区分不遵循传统关系数据库模型的数据库。有开源和商业版本的 NoSQL 数据库,甚至有越来越常见的基于云的选项。NoSQL 数据库有各种广泛的分类,一些更常见的范式如下:

  • 键值:这些 NoSQL 数据库根据哈希的原则存储数据——一个唯一的键标识了与该键相关的一组属性。在这种术语中,一个键的例子可能是个人的国民身份证号码(如美国的社会安全号码或印度的 Aadhaar)。这可以与个人的姓名、地址、电话号码和其他变量相关联。数据库的最终用户可以通过 ID 号码查询,直接访问有关个人的信息。像 Redis 这样的开源键值数据库和像 Riak 这样的商业数据库非常受欢迎。

  • 内存中:虽然数据库一直在使用内存设施,比如将缓存存储在内存中以提供比存储在磁盘上更快的访问,但随着大数据的出现,它们被更广泛地采用。在内存中访问数据的速度比从磁盘访问相同的信息快几个数量级(约 100 纳秒),后者的速度是前者的 100,000 倍(1-10 毫秒)。一些 NoSQL 数据库,如 Redis 和 KDB+,利用临时内存存储以提供对经常使用的数据更快的访问。

  • 列式:这些数据库将多列数据附加到表中,而不是行。列式存储相对于基于行的存储的主要优势在于,列式布局提供了更快地访问数据的手段,减少了 I/O 开销,特别适用于分析用例。通过将数据分隔成单独的列,数据库查询可以通过扫描适当的列而不是逐行扫描表来检索数据,并且可以非常好地利用并行处理设施。知名的列式数据库包括 Cassandra、Google BigTable 等。

  • 面向文档:在许多方面,文档导向数据库被认为是纯键值存储的一种升级,它存储不符合任何特定模式的数据,比如新闻文章等非结构化文本。这些数据库提供了一种方式来封装多个键值对中的信息,这些键值对在结构上不一定要在所有其他条目中保持一致。因此,像 MongoDB 这样的文档数据库被广泛用于媒体相关组织,如纽约时报和福布斯,以及其他主流公司。

  • 基于云的解决方案: 最后,诸如 AWS Redshift、Azure SQL 数据仓库和 Google Bigquery 等大规模数据挖掘的基于云的解决方案允许用户直接在云供应商的平台上查询数据集,而无需创建自己的架构。尽管最终用户可以选择拥有自己的内部专家,如 Redshift 系统管理员,但基础设施、维护和日常例行任务的管理大部分由供应商执行,从而减少了客户端的运营开销。

摘要

在本章中,我们对大数据和企业中实施大数据解决方案的一些组成部分进行了高层次的概述。大数据需要选择最佳的软件和硬件堆栈,这是一项非常不容易的工作,其中一个原因是行业中有数百种解决方案。尽管大数据战略的话题可能被视为更适合管理层而不是技术观众,但理解其中的细微差别是至关重要的。

请注意,如果没有适当的、明确定义的策略和相应的高层支持,IT 部门将在提供成功解决方案的程度上受到限制。此外,解决方案,包括硬件软件堆栈,应该能够得到现有 IT 资源的充分管理和支持。大多数公司会发现,对于大数据实施来说,招聘新员工是必不可少的。由于这类实施需要评估各种因素 - 业务需求、预算、资源和其他变量,因此根据规模和范围,通常需要几个月甚至一年以上的前期时间。

这些主题将在后面的章节中深入讨论,本节作为对该主题的初步介绍。

第三章:分析工具包

今天有几个平台用于大规模数据分析。在广义上,这些平台分为主要用于数据挖掘的平台,比如使用 NoSQL 平台分析大型数据集,以及用于数据科学的平台,即机器学习和预测分析。通常,解决方案可能具有这两种特征——一个用于存储和管理数据的强大基础平台,以及在其之上构建的提供数据科学附加功能的解决方案。

在本章中,我们将向您展示如何安装和配置您的分析工具包,这是我们在接下来的章节中将使用的一系列软件:

  • 分析工具包的组件

  • 系统建议

  • 在笔记本电脑或工作站上安装

  • 在云上安装

  • 安装 Hadoop

  • Hadoop 分布

  • Cloudera Hadoop 分布(CDH)

  • 安装 Spark

  • 安装 R 和 Python

分析工具包的组件

本书将利用几种用于大数据挖掘和更一般的数据科学的关键技术。我们的分析工具包包括 Hadoop 和 Spark,它们可以在用户的本地机器上安装,也可以在云上安装;还有 R 和 Python,它们都可以在用户的机器上安装,也可以在云平台上安装。您的分析工具包将包括:

软件/平台 用于数据挖掘 用于机器学习
Hadoop X
Spark X X
Redis X
MongoDB X
开源 R X X
Python(Anaconda) X X
Vowpal Wabbit X
LIBSVM,LIBLINEAR X
H2O X

系统建议

如果您在本地机器上安装 Hadoop,建议您的系统至少具有 4-8GB 的 RAM(内存)和至少 50GB 的充足的磁盘空间。理想情况下,8GB 或更多内存对于大多数应用程序来说足够了。低于这个数值,性能会降低,但不会阻止用户进行练习。请注意,这些数字是适用于本书中概述的练习的估计值。生产环境自然会有更高的要求,这将在后面讨论。

安装分析软件,特别是像 Hadoop 这样的平台,可能在技术复杂性方面非常具有挑战性,用户很常见地会遇到必须要费力解决的错误。用户花费更多时间尝试解决错误和修复安装问题,而不是他们理想情况下应该花费的时间。这种额外的开销可以通过使用虚拟机VMs)或者最近更常用的 Docker 等容器来轻松减轻。对于像 R 和 Python 这样更简单的平台,我们将使用预装有各种库的开源版本。

在笔记本电脑或工作站上安装

本书中的练习可以在任何 Windows、macOS 或 Linux 机器上进行。用户需要 Oracle VirtualBox(可以从www.virtualbox.org/wiki/Downloads)开始安装分析工具包所需的软件。

在云上安装

在您的物理硬件上安装软件的另一种选择是使用基于云的服务。云服务,比如亚马逊的 AWS(亚马逊网络服务)和微软的 Azure,提供了一个极其灵活和多功能的环境,可以按需提供服务器,每小时的使用成本只需几美分到几美元。虽然云安装超出了本书的范围,但非常简单地创建一个免费的 AWS 账户,并使用它来安装本书中讨论的不同分析软件的各个部分。请注意,如果您使用 AWS/Azure 或任何其他云服务,您将需要使用 Cloudera Hadoop 分布的 Docker 版本。

安装 Hadoop

安装 Hadoop 有几种方法。最常见的方法有:

  1. hadoop.apache.org的源文件中安装 Hadoop

  2. 使用来自 Cloudera 和 Hortonworks 等商业供应商的开源发行版进行安装

在这个练习中,我们将安装Cloudera 分布式 Apache HadoopCDH),这是一个由几个 Hadoop 和与 Apache 相关的产品组成的集成平台。Cloudera 是一个流行的商业 Hadoop 供应商,除了其自己的 Hadoop 版本外,还为企业规模的 Hadoop 部署提供托管服务。在我们的情况下,我们将在 VM 环境中安装 HDP Sandbox。

安装 Oracle VirtualBox

VM 环境本质上是现有操作系统的副本,可能已经预装了软件。VM 可以以单个文件的形式交付,这允许用户通过仅启动文件而不是重新安装操作系统并配置它来模拟另一个系统来复制整个机器。VM 在一个独立的环境中运行;也就是说,它不依赖于主机操作系统来提供其功能。

要安装 CDH Quickstart VM,我们将使用 Oracle VirtualBox,该软件用于从 VM 文件启动 VMs。

在 VirtualBox 中安装 CDH 的步骤:

  1. www.virtualbox.org/wiki/Downloads下载适合您系统的 Oracle VirtualBox(Windows、macOS 或 Linux)(如果无法访问此链接,请转到www.virtualbox.org/并选择适当的链接转到下载页面)。

  2. 双击 Oracle VirtualBox 可执行文件,并按照屏幕上的提示进行安装(您可以接受屏幕上显示的默认设置)。

  3. 安装了 VirtualBox 后,您还应该安装可在www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html#extpack下载的Oracle VM VirtualBox 扩展包

下载与您的环境相关的扩展包文件,并单击/双击该文件。这将在 Oracle VM VirtualBox 应用程序中打开并在 VirtualBox 环境中安装扩展包。

下载和安装 CDH Quickstart VM:可以从 Cloudera 网站下载 CDH 的 Quickstart VM 或 Docker 镜像。步骤如下:

  1. 转到www.cloudera.com,然后单击页面顶部的下载菜单中的 Quickstart VMs。如果导航已更改,可以在 Google 上搜索 Cloudera Quickstart VM,通常会直接带您到 Cloudera 下载页面:

Cloudera 主页上的 QuickStart VM 链接

  1. 这将打开 CDH 下载页面的 Quickstart。在“选择平台”菜单中,选择VirtualBox。填写出现的表格,然后单击“继续”。下载的文件将具有.zip扩展名。解压文件以提取.ova 或.ovf文件:

在 Cloudera Quickstart 下载选项上选择 Virtualbox

我们得到以下登录屏幕:

CDH 注册屏幕

首先列出了条款和条件:

CDH 许可条款接受

CDH 的 VM 下载开始:

CDH VM 超过 5GB,可能需要一段时间来下载

解压文件。文件夹中将包含以下图像中显示的文件:

如果文件是 Zip 格式,则解压文件

下载文件超过 5GB,根据您的互联网连接速度,可能需要一些时间

  1. 下载完成后,双击.ova 或.ovf文件,它将在 Oracle VirtualBox 中打开:

在 Virtualbox 中为 VM 选择选项

您还可以通过启动 Oracle VirtualBox 手动打开文件,转到文件|导入虚拟设备,并选择您下载的.ova/.ovf文件作为要导入的设备。

保持所有选项默认,并单击导入按钮,这将开始导入过程。在此阶段,Cloudera CDH Quickstart VM 正在加载到您的 Oracle VirtualBox 环境中。

  1. 导入文件后,您可以通过单击窗口顶部的绿色箭头来启动它:

已加载 CDH VM 的 Oracle Virtualbox

  1. 在 OS 初始化时保持默认设置:

CDH 主 OS 页面

我们在安装的最后一步中得到以下屏幕:

CDH 网页管理 Hadoop 和其他 CDH 组件

这结束了使用 Hortonworks 数据平台安装 Hadoop 环境的安装。

在其他环境中安装 CDH

CDH Quickstart VM 也可以在 VMWare、Docker 和云平台上安装。有关相同的说明可在以下页面提供的链接中找到。

安装 Packt 数据科学 Box

我们还为书中的一些练习创建了一个单独的虚拟机。

gitlab.com/packt_public/vm下载 Packt 数据科学虚拟机 Vagrant 文件。

要加载 VM,首先从www.vagrantup.com/downloads.html下载Vagrant

Vagrant 的下载页面

完成下载后,通过运行下载的 Vagrant 安装文件来安装Vagrant。安装完成后,您将收到重新启动计算机的提示。重新启动系统,然后继续加载 vagrant 文件的下一步:

完成 Vagrant 安装

在最后一步上点击确认以重新启动:

重新启动系统

在终端或命令提示符中,转到您下载了 Packt 数据科学 Vagrant 文件的目录,并运行以下命令(在 Windows 中显示):

$ vagrant box add packtdatascience packtdatascience.box ==> box: Box file was not detected as metadata. Adding it directly... 

==> box: Adding box 'packtdatascience' (v0) for provider: 

box: Unpacking necessary files from: file://C:/Users/packt/Downloads/packt_public_vm/packtdatascience.box 

box: Progress: 100% (Rate: 435M/s, Estimated time remaining: --:--:--) 

==> box: Successfully added box 'packtdatascience' (v0) for 'virtualbox'! $ vagrant box list packtdatascience (virtualbox, 0) 

C:UsersNataraj DasguptaDownloadspackt_public_vm>vagrant up 

Bringing machine 'default' up with 'virtualbox' provider... 

==> default: Importing base box 'packtdatascience'... 

==> default: Matching MAC address for NAT networking... 

==> default: Setting the name of the VM: packt_public_vm_default_1513453154192_57570 

==> default: Clearing any previously set network interfaces... 

==> default: Preparing network interfaces based on configuration... 

    default: Adapter 1: nat 

==> default: Forwarding ports... 

    default: 22 (guest) => 2222 (host) (adapter 1) 

==> default: Booting VM...
 ...  

如果一切顺利,您应该在 Oracle VirtualBox 中看到一个新条目:

已加载 Packt 数据科学 VM 的 Oracle Virtualbox

双击框的名称以启动(和测试)它。使用 id/password 登录为packt/packt

Packt VM 的登录屏幕

安装 Spark

CDH Quickstart VM 包括 Spark 作为其中一个组件,因此不需要单独安装 Spark。我们将在专门讨论 Spark 的章节中更多地讨论 Spark。

此外,我们关于 Spark 的教程将使用 Databricks 社区版,可以从community.cloud.databricks.com/访问。有关创建帐户和执行必要步骤的说明已在第六章中提供,用于大数据分析的 Spark

安装 R

R 是一种统计语言,在过去 3-5 年中变得非常流行,特别是作为一个可以用于各种用例的平台,从简单的数据挖掘到复杂的机器学习算法。根据 2016 年中期 IEEE Spectrum 发布的一篇文章,R 在世界排名前 10 的语言中排名第 5。

可以从www.r-project.org的 CRAN 网站上下载开源 R,该网站位于cran.r-project.org/mirrors.html

或者,您可以从mran.microsoft.com/rro/的 Microsoft R Open 页面下载 R。 这以前被称为 Revolution R Open,是由 Revolution Analytics 发布的增强版本的开源 R。 在 2015 年 Microsoft 收购 Revolution Analytics 后,它在新所有权下进行了重新品牌。

Microsoft R Open 包括 R 的所有功能,还包括以下功能:

  • 默认安装了许多 R 软件包,以及由 Microsoft Corporation 发布的一组专业软件包,这些软件包补充了开源 R 的现有功能

  • 多线程数学库,用于 R 中的多线程计算

  • 称为 MRAN 的固定 CRAN 存储库。 CRAN,全面的 R 存档网络是一个包含 R 二进制文件,软件包和相关内容的站点集合。 CRAN 上的软件包可以持续更新。 MRAN 获取 CRAN 的固定快照,直到下一个发布保持不变,从而实现可重现性和一致性。

下载并安装 Microsoft R Open 的步骤

我们按照以下步骤进行:

  1. 前往mran.microsoft.com并点击立即下载按钮:

Microsoft 开放 R 主页

  1. 选择适合您系统的发行版(Windows,macOS 或 Linux):

Microsoft 开放 R 版本

  1. 下载完成后,双击下载的文件安装Microsoft R Open

  2. 请注意,在 macOS 上,您可能会收到以下错误消息:

OS X 消息(使用下面的方法绕过)

  1. 如果发生这种情况,请右键单击下载的文件,然后从弹出的菜单中选择“打开”。 这将允许您手动打开文件并安装:

绕过 OS X 之前显示的消息

  1. 安装后,双击Microsoft R Open启动应用程序:

Microsoft R 控制台

安装 RStudio

RStudio 是由rstudio.org发布的应用程序,提供了功能强大且功能丰富的图形IDE集成开发环境)。

以下是安装 RStudio 的步骤:

  1. 前往www.rstudio.com/products/rstudio/download

R Studio 版本

  1. 点击与您的操作系统相关的链接,下载并安装相应的文件:

下载 RStudio

  1. 请注意,在 macOS 上,您可以简单地将下载的文件移动到应用程序文件夹。 在 Windows 和 Linux 操作系统上,双击下载的文件以完成安装文件的步骤:

在 Mac 上安装 RStudio(复制到应用程序文件夹)

安装 Python

我们按照以下步骤进行安装:

  1. 与 R 类似,Python 因其多功能和多样化的软件包而备受欢迎。 Python 通常作为大多数现代基于 Linux 的操作系统的一部分提供。 对于我们的练习,我们将使用 Continuum Analytics®的 Anaconda,它通过许多数据挖掘和机器学习相关的软件包本地安装作为平台的一部分,增强了基本的开源 Python 提供。 这消除了从业者手动下载和安装软件包的需要。 在这方面,它在精神上与 Microsoft R Open 类似。 正如 Microsoft R 增强了基本的开源 R 提供的附加功能一样,Anaconda 改进了基本的开源 Python 提供的功能,以提供新的功能。

  2. 安装 Anaconda Python 的步骤

  3. 前往www.continuum.io/downloads

Python Anaconda 主页

  1. 下载适合您系统的发行版。请注意,我们将下载 Python v2.7(而不是 3.x 版本):

选择 Python Anaconda 安装程序

  1. 安装完成后,您应该能够打开终端窗口(或 Windows 中的命令窗口)并输入 Python,这将启动 Anaconda:

在控制台中启动 Python Anaconda

安装 Hadoop(CDH)、Spark、R 和 Python 的过程到此结束。在后面的章节中,我们将更详细地研究这些平台。

总结

本章介绍了一些用于数据科学的关键工具。特别是,它演示了如何下载和安装 Cloudera Hadoop 分发(CDH)、Spark、R、RStudio 和 Python 的虚拟机。虽然用户可以下载 Hadoop 的源代码并安装在 Unix 系统上,但通常会出现问题,并且需要大量的调试。使用虚拟机可以让用户在最小的努力下开始使用和学习 Hadoop,因为它是一个完全预配置的环境。

此外,R 和 Python 是机器学习和一般分析中最常用的两种语言。它们适用于所有流行的操作系统。虽然它们可以安装在虚拟机中,但鼓励用户尝试在本地机器(笔记本电脑/工作站)上安装它们,如果可行的话,因为这样性能会相对更高。

在下一章中,我们将更深入地了解 Hadoop 及其核心组件和概念的细节。

第四章:使用 Hadoop 的大数据

Hadoop 已经成为大数据世界的事实标准,特别是在过去三到四年里。 Hadoop 于 2006 年作为 Apache Nutch 的一个子项目开始,并引入了与分布式文件系统和分布式计算相关的两个关键功能,也被称为 MapReduce,这在开源社区中迅速流行起来。 今天,已经开发出了数千种利用 Hadoop 核心功能的新产品,并且它已经发展成一个包含 150 多种相关主要产品的庞大生态系统。可以说,Hadoop 是启动大数据和分析行业的主要催化剂之一。

在本章中,我们将讨论 Hadoop 的背景和核心概念,Hadoop 平台的组件,并深入了解 Hadoop 生态系统中的主要产品。 我们将了解分布式文件系统和分布式处理的核心概念,以及优化以提高 Hadoop 部署性能。 我们将以使用Cloudera Hadoop DistributionCDH)进行真实世界的实践来结束。 我们将涵盖的主题有:

  • Hadoop 的基础知识

  • Hadoop 的核心组件

  • Hadoop 1 和 Hadoop 2

  • Hadoop 分布式文件系统

  • 使用 MapReduce 的分布式计算原理

  • Hadoop 生态系统

  • Hadoop 生态系统概述

  • Hive,HBase 等

  • Hadoop 企业部署

  • 内部部署

  • 云部署

  • Cloudera Hadoop 的实践

  • 使用 HDFS

  • 使用 Hive

  • 使用 WordCount 的 MapReduce

Hadoop 的基础知识

在 2006 年,Hadoop 的创造者 Doug Cutting 正在 Yahoo!工作。 他积极参与了一个名为 Nutch 的开源项目,该项目涉及开发大规模网络爬虫。 从高层次上看,网络爬虫本质上是一种可以在互联网上以自动方式浏览和索引网页的软件。 直观地,这涉及对大量数据进行高效的管理和计算。 2006 年 1 月底,Doug 正式宣布了 Hadoop 的开始。 请求的第一行,仍然可以在issues.apache.org/jira/browse/INFRA-700上找到,是Lucene PMC 已投票将 Nutch 的一部分拆分为一个名为 Hadoop 的新子项目。 因此,Hadoop 诞生了。

在开始时,Hadoop 有两个核心组件:Hadoop 分布式文件系统HDFS)和 MapReduce。 这是 Hadoop 的第一次迭代,现在也被称为 Hadoop 1。 稍后,在 2012 年,添加了第三个组件,称为YARN另一个资源协调器),它解耦了资源管理和作业调度的过程。 在更详细地探讨核心组件之前,了解 Hadoop 的基本前提将有所帮助:

Doug Cutting 在issues.apache.org/jira/browse/NUTCH-193上发布了他打算将Nutch 分布式 FSNDFS)和 MapReduce 分离到一个名为 Hadoop 的新子项目的意图。

Hadoop 的基本前提

Hadoop 的基本前提是,不是尝试在单个大型机器上执行任务,而是将任务细分为较小的段,然后将其委派给多个较小的机器。 这些所谓的较小机器然后会在自己的数据部分上执行任务。 一旦较小的机器完成了它们的任务,产生了它们被分配的任务的结果,那么这些单独的结果单元将被聚合以产生最终结果。

尽管在理论上,这可能看起来相对简单,但有各种技术考虑要牢记。 例如:

  • 网络是否足够快,可以从每个单独的服务器收集结果?

  • 每个单独的服务器是否能够从磁盘快速读取数据?

  • 如果一个或多个服务器失败,我们是否必须重新开始?

  • 如果有多个大任务,应该如何设置优先级?

在处理这种性质的分布式架构时,还有许多其他考虑因素。

Hadoop 的核心模块

Hadoop 的核心模块包括:

  • Hadoop Common:Hadoop 所需的库和其他常见的辅助工具

  • HDFS:存储数据的分布式、高可用、容错的文件系统

  • Hadoop MapReduce:涉及跨商品服务器(或节点)的分布式计算的编程范式

  • Hadoop YARN:作业调度和资源管理的框架

在这些核心组件中,YARN 于 2012 年推出,以解决 Hadoop 首次发布的一些缺点。Hadoop 的第一个版本(或者等效地说是 Hadoop 的第一个模型)使用 HDFS 和 MapReduce 作为其主要组件。随着 Hadoop 的流行,使用 MapReduce 提供的设施之外的设施的需求变得越来越重要。这,再加上一些其他技术考虑因素,导致了 YARN 的开发。

现在让我们来看一下之前列举的 Hadoop 的显著特点。

Hadoop 分布式文件系统 - HDFS

HDFS 构成了所有 Hadoop 安装的基础。文件,或者更一般地说是数据,存储在 HDFS 中,并由 Hadoop 的节点访问。

HDFS 执行两个主要功能:

  • 命名空间:提供保存集群元数据的命名空间,即 Hadoop 集群中数据的位置

  • 数据存储:作为 Hadoop 集群中使用的数据的存储

文件系统被称为分布式,因为数据存储在多台服务器上的块中。可以通过一个简单的例子直观地理解 HDFS。考虑一本由 A-Z 章组成的大书。在普通文件系统中,整本书将作为一个单独的文件存储在磁盘上。在 HDFS 中,这本书将被分割成更小的块,比如 A-H 章的一个块,I-P 章的另一个块,以及 Q-Z 章的第三个块。这些块然后存储在不同的机架(或者用这个类比来说是书架)上。此外,每一章都会被复制三次,这样每一章都会有三个副本。

假设整本书的大小是 1GB,每一章大约是 350MB:

HDFS 的书架类比

以这种方式存储书籍实现了一些重要的目标:

  • 由于这本书已经被分成了三部分,每部分都被章节组复制了三次,这意味着我们的进程可以通过从不同服务器查询部分来并行读取书。这减少了 I/O 争用,非常适合并行使用的一个很好的例子。

  • 如果任何一个机架不可用,我们可以从任何其他机架检索章节,因为每个章节在不同机架上都有多个副本。

  • 如果我被分配的任务只需要访问单独的一章,比如说 B 章,我只需要访问对应 A-H 章的文件。由于对应 A-H 章的文件大小是整本书的三分之一,访问和读取文件的时间会更短。

  • 其他好处,比如对不同章节组的选择性访问权限等,也是可能的。

这可能是对实际 HDFS 功能的过度简化的类比,但它传达了这项技术的基本原则 - 大文件被分割成块(块),并以高可用性冗余配置分布在多台服务器上。现在我们将更详细地看一下实际的 HDFS 架构:

Hadoop 的 HDFS 后端包括:

  • NameNode:这可以被认为是主节点。NameNode 包含集群元数据,并知道存储在哪个位置的数据 - 简而言之,它持有命名空间。它将整个命名空间存储在 RAM 中,当请求到达时,提供有关哪些服务器持有所需任务的数据的信息。在 Hadoop 2 中,可以有多个 NameNode。可以创建一个辅助节点作为辅助节点。因此,它不是备用 NameNode,而是帮助保持集群元数据最新的节点。

  • DataNode:DataNodes 是负责存储数据块并在收到新请求时执行计算操作的单独服务器。这些主要是低性能的商品服务器,资源和容量比存储集群元数据的 NameNode 要低。

HDFS 中的数据存储过程

以下几点应该能很好地说明数据存储过程:

HDFS 中的所有数据都是以块的形式写入的,通常大小为 128 MB。因此,一个大小为 512 MB 的单个文件将被分成四个块(4 * 128 MB)。然后将这些块写入 DataNodes。为了保持冗余和高可用性,每个块都会被复制以创建副本。一般来说,Hadoop 安装的复制因子为 3,表示每个数据块都会被复制三次。

这样可以保证冗余性,以便在其中一个服务器失败或停止响应时,始终有第二个甚至第三个副本可用。为了确保这个过程能够无缝运行,DataNode 将副本放在独立的服务器上,并且还可以确保数据中心不同机架上的服务器上放置块。这是因为即使所有副本都在独立的服务器上,但所有服务器都在同一个机架上,机架电源故障将意味着没有副本可用。

将数据写入 HDFS 的一般过程如下:

  1. NameNode 收到一个请求,要求将新文件写入 HDFS。

  2. 由于数据必须以块或分块的形式写入,HDFS 客户端(发出请求的实体)开始将数据缓存到本地缓冲区,一旦缓冲区达到分配的块大小(例如 128 MB),它会通知 NameNode 准备好写入第一个数据块(分块)。

  3. 根据其对 HDFS 集群状态的了解,NameNode 会提供关于需要存储块的目标 DataNode 的信息。

  4. HDFS 客户端将数据写入目标 DataNode,并在块的写入过程完成后通知 NameNode。

  5. 随后,目标 DataNode 开始将其数据块的副本复制到第二个 DataNode,后者将作为当前块的副本。

  6. 第二个 DataNode 完成写入过程后,它将数据块发送给第三个 DataNode。

  7. 这个过程重复进行,直到所有与数据(或等效地,文件)对应的块都被复制到不同的节点上。

请注意,块的数量将取决于文件大小。以下图示了数据在 5 个数据节点之间的分布。

主节点和数据节点

Hadoop 的第一个版本中的 HDFS 架构,也称为 Hadoop 1,具有以下特点:

  • 单个 NameNode:只有一个 NameNode 可用,因此它也是单点故障,因为它存储了整个集群的元数据。

  • 存储数据块的多个 DataNodes,处理客户端请求,并在数据块上执行 I/O 操作(创建、读取、删除等)。

  • Hadoop 的第二个版本中的 HDFS 架构,也被称为 Hadoop 2,提供了原始 HDFS 设计的所有优点,并添加了一些新特性,最显著的是具有多个可以充当主要和次要 NameNode 的 NameNode 的能力。其他功能包括具有多个命名空间以及 HDFS 联邦。

  • HDFS 联邦值得特别一提。来自hadoop.apache.org的以下摘录以非常精确的方式解释了这个主题:

NameNode 是联邦的;NameNode 是独立的,不需要彼此协调。DataNode 被用作所有 NameNode 的块的共同存储。每个 DataNode 在集群中注册。DataNode 发送周期性的心跳和块报告。

Secondary NameNode 并不是备用节点,它不能在 NameNode 不可用时执行与 NameNode 相同的任务。然而,它通过执行一些清理操作使得 NameNode 重新启动过程更加高效。

这些操作(例如将 HDFS 快照数据与数据更改信息合并)通常在 NameNode 重新启动时由 NameNode 执行,根据自上次重新启动以来的更改量,可能需要很长时间。然而,Secondary NameNode 可以在主 NameNode 仍在运行时执行这些清理操作,以便在重新启动时,主 NameNode 可以更快地恢复。由于 Secondary NameNode 基本上在定期间隔对 HDFS 数据执行检查点,因此它也被称为检查点节点。

Hadoop MapReduce

MapReduce 是 Hadoop 的一个重要特性,可以说是使其著名的最重要的特性之一。MapReduce 的工作原理是将较大的任务分解为较小的子任务。与将单个机器委派为计算大型任务不同,可以使用一组较小的机器来完成较小的子任务。通过以这种方式分配工作,相对于使用单机架构,任务可以更加高效地完成。

这与我们在日常生活中完成工作的方式并没有太大不同。举个例子会更清楚一些。

MapReduce 的直观介绍

让我们以一个假设的由 CEO、董事和经理组成的组织为例。CEO 想知道公司有多少新员工。CEO 向他的董事发送请求,要求报告他们部门的新员工数量。董事再向各自部门的经理发送请求,要求提供新员工的数量。经理向董事提供数字,董事再将最终值发送回 CEO。

这可以被认为是 MapReduce 的一个现实世界的例子。在这个类比中,任务是找到新员工的数量。CEO 并没有自己收集所有数据,而是委派给了董事和经理,他们提供了各自部门的数字,如下图所示:

MapReduce 的概念

在这个相当简单的场景中,将一个大任务(在整个公司中找到新员工)分解为较小的任务(每个团队中的新员工),然后重新聚合个体数字,类似于 MapReduce 的工作方式。

MapReduce 的技术理解

MapReduce,顾名思义,有一个映射阶段和一个减少阶段。映射阶段通常是对其输入的每个元素应用的函数,从而修改其原始值。

MapReduce 生成键值对作为输出。

键值对: 键值对建立了一种关系。例如,如果约翰今年 20 岁,一个简单的键值对可以是(约翰,20)。在 MapReduce 中,映射操作产生这样的键值对,其中有一个实体和分配给该实体的值。

在实践中,映射函数可能会复杂,并涉及高级功能。

减少阶段接收来自映射函数的键值输入,并执行汇总操作。例如,考虑包含学校不同年级学生年龄的映射操作的输出:

学生姓名 班级 年龄
John 年级 1 7
Mary 年级 2 8
Jill 年级 1 6
Tom 年级 3 10
Mark 年级 3 9

我们可以创建一个简单的键值对,例如取班级和年龄的值(可以是任何值,但我只是拿这些来提供例子)。在这种情况下,我们的键值对将是(年级 1,7),(年级 2,8),(年级 1,6),(年级 3,10)和(年级 3,9)。

然后可以将计算每个年级学生年龄平均值的操作定义为减少操作。

更具体地说,我们可以对输出进行排序,然后将与每个年级对应的元组发送到不同的服务器。

例如,服务器 A 将接收元组(年级 1,7)和(年级 1,6),服务器 B 将接收元组(年级 2,8),服务器 C 将接收元组(年级 3,10)和(年级 3,9)。然后,服务器 A、B 和 C 将找到元组的平均值并报告(年级 1,6.5),(年级 2,8)和(年级 3,9.5)。

请注意,在这个过程中有一个中间步骤,涉及将输出发送到特定服务器并对输出进行排序,以确定应将其发送到哪个服务器。事实上,MapReduce 需要一个洗牌和排序阶段,其中键值对被排序,以便每个减少器接收一组固定的唯一键。

在这个例子中,如果说,而不是三个服务器,只有两个,服务器 A 可以被分配为计算与年级 1 和 2 对应的键的平均值,服务器 B 可以被分配为计算年级 3 的平均值。

在 Hadoop 中,MapReduce 期间发生以下过程:

  1. 客户端发送任务请求。

  2. NameNode 分配将执行映射操作和执行减少操作的 DataNodes(单独的服务器)。请注意,DataNode 服务器的选择取决于所需操作的数据是否位于服务器本地。数据所在的服务器只能执行映射操作。

  3. DataNodes 执行映射阶段并产生键值(k,v)对。

当映射器生成(k,v)对时,它们根据节点分配的发送到这些减少节点。键分配给服务器取决于分区函数,这可以是键的哈希值(这是 Hadoop 中的默认值)。

一旦减少节点接收到与其负责计算的键对应的数据集,它就应用减少函数并生成最终输出。

Hadoop 最大程度地利用了数据局部性。映射操作由本地保存数据的服务器执行,即在磁盘上。更准确地说,映射阶段将仅由持有文件对应块的服务器执行。通过委托多个独立节点独立执行计算,Hadoop 架构可以有效地执行非常大规模的数据处理。

块大小和映射器和减少器的数量

在 MapReduce 过程中的一个重要考虑因素是理解 HDFS 块大小,即文件被分割成的块的大小。需要访问某个文件的 MapReduce 任务将需要对表示文件的每个块执行映射操作。例如,给定一个 512MB 的文件和 128MB 的块大小,需要四个块来存储整个文件。因此,MapReduce 操作将至少需要四个映射任务,其中每个映射操作将应用于数据的每个子集(即四个块中的每一个)。

然而,如果文件非常大,比如需要 10,000 个块来存储,这意味着我们需要 10,000 个映射操作。但是,如果我们只有 10 台服务器,那么我们将不得不向每台服务器发送 1,000 个映射操作。这可能是次优的,因为它可能导致由于磁盘 I/O 操作和每个映射的资源分配设置而产生高惩罚。

所需的减少器数量在 Hadoop Wiki 上非常优雅地总结了(wiki.apache.org/hadoop/HowManyMapsAndReduces)。

理想的减少器应该是最接近以下值的最佳值:

  • 块大小的倍数 * 5 到 15 分钟之间的任务时间 * 创建尽可能少的文件

除此之外,很有可能你的减少器不太好。用户有极大的倾向使用一个非常高的值(“更多的并行性意味着更快!”)或一个非常低的值(“我不想超出我的命名空间配额!”)。这两种情况都同样危险,可能导致以下一种或多种情况:

  • 下一个工作流程阶段的性能差 * 由于洗牌而导致性能差 * 由于过载了最终无用的对象而导致整体性能差 * 没有真正合理的原因而破坏磁盘 I/O * 由于处理疯狂数量的 CFIF/MFIF 工作而产生大量的网络传输

Hadoop YARN

YARN 是 Hadoop 2 中引入的一个模块。在 Hadoop 1 中,管理作业和监视它们的过程是由称为 JobTracker 和 TaskTracker 的进程执行的。运行 JobTracker 守护进程(进程)的 NameNodes 会将作业提交给运行 TaskTracker 守护进程(进程)的 DataNodes。

JobTracker 负责协调所有 MapReduce 作业,并作为管理进程、处理服务器故障、重新分配到新 DataNodes 等的中央管理员。TaskTracker 监视 DataNode 中本地作业的执行,并向 JobTracker 提供状态反馈,如下所示:

JobTracker 和 TaskTrackers

这种设计长时间以来运行良好,但随着 Hadoop 的发展,对更复杂和动态功能的需求也相应增加。在 Hadoop 1 中,NameNode,因此是 JobTracker 进程,管理作业调度和资源监控。如果 NameNode 发生故障,集群中的所有活动将立即停止。最后,所有作业都必须以 MapReduce 术语表示 - 也就是说,所有代码都必须在 MapReduce 框架中编写才能执行。

Hadoop 2 解决了所有这些问题:

  • 作业管理、调度和资源监控的过程被解耦并委托给一个名为 YARN 的新框架/模块

  • 可以定义一个辅助主 NameNode,它将作为主 NameNode 的辅助

  • 此外,Hadoop 2.0 将容纳 MapReduce 以外的框架

  • Hadoop 2 不再使用固定的映射和减少插槽,而是利用容器

在 MapReduce 中,所有数据都必须从磁盘读取,这对于大型数据集的操作来说是可以接受的,但对于小型数据集的操作来说并不是最佳选择。事实上,任何需要非常快速处理(低延迟)、具有交互性的任务或需要多次迭代(因此需要多次从磁盘读取相同数据)的任务都会非常慢。

通过消除这些依赖关系,Hadoop 2 允许开发人员实现支持具有不同性能要求的作业的新编程框架,例如低延迟和交互式实时查询,机器学习所需的迭代处理,流数据处理等不同拓扑结构,优化,例如内存数据缓存/处理等。

出现了一些新术语:

  • ApplicationMaster:负责管理应用程序所需的资源。例如,如果某个作业需要更多内存,ApplicationMaster 将负责获取所需的资源。在这种情况下,应用程序指的是诸如 MapReduce、Spark 等应用执行框架。

  • 容器:资源分配的单位(例如,1GB 内存和四个 CPU)。一个应用程序可能需要多个这样的容器来执行。ResourceManager 为执行任务分配容器。分配完成后,ApplicationMaster 请求 DataNodes 启动分配的容器并接管容器的管理。

  • ResourceManager:YARN 的一个组件,其主要作用是为应用程序分配资源,并作为 JobTracker 的替代品。ResourceManager 进程在 NameNode 上运行,就像 JobTracker 一样。

  • NodeManagers:NodeManagers 是 TaskTracker 的替代品,负责向 ResourceManager(RM)报告作业的状态,并监视容器的资源利用情况。

下图显示了 Hadoop 2.0 中 ResourceManager 和 NodeManagers 的高层视图:

Hadoop 2.0

Hadoop 2 中固有的显着概念已在下一图中说明:

Hadoop 2.0 概念

YARN 中的作业调度

大型 Hadoop 集群同时运行多个作业并不罕见。当有多个部门提交了多个作业时,资源的分配就成为一个重要且有趣的话题。如果说,A 和 B 两个部门同时提交了作业,每个请求都是为了获得最大可用资源,那么哪个请求应该优先获得资源呢?一般来说,Hadoop 使用先进先出FIFO)策略。也就是说,谁先提交作业,谁就先使用资源。但如果 A 先提交了作业,但完成 A 的作业需要五个小时,而 B 的作业将在五分钟内完成呢?

为了处理作业调度中的这些细微差别和变量,已经实施了许多调度方法。其中三种常用的方法是:

  • FIFO:如上所述,FIFO 调度使用队列来优先处理作业。作业按照提交的顺序执行。

  • CapacityScheduler:CapacityScheduler 根据每个部门可以提交的作业数量分配值,其中部门可以表示用户的逻辑组。这是为了确保每个部门或组可以访问 Hadoop 集群并能够利用最少数量的资源。如果服务器上有未使用的资源,调度程序还允许部门根据每个部门的最大值设置超出其分配容量。因此,CapacityScheduler 的模型提供了每个部门可以确定性地访问集群的保证。

  • 公平调度程序:这些调度程序试图在不同应用程序之间均匀平衡资源的利用。虽然在某个特定时间点上可能无法实现平衡,但通过随时间平衡分配,可以使用公平调度程序实现平均值更或多或少相似的目标。

这些以及其他调度程序提供了精细的访问控制(例如基于每个用户或每个组的基础)并主要利用队列来优先和分配资源。

Hadoop 中的其他主题

Hadoop 还有一些其他方面值得特别提及。由于我们已经详细讨论了最重要的主题,本节概述了一些其他感兴趣的主题。

加密

数据加密是根据官方规定对各种类型的数据进行的。在美国,要求符合 HIPAA 规定的规则,对识别患者信息的数据进行加密存储。HDFS 中的数据可以在静态状态(在磁盘上)和/或传输过程中进行加密。用于解密数据的密钥通常由密钥管理系统(KMS)管理。

用户认证

Hadoop 可以使用服务器的本机用户认证方法。例如,在基于 Linux 的机器上,用户可以根据系统/etc/passwd文件中定义的 ID 进行身份验证。换句话说,Hadoop 继承了服务器端设置的用户认证。

通过 Kerberos 进行用户认证,这是一种跨平台的认证协议,在 Hadoop 集群中也很常见。Kerberos 基于授予用户临时权限的票据概念。可以使用 Kerberos 命令使票据无效,从而限制用户根据需要访问集群上的资源的权限。

请注意,即使用户被允许访问数据(用户认证),由于另一个名为授权的功能,他或她仍然可能受到访问数据的限制。该术语意味着即使用户可以进行身份验证并登录到系统,用户可能仅限于可以访问的数据。通常使用本机 HDFS 命令执行此级别的授权,以更改目录和文件所有权为指定的用户。

Hadoop 数据存储格式

由于 Hadoop 涉及存储大规模数据,因此选择适合您用例的存储类型至关重要。Hadoop 中可以以几种格式存储数据,选择最佳存储格式取决于您对读/写 I/O 速度的要求,文件可以按需压缩和解压缩的程度,以及文件可以被分割的容易程度,因为数据最终将被存储为块。

一些流行和常用的存储格式如下:

  • 文本/CSV:这些是纯文本 CSV 文件,类似于 Excel 文件,但以纯文本格式保存。由于 CSV 文件包含每行的记录,因此将文件拆分为数据块是自然而然的。

  • Avro:Avro 旨在改善在异构系统之间高效共享数据。它使用数据序列化,将模式和实际数据存储在单个紧凑的二进制文件中。Avro 使用 JSON 存储模式和二进制格式存储数据,并将它们序列化为单个 Avro 对象容器文件。多种语言,如 Python、Scala、C/C++等,都有本机 API 可以读取 Avro 文件,因此非常适合跨平台数据交换。

  • Parquet:Parquet 是一种列式数据存储格式。这有助于提高性能,有时甚至显著提高性能,因为它允许按列存储和访问数据。直观地说,如果你正在处理一个包含 100 列和 100 万行的 1GB 文件,并且只想从这 100 列中查询数据,能够只访问单独的列会比访问整个文件更有效。

  • ORCFiles:ORC 代表优化的行列格式。从某种意义上说,它是对纯列格式(如 Parquet)的进一步优化。ORCFiles 不仅按列存储数据,还按行存储,也称为条带。因此,以表格格式存储的文件可以分割成多个较小的条带,其中每个条带包含原始文件的一部分行。通过这种方式分割数据,如果用户任务只需要访问数据的一个小部分,那么该过程可以查询包含数据的特定条带。

  • SequenceFiles:在 SequenceFiles 中,数据表示为键值对并以二进制序列化格式存储。由于序列化,数据可以以紧凑的二进制格式表示,不仅减小了数据大小,而且提高了 I/O。Hadoop,尤其是 HDFS,在存在多个小文件(如音频文件)时效率不高。SequenceFiles 通过允许将多个小文件存储为单个单元或 SequenceFile 来解决了这个问题。它们也非常适合可分割的并行操作,并且对于 MapReduce 作业总体上是高效的。

  • HDFS 快照:HDFS 快照允许用户以只读模式保存特定时间点的数据。用户可以在 HDFS 中创建快照,实质上是数据在那个时间点的副本,以便在以后需要时检索。这确保了在文件损坏或其他影响数据可用性的故障发生时可以恢复数据。在这方面,它也可以被视为备份。快照存储在一个.snapshot 目录中,用户在那里创建了它们。

  • 节点故障处理:大型 Hadoop 集群可能包含数万个节点。因此,任何一天都可能发生服务器故障。为了让 NameNode 了解集群中所有节点的状态,DataNodes 向 NameNode 发送定期心跳。如果 NameNode 检测到服务器已经失败,即它停止接收心跳,它会将服务器标记为失败,并将本地服务器上的所有数据复制到新实例上。

Hadoop 3 中预期的新功能

在撰写本书时,Hadoop 3 处于 Alpha 阶段。关于 Hadoop 3 中将可用的新变化的详细信息可以在互联网上找到。例如,hadoop.apache.org/docs/current/提供了关于架构新变化的最新信息。

Hadoop 生态系统

这一章应该被命名为 Apache 生态系统。像本节中将讨论的所有其他项目一样,Hadoop 是一个 Apache 项目。Apache 是一个开源项目的简称,由 Apache 软件基金会支持。它最初起源于 90 年代初开发的 Apache HTTP 服务器,并且今天是一个协作的全球倡议,完全由参与向全球技术社区发布开源软件的志愿者组成。

Hadoop 最初是 Apache 生态系统中的一个项目,现在仍然是。由于其受欢迎程度,许多其他 Apache 项目也直接或间接地与 Hadoop 相关联,因为它们支持 Hadoop 环境中的关键功能。也就是说,重要的是要记住,这些项目在大多数情况下可以作为独立产品存在,可以在没有 Hadoop 环境的情况下运行。它是否能提供最佳功能将是一个单独的话题。

在本节中,我们将介绍一些对 Hadoop 的增长和可用性产生了重大影响的 Apache 项目,如下图所示:

产品 功能
Apache Pig Apache Pig,也称为 Pig Latin,是一种专门设计用于通过简洁的语句表示 MapReduce 程序的语言,这些语句定义了工作流程。使用传统方法编写 MapReduce 程序,比如用 Java,可能会非常复杂,Pig 提供了一种简单的抽象来表达 MapReduce 工作流程和复杂的抽取-转换-加载ETL)过程。Pig 程序通过 Grunt shell 执行。
Apache HBase Apache HBase 是一个分布式列式数据库,位于 HDFS 之上。它是基于 Google 的 BigTable 模型设计的,其中数据以列格式表示。HBase 支持跨数十亿条记录的表的低延迟读写,并且非常适合需要直接随机访问数据的任务。更具体地说,HBase 以三个维度索引数据 - 行、列和时间戳。它还提供了一种表示具有任意列数的数据的方法,因为列值可以在 HBase 表的单元格中表示为键值对。
Apache Hive Apache Hive 提供了类似 SQL 的方言来查询存储在 HDFS 中的数据。Hive 将数据以序列化的二进制文件形式存储在 HDFS 中的类似文件夹的结构中。与传统数据库管理系统中的表类似,Hive 以表格格式存储数据,根据用户选择的属性在 HDFS 中进行分区。因此,分区是高级目录或表的子文件夹。概念上提供了第三层抽象,即桶,它引用 Hive 表的分区中的文件。
Apache Sqoop Sqoop 用于从传统数据库中提取数据到 HDFS。因此,将数据存储在关系数据库管理系统中的大型企业可以使用 Sqoop 将数据从其数据仓库转移到 Hadoop 实现中。
Apache Flume Flume 用于管理、聚合和分析大规模日志数据。
Apache Kafka Kafka 是一个基于发布/订阅的中间件系统,可用于实时分析和随后将流数据(在 HDFS 中)持久化。
Apache Oozie Oozie 是一个用于调度 Hadoop 作业的工作流管理系统。它实现了一个称为有向无环图DAG)的关键概念,这将在我们关于 Spark 的部分中讨论。
Apache Spark Spark 是 Apache 中最重要的项目之一,旨在解决 HDFS-MapReduce 模型的一些缺点。它最初是加州大学伯克利分校的一个相对较小的项目,迅速发展成为用于分析任务的 Hadoop 最重要的替代方案之一。Spark 在行业中得到了广泛的应用,并包括其他各种子项目,提供额外的功能,如机器学习、流式分析等。

CDH 实战

在本节中,我们将利用 CDH QuickStart VM 来学习本章讨论的一些主题。这些练习不一定要按照时间顺序进行,并且不依赖于完成其他练习。

我们将在本节中完成以下练习:

  • 使用 Hadoop MapReduce 进行词频统计

  • 使用 HDFS

  • 使用 Apache Hive 下载和查询数据

使用 Hadoop MapReduce 进行词频统计

在本练习中,我们将尝试计算有史以来最长小说之一中每个单词的出现次数。对于本练习,我们选择了由乔治和/或玛德琳·德·斯库德里(Georges and/or Madeleine de Scudéry)于 1649-1653 年间编写的书籍《Artamène ou le Grand Cyrus》。该书被认为是有史以来第二长的小说,根据维基百科上相关列表(en.wikipedia.org/wiki/List_of_longest_novels)。这部小说共有 10 卷,共计 13,905 页,约有两百万字。

首先,我们需要在 VirtualBox 中启动 Cloudera Distribution of Hadoop Quickstart VM,并双击 Cloudera Quickstart VM 实例:

启动需要一些时间,因为它初始化所有与 CDH 相关的进程,如 DataNode、NameNode 等:

一旦进程启动,它将启动一个默认的着陆页,其中包含与 Hadoop 相关的许多教程的引用。在本节中,我们将在 Unix 终端中编写我们的 MapReduce 代码。从左上角菜单中启动终端,如下截图所示:

现在,我们必须按照以下步骤进行:

  1. 创建一个名为cyrus的目录。这是我们将存储包含书文本的所有文件的地方。

  2. 按照第 4 步所示运行getCyrusFiles.sh。这将把书下载到cyrus目录中。

  3. 按照所示运行processCyrusFiles.sh。该书包含各种 Unicode 和不可打印字符。此外,我们希望将所有单词改为小写,以忽略相同但具有不同大小写的单词的重复计数。

  4. 这将产生一个名为cyrusprint.txt的文件。该文件包含整本书的全部文本。我们将在这个文本文件上运行我们的 MapReduce 代码。

  5. 准备mapper.pyreducer.py。顾名思义,mapper.py运行 MapReduce 过程的映射部分。同样,reducer.py运行 MapReduce 过程的减少部分。文件mapper.py将文档拆分为单词,并为文档中的每个单词分配一个值为一的值。文件reducer.py将读取mapper.py的排序输出,并对相同单词的出现次数进行求和(首先将单词的计数初始化为一,并在每个新单词的出现时递增)。最终输出是一个包含文档中每个单词计数的文件。

步骤如下:

  1. 创建getCyrusFiles.sh - 此脚本将用于从网络中检索数据:
[cloudera@quickstart ~]$ mkdir cyrus 
[cloudera@quickstart ~]$ vi getCyrusFiles.sh 
[cloudera@quickstart ~]$ cat getCyrusFiles.sh  
for i in `seq 10` 
do 
curl www.artamene.org/documents/cyrus$i.txt -o cyrus$i.txt 
done 
  1. 创建processCyrusFiles.sh - 此脚本将用于连接和清理在上一步中下载的文件:
[cloudera@quickstart ~]$ vi processCyrusFiles.sh 
[cloudera@quickstart ~]$ cat processCyrusFiles.sh  
cd ~/cyrus; 
for i in `ls cyrus*.txt` do cat $i >> cyrusorig.txt; done 
cat cyrusorig.txt | tr -dc '[:print:]' | tr A-Z a-z > cyrusprint.txt  
  1. 更改权限为 755,以使.sh文件在命令提示符下可执行:
[cloudera@quickstart ~]$ chmod 755 getCyrusFiles.sh  
[cloudera@quickstart ~]$ chmod 755 processCyrusFiles.sh  
  1. 执行getCyrusFiles.sh
[cloudera@quickstart cyrus]$ ./getCyrusFiles.sh  
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100  908k  100  908k    0     0   372k      0  0:00:02  0:00:02 --:--:--  421k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1125k  100 1125k    0     0   414k      0  0:00:02  0:00:02 --:--:--  471k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1084k  100 1084k    0     0   186k      0  0:00:05  0:00:05 --:--:--  236k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1048k  100 1048k    0     0   267k      0  0:00:03  0:00:03 --:--:--  291k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1116k  100 1116k    0     0   351k      0  0:00:03  0:00:03 --:--:--  489k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1213k  100 1213k    0     0   440k      0  0:00:02  0:00:02 --:--:--  488k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1119k  100 1119k    0     0   370k      0  0:00:03  0:00:03 --:--:--  407k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1132k  100 1132k    0     0   190k      0  0:00:05  0:00:05 --:--:--  249k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1084k  100 1084k    0     0   325k      0  0:00:03  0:00:03 --:--:--  365k 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100 1259k  100 1259k    0     0   445k      0  0:00:02  0:00:02 --:--:--  486k 

[cloudera@quickstart cyrus]$ ls 
cyrus10.txt  cyrus3.txt  cyrus6.txt  cyrus9.txt 
cyrus1.txt   cyrus4.txt  cyrus7.txt  getCyrusFiles.sh 
cyrus2.txt   cyrus5.txt  cyrus8.txt  processCyrusFiles.sh 

  1. 执行processCyrusFiles.sh

[cloudera@quickstart cyrus]$ ./processCyrusFiles.sh  

[cloudera@quickstart cyrus]$ ls 
cyrus10.txt  cyrus3.txt  cyrus6.txt  cyrus9.txt      getCyrusFiles.sh 
cyrus1.txt   cyrus4.txt  cyrus7.txt  cyrusorig.txt   processCyrusFiles.sh 
cyrus2.txt   cyrus5.txt  cyrus8.txt  cyrusprint.txt 

[cloudera@quickstart cyrus]$ ls -altrh cyrusprint.txt  
-rw-rw-r-- 1 cloudera cloudera 11M Jun 28 20:02 cyrusprint.txt 

[cloudera@quickstart cyrus]$ wc -w cyrusprint.txt  
1953931 cyrusprint.txt 
  1. 执行以下步骤,将最终文件cyrusprint.txt复制到 HDFS,创建mapper.pyreducer.py脚本。

mapper.pyreducer.py文件在 Glenn Klockwood 的网站上有引用(www.glennklockwood.com/data-intensive/hadoop/streaming.html),该网站提供了大量关于 MapReduce 和相关主题的信息。

以下代码显示了mapper.py的内容:

[cloudera@quickstart cyrus]$ hdfs dfs -ls /user/cloudera 

[cloudera@quickstart cyrus]$ hdfs dfs -mkdir /user/cloudera/input 

[cloudera@quickstart cyrus]$ hdfs dfs -put cyrusprint.txt /user/cloudera/input/ 

[cloudera@quickstart cyrus]$ vi mapper.py 

[cloudera@quickstart cyrus]$ cat mapper.py  
#!/usr/bin/env python 
#the above just indicates to use python to intepret this file 
#This mapper code will input a line of text and output <word, 1> # 

import sys 
sys.path.append('.') 

for line in sys.stdin: 
   line = line.strip() 
   keys = line.split() 
   for key in keys: 
          value = 1 
          print ("%s\t%d" % (key,value)) 

[cloudera@quickstart cyrus]$ vi reducer.py # Copy-Paste the content of reducer.py as shown below using the vi or nano Unix editor.

[cloudera@quickstart cyrus]$ cat reducer.py  
#!/usr/bin/env python 

import sys 
sys.path.append('.') 

last_key = None 
running_total = 0 

for input_line in sys.stdin: 
   input_line = input_line.strip() 
   this_key, value = input_line.split("\t", 1) 
   value = int(value) 

   if last_key == this_key: 
       running_total += value 
   else: 
       if last_key: 
           print("%s\t%d" % (last_key, running_total)) 
       running_total = value 
       last_key = this_key 

if last_key == this_key: 
   print( "%s\t%d" % (last_key, running_total) ) 

[cloudera@quickstart cyrus]$ chmod 755 *.py
  1. 执行 mapper 和 reducer 脚本,执行 MapReduce 操作以产生词频统计。您可能会看到如下所示的错误消息,但出于本练习的目的(以及为了生成结果),您可以忽略它们:
[cloudera@quickstart cyrus]$ hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -input /user/cloudera/input -output /user/cloudera/output -mapper /home/cloudera/cyrus/mapper.py -reducer /home/cloudera/cyrus/reducer.py 

packageJobJar: [] [/usr/lib/hadoop-mapreduce/hadoop-streaming-2.6.0-cdh5.10.0.jar] /tmp/streamjob1786353270976133464.jar tmpDir=null 
17/06/28 20:11:21 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 
17/06/28 20:11:21 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032 
17/06/28 20:11:22 INFO mapred.FileInputFormat: Total input paths to process : 1 
17/06/28 20:11:22 INFO mapreduce.JobSubmitter: number of splits:2 
17/06/28 20:11:23 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1498704103152_0002 
17/06/28 20:11:23 INFO impl.YarnClientImpl: Submitted application application_1498704103152_0002 
17/06/28 20:11:23 INFO mapreduce.Job: The url to track the job: http://quickstart.cloudera:8088/proxy/application_1498704103152_0002/ 
17/06/28 20:11:23 INFO mapreduce.Job: Running job: job_1498704103152_0002 
17/06/28 20:11:30 INFO mapreduce.Job: Job job_1498704103152_0002 running in uber mode : false 
17/06/28 20:11:30 INFO mapreduce.Job:  map 0% reduce 0% 
17/06/28 20:11:41 INFO mapreduce.Job:  map 50% reduce 0% 
17/06/28 20:11:54 INFO mapreduce.Job:  map 83% reduce 0% 
17/06/28 20:11:57 INFO mapreduce.Job:  map 100% reduce 0% 
17/06/28 20:12:04 INFO mapreduce.Job:  map 100% reduce 100% 
17/06/28 20:12:04 INFO mapreduce.Job: Job job_1498704103152_0002 completed successfully 
17/06/28 20:12:04 INFO mapreduce.Job: Counters: 50 
   File System Counters 
          FILE: Number of bytes read=18869506 
          FILE: Number of bytes written=38108830 
          FILE: Number of read operations=0 
          FILE: Number of large read operations=0 
          FILE: Number of write operations=0 
          HDFS: Number of bytes read=16633042 
          HDFS: Number of bytes written=547815 
          HDFS: Number of read operations=9 
          HDFS: Number of large read operations=0 
          HDFS: Number of write operations=2 
   Job Counters  
          Killed map tasks=1 
          Launched map tasks=3 
          Launched reduce tasks=1 
          Data-local map tasks=3 
          Total time spent by all maps in occupied slots (ms)=39591 
          Total time spent by all reduces in occupied slots (ms)=18844 
          Total time spent by all map tasks (ms)=39591 
          Total time spent by all reduce tasks (ms)=18844 
          Total vcore-seconds taken by all map tasks=39591 
          Total vcore-seconds taken by all reduce tasks=18844 
          Total megabyte-seconds taken by all map tasks=40541184 
          Total megabyte-seconds taken by all reduce tasks=19296256 
   Map-Reduce Framework 
          Map input records=1 
          Map output records=1953931 
          Map output bytes=14961638 
          Map output materialized bytes=18869512 
          Input split bytes=236 
          Combine input records=0 
          Combine output records=0 
          Reduce input groups=45962 
          Reduce shuffle bytes=18869512 
          Reduce input records=1953931 
          Reduce output records=45962 
          Spilled Records=3907862 
          Shuffled Maps =2 
          Failed Shuffles=0 
          Merged Map outputs=2 
          GC time elapsed (ms)=352 
          CPU time spent (ms)=8400 
          Physical memory (bytes) snapshot=602038272 
          Virtual memory (bytes) snapshot=4512694272 
          Total committed heap usage (bytes)=391979008 
   Shuffle Errors 
          BAD_ID=0 
          CONNECTION=0 
          IO_ERROR=0 
          WRONG_LENGTH=0 
          WRONG_MAP=0 
          WRONG_REDUCE=0 
   File Input Format Counters  
          Bytes Read=16632806 
   File Output Format Counters  
          Bytes Written=547815 
17/06/28 20:12:04 INFO streaming.StreamJob: Output directory: /user/cloudera/output
  1. 结果存储在 HDFS 中的/user/cloudera/output目录下,文件名以part-为前缀:
[cloudera@quickstart cyrus]$ hdfs dfs -ls /user/cloudera/output 
Found 2 items 
-rw-r--r--   1 cloudera cloudera          0 2017-06-28 20:12 /user/cloudera/output/_SUCCESS 
-rw-r--r--   1 cloudera cloudera     547815 2017-06-28 20:12 /user/cloudera/output/part-00000  
  1. 要查看文件的内容,请使用hdfs dfs -cat并提供文件名。在这种情况下,我们查看输出的前 10 行:
[cloudera@quickstart cyrus]$ hdfs dfs -cat /user/cloudera/output/part-00000 | head -10 
!  1206 
!) 1 
!quoy,    1 
'  3 
'' 1 
'. 1 
'a 32 
'appelloit 1 
'auoit    1 
'auroit   10  

使用 Hive 分析石油进口价格

在本节中,我们将使用 Hive 分析 1980-2016 年间世界各国的石油进口价格。数据可从OECD(经济合作与发展组织)的网站上获取,网址如下截图所示:

实际的 CSV 文件可从stats.oecd.org/sdmx-json/data/DP_LIVE/.OILIMPPRICE.../OECD?contentType=csv&amp;detail=code&amp;separator=comma&amp;csv-lang=en获取。

由于我们将在 Hive 中加载数据,因此通过 Cloudera Quickstart CDH 环境中的终端将文件下载到我们的主目录是有意义的。我们将执行以下步骤:

  1. 将 CSV 文件下载到 CDH 环境中:

# Download the csv file 
cd /home/cloudera; 
wget -O oil.csv "https://stats.oecd.org/sdmx-json/data/DP_LIVE/.OILIMPPRICE.../OECD?contentType=csv&amp;detail=code&amp;separator=comma&amp;csv-lang=en" 
  1. 清理 CSV 文件。数据清洗是数据科学中非常重要的领域。在实践中,经常会收到需要清洗的文件。这是因为列中可能包含无效字符或值、缺失数据、缺少或额外的分隔符等。我们注意到各种值都用双引号(")括起来。在 Hive 中,我们可以通过在创建表时指定quoteChar属性来忽略引号。由于 Linux 也提供了简单易行的方法来删除这些字符,我们使用sed来删除引号:
[cloudera@quickstart ~]$ sed -i 's/\"//g' oil.csv 

此外,在我们下载的文件oil.csv中,我们观察到存在可能引起问题的不可打印字符。我们通过发出以下命令将它们删除:

[cloudera@quickstart ~]$ tr -cd '\11\12\15\40-\176' oil_.csv > oil_clean.csv

(来源:alvinalexander.com/blog/post/linux-unix/how-remove-non-printable-ascii-characters-file-unix

最后,我们将新文件(oil_clean.csv)复制到oil.csv。由于oil.csv文件已存在于同一文件夹中,我们收到了覆盖消息,我们输入yes

[cloudera@quickstart ~]$ mv oil_clean.csv oil.csv 
mv: overwrite `oil.csv'? yes 
  1. 登录到 Cloudera Hue:

在浏览器的书签栏中点击 Hue。这将显示 Cloudera 登录界面。使用 IDcloudera和密码cloudera登录:

  1. 从 Hue 登录窗口的快速启动下拉菜单中选择 Hue:

  1. 创建表模式,加载 CSV 文件oil.csv,并查看记录:
CREATE TABLE IF NOT EXISTS OIL 
   (location String, indicator String, subject String, measure String,  
   frequency String, time String, value Float, flagCode String) 
   ROW FORMAT DELIMITED 
   FIELDS TERMINATED BY ',' 
   LINES TERMINATED BY '\n' 
   STORED AS TEXTFILE 
   tblproperties("skip.header.line.count"="1"); 

LOAD DATA LOCAL INPATH '/home/cloudera/oil.csv' INTO TABLE OIL; 
SELECT * FROM OIL; 

  1. 加载石油文件。

  2. 现在表已加载到 Hive 中,您可以使用 HiveQL 运行各种 Hive 命令。这些命令的完整集合可在cwiki.apache.org/confluence/display/Hive/LanguageManual上找到。

例如,要查找 1980-2015 年(数据集的日期范围)每个国家的石油价格的最大值、最小值和平均值,我们可以使用熟悉的 SQL 运算符。查询如下:

SELECT LOCATION, MIN(value) as MINPRICE, AVG(value) as AVGPRICE,  
MAX(value) as MAXPRICE 
FROM OIL 
WHERE FREQUENCY LIKE "A" 
GROUP BY LOCATION; 

以下是相同的截图:

类似地,我们可以使用一系列其他 SQL 命令。Hive 手册详细介绍了这些命令以及数据保存、查询和检索的各种方式。

Hue 包括一系列有用的功能,如数据可视化、数据下载等,允许用户对数据进行临时分析。

要访问可视化功能,请在结果部分的网格图标下方点击可视化图标,如下截图所示:

选择散点图。在 Hue 中,这种类型的图表,也被更普遍地称为散点图,允许用户非常容易地创建多变量图表。可以选择 x 和 y 轴的不同数值,以及散点大小和分组,如下截图所示:

以下是一个简单的饼图,可以通过在下拉菜单中选择饼图来构建:

在 Hive 中连接表格

Hive 支持高级连接功能。以下是使用左连接的过程。如图所示,原始表格中有每个国家的数据,用它们的三字母国家代码表示。由于 Hue 支持地图图表,我们可以添加纬度和经度的数值,将石油定价数据叠加在世界地图上。

为此,我们需要下载一个包含纬度和经度数值的数据集:

# ENTER THE FOLLOWING IN THE UNIX TERMINAL 
# DOWNLOAD LATLONG CSV FILE 

cd /home/cloudera; 
wget -O latlong.csv "https://gist.githubusercontent.com/tadast/8827699/raw/7255fdfbf292c592b75cf5f7a19c16ea59735f74/countries_codes_and_coordinates.csv" 

# REMOVE QUOTATION MARKS 
sed -i 's/\"//g' latlong.csv 

一旦文件被下载和清理,就在 Hive 中定义模式并加载数据:

CREATE TABLE IF NOT EXISTS LATLONG 
   (country String, alpha2 String, alpha3 String, numCode Int, latitude Float, longitude Float) 
   ROW FORMAT DELIMITED 
   FIELDS TERMINATED BY ',' 
   LINES TERMINATED BY '\n' 
   STORED AS TEXTFILE 
   TBLPROPERTIES("skip.header.line.count"="1"); 

LOAD DATA LOCAL INPATH '/home/cloudera/latlong.csv' INTO TABLE LATLONG; 

将石油数据与纬度/经度数据进行连接:

SELECT DISTINCT * FROM 
(SELECT location, avg(value) as AVGPRICE from oil GROUP BY location) x 
LEFT JOIN 
(SELECT TRIM(ALPHA3) AS alpha3, latitude, longitude from LATLONG) y 
ON (x.location = y.alpha3); 

现在我们可以开始创建地理空间可视化。请记住,这些是在 Hue 中提供非常方便的查看数据的初步可视化。可以使用 shapefile、多边形和其他高级图表方法在地理数据上开发更深入的可视化。

从下拉菜单中选择渐变地图,并输入适当的数值来创建图表,如下图所示:

下一个图表是使用下拉菜单中的标记地图选项开发的。它使用三个字符的国家代码来在相应的区域放置标记和相关数值,如下图所示:

总结

本章提供了 Hadoop 的技术概述。我们讨论了 Hadoop 的核心组件和核心概念,如 MapReduce 和 HDFS。我们还研究了使用 Hadoop 的技术挑战和考虑因素。虽然在概念上可能看起来很简单,但 Hadoop 架构的内部运作和正式管理可能相当复杂。在本章中,我们强调了其中一些。

我们以使用 Cloudera Distribution 的 Hadoop 进行了实际操作的方式结束。对于本教程,我们使用了之前从 Cloudera 网站下载的 CDH 虚拟机。

在下一章中,我们将看一下 NoSQL,这是 Hadoop 的一个替代或补充解决方案,取决于您个人和/或组织的需求。虽然 Hadoop 提供了更丰富的功能集,但如果您的预期用例可以简单地使用 NoSQL 解决方案,后者可能是在所需的努力方面更容易的选择。

第五章:使用 NoSQL 进行大数据挖掘

术语NoSQL最初是由 Carlo Strozzi 使用的,他在 1998 年发布了 Strozzi NoSQL 开源关系数据库。在 2000 年代末,数据库架构中出现了新的范式,其中许多范式不符合关系数据库系统所需的严格约束。由于这些数据库不符合 ACID 兼容性等标准数据库约定,它们很快被归为一个称为 NoSQL 的广泛类别。

每个 NoSQL 数据库都声称对某些用例最优。虽然其中很少有适合成为通用数据库管理系统的要求,但它们都在整个 NoSQL 系统范围内利用了一些共同的主题。

在本章中,我们将讨论 NoSQL 数据库管理系统的一些广泛类别。我们将讨论引发迁移到 NoSQL 数据库系统的主要驱动因素,以及这些数据库如何解决导致它们广泛采用的特定业务需求,并最后进行一些 NoSQL 实际练习。

本章涵盖的主题包括:

  • 为什么选择 NoSQL?

  • NoSQL 数据库

  • 内存数据库

  • 列式数据库

  • 面向文档的数据库

  • 键值数据库

  • 图数据库

  • 其他 NoSQL 类型和总结

  • NoSQL 系统的实际练习

为什么选择 NoSQL?

术语 NoSQL 通常意味着不仅仅是 SQL:也就是说,底层数据库具有与常见和传统数据库系统不同的属性。因此,除了它们不提供 ACID 兼容性的特征之外,没有明确的区分资格数据库作为 NoSQL 的标准。因此,了解 ACID 属性的性质将有助于理解数据库系统多年来的主要特点,以及简要讨论 BASE 和 CAP 的重要性,这两个术语是当今数据库的核心术语。

ACID、BASE 和 CAP 属性

让我们首先讨论 ACID 和 SQL。

ACID 和 SQL

ACID 代表原子性、一致性、隔离性和持久性:

  • 原子性:这表示数据库事务要么完全执行,要么根本不执行。换句话说,要么所有事务都应该被提交,即完全持久化,要么根本不提交。没有部分执行事务的余地。

  • 一致性:对数据的约束,即确定数据库内数据管理的规则,将在整个数据库中保持一致。不同的实例不会遵守与数据库其他实例不同的规则。

  • 隔离性:此属性定义了并发操作(事务)如何读取和写入数据的规则。例如,如果某个记录正在被更新,而另一个进程读取同一条记录,数据库系统的隔离级别将决定返回给用户的数据版本。

  • 持久性:数据库系统的持久性通常表示已提交的事务即使在系统故障的情况下也将保持持久。这通常通过数据库可以在恢复期间参考的事务日志来管理。

读者可能会注意到这里定义的所有属性主要与数据库事务有关。事务是遵守上述规则并对数据库进行更改的操作单元。例如,从 ATM 机中典型的取款可能有以下逻辑路径:

  1. 用户从 ATM 机中取款

  2. 银行检查用户的当前余额

  3. 数据库系统从用户的账户中扣除相应的金额

  4. 数据库系统更新用户账户中的金额以反映变化

因此,在 1990 年代中期之前广泛使用的大多数数据库,如 Oracle、Sybase、DB2 等,都针对记录和管理事务数据进行了优化。直到这个时候,大多数数据库都负责管理事务数据。90 年代中期互联网的快速增长导致出现了新类型的数据,这些数据不一定需要严格的 ACID 兼容性要求。YouTube 上的视频、Pandora 上的音乐和企业电子邮件记录都是事务数据库不会增加价值的用例的例子,除了作为存储数据的技术层之外。

NoSQL 的 BASE 属性

到了 2000 年代末,数据量激增,显然需要一种新的替代模型来管理数据。这种新模型称为 BASE,成为取代 ACID 成为首选数据库管理系统模型的基础主题。

BASE代表Basically Available Soft-state Eventually consistency。这意味着数据库基本上大部分时间都可以使用;也就是说,可能会有一段时间服务不可用(因此应该实施额外的冗余措施)。Soft-state意味着系统的状态不能保证 - 相同数据的不同实例可能具有不同的内容,因为它可能还没有捕获集群另一部分的最新更新。最后,eventually consistent 意味着尽管数据库可能并非始终处于相同状态,但最终会达到相同状态;也就是说,变得consistent

CAP 定理

CAP 定理由 Eric Allen Brewer 于 1990 年代末首次提出,它对分布式数据库系统的约束或更一般地说特征进行了分类。简而言之,CAP 定理假设严格来说,数据库系统只能保证 CAP 定义的三个属性中的两个。

  • 一致性:数据应该在数据库的所有实例中保持一致,因此,在查询时应该在所有节点上提供一致的结果

  • 可用性:无论任何单个节点的状态如何,系统在执行查询时始终会响应结果(无论是否是最新提交)

  • 分区容错性:这意味着当节点在网络上分离时,系统应该继续正常运行,即使任何节点失去与另一个节点的互联性

从这一点可以看出,在集群中,节点将通过网络连接,而网络本质上是可以中断的,因此必须保证分区容错性,以便系统能够继续正常运行。在这种情况下,争议在于选择一致性和可用性之间。例如,如果系统必须保持一致;也就是说,在所有节点上显示最新的提交,所有节点不能同时可用,因为一些节点可能没有最新的提交。在这种情况下,对新更新的查询将不会执行,直到所有节点都已更新为新数据。在可用性的情况下,以类似的术语,我们无法保证一致性,因为始终可用意味着一些节点将不具有与另一个节点相同的数据,如果新的更新尚未写入到相应的节点上。

在决定是确保一致性还是确保可用性之间存在很大的混乱和争议,因此数据库被分类为CPAP。对于这个练习,我们不需要陷入术语,因为那将导致一场相当抽象和哲学的讨论。上述术语的信息主要是为了反映一些驱动数据库开发的基础理论。

NoSQL 技术的需求

虽然大多数数据库系统最初是为了管理事务而设计的,但互联网相关技术的增长和不需要事务系统严格净化性质的新类型数据的增长,促使了替代框架的发展。

例如,存储以下类型的数据不一定需要复杂的事务性数据库

  • 电子邮件

  • 媒体文件,如音频/视频文件

  • 社交网络消息

  • 网站 HTML 页面

  • 许多其他类型的数据

此外,用户数量的增加,以及因此而产生的数据量,表明需要开发具有以下特点的更加健壮的架构:

  • 可扩展以管理不断增加的数据量

  • 利用商品硬件减少对昂贵硬件的依赖

  • 提供跨多个节点的分布式处理能力,以处理大规模数据集

  • 具有容错能力/提供高可用性以处理节点和站点故障

可扩展意味着系统可以通过增加节点数量(即横向扩展)来容纳数据量的增加。此外,增加节点数量对系统性能的影响应该最小。

容错意味着系统应该能够处理节点故障,在一个拥有数百甚至数千个节点的大型分布式系统中,这种情况并不罕见。

这导致了各种具有突破性和影响力的系统的发展,其中最显著的可能是 Google Bigtable 和 Amazon Dynamo。

Google Bigtable

Bigtable 是一个于 2004 年启动的项目,旨在管理 Google 各种项目中使用的数据的可扩展性和性能。描述该系统特性的开创性论文于 2006 年发布(static.googleusercontent.com/media/research.google.com/en//archive/bigtable-osdi06.pdf),标题为Bigtable: A Distributed Storage System for Structured Data。实质上,Bigtable 是一个列存储(稍后详述),其中每个值可以使用行键、列键和时间戳唯一标识。它是最早体现将数据存储在列格式而不是使用更常见的基于行的布局的数据库之一。尽管在 Bigtable 之前存在诸如 kdb+和 Sybase IQ 之类的列式数据库,但行业领先者使用该方法来管理 PB 级别信息的概念将该概念推上了舞台。

Bigtable 的官方网站总结了键值主张:

Bigtable 旨在以一致的低延迟和高吞吐量处理大规模工作负载,因此它是操作和分析应用的绝佳选择,包括物联网、用户分析和金融数据分析。

自从 Bigtable 推出以来,其他几个 NoSQL 数据库也采用了列式数据布局的惯例;其中最著名的是 HBase 和 Accumulo,它们都是 Apache 项目。

Bigtable 解决方案如今可以在cloud.google.com/bigtable/上使用,并可以按订阅方式购买。较小数据量的费用相当低廉和合理,而更大的安装则需要更广泛的实施。

Amazon Dynamo

就在 Google 宣布 Bigtable 不久之后,亚马逊在 2007 年 10 月举办的第 21 届操作系统原理研讨会上宣布了其内部 Dynamo 数据库(www.sosp2007.org)。

在这篇论文中,亚马逊描述了一种名为 Dynamo 的键值存储,该论文现在可以在 Werner Vogels 的网站上找到www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf,Dynamo 被用于支持亚马逊 AWS 上的一些最关键的内部服务,如 S3。该论文提出了一些关键概念,如键值存储、一致性哈希和向量时钟等,这些概念在 Dynamo 中得到了实现。

因此,Dynamo 为大规模数据集的列存储提供了一种替代方案,引入了一种基本不同的方法,利用了键值关联。

在接下来的几节中,我们将讨论各种类型的 NoSQL 技术,以及它们各自具有使它们对某些用例最优的特性。NoSQL 已经引领了我们对待数据库的范式转变,并为以前不可行的规模提供了急需的数据管理替代视图。

NoSQL 数据库

在我们讨论 NoSQL 类型和数据库时,我们将主要关注 NoSQL 数据库的以下特性:

  • 内存数据库

  • 列式数据库

  • 面向文档的数据库

  • 键值数据库

  • 图数据库

  • 其他 NoSQL 类型和总结

今天在行业中使用的大多数 NoSQL 类型都属于这些类别中的一个或多个。接下来的几节将讨论每种 NoSQL 产品的高级特性、它们的主要优势以及市场上属于各自类别的产品。

内存数据库

内存数据库,顾名思义,利用计算机内存,即 RAM,来存储数据集。在我们研究内存数据库如何工作之前,值得回顾一下典型计算机中数据传输是如何发生的:

简单数据流计算机层次结构

如前图所示,数据从磁盘到内存到 CPU。这是对确切过程的非常高级的概括,因为在 CPU 不需要发送指令从内存读取数据的条件下(例如当数据已经存在于 CPU L2 缓存中 - 这是 CPU 中包含用于缓存数据的内存的一部分),但从根本上讲,CPU、RAM 和磁盘之间的过程是线性的。

存储在磁盘上的数据可以以取决于磁盘的 I/O(输入/输出)吞吐量的一定速率转移到内存。从磁盘访问数据大约需要 10-20 毫秒(ms)。虽然确切的数字取决于数据的大小,但最小的寻道时间(磁盘找到数据位置所需的时间)本身大约是 10-15 毫秒。将这与从内存获取数据所需的时间相比,大约是 100 纳秒。最后,从 CPU L2 缓存读取数据大约需要 7 纳秒。

为了形象地说明这一点,15 毫秒的磁盘访问时间,即 15,000,000 纳秒,比从内存访问数据所需的时间慢 150,000 倍。换句话说,相对于磁盘,已经存在于内存中的数据可以以惊人的速度读取,快 150,000 倍。这基本上是读取随机数据的情况。读取顺序数据的时间可能不那么引人注目,但仍然快近一个数量级。

如果将磁盘和 RAM 表示为汽车,RAM 汽车在磁盘汽车只能勉强行驶两英里的时间内已经到达月球并且正在返回的路上。这就是差距有多大。

因此,从这个自然地得出结论,如果数据存储在 RAM 中,特别是在较大数据集的情况下,访问时间将大大降低,因此数据处理的时间(至少在 I/O 级别上)将显着减少。

传统上,所有数据库数据都存储在磁盘上。随着互联网的出现,行业开始利用memcached,它提供了一种通过 API 将数据以键值对的形式存储在内存中的方法。例如,MySQL 数据库通常使用 memcached API 来将对象缓存在内存中,以优化读取速度并减少对主要(MySQL)数据库的负载。

然而,随着数据量的增加,使用数据库和 memcached 方法的复杂性开始显现,专门设计用于在内存中存储数据(有时同时存储在磁盘和内存中)的数据库正在迅速发展。

因此,内存数据库(如 Redis)开始取代 memcached 成为驱动网站的快速缓存存储。在 Redis 的情况下,尽管数据将以键值对的形式存储在内存中,但也有选项将数据持久化到磁盘上。这使其与严格的内存缓存解决方案(如 memcached)有所区别。

推动向内存数据库转变的主要因素可以总结如下:

  • 通过传统的 MySQL + memcached 组合等方式来管理不断增加的数据量的复杂性,例如网站流量

  • 降低了 RAM 成本,使购买更大容量的内存更加经济

  • 整个行业都在朝着 NoSQL 技术发展,这导致了对新型创新数据库平台的增加关注和社区参与。

  • 内存中更快的数据操作提供了一种减少 I/O 开销的方法,这在需要超快速、低延迟处理数据的情况下非常重要

如今,行业中提供内存功能的数据库的主要选择包括:

开源 商业
Redis Kdb+
memcacheDB Oracle TimesTen
Aerospike SAP HANA
VoltDB HP Vertica
Apache Ignite Altibase
Apache Geode Oracle Exalytics
MonetDB MemSQL

请注意,其中一些支持混合架构,数据可以同时存储在内存和磁盘中。一般来说,数据会从内存传输到磁盘以实现持久化。此外,一些商业内存数据库提供可以根据各自解决方案适用的许可证条款免费下载和使用的社区版本。在这些情况下,它们既是开源的,也是商业的。

列式数据库

列式数据库自 90 年代以来就存在,但在谷歌 Bigtable 发布后变得更加突出。它们本质上是一种存储数据的方法,可以以相对于基于行/元组的存储方式更快速和高效地查询非常大量的数据。

列式数据库的好处,或者更具体地说,独立存储每列数据,可以通过一个简单的例子来说明。

考虑一个包含 1 亿个家庭地址和电话号码的表。同时考虑一个简单的查询,要求用户找到纽约州 Albany 市中 1990 年后建造的家庭数量。我们将创建一个假设的表来说明按行和按列查询数据的差异。

硬件特性

平均磁盘读取速度:每秒 200 MB

数据库特性

表名:housedb

  • 总行数=1 亿

  • 纽约州的总行数=两百万

  • 拥有纽约州 Albany 市的总行数=10,000

  • 拥有纽约州 Albany 市和 YearBuilt > 1990 的总行数= 500

数据大小

假设每行数据的大小如下:

  • PlotNumber,YearBuilt 各= 8 字节=总共 16 字节

  • 所有者,地址,州和城市各= 12 字节=总共 48 字节

  • 每行的净大小(字节)= 16 + 48 = 64 字节

请注意,实际大小将更大,因为还有其他考虑因素,如索引和其他表优化以及相关的开销,出于简单起见,我们不会在这里考虑。

我们还将假设列式数据库维护了一个隐式的行索引,允许在每个列向量中的特定索引处查询数据。

以下表显示了前 4 条记录:

PlotNumber Owner Address State City YearBuilt
1 John 1 Main St. WA Seattle 1995
2 Mary 20 J. Ave. NY Albany 1980
3 Jane 5 45^(th) St. NY Rye Brook 2001
4 John 10 A. Blvd. CT Stamford 2010

总的来说,这张表有 1 亿条记录。最后几条记录如下所示:

PlotNumber Owner Address State City YearBuilt
99999997 Jim 23 B. Lane NC Cary 1995
99999998 Mike 5 L. Street NY Syracuse 1993
99999999 Tim 10 A. Blvd. NY Albany 2001
100000000 Jack 10 A. Blvd. CT Stamford 2010

我们将对这个数据集运行以下查询:

select * from housedb where State like 'NY' and City like 'Albany' and YearBuilt > 1990 

场景 A:逐行搜索

在第一种情况下,如果我们进行天真的逐行搜索,由于每列的数据并未分开存储,而是扫描了每行的数据,我们将不得不查询以下内容:

1 亿 * 64 字节(每行的大小)= 6,400 万字节=大约 6000 MB 的数据

以 200 MBps 的磁盘读取速度来说,这意味着大约需要 6000 / 200 = 30 秒来读取所有记录以找到匹配的条目。

场景 B:逐列搜索

假设数据的每一列都存储在代表各自列的单独文件中,我们将逐个查找每个 where 子句:

select * from housedb where State like 'NY' and City like 'Albany' and YearBuilt > 1990 
  1. Where clause part 1: where State like 'NY'

如前所述,州列有 1 亿条记录,每条记录大小为 12 字节。

在这种情况下,我们只需要搜索以下内容:

1 亿 * 12 字节= 12 亿字节= 1000 MB 的数据。

以 200 MBps 的数据读取速率,这将花费 200 MB,读取列数据将花费 1000 / 200 = 5 秒。

这返回了两百万条记录(如前面所述的数据库特性)

  1. Where clause part 2: City like 'Albany'

在前面的步骤中,我们已经将搜索范围缩小到满足 NY 州条件的两百万条记录。在第二个 where 子句步骤中,现在,我们不需要查询所有 1 亿条记录。相反,我们只需查看满足条件的两百万条记录,以确定哪些属于 Albany 市。

在这种情况下,我们只需要搜索以下内容:

2 百万 * 12 字节= 2400 万字节=大约 20 MB 的数据

以 200 MBps 的数据读取速率,这将花费 0.1 秒。

这返回了 1 万条记录(如前面在数据库特性中提到的)。

  1. Where clause part 3: YearBuilt > 1990

在前面的步骤中,我们进一步将搜索范围缩小到满足 NY 州和 Albany 市两个条件的 1 万条记录。在这一步中,我们将查询 1 万条 YearBuilt 列的记录,以确定哪些满足 YearBuilt > 1990 的条件。

在这种情况下,我们只需要搜索以下内容:

10,000 * 16 字节= 160,000 字节=大约 150 KB 的数据

以 200 MBps 的数据读取速率,这将花费 0.00075 秒,我们可以四舍五入为零秒。

因此,在查询数据时花费的净时间为:

  • Where clause part 1: where State like 'NY' - 五秒

  • Where clause part 2: City like 'Albany' - 0.1 秒

  • Where clause part 3: YearBuilt > 1990 - 零秒

读取数据所花费的净时间= 5.1 秒。

重要提示:实际的读取或更具体地说,扫描性能取决于各种其他因素。元组(行)的大小,重建元组的时间(元组重建),内存带宽(数据从主存储器读入 CPU 的速度等),缓存行大小和其他因素。在实践中,由于各种抽象级别,实际性能可能会较慢。此外,还有其他考虑因素,如硬件架构和并行操作,可以积极或否定地影响整体性能。这些主题更加深入,需要专门阅读。这里的分析专注于磁盘 I/O,这是整体性能的关键方面之一。

前面的示例演示了查询以列存储的数据的好处,从查询性能或效率的角度来看,这取决于数据的大小。列式数据还提供了另一个好处,即它允许以列的形式存储可能具有任意模式的表。

考虑前表的前四行。例如,如果某些行中有缺失信息,那将导致稀疏列:

PlotNumber Owner Address State City YearBuilt
1 John 1 Main St. NULL 西雅图 1995
2 Mary 20 J. Ave. 纽约 NULL NULL
3 Jane NULL 纽约 莱布鲁克 NULL
4 John 10 A. Blvd. 康涅狄格 NULL NULL

我们可以创建一个名为Complete_Address列族,而不是填充 NULL 值,该列族可以包含与仅具有相应数据的字段对应的任意数量的键值对:

PlotNumber Owner Complete_Address YearBuilt
1 John 地址:1 Main St. 城市:西雅图 1995
2 Mary 地址:20 J. Ave. 州:纽约 NULL
3 Jane 州:纽约 城市:莱布鲁克 NULL
4 John 地址:10 A. Blvd. 州:康涅狄格 NULL

列式数据库提供的第三个非常重要的好处是能够根据三个键检索数据:行键、列键和时间戳,这些键可以唯一标识每条记录,从而可以非常快速地访问所需的数据。

例如,由于所有权字段在财产(PlotNumber)出售时可能会更改,因此我们可以添加另一个字段,表示记录的日期;即记录对应的日期。这将允许我们区分在所有其他数据保持不变的情况下发生所有权变更的属性:

PlotNumber Owner Address State City YearBuilt RecordDate
1 John 1 Main St. 华盛顿 西雅图 1995 2001.04.02
2 Mary 20 J. Ave. 纽约 奥尔巴尼 1980 2007.05.30
3 Jane 5 45^(th) St. 纽约 莱布鲁克 2001 2001.10.24
4 John 10 A. Blvd. 康涅狄格 斯坦福 2010 2003.07.20

由于每个 PlotNumber 可以有多条记录以适应所有权的变更,我们现在可以定义三个键,可以唯一标识每条记录中每个数据单元,如下所示:

  • 行键:PlotNumber

  • 列键:列名

  • 时间戳键:RecordDate

表中每条记录中的每个单元格都将具有一个唯一的三值对,用于将其与其他单元格区分开来。

诸如 Bigtable、Cassandra 等数据库采用这种方法,以便迅速高效地进行大规模数据分析。

以下是一些流行的列式数据库。请注意,由于数据库可以具有多个 NoSQL 属性(例如内存和列式),因此可能会有重复:

开源 商业
Apache Parquet Kdb+
MonetDB Teradata
MariaDB SAP HANA
Druid HP Vertica
HBase Oracle Exadata
Apache Kudu ParAccel
Apache Arrow Actian Vector

面向文档的数据库

基于文档或面向文档的数据库作为存储具有可变结构的数据的手段变得突出;也就是说,每条记录不一定总是符合固定模式。此外,文档可能既有结构化部分,也有非结构化部分。

结构化数据本质上是可以以表格格式存储的数据,比如电子表格中的数据。存储在 Excel 电子表格或 MySQL 表中的数据都属于结构化数据集的类别。无法以严格的表格格式表示的数据,比如书籍、音频文件、视频文件或社交网络消息,被视为非结构化数据。因此,在面向文档的数据库中,我们将主要处理结构化和非结构化文本数据。

一个直观的解释是,数据可以包含结构化和非结构化文本,可以在电话日记的例子中找到。尽管随着数字数据存储的增长,这些已经越来越少见,但我们中的许多人可能还记得电话号码写在口袋本上的时候。下面的图片展示了我们如何在电话日记中存储数据:

地址簿(半结构化数据集)

在上面的例子中,以下字段可以被视为结构化的:

  • 姓名

  • 地址

  • 电话和传真

在地址字段下面有一行,用户可以输入任意信息,例如,在 2015 年的一次会议上见面,就职于 ABC 公司。这本质上是日记记录者在输入具体信息时写下的一条注释。由于这样的自由格式字段没有明确定义的特征,它也可能包含第二个电话号码,或者备用地址和其他信息。这将被视为非结构化文本。

此外,由于其他字段之间没有相互依赖,用户可以填写地址但不填写电话号码,或者填写姓名和电话号码但不填写地址。

面向文档的数据库,凭借其存储无模式数据的能力;也就是说,不符合任何固定模式的数据,比如固定列和固定数据类型,因此是存储这些信息的合适平台。

因此,由于电话日记包含的数据量要小得多,在实践中,我们可以以其他格式存储它,但是当我们处理包含结构化和非结构化信息的大规模数据时,面向文档的数据集的必要性就变得明显起来。

以电话日记为例,数据可以以 JSON 格式存储在面向文档的数据集中,如下所示:

( 
 { 
   "name": "John", 
   "address": "1 Main St.", 
   "notes": "Met at conference in 2015", 
   "tel": 2013249978, 
 }, 
 { 
   "name": "Jack", 
   "address": "20 J. Blvd", 
   "notes": "Gym Instructor", 
   "tel": 2054584538, 
   "fax": 3482274573 
 } 
) 

JSON,全称JavaScript Object Notation,提供了一种以可移植的基于文本的键值对格式表示数据的方法。如今,JSON 格式的数据在整个行业中无处不在,并已成为存储没有固定模式的数据的标准。它也是一个很好的交换结构化数据的媒介,因此经常用于这样的数据集。

上述示例提供了一个基本的例子,以传达面向文档的数据库是如何工作的。因此,这是一个非常简单且直观的例子。在实践中,像 MongoDB 和 CouchDB 这样的面向文档的数据库被用来存储吉字节和太字节的信息。

例如,考虑一个网站,它存储用户及其电影偏好的数据。每个用户可能有多部他们观看过的电影,评分过的电影,推荐的电影,他们愿望清单中添加的电影,以及其他类似的物品。在这种情况下,数据集中有各种任意的元素,其中许多是可选的,许多可能包含多个值(例如,用户推荐的多部电影),使用 JSON 格式来捕获信息变得最优。这就是面向文档的数据库提供了一个优越和最佳的平台来存储和交换数据的地方。

更具体地说,诸如 MongoDB 之类的数据库以 BSON 格式存储信息,这是 JSON 文档的二进制版本,具有额外的优化以适应数据类型、Unicode 字符和其他功能,以提高基本 JSON 文档的性能。

更全面的一个存储在 MongoDB 中的 JSON 文档的例子可能是关于航空乘客的数据,其中包含了关于个别乘客的许多属性的信息,例如:

{ 
   "_id" : ObjectId("597cdbb193acc5c362e7ae96"), 
   "firstName" : "Rick", 
   "age" : 66, 
   "frequentFlyer" : ( 
          "Delta" 
   ), 
   "milesEarned" : ( 
          88154 
   ) 
} 
{ 
   "_id" : ObjectId("597cdbb193acc5c362e7ae97"), 
   "firstName" : "Nina", 
   "age" : 53, 
   "frequentFlyer" : ( 
          "Delta", 
          "JetBlue", 
          "Delta" 
   ), 
   "milesEarned" : ( 
          59226, 
          62025, 
          27493 
   ) 
} 

每个条目都由_id字段唯一标识,这使我们能够直接查询与特定用户相关的信息,并在不必查询数百万条记录的情况下检索数据。

如今,面向文档的数据库被用来存储各种各样的数据集。例如包括以下用法:

  • 日志文件和与日志文件相关的信息

  • 文章和其他基于文本的出版物

  • 地理位置数据

  • 用户/用户账户相关信息

  • 许多更适合基于文档/JSON 的存储的用例

知名的面向文档的数据库包括以下内容:

开源 商业
MongoDB Azure Cosmos DB
CouchDB OrientDB
Couchbase Server Marklogic

键值数据库

键值数据库的操作原则是将数据结构化为与键对应的值对。为了突出键值数据库的好处,有必要重新审视哈希映射的重要性,哈希映射是计算机科学中常见的术语,用于指定一种独特的数据结构,为键对提供常数时间查找。

哈希表的一个直观例子如下:

考虑一组 500 本书和五个书架。每个书架有五层。书可以以任意顺序放置,但这将使查找特定书籍变得非常困难,您可能需要在找到所需的书之前浏览数百本书。对书籍进行分类的一种方法是为每个书架分配字母范围,例如 A-E,F-J,K-O,P-T,U-Z,并使用书名的第一个字母将其分配到特定的书架上。然而,假设您有大量以 A-E 字母开头的书。这意味着为 A-E 分配的书架相对于其他书架有更多的书。

一个更优雅的替代方案可能是为每本书分配一个值,并使用相应的值来确定书屋或书架属于哪本书。为了为每本书分配一个数字,我们可以使用书名中每个字母对应的数字之和,分别使用 1-26 的范围来对 A-Z 的字母进行编号:

我们的简单哈希映射

由于我们有五个书架,每个书架有五层,所以我们总共有 25 个书架。将书分配到特定书架的一种方法是取书名中字母的数字值,将其相加并除以 26 得到书的数字值。任何数字除以 25 都会得到 0-25 之间的余数;也就是说,26 个唯一的值。然后我们可以使用这个值来将书分配到特定的书架上。这就成为我们自己创建的哈希函数。

在这 25 个书架中,每个书架现在分配了一个与值 0-25 相对应的数字值,最后一个书架分配了值 24 和 25。例如,书架零被分配用于存储其数字值除以 26 得到零的书籍,书架一被分配用于存储其数字值除以 26 得到一的书籍,书架 25 被分配用于存储其数字值除以 26 得到 24 或 25 的书籍。

一个例子将有助于更具体地说明这个概念。

书名:哈姆雷特

标题的数字值:

哈希值

数字值的总和 = 8 + 1 + 13 + 12 + 5 + 20 = 59

将数字除以 26 = 2,余数为 7

因此,这本书被分配到第七个书架上。

我们基本上找到了一种有条不紊地为每本书分配书架的方法,因为我们有一个固定的规则,所以当新的书籍请求到达时,我们几乎可以立即找到它,因为我们将知道与书籍对应的书架。

上述方法说明了哈希的概念,在实践中,我们将使用一个哈希函数为每本书找到一个唯一的值,假设我们可以获得任意数量的书架和槽,我们可以简单地使用书的纯数值来确定它应该属于哪个书架。

有些情况下,两本书可能具有相同的数值,这种情况下,我们可以将书籍堆叠在相应的槽中。在计算机科学中,多个值对应一个键的这种效果被称为碰撞,在这种情况下,我们将通过列表或类似的数据类型分配多个项目。

在实际应用中,我们要处理的项目比书籍的简单示例要复杂得多。通常,我们会使用更复杂的哈希函数,以降低碰撞的几率,并相应地分配键值对。数据将存储在内存中的连续数组中,因此,当请求某个键时,我们可以通过使用哈希函数来立即找到数据所在的内存位置。

因此,使用键值对存储数据可能非常强大,因为检索与键对应的信息的时间可以非常快,因为无需搜索长列表以识别匹配的键。

键值数据库采用相同的原则为每个记录分配唯一的键,并且与每个键对应的数据存储在相应的位置。在我们讨论 MongoDB 时,我们看到记录被分配了一个特定的键,该键在每个记录中由_id值标识。在实践中,我们可以使用这个值以恒定时间检索相应的数据。

如前所述,memcached 曾经是存储键值对数据的首选方法,用于需要对频繁使用的数据进行非常快速访问的网络服务。实质上,它作为一个内存缓存,用于存储临时信息。随着 NoSQL 数据库的出现,扩展了 memcached 有限用例的新平台变得突出起来。诸如 Redis 之类的解决方案不仅提供了在内存中存储数据的能力,还提供了将数据持久化到磁盘的能力。此外,这些键值存储支持水平扩展,允许将键值对分布在数百个节点上。

键值存储的缺点是,无法像标准数据库那样灵活地查询数据,后者支持多级索引和更丰富的 SQL 命令集。然而,恒定时间查找的好处意味着对于需要键值结构的用例,几乎没有其他解决方案在性能和效率上可以与之媲美。例如,一个拥有成千上万用户的购物网站可以将用户配置文件信息存储在键值数据库中,并能够通过简单应用与用户 ID 相对应的哈希函数来查找个别信息。

如今,键值数据库使用各种方法来存储数据:

  • SSTables:以字符串形式表示的排序键值对文件(直接映射到Google 文件系统GFS))。

  • B-树:平衡树,通过遍历叶子/节点来识别值。

  • 布隆过滤器:当键的数量很大时使用的更优化的键值方法。它使用多个哈希函数将位值设置为数组中对应的键。

  • 分片:涉及将数据分区到多个节点。

众所周知的键值数据库包括:

开源 商业
Redis 亚马逊 DynamoDB
Cassandra Riak
Aerospike Oracle NoSQL
Apache Ignite Azure Cosmos DB
Apache Accumulo Oracle Berkeley DB

图形数据库

图形数据库提供了一种高效的数据表示,其中记录之间存在相互关系。典型的例子包括您的社交网络好友列表、LinkedIn 联系人、Netflix 电影订阅者。通过利用基于树形/图形数据结构的优化算法进行搜索,图形数据库可以以一种新颖的方式定位信息,相对于其他 NoSQL 解决方案。在这样的结构中,离散信息和属性被表示为叶子、边和节点。

下图显示了一个可以查询的网络的非典型表示,可以使用图形数据库发现或查找复杂的相互关系。在实践中,生产图形数据库包含数百万个节点:

图形数据库

尽管它们不像其他类型的 NoSQL 数据库那样普遍,基于图形的平台被用于业务关键领域。例如,信用卡公司使用图形数据库通过查询数百万数据点来评估其他具有类似购买模式的持卡人的购买行为,以发现个体持卡人可能感兴趣的新产品。社交网络网站使用图形数据库来计算相似度分数,提供好友建议和其他相关指标。

知名的图形数据库包括以下:

开源 商业
Apache Giraph Datastax Enterprise Graph
Neo4j Teradata Aster
JanusGraph Oracle Spatial and Graph
Apache Ignite

其他 NoSQL 类型和其他类型的数据库

本节描述了当今使用的一些常见 NoSQL 范式。还有一些新兴平台具有自己的优势和独特特点。这里简要概述了其中一些:

类型 特性
面向对象数据库 这些数据库利用面向对象编程中的概念来存储以对象表示的数据。
云数据库 由云供应商提供的数据库,如亚马逊、微软和谷歌,仅在其各自的云平台上提供,如亚马逊 Redshift、Azure SQL 数据库和谷歌 BigQuery。
GPU 数据库 这是数据库世界中的一个较新的参与者,利用 GPU(图形处理单元)卡来处理数据。例如 MapD、Kinetica 等。
FPGA 加速数据库 随着英特尔即将宣布发布搭载 FPGA 的新芯片,百度等公司已开始开发利用 FPGA 处理能力来提高 SQL 查询性能的 FPGA 加速系统。
流处理/IoT 数据库 优化用于处理来自医疗设备和传感器等流数据的数据库,或更一般的平台。其中最流行的一个例子是 Apache Storm。

经常被问到的一个问题是是否有一个 NoSQL 数据库适用于所有用例。虽然数据库可以具有支持 NoSQL 系统多个元素的多个特性(通常被称为多模数据库),但在实践中,一个能够在广泛的用例集中表现良好的单一解决方案是罕见的。在实际应用中,公司通常实施多个解决方案来满足数据挖掘需求。在下一节中,我们将使用本章讨论的 NoSQL 解决方案完成一些真实数据集的实际练习。

使用 MongoDB 分析诺贝尔奖获得者的数据

在第一个练习中,我们将使用MongoDB,这是一种领先的面向文档的数据库,来分析 1902 年至今的诺贝尔奖获得者。MongoDB 提供了一个简单直观的界面,用于处理 JSON 文件。正如之前讨论的,JSON 是一种灵活的格式,允许使用结构化方法表示数据。

JSON 格式

考虑以下表:

名字 姓氏 信息
约翰 15 主题:历史,等级 B
杰克 18 主题:物理,等级 A
吉尔 17 主题:物理,等级 A+

信息字段包含一个包含在主题和等级下分类的多个值的列。包含多个数据的列也称为包含嵌套数据的列。

可移植性一直是将数据从一个系统转移到另一个系统的重要方面。通常情况下,ODBC 连接器用于在数据库系统之间传输数据。另一种常见的格式是 CSV 文件,其中数据表示为逗号分隔的值。CSV 文件适用于不包含更复杂数据结构(如嵌套值)的结构化数据。在这种情况下,JSON 提供了一种最佳和结构化的方式,使用键值对语法捕获和保留信息。

在 JSON 表示中,表可以定义如下:

( 
   { 
      "Firstname":"John", 
      "Age":15, 
      "Information":{ 
         "Subject":"History", 
         "Grade":"B" 
      } 
   }, 
   { 
      "Firstname":"Jack", 
      "Age":18, 
      "Information":{ 
         "Subject":"Physics", 
         "Grade":"A" 
      } 
   }, 
   { 
      "Firstname":"Jill", 
      "Age":17, 
      "Information":{ 
         "Subject":"Physics", 
         "Grade":"A+" 
      } 
   } 
) 

请注意,信息键包含两个键,主题等级,每个键都有相应的值。

如今,大多数产品开发人员和供应商都能够接受 JSON 格式的数据。此外,由于复杂关系可以以简单的方式在文本格式中表达和交换,JSON 在全球开发者社区中变得非常流行。

MongoDB 以 JSON 格式捕获数据。它在内部以 BSON 的形式存储数据,这是 JSON 数据的优化二进制表示。

安装和使用 MongoDB

MongoDB 支持 Windows、Linux 和 OS X 等所有主要平台。

有关安装 MongoDB 的详细信息可以在官方网站docs.mongodb.com/manual/installation/上找到。请注意,我们将使用 MongoDB 社区版。

对于我们的练习,我们将重复使用我们的 Cloudera Hadoop 分发 VM 中的 Linux CentOS 环境。

然而,这个练习并不依赖于您安装 MongoDB 的平台。安装完成后,您可以在任何其他支持的平台上执行本章中指示的命令。如果您有一个独立的 Linux 机器,您也可以使用它。

我们将讨论 MongoDB 的一些常见语义,并下载两个数据集来计算按大陆分组的诺贝尔奖获得者数量。诺贝尔奖获得者的完整数据转储可从nobelprize.org获取。数据包含所有获奖者的主要属性。我们希望将这些数据与各国的人口统计信息整合,以提取更有趣的分析信息:

  1. 下载 MongoDB:MongoDB 可以从www.mongodb.com/download-center#community下载。

为了确定适用于我们的版本,我们检查了 CDH VM 上安装的 Linux 版本:

(cloudera@quickstart ~)$ lsb_release -a 
LSB Version:     :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch 
Distributor ID:  CentOS 
Description:     CentOS release 6.7 (Final) 
Release:  6.7 
Codename: Final 
  1. 根据信息,我们必须使用 MongoDB 的 CentOS 版本,并根据docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/上的说明安装软件,如下所示:
The first step involved adding the repo as follows. Type in sudo nano /etc/yum.repos.d/mongodb-org-3.4.repo on the command line and enter the text as shown. 

(root@quickstart cloudera)# sudo nano /etc/yum.repos.d/mongodb-org-3.4.repo 

### Type in the information shown below and press CTRL-X 
### When prompted to save buffer, type in yes

(mongodb-org-3.4)
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc

以下截图显示了文件的内容:

设置 MongoDB 仓库

如下截图所示,输入Y表示是:

保存.repo 文件

按照图像所示保存文件如下。这将允许我们安装mongo-db

编写和保存.repo 文件

# Back in terminal, type in the following

(cloudera@quickstart ~)$ sudo yum install -y mongodb-org 

(...) 

Installing: 
 mongodb-org                x86_64         3.4.6-1.el6         mongodb-org-3.4         5.8 k 
Installing for dependencies: 
 mongodb-org-mongos         x86_64         3.4.6-1.el6         mongodb-org-3.4          12 M 
 mongodb-org-server         x86_64         3.4.6-1.el6         mongodb-org-3.4          20 M 
 mongodb-org-shell          x86_64         3.4.6-1.el6         mongodb-org-3.4          11 M 
 mongodb-org-tools          x86_64         3.4.6-1.el6         mongodb-org-3.4          49 M 

Transaction Summary 
===================================================================== 
Install       5 Package(s) 

Total download size: 91 M 
Installed size: 258 M 
Downloading Packages: 
(1/5): mongodb-org-3.4.6-1.el6.x86_64.rpm                             | 5.8 kB     00:00      
(...) 

Installed: 
  mongodb-org.x86_64 0:3.4.6-1.el6                                                            

Dependency Installed: 
  mongodb-org-mongos.x86_64 0:3.4.6-1.el6       mongodb-org-server.x86_64 0:3.4.6-1.el6       
  mongodb-org-shell.x86_64 0:3.4.6-1.el6        mongodb-org-tools.x86_64 0:3.4.6-1.el6        

Complete! 

### Attempting to start mongo without first starting the daemon will produce an error message ### 
### You need to start the mongo daemon before you can use it ### 

(cloudera@quickstart ~)$ mongo MongoDB shell version v3.4.6 
connecting to: mongodb://127.0.0.1:27017 
2017-07-30T10:50:58.708-0700 W NETWORK  (thread1) Failed to connect to 127.0.0.1:27017, in(checking socket for error after poll), reason: Connection refused 
2017-07-30T10:50:58.708-0700 E QUERY    (thread1) Error: couldn't connect to server 127.0.0.1:27017, connection attempt failed : 
connect@src/mongo/shell/mongo.js:237:13 
@(connect):1:6 
exception: connect failed
### The first step is to create the MongoDB dbpath - this is where MongoDB will store all data 

### Create a folder called, mongodata, this will be the mongo dbpath ### 

(cloudera@quickstart ~)$ mkdir mongodata
### Start mongod ### 

(cloudera@quickstart ~)$ mongod --dbpath mongodata 
2017-07-30T10:52:17.200-0700 I CONTROL  (initandlisten) MongoDB starting : pid=16093 port=27017 dbpath=mongodata 64-bit host=quickstart.cloudera 
(...) 
2017-07-30T10:52:17.321-0700 I INDEX    (initandlisten) build index done.  scanned 0 total records. 0 secs 
2017-07-30T10:52:17.321-0700 I COMMAND  (initandlisten) setting featureCompatibilityVersion to 3.4 
2017-07-30T10:52:17.321-0700 I NETWORK  (thread1) waiting for connections on port 27017 

打开一个新的终端,并按照以下截图中所示下载 JSON 数据文件:

从 Mac OS X 的终端应用程序中选择“打开终端”

# Download Files
# laureates.json and country.json ###
# Change directory to go to the mongodata folder that you created earlier 
(cloudera@quickstart ~)$ cd mongodata 

(cloudera@quickstart mongodata)$ curl -o laureates.json "http://api.nobelprize.org/v1/laureate.json" 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100  428k    0  428k    0     0   292k      0 --:--:--  0:00:01 --:--:--  354k 

### Clean the file laureates.json 
### Delete content upto the first ( on the first line of the file 
### Delete the last } character from the file 
### Store the cleansed dataset in a file called laureates.json 

请注意,文件需要稍作修改。代码如下图所示:

修改我们应用程序的.json 文件

(cloudera@quickstart mongodata)$ cat laureates.json | sed 's/^{"laureates"://g' | sed 's/}$//g' > mongofile.json 

### Import the file laureates.json into MongoDB 
### mongoimport is a utility that is used to import data into MongoDB 
### The command below will import data from the file, mongofile.json 
### Into a db named nobel into a collection (i.e., a table) called laureates 

(cloudera@quickstart mongodata)$ mongoimport --jsonArray --db nobel --collection laureates --file mongofile.json 2017-07-30T11:06:35.228-0700   connected to: localhost 
2017-07-30T11:06:35.295-0700   imported 910 documents 

为了将laureate.json中的数据与特定国家的信息相结合,我们需要从geonames.org下载countryInfo.txt。我们现在将下载练习所需的第二个文件country.json。我们将使用laureates.jsoncountry.json进行练习。

### country.json:从www.geonames.org下载(许可证:creativecommons.org/licenses/by/3.0/)。修改 JSON 字符串的开头和结尾,以便导入 MongoDB,如下所示:

# The file country.json contains descriptive information about all countries
# We will use this file for our tutorial

### Download country.json

(cloudera@quickstart mongodata)$ curl -o country.json "https://raw.githubusercontent.com/xbsd/packtbigdata/master/country.json" 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
                                 Dload  Upload   Total   Spent    Left  Speed 
100  113k  100  113k    0     0   360k      0 --:--:-- --:--:-- --:--:--  885k 

### The file, country.json has already been cleaned and can be imported directly into MongoDB 
(cloudera@quickstart mongodata)$ mongoimport --jsonArray --db nobel --collection country --file country.json 2017-07-30T12:10:35.554-0700   connected to: localhost 
2017-07-30T12:10:35.580-0700   imported 250 documents 

### MONGO SHELL ### 
(cloudera@quickstart mongodata)$ mongo MongoDB shell version v3.4.6 
connecting to: mongodb://127.0.0.1:27017 
MongoDB server version: 3.4.6 
Server has startup warnings:  
(...) 

2017-07-30T10:52:17.298-0700 I CONTROL  (initandlisten)  

### Switch to the database nobel using the 'use <databasename>' command 
> use nobel switched to db nobel 

### Show all collections (i.e., tables) 
### This will show the tables that we imported into MongoDB - country and laureates
> show collections country 
laureates 
>  

### Collections in MongoDB are the equivalent to tables in SQL 

### 1\. Common Operations 

### View collection statistics using db.<dbname>.stats() 
> db.laureates.stats() 

   "ns" : "nobel.laureates", # Name Space 
   "size" : 484053,          # Size in Bytes 
   "count" : 910,            # Number of Records 
   "avgObjSize" : 531,       # Average Object Size 
   "storageSize" : 225280,   # Data size 

# Check space used (in bytes) 
> db.laureates.storageSize() 225280 

# Check number of records
> db.laureates.count() 910 

### 2\. View data from collection 
### 
### There is an extensive list of commands that can be used in MongoDB. As such discussing them all is outside the scope of the text. However, a few of the familiar commands have been given below as a marker to help the reader get started with the platform. 

### See first record for laureates using findOne() 
### findOne() will show the first record in the collection 
> db.laureates.findOne() 

{ 
   "_id" : ObjectId("597e202bcd8724f48de485d4"), 
   "id" : "1", 
   "firstname" : "Wilhelm Conrad", 
   "surname" : "Röntgen", 
   "born" : "1845-03-27", 
   "died" : "1923-02-10", 
   "bornCountry" : "Prussia (now Germany)", 
   "bornCountryCode" : "DE", 
   "bornCity" : "Lennep (now Remscheid)", 
   "diedCountry" : "Germany", 
   "diedCountryCode" : "DE", 
   "diedCity" : "Munich", 
   "gender" : "male", 
   "prizes" : ( 
          { 
                 "year" : "1901", 
                 "category" : "physics", 
                 "share" : "1", 
                 "motivation" : "\"in recognition of the extraordinary services he has rendered by the discovery of the remarkable rays subsequently named after him\"", 
                 "affiliations" : ( 
                        { 
                               "name" : "Munich University", 
                               "city" : "Munich", 
                               "country" : "Germany" 
                        } 
                 ) 
          } 
   ) 
} 

### See all records for laureates
> db.laureates.find() 

{ "_id" : ObjectId("597e202bcd8724f48de485d4"), "id" : "1", "firstname" : "Wilhelm Conrad", "surname" : "Röntgen", "born" : "1845-03-27", "died" : "1923-02-10", "bornCountry" : "Prussia (now Germany)", "bornCountryCode" : "DE", "bornCity" : "Lennep (now Remscheid)" 
(...) 

... 

### MongoDB functions accept JSON formatted strings as parameters to options 
### Some examples are shown below for reference 

### Query a field - Find all Nobel Laureates who were male 
> db.laureates.find({"gender":"male"}) 
(...) 
{ "_id" : ObjectId("597e202bcd8724f48de485d5"), "id" : "2", "firstname" : "Hendrik Antoon", "surname" : "Lorentz", "born" : "1853-07-18", "died" : "1928-02-04", "bornCountry" : "the Netherlands", "bornCountryCode" : "NL", "bornCity" : "Arnhem", "diedCountry" : "the Netherlands", "diedCountryCode" : "NL", "gender" : "male", "prizes" : ( { "year" : "1902", "category" : "physics", "share" : "2", "motivation" : "\"in recognition of the extraordinary service they rendered by their researches into the influence of magnetism upon radiation phenomena\"", "affiliations" : ( { "name" : "Leiden University", "city" : "Leiden", "country" : "the Netherlands" } ) } ) } 
(...) 

查询一个字段 - 查找所有在美国出生并获得诺贝尔物理学奖的诺贝尔奖获得者。请注意,这里有一个嵌套字段(如所示,类别在奖项下)。因此,我们将使用点表示法,如下图所示。

说明category,一个嵌套字段的图像:

嵌套的 JSON 字段

> db.laureates.find({"bornCountryCode":"US", "prizes.category":"physics", "bornCity": /Chicago/}) 

{ "_id" : ObjectId("597e202bcd8724f48de48638"), "id" : "103", "firstname" : "Ben Roy", "surname" : "Mottelson", "born" : "1926-07-09", "died" : "0000-00-00", "bornCountry" : "USA", "bornCountryCode" : "US", "bornCity" : "Chicago, IL", 
... 

### Check number of distinct prize categories using distinct 
> db.laureates.distinct("prizes.category") ( 
   "physics", 
   "chemistry", 
   "peace", 
   "medicine", 
   "literature", 
   "economics" 
) 

### Using Comparison Operators 
### MongoDB allows users to chain multiple comparison operators
### Details on MongoDB operators can be found at: https://docs.mongodb.com/manual/reference/operator/ 

# Find Nobel Laureates born in either India or Egypt using the $in operator
> db.laureates.find ( { bornCountryCode: { $in: ("IN","EG") } } ) 

{ "_id" : ObjectId("597e202bcd8724f48de485f7"), "id" : "37", "firstname" : "Sir Chandrasekhara Venkata", "surname" : "Raman", "born" : "1888-11-07", "died" : "1970-11-21", "bornCountry" : "India", "bornCountryCode" : "IN", "bornCity" : "Tiruchirappalli", "diedCountry" : "India", "diedCountryCode" : "IN", "diedCity" : "Bangalore", "gender" : "male", "prizes" : ( { "year" : "1930", "category" : "physics", "share" : "1", "motivation" : "\"for his work on the scattering of light and for the discovery of the effect named after him\"", "affiliations" : ( { "name" : "Calcutta University", "city" : "Calcutta", "country" : "India" } ) } ) } 
... 

### Using Multiple Comparison Operators 

### Find Nobel laureates who were born in either US or China and won prize in either Physics or Chemistry using the $and and $or operator 
> db.laureates.find( { 
$and : ({ $or : ( { bornCountryCode : "US" }, { bornCountryCode : "CN" } ) },
{ $or : ( { "prizes.category" : "physics" }, { "prizes.category" : "chemistry" }  ) } 
    ) 
} ) 

{ "_id" : ObjectId("597e202bcd8724f48de485ee"), "id" : "28", "firstname" : "Robert Andrews", "surname" : "Millikan", "born" : "1868-03-22", "died" : "1953-12-19", "bornCountry" : "USA", "bornCountryCode" : "US", "bornCity" : "Morrison, IL", "diedCountry" : "USA", "diedCountryCode" : "US", "diedCity" : "San Marino, CA", "gender" : "male", "prizes" : ( { "year" : "1923", "category" : "physics", "share" : "1", "motivation" : "\"for his work on the elementary charge of electricity and on the photoelectric effect\"", "affiliations" : ( { "name" : "California Institute of Technology (Caltech)", "city" : "Pasadena, CA", "country" : "USA" } ) } ) } 
... 

### Performing Aggregations is one of the common operations in MongoDB queries 
### MongoDB allows users to perform pipeline aggregations, map-reduce aggregations and single purpose aggregations 

### Details on MongoDB aggregations can be found at the URL 
### https://docs.mongodb.com/manual/aggregation/ 

### Aggregation Examples 

### Count and aggregate total Nobel laureates by year and sort in descending order 
### Step 1: Use the $group operator to indicate that prize.year will be the grouping variable 
### Step 2: Use the $sum operator (accumulator) to sum each entry under a variable called totalPrizes 
### Step 3: Use the $sort operator to rank totalPrizes 

> db.laureates.aggregate( 
  {$group: {_id: '$prizes.year', totalPrizes: {$sum: 1}}},  
  {$sort: {totalPrizes: -1}} 
); 

{ "_id" : ( "2001" ), "totalPrizes" : 15 } 
{ "_id" : ( "2014" ), "totalPrizes" : 13 } 
{ "_id" : ( "2002" ), "totalPrizes" : 13 } 
{ "_id" : ( "2000" ), "totalPrizes" : 13 } 

(...) 

### To count and aggregate total prizes by country of birth 
> db.laureates.aggregate( 
  {$group: {_id: '$bornCountry', totalPrizes: {$sum: 1}}}, 
  {$sort: {totalPrizes: -1}} 
); 

{ "_id" : "USA", "totalPrizes" : 257 } 
{ "_id" : "United Kingdom", "totalPrizes" : 84 } 
{ "_id" : "Germany", "totalPrizes" : 61 } 
{ "_id" : "France", "totalPrizes" : 51 } 
...

### MongoDB also supports PCRE (Perl-Compatible) Regular Expressions 
### For more information, see https://docs.mongodb.com/manual/reference/operator/query/regex 

### Using Regular Expressions: Find count of nobel laureates by country of birth whose prize was related to 'radiation' (as indicated in the field motivation under prizes) 

> db.laureates.aggregate( 
  {$match : { "prizes.motivation" : /radiation/ }}, 
  {$group: {_id: '$bornCountry', totalPrizes: {$sum: 1}}},  
  {$sort: {totalPrizes: -1}} 
); 

{ "_id" : "USA", "totalPrizes" : 4 } 
{ "_id" : "Germany", "totalPrizes" : 2 } 
{ "_id" : "the Netherlands", "totalPrizes" : 2 } 
{ "_id" : "United Kingdom", "totalPrizes" : 2 } 
{ "_id" : "France", "totalPrizes" : 1 } 
{ "_id" : "Prussia (now Russia)", "totalPrizes" : 1 } 

#### Result: We see that the highest number of prizes (in which radiation was mentioned as a key-word) was the US 

### Interestingly, we can also do joins and other similar operations that allow us to combine the data with other data sources 
### In this case, we'd like to join the data in laureates with the data from country information obtained earlier 
### The collection country contains many interesting fields, but for this exercise, we will show how to find the total number of nobel laureates by continent 

### The Left Join 

### Step 1: Use the $lookup operator to define the from/to fields, collection names and assign the data to a field named countryInfo 

### We can join the field bornCountryCode from laureates with the field countryCode from the collection country 
> db.laureates.aggregate( 
  {$lookup: { from: "country", localField: "bornCountryCode", foreignField: "countryCode", as: "countryInfo" }}) 

{ "_id" : ObjectId("597e202bcd8724f48de485d4"), "id" : "1", "firstname" : "Wilhelm Conrad", "surname" : "Röntgen", "born" : "1845-03-27", "died" : "1923-02-10", "bornCountry" : "Prussia (now Germany)", "bornCountryCode" : "DE", "bornCity" : "Lennep (now (..) "country" : "Germany" } ) } ), "countryInfo" : ( { "_id" : ObjectId("597e2f2bcd8724f48de489aa"), "continent" : "EU", "capital" : "Berlin", "languages" : "de", "geonameId" : 2921044, "south" : 47.2701236047002, ...

### With the data joined, we can now perform combined aggregations 

### Find the number of Nobel laureates by continent 
> db.laureates.aggregate( 
  {$lookup: { from: "country", localField: "bornCountryCode", foreignField: "countryCode", as: "countryInfo" }}, 
  {$group: {_id: '$countryInfo.continent', totalPrizes: {$sum: 1}}}, 
  {$sort: {totalPrizes: -1}} 
); 

... ); 
{ "_id" : ( "EU" ), "totalPrizes" : 478 } 
{ "_id" : ( "NA" ), "totalPrizes" : 285 } 
{ "_id" : ( "AS" ), "totalPrizes" : 67 } 
...
This indicates that Europe has by far the highest number of Nobel Laureates.  

还有许多其他操作可以执行,但前一节的目的是以简单的用例高层次介绍 MongoDB。本章中提供的 URL 包含有关使用 MongoDB 的更深入信息。

行业中还有几种可视化工具用于与 MongoDB 集合中存储的数据进行交互和可视化,使用点对点界面。一个简单但功能强大的工具叫做 MongoDB Compass,可以在www.mongodb.com/download-center?filter=enterprise?jmp=nav#compass.下载。

导航到前面提到的 URL,并下载适合您环境的 Compass 版本:

下载 MongoDB Compass

安装后,您将看到欢迎屏幕。点击“下一步”直到看到主仪表板:

MongoDB Compass 截图

点击“性能”以查看 MongoDB 的当前状态:

MongoDB 性能屏幕

单击左侧边栏上单词旁边的箭头,扩展诺贝尔数据库。您可以单击并拖动条形图的不同部分,并运行临时查询。如果您想要对数据集有一个整体的了解,而不必手动运行所有查询,这非常有用,如下图所示:

在 MongoDB Compass 中查看我们的文件

使用真实世界数据跟踪医生的付款

医生和医院都会收到来自各种外部组织的付款,例如从从事销售代表的制药公司,这些代表不仅教育从业者使用他们的产品,还提供礼物或以其他方式提供支付。理论上,给医生的礼物或付款并不意味着要影响他们的处方行为,制药公司采取谨慎措施来对向医疗保健提供者支付的款项进行核查和平衡。

2010 年,奥巴马总统的标志性平价医疗法案ACA),在民间俗称为奥巴马医改,生效。与 ACA 同时生效的是一项名为阳光法案的单独立法,该法案规定了制药公司和其他组织必须报告以货币价值(直接或间接)支付的物品。尽管过去存在这样的规定,但很少有这样的规定可以公开获取。通过公开提供向所有医生支付的详细付款记录,阳光法案在涉及医疗保健提供者的货币交易中引入了前所未有的透明度。

数据可以在 CMS Open Payments 的网站openpaymentsdata.cms.gov上免费获取。

该网站提供了一个查询数据的接口,但没有任何手段进行大规模数据聚合。例如,如果用户想要找到康涅狄克州的总付款金额,通过默认的基于 Web 的工具运行查询没有简单和容易的方法。提供了提供此功能的 API,但需要一定的熟悉度和技术知识才能有效使用。有第三方产品提供这样的设施,但在大多数情况下它们是昂贵的,并且最终用户无法根据自己的特定需求修改软件。

在本教程中,我们将开发一个快速、高效的基于 Web 的应用程序,用于分析 2016 年向医生支付的数千万条记录。我们将使用 NoSQL 数据库、R 和 RStudio 的组合来创建最终产品 - 基于 Web 的门户,通过该门户最终用户可以实时查询数据库。

我们将使用以下技术来开发应用程序:

对于本教程,我将使用我们为 Hadoop 练习下载的 VM 镜像。这些工具也可以安装在 Windows、Mac 和其他 Linux 机器上。选择 VM 主要是为了提供一个一致的、本地的、与操作系统无关的平台。

安装 kdb+、R 和 RStudio

提供了 Packt Data Science VM 下载,其中包含本章所需的所有必要软件。但是,如果您更喜欢在本地计算机上安装软件,可以在以下部分提供的说明中进行。您可以跳过安装部分,直接进入开发开放支付应用程序部分。

安装 kdb+

kdb+是一个时间序列、内存中的列式数据库,已经在金融行业使用了近 20 年。它是可用于进行大规模数据挖掘的最快数据库平台之一,但由于几乎一直被对冲基金和投资银行专门使用,因此并不像其他 NoSQL 工具那样为人所知。特别是由于其速度和在处理大量数据时的低开销,它被进行高频交易的算法交易台使用。

使用 kdb+,在笔记本电脑上分析数千万甚至数亿条记录相当简单。主要的约束将在硬件层面 - 例如可用于处理数据的内存、磁盘空间和 CPU 的数量。在本教程中,我们将安装可供非商业使用的免费 32 位版本的 kdb+。

kdb+不是开源的,但学术机构可以通过写信至academic@kx.com免费使用 64 位许可证。

kdb+具有某些关键特征,使其非常适合大规模数据分析:

  • 低级实现:数据库是用 C 编写的,因此减少了大多数当代 NoSQL 数据库的性能问题,这些数据库严重依赖于 Java,后者实现了多层抽象以提供处理能力。

  • 架构简单:kdb+数据库的整个二进制文件大小约为 500-600 KB。这只是 MP3 歌曲大小的一小部分,即使在拨号连接上也可以轻松下载

  • MapReduce:该数据库实现了一个内部 MapReduce 过程,允许查询同时在多个核心上执行

  • 无需安装:该数据库不需要系统级别的特权,用户可以在大多数系统上使用他们的用户帐户开始使用 kdb+

  • 企业就绪:该数据库已经使用了近 20 年,是一个非常成熟的产品,用于全球企业环境中分析高频交易数据等应用

  • 接口广泛可用:该数据库具有广泛的接口,可用于诸如 C、C++、C#、Java、R、Python、MATLAB 等语言,以便与现有软件轻松集成

安装 kdb+的步骤如下。请注意,如果您使用 Packt 数据科学 VM,则无需进行额外安装。这些说明主要是为了那些想要全新安装软件的用户提供的。

尽管说明是针对 Linux 的,但对于 Windows 和 Mac 来说,安装过程也非常简单。这些说明主要是针对 Packt 数据科学 VM 的。有关下载 Packt 数据科学 VM 的说明,请参阅第三章,分析工具包

  1. 访问www.kx.com,并从“Connect with us”菜单中点击Download下拉选项。您也可以直接访问位于kx.com/download/的下载页面:

Kx Systems 首页

下载页面如下截图所示:

下载 KDB+

  1. 在下一页上点击下载。

  2. 点击kx.com/download/,同意条款后,您可以选择您需要的下载。如果您使用 VM,请下载Linux-86 版本

  3. 选择“保存文件”以将下载的 ZIP 文件保存在您的下载文件夹中:

KDB+ 32 位许可条款

转到下载文件所在的文件夹,并将 ZIP 文件复制到您的主目录下:

KDB+ Zip 文件下载

对于 Mac 或 Linux 系统,这将是~/文件夹。在 Windows 中,将 ZIP 文件复制到C:\并解压以提取q文件夹。以下说明主要适用于基于 Linux 的系统:

$ cd Downloads/ # cd to the folder where you have downloaded the zip file 

$ unzip linuxx86.zip  
Archive:  linuxx86.zip 
  inflating: q/README.txt             
  inflating: q/l32/q                  
  inflating: q/q.q                    
  inflating: q/q.k                    
  inflating: q/s.k                    
  inflating: q/trade.q                
  inflating: q/sp.q                   

$ mv ~/Downloads/q ~/ 
$ cd ~/q 
$ cd l32 
$ ./q KDB+ 3.5 2017.06.15 Copyright (C) 1993-2017 Kx Systems 
l32/ 1()core 3830MB cloudera quickstart.cloudera 10.0.2.15 NONEXPIRE   

Welcome to kdb+ 32bit edition 
For support please see http://groups.google.com/d/forum/personal-kdbplus 
Tutorials can be found at http://code.kx.com/wiki/Tutorials 
To exit, type \\ 
To remove this startup msg, edit q.q 
q)\\
/NOTE THAT YOU MAY NEED TO INSTALL THE FOLLOWING IF YOU GET AN ERROR MESSAGE STATING THAT THE FILE q CANNOT BE FOUND. IN THAT CASE, INSTALL THE REQUISITE SOFTWARE AS SHOWN BELOW 

$ sudo dpkg --add-architecture i386 
$ sudo apt-get update 
$ sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 

安装 R

应用的前端将使用 R 开发。有三种选项可供安装 R 以完成本教程:

  1. 如果您已经从第三章,分析工具包中安装了 Microsoft R,并且将在本教程中使用您的本地机器,则无需进行进一步安装。

  2. 或者,如果您将使用 Packt 数据科学 Virtualbox VM,则无需进行进一步安装。

  3. 如果您计划从官方 R 网站安装 R,则可以从列在cran.r-project.org/mirrors.html的下载站点(镜像)中下载二进制文件:

安装开源 R

安装 RStudio

我们将使用 RStudio 来构建我们的基于 Web 的应用程序。您可以从网站上下载 RStudio 的二进制文件,也可以从终端安装。RStudio 有两个版本-RStudio 桌面版和 RStudio 服务器版。这两个版本都可以用于构建应用程序。服务器版提供了一个可以供多个用户使用的界面,而桌面版通常在用户的本地机器上使用。

这些说明也出现在第三章,分析工具包中。它们已在此提供供参考。

有两种方法可以完成 R 教程的安装:

  1. 如果您将使用 Packt 数据科学 VM,则无需进行进一步安装。

  2. 如果您将在本教程中使用本地计算机,您可以从www.rstudio.com/products/rstudio/download/#download下载 RStudio 桌面,或者从www.rstudio.com/products/rstudio/download-server/下载 RStudio 服务器(仅适用于 Linux 用户)。

以下说明是为希望从供应商网站下载 RStudio 并进行全新安装的用户提供的:

转到www.rstudio.com的网站,然后点击产品 | RStudio

开源 R Studio 桌面版本

在 RStudio 页面上,点击下载 RStudio 桌面

选择 RStudio 桌面

选择 RStudio 桌面的免费版本:

选择开源 R Studio 桌面

RStudio 适用于 Windows、Mac 和 Linux。

下载适合您系统的可执行文件,然后进行安装:

RStudio 二进制文件(版本)

CMS Open Payments 门户

在这一部分,我们将开始为 CMS Open Payments 开发我们的应用程序。

Packt 数据科学 VM 包含本教程所需的所有软件。要下载 VM,请参考第三章,分析工具包

下载 CMS Open Payments 数据

CMS Open Payments 数据可以直接从 CMS 网站作为基于 Web 的下载获得。我们将使用 Unix wget 实用程序下载数据,但首先我们必须在 CMS 网站上注册,以获得我们自己的 API 密钥:

  1. 转到openpaymentsdata.cms.gov,然后点击页面右上角的登录链接:

CMS OpenPayments 的主页

点击注册

CMS OpenPayments 的注册页面

输入您的信息,然后点击创建我的帐户按钮:

CMS OpenPayments 的注册表格

登录到您的帐户:

登录到 CMS OpenPayments

点击管理下的Packt 开发者应用程序。请注意,这里的“应用程序”是指您可能创建的应用程序,该应用程序将查询 CMS 网站上可用的数据:

创建“应用程序”

为应用程序指定一个名称(示例显示在下图中):

定义一个应用程序

您将收到通知,应用程序令牌已创建:

创建应用程序令牌

系统将生成一个应用程序令牌。复制应用程序令牌

应用程序令牌

  1. 现在,以 packt 用户的身份登录到 Packt 数据科学 VM,并在用您被分配的术语YOURAPPTOKEN替换为以下 shell 命令后执行(它将是一长串字符/数字)。请注意,对于本教程,我们将仅下载一些列并将数据限制为仅医生(另一个选项是医院)。

您可以通过减少命令末尾指定的限制值来减少下载的数据量。在命令中,我们使用了12000000(1200 万),这将允许我们下载代表医生支付的整个 2016 年数据集。例如,如果您只下载了一百万条记录,而不是大约 1100 万到 1200 万条记录,应用程序仍将正常工作。

注意:下面显示了两种方法。一种使用令牌,另一种不使用令牌。应用程序令牌允许用户具有更高的限流限制。更多信息请参阅dev.socrata.com/docs/app-tokens.html

# Replace YOURAPPTOKEN and 12000000 with your API Key and desired record limit respectively

cd /home/packt; 

time wget -O cms2016.csv 'https://openpaymentsdata.cms.gov/resource/vq63-hu5i.csv?$$app_token=YOURAPPTOKEN&$query=select Physician_First_Name as firstName,Physician_Last_Name as lastName,Recipient_City as city,Recipient_State as state,Submitting_Applicable_Manufacturer_or_Applicable_GPO_Name as company,Total_Amount_of_Payment_USDollars as payment,Date_of_Payment as date,Nature_of_Payment_or_Transfer_of_Value as paymentNature,Product_Category_or_Therapeutic_Area_1 as category,Name_of_Drug_or_Biological_or_Device_or_Medical_Supply_1 as product where covered_recipient_type like "Covered Recipient Physician" limit 12000000' 

重要提示:也可以在不使用应用程序令牌的情况下下载文件。但是,应该谨慎使用该方法。可以在以下显示的 URL 中下载文件,而无需使用应用程序令牌:

# Downloading without using APP TOKEN
 wget -O cms2016.csv 'https://openpaymentsdata.cms.gov/resource/vq63-hu5i.csv?$query=select Physician_First_Name as firstName,Physician_Last_Name as lastName,Recipient_City as city,Recipient_State as state,Submitting_Applicable_Manufacturer_or_Applicable_GPO_Name as company,Total_Amount_of_Payment_USDollars as payment,Date_of_Payment as date,Nature_of_Payment_or_Transfer_of_Value as paymentNature,Product_Category_or_Therapeutic_Area_1 as category,Name_of_Drug_or_Biological_or_Device_or_Medical_Supply_1 as product where covered_recipient_type like "Covered Recipient Physician" limit 12000000'

创建 Q 应用程序

本节描述了创建 kdb+/Q 应用程序的过程,从数据库加载数据并创建将作为应用程序后端的脚本开始。

加载数据

使用 ID packt(密码:packt)登录 VM:

登录 Packt VM

# We will start KDB+ - the NoSQL database that we'll use for the tutorial

# Launch the Q Console by typing: 

packt@vagrant:~$ rlwrap ~/q/l32/q -s 4 -p 5001 

KDB+ 3.5 2017.06.15 Copyright (C) 1993-2017 Kx Systems 
l32/ 1()core 3951MB packt vagrant 127.0.1.1 NONEXPIRE 

Welcome to kdb+ 32bit edition 
For support please see http://groups.google.com/d/forum/personal-kdbplus 
Tutorials can be found at http://code.kx.com/wiki/Tutorials 
To exit, type \\ 
To remove this startup msg, edit q.q 
q) 
# Enter the following at the Q console. Explanations for each of the commands have been provided in the comments (using /):/change to the home directory for user packt 
\cd /home/packt/ /Define the schema of the cms table 
d:(`category`city`company`date`firstName`lastName`payment`paymentNature`product`state)!"SSSZSSFSSS"; /Read the headersfrom the cms csv file. These will be our table column names 
 columns:system "head -1 cms2016.csv"; 
columns:`$"," vs ssr(raze columns;"\"";""); /Run Garbage Collection 
.Q.gc(); /Load the cms csv file 
\ts cms2016:(d columns;enlist",")0:`:cms2016.csv; /Add a month column to the data 
\ts cms2016: `month`date xasc update month:`month$date, date:`date$date from cms2016 

.Q.gc(); /Modify character columns to be lower case. The data contains u 
\ts update lower firstName from `cms2016 
\ts update lower lastName from `cms2016 
\ts update lower city from `cms2016 
\ts update lower state from `cms2016 
\ts update lower product from `cms2016 
\ts update lower category from `cms2016 
\ts update lower paymentNature from `cms2016 
\ts update lower company from `cms2016
.Q.gc() 

cms2016:`month`date`firstName`lastName`company`state`city`product`category`payment`paymentNature xcols cms2016 

count cms2016 /11 million /Function to save the data that was read from the CMS csv file
 savedata:{show (string .z.T)," Writing: ",string x;cms::delete month from select from cms2016 where month=x; .Q.dpft(`:cms;x;`date;`cms)} 
/Save the data in monthly partitions in the current folder 
 savedata each 2016.01m +til 12

后端代码

脚本完成后,通过键入\\并按Enter退出 Q 提示。

将以下文本复制到名为cms.q的文件中:

system "p 5001" 

system "l /home/packt/cms" 

/firstCap: Takes a string (sym) input and capitalizes the first letter of each word separated by a blank space 
firstCap:{" " sv {@(x;0;upper)} each (" " vs string x) except enlist ""}
/VARIABLES AND HELPER TABLES 

/alldata: Aggregates data from the primary cms database 
alldata: distinct `company`product xasc update showCompany:`$firstCap each company, showProduct:`$firstCap each product from ungroup select distinct product by company from cms where not null product 

/minDate: First month 
minDate:exec date from select min date from cms where month=min month 

/maxDate: Last month 
maxDate:exec date from select max date from cms where month=max month 

/companyStateCity: Cleans and normalises the company names (capitalisations, etc) 
companyStateCity:select asc upper distinct state, asc `$firstCap each distinct city by company from cms 

/FUNCTIONS 
/getShowProduct: Function to get product list from company name  getShowProduct:{$((`$"Select All") in x;raze exec showProduct from alldata;exec showProduct from alldata where showCompany in x)}
/getShowState: Function to get state list from company name getShowState:{$((`$"Select All") in x;raze exec state from companyStateCity;exec state from companyStateCity where company = exec first company from alldata where showCompany in x)}
/getShowCity: Function to get city list from company name 
getShowCity:{$((`$"Select All") in x;raze exec city from companyStateCity;exec city from companyStateCity where company = exec first company from alldata where showCompany in x)}
/getShowInfo: Generic Function for Product, State and City 
getShowInfo:{y:`$"|" vs y;:asc distinct raze raze $(x~`product;getShowProduct each y;x~`state;getShowState each y;x~`city;getShowCity each y;"")}

/Example: Run this after loading the entire script after removing the comment mark (/) from the beginning 
/getShowInfo(`state;"Abb Con-cise Optical Group Llc|Select All|Abbott Laboratories") 

/Convert encoded URL into a Q dictionary 
decodeJSON:{.j.k .h.uh x} 

/Convert atoms to list 
ensym:{$(0>type x;enlist x;x)}

/Date functions 

withinDates:{enlist (within;`date;"D"$x(`date))} 
withinMonths:{enlist (within;`month;`month$"D"$x(`date))} 
/Helper function to remove null keys 
delNullDict:{kx!x kx:where {not x~0n} each x}
/If showdata=enlist 1, 

/Function to process the data for displaying results only 

getData:{"x is the dictionary from web";d:`$dx:lower delNullDict x; enz:`$delete showData,date,columns from dx; ?(`cms;(withinMonths x),(withinDates x),{(in;x 0;enlist 1_x)} each ((key enz),'value enz);0b;(dc)!dc:ensym `$x`columns)}

/Aggregation Function

aggDict:(`$("Total Payment";"Number of Payments";"Minimum Payment";"Maximum Payment";"Average Payment"))!((sum;`payment);(#:;`i);(min;`payment);(max;`payment);(avg;`payment))
/Function to aggregate the data 
getDataGroups:{(aggDict;x) "x is the dictionary from web";d:`$dx:lower delNullDict x; enz:`$delete showData,date,columns,aggVars,aggData from dx; ?(`cms;(withinMonths x),(withinDates x),{(in;x 0;enlist 1_x)} each ((key enz),'value enz);xv!xv:ensym `$x`aggVars;xa!aggDict xa:ensym `$x`aggData)}(aggDict;)

/Generic Function to create error messages

errtable:{tab:(()Time:enlist `$string .z.Z;Alert:enlist x);(tab;"Missing Fields")}

/Validation for input

initialValidation:{$(0n~x(`company);:errtable `$"Company must be selected";(`aggVars in key x) and ((0=count x(`aggVars)) or 0n~x(`aggData));:errtable `$"Both Metric and Aggregate Data field should be selected when using Aggregate Data option";x)}
/Special Handling for some variables, in this case month specialHandling:{0N!x;$(`month in cols x; update `$string month from x;x)}

/Normalise Columns
columnFix:{(`$firstCap each cols x) xcol x}

/Use comma separator for numeric values
commaFmt: {((x<0)#"-"),(reverse","sv 3 cut reverse string floor a),1_string(a:abs x)mod 1}

/Wrapper for show data and aggregate data options
getRes:{0N!x;.Q.gc();st:.z.t;x:decodeJSON x; if (not x ~ ix:initialValidation x;:ix); res:$(`aggData in key x;getDataGroups x;getData x);res:specialHandling res; res:columnFix res;ccms:count cms; cres:count res; en:.z.t; .Q.gc();:(res;`$(string en),": Processed ",(commaFmt ccms)," records in ",(string en - st)," seconds. Returned result with ",(commaFmt cres)," rows.\n")

创建前端 Web 门户

R Shiny是一个旨在简化基于 Web 的应用程序开发的软件包,自 2012-2013 年左右推出以来一直备受关注。一般来说,R 开发人员往往不太擅长前端开发,因为他们的主要工作领域与统计学或类似学科相关。

随着数据科学作为一种职业和主流活动的普及,创建复杂的基于 Web 的应用程序成为必要手段,以便在动态环境中向最终用户提供结果。

自 2010-2011 年以来,JavaScript 几乎失去了原有的吸引力,却又意外地卷土重来,很快,Web 世界就因发布各种领先的 JavaScript 软件包(如 D3、Angular、Ember 等)而沸腾起来。

但这些主要是由经验丰富的 JavaScript 开发人员使用的,其中很少有人也精通 R。开发一个解决方案,可以帮助弥合 JavaScript 基础应用程序开发和 R 编程之间的差距,成为 R 开发人员展示和与更广泛的受众分享他们的工作的必要性。

R Shiny 开发人员平台

R Shiny 为 R 开发人员引入了一个平台,可以创建基于 JavaScript 的 Web 应用程序,而无需涉及 JavaScript,或者即使精通 JavaScript 也无需涉及。

为了构建我们的应用程序,我们将利用 R Shiny,并创建一个接口来连接我们在前一节中设置的 CMS Open Payments 数据。

如果您正在使用自己的 R 安装(本地),您需要安装一些 R 软件包。请注意,如果您使用的是 Linux 工作站,可能需要安装一些额外的 Linux 软件包。例如,在 Ubuntu Linux 中,您需要安装以下软件包。您可能已经安装了其中一些软件包,如果是这样,您将收到一条消息,指示对应软件包不需要进一步更改:

sudo apt-get install software-properties-common libssl-dev libcurl4-openssl-dev gdebi-core rlwrap 

如果您正在使用 Packt 数据科学 VM,您可以直接进行应用程序开发,因为这些 Linux 软件包已经为您安装好了。

Shiny 应用程序需要一些额外的 R 软件包来提供其所有功能。请注意,R 软件包与前面描述的 Linux 软件包不同。数以千计的 R 软件包为特定学科领域提供专门的功能。对于 Web 应用程序,我们将安装一些 R 软件包,以便利用 Web 应用程序中的一些功能。

以下步骤概述了创建 Web 门户的过程:

  1. 登录到 RStudio。如果您使用 Packt Data Science VM,请转到http://localhost:8787/auth-sign-in。使用用户 ID packt 和密码 packt(与用户 ID 相同)登录。

请注意,如果您已在本地安装了 RStudio,则不会有单独的登录屏幕。该说明纯粹适用于 Packt Data Science VM:

登录到 RStudio 服务器(仅适用于 Packt VM)

如果收到错误消息,说明无法加载该站点,可能是因为端口转发尚未设置。要解决此问题,请进行以下更改:

  1. 在 VirtualBox 中,右键单击 VM 并选择设置。

  2. 点击设置下的网络,并展开高级旁边的箭头:

设置 VM 参数

  1. 点击端口转发并添加规则,将端口 8787 从 VM 转发到主机。必须添加标记为 Packt Rule 的规则,如下所示:

配置端口转发

  1. 登录后,您将看到以下屏幕。这是 RStudio 的界面,您将使用它来完成练习。我们将在后面的章节中更详细地讨论 R 和 RStudio,本节说明了创建基本 Web 应用程序的过程:

RStudio 控制台

  1. 安装必要的 R 包。点击文件|R 脚本并复制并粘贴以下代码。

  2. 然后,点击源以执行以下行:

install.packages(c("shiny","shinydashboard","data.table", 
                   "DT","rjson","jsonlite","shinyjs","devtools")) 

library(devtools) 
devtools::install_github('kxsystems/rkdb', quiet=TRUE) 

通过 RStudio 在 R 中安装所需的包

  1. 点击文件|新建文件|Shiny Web App:

创建新的 RShiny 应用程序

  1. 在“应用程序名称”下键入cmspackt,然后点击“创建”:

为 RShiny 应用程序指定名称

这将在主目录中创建一个cmspackt文件夹,如下所示:

R Shiny 应用程序的 app.R 文件

  1. 将以下代码复制并粘贴到app.R部分中:
# # This is a Shiny web application. You can run the application by clicking # the 'Run App' button above. # # Find out more about building applications with Shiny here: # # http://shiny.rstudio.com/ 

#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#

library(shiny)
library(shinydashboard)
library(data.table)
library(DT)
library(rjson)
library(jsonlite)
library(shinyjs)
library(rkdb)

ui <- dashboardPage (skin="purple", dashboardHeader(title = "CMS Open Payments 2016"),
  dashboardSidebar(
  useShinyjs(),
  sidebarMenu(
  uiOutput("month"),
  uiOutput("company"),
  uiOutput("product"),
  uiOutput("state"),
  uiOutput("city"),
  uiOutput("showData"),
  uiOutput("displayColumns"),
  uiOutput("aggregationColumns"),
  actionButton("queryButton", "View Results")

  )
  ),dashboardBody(
  tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "packt.css")),
  textOutput("stats"),
  dataTableOutput("tableData")
  ),
  title = "CMS Open Payments Data Mining"
)

# Define server logic required to draw a histogram
server <- function(input, output, session) {

  h <- open_connection("localhost","5001")

  minDate <- execute(h,"minDate")
  maxDate <- execute(h,"maxDate")
  startDate <- minDate
  endDate <- startDate + 31

cmsdata <- data.table(dbColumns=c("month","date","firstName","lastName","city","state","company","product","category","payment","paymentNature"), webColumns=c("Month","Date","First Name","Last Name","City","State","Company","Product","Category","Payment","Payment Nature"))

companyData <- execute(h,"exec distinct showCompany from alldata")

gbyVars <- c("Company","Product","State","City","Category","Payment Nature")

PLACEHOLDERLIST <- list(
    placeholder = 'Please select an option below',
    onInitialize = I('function() { this.setValue(""); }')
  )

PLACEHOLDERLIST2 <- list(
    placeholder = 'Select All',
    onInitialize = I('function() { this.setValue(""); }')
  )

output$month <- renderUI({
    dateRangeInput("date", label = 'PAYMENT DATE', start = startDate, end = endDate, min = minDate, max = maxDate)
  })

output$company <- renderUI({
    selectizeInput("company","COMPANY" , companyData, multiple = TRUE,options = PLACEHOLDERLIST)
  })

output$product <- renderUI({
    productQuery <- paste0("getShowInfo(`product;\"",paste(input$company,collapse="|"),"\")")
    productVals <- execute(h,productQuery)
    selectizeInput("product", "DRUG/PRODUCT" , productVals, multiple = TRUE,options = PLACEHOLDERLIST2)
  }) 

output$state <- renderUI({
    stateQuery <- paste0("getShowInfo(`state;\"",paste(input$company,collapse="|"),"\")")
    stateVals <- execute(h,stateQuery)
    selectizeInput("state", "STATE" , stateVals, multiple = TRUE,options = PLACEHOLDERLIST2)
  }) 

output$city <- renderUI({
    cityQuery <- paste0("getShowInfo(`city;\"",paste(input$company,collapse="|"),"\")")
    cityVals <- execute(h,cityQuery)
    selectizeInput("city", "CITY" , cityVals, multiple = TRUE,options = PLACEHOLDERLIST2)
  })

output$showData <- renderUI({
    selectInput("showData", label = "DISPLAY TYPE", choices = list("Show Data" = 1, "Aggregate Data" = 2), selected = 1)
  })

output$displayColumns <- renderUI({
    if (is.null(input$showData)) {selectInput("columns", "SHOW DATA",cmsdata$webColumns, selectize = FALSE, multiple = TRUE, size=11)}
    else if(input$showData == 1) {selectInput("columns", "SHOW DATA",cmsdata$webColumns, selectize = FALSE, multiple = TRUE, size=11) } 
    else if(input$showData == 2) {selectInput("aggVars", "AGGREGATE DATA",gbyVars, selectize = FALSE, multiple = TRUE, size=6) }
  }) 

output$aggregationColumns <- renderUI ({ conditionalPanel(
    condition = "input.showData != 1",
    selectInput("aggData", "CALCULATE METRICS" , c("Total Payment","Number of Payments","Minimum Payment","Maximum Payment","Average Payment"), selectize = TRUE, multiple = TRUE)
  )})

getTableData <- eventReactive(input$queryButton, {
    disable("queryButton")
    queryInfo <- (list(date=as.character(input$date),company=input$company, product=input$product, state=input$state, city=input$city,columns=cmsdata$dbColumns(cmsdata$webColumns %in% input$columns),showData=input$showData))
    if (input$showData !=1) {queryInfo <- c(queryInfo, list(aggVars=cmsdata$dbColumns(cmsdata$webColumns %in% input$aggVars), aggData=input$aggData))} else {queryInfo <- c(queryInfo)}
    JSON <- rjson::toJSON(queryInfo)
    getQuery <- paste0("getRes \"",URLencode(JSON),"\"")
    finalResults <- execute(h,getQuery)
    enable("queryButton")
    print (finalResults)
    fres <<- finalResults
    print (class(finalResults((1))))
    print (finalResults)
    finalResults
  })

 output$tableData <- renderDataTable({ datatable(getTableData()((1)))})
 output$stats <- renderText({(getTableData())((2))})

}

# Run the application 
shinyApp(ui = ui, server = server)
  1. 点击右下角的新文件夹:

创建 CSS 文件夹

  1. 将新文件夹重命名为cmspackt/www,如下所示:

为文件夹指定名称

  1. 点击文件|新建文件|文本文件:

创建 CSS 文件

  1. 复制并粘贴以下代码:
.shiny-text-output, .shiny-bount-output { 
  margin: 1px; 
  font-weight: bold; 
} 

.main-header .logo { 
height: 20px; 
font-size: 14px; 
font-weight: bold; 
line-height: 20px; 
} 

.main-header .sidebar-toggle { 
  padding: 0px; 
} 

.main-header .navbar { 
  min-height: 0px !important; 
} 

.left-side, .main-sidebar { 
  padding-top: 15px !important; 
} 

.form-group { 
  margin-bottom: 2px; 
} 

.selectize-input { 
  min-height: 0px !important; 
  padding-top: 1px !important; 
  padding-bottom: 1px !important; 
  padding-left: 12px !important; 
  padding-right: 12px !important; 
} 

.sidebar { 
  height: 99vh;  
  overflow-y: auto; 
} 

section.sidebar .shiny-input-container { 
    padding: 5px 15px 0px 12px; 
} 

.btn { 
  padding: 1px; 
  margin-left: 15px; 
  color:#636363; 
  background-color:#e0f3f8; 
  border-color:#e0f3f8; 
} 

.btn.focus, .btn:focus, .btn:hover { 
  color: #4575b4; 
  background-color:#fff; 
  border-color:#fff; 
} 

pre { 
    display: inline-table; 
    width: 100%; 
    padding: 2px; 
    margin: 0 0 5px; 
    font-size: 12px; 
    line-height: 1.42857143; 
    color: rgb(51, 52, 53); 
    word-break: break-all; 
    word-wrap: break-word; 
    background-color: rgba(10, 9, 9, 0.06); 
    border: 1px rgba(10, 9, 9, 0.06); 
    /* border-radius: 4px */ 
} 

.skin-red .sidebar a { 
    color: #fff; 
} 

.sidebar { 
  color: #e0f3f8; 
  background-color:#4575b4; 
  border-color:#4575b4; 
}
  1. 点击文件|另存为以保存文件,如下所示:

为 CSS 文件选择另存为

  1. 另存为/home/packt/cmspackt/www/packt.css,如下所示:

保存 CSS 文件

您的应用程序现在已准备就绪!

将所有内容放在一起- CMS Open Payments 应用程序

在之前的部分中,我们已经学习了如何:

  • 下载数据集

  • 创建后端数据库

  • 为后端数据库创建代码

  • 设置 RStudio

  • 创建 R Shiny 应用程序

要启动应用程序,请完成以下步骤:

  1. 启动 Q 应用程序,确保您在主目录中。键入 pwd 并按 Enter。这将显示/home/packt的当前工作目录,如下图所示。

  2. 接下来,键入q并按 Enter。

  3. q提示符下,键入\l cms.q

请注意,cms.q是我们在开发 Q 应用程序时在早期部分创建的文件。

脚本将加载数据库并返回到q)提示:

将所有内容放在一起:在 KDB+会话中加载 CMS KDB+ Q 脚本

  1. 启动 CMS Open Payment 应用程序

  2. 在 RStudio 中打开包含 R 代码的app.R文件,并点击右上角的 Run App,如下所示:

运行 RShiny 应用程序

这将启动 Web 应用程序,如下所示:

RShiny 应用程序

我们现在已经完成了开发一个完整的 CMS Open Payments 应用程序,允许最终用户过滤、聚合和分析数据。现在,您可以通过在屏幕上选择各种选项来运行查询。应用程序有两个功能:

  • 过滤数据(默认视图)

  • 聚合数据(您可以通过从显示类型菜单中选择聚合数据切换到此选项)

应用程序

过滤示例:查看某家公司在纽约州为某种药物支付的款项:

使用 RShiny 应用程序

请注意,系统在标题消息中显示处理了 1100 万条记录,用时 21 毫秒。出于隐私原因,屏幕截图中的公司名称和产品名称已被隐藏,但您可以自由尝试不同的选项。

请注意,在默认的虚拟机中,我们只使用了一个内核和非常有限的内存,即使在具有非常有限资源的笔记本电脑上,使用 kdb+处理数据的速度也轻松超过了许多富裕的商业解决方案的性能。

聚合示例:选择聚合数据计算指标字段的选项,以查看按州、支付类别和支付性质分组的总付款额,针对特定公司和产品。请注意,出于隐私原因,屏幕截图中的公司名称和产品名称已被隐藏。

请注意顶部的消息,其中说明:

记录指示查询和应用程序性能

这表明了底层 kdb+数据库处理数据的速度。在这种情况下,它使用给定的选项在 22 毫秒内过滤和聚合了 1100 万条记录。

CMS OpenPayments 应用程序截图

摘要

本章介绍了 NoSQL 的概念。这个术语近年来变得越来越流行,特别是由于它与大数据分析的相关性和直接应用。我们讨论了 NoSQL 中的核心术语、它们的各种类型以及行业中用于这些功能的流行软件。最后,我们通过使用 MongoDB 和 kdb+进行了几个教程。

我们还使用 R 和 R Shiny 构建了一个应用程序,以创建一个动态的 Web 界面,与加载在 kdb+中的数据进行交互。

下一章将介绍当今数据科学中另一个常见的技术,即 Spark。这是另一个工具包,如今赋予全球数据科学家们力量。

第六章:用于大数据分析的 Spark

随着 Hadoop 及其相关技术在各自生态系统中的使用日益突出,Hadoop 操作模型的一些明显和显著的缺陷变得明显。特别是对 MapReduce 范式的根深蒂固的依赖以及与 MapReduce 相关的其他方面,使得 Hadoop 生态系统的真正功能性使用仅对深度投资于相关技术的主要公司可能。

在 2011 年的加州大学伯克利分校电气工程和计算机科学EECS)年度研究研讨会上,Ian Stoica 教授在一次演讲中宣布了该大学一个新的研究小组的愿景(amplab.cs.berkeley.edu/about/)。它奠定了一个将深刻改变大数据格局的关键单位的基础。AMPLab 于 2011 年 2 月成立,旨在通过整合算法、机器和人员提供可扩展和统一的解决方案,以满足未来的需求,而无需进行任何重大的重新设计工作。

从 AMPLab 计划发展出来的最著名和最广泛使用的项目是 Spark,可以说是 Hadoop 生态系统的一个更优秀的替代方案,或者更准确地说是扩展

在本章中,我们将介绍 Spark 的一些显著特点,并以一个真实世界的教程结束,介绍如何使用 Spark。我们将涵盖的主题包括:

  • Spark 的出现

  • Spark 中的理论概念

  • Spark 的核心组件

  • Spark 架构

  • Spark 解决方案

  • Spark 教程

Spark 的出现

当 Spark 的第一个版本于 2014 年发布时,自 2009 年以来,Hadoop 在商业领域已经经历了数年的增长。尽管 Hadoop 解决了高效分析大规模数据集的主要障碍,使用广泛可访问的分布式计算方法,但仍存在阻碍其更广泛接受的缺陷。

Hadoop 的限制

Hadoop 的一些常见限制如下:

  • I/O 绑定操作:由于依赖本地磁盘存储来保存和检索数据,Hadoop 中执行的任何操作都会产生 I/O 开销。在涉及数千个数据块跨越数百台服务器的大型数据集的情况下,问题变得更加严重。公平地说,通过 HDFS 协调并发 I/O 操作的能力构成了 Hadoop 世界中分布式计算的基础。然而,有效地利用这种能力并在不同的用例和数据集中调整 Hadoop 集群需要极大且可能是不成比例的专业知识水平。因此,工作负载的 I/O 绑定特性成为使用 Hadoop 处理极大数据集的阻碍因素。例如,需要数百次迭代操作的机器学习用例意味着系统会在每次迭代中产生 I/O 开销。

  • MapReduce 编程(MR)模型:正如本书前面部分所讨论的,Hadoop 中的所有操作都需要用 MapReduce 编程模型来表达问题,即用户必须以每对键值独立计算的方式来表达问题。在 Hadoop 中,编写高效的 MapReduce 程序,特别是对于那些对 Java 或 Hadoop(或两者)都不熟悉的人来说,是非常困难的。

  • 非 MR 使用案例:由于依赖 MapReduce,其他更常见和更简单的概念,如过滤器、连接等,也必须以 MapReduce 程序的形式表达。因此,跨主键在两个文件之间进行连接必须采用键值对方法。这意味着简单和复杂的操作都很难在没有重大编程工作的情况下实现。

  • 编程 API:在 Hadoop 中将 Java 作为中心编程语言的使用意味着,为了能够正确地管理和使用 Hadoop,开发人员必须对 Java 和相关主题(如 JVM 调优、垃圾收集等)有很强的了解。这也意味着,其他流行语言(如 R、Python 和 Scala)的开发人员几乎没有办法重用或至少在他们最擅长的语言中实现他们的解决方案。

  • 总的来说,尽管 Hadoop 世界曾经领导了大数据革命,但它未能使大数据技术在广泛范围内得到民主化使用。

AMPLab 团队早早意识到了这些缺点,并着手创建 Spark 来解决这些问题,并希望开发一种新的、更优越的替代方案。

克服 Hadoop 的局限性

现在我们将看一下前一节讨论的一些限制,并了解 Spark 如何通过这些方面来解决这些问题,从而提供了 Hadoop 生态系统的一个更优越的替代方案。

首先要牢记的一个关键区别是,Spark 不需要 Hadoop 才能运行。事实上,Spark 访问数据的底层后端可以是诸如 HBase、Hive 和 Cassandra 以及 HDFS 等技术。

这意味着希望利用独立的 Spark 系统的组织可以在没有已有的 Hadoop 基础设施的情况下这样做。

Spark 的解决方案如下:

  • I/O 绑定操作:与 Hadoop 不同,Spark 可以存储和访问存储在内存中的数据,即 RAM - 正如前面讨论的,这比从磁盘读取数据快 1000 多倍。随着 SSD 驱动器的出现,成为当今企业系统的标准,差异已经显著减少。最近的 NVMe 驱动器可以提供每秒 3-5GB(千兆字节)的带宽。然而,RAM 的读取速度平均约为 25-30GB 每秒,仍然比从较新的存储技术中读取快 5-10 倍。因此,能够将数据存储在 RAM 中,可以使 Spark 操作读取数据的时间提高 5 倍或更多。这是对依赖于磁盘读取所有操作的 Hadoop 操作模型的显著改进。特别是,涉及迭代操作的任务,如机器学习,受益于 Spark 能够存储和从内存中读取数据的功能。

  • MapReduce 编程(MR)模型:虽然 MapReduce 是用户可以从 Hadoop 平台中受益的主要编程模型,但 Spark 并没有相同的要求。这对于更复杂的用例特别有帮助,比如涉及无法轻松并行化的计算的定量分析,比如机器学习算法。通过将编程模型与平台解耦,Spark 允许用户编写和执行用各种语言编写的代码,而不强制任何特定的编程模型作为先决条件。

  • 非 MR 用例:Spark SQL、Spark Streaming 和 Spark 生态系统的其他组件提供了丰富的功能,允许用户执行常见任务,如 SQL 连接、聚合和相关的类似数据库的操作,而无需利用其他外部解决方案。Spark SQL 查询通常针对存储在 Hive 中的数据(JSON 是另一个选项)执行,并且该功能也可用于其他 Spark API,如 R 和 Python。

  • 编程 API:Spark 中最常用的 API 是 Python、Scala 和 Java。对于 R 程序员,还有一个名为SparkR的单独包,允许直接从 R 访问 Spark 数据。这是 Hadoop 和 Spark 之间的一个主要区别,通过在这些语言中公开 API,Spark 立即对更大的开发者社区可用。在数据科学和分析中,Python 和 R 是最突出的选择语言,因此,任何 Python 或 R 程序员都可以利用 Spark,相对于 Hadoop,学习曲线更简单。此外,Spark 还包括一个用于临时分析的交互式 shell。

Spark 中的理论概念

以下是 Spark 中的核心概念:

  • 弹性分布式数据集

  • 有向无环图

  • SparkContext

  • Spark DataFrames

  • 操作和转换

  • Spark 部署选项

弹性分布式数据集

弹性分布式数据集,更常被称为RDD,是 Spark 中使用的主要数据结构。RDD 本质上是一个记录的集合,以分布式的方式存储在 Spark 集群中。RDD 是不可变的,也就是说,一旦创建就无法更改。存储在节点上的 RDD 可以并行访问,因此本身支持并行操作。

用户无需编写单独的代码来获得并行化的好处,只需运行特定的命令即可获得与 Spark 平台本身相关的操作和转换的好处。由于 RDD 也可以存储在内存中,作为额外的好处,并行操作可以直接在内存中对数据进行操作,而不会产生昂贵的 I/O 访问惩罚。

有向无环图

在计算机科学和数学术语中,有向无环图表示一对节点(也称为顶点)之间用边(或线)连接的图,这些边是单向的。也就是说,给定节点 A 和节点 B,边可以连接 A 到 B 或 B 到 A,但不能同时连接。换句话说,任何一对节点之间没有循环关系。

Spark 利用 DAG 的概念来构建内部工作流程,以划分 Spark 作业中不同阶段的处理。从概念上讲,这类似于创建一份虚拟流程图,展示了获得特定输出所需的一系列步骤。例如,如果所需的输出涉及在文档中生成单词计数,中间步骤 map-shuffle-reduce 可以表示为一系列导致最终结果的操作。通过维护这样的map,Spark 能够跟踪操作中涉及的依赖关系。更具体地说,RDD 是节点,而稍后在本节中讨论的转换是 DAG 的边缘

SparkContext

SparkContext 是所有 Spark 操作的入口点,也是应用程序连接到 Spark 集群资源的方式。它初始化了一个 Spark 实例,然后可以用于创建 RDD,对 RDD 执行操作和转换,提取数据和其他 Spark 功能。SparkContext 还初始化了进程的各种属性,如应用程序名称、核心数、内存使用参数和其他特性。这些属性集中在 SparkConf 对象中,作为参数传递给 SparkContext。

SparkSession是用户启动与 Spark 连接的新抽象。它是 Spark 2.0.0 之前SparkContext提供的功能的超集。然而,实践者仍然可以互换使用SparkSessionSparkContext来表示同一个实体;即与Spark交互的主要方式。SparkSession本质上结合了SparkContextHiveContext的功能。

Spark DataFrames

在 Spark 中,DataFrame 是组织成行和列的原始数据。这在概念上类似于 CSV 文件或 SQL 表。使用 R、Python 和其他 Spark API,用户可以使用常见的 Spark 命令与 DataFrame 交互,用于过滤、聚合和更一般的数据操作。DataFrame 中包含的数据实际上位于 Spark 集群的多个节点上。然而,通过在DataFrame中表示它们,它们看起来像是一个统一的数据单元,而不暴露底层操作的复杂性。

请注意,DataFrame 和 Dataset 不是 Spark 中常用的术语。Dataset 指的是存储在 Spark 集群中的实际数据。DataFrame 是 Dataset 的表格表示。

从 Spark 2.0 开始,DataFrame 和 Dataset API 被合并,DataFrame 现在本质上代表了一组行的 Dataset。也就是说,DataFrame 仍然是想要利用 Python 和 R 与 Spark 数据交互的用户的主要抽象。

操作和转换

Spark 操作有两种类型:

  • 转换

  • 操作

转换指定一般的数据操作,如过滤数据、连接数据、执行聚合、抽样数据等。当执行代码中包含转换操作的行时,转换不会返回任何结果。相反,命令在执行时会向 Spark 的内部 DAG 添加相应的操作请求。常见的转换示例包括:mapfiltergroupByunioncoalesce等等。

操作,另一方面,返回结果。换句话说,它们执行用户可能在相应的 RDD 上指定的一系列转换(如果有的话),并产生输出。换句话说,操作触发 DAG 中步骤的执行。常见的操作包括:reducecollecttakeaggregateforeach等等。

请注意,RDD 是不可变的。它们不能被改变;转换和操作总是会产生新的 RDD,但永远不会修改现有的 RDD。

Spark 部署选项

Spark 可以以各种模式部署。最重要的是:

  • 独立模式:作为一个独立的集群,不依赖于任何外部集群管理器

  • Amazon EC2:在亚马逊网络服务的 EC2 实例上,可以从 S3 访问数据

  • Apache YARN:Hadoop ResourceManager

其他选项包括Apache MesosKubernetes

更多详细信息可以在 Spark 文档网站找到,spark.apache.org/docs/latest/index.html

Spark API

Spark 平台可以通过 Python、Scala、R 和 Java 中可用的 Spark API 轻松访问。它们一起使得在 Spark 中处理数据变得简单且广泛可访问。在 Spark 项目初始阶段,它只支持 Scala/Java 作为主要 API。然而,由于 Spark 的一个主要目标是为多样化的开发者提供一个简单的接口,Scala API 之后又跟着 Python 和 R API。

在 Python 中,PySpark 包已经成为 Python 开发者社区编写 Spark 应用程序的广泛标准。在 R 中,用户通过 SparkR 包与 Spark 进行交互。这对于可能也对在 Spark 生态系统中存储的数据进行操作的 R 开发者来说是有用的。这两种语言在数据科学社区中非常普遍,因此,引入 Python 和 R API 为分析用例上的大数据分析在 Spark 上的民主化奠定了基础。

Spark 的核心组件

以下组件在 Spark 中非常重要:

  • Spark Core

  • Spark SQL

  • Spark Streaming

  • GraphX

  • MLlib

Spark Core

Spark Core 在 Spark 中提供了基本功能,如使用 RDD、执行操作和转换,以及更多的管理任务,如存储、高可用性和其他主题。

Spark SQL

Spark SQL 为用户提供了使用标准 SQL 命令查询存储在 Apache Hive 中的数据的能力。这通过提供开发人员通过 Spark SQL 接口使用常见的 SQL 术语与数据集交互,增加了额外的可访问性。托管底层数据的平台不仅限于 Apache Hive,还可以包括 JSON、Parquet 等。

Spark Streaming

Spark 的流处理组件允许用户与流数据进行交互,如与网络相关的内容等。它还包括高可用性等企业特性。Spark 可以从各种中间件和数据流服务中读取数据,如 Apache Kafka、Apache Flume 和云服务供应商如亚马逊网络服务。

GraphX

Spark 的 GraphX 组件支持基于图的操作,类似于支持专门数据结构的图数据库技术。这使得使用、访问和表示数据的相互连接点变得容易,如社交网络。除了分析,Spark GraphX 平台还支持图算法,这些算法对于需要在规模上表示关系的业务用例非常有用。例如,信用卡公司使用类似于 Spark 的 GraphX 组件的基于图的数据库来构建检测具有相似特征的用户的推荐引擎。这些特征可能包括购买习惯、位置、人口统计学和其他定性和定量因素。在这些情况下使用图系统允许公司构建网络,其中节点代表个体,边代表关系度量,以找到它们之间的共同特征。

MLlib

MLlib 是 Spark 生态系统的旗舰组件之一。它提供了一个可扩展的、高性能的接口,用于在 Spark 中执行资源密集型的机器学习任务。此外,MLlib 可以原生连接到 HDFS、HBase 和其他在 Spark 中支持的底层存储系统。由于这种多功能性,用户不需要依赖预先存在的 Hadoop 环境来开始使用内置到 MLlib 中的算法。MLlib 中支持的一些算法包括:

  • 分类:逻辑回归

  • 回归:广义线性回归、生存回归等

  • 决策树、随机森林和梯度提升树

  • 推荐:交替最小二乘法

  • 聚类:K 均值、高斯混合和其他

  • 主题建模:潜在狄利克雷分配

  • Apriori:频繁项集、关联规则

ML 工作流程实用程序包括:

  • 特征转换:标准化、归一化等

  • ML Pipeline 构建

  • 模型评估和超参数调整

  • ML 持久性:保存和加载模型和管道

Spark 的架构

Spark 由 3 个主要的架构组件组成:

  • SparkSession/SparkContext

  • 集群管理器

  • 工作节点(托管执行器进程)

SparkSession/SparkContext,或者更一般地说,Spark Driver,是所有 Spark 应用程序的入口点,如前所述。SparkContext 将用于创建 RDD 并对 RDD 执行操作。SparkDriver 发送指令到工作节点以安排任务。

集群管理器在概念上类似于 Hadoop 中的资源管理器,事实上,支持的解决方案之一是 YARN。其他集群管理器包括 Mesos。Spark 也可以在独立模式下运行,在这种情况下不需要 YARN/Mesos。集群管理器协调工作节点之间的通信,管理节点(如启动、停止等),并执行其他管理任务。

工作节点是托管 Spark 应用程序的服务器。每个应用程序都有自己独特的执行器进程,即执行实际操作和转换任务的进程。通过分配专用的执行器进程,Spark 确保任何特定应用程序中的问题不会影响其他应用程序。工作节点由执行器、JVM 和 Spark 应用程序所需的 Python/R/其他应用程序进程组成。请注意,在 Hadoop 的情况下,工作节点和数据节点是一样的:

Spark 解决方案

Spark 直接可从spark.apache.org作为开源解决方案获得。Databricks是 Spark 商业解决方案的领先提供商。对于熟悉 Python、R、Java 或 Scala 编程的人来说,由于高效的接口(如 PySpark API),开始使用 Spark 所需的时间很短。

基于云的 Spark 平台,如 Databricks Community Edition,提供了一种简单易行的方式来使用 Spark,而不需要安装和配置 Spark。因此,希望使用 Spark 进行编程和相关任务的用户可以更快地开始,而不需要花时间在管理任务上。

Spark 实践

在本节中,我们将在 Databricks 的 Community Edition 上创建一个帐户,并完成一个实际操作的练习,引导读者了解操作、转换和 RDD 概念的基础知识。

注册 Databricks Community Edition

以下步骤概述了注册Databricks Community Edition的过程:

  1. 转到databricks.com/try-databricks

  1. 点击立即开始按钮并输入您的信息:

  1. 确认您已阅读并同意弹出菜单中的条款(向下滚动到底部找到同意按钮):

  1. 检查您的电子邮件,确认来自 Databricks 的确认电子邮件,并点击链接确认您的账户:

  1. 点击链接确认您的账户后,您将被带到一个登录界面,在那里您可以使用注册账户时使用的电子邮件地址和密码登录:

  1. 登录后,点击集群设置一个 Spark 集群,如下图所示:

  1. 输入Packt_Exercise作为集群名称,然后点击页面顶部的创建集群按钮:

  1. 这将启动启动一个 Spark 集群的过程,我们将在其中使用 iPython 笔记本执行我们的 Spark 命令。iPython Notebook 是一个常用的 IDE 的名称,它是一个用于编写和测试 Python 代码的基于 Web 的开发应用程序。笔记本还可以通过内核支持其他语言,但在本练习中,我们将专注于 Python 内核。

一段时间后,状态将从待定变为运行:

几分钟后状态变为运行:

  1. 点击工作区(在左侧栏)并选择选项用户 | (您的用户 ID),然后点击您的电子邮件地址旁边的下拉箭头。选择创建 | 笔记本:

  1. 在弹出屏幕中,输入Packt_Exercise作为笔记本的名称,然后点击创建按钮:

  1. 单击创建按钮后,您将直接进入笔记本,如下面的屏幕截图所示。这是 Spark 笔记本,您将能够执行接下来几个部分中给出的其余代码。应在笔记本的单元格中输入代码,如所示。输入代码后,按Shift + Enter执行相应的单元格:

  1. 在接下来的几个练习中,您可以将文本复制粘贴到笔记本的单元格中。或者,您还可以导入笔记本并直接在工作区中加载它。如果这样做,您将不需要输入命令(尽管输入命令将提供更多的实践熟悉度)。

  2. 复制粘贴命令的另一种方法:您可以通过单击以下屏幕截图中显示的导入来导入笔记本:

  1. 在弹出菜单中输入以下URL(选择URL作为选项导入):

  1. 然后笔记本将显示在您的电子邮件 ID 下。单击笔记本的名称加载它:

Spark 练习-亲身体验 Spark(Databricks)

本笔记本是基于 Databricks 进行的教程(databricks.com/)。该教程将使用 Databricks 的 Spark 社区版进行,可在databricks.com/try-databricks注册。Databricks 是 Spark 的商业和企业支持版本的领先提供商。

在本教程中,我们将介绍一些在 Spark 中使用的基本命令。鼓励用户尝试更广泛的 Spark 教程和笔记本,这些教程和笔记本可以在网络上找到更详细的示例。

Spark 的 Python API 文档可以在spark.apache.org/docs/latest/api/python/pyspark.html#pyspark.sql找到。

本书的数据已导入 Databricks 的 Spark 平台。有关导入数据的更多信息,请转到导入数据 - Databricks (docs.databricks.com/user-guide/importing-data.html)。

# COMMAND ----------

# The SparkContext/SparkSession is the entry point for all Spark operations
# sc = the SparkContext = the execution environment of Spark, only 1 per JVM
# Note that SparkSession is now the entry point (from Spark v2.0)
# This tutorial uses SparkContext (was used prior to Spark 2.0)

from pyspark import SparkContext
# sc = SparkContext(appName = "some_application_name") # You'd normally run this, but in this case, it has already been created in the Databricks' environment

# COMMAND ----------

quote = "To be, or not to be, that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take Arms against a Sea of troubles, And by opposing end them: to die, to sleep No more; and by a sleep, to say we end the heart-ache, and the thousand natural shocks that Flesh is heir to? 'Tis a consummation devoutly to be wished. To die, to sleep, To sleep, perchance to Dream; aye, there's the rub, for in that sleep of death, what dreams may come, when we have shuffled off this mortal coil, must give us pause."

# COMMAND ----------
sparkdata = sc.parallelize(quote.split(' '))

# COMMAND ----------
print "sparkdata = ", sparkdata
print "sparkdata.collect = ", sparkdata.collect
print "sparkdata.collect() = ", sparkdata.collect()[1:10]

# COMMAND ----------
# A simple transformation - map
def mapword(word):
 return (word,1)

print sparkdata.map(mapword) # Nothing has happened here
print sparkdata.map(mapword).collect()[1:10] # collect causes the DAG to execute

# COMMAND ----------
# Another Transformation

def charsmorethan2(tuple1):
 if len(tuple1[0])>2:
 return tuple1
 pass

rdd3 = sparkdata.map(mapword).filter(lambda x: charsmorethan2(x))
# Multiple Transformations in 1 statement, nothing is happening yet
rdd3.collect()[1:10] 
# The DAG gets executed. Note that since we didn't remove punctuation marks ... 'be,', etc are also included

# COMMAND ----------
# With Tables, a general example
cms = sc.parallelize([[1,"Dr. A",12.50,"Yale"],[2,"Dr. B",5.10,"Duke"],[3,"Dr. C",200.34,"Mt. Sinai"],[4,"Dr. D",5.67,"Duke"],[1,"Dr. E",52.50,"Yale"]])

# COMMAND ----------
def findPayment(data):
 return data[2]

print "Payments = ", cms.map(findPayment).collect()
print "Mean = ", cms.map(findPayment).mean() # Mean is an action

# COMMAND ----------
# Creating a DataFrame (familiar to Python programmers)

cms_df = sqlContext.createDataFrame(cms, ["ID","Name","Payment","Hosp"])
print cms_df.show()
print cms_df.groupby('Hosp').agg(func.avg('Payment'), func.max('Payment'),func.min('Payment'))
print cms_df.groupby('Hosp').agg(func.avg('Payment'), func.max('Payment'),func.min('Payment')).collect()
print
print "Converting to a Pandas DataFrame"
print "--------------------------------"
pd_df = cms_df.groupby('Hosp').agg(func.avg('Payment'), func.max('Payment'),func.min('Payment')).toPandas()
print type(pd_df)
print
print pd_df

# COMMAND ----------
wordsList = ['to','be','or','not','to','be']
wordsRDD = sc.parallelize(wordsList, 3) # Splits into 2 groups
# Print out the type of wordsRDD
print type(wordsRDD)

# COMMAND ----------
# Glom coallesces all elements within each partition into a list
print wordsRDD.glom().take(2) # Take is an action, here we are 'take'-ing the first 2 elements of the wordsRDD
print wordsRDD.glom().collect() # Collect

# COMMAND ----------
# An example with changing the case of words
# One way of completing the function
def makeUpperCase(word):
 return word.upper()

print makeUpperCase('cat')

# COMMAND ----------
upperRDD = wordsRDD.map(makeUpperCase)
print upperRDD.collect()

# COMMAND ----------
upperLambdaRDD = wordsRDD.map(lambda word: word.upper())
print upperLambdaRDD.collect()

# COMMAND ----------

# Pair RDDs
wordPairs = wordsRDD.map(lambda word: (word, 1))
print wordPairs.collect()

# COMMAND ----------

# #### Part 2: Counting with pair RDDs 
# There are multiple ways of performing group-by operations in Spark
# One such method is groupByKey()
# 
# ** Using groupByKey() **
# 
# This method creates a key-value pair whereby each key (in this case word) is assigned a value of 1 for our wordcount operation. It then combines all keys into a single list. This can be quite memory intensive, especially if the dataset is large.

# COMMAND ----------
# Using groupByKey
wordsGrouped = wordPairs.groupByKey()
for key, value in wordsGrouped.collect():
 print '{0}: {1}'.format(key, list(value))

# COMMAND ----------
# Summation of the key values (to get the word count)
wordCountsGrouped = wordsGrouped.map(lambda (k,v): (k, sum(v)))
print wordCountsGrouped.collect()

# COMMAND ----------

# ** (2c) Counting using reduceByKey **
# 
# reduceByKey creates a new pair RDD. It then iteratively applies a function first to each key (i.e., within the key values) and then across all the keys, i.e., in other words it applies the given function iteratively.

# COMMAND ----------

wordCounts = wordPairs.reduceByKey(lambda a,b: a+b)
print wordCounts.collect()

# COMMAND ----------
# %md
# ** Combining all of the above into a single statement **

# COMMAND ----------

wordCountsCollected = (wordsRDD
 .map(lambda word: (word, 1))
 .reduceByKey(lambda a,b: a+b)
 .collect())
print wordCountsCollected

# COMMAND ----------

# %md
# 
# This tutorial has provided a basic overview of Spark and introduced the Databricks community edition where users can upload and execute their own Spark notebooks. There are various in-depth tutorials on the web and also at Databricks on Spark and users are encouraged to peruse them if interested in learning further about Spark.

总结

在本章中,我们了解了 Spark 的一些核心特性,这是当今大数据领域中最突出的技术之一。自 2014 年发布以来,Spark 已迅速成熟,当时它作为一个大数据解决方案发布,缓解了 Hadoop 的许多缺点,如 I/O 争用等。

如今,Spark 有几个组件,包括专门用于流式分析和机器学习的组件,并且正在积极开发中。Databricks 是 Spark 商业支持版本的领先提供商,还托管了一个非常方便的基于云的 Spark 环境,用户可以免费访问有限资源。这大大降低了用户的准入门槛,因为用户无需安装完整的 Spark 环境来学习和使用该平台。

在下一章中,我们将开始讨论机器学习。直到这一部分,大部分文本都集中在大规模数据的管理上。有效利用数据并从数据中获得洞察力始终是最终目标。为了做到这一点,我们需要采用今天已经变得司空见惯的先进算法技术。下一章将讨论机器学习的基本原则,之后我们将在随后的章节中更深入地探讨这一主题领域。

第七章:机器学习概念简介

机器学习已经成为我们日常生活中司空见惯的话题。该领域的发展如此戏剧性,以至于今天,甚至手机都集成了先进的机器学习和人工智能相关设施,能够根据人类指令做出响应和采取行动。

曾经只限于大学课堂的一个学科,如今已经发展成为一个完全成熟的行业,以一种我们几年前无法想象的方式渗透到我们的日常生活中。

本章的目的是向读者介绍机器学习的基础知识,并以简单明了的术语解释概念,帮助读者熟悉该学科的核心思想。我们将从机器学习的高层概述开始,解释不同的类别以及如何加以区分。我们将解释机器学习中一些显著的概念,如数据预处理、特征工程和变量重要性。下一章将更详细地介绍单个算法和理论机器学习。

我们将通过使用 R 来执行机器学习操作的真实数据集来结束本章。

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

  • 什么是机器学习?

  • 流行的出现

  • 机器学习、统计学和人工智能(AI)

  • 机器学习的类别

  • 机器学习的核心概念

  • 机器学习教程

什么是机器学习?

机器学习并不是一个新的学科;它作为一个正式学科已经存在了 70 多年,但是以不同的名称存在:统计学,更普遍的是数学,然后是人工智能AI),今天是机器学习。虽然统计学和人工智能等其他相关学科同样普遍,但是机器学习已经开辟了一个独立的领域,成为一个独立的学科。

简而言之,机器学习涉及基于历史数据预测未来事件。我们在日常生活中看到它的体现,无论我们是否知情,我们都会每天应用机器学习的原则。

当我们随意评论一部电影是否会在票房上成功,使用我们对主演的人气的理解时,我们正在应用机器学习,尽管是下意识地。我们对主演角色的理解是在多年观看他们出演的电影中形成的。当我们对未来出演同一人的电影的成功做出评估时,我们是在利用历史信息进行评估。

另一个例子是,如果我们有关于温度、湿度和降水(雨)的数据,比如 12 个月的数据,我们能否利用这些信息来预测今天是否会下雨,给定温度和湿度的信息?

这类似于统计学中常见的回归问题。但是,机器学习涉及对练习应用更高级别的严谨性,以便基于不仅仅是理论计算,而且是使用迭代方法进行数百次甚至数千次验证计算后得出结论。

需要在这里指出和澄清的是,术语“机器学习”指的是通常在计算设备上执行的旨在预测结果的算法或程序。这些算法构建数学模型,然后可以用来进行预测。人们普遍错误地认为机器学习实际上是指一个“学习”的“机器”。正如刚才解释的那样,实际含义要逊色得多。

机器学习的演变

机器学习的时间线,如维基百科上所述(en.wikipedia.org/wiki/Timeline_of_machine_learning),提供了该领域演变的简明而富有洞察力的概述。其根源可以追溯到 18 世纪中期,当时托马斯·贝叶斯在伦敦皇家学会上发表了他关于逆概率的论文。逆概率,今天更常被称为概率分布,涉及确定给定一组先前事件的系统状态的问题。例如,如果一个盒子里有牛奶巧克力和白巧克力,你随机拿出几个,得到两块牛奶巧克力和三块白巧克力,我们能推断盒子里有多少块巧克力吗?

换句话说,我们能根据我们可以假设一个正式理论的一些数据点推断出未知的情况吗?贝叶斯的工作被皮埃尔-西蒙·拉普拉斯进一步发展成为贝叶斯定理,收录在他的著作《概率分析理论》中。

在 20 世纪初,安德烈·马尔可夫对普希金的诗《叶甫盖尼·奥涅金》的分析,以确定俄罗斯文学中辅音和元音的押韵,导致了一种称为马尔可夫链的技术的发展,该技术今天用于对涉及随机事件的复杂情况进行建模。谷歌的 PageRank 算法实现了马尔可夫链的一种形式。

机器学习的第一个正式应用,或者更普遍地说,人工智能的最终出现作为一门学科,应归功于艾伦·图灵。他开发了图灵测试——一种确定机器是否足够智能以模仿人类行为的方法。图灵在他的论文《计算机器械与智能》中提出了这一点,论文开头是这样的:

我建议考虑这个问题,“机器能思考吗?”这应该从定义“机器”和“思考”的含义开始。这些定义可能被构造得尽可能反映这些词的正常用法,但这种态度是危险的。如果通过检查它们通常的用法来找到“机器”和“思考”的含义,很难逃脱这样的结论,即问题“机器能思考吗?”的含义和答案应该在统计调查中寻找,比如盖洛普民意调查。但这是荒谬的。我不打算尝试这样的定义,而是用另一个问题来代替它,这个问题与它密切相关,并用相对明确的词语表达。

图灵在论文的后面写道:

“原始问题‘机器能思考吗?’我认为太毫无意义,不值得讨论。尽管如此,我相信在本世纪末,词语的使用和一般受过教育的观点将发生如此大的变化,以至于人们将能够谈论机器思考而不期望遭到反驳。我进一步相信,隐藏这些信念是没有任何有益的目的。”

图灵在人工智能领域的工作之后,机器学习和人工智能出现了一系列重要事件。1951 年,马文·米斯基开发了第一个神经网络,阿瑟·塞缪尔在 1952 年开始了第一个下棋的机器学习程序的工作,罗森布拉特在 1957 年发明了感知器,这是神经网络的基本单元。杰出人物如利奥·布雷曼、杰罗姆·弗里德曼、弗拉迪米尔·瓦普尼克和阿列克谢·切尔沃年基斯、杰夫·辛顿和杨立昆通过 20 世纪 90 年代末做出了重大贡献,使机器学习成为当今独立的研究领域。我们对他们的工作和贡献深表感激,这使得机器学习在当今的研究领域中脱颖而出。

1997 年,IBM 的深蓝击败了卡斯帕罗夫,这立刻成为了全球轰动的事件。一台机器能够击败世界顶级国际象棋冠军并非寻常的成就。这一事件为机器学习赢得了一些急需的可信度,使其成为图灵所设想的智能机器的有力竞争者。

机器学习成功的因素

鉴于机器学习作为一个学科已经存在了几十年,人们不禁要问:为什么它没有比今天更早地变得如此受欢迎?事实上,诸如神经网络之类的复杂机器学习算法的理论在 20 世纪 90 年代晚期就已经广为人知,而在理论领域,基础也早已奠定。

机器学习成功的几个因素:

  • 互联网:网络在民主化信息和以前所未有的方式连接人们方面发挥了关键作用。它使信息交换变得简单,这是通过印刷媒体传播信息的现有方法所无法实现的。网络不仅转变和革新了信息传播,还开辟了新的机会。正如前面提到的,谷歌的 PageRank 是将统计模型应用于开发高度成功的网络企业的最早大规模和高度可见的成功之一。

  • 社交媒体:虽然网络提供了一个交流平台,但缺乏与现实世界中人们互动的灵活性。有一个明显的但低调的、可以说是未被开发的差距。诸如 IRC 和 Usenet 之类的工具是社交网络网站的前身,比如 Myspace,这是最早用于创建个人网络的基于网络的平台之一。到了 21 世纪初至中期,Facebook 成为社交网络的领导者。这些平台提供了一个独特的机会,利用互联网以个人层面收集数据。每个用户留下了一串信息,可以使用自然语言处理和其他技术进行收集和分析。

  • 计算硬件:用于计算机的硬件以指数速度发展。机器学习算法本质上是计算和资源密集型的,也就是说,它们需要强大的 CPU、快速的磁盘和根据数据大小的高内存。在固态硬盘SSD)上存储数据的新方法是从以前的旋转硬盘存储方式中跨越的一大步。更快的访问意味着数据可以以更快的速度传递给 CPU,并减少了传统计算中一直存在的 I/O 瓶颈。更快的 CPU 意味着可以及时执行机器学习算法所需的数百甚至数千次迭代。最后,需求导致了计算资源价格的降低,使更多人能够负担得起原本价格昂贵的计算硬件。算法是存在的,但资源最终能够以合理的时间和成本来执行它们。

  • 编程语言和软件包:R 和 Python 开发者等社区抓住了机会,个人开始发布暴露他们的工作给更广泛的程序员社区的软件包。特别是提供机器学习算法的软件包立即受到欢迎,并激发了其他从业者发布他们的个人代码库,使得 R 等平台成为一个真正的全球协作努力。如今,R 中有超过 10,000 个软件包,而 2010 年只有 2000 个。

机器学习、统计学和人工智能

机器学习是一个有各种同义词的术语——这些名称是企业的营销活动的结果,或者只是可以互换使用的术语。尽管有人可能会争辩它们有不同的含义,但它们最终都指的是机器学习作为一门学科,它利用历史信息来预测未来事件。

机器学习常听到的术语包括预测分析、预测分析、预测建模等等。因此,除非发布材料的实体解释了他们对术语的解释,更具体地说明了它的不同之处,否则可以安全地假设他们是在指机器学习。这往往会让新手感到困惑,主要是由于技术术语的误用和滥用。

另一方面,统计学是一个已经有 200 多年历史的独立学科领域。这个词源自新拉丁语statisticum collegium(英语中的国务院)和意大利语statista,意思是政治家或政治家。您可以访问en.wikipedia.org/wiki/History_of_statistics#Etymology了解更多关于这个主题的详情。机器学习实现了各种统计模型,由于涉及到的计算严谨,它与经典统计学的分支有所不同。

人工智能也与机器学习密切相关,但它是一个更广泛的主题。它可以被宽泛地定义为在存在不确定性的情况下,能够以(通常)负责任和社会意识的方式做出具体决策,以达到目标终极目标的系统(软件/硬件)。换句话说,人工智能旨在通过系统地处理既包括已知又包括未知(潜在)因素的情况来产生行动。

人工智能唤起了智能机器人在科幻电影中的形象,就像它提醒我们智能系统,比如 IBM Watson,可以解析复杂问题并处理模糊陈述以找到具体答案一样。

机器学习与一些相同特征-使用训练数据逐步开发模型,并使用测试数据测量准确性。然而,人工智能已经存在了很多年,并且是一个家喻户晓的术语。美国的卡内基梅隆大学等机构一直在制定人工智能的关键原则和指导方针。

关于人工智能与机器学习的在线资源/文章似乎没有提供任何关于它们之间区别的定论。然而,大学的人工智能课程大纲使这些区别变得非常明显。您可以在cs.brown.edu/courses/csci1410/lectures.html了解更多关于人工智能的信息。

人工智能涉及涉及的广泛研究领域:

  • 受限优化:在给定情况下,达到最佳结果,考虑一组约束或限制

  • 博弈论:例如,零和游戏,均衡等-根据决策如何影响未来决策和影响期望的最终目标来做出权衡决策

  • 不确定性/贝叶斯定理:在先验信息的情况下,发生这种情况的可能性是多少,考虑到已经发生了其他事情

  • 规划:制定行动计划=一组路径(图),以应对情况/达到最终目标

  • 机器学习:通过使用旨在处理不确定性并模仿人类推理的算法来实现(实现)前述目标。通常用于人工智能的机器学习算法包括:

  • 神经网络/深度学习(发现隐藏因素)

  • 自然语言处理(NLP)(使用语气,语言学等理解上下文)

  • 视觉对象识别

  • 概率模型(例如,贝叶斯分类器)

  • 马尔可夫决策过程(例如,随机事件的决策,例如赌博)

  • 各种其他机器学习算法(聚类、支持向量机)

  • 社会学:研究机器学习决策如何影响社会,并采取补救措施纠正问题

机器学习的分类

1959 年,Arthur Samuel 在 IBM 工作时创造了机器学习这个术语。机器学习的一个流行定义归功于 Arthur,据信他称机器学习为一门计算机科学领域,使计算机能够在没有明确编程的情况下学习

1998 年,Tom Mitchell 对机器学习增加了更具体的定义,并称其为一种研究算法的学科,这些算法通过经验 E 在某个任务 T 上提高其性能 P。

一个简单的解释可以帮助说明这个概念。现在,我们大多数人都熟悉电子邮件中的垃圾邮件概念。大多数电子邮件账户也包含一个名为垃圾邮件垃圾或类似术语的单独文件夹。对文件夹的粗略检查通常会显示出许多邮件,其中许多可能是未经请求的并包含无意义的信息。

将电子邮件分类为垃圾邮件并将其移动到文件夹中的简单任务也涉及机器学习的应用。Andrew Ng 在他的流行机器学习 MOOC 课程中优雅地强调了这一点。

在 Mitchell 的术语中,垃圾邮件分类过程涉及:

  • 任务 T:将电子邮件分类为垃圾邮件/非垃圾邮件

  • 性能 P:准确识别为垃圾邮件的数量

  • 经验 E:模型提供了被标记为垃圾邮件/非垃圾邮件的电子邮件,并利用这些信息来确定新邮件是否为垃圾邮件

广义上讲,机器学习有两种明显的类型:

  • 监督式机器学习

  • 无监督式机器学习

我们将在这里依次讨论它们。

监督式和无监督式机器学习

让我们先从监督式机器学习开始。

监督式机器学习

监督式机器学习指的是涉及使用标记数据预测结果的机器学习练习。标记数据简单地指的是我们用来进行预测的数据集(以及我们将要预测的结果)具有明确的值(不管是什么)。例如,将电子邮件分类为垃圾邮件或非垃圾邮件、预测温度和从图像中识别人脸都是监督式机器学习的例子。

车辆里程、数字识别和其他例子

给定一个包含有关每加仑英里数、汽缸数等各种汽车信息的数据集,如果我们只有其他值可用,我们能预测每加仑英里数的值吗?

在这种情况下,我们的结果是mpg,我们使用cyl(汽缸数)、hp(马力)、gear(齿轮数)等其他变量来构建一个模型,然后应用于一个数据集,其中mpg的值标记为MISSING。模型读取数据的前五行中这些列的信息,并根据这些信息预测其他行中mpg的值,如下图所示:

之所以被认为是监督式的是因为在构建我们的机器学习模型的过程中,我们向模型提供了关于结果的信息。其他例子包括:

  • 识别字母和数字:在这种情况下,模型的输入是图像,比如字母和数字的图像,结果是图像上显示的字母数字值。构建模型后,可以用于识别和预测图像中显示的数字。这是一个简单的例子,但非常强大。想象一下,如果你拿到了 10 万张带有门牌号码的房屋图片。手动识别门牌号码的方式是逐个查看每张图片并写下号码。机器学习模型使我们能够完全自动化整个操作。你可以简单地运行模型来识别图像,以极短的时间内获得结果,而不必手动查看每个图像。

  • 自动驾驶汽车:算法的输入是图像,图像中的对象已被识别,例如人、街道标志、汽车、树木、商店和其他元素。一旦展示了足够数量的图像,并且给出了一个未标记的图像,也就是对象尚未被识别的图像,算法就能够识别它们。公平地说,这是对一个非常复杂的主题的高度简化的解释,但总体原则是相同的。

用于数字识别的 MNIST 数据集:

无监督机器学习

无监督机器学习涉及没有标记结果的数据集。以预测汽车的每加仑英里数为例,在无监督练习中,我们的数据集将如下所示:

如果所有的结果都缺失,那么就不可能知道这些值可能是什么。请记住,机器学习的主要前提是利用历史信息对结果未知的数据集进行预测。但是,如果历史信息本身没有任何确定的结果,那么就不可能建立模型。在不知道任何其他信息的情况下,表中的 mpg 值可能全部为 0 或全部为 100;我们无法判断,因为没有任何数据点可以帮助我们得出这个值。

这就是无监督机器学习的应用。在这种类型的机器学习中,我们并不试图预测结果。相反,我们试图确定哪些项目彼此最相似。

这种练习的一个常见名称是聚类,也就是说,我们试图找到彼此最相似的记录的或组。我们可以在哪些地方使用这些信息,无监督学习的一些例子是什么?

网络上有各种新闻聚合器 - 这些网站本身不发布信息,而是从其他新闻来源收集信息。谷歌新闻就是这样的一个聚合器。比如,如果我们要搜索卡西尼号对土星拍摄的最新图像的信息,我们可以在谷歌新闻上简单搜索这个短语news.google.com/news/?gl=US&amp;ned=us&amp;hl=en。这里有一个示例:

请注意,在新闻文章底部有一个“查看全部”的链接。点击该链接将带您到包含所有其他相关新闻文章的页面。当然,谷歌并没有手动将文章分类为特定的搜索词。事实上,谷歌事先并不知道用户会搜索什么。搜索词本来也可能是“太空中土星环的图片”。

那么,谷歌是如何知道哪些文章属于特定的搜索词的呢?答案在于聚类或无监督学习原则的应用。无监督学习检查特定数据集的属性,以确定哪些文章彼此最相似。为了做到这一点,算法甚至不需要知道上下文背景。

假设你拿到了两套没有封面的书,一套是关于园艺的书,另一套是关于计算机编程的书。尽管你可能不知道书的标题,但很容易区分计算机书和园艺书。一套书会有大量与计算机相关的术语,而另一套会有大量与植物相关的术语。仅凭书中的图片就能区分出两种不同的书类别,即使是一个不了解计算机或园艺的读者也不难。

无监督机器学习的其他示例包括检测恶性和非恶性肿瘤以及基因测序。

细分监督机器学习

监督机器学习可以进一步细分为以下练习之一:

  • 分类

  • 回归

这些概念非常简单。

分类涉及具有离散结果的机器学习任务 - 分类结果。所有名词都是分类变量,例如水果、树木、颜色和真/假。

分类练习中的结果变量也被称为离散或分类变量

一些例子包括:

  • 根据大小、重量和形状确定水果

  • 给定一组数字图像的数字(如前一章所示)

  • 识别街道上的物体

  • 识别红心、黑桃、红桃和梅花的扑克牌

  • 根据学生的成绩确定学生的班级排名

  • 最后一个可能看起来不明显,但是排名,即 1(st)、2(nd)、3^(rd)表示一个固定的类别。一个学生可以排名,比如 1^(st)或 2^(nd),但不能有 1.5 的排名!

下面显示了一些非典型的分类示例的图像:

不同类型水果的分类 扑克牌的分类:红心、黑桃、红桃和梅花

回归,另一方面,涉及计算数值结果。您可以执行数值运算的任何结果,例如加法、减法、乘法和除法,都将构成回归问题。

回归的例子包括:

  • 预测每日温度

  • 计算股价

  • 预测住宅物业和其他物业的销售价格

下面显示了一些非典型的回归示例的图像。在这两种情况下,我们处理的是连续的定量数值数据。因此,回归的结果变量也被称为定量或连续变量

计算房价 使用其他市场数据计算股价

请注意,分类或回归的概念并不适用于无监督学习。由于无监督学习中没有标签,因此在严格意义上不存在离散的分类或回归。也就是说,由于无监督学习将数据分类为簇,簇中的对象通常被认为属于同一类(与同一簇中的其他对象相同)。这类似于分类,只是在事后创建,而在对象被分类到各个簇之前并不存在类。

机器学习中的常见术语

在机器学习中,您经常会听到特征、预测变量和因变量这些术语。它们都是一样的。它们都指的是用于预测结果的变量。在我们之前关于汽车的例子中,变量cyl(汽缸)、hp(马力)、wt(重量)和gear(齿轮)是预测变量,而mpg(每加仑英里数)是结果。

简单来说,以电子表格为例,列的名称本质上被称为特征、预测变量和因变量。例如,如果我们获得了一个收费站收费的数据集,并被要求根据一天的时间和其他因素来预测收费金额,一个假设的例子可能如下:

在这个电子表格中,列datetimeagencytypeprepaidrate是特征或预测变量,而列amount是我们的结果或因变量(我们正在预测的内容)。

金额的值取决于其他变量的值(因此被称为自变量)。

简单的方程也反映了明显的区别,例如,在一个方程中,y = a + b + c左手边LHS)是因变量/结果变量,abc是特征/预测变量。

总之:

机器学习的核心概念

机器学习中有许多重要的概念;我们将介绍一些更常见的主题。机器学习涉及一个多步骤的过程,从数据获取、数据挖掘,最终到构建预测模型。

模型构建过程的关键方面包括:

  • 数据预处理:预处理和特征选择(例如,居中和缩放,类别不平衡和变量重要性)

  • 训练,测试分割和交叉验证

  • 创建训练集(比如说,数据的 80%)

  • 创建测试集(数据的大约 20%)

  • 执行交叉验证

  • 创建模型,获取预测

  • 你应该尝试哪些算法?

  • 你试图优化哪些准确性指标?

  • 你应该使用哪些调整参数?

机器学习中的数据管理步骤

预处理,或者更一般地处理数据,是大多数机器学习练习的一个重要部分。你开始使用的数据集很少会与你构建机器学习模型的确切格式一致;在大多数情况下,它都需要进行相当多的清理。事实上,数据清理通常是整个过程中最耗时的部分。在本节中,我们将简要介绍一些你在实践中可能遇到的顶级数据处理步骤。

预处理和特征选择技术

数据预处理,顾名思义,涉及筛选数据,使其适用于机器学习练习。有各种各样的预处理方法,这里列举了一些比较常见的方法。

请注意,数据预处理应该作为交叉验证步骤的一部分进行,也就是说,预处理不应该在事先进行,而应该在模型构建过程中进行。稍后将对此进行更详细的解释。

居中和缩放

对数值列应用中心和缩放函数通常是为了标准化数据并消除数字的数量或差异的影响。你可能在大学课程中遇到过这种情况,学生会按照标准化的方式或曲线进行评分。

例如,假设一张考试试卷异常困难,10 名学生中有一半的学生得分低于 60 分 - 这是课程的及格率。教授可以选择 a)决定让 50%的学生重新上课,或者 b)标准化分数以找出学生相对于彼此的表现。

假设班级分数是:

45,66,66,55,55,52,61,64,65,49

以 60 分为及格分数,这意味着得分为 45、55、55、52 和 49 的学生将无法成功完成课程。

然而,这可能并不是他们相对优点的真正准确的表示。教授可以选择使用一种称为标准化的中心和缩放方法,它包括:

  • 找到所有分数的平均值

  • 从分数中减去平均值

  • 将结果除以所有分数的标准差

下面是操作的示例。

分数的平均值是 57.8。因此,从每个数字中减去 57.8 会产生第二行中显示的数字。但是,我们还没有完成。我们需要将这些数字除以分数的标准差,以获得最终的标准化值:

除以SD标准差)表明,在所有测试成绩范围内,只有两名学生的成绩低于一个标准差。因此,根据原始数字,不是五名学生未能成功完成课程,而是只有两名学生。

尽管这是一个真正简单的操作,但不难看出,它在平滑数据的大波动方面非常有效。

在 R 中,可以使用 scale 命令非常容易地进行居中和缩放,如下所示:

> scores <- c(45,66,66,55,55,52,61,64,65,68) 
> scale(scores) 
            [,1] 
 [1,] -1.9412062 
 [2,]  0.8319455 
 [3,]  0.8319455 
 [4,] -0.6206578 
 [5,] -0.6206578 
 [6,] -1.0168223 
 [7,]  0.1716713 
 [8,]  0.5678358 
 [9,]  0.6998907 
[10,]  1.0960552 
attr(,"scaled:center") 
[1] 59.7 
attr(,"scaled:scale") 
[1] 7.572611 

接近零方差函数

nearZeroVar函数在R package, caret中可用于识别具有很少或没有方差的变量。考虑一个具有仅三个不同值的 10,000 个数字集。这样的变量可能对算法几乎没有价值。为了使用nearZeroVar函数,首先在 RStudio 中安装 R 软件包 caret(我们在第三章中设置了The Analytics Toolkit)。使用nearZeroVar的效果的确切代码如下所示:

> library(caret) 
Loading required package: lattice 
Loading required package: ggplot2 
Need help getting started? Try the cookbook for R: http://www.cookbook-r.com/Graphs/ 

> repeated <- c(rep(100,9999),10) # 9999 values are 100 and the last value is 10 

>random<- sample(100,10000,T) # 10,000 random values from 1 - 100 

>data<- data.frame(random = random, repeated = repeated) 

>nearZeroVar(data) 
[1] 2 

> names(data)[nearZeroVar(data)] 
[1] "repeated" 

正如示例所示,该函数能够正确检测到符合标准的变量。

去除相关变量

相关变量可能会产生过分强调变量贡献的结果。在回归练习中,这会增加 R² 的值,并且不准确地代表模型的实际性能。尽管许多类别的机器学习算法对相关变量的影响具有抵抗力,但它值得一提,因为这是该学科中的一个常见主题。

删除这样的变量的前提是冗余变量不会为模型增加增量值。例如,如果数据集包含英寸和米的身高,这些变量的相关性几乎完全为 1,使用其中一个与使用另一个一样好。使用去除相关变量的方法进行实际练习,可以极大地帮助简化模型,特别是涉及我们无法直观判断的变量。

以下示例说明了去除相关变量的过程。数据集Pima Indians Diabetes包含有关 Pima 印第安人饮食的重要统计数据,以及名为diabetes的结果变量。

在接下来的章节示例中,我们将经常提到这个数据集。数据集中不同列的含义的高级概述如下:

pregnant Number of times pregnant 
glucose  Plasma glucose concentration (glucose tolerance test) 
pressure Diastolic blood pressure (mm Hg) 
triceps  Triceps skin fold thickness (mm) 
insulin  2-Hour serum insulin (mu U/ml) 
mass     Body mass index (weight in kg/(height in m)\²) 
pedigree Diabetes pedigree function 
age            Age (years) 
diabetes Class variable (test for diabetes) 

我们有兴趣查找除糖尿病(我们的结果变量)以外的任何相关变量。如果有的话,删除冗余变量可能会有用。

在 RStudio 中安装mlbenchcorrplot软件包,并执行以下命令:

install.packages("mlbench") 
install.packages("corrplot") 

library(corrplot) 
library(mlbench) 
data (PimaIndiansDiabetes)
diab <- PimaIndiansDiabetes # To produce a correlogram 
corrplot(cor(diab[,-ncol(diab)]), method="color", type="upper") # To get the actual numbers 
corrplot(cor(diab[,-ncol(diab)]), method="number", type="upper")

该命令将使用corrplot软件包从www.sthda.com/english/wiki/visualize-correlation-matrix-using-correlogram生成一个图表,如下所示:

>

阴影越深,相关性越高。在这种情况下,它显示年龄和怀孕之间有相对较高的相关性。我们可以使用method="number"找到确切的值。您也可以在www.sthda.com/english/wiki/visualize-correlation-matrix-using-correlogram上查看图表。

我们还可以使用以下函数直接查找相关变量,而无需绘制相关图:

correlated_columns<- findCorrelation(cor(diab[,-ncol(diab)]), cutoff = 0.5) 
correlated_columns 

其他常见的数据转换

还有其他几种数据转换方法适用于不同的情况。这些转换的摘要可以在caret软件包的文档网站的Pre-Processing下找到topepo.github.io/caret/pre-processing.html

在 caret 的预处理函数中提供的选项可以在其帮助部分中找到,通过在 RStudio 中运行命令?preProcess。其代码如下:

Method 

a character vector specifying the type of processing. 

Possible values are "BoxCox", "YeoJohnson", "expoTrans", "center", "scale", "range", "knnImpute", "bagImpute", "medianImpute", "pca", "ica", "spatialSign", "corr", "zv", "nzv", and "conditionalX" (see Details below) 

数据抽样

您可能会遇到具有高度不平衡结果类别的数据集。例如,如果您正在处理一个罕见疾病的数据集,您的结果变量是真或假,由于发生的罕见性,您可能会发现标记为假的观察数量(即,该人没有罕见疾病)远远高于标记为真的观察数量(即,该人患有罕见疾病)。

机器学习算法试图最大化性能,在许多情况下可能是预测的准确性。比如,在 1000 条记录的样本中,只有 10 条被标记为真,其余的990条观察结果都是假的。

如果有人随机将所有观察结果都标记为假,准确率将是:

(990/1000) * 100 = 99% 

但是,这项练习的目标是找到患有罕见疾病的个体。我们已经很清楚,由于疾病的性质,大多数个体不会属于这一类别。

数据抽样本质上是最大化机器学习指标,如特异性、敏感性、精确度、召回率和 kappa的过程。这些将在后面讨论,但在本节的目的上,我们将展示一些方法,通过这些方法,您可以对数据进行抽样,以产生一个更均衡的数据集。

R 软件包caret包括几个有用的函数,用于从不平衡的数据集中创建一个平衡的类别分布。

在这些情况下,我们需要重新对数据进行重新抽样,以获得更好的类别分布,以建立一个更有效的模型。

一些常见的方法包括:

  • 上采样:增加具有较少实例的类别

  • 下采样:减少具有更多实例的类别

  • 创建合成示例(例如,SMOTE合成少数过采样技术))

  • 随机过采样(例如,(ROSE) 随机过采样示例

我们将使用与先前示例相同的数据创建一个模拟数据集,其中 95%的行将被标记为负:

library(mlbench) 
library(caret) 
diab<- PimaIndiansDiabetes 

diabsim<- diab 
diabrows<- nrow(diabsim) 
negrows<- floor(.95 * diabrows) 
posrows<- (diabrows - negrows) 

negrows 
[1] 729 

posrows 
[1] 39 

diabsim$diabetes[1:729]     <- as.factor("neg")
diabsim$diabetes[-c(1:729)] <- as.factor("pos")
table(diabsim$diabetes) 

neg. pos 
729  39 

# We observe that in this simulated dataset, we have 729 occurrences of positive outcome and 39 occurrences of negative outcome

# Method 1: Upsampling, i.e., increasing the number of observations marked as 'pos' (i.e., positive) 

upsampled_simdata<- upSample(diabsim[,-ncol(diabsim)], diabsim$diabetes) 
table(upsampled_simdata$Class) 

negpos 
729 729 

# NOTE THAT THE OUTCOME IS CALLED AS 'Class' and not 'diabetes' 
# This is because of the use of the variable separately 
# We can always rename the column to revert to the original name 

# Method 2: Downsampling, i.e., reducing the number of observations marked as 'pos' (i.e., positive) 

downsampled_simdata<- downSample(diabsim[,-ncol(diabsim)], diabsim$diabetes) 
table(downsampled_simdata$Class) 

neg pos 
39  39 
  • SMOTE合成少数类过采样技术)是第三种方法,它不是简单的上/下采样,而是从少数类的最近邻中创建合成记录。在我们的模拟数据集中,很明显neg是少数类,也就是发生次数最少的类别。

SMOTE 函数的帮助文件简洁地解释了这个概念:

不平衡的分类问题给许多学习算法带来了问题。这些问题的特点是每个问题类别的案例比例不均衡。

SMOTE(Chawla 等人,2002)是一个用于解决这个问题的著名算法。该方法的一般思想是使用少数类的最近邻人工生成新的示例。此外,多数类的示例也被下采样,从而导致更平衡的数据集:

# Method 3: SMOTE 
# The function SMOTE is available in the R Package DMwR 
# In order to use it, we first need to install DmWR as follows 

install.packages ("DMwR") 

# Once the package has been installed, we will create a synthetic 
# Dataset in which we will increase the number of 'neg' records 
# Let us check once again the distribution of neg/pos in the dataset 

table(diabsim$diabetes) 

negpos 
729  39 

# Using SMOTE we can create synthetic cases of 'pos' as follows 

diabsyn<- SMOTE(diabetes ~ ., diabsim, perc.over = 500, perc.under = 150) 

# perc.over = 500 means, increase the occurrence of the minority 
# class by 500%, i.e., 39 + 5*39 = 39 + 195 = 234 

# perc.under = 150 means, that for each new record generated for the 
# Minority class, we will generate 1.5 cases of the majority class 
# In this case, we created 195 new records (500% of 39) and hence 
# we will generate 150% of 195 records = 195 * 150% = 195 * 1.5 
# = 292.5, or 292 (rounded down) new records 

# We can verify this by running the table command against the newly 
# Created synthetic dataset, diabsyn 

table(diabsyn$diabetes) 

negpos 
292 234
  • ROSE(随机过采样示例),本节的最后一种方法,通过 R 中的 ROSE 软件包提供。与 SMOTE 类似,它是一种生成合成样本的方法。ROSE 的帮助文件说明了该函数的高级用法如下:

通过随机过采样示例生成合成数据,通过扩大少数和多数类示例的特征空间来创建合成数据样本。在操作上,新的示例是从两个类的条件核密度估计中抽取的,如 Menardi 和 Torelli(2013)中所述。

install.packages("ROSE") 
library(ROSE) 

# Loaded ROSE 0.0-3 
set.seed(1) 

diabsyn2 <- ROSE(diabetes ~ ., data=diabsim) 

table(diabsyn2$data$diabetes) 

# negpos 
# 395 373 

数据插补

有时,您的数据可能存在缺失值。这可能是由于数据收集过程中的错误、真正缺失的数据或其他原因,导致信息不可用。缺失数据的现实世界例子可以在调查中找到,调查对象没有回答调查中的特定问题。

您可能有一个包含 1000 条记录和 20 列的数据集,其中某一列有 100 个缺失值。您可以选择完全丢弃这一列,但这也意味着丢弃了 90%的信息。您仍然有其他 19 列具有完整数据。另一个选择是简单地排除该列,但这意味着您无法利用该列中可用的数据所带来的好处。

存在多种数据插补方法,即填充缺失数据的过程。我们不知道确切的值是什么,但通过查看表中的其他条目,我们可能能够对值进行系统的评估。

一些常见的数据插补方法包括:

  • 均值、中位数、众数插补:使用列的均值、中位数或众数值替换缺失值。然而,这样做会增加被插补的变量之间的相关性,这对多变量分析可能不是理想的。

  • K 最近邻插补:kNN 插补是使用机器学习方法(最近邻)来填补缺失值的过程。它通过找到与具有缺失值的记录最相似的 k 条记录,并使用欧几里德距离相对于 k 条记录计算加权平均值来工作。

  • 使用回归模型进行插补:回归方法使用 R 中的标准回归方法来预测缺失变量的值。然而,正如维基百科上关于基于回归的插补的相应部分所指出的那样en.wikipedia.org/wiki/Imputation_(statistics)#Regression,问题在于(回归插补)估计的插补数据没有包括误差项。因此,估计值完全符合回归线,没有任何残差方差。这导致关系被过度识别,并表明插补值的精度比实际情况更高。

  • 热卡插补:使用数据集本身的观察值填充缺失值的另一种技术。这种方法虽然非常普遍,但有一个局限性,即通过为大范围的缺失值分配一个单一值,可能会在观察中增加显著的偏差,并产生误导性的结果。

这里提供了一个简短的示例,演示了如何使用 kNN 插补进行插补。我们通过在PimaIndiansDiabetes数据集中将大量值更改为 NA 来模拟缺失数据。

我们利用以下因素进行处理:

  • 我们使用均值来填充 NA 值。

  • 我们使用 kNN 插补来填补缺失值。然后比较这两种方法的表现:

library(DMwR) 
library(caret) 

diab<- PimaIndiansDiabetes 

# In the dataset, the column mass represents the body mass index 
# Of the individuals represented in the corresponding row 

# mass: Body mass index (weight in kg/(height in m)\²) 

# Creating a backup of the diabetes dataframe 
diabmiss_orig<- diab 

# Creating a separate dataframe which we will modify 
diabmiss<- diabmiss_orig 

# Saving the original values for body mass 
actual <- diabmiss_orig$mass 

# Change 91 values of mass to NA in the dataset 
diabmiss$mass[10:100] <- NA 

# Number of missing values in mass 
sum(is.na(diabmiss$mass)) 

# 91 

# View the missing values 
diabmiss[5:15,] 

我们得到以下输出:

# Test with using the mean, we will set all the missing values 
# To the mean value for the column 

diabmiss$mass[is.na(diabmiss$mass)] <- mean(diabmiss$mass,na.rm = TRUE) 

# Check the values that have been imputed 
data.frame(actual=actual[10:100], impute_with_mean=diabmiss$mass[10:100]) 

前面代码的输出如下:

# Check the Root-Mean-Squared-Error for the entire column 
# Root Mean Squared Error provides an estimate for the 
# Difference between the actual and the predicted values 
# On 'average' 

diabmissdf<- data.frame(actual=actual, impute_with_mean=diabmiss$mass) 
rmse1 <- RMSE(diabmissdf$impute_with_mean,actual) 
rmse1 

# [1] 3.417476 

# We will re-run the exercise using knnImputation (from package DMwR) 

# Change the value of the records back to NA 
diabmiss<- diabmiss_orig 
diabmiss$mass[10:100] <- NA 

# Perform knnImputation 
diabknn<- knnImputation(diabmiss,k=25) 

# Check the RMSE value for the knnImputation method 
rmse2 <- RMSE(diabknn$mass,actual) 
rmse2 

# [1] 3.093827 

# Improvement using the knnImputation methods in percentage terms 

100 * (rmse1-rmse2)/rmse1 

[1] 22.20689 

虽然这可能不代表一个显著的变化,但仍然比使用简单的方法(如使用均值或常数值)要好。

R 中有几个数据插补的包。其中一些著名的包如下:

  • Amelia II:时间序列数据中的缺失信息

gking.harvard.edu/amelia

  • 使用 R 包进行热卡补充: HotDeckImputation 和 hot.deck

cran.r-project.org/web/packages/HotDeckImputation/

cran.r-project.org/web/packages/hot.deck/

  • 多变量填充(通过链式方程)

cran.r-project.org/web/packages/mice/index.html

  • 在 R 包中使用贝叶斯框架进行值的填充: mi

cran.r-project.org/web/packages/mi/index.html

变量的重要性

在模型构建过程中,数据集可能有数十个变量。并非所有变量都可能对预测模型有价值。将数据集减少到包括变量子集并允许机器学习程序员花更多时间来调整选择的变量和模型构建过程是很常见的。减少数据集中变量数量也有技术上的理由。在非常大的、即高维数据集上执行机器学习建模可能非常计算密集,即可能需要大量的时间、CPU 和 RAM 来执行数值运算。这不仅使得应用某些算法变得不切实际,还会导致不必要的延迟。因此,变量的系统选择有助于分析时间和算法分析的计算要求。

变量选择也被称为特征选择/属性选择。随机森林和套索回归等算法实现了变量选择作为其算法操作的一部分。但是,变量选择也可以作为一个单独的练习来完成。

R 包caret为变量选择提供了一个非常简单易用和直观的接口。由于我们还没有讨论建模过程,我们将学习如何找到重要的变量,并在下一章深入探讨这个主题。

我们将使用一个常见的、众所周知的算法,称为RandomForest,用于构建决策树。该算法将在下一章中更详细地描述,但在这里使用它的目的仅仅是为了展示如何进行变量选择。这个例子说明了一般过程是什么样的。

我们将重复使用我们一直在处理的数据集,即来自mlbench包的PimaIndiansDiabetes数据。我们还没有讨论模型训练过程,但在这里使用它是为了得出变量重要性的值。在这种情况下,结果变量是糖尿病,其他变量被用作自变量。换句话说,我们能否使用可用的数据来预测一个人是否患有糖尿病:

diab<- PimaIndiansDiabetes 

# We will use the createDataPartition function from caret to split 
# The data. The function produces a set of indices using which we 
# will create the corresponding training and test sets 

training_index<- createDataPartition(diab$diabetes, p = 0.80, list = FALSE, times = 1) 

# Creating the training set 
diab_train<- diab[training_index,] 

# Create the test set 
diab_test<- diab[-training_index,] 

# Create the trainControl parameters for the model 
diab_control<- trainControl("repeatedcv", number = 3, repeats = 2, classProbs = TRUE, summaryFunction = twoClassSummary) 

# Build the model 
rf_model<- train(diabetes ~ ., data = diab_train, method = "rf", preProc = c("center", "scale"), tuneLength = 5, trControl = diab_control, metric = "ROC") 

# Find the Variable Importance 
varImp(rf_model) 
rf variable importance 

         Overall 
glucose  100.000 
mass      52.669 
age       39.230 
pedigree  24.885 
pressure  12.619 
pregnant   6.919 
insulin    2.294 
triceps    0.000 

# This indicates that glucose levels, body mass index and age are the top 3 predictors of diabetes. 

# caret also includes several useful plot functions. We can visualize the variable importance using the command: 

plot(varImp(rf_model)) 

上述代码的输出如下所示。它表明葡萄糖、体重指数和年龄是对创建模型(预测糖尿病)做出最大贡献的变量。

训练、测试拆分和交叉验证概念

在机器学习中,训练、测试拆分和交叉验证集是一个基本概念。这是一个纯统计方法与机器学习方法有实质区别的领域之一。在统计建模任务中,一个人可能进行回归、参数/非参数测试,并应用其他方法,而在机器学习中,算法方法被补充了对产生的结果的迭代评估和随后的模型改进的元素。

将数据拆分为训练集和测试集

每个机器学习建模练习都始于数据清洗的过程,正如前面讨论的那样。下一步是将数据分割成训练集和测试集。通常是通过随机选择数据中的行来完成的,这些行将被用来创建模型。然后未被选择的行将被用来测试最终模型。

通常的分割在 70-80%之间(训练数据与测试数据)。在 80-20 的分割中,80%的数据将被用来创建模型。剩下的 20%将被用来测试最终模型。

我们在前面的部分中应用了这个方法,但我们可以再次查看代码。createDataPartition函数被用来分割数据,参数为p = 0.80training_index变量保存了我们将使用的训练索引(datasetdiab):

training_index<- createDataPartition(diab$diabetes, p = 0.80, list = FALSE, times = 1) 

length(training_index) # Number of items that we will select for the train set [1] 615 

nrow(diab) # The total number of rows in the dataset [1] 768 

# Creating the training set, this is the data we will use to build our model 
diab_train<- diab[training_index,] 

# Create the test set, this is the data against which we will test the performance of our model 
diab_test<- diab[-training_index,] 

我们不一定要使用createDataPartition函数,而是可以使用简单的 R 命令创建一个随机样本,如下所示:

# Create a set of random indices representing 80% of the data 
training_index2 <- sample(nrow(diab),floor(0.80*nrow(diab))) 

# Check the size of the indices just created 
length(training_index2) [1] 614 

# Create the training set 
diab_train2 <- diab[training_index2,] 

# Create the test set 
diab_test2 <- diab[-training_index2] 

交叉验证参数

交叉验证将训练-测试分割的概念推向了下一个阶段。机器学习练习的目标本质上是找到哪组模型参数能提供最佳的性能。模型参数指的是函数(模型)所需的参数。例如,对于决策树模型,参数可能包括模型应该构建的深度级别、分割数量等。如果有n个不同的参数,每个参数有k个不同的值,那么总参数数量将是k^n。通常我们会为每个参数选择一组固定的组合,可能最终会有 100-1000+个组合。我们将测试模型的性能(例如,正确预测结果的准确度)。

对于一个简单的训练-测试分割,比如说,如果我们选择了 500 个参数组合,我们只需要对训练数据集运行它们,并确定哪一个显示出最佳性能。

通过交叉验证,我们进一步将训练集分成更小的子集,比如说通常使用三折或五折。如果有三折,也就是说,我们将训练集分成三个子集,我们将一折放在一边,比如说第 2 折,然后使用第 1 折和第 3 折构建一个模型。然后测试它对第 2 折的准确性。这个步骤会重复多次,每次迭代都代表了一组独特的折,训练-测试过程和准确度测量。最终,我们会选择表现最佳的参数组合。

标准的方法可以总结如下:

  1. 创建一个 80-20 的训练-测试分割

  2. 使用不同的模型参数组合执行你的模型

  3. 选择表现最佳的模型参数并创建最终模型

  4. 在测试集上应用最终模型以查看结果

交叉验证方法要求我们进一步将训练数据集分成更小的子集。这些子集通常被称为,总称为k 折,其中k代表分割的数量:

  1. 创建一个 80-20 的训练-测试分割

  2. 将训练集分成 k 折,比如说三折

  3. 将第 1 折放在一边,使用第 2 折和第 3 折构建模型

  4. 在第 1 折上测试你的模型表现(例如,准确结果的百分比)

  5. 将第 2 折放在一边,使用第 1 折和第 3 折构建模型

  6. 在第 2 折上测试你的模型表现

  7. 将第 3 折放在一边,使用第 1 折和第 2 折构建模型

  8. 在第 3 折上测试你的模型表现

  9. 取所有三折模型的平均性能

  10. 每组模型参数重复步骤 1

  11. 选择表现最佳的模型参数并创建最终模型

  12. 在测试集上应用最终模型以查看结果

这张图片说明了使用不带交叉验证的方法和带交叉验证的方法之间的差异。交叉验证方法可以说更加健壮,并且涉及对模型的严格评估。也就是说,尝试最初创建一个不带交叉验证的模型通常是有用的,以了解可能期望的性能。例如,如果使用 2-3 个训练-测试分割构建的模型显示出 30%的准确性,那么很可能任何其他方法,包括交叉验证,都不会使其达到 90%。换句话说,标准方法有助于了解可能期望的性能。由于交叉验证可能非常耗费计算资源和时间,因此在性能的初步分析中获得初始反馈是有帮助的。

R 中的 caret 包提供了一个非常用户友好的方法来使用交叉验证构建模型。请记住,数据预处理必须通过或作为交叉验证过程的一个组成部分。因此,假设我们需要对数据集进行中心化和缩放,并进行五折交叉验证,我们只需要在 caret 的trainControl函数中定义我们想要使用的抽样类型。

Caret 关于trainControl的网页提供了函数的详细概述,并附有示例,网址为topepo.github.io/caret/model-training-and-tuning.html#basic-parameter-tuning

我们在之前的练习中使用了这种方法,在PimaIndiansDiabetes数据集上使用RandomForest构建了一个模型。这里再次展示出来,以表明这种技术的使用情况:

# Create the trainControl parameters for the model 
# The parameters indicate that a 3-Fold CV would be created 
# and that the process would be repeated 2 times (repeats) 
# The class probabilities in each run will be stored 
# And we'll use the twoClassSummary* function to measure the model 
# Performance 
diab_control<- trainControl("repeatedcv", number = 3, repeats = 2, classProbs = TRUE, summaryFunction = twoClassSummary) 

# Build the model 
# We used the train function of caret to build the model 
# As part of the training process, we specified a tunelength** of 5 
# This parameter lets caret select a set of default model parameters 
# trControl = diab_control indicates that the model will be built 
# Using the cross-validation method specified in diab_control 
# Finally preProc = c("center", "scale") indicate that the data 
# Would be centered and scaled at each pass of the model iteration 

rf_model<- train(diabetes ~ ., data = diab_train, method = "rf", preProc = c("center", "scale"), tuneLength = 5, trControl = diab_control, metric = "ROC") 

您可以从cran.r-project.org/web/packages/caret/vignettes/caret.pdf获取有关summaryFunction的更详细解释。

summaryFunction参数用于传递一个函数,该函数接受观察值和预测值,并估计某种性能指标。该包中已经包含了两个这样的函数:defaultSummarytwoClassSummary。后者将计算特定于两类问题的度量,例如 ROC 曲线下面积、灵敏度和特异性。由于 ROC 曲线是基于预测类别概率的(这些概率不会自动计算),因此需要另一个选项。classProbs = TRUE选项用于包括这些计算。

以下是来自carettrain函数的帮助文件中关于tuneLength的解释。

tuneLength是一个整数,表示调整参数网格中的粒度。默认情况下,该参数是由train生成的每个调整参数的级别数。如果trainControl选项中有search = random,则这是由随机搜索生成的调整参数组合的最大数量。

请注意,如果给出了这个参数,必须要有名称。

创建模型

创建模型后的最后一步是使用模型对测试数据集进行预测。通常使用 R 中的predict函数来完成,第一个参数是创建的模型,第二个参数是您想要获取预测结果的数据集。

PimaIndiansDiabetes数据集为例,在模型构建完成后,我们可以按以下方式在测试数据集上进行预测:

# Install the R Package e1071, if you haven't already 
# By running install.packages("e1071") 

# Use the predict function and the rf_model that was previously built 
# To get the predictions on the test dataset 
# Note that we are not including the column diabetes in the test 
# dataset by using diab_test[,-ncol(diab_test)] 

predictions<- predict(rf_model, diab_test[,-ncol(diab_test)]) 

# First few records predicted 
head(predictions)
[1] negnegpospospospos 
Levels: negpos 

# The confusion matrix allows us to see the number of true positives 
# False positives, True negatives and False negatives 

cf<- confusionMatrix(predictions, diab_test$diabetes) 
cf 

# Confusion Matrix and Statistics 
#  
#        Reference 
# Prediction negpos 
#        neg  89  21 
#        pos  11  32 
#  
# Accuracy : 0.7908           
# 95% CI : (0.7178, 0.8523) 
# No Information Rate : 0.6536           
# P-Value [Acc> NIR] : 0.0001499        
#  
# Kappa : 0.5167           
# Mcnemar's Test P-Value : 0.1116118        
#  
# Sensitivity : 0.8900           
# Specificity : 0.6038           
# PosPredValue : 0.8091           
# NegPredValue : 0.7442           
# Prevalence : 0.6536           
# Detection Rate : 0.5817           
# Detection Prevalence : 0.7190           
# Balanced Accuracy : 0.7469           
#  
# 'Positive' Class :neg 

让我们看看混淆矩阵告诉我们什么:

# This indicates that of the records that were marked negative (neg) 
# We predicted 89 of them as negative and 11 as positive (i.e., they 
# were negative but we incorrectly classified them as a positive 

# We correctly identified 32 positives but incorrectly classified 
# 21 positives as negative 

# 
#           Reference 
# Prediction neg  pos 
#        neg  89  21 
#        pos  11  32 

# The overall accuracy was 79% 
# This can be improved (significantly) by using more  
# Accuracy : 0.7908           

# We can plot the model using plot(rf_model) as follows 
plot(rf_model) 

绘图如下:

# And finally we can also visualize our confusion matrix using the 
# inbuilt fourfoldplot function in R 

fourfoldplot(cf$table) 

我们得到的绘图如下:

根据fourfoldplot的文档[来源:stat.ethz.ch/R-manual/R-devel/library/graphics/html/fourfoldplot.html],二元行和列变量之间的关联(与 1 不同的几率比)由对角线相对方向的单元格大小差异的倾向来指示;颜色用于显示这个方向。几率比的置信环允许对无关联的零假设进行视觉检验;如果相邻象限的环重叠,那么观察计数与零假设一致。

利用模型中的多核处理

在这里使用 PimaIndianDiabetes2 数据集重复上一节的练习。该数据集包含一些缺失值。因此,我们将首先填补缺失值,然后运行机器学习示例。

该练习已经以一些额外的细微差别重复进行,比如使用多核/并行处理以使交叉验证运行更快。

要利用多核处理,使用以下代码安装doMC包:

Install.packages("doMC")  # Install package for multicore processing 
Install.packages("nnet") # Install package for neural networks in R 

现在我们将按照这里的代码运行程序:

# Load the library doMC 
library(doMC) 

# Register all cores 
registerDoMC(cores = 8) 

# Set seed to create a reproducible example 
set.seed(100) 

# Load the PimaIndiansDiabetes2 dataset 
data("PimaIndiansDiabetes2",package = 'mlbench') 
diab<- PimaIndiansDiabetes2 

# This dataset, unlike PimaIndiansDiabetes has 652 missing values! 
> sum(is.na(diab)) [1] 652 

# We will use knnImputation to fill in the missing values 
diab<- knnImputation(diab) 

# Create the train-test set split 
training_index<- createDataPartition(diab$diabetes, p = .8, list = FALSE, times = 1) 

# Create the training and test dataset 
diab_train<- diab[training_index,] 
diab_test<- diab[-training_index,] 

# We will use 10-Fold Cross Validations 
diab_control<- trainControl("repeatedcv", number = 10, repeats = 3, search = "random", classProbs = TRUE) 

# Create the model using methodnnet (a Neural Network package in R) 
# Note that we have changed the metric here to "Accuracy" instead of # ROC 
nn_model<- train(diabetes ~ ., data = diab_train, method = "nnet",   preProc = c("center", "scale"), trControl = diab_control, tuneLength = 10, metric = "Accuracy") 

predictions<- predict(nn_model, diab_test[,-ncol(diab_test)]) 
cf<- confusionMatrix(predictions, diab_test$diabetes) 
cf 

# >cf 
# Confusion Matrix and Statistics 
#  
#        Reference 
# Prediction negpos 
#        neg  89  19 
#        pos  11  34 
#  
# Accuracy : 0.8039           
# 95% CI : (0.7321, 0.8636) 
# No Information Rate : 0.6536           
# P-Value [Acc> NIR] : 3.3e-05          
#  

即使有 650 多个缺失值,我们的模型也能够达到 80%以上的准确率。

它肯定可以得到改进,但作为基准,它展示了机器学习模型可以期望的性能类型。

在二元结果变量的情况下,随机猜测的准确率为 50%。80%的准确率显然比我们只使用猜测所能达到的准确率要高得多:

 plot(nn_model) 

得到的图如下:

fourfoldplot(cf$table) 

结果如下图所示:

总结

在本章中,我们了解了机器学习的基本原理,不同类型,如监督和无监督,以及数据预处理、数据填补、管理不平衡类别和其他主题。

我们还了解了今天可以互换使用的一些关键术语之间的区别,特别是 AI 和机器学习这两个术语。我们了解到人工智能涉及到各种各样的主题,如博弈论、社会学、受限优化和机器学习;相对于机器学习,AI 的范围要广得多。

机器学习促进了人工智能;也就是说,机器学习算法被用来创建人工智能系统,但它们的范围不同。回归问题(在给定一组点的情况下找到最佳拟合线)可以被视为机器学习算法,但在概念上,它不太可能被视为 AI 算法(尽管从技术上讲它可能是)。

在下一章中,我们将研究机器学习中的其他概念,如偏差、方差和正则化。我们还将了解一些重要的算法,并学习如何使用 R 中的机器学习包应用它们。

第八章:深入学习机器学习

之前关于机器学习的章节提供了该主题的初步概述,包括该主题领域的不同类别和核心概念。本章将更深入地探讨机器学习的理论方面,比如算法的限制以及不同算法的工作原理。

机器学习是一个广阔而复杂的主题,因此本章侧重于不同主题的广度,而不是深度。这些概念是以高层次介绍的,读者可以参考其他来源进一步了解这些主题。

我们将首先讨论机器学习中的一些基本理论,比如梯度下降和 VC 维度。接下来,我们将研究偏差和方差,这两个在任何建模过程中最重要的因素,以及偏差-方差权衡的概念。

接下来我们将讨论各种机器学习算法,它们的优势和应用领域。

最后,我们将通过使用真实世界的数据集来执行机器学习操作,来总结本章。

本章将涵盖以下主题:

  • 偏差、方差和正则化属性

  • 梯度下降和 VC 维度理论

  • 机器学习算法

  • 教程:使用 R 进行机器学习

偏差、方差和正则化属性

偏差、方差以及与之密切相关的正则化在机器学习领域中占据着非常特殊和基础的位置。

当机器学习模型过于“简单”时,就会出现偏差,导致结果与实际值一直偏离。

方差发生在模型过于“复杂”时,导致在测试数据集上结果非常准确,但在未见过/新的数据集上表现不佳。

一旦用户熟悉了创建机器学习模型的过程,似乎这个过程相当简单-获取数据,创建训练集和测试集,创建模型,在测试数据集上应用模型,练习完成。创建模型很容易;创建一个模型则是一个更具挑战性的话题。但是如何测试模型的质量呢?也许更重要的是,如何构建一个“好”的模型呢?

答案在于一个叫做正则化的术语。这可能是一个花哨的词,但它的意思只是在创建模型的过程中,通过对训练数据集上过于出色的表现进行惩罚,对表现不佳的模型进行放松,从而受益。

要理解正则化,了解过拟合和欠拟合的概念会有所帮助。为此,让我们看一个简单但熟悉的例子,即绘制最佳拟合线。对于那些使用过 Microsoft Excel 的人,你可能已经注意到了绘制最佳拟合线的选项-实质上,给定一组点,你可以绘制一条代表数据并逼近点所代表的函数的线。

以下表格显示了几个属性的价格与面积的关系。为了确定房价与房屋大小之间的关系,我们可以绘制最佳拟合线或趋势线,如下所示:

Sq. ft. Price ($)
862 170,982
1235 227,932
932 183,280
1624 237,945
1757 275,921
1630 274,713
1236 201,428
1002 193,128
1118 187,073
1339 202,422
1753 283,989
1239 228,170
1364 230,662
995 169,369
1000 157,305

如果我们使用线性趋势线绘制最佳拟合线,图表会看起来像这样:

Excel 提供了一个有用的附加功能,允许用户绘制趋势线的延伸,这可以提供未知变量的估计或预测。在这种情况下,延伸趋势线将告诉我们,根据函数,1800-2000 平方英尺范围内的房屋价格可能是多少。

描述数据的线性函数如下:

y=126.13x + 54,466.81

下图中的延伸趋势线显示价格很可能在 275,000 美元和 300,000 美元之间:

然而,有人可能会认为这条线不是最好的近似,可能可以增加 R2 的值,这种情况下是 0.87。一般来说,R² 越高,描述数据的模型就越好。有各种不同类型的值,但在本节中,我们假设越高,模型就越好。

在下一节中,我们将绘制一个具有更高 R² 的新趋势线,但使用多项式函数。这个函数具有更高的 R²(0.91 比 0.87),在视觉上看起来更接近平均点。

在这种情况下,函数是一个 6 次多项式:

y = -0.00x⁶ + 0.00x⁵ - 0.00x⁴ + 2.50x³ - 2,313.40x² + 1,125,401.77x - 224,923,813.17

但是,即使该线具有更高的 R²,如果我们延伸趋势线,试图找出 1800-2000 平方英尺范围内房屋的价格可能是什么,我们得到以下结果。

1800-2000 平方英尺范围内的房屋价格从大约 280,000 美元到负 2 百万美元。换句话说,购买 1800 平方英尺房屋的人预计要花费 280,000 美元,而购买 2000 平方英尺房屋的人根据这个函数应该获得 200 万美元!当然,这是不准确的,但我们刚刚见证的是所谓的过拟合。下图说明了这一现象。

在光谱的另一端是欠拟合。当构建的模型不能描述数据时就会发生这种情况。在下图中,函数 y = 0.25x - 200 就是一个例子:

简而言之,这一部分可以简化如下:

  • 一个过于拟合数据的函数,可以近似训练数据集中的几乎所有点的函数被认为是过拟合。

  • 一个完全不适合数据的函数,或者换句话说远离训练数据集中实际点的函数被认为是欠拟合。

  • 机器学习是在过拟合和欠拟合数据之间取得平衡的过程。这可能是一个不容易的练习,这就是为什么即使构建模型可能是微不足道的,构建一个相当不错的模型却是一个更加困难的挑战。

  • 欠拟合是指你的函数“根本不思考”-它具有很高的偏差。

  • 过拟合是指你的函数“想得太多”-它具有很高的方差。

  • 欠拟合和过拟合的另一个例子将在接下来的例子中给出。

假设我们的任务是确定一堆水果是橙子还是苹果,并已经知道它们在水果篮(左侧或右侧)、大小和重量的位置:

篮子 1(训练数据集) 篮子 2(测试数据集)

过拟合的一个例子可能是,根据训练数据集,关于篮子 1,我们可能得出结论说篮子右侧只有橙子,左侧全是苹果。

欠拟合的一个例子可能是我得出结论说篮子里只有橙子。

模型 1:在第一种情况下-过拟合-我实际上是在记忆位置。

模型 2:在第二种情况下 - 对于欠拟合 - 我根本记不清任何东西。

现在,给定第二个篮子 - 位置为苹果和橙子互换的测试数据集 - 如果我使用模型 1,我会错误地得出右手边的所有水果都是橙子,左手边的都是苹果的结论(因为我记住了训练数据)。

如果我使用模型 2,我会再次错误地得出所有水果都是橙子的结论。

然而,有办法管理欠拟合和过拟合之间的平衡 - 或者换句话说,高偏差和高方差之间的平衡。

用于偏差-方差权衡的常用方法之一称为正则化。这指的是对模型进行惩罚(例如,回归中的模型系数),以产生一个能够在一系列数据点上很好泛化的输出。

下一页的表格说明了偏差和方差的一些关键概念,并说明了当模型存在高偏差或高方差时的补救措施选项:

在建模过程中,高偏差通常表现为训练集误差和测试集误差保持一致地高。对于高方差(过拟合),训练集误差迅速减少,但测试集误差保持不变。

梯度下降和 VC 维度理论

梯度下降和 VC 维度是机器学习中的两个基本理论。一般来说,梯度下降提供了一种结构化方法来找到函数的最优系数。函数的假设空间可能很大,通过梯度下降,算法试图找到成本函数(例如,误差的平方和)最低的最小值。

VC 维度提供了系统中可以分类的最大点数的上限。它本质上是函数丰富性的度量,并以结构化方式提供了对假设限制的评估。函数或假设可以准确分类的点数称为假设的 VC 维度。例如,线性边界可以准确分类 2 或 3 个点,但不能是 4 个。因此,这个二维空间的 VC 维度将是 3。

VC 维度,就像计算学习理论中的许多其他主题一样,既复杂又有趣。这是一个较少人知晓(和讨论)的话题,但它试图回答关于学习限制的问题,因此具有深远的影响。

流行的机器学习算法

有各种不同类别的机器学习算法。因此,由于算法可以同时属于多个“类别”或类别,概念上很难明确说明算法专属于单一类别。在本节中,我们将简要讨论一些最常用和知名的算法。

这些包括:

  • 回归模型

  • 关联规则

  • 决策树

  • 随机森林

  • Boosting 算法

  • 支持向量机

  • K 均值

  • 神经网络

请注意,在这些示例中,我们展示了使用整个数据集的 R 函数的基本用法。在实践中,我们会将数据分成训练集和测试集,一旦建立了令人满意的模型,就会将其应用于测试数据集以评估模型的性能。

回归模型

回归模型从统计学中常用的线性、逻辑和多元回归算法到 Ridge 和 Lasso 回归,后者对系数进行惩罚以提高模型性能。

在我们之前的例子中,我们看到了在创建趋势线时应用线性回归的情况。多元线性回归指的是创建模型的过程需要多个自变量。

例如:

总广告成本 = x*印刷广告,将是一个简单的线性回归;而

总广告成本 = X + 印刷广告 + 广播广告 + 电视广告,由于存在多个独立变量(印刷、广播和电视),将是多元线性回归。

逻辑回归是另一种常用的统计回归建模技术,用于预测离散分类值的结果,主要用于结果变量是二分的情况(例如,0 或 1,是或否等)。然而,也可以有超过 2 个离散的结果(例如,州 NY、NJ、CT),这种类型的逻辑回归称为多项式逻辑回归

岭回归和 Lasso 回归在线性回归的其他方面之外还包括一个正则化项(λ)。正则化项,岭回归,会减少β系数(因此“惩罚”系数)。在 Lasso 中,正则化项倾向于将一些系数减少到 0,从而消除变量对最终模型的影响:

# Load mlbench and create a regression model of glucose (outcome/dependent variable) with pressure, triceps and insulin as the independent variables.

> library("mlbench") 
>lm_model<- lm(glucose ~ pressure + triceps + insulin, data=PimaIndiansDiabetes[1:100,]) 
> plot(lm_model) 

关联规则

关联规则挖掘,或apriori,试图找到数据集中变量之间的关系。关联规则经常用于各种实际的现实用例。给定一组变量,apriori 可以指示交易数据集中固有的模式。我们的一个教程将基于实现用于 apriori 的 R Shiny 应用程序,因此在本节中将更加重视这一点。

例如,假设一个超市连锁店正在决定货架上商品的摆放顺序。针对包含销售交易的数据库运行的 apriori 算法将识别出最常一起购买的商品。这使得超市能够确定哪些商品,当放置在彼此紧邻的战略位置时,可以产生最多的销售额。这通常也被称为市场篮子分析

反映这一点的一个简单例子可能是:

# The LHS (left-hand side) leads to the RHS (right-hand side) in the relationships shown below.

# For instance, {Milk, Bread} --> {Butter} indicates that someone purchasing milk and bread is also likely to purchase butter.

{Milk, Bread} --> {Butter}
{Butter, Egg} --> {Baking Tray}
{Baking Tray, Butter} --> {Sugar}
...

在所有这些情况下,左侧购买某物导致了表达式右侧提到的物品的购买。

还可以从不一定包含交易的数据库中导出关联规则,而是使用滑动窗口沿着时间属性浏览事件,比如 WINEPI 算法。

Apriori 中有 3 个主要的度量。为了说明它们,让我们使用一个包含 4 个独立交易中购买的商品的样本数据集:

交易 商品 1 商品 2 商品 3
1 牛奶 面包 黄油
2 牛奶 鸡蛋 黄油
3 面包 鸡蛋 奶酪
4 黄油 面包 鸡蛋

置信度

置信度指的是当左侧有效时,apriori 表达式的右侧有多少次有效。例如,给定一个表达式:

{Milk} à {Bread}

我们想知道牛奶也购买时面包经常购买吗。

在这种情况下:

  • 交易 1:牛奶和面包都存在

  • 交易 2:有牛奶,但没有面包

  • 交易 3 和 4:牛奶不存在

因此,根据我们所看到的,有 2 个交易中有牛奶,其中有 1 个交易中有面包。因此,规则{牛奶} à {面包}的置信度为 1/2 = 50%

再举个例子:

{Bread} à {Butter}

我们想知道,购买面包时,黄油也经常购买吗?:

  • 交易 1:面包和黄油都存在

  • 交易 2:没有面包(黄油是存在的,但我们的参考点是面包,因此这不算)

  • 交易 3:有面包但没有黄油

  • 交易 4:面包和黄油都存在

因此,在这种情况下,我们有 3 个交易中有面包,3 个交易中有面包和黄油。因此,在这种情况下,规则{面包} à {黄油}的“置信度”是2/3 = 66.7

支持

支持是指规则满足的次数与数据集中的总交易次数的比率。

例如:

{牛奶} --> {面包},在 4 次交易中发生了 1 次(在交易 1)。因此,这条规则的支持率为¼ = 0.25(或 25%)。

{面包} --> {黄油},在 4 次交易中发生了 2 次(在交易 1 和 4)。因此,这条规则的支持率为½ = 0.50(或 50%)。

提升

提升可以说是 3 个度量中最重要的一个;它衡量了规则相对于表达式的两侧的支持度;换句话说,它衡量了规则相对于 LHS 和 RHS 的随机发生的强度。它正式定义为:

提升=支持(规则)/(支持(LHS)支持(RHS))*

低提升值(例如,小于或等于 1)表示 LHS 和 RHS 的发生是相互独立的,而较高的提升度量表示共同发生是显著的。

在我们之前的例子中,

{面包} --> {黄油}的提升为:

支持({面包} --> {黄油})

支持{面包} * 支持{黄油}

= 0.50/((3/4)*(3/4))= 0.50/(0.75 * 0.75)= 0.89。

这表明尽管规则的置信度很高,但规则本身相对于可能高于 1 的其他规则并不重要。

一个提升高于 1 的规则示例是:

{项目 1:面包} --> {项目 3:奶酪}

这有一个提升:

支持{项目 1:面包 --> 项目 3:奶酪}/(支持{项目 1:奶酪} * 支持{项目 3:奶酪})

=(1/4)/((1/4)*(1/4)= 4。

决策树

决策树是一种预测建模技术,它生成推断出某种结果的可能性的规则,这些规则是基于先前结果的可能性推导出来的。一般来说,决策树通常类似于流程图,具有一系列节点和叶子,表示父子关系。不链接到其他节点的节点称为叶子。

决策树属于一类算法,通常被称为CART分类和回归树)。如果感兴趣的结果是一个分类变量,它属于分类练习,而如果结果是一个数字,它被称为回归树。

一个例子将有助于使这个概念更清晰。看一下图表:

图表显示了一个假设的场景:如果学校关闭/不关闭。蓝色的矩形框代表节点。第一个矩形(学校关闭)代表节点,而内部矩形代表内部节点。带有倾斜边缘的矩形框(绿色和斜体字母)代表“叶子”(或终端节点)。

决策树易于理解,是少数不是“黑匣子”的算法之一。用于创建神经网络的算法通常被认为是黑匣子,因为由于模型的复杂性,很难(甚至不可能)直观地确定最终结果达成的确切路径。

在 R 中,有各种创建决策树的工具。在 R 中创建它们的常用库是rpart。我们将重新访问我们的PimaIndiansDiabetes数据集,看看如何使用该包创建决策树。

我们想创建一个模型来确定葡萄糖、胰岛素、(体重)质量和年龄与糖尿病的关系。请注意,在数据集中,糖尿病是一个具有是/否响应的分类变量。

为了可视化决策树,我们将使用rpart.plot包。相同的代码如下所示:

install.packages("rpart") 
install.packages("rpart.plot") 

library(rpart) 
library(rpart.plot) 

rpart_model<- rpart (diabetes ~ glucose + insulin + mass + age, data = PimaIndiansDiabetes) 

>rpart_model 
n= 768  

node), split, n, loss, yval, (yprob) 
      * denotes terminal node 

  1) root 768 268 neg (0.6510417 0.3489583)   
    2) glucose< 127.5 485  94neg (0.8061856 0.1938144) * 
    3) glucose>=127.5 283 109 pos (0.3851590 0.6148410)   
      6) mass< 29.95 76  24neg (0.6842105 0.3157895)   
       12) glucose< 145.5 41   6 neg (0.8536585 0.1463415) * 
       13) glucose>=145.5 35  17pos (0.4857143 0.5142857)   
         26) insulin< 14.5 21   8 neg (0.6190476 0.3809524) * 
         27) insulin>=14.5 14   4 pos (0.2857143 0.7142857) * 
      7) mass>=29.95 207  57pos (0.2753623 0.7246377)   
       14) glucose< 157.5 115  45pos (0.3913043 0.6086957)   
         28) age< 30.5 50  23neg (0.5400000 0.4600000)   
           56) insulin>=199 14   3 neg (0.7857143 0.2142857) * 
           57) insulin< 199 36  16pos (0.4444444 0.5555556)   
            114) age>=27.5 10   3 neg (0.7000000 0.3000000) * 
            115) age< 27.5 26   9 pos (0.3461538 0.6538462) * 
         29) age>=30.5 65  18pos (0.2769231 0.7230769) * 
       15) glucose>=157.5 92  12pos (0.1304348 0.8695652) * 

>rpart.plot(rpart_model, extra=102, nn=TRUE)

# The plot shown below illustrates the decision tree that the model, rpart_model represents.

从顶部开始阅读,图表显示数据集中有 500 个糖尿病=neg的情况(共 768 条记录)。

> sum(PimaIndiansDiabetes$diabetes=="neg") 
[1] 500 

在数据集中总共 768 条记录中,血糖<128 的记录有 485 条被标记为负面。其中,模型正确预测了 391 个案例为负面(节点编号 2,从底部向左的第一个节点)。

对于血糖读数>128 的记录,有 283 条记录标记为阳性(节点编号 3,即最顶部/根节点的下方节点)。模型正确分类了这些案例中的 174 个。

另一个更近期的提供直观决策树和全面视觉信息的包是FFTreesFast and Frugal Decision Trees)。以下示例仅供信息目的:

install.packages("FFTrees") 
library(caret) 
library(mlbench) 
library(FFTrees) 
set.seed(123) 

data("PimaIndiansDiabetes") 
diab<- PimaIndiansDiabetes 
diab$diabetes<- 1 * (diab$diabetes=="pos") 

train_ind<- createDataPartition(diab$diabetes,p=0.8,list=FALSE,times=1) 

training_diab<- diab[train_ind,] 
test_diab<- diab[-train_ind,] 

diabetes.fft<- FFTrees(diabetes ~.,data = training_diab,data.test = test_diab) 
plot(diabetes.fft)

# The plot below illustrates the decision tree representing diabetes.fft using the FFTrees package.

决策树通过递归地分割数据,直到达到停止条件,比如达到一定深度或案例数量低于指定值。每次分割都是基于将导致“更纯净子集”的变量进行的。

原则上,我们可以从给定的变量集合中生成无数棵树,这使得它成为一个特别困难和棘手的问题。存在许多算法可以提供一种有效的方法来分裂和创建决策树。其中一种方法是 Hunt's Algorithm。

有关该算法的更多详细信息可以在以下链接找到:www-users.cs.umn.edu/~kumar/dmbook/ch4.pdf

随机森林扩展

随机森林是我们刚讨论的决策树模型的扩展。在实践中,决策树易于理解、易于解释、使用现有算法快速创建,并且直观。然而,决策树对数据的细微变化敏感,只允许沿着一个轴进行分割(线性分割),并且可能导致过拟合。为了减轻决策树的一些缺点,同时仍然获得其优雅之处,诸如随机森林的算法会创建多个决策树,并对随机特征进行抽样以建立一个聚合模型。

随机森林基于自助聚合bagging的原则。Bootstrap 是一个统计术语,表示带有替换的随机抽样。对给定的记录进行自助采样意味着随机抽取一定数量的记录,并可能在样本中多次包含相同的记录。然后,用户会在样本上测量他们感兴趣的指标,然后重复这个过程。通过这种方式,从随机样本中多次计算的指标值的分布预计将代表总体的分布,以及整个数据集。

Bagging 的一个例子是一组 3 个数字,比如(1,2,3,4):

(1,2,3),(1,1,3),(1,3,3),(2,2,1),等等。

Bootstrap Aggregating,或bagging,意味着利用多个自助采样进行投票,同时在每个个体样本(n 条记录的集合)上构建模型,最后对结果进行聚合。

随机森林还实现了简单 bagging 之外的另一层操作。它还会在每次分裂时随机选择要包括在模型构建过程中的变量。例如,如果我们使用PimaIndiansDiabetes数据集创建一个随机森林模型,其中包括变量 pregnant, glucose, pressure, triceps, insulin, mass, pedigree, age, 和 diabetes,在每个自助采样(n 条记录的抽样)中,我们会选择一个随机特征子集来构建模型--例如,glucose, pressure, 和 insulin; insulin, age, 和 pedigree; triceps, mass, 和 insulin; 等等。

在 R 中,用于 RandomForest 的常用包被称为 RandomForest。我们可以通过该包直接使用,也可以通过 caret 使用。两种方法如下所示:

  1. 使用 Random Forest 包:
> rf_model1 <- randomForest(diabetes ~ ., data=PimaIndiansDiabetes) > rf_model1 Call: randomForest(formula = diabetes ~ ., data = PimaIndiansDiabetes) 
Type of random forest: classification Number of trees: 500 No. of variables tried at each split: 2 OOB estimate of error rate: 23.44% Confusion matrix: negposclass.error neg430 70 0.1400000 pos 110 158 0.4104478
  1. 使用 caret 的method="rf"函数进行随机森林:
> library(caret) 
> library(doMC) 

# THE NEXT STEP IS VERY CRITICAL - YOU DO 'NOT' NEED TO USE MULTICORE 
# NOTE THAT THIS WILL USE ALL THE CORES ON THE MACHINE THAT YOU ARE 
# USING TO RUN THE EXERCISE 

# REMOVE THE # MARK FROM THE FRONT OF registerDoMC BEFORE RUNNING 
# THE COMMAND 

># registerDoMC(cores = 8) # CHANGE NUMBER OF CORES TO MATCH THE NUMBER OF CORES ON YOUR MACHINE  

>rf_model<- train(diabetes ~ ., data=PimaIndiansDiabetes, method="rf") 
>rf_model 
Random Forest  

768 samples 
  8 predictor 
  2 classes: 'neg', 'pos'  

No pre-processing 
Resampling: Bootstrapped (25 reps)  
Summary of sample sizes: 768, 768, 768, 768, 768, 768, ...  
Resampling results across tuning parameters: 

mtry  Accuracy   Kappa     
  2     0.7555341  0.4451835 
  5     0.7556464  0.4523084 
  8     0.7500721  0.4404318 

Accuracy was used to select the optimal model using  the largest value. 
The final value used for the model was mtry = 5\. 

>getTrainPerf(rf_model) 

TrainAccuracyTrainKappa method 
1     0.7583831  0.4524728rf 

还可以在原始随机森林模型的每棵树中看到分裂和其他相关信息(未使用 caret)。这可以使用getTree函数来完成:

>getTree(rf_model1,1,labelVar = TRUE) 
    left daughter right daughter split var split point status prediction 
1               2              3      mass     27.8500      1       <NA> 
2               4              5       age     28.5000      1       <NA> 
3               6              7   glucose    155.0000      1       <NA> 
4               8              9       age     27.5000      1       <NA> 
5              10             11      mass      9.6500      1       <NA> 
6              12             13  pregnant      7.5000      1       <NA> 
7              14             15   insulin     80.0000      1       <NA> 
8               0              0      <NA>      0.0000     -1        neg 
9              16             17  pressure     68.0000      1       <NA> 
10              0              0      <NA>      0.0000     -1        pos 
11             18             19   insulin    131.0000      1       <NA> 
12             20             21   insulin     87.5000      1       <NA> 

 [...]

提升算法

提升是一种使用权重和一组弱学习器(如决策树)来提高模型性能的技术。提升根据模型误分类和未来学习器(在提升机器学习过程中创建)关注误分类示例来为数据分配权重。正确分类的示例将被重新分配新的权重,通常低于未正确分类的示例。权重可以基于成本函数,例如使用数据子集的多数投票。

简单而非技术性地说,提升使用一系列弱学习器,每个学习器都从先前学习器的错误中“学习”

与装袋相比,提升通常更受欢迎,因为它根据模型性能分配权重,而不是像装袋那样对所有数据点分配相等的权重。这在概念上类似于加权平均与没有加权标准的平均函数之间的区别。

R 中有几个用于提升算法的软件包,其中一些常用的如下:

  • Adaboost

  • GBM(随机梯度提升)

  • XGBoost

其中,XGBoost 是一个广泛流行的机器学习软件包,在竞争激烈的机器学习平台(如 Kaggle)上被非常成功地使用。XGBoost 有一种非常优雅和计算效率高的方式来创建集成模型。由于它既准确又极快,用户经常用 XGBoost 来处理计算密集型的机器学习挑战。您可以在www.kaggle.com了解更多关于 Kaggle 的信息。

# Creating an XGBoost model in R

library(caret)
library(xgboost) 

set.seed(123) 
train_ind<- sample(nrow(PimaIndiansDiabetes),as.integer(nrow(PimaIndiansDiabetes)*.80)) 

training_diab<- PimaIndiansDiabetes[train_ind,] 
test_diab<- PimaIndiansDiabetes[-train_ind,] 

diab_train<- sparse.model.matrix(~.-1, data=training_diab[,-ncol(training_diab)]) 
diab_train_dmatrix<- xgb.DMatrix(data = diab_train, label=training_diab$diabetes=="pos") 

diab_test<- sparse.model.matrix(~.-1, data=test_diab[,-ncol(test_diab)]) 
diab_test_dmatrix<- xgb.DMatrix(data = diab_test, label=test_diab$diabetes=="pos") 

param_diab<- list(objective = "binary:logistic", 
eval_metric = "error", 
              booster = "gbtree", 
max_depth = 5, 
              eta = 0.1) 

xgb_model<- xgb.train(data = diab_train_dmatrix, 
param_diab, nrounds = 1000, 
watchlist = list(train = diab_train_dmatrix, test = diab_test_dmatrix), 
print_every_n = 10) 

predicted <- predict(xgb_model, diab_test_dmatrix) 
predicted <- predicted > 0.5 

actual <- test_diab$diabetes == "pos" 
confusionMatrix(actual,predicted) 

# RESULT 

Confusion Matrix and Statistics 

          Reference 
Prediction FALSE TRUE 
     FALSE    80   17 
     TRUE     21   36 

Accuracy : 0.7532           
                 95% CI : (0.6774, 0.8191) 
    No Information Rate : 0.6558           
    P-Value [Acc> NIR] : 0.005956         

Kappa : 0.463            
Mcnemar's Test P-Value : 0.626496         

Sensitivity : 0.7921           
Specificity : 0.6792           
PosPredValue : 0.8247           
NegPredValue : 0.6316           
Prevalence : 0.6558           
         Detection Rate : 0.5195           
   Detection Prevalence : 0.6299           
      Balanced Accuracy : 0.7357           

       'Positive' Class : FALSE       

支持向量机

支持向量机,通常称为SVMs,是另一类用于使用称为超平面的概念将数据分类为一类或另一类的机器学习算法。超平面用于在点之间划定线性边界。

例如,在 x-y 轴上给定一组黑白点,我们可以找到多条分隔它们的线。在这种情况下,线代表了划分每个点所属类别的函数。在下图中,线 H1 和 H2 都准确地分隔了点。在这种情况下,我们如何确定 H1 和 H2 中哪一个是最佳线呢?:

直观地说,最靠近点的线 - 例如,垂直线 H1 - 可能是分隔点的最佳线。由于该线离点太近,因此对给定数据集上的点太具体,如果新点稍微偏离线的右侧或左侧,可能会被错误分类。换句话说,该线对数据的小变化过于敏感(这可能是由于随机/确定性噪声,如数据中的缺陷)。

另一方面,线 H2 成功地分隔了数据,同时保持了离线最近的点的最大可能距离。数据中的轻微缺陷不太可能影响点的分类,就像线 H1 可能做的那样。这本质上描述了下图中所示的最大间隔分离原则。

靠近线的点,也称为超平面,被称为“支持向量”(因此得名)。在图像中,位于虚线上的点因此是支持向量。

然而,在现实世界中,并非所有点都可能是“线性可分”的。支持向量机利用了一种称为“核技巧”的概念。实质上,可能不是线性可分的点可以被投影或映射到更高维度的表面上。例如,给定一个在 2D x-y 空间上的一组点,如果它们不是线性可分的,那么可能可以将它们投影到 3 维空间上,如下图所示。红色的点在 2D 线上是不可分的,但是当映射到 3 维表面时,它们可以被如下图所示的超平面分开:

R 中有几个包可以让用户利用 SVM,比如kernlabe1071klaR等。在这里,我们展示了来自e1071包的 SVM 的使用,如下所示:

library(mlbench) 
library(caret) 
library(e1071) 
set.seed(123) 

data("PimaIndiansDiabetes") 
diab<- PimaIndiansDiabetes 

train_ind<- createDataPartition(diab$diabetes,p=0.8,list=FALSE,times=1) 

training_diab<- diab[train_ind,] 
test_diab<- diab[-train_ind,] 

svm_model<- svm(diabetes ~ ., data=training_diab) 
plot(svm_model,training_diab, glucose ~ mass) 

# The plot below illustrates the areas that are classified 'positive' and 'negative'

# Creating and evaluating the Confusion Matrix for the SVM model

svm_predicted<- predict(svm_model,test_diab[,-ncol(test_diab)]) 
confusionMatrix(svm_predicted,test_diab$diabetes) 

Confusion Matrix and Statistics 

          Reference 
Prediction negpos 
neg  93  26 
pos7  27 

Accuracy : 0.7843           
                 95% CI : (0.7106, 0.8466) 
    No Information Rate : 0.6536           
    P-Value [Acc> NIR] : 0.0003018        

Kappa : 0.4799           
Mcnemar's Test P-Value : 0.0017280        

Sensitivity : 0.9300           
Specificity : 0.5094           
PosPredValue : 0.7815           
NegPredValue : 0.7941           
Prevalence : 0.6536           
         Detection Rate : 0.6078           
   Detection Prevalence : 0.7778           
      Balanced Accuracy : 0.7197           

       'Positive' Class :neg 

K-Means 机器学习技术

K-Means 是最流行的无监督机器学习技术之一,用于创建聚类,从而对数据进行分类。

一个直观的例子可以如下提出:

假设一所大学开设了一门新的美国历史和亚洲历史课程。该大学保持 15:1 的学生-教师比例,因此每 15 名学生配备 1 名教师。它进行了一项调查,其中包含每位学生对学习美国历史或亚洲历史的偏好分配的 10 分数值分数。

我们可以使用 R 中内置的 K-Means 算法创建 2 个簇,可能通过每个簇中的点的数量来估计可能报名每门课程的学生人数。相同的代码如下所示:

library(data.table) 
library(ggplot2) 
library() 

historyData<- fread("~/Desktop/history.csv") 
ggplot(historyData,aes(american_history,asian_history)) + geom_point() + geom_jitter() 

historyCluster<- kmeans(historyData,2) # Create 2 clusters 
historyData[,cluster:=as.factor(historyCluster$cluster)] 
ggplot(historyData, aes(american_history,asian_history,color=cluster)) + geom_point() + geom_jitter()

# The image below shows the output of the ggplot command. Note that the effect of geom_jitter can be seen in the image below (the points are nudged so that overlapping points can be easily visible)

以下图像可以直观地估计每门课程可能报名的学生人数(从而确定可能需要多少老师):

K-Means 算法有几种变体,但标准和最常用的是 Lloyd 算法。算法步骤如下:

给定一组 n 个点(比如在 x-y 轴上),为了找到 k 个簇:

  1. 从数据集中随机选择 k 个点,代表 k 个簇的中点(比如初始质心)。

  2. 从所选的 k 个点到其他点的距离(代表 k 个簇)被测量,并分配给距离最近的簇。

  3. 簇中心被重新计算为簇中点的平均值。

  4. 再次计算质心与所有其他点之间的距离,如步骤 2 中所示,并计算新的质心,如步骤 3 中所示。以此类推,重复步骤 2 和 3,直到没有新数据被重新分配。

存在各种用于聚类的距离和相似度度量,如欧氏距离(直线距离),余弦相似度(向量之间的夹角的余弦),汉明距离(通常用于分类变量),马哈拉诺比斯距离(以 P.C.马哈拉诺比斯命名;这测量了一个点与分布的均值之间的距离),等等。

尽管不能总是明确地确定最佳的簇数,但有各种方法试图找到一个估计。一般来说,可以通过簇内点之间的接近程度(簇内方差,如平方和-WSS)和簇之间的距离来衡量簇(因此簇之间的较大距离会使簇更容易区分)。用于确定最佳数量的一种方法称为肘部法。以下图表说明了这个概念:

图表显示了 WSS(我们试图最小化的簇内平方和)与簇的数量之间的关系。显然,将簇的数量从 1 增加到 2 会大幅降低 WSS 值。当增加更多的簇时,WSS 的值会迅速下降,直到第 4 或第 5 个簇,之后再增加簇不会显著改善 WSS。通过视觉评估,机器学习从业者可以得出结论,可以创建的理想簇的数量在 3-5 之间,根据图像。

请注意,低 WSS 分数不足以确定最佳簇的数量。必须通过检查指标的改善来完成。当每个点成为独立簇时,WSS 最终会减少到 0。

与神经网络相关的算法

与神经网络相关的算法已经存在了很多十年。第一个计算模型是由沃伦·麦卡洛克和沃尔特·皮茨于 1943 年在《数学生物物理学公报》上描述的。

您可以在pdfs.semanticscholar.org/5272/8a99829792c3272043842455f3a110e841b1.pdfen.wikipedia.org/wiki/Artificial_neural_network了解更多相关概念。

物理世界中的各种人造物体,如飞机,都从自然中汲取了灵感。神经网络本质上是对神经元之间数据交换现象的一种表征,这种现象发生在人类神经系统中的轴突和树突(也称为树突)之间。就像数据在一个神经元和多个其他神经元之间传递以做出复杂的决策一样,人工神经网络以类似的方式创建了一个接收其他神经元输入的神经元网络。

在高层次上,人工神经网络由 4 个主要组件组成:

  • 输入层

  • 隐藏层

  • 输出层

  • 节点和权重

这在下图中表示出来:

图中的每个节点根据前一层的输入产生输出。输出是使用激活函数产生的。有各种类型的激活函数,产生的输出取决于所使用的函数类型。例如二进制步进(0 或 1)、双曲正切(-1 到+1 之间)、Sigmoid 等。

下图说明了这个概念:

值 x1 和 x2 是输入,w1 和 w2 代表权重,节点代表对输入和它们的权重进行评估并由激活函数产生特定输出的点。因此,输出 f 可以表示为:

这里,f 代表激活函数,b 代表偏置项。偏置项独立于权重和输入值,并允许用户移动输出以实现更好的模型性能。

具有多个隐藏层(通常为 2 个或更多)的神经网络计算量很大,在最近的日子里,具有多个隐藏层的神经网络,也被称为深度神经网络或更一般地称为深度学习,已经变得非常流行。

行业中的许多发展都是由机器学习和人工智能推动的,这些发展直接是多层神经网络的实现结果。

在 R 中,nnet包提供了一个可直接使用的神经网络接口。尽管在实践中,神经网络通常需要复杂的硬件、GPU 卡等,但为了说明的目的,我们已经利用nnet包在PimaIndiansDiabetes数据集上运行了早期的分类练习。在这个例子中,我们将利用 caret 来执行nnet模型:

library(mlbench) 
library(caret) 
set.seed(123) 

data("PimaIndiansDiabetes") 
diab<- PimaIndiansDiabetes 

train_ind<- createDataPartition(diab$diabetes,p=0.8,list=FALSE,times=1) 

training_diab<- diab[train_ind,] 
test_diab<- diab[-train_ind,] 

nnet_grid<- expand.grid(.decay = c(0.5,0.1), .size = c(3,5,7)) 

nnet_model<- train(diabetes ~ ., data = training_diab, method = "nnet", metric = "Accuracy", maxit = 500, tuneGrid = nnet_grid) 

# Generating predictions using the neural network model
nnet_predicted <- predict(nnet_model, test_diab)

> plot (nnet_model)

# Confusion Matrix for the Neural Network model

confusionMatrix(nnet_predicted,test_diab$diabetes)

Confusion Matrix and Statistics 

          Reference 
Prediction negpos 
neg  86  22 
pos  14  31 

Accuracy : 0.7647           
                 95% CI : (0.6894, 0.8294) 
    No Information Rate : 0.6536           
    P-Value [Acc> NIR] : 0.001988         

Kappa : 0.4613           
Mcnemar's Test P-Value : 0.243345         

Sensitivity : 0.8600           
Specificity : 0.5849           
PosPredValue : 0.7963           
NegPredValue : 0.6889           
Prevalence : 0.6536           
         Detection Rate : 0.5621           
   Detection Prevalence : 0.7059           
      Balanced Accuracy : 0.7225           

       'Positive' Class :neg 

教程 - 使用 CMS 数据进行关联规则挖掘

本教程将实现一个用于访问在 R 中使用 Apriori 包创建的规则的接口。

我们将从 CMS OpenPayments 网站下载数据。该网站提供有关公司向医生和医院支付的数据:

该网站提供了多种下载数据的方式。用户可以选择感兴趣的数据集并手动下载。在我们的情况下,我们将使用其中一种面向所有用户的基于 Web 的 API 来下载数据。

下载数据

数据集可以通过 Unix 终端(在虚拟机中)下载,也可以直接从浏览器访问该网站进行下载。如果您在虚拟机中下载数据集,请在终端窗口中运行以下命令:

time wget -O cms2016_2.csv 'https://openpaymentsdata.cms.gov/resource/vq63-hu5i.csv?$query=select Physician_First_Name as firstName,Physician_Last_Name as lastName,Recipient_City as city,Recipient_State as state,Submitting_Applicable_Manufacturer_or_Applicable_GPO_Name as company,Total_Amount_of_Payment_USDollars as payment,Nature_of_Payment_or_Transfer_of_Value as paymentNature,Product_Category_or_Therapeutic_Area_1 as category,Name_of_Drug_or_Biological_or_Device_or_Medical_Supply_1 as product where covered_recipient_type like "Covered Recipient Physician" and Recipient_State like "NY" limit 1200000' 

或者,如果您从浏览器下载数据,请在浏览器窗口中输入以下 URL 并点击Enter

openpaymentsdata.cms.gov/resource/vq63-hu5i.csv?$query=select Physician_First_Name as firstName,Physician_Last_Name as lastName,Recipient_City as city,Recipient_State as state,Submitting_Applicable_Manufacturer_or_Applicable_GPO_Name as company,Total_Amount_of_Payment_USDollars as payment,Nature_of_Payment_or_Transfer_of_Value as paymentNature,Product_Category_or_Therapeutic_Area_1 as category,Name_of_Drug_or_Biological_or_Device_or_Medical_Supply_1 as product where covered_recipient_type like "Covered Recipient Physician" and Recipient_State like "NY"

如下图所示:

编写 Apriori 的 R 代码

如前所述,Apriori 算法允许用户查找数据集中固有的关系或模式。为此,我们将在 R/RStudio 中使用 arules 包。该代码将读取下载的数据集(在示例中称为cms2016_2.csv)并运行 Apriori 算法以查找关联规则。

在 RStudio 中创建一个新的 R 文件,并输入以下代码。确保您更改了下载的 csv 文件的位置,以便将其存储在适当的目录中:

library(data.table) 
library(arules) 

cms<- fread("~/cms2016_2.csv") # CHANGE THIS TO YOUR LOCATION OF THE DATA 

cols <- c("category","city","company","firstName","lastName","paymentNature","product") 

cms[ ,(cols) := lapply(.SD, toupper), .SDcols = cols] 

cms[,payment:=as.numeric(payment)] 

quantile_values<- quantile(cms$payment,seq(0,1,.25)) 
interval_values<- findInterval(cms$payment,quantile_values,rightmost.closed=TRUE) 

cms[,quantileVal:=factor(interval_values, labels=c("0-25","25-50","50-75","75-100"))] 

rules_cols<- c("category","city","company","paymentNature","product","quantileVal") 

cms[ ,(rules_cols) := lapply(.SD, factor), .SDcols = rules_cols] 

cms_factor<- cms[,.(category,city,company,paymentNature,product,quantileVal)] 

rhsVal<- paste0("quantileVal","=",c("0-25","25-50","50-75","75-100")) 

cms_rules<- apriori(cms_factor,parameter=list(supp=0.001,conf=0.25,target="rules",minlen=3)) 

cms_rules_dt<- data.table(as(cms_rules,"data.frame")) 
cms_rules_dt[, c("LHS", "RHS") := tstrsplit(rules, "=>", fixed=TRUE)] 
num_cols<- c("support","confidence","lift") 
cms_rules_dt[,(num_cols) := lapply(.SD, function(x){round(x,2)}), .SDcols = num_cols] 

saveRDS(cms_rules_dt,"cms_rules_dt.rds") 
saveRDS(cms_factor,"cms_factor_dt.rds") 

Shiny(R 代码)

在 RStudio 中,选择文件|新建文件|Shiny Web 应用程序:

app.R中输入以下代码:

# Packt: Big Data Analytics 
# Chapter 8 Tutorial 

library(shiny) 
library(shinydashboard) 
library(data.table) 
library(DT) 
library(shinyjs) 

cms_factor_dt<- readRDS("~/r/rulespackt/cms_factor_dt.rds") 
cms_rules_dt<- readRDS("~/r/rulespackt/cms_rules_dt.rds") 

# Define UI for application that draws a histogram 
ui<- dashboardPage (skin="green",    
dashboardHeader(title = "Apriori Algorithm"), 
dashboardSidebar( 
useShinyjs(), 
sidebarMenu( 
uiOutput("company"), 
uiOutput("searchlhs"), 
uiOutput("searchrhs"), 
uiOutput("support2"), 
uiOutput("confidence"), 
uiOutput("lift"), 
downloadButton('downloadMatchingRules', "Download Rules") 

         ) 
),dashboardBody( 
tags$head( 
tags$link(rel = "stylesheet", type = "text/css", href = "packt2.css"), 
tags$link(rel = "stylesheet", type = "text/css", href = "//fonts.googleapis.com/css?family=Fanwood+Text"), 
tags$link(rel = "stylesheet", type = "text/css", href = "//fonts.googleapis.com/css?family=Varela"), 
tags$link(rel = "stylesheet", type = "text/css", href = "fonts.css"), 

tags$style(type="text/css", "select { max-width: 200px; }"), 
tags$style(type="text/css", "textarea { max-width: 185px; }"), 
tags$style(type="text/css", ".jslider { max-width: 200px; }"), 
tags$style(type='text/css', ".well { max-width: 250px; padding: 10px; font-size: 8px}"), 
tags$style(type='text/css', ".span4 { max-width: 250px; }") 

         ), 
fluidRow( 
dataTableOutput("result") 
) 
       ), 
       title = "Aprior Algorithm" 
) 

# Define server logic required to draw a histogram 
server <- function(input, output, session) { 

  PLACEHOLDERLIST2 <- list( 
    placeholder = 'Select All', 
onInitialize = I('function() { this.setValue(""); }') 
  ) 

output$company<- renderUI({ 
datasetList<- c("Select All",as.character(unique(sort(cms_factor_dt$company)))) 
selectizeInput("company", "Select Company" ,  
datasetList, multiple = FALSE,options = PLACEHOLDERLIST2,selected="Select All") 
  }) 

output$searchlhs<- renderUI({ 
textInput("searchlhs", "Search LHS", placeholder = "Search") 
  }) 

output$searchrhs<- renderUI({ 
textInput("searchrhs", "Search RHS", placeholder = "Search") 
  }) 

  output$support2 <- renderUI({ 
sliderInput("support2", label = 'Support',min=0,max=0.04,value=0.01,step=0.005) 
  }) 

output$confidence<- renderUI({ 
sliderInput("confidence", label = 'Confidence',min=0,max=1,value=0.5) 
  }) 

output$lift<- renderUI({ 
sliderInput("lift", label = 'Lift',min=0,max=10,value=0.8) 
  }) 

dataInput<- reactive({ 
    print(input$support2) 
    print(input$company) 
    print(identical(input$company,"")) 

    temp <- cms_rules_dt[support > input$support2 & confidence >input$confidence& lift >input$lift] 

    if(!identical(input$searchlhs,"")){ 
searchTerm<- paste0("*",input$searchlhs,"*") 
      temp <- temp[LHS %like% searchTerm] 
    } 

    if(!identical(input$searchrhs,"")){ 
searchTerm<- paste0("*",input$searchrhs,"*") 
      temp <- temp[RHS %like% searchTerm] 
    } 

if(!identical(input$company,"Select All")){ 
      # print("HERE") 
      temp <- temp[grepl(input$company,rules)] 
    } 
    temp[,.(LHS,RHS,support,confidence,lift)] 
  }) 

output$downloadMatchingRules<- downloadHandler( 
    filename = "Rules.csv", 
    content = function(file) { 
      write.csv(dataInput(), file, row.names=FALSE) 
    } 
  ) 

output$result<- renderDataTable({ 
    z = dataInput() 
    if (nrow(z) == 0) { 
      z <- data.table("LHS" = '', "RHS"='', "Support"='', "Confidence"='', "Lift" = '') 
    } 
setnames(z, c("LHS", "RHS", "Support", "Confidence", "Lift")) 
datatable(z,options = list(scrollX = TRUE)) 
  }) 

}  shinyApp(ui = ui, server = server)

以下图像显示了代码被复制并保存在名为app.R的文件中。

为应用程序使用自定义 CSS 和字体

对于我们的应用程序,我们将使用自定义的 CSS 文件。我们还将使用自定义字体,以使应用程序具有良好的外观和感觉。

您可以从本书的软件存储库中下载自定义的 CSS 文件。

CSS、字体和其他相关文件应存储在名为www的文件夹中,该文件夹位于您创建 R Shiny 应用程序的目录中:

运行应用程序

如果一切顺利,您现在应该能够通过点击页面顶部的“运行应用程序”选项来运行应用程序,如下图所示:

单击“运行”按钮后,用户将看到一个类似下面所示的弹出窗口。请注意,浏览器中应启用弹出窗口才能正常运行。

该应用程序具有多个控件,例如:

  • 搜索 LHS/RHS:在规则的左侧或右侧输入您想要过滤的任何测试。

  • 支持:指示数据集中规则的普遍性。

  • 置信度:规则中有多少是精确匹配的。

  • 提升:定义规则重要性的变量。大于 1 的数字被认为是显著的。

只要它们以与 R 脚本部分中概述的方式类似的方式进行处理,您就可以将此应用于任何其他规则文件。

总结

机器学习从业者常常认为创建模型很容易,但创建一个好模型要困难得多。事实上,不仅创建一个“好”模型很重要,更重要的是知道如何识别“好”模型,这是成功与不那么成功的机器学习努力之间的区别。

在本章中,我们深入了解了机器学习中一些更深层次的理论概念。偏差、方差、正则化和其他常见概念都在需要时用例子解释了。通过附带的 R 代码,我们还学习了一些常见的机器学习算法,如随机森林、支持向量机等。最后,我们通过教程学习了如何针对 CMS OpenPayments 数据创建一个详尽的基于 Web 的关联规则挖掘应用程序。

在下一章中,我们将阅读一些在企业中用于大数据和机器学习的技术。我们还将讨论云计算的优点以及它们如何影响企业软件和硬件堆栈的选择。

第九章:企业数据科学

到目前为止,我们已经讨论了关于数据挖掘和机器学习的各种主题。大多数示例都是设计成任何使用标准计算机的人都能够运行它们并完成练习。在现实世界的情况下,数据集会比一般家庭使用中遇到的要大得多。

传统上,我们依赖于诸如 SQL Server、Oracle 等众所周知的数据库技术来进行组织数据仓库和数据管理。NoSQL 和基于 Hadoop 的解决方案的出现对这种操作模式产生了重大变化。尽管公司起初不情愿,但这些工具的普遍吸引力变得太大以至于无法忽视,今天,大多数,如果不是所有的大型组织都利用一个或多个非传统的当代解决方案来满足其企业数据需求。

此外,云计算的出现已经改变了大多数企业,内部数据中心正在迅速被基于云的基础设施所取代。云领域的主要市场领导者是亚马逊(亚马逊网络服务)、微软(Azure),在较小程度上是谷歌(谷歌计算引擎)。

数据仓库、数据科学和机器学习需求主要在这些平台上得到满足。

在本节中,我们将研究企业市场中流行的各种技术平台,它们的优势、用例和潜在的缺陷。此外,我们还将使用 AWS 完成一个教程,使用试用账户按需启动新实例。

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

  • 企业数据科学概述

  • 企业数据挖掘

  • 企业人工智能和机器学习

  • 企业基础设施

  • 其他考虑因素,如数据战略、治理和工具选择

  • 亚马逊网络服务教程

企业数据科学概述

数据科学在企业 IT 和分析方面是一个相对较新的话题。传统上,研究人员和分析师主要属于以下两类:

  • 使用复杂的计算语言和/或硬件进行专业任务的高度技术研究人员

  • 分析师可以使用诸如 Excel 和 BI 平台等工具来进行简单和复杂的数据分析

组织开始在 2000 年代末期研究大数据和更一般的数据科学平台。到 2013 年,Hadoop 和 NoSQL 平台等解决方案已经获得了巨大的动力。以下表格显示了数据科学的发展:

年份 发展
1970 年代至 20 世纪 90 年代末 广泛使用关系数据库管理系统。实体关系模型、结构化查询语言(SQL)和其他发展最终导致了 90 年代末数据库的快速扩张。
2000 年代初 Y2K 的反高潮,尽管代价高昂,但并未发生,再加上互联网泡沫的破裂导致了停滞期。在数据库方面,或者更一般地说,数据挖掘平台,这意味着公司不再像关注新的创新那样,而是更关注保持业务的运行。

| 2005-2010 | 该行业缓慢复苏,但直到 2005 年才开始出现新的发展。一些值得注意的事件包括:

  • 2006 年:GoogleBigTable 论文发表

  • 2006 年:亚马逊网络服务云平台推出

  • 2007 年:亚马逊 Dynamo 论文发表

  • 2008 年:Facebook 开源 Cassandra

  • 2009 年:MongoDB 发布

  • 2009 年:Redis 发布

|

2010-2012 2010 年:NoSQL 会议和相关活动开始变得流行,NoSQL成为一个普遍接受的技术术语。与此同时,Hadoop 变得广泛流行,几乎所有主要公司开始实施与 Hadoop 相关的技术。2011 年:市场领导者开始采用大数据并制定大数据战略。大量声称大数据巨大潜力的文章和研究论文使其非常流行。麦肯锡发表了一篇关于大数据的论文,并称其为创新、竞争和生产力的下一个前沿。2012 年 10 月的《哈佛商业评论》刊登了一篇对数据科学家的非常积极的展望,这立即变得流行起来。
2013-2015 大数据技术的增长导致了一个称为数据科学的概念的发展,这将焦点从仅仅是数据转移到了数据的价值。再加上机器学习的发展以及 R、Python 和其他面向数据科学的平台的流行,行业的关注重点转移到了从数据中获取洞察,而不仅仅是管理数据。机器学习成为了新的热门词汇。
2016- 智能设备、可穿戴设备、AI 手机、自动驾驶汽车等创新解决方案的发展为现有的大数据和机器学习趋势增加了人工智能的新组成部分。制造商开始广泛宣传技术解决方案的智能能力,而不仅仅是机器学习能力。

实施大数据平台或者更一般地说,大数据倡议的责任通常由公司的 IT 或分析部门负责,如果这样的部门存在的话。

在对组织中的大数据和数据科学代表进行的一般调查中,我们观察到,在大多数情况下,首席信息官或首席数据/数字官负责企业大数据战略,如下图所示:

尽管分析和 IT 团队发挥了重要作用,但毫不奇怪,最终责任被委托给了公司的 C 级管理层。

企业对大数据的投资也各不相同,大多数组织的投资额在 10 万到 100 万美元之间。对中大型组织的分析产生了预期的结果。然而,显而易见的是,几乎所有受访者至少在大数据方面进行了一些投资

大多数组织还报告了对高级分析的企业要求。这有助于获得所需的预算来实施和推进组织内的分析水平。

此外,对数据科学收入潜力的预测预测极大地帮助了向高级管理层论证,即适当的大数据投资对公司未来的增长至关重要。

当前,大数据和业务分析的收入已经呈指数级增长,超过 1500 亿美元,这给企业实施这种能力带来了巨大压力。

组织对大数据作为企业要求的认识和接受的另一个方面是对这种工具效用的文化认知。在对大型公司的 C 级管理层进行的调查中,大多数受访者表示他们的部门经理正在使用分析,但并不是所有部门都有统一的参与水平,如下图所示:

此外,大数据在整个组织中的合作策略似乎也没有达到商业成功所需的程度。调查的受访者表示,合作,即分析倡议的跨职能部门协作,定义不够明确:

虽然对一些问题的回答有所偏颇,其中一个类别占压倒性多数,但关于大数据和分析在组织中的挑战的反馈总体上有着广泛的一致意见。以下图表显示了调查中每个参与者对分析挑战的反馈:

所有这些都导致企业中一个有趣但矛盾的分析困境。尽管大数据和分析的价值被广泛理解和接受,但在适当的方法上存在一种模糊感,如下图所示:

企业分析成功的路线图

根据我们的经验,与数据仓库等既定术语相比,分析是一个相当新的术语,需要谨慎的方法,以确保即时成功和随后的倡议长期成功。

过早尝试通过大规模、高预算的参与来完成初始分析项目的项目,如果项目结果不如预期,可能会危及整个倡议。

此外,在这类项目中,结果措施并不明确定义。换句话说,衡量结果的价值是模糊的。有时,它也无法量化。这是因为分析倡议的成功带来的好处不仅仅是即时的货币或技术能力。成功的分析项目通常有助于增强高管对部门进行此类项目的信心,从而可能导致更大的努力。

与大数据分析相关的一般挑战如下:

  • 几乎每家公司都在投资大数据、机器学习和人工智能

  • 通常,公司都有一个企业命令

  • 找到合适的使用案例可能是具有挑战性的

  • 即使找到它们,结果可能是不确定的(这会引起共鸣吗,需要多长时间等)

  • 即使实现它们,是否已经确定了最佳目标可能是难以捉摸的(例如,当使用 HDFS 仅用于存储数据时)

现在,让我们看一些数据科学和分析倡议的一般指导原则

  • 与组织中的业务合作伙伴进行会议和一对一审查,审查他们的工作流程,并就分析和/或数据挖掘可以提供最大价值的地方征求反馈

  • 确定业务运营的具体方面是重要的,并与公司的收入流相关;一旦完成,使用案例将产生可衡量的影响

  • 使用案例不必是复杂的;它们可以是简单的任务,比如机器学习或数据挖掘

  • 直观,易于理解,可以向朋友和家人解释

  • 理想情况下,使用案例需要通过传统手段来完成今天的努力。解决方案不仅应该使一系列用户受益,而且还应该具有高管可见性

  • 确定低难度 - 高价值短期)与高难度 - 高价值长期)使用案例

  • 教育业务赞助商,分享想法,表现热情(就像一次长时间的面试)

  • 低难度 - 高价值得分早期胜利,创建最小可行解决方案,并在进一步增强使用解决方案之前让管理层接受(需要时间)

早期胜利作为一种催化剂,a)增强高管信心,b)也使得更容易证明预算,从而更容易转向高难度 - 高价值任务。

最后两点很重要,因为有必要确定低难度 - 高价值项目。这可能是对经验丰富的从业者来说看起来基本的任务,但对最终用户非常有价值。

一家大型企业组织中的分析团队的一位高管曾经说过,该年度最成功的项目是更改电子邮件报告的时间。将报告的发送时间从早上改为下午晚些时候。似乎在更改时间后,与报告的互动变得更加活跃。早上的日程安排往往非常忙碌,而另一方面,下午的报告为接收者提供了更轻松的时间来审阅报告。

一些 难度潜在价值很高的项目示例可能包括:

  • 通过组合开源工具和数据库,自动化业务组频繁进行的手动任务;例如,可以轻松使用组合开源工具和数据库自动化在 Excel 中创建的报告。

  • 使用编程脚本将手动股票分析转换为自动化版本。这可能涉及任务,如创建常规表、数据透视表和图表,这些都是在 Excel 中创建的,但可以转换为自动化流程。

  • 使用 R Shiny 为业务应用创建 Web 界面,并实施预测分析功能。

  • 将 IT 基础设施的某些部分迁移到云平台。这可能看起来违反直觉,特别是如果组织不习惯在云环境中工作。然而,管理云部署的简单性和便利性可能意味着总体拥有成本和运营开销的减少。

使用情况的最终选择将取决于各种因素,前面提到的情况旨在提供可能尝试的项目类型的大致概念,以及可能产生积极结果的工作流程。在下一节中,我们将查看行业中用于数据科学的一些特定软件和硬件解决方案。

企业中的数据科学解决方案

如前所述,一般来说,我们可以将数据科学大致分为两个主要部分:

  • 企业数据仓库和数据挖掘

  • 企业数据科学:机器学习、人工智能

在本节中,我们将分别查看每个,并讨论行业中用于提供这些功能的软件和硬件解决方案。

企业数据仓库和数据挖掘

今天,行业中有大量数据库可用,它们被宣传为能够运行复杂分析查询的 NoSQL 系统。它们中的大多数都具有典型 NoSQL 系统的一个或多个特性,如列式、内存、键值、面向文档、基于图形等。下一节将重点介绍今天使用的一些关键企业 NoSQL 系统。

传统数据仓库系统

传统数据仓库可能是一个误称,因为大多数传统系统也已经融合了 NoSQL 的核心概念。然而,在这种情况下,这个术语旨在指示在 NoSQL 系统出现之前就存在的数据库,并且还添加了使它们符合企业数据科学要求的功能。

Oracle Exadata、Exalytics 和 TimesTen

Oracle Exadata、Exalytics 和 Exalogic 属于 Oracle 的 Exa 产品系列。Exadata是 Oracle 的高性能工程化数据库平台,专为资源密集型查询而设计。一般来说,它预计将显着改善非 Exadata 系统的查询性能,并支持高级软件功能,如内存计算、独立行和基于列的过滤,以及其他硬件功能,如支持最新的存储设备,包括 NVMe,在内存容错等。

Exalytics是一个旨在主要用于BI工作负载的补充解决方案。Exa 产品系列被认为是工程系统,而不是设备。后者可能表示预设和预装的软件-硬件堆栈,而工程系统预计将支持更高级别的灵活性,以选择安装的组件,这些组件根据客户需求进行选择安装。在企业安装中常见的 Exalytics 的关键组件之一是OBIEEOracle Business Intelligence Enterprise Edition)。这是一个完整的 BI 套件,并且受益于名为Times Ten的基础内存数据库,这也是 Exalytics 生态系统的一部分。

业务用例:Oracle Exadata 用于 OLTP 事务工作负载,速度和性能至关重要。

另一方面,Exalytics 用于分析工作负载。集成的 OBIEE 界面与 TimesTen 一起提供了一个紧密耦合的分析环境。Oracle Exadata 也可以作为基于云的服务提供。

HP Vertica

HP 的 Vertica 是一个面向列的、大规模并行处理的数据库系统,具有诸如支持数据库机器学习和本地集成到开源系统(如 Apache Kafka 和 Apache Spark)等关键软件特性,并且通常部署在多节点硬件架构上。Vertica 支持流行的云环境,如亚马逊网络服务AWS)、Google 和 Azure。Vertica 支持标准的交互式 SQL 界面,因此可以轻松与大多数当代 BI 工具兼容。

有趣的是,HP Vertica 是少数几个也作为社区版提供的企业数据库之一。这意味着对于有兴趣尝试 Vertica(在其许可范围内)或者只是想更多了解该平台的用户,可以利用社区版,可以从 HP Vertica 的网站免费下载。

业务用例:与本节中指示的其他数据库类似,Vertica 包含几个显着特性,如数据库处理、并行处理能力等。Vertica 支持各种分析工作负载,并附带相关的商业许可费用(与所有其他商业数据库产品一样)。社区版的可用性,以及 HP 在大多数情况下愿意进行大规模部署的概念验证,为企业提供了充分的机会,以在做出决定之前尝试和测试具有公司特定用例的平台。

Teradata

Teradata 被广泛认为是企业数据库技术的领导者。它的数据库,也被称为同名,与其他竞争对手产品共享一些相同的特性。Teradata 的一些关键特性包括与许多开源解决方案的本地集成,如 R、RStudio、Jupyter 和 SAS;时间序列支持;内置的用于机器学习和人工智能的分析函数;支持各种数据类型,如 CSV、JSON 和文本,以及空间/时间数据。

分析平台,也被称为 Aster Analytics,可以作为社区版从aster-community.teradata.com/community/download下载。

传统上,Teradata 是作为设备解决方案提供的,即数据库和硬件都作为单个集成单元提供,但如今也可以使用 Teradata Everywhere 在云中使用 Teradata。该软件可以在混合架构(既在本地又在云中)以及在 AWS 和 Microsoft Azure 等公共云环境中部署。捆绑服务、基于订阅的服务以及即服务选项都是可用的。Teradata Intellicloud 是 Teradata 提供的基于订阅的云产品,其中包括 Teradata 生态系统中的几种产品在托管环境中。

业务用例:Teradata 是几十年来备受企业青睐的数据库,并且在大型组织中具有很强的信誉。近年来,Teradata 积极与开源系统(如 R、Jupyter 和其他产品)进行整合,使其更具吸引力,可以说有助于提高其知名度。Teradata 设备可能相对昂贵,并且与其他商业选项一样,需要适当的 POC 来评估其对组织特定用例的适用性。

IBM 数据仓库系统(前身为 Netezza 设备)

IBM Netezza 过去是作为单独的数据仓库设备销售的,在某种程度上类似于 Teradata 的营销方式。最近,Netezza 已被移至更广泛的 IBM 数据仓库系统分类下,更符合当代大数据管理非常大数据量的需求。IBM Pure Systems、PureSystems for Analytics 和 IBM Integrated Analytics System 是一些提供与 Netezza 基本相同功能的新解决方案,它们在一个集成的生态系统中提供。

集成分析环境包括嵌入式 Apache Spark 用于机器学习,Jupyter 笔记本用于数据科学工作负载,一个通用的 SQL 引擎,可连接到其他 NoSQL 和 Hadoop 实现,并支持在高性能架构上部署,可选择托管的云环境

业务用例:Netezza 一直受到那些传统上对 IBM 相关技术(如 DB2、AIX 和其他 IBM 产品)有很强依赖的公司的青睐。新的集成产品环境为现有 IBM 投资增加数据科学能力提供了机会。

PostgreSQL

在本节中,PostgreSQL 是一个有趣的选择,因为从技术上讲,PostgreSQL 没有单独的 NoSQL 版本,而是在最近的发布中添加了各种功能,为现有的 Postgres 实现增加了 NoSQL 功能。

PostgreSQL 的支持者正确指出,它是一种更古老、经过测试的技术,最早在 1990 年代中期发布。Postgres现在支持分层文档数据存储、JSON、键值存储(称为HStore)和分片,并包括各种编程语言的接口以及多样的数据源。换句话说,PostgreSQL 已经扩展以支持类似 NoSQL 的功能,同时保持其作为传统关系数据库管理系统的现有功能。

PostgreSQL 可作为功能齐全的开源产品使用。

业务用例:尽管本节中的大多数技术都可以通过商业许可获得(以获取其所有功能),但由于其开源特性,PostgreSQL 是尝试成熟数据库的一种非常具有成本效益的方式,而无需进行大额初始投资。它还可以作为尝试 NoSQL 功能的测试平台,例如在最终决定之前处理 JSON 数据。在任何情况下,PostgreSQL 都是一个强大的平台,可以支持企业需求。还有一些基于 PostgreSQL 构建的商业衍生产品,例如 Greenplum,也可以作为开源产品使用。

Greenplum

Greenplum Database®是建立在 PostgreSQL 之上的,并添加了许多重要的分析功能。这些功能包括创新的基于成本的查询优化器,与 Apache MADlib 的集成,以及行或列存储的选择。它具有流行编程语言(如 R、Python 和 Java)的本机接口,并支持大规模并行架构。可以免费从greenplum.org/download/下载 Greenplum。

业务用例Pivotal提供了具有全面支持的 Greenplum 商业发行版。Greenplum 非常成功,其中一个原因是它已经被证明在大型企业工作负载方面具有出色的性能。商业支持的可用性对于需要专门支持和服务级别协议(SLA)以保证关键业务运营的组织非常有益。

SAP Hana

SAP Hana 是 SAP 推出的一款列存储、内存数据库,支持 NoSQL 功能。Hana 支持多核并行操作、多租户,并且完全符合ACID,可以处理各种分析工作负载,包括预测建模、流式分析、时间序列分析以及空间、文本和基于图形的分析。您还可以在 SAP Hana 系统中管理基于 JSON 的非结构化数据。

Hana 还可以与其他 SAP 产品(如 SAP Fiori)原生配合使用,后者包括在人力资源、财务、会计和其他部门中使用的各种 SAP UX 应用程序。

业务用例:SAP 几十年来一直是企业组织的主力军,并且被用于各种应用,尤其是制造和财务/会计需求。SAP Hana 为现有的 SAP 安装增加了一个强大的高性能数据库。一般来说,由于企业级部署涉及高昂的成本,SAP 主要用于业务关键需求。对于依赖于 SAP 的大型组织来说,Hana 的好处可能会超过成本。此外,虽然 Hana 可以提供各种 NoSQL 功能,但公司可能会发现他们将基于预算、性能需求和其他因素最终使用两种或更多不同的解决方案。

企业和开源 NoSQL 数据库

前一节概述了一些已知的传统数据库/RDBMS 解决方案,这些解决方案已经增加了企业级 NoSQL 功能。接下来的部分将介绍一些特定于数据库解决方案的更为专业的业务用例。

kdb+

Kx Systems 的kdb+是高频交易和其他类似环境中使用了近 20 年的最快、最高效和最轻量级的数据库之一。它在金融领域之外的知名度要低得多,但可以说它是世界数据库领域中设计和优化效率最高的系统之一。

kdb+从一开始就支持内存列存储,技术上是q编程语言的扩展。kdb+中的表本质上是 q 语言中的数据结构。然而,与其他编程语言中类似概念不同,kdb+表是企业级的,可以轻松处理 TB 和 PB 级别的数据。

由于其固有的编程语言,用 q 编写的代码可以针对存储在 kdb+中的数据运行,因此可以非常轻松地在数据库中运行自定义函数

此外,kdb+二进制文件的大小约为 500 到 600KB,足够小,可以适应大多数现代 CPU 的 L3 缓存。

kdb+还包括内置的 MapReduce 功能,使查询可以自动在多核 CPU 上并行执行。

业务用例:Kdb+是企业设置中存在的最强大的数据库之一。传统上只能通过永久的基于核心的许可证获得,但最近,该公司已经增加了对基于订阅和按需许可的支持。其低占用空间和简单易用性使其非常适合企业需求。然而,这也带来了一个警告。q 语言非常简洁,对新用户可能显得晦涩。可以说,与其他语言相比,该语言的学习曲线略陡,并且需要实践和第一手经验。尽管如此,有丰富的在线资源可供学习和利用数据库的功能。用于 R、Python、C、Java 和其他编程语言的本机接口,以及用于机器学习的库,使其特别适合涉及大型数据集的数据科学工作负载。

尽管 kdb+不是开源产品,但通常可以免费个人使用:kx.com/download/

MongoDB

MongoDB是文档导向数据库领域的市场领导者,用于以 JSON 格式存储数据。它支持按需查询、索引和聚合,并且具有丰富的 Python、Java 和 JavaScript 等语言的接口。其他功能,如水平扩展和分片、高可用性、名为 Compass 的集成数据探索工具等,增加了数据库的现有功能。

业务用例:考虑用于存储非结构化或半结构化数据的数据库的公司可能会发现 MongoDB 的特性非常适合查询这些数据集。该数据库不需要在开始时定义固定的模式,使其灵活且可扩展,以支持添加到现有数据中的新属性。MongoDB 可从www.mongodb.com/download-center免费下载,并且还可以通过 MongoDB Atlas 作为托管和托管的云解决方案实施。还提供了支持诸如内存和加密存储等功能的企业版,可按订阅方式使用。

Cassandra

Cassandra是最成功和广泛使用的企业 NoSQL 系统之一。它结合了列式和键值概念,并将数据存储在基于行的分区中。每个分区又是一个主键。行可以有多个列,每行的列数可能不同。

Cassandra 数据库可以通过 CQL 进行查询,CQL 使用类似 SQL 的语法,使数据查询、保存和其他常见任务的过程更加简单。Cassandra 还使用分散式架构;它没有任何单点故障,并支持多节点架构。

除了 Cassandra DBMS 的标准水平可扩展性外,该平台还支持弹性可扩展性,并且能够根据需要透明地分配和取消分配节点。总的来说,Cassandra 是企业 NoSQL 系统中最强大的选择之一,并且在全球多个大型公司的生产环境中使用。

业务用例:Cassandra 是一个完全开源的解决方案,实现了 NoSQL 系统的多个关键特性。它在全球生产工作负载中被广泛使用,并已经发展成一个稳定、企业级的开源平台。换句话说,Cassandra 非常适合管理大型组织的需求,并且不会产生额外的许可成本。Datastax 也提供了商业、许可和付费版本的 Cassandra:www.datastax.com/products/datastax-enterprise。它被称为DSEDatastax Enterprise)。DSE 集成了各种企业功能,如安全性和搜索,并且还可以通过 Datastax 托管的云环境使用流行的云提供商如 AWS。

Neo4j

Neo4j是一种基于图形的数据库,用于建模不同实体之间的关系。该数据库使用图论中熟悉的概念来创建基于树的表示(具有节点和关系)的相互连接的主题。它最常与推荐引擎一起使用。在概念上,Neo4j 图数据库可以将个体表示为节点,这些节点通过它们的分离程度相互连接。这理论上允许最终用户追踪任意节点之间的分离程度或一个个体到另一个个体之间的分离程度。

Neo4j 平台提供了各种基于图形的表示,如加权、有向、单向和标记。

业务用例:需要进行深入的客户级或用户级分析的公司,如社交网络或推荐系统(如 Netflix),部署基于图形的数据库如 Neo4j 将获得巨大的好处。如今,该平台支持人工智能和机器学习、物联网、实时推荐等许多在企业中使用的有用特性。

尽管 Neo4j 可以作为开源软件从neo4j.com/download/?ref=hro下载,但也有一个商业许可版本,称为 Neo4j 企业版。

云数据库

云数据库,顾名思义,是指来自云供应商如亚马逊、谷歌和微软的数据仓库或数据库系统。

亚马逊 Redshift、Redshift Spectrum 和 Athena 数据库

最常用的基于云的数据仓库平台之一是亚马逊 Redshift。它是云生态系统中数据管理的最重要平台。它基于 PostgreSQL,主要用于分析工作负载。Redshift 具有高度可扩展性,并且相对于具有类似特性的本地数据库,需要的工作量明显较少。可以直接从 AWS 控制台部署(在注册 AWS 账户后)。可以通过 AWS 控制台无缝地添加或删除节点,以相应地增加或减少容量。

Redshift 的一个较新的版本称为Redshift Spectrum允许查询存储在亚马逊 S3 中的数据,这是 AWS 的标准存储层。这意味着用户可以直接查询存储在磁盘上的数据,而无需将其加载到 Redshift 特定的实例中。总体而言,Redshift 相对快速、价格低廉,更重要的是易于使用和部署。Redshift Spectrum 采用按查询付费模式——用户只需为执行的查询付费,每扫描一 TB 的数据收取一定费用。

Amazon Athena在许多方面类似于 Amazon Redshift Spectrum,因为它也用于查询存储在 S3 上的数据。然而,与 Amazon Redshift Spectrum 的功能不能在未购买 Amazon Redshift 的情况下使用不同,用户可以按需利用 Amazon Athena,并且无需预留任何额外的硬件。另一方面,因为 Amazon Redshift Spectrum 与 Redshift 生态系统紧密集成,用户可以在这两个解决方案中分配其工作负载。需要更快处理的数据可以保留在 Amazon Redshift 上,而较少使用/不太关键的数据可以存储在 S3 上,并使用 Redshift Spectrum 进行查询:

您可以在aws.amazon.com/redshift/spectrum/了解更多关于 Amazon Redshift Spectrum 的信息。

谷歌 BigQuery 和其他云服务

谷歌 BigQuery类似于 Amazon Redshift,它也是一个完全基于云的大规模数据仓库系统。然而,Redshift 需要单独的配置(AWS 集群和 Redshift 资源),而谷歌 BigQuery 是同样的即插即用等效产品。要使用 BigQuery,用户只需在bigquery.cloud.google.com创建一个帐户,并在加载数据集后开始运行查询。

与 Redshift 相比,BigQuery 的计费方式也有很大不同。用户每月可以免费查询累计 1TB 的数据。BigQuery 采用按使用量付费的模式,查询具有分配的成本。实质上,BigQuery 抽象了设置数据库的复杂性,使最终用户能够专注于编写查询和/或执行分析,而无需设置基础架构。因此,扩展查询、分配资源以及可能需要手动干预的任务(例如由 DBA 执行)都变得多余。

谷歌云平台上还有一系列其他 NoSQL 产品,包括谷歌云数据存储,一个基于文档的 NoSQL 数据库;谷歌 BigTable;谷歌 Spanner;以及其他一些产品。以下图显示了谷歌 BigQuery 数据库:

Azure CosmosDB

Azure CosmosDB是微软的 NoSQL 云数据库之一。Azure 中的其他 NoSQL 系统包括表存储、Azure Redis 缓存等。CosmosDB 被认为是一种多模型数据库;它可以支持键值对、基于文档的查询、基于图形的模型,以及关系数据库查询。

传统的微软数据库,比如 SQL Server 也可以在 Azure 平台上作为完全托管和托管解决方案使用。您可以在azure.microsoft.com/en-in/services/cosmos-db/了解更多关于 Azure 平台的信息。以下图显示了微软 Azure 平台的解决方案窗口:

GPU 数据库

GPU 数据库是近期发展的产物,随着用于数据科学相关任务(如机器学习)的图形处理单元卡的增长而出现。当查询可以并行化时,GPU 的工作效果最佳。这是因为 GPU 包含数千个核心。通过将每个核心委派给数据的一个小子集来工作,GPU 通常可以以令人印象深刻的快速速率进行计算,远远超过基于 CPU 的查询性能。

Brytlyt

Brytlyt是 GPU 数据库领域的新进入者。它配备了一个名为Spotlyt的可视化产品。早期测试表明 Brytlyt 超越了一些具有挑战性的基准。然而,它在其他用例中的泛化效果有待观察。

Brytlyt 在亚马逊 AWS 市场(aws.amazon.com/marketplace/pp/B074JZNSWZ?qid=1513342415797&sr=0-1&ref_=srh_res_product_title)上可供尝试。

MapD

MapD是早期开发商之一,开发了商用 GPU 数据库平台。与 Brytlyt 类似,它也展示了令人印象深刻的早期结果。然而,由于基于 GPU 的数据库仍处于早期阶段,流行的使用和采用最终将决定它们是否会成为企业中的常见现象。

基于 GPU 的数据库的主要挑战之一是需要正确配置基于 GPU 的系统。这可能需要专门的技能,因为使用 GPU 卡进行计算与使用 GPU 卡进行常见任务(如渲染图像)是完全不同的。因此,希望在采用正式版本之前尝试基于 GPU 的数据库的用户会发现,在 AWS 中利用预配置的镜像(AMI 镜像)更容易,这将需要最少的系统配置。

其他常见的数据库

还有其他各种类型的数据库,例如用于分析流数据的数据库(Amazon Kinesis),以及使用百度的专用加速卡处理数据的数据库。

企业数据科学 - 机器学习和人工智能

数据科学解决方案在过去的 4-5 年里迅速成熟,类似于数据科学其他领域的发展,如 NoSQL、Hadoop 和其他数据挖掘解决方案。尽管许多先前的数据库系统也包含了数据科学的关键特性,如机器学习等,但本节重点介绍了一些主要用于机器学习和/或人工智能的高级解决方案,而不是数据管理。

事实上,大数据产品和数据科学产品之间的区别变得模糊,因为最初用于大数据处理的产品已经融合了数据科学的关键特性,反之亦然。

R 编程语言

R,正如我们在之前的章节中所看到的,最初是为统计编程而设计的环境。它起源于新西兰大学的一个项目,Ross IhankaRobert Gentleman将 R 开发为 S 编程语言的一个变体,S 编程语言是由贝尔实验室的 John Chambers 开发的。尽管 R 最初是为统计编程而设计的,但在过去的 7 到 8 年里,它已经发展成为一个成熟的、多方面的语言,增强了对相关学科的支持,如机器学习、高性能计算、可视化、计量经济学、时间序列分析等。其中一些领域也在cran.r-project.org/web/views/上附有相关信息。

Revolution Analytics 提供了一个带有企业支持的 R 商业版本。2015 年,它被重新命名为Microsoft R Open(开源版本)和Microsoft R Server(商业版本)。

尽管以微软品牌推广,但请注意,Microsoft R 也适用于 Linux 和 Mac OS。

R 中流行的机器学习包括e1071randomForestgbmkernlabarules等。这些列在cran.r-project.org/web/views/MachineLearning.html上。另一个流行的包叫做 caret,它作为各种算法包的包装器,并提供了一个有用的统一接口,可以运行算法,而不必符合各个包的细微差别。

R 还通过multicoredoMC等包支持多核编程。这些列在cran.r-project.org/web/views/HighPerformanceComputing.html上。

Python

Python 中的scikit-learn包可以说是所有平台中最全面的机器学习包,其中包含了大量的机器学习算法。与 R 相比,它被认为速度更快,并且是各种企业组织的首选工具。以下截图显示了我们可以下载scikit-learn包的网页:

Python 的商业支持企业版本是Anaconda,它预先配置了有用的机器学习和数据挖掘包,可从 Continuum Analytics 获得。名为Anaconda Cloud的云版本允许新用户开始利用 Anaconda Python 的功能,而无需单独下载和安装它。

OpenCV、Caffe 等

图像识别是机器学习中更成功的领域之一。虽然大多数机器学习任务需要相对长的时间才能衡量和量化它们的真正好处,但图像识别是一个熟悉的主题领域,可以很容易地理解。实质上,它涉及识别对象并正确分类它们。它有多种应用,从识别车牌号码到人脸识别,可在移动设备和机器人中使用。

OpenCV 为各种图像识别任务提供了标准接口,并且还可以利用硬件加速功能来优化性能。

其他知名的用于图像处理的机器学习软件包括 Caffe、cuDNN、TensorFlow 等。请注意,这些包不仅限于简单的图像识别,还可以用于其他深度学习用例。

Spark

Spark 中的 MLlib 库提供了各种机器学习算法的正式实现,可在 Spark 平台中使用。pySpark 的可用性使得对具有 Python 编程知识的人来说更容易使用这些功能。如果组织已经有现有的 Spark 平台,值得探索 MLlib 中的机器学习能力。

以下截图为您提供了 MLlib 的简要概述:

深度学习

具有多个隐藏层(通常超过两个)和/或节点的神经网络通常被归类为深度学习。机器学习的一些当代进步,如自动驾驶汽车,直接是深度学习在实际日常任务中的应用的结果。

有各种深度学习框架/包,一些著名的包括:

  • TensorFlow

  • cuDNN

  • Theano

  • Torch

  • 百度的 PaddlePaddle

H2O 和 Driverless AI

作为 Kaggle 竞赛的热门平台,H2O提供了一个大规模可扩展的实时机器学习界面,具有 R、Python、Spark 等的本地集成。可以免费从www.h2o.ai/h2o/下载。

Driverless AI是 H2O 产品线的最新成员。它旨在通过实现自动化界面来使机器学习对从业者更容易,该界面尝试通过自动方式创建模型并优化准确性,通过构建和评估多个模型来实现。以下截图显示了 H2O 平台的主页:

Datarobot

在概念上,Datarobot 与 H2O 的 Driverless AI 类似,它也尝试通过创建和评估多个模型来自动构建机器学习模型。

然而,与 H2O 不同,尽管它可能非常强大,Datarobot 需要支付许可费,对于较小的公司来说可能会很昂贵。

命令行工具

有多个机器学习工具可以在 Unix 命令行上执行。对于其中一些工具,R、Python 和其他语言已经存在接口,允许用户利用它们的功能,而无需从 Unix 终端使用它们。一些流行的命令行实用程序包括:

  • LIBSVM

  • LIBLINEAR

  • Vowpal Wabbit

  • MLPACK

  • libFM

Apache MADlib

Apache MADlib是一个鲜为人知但功能丰富的平台,旨在在数据库中执行分析和运行算法,也就是说,它可以在本地执行函数,而无需外部编程接口。它支持并行处理,并且可以与 Greenplum、PostgreSQL 等多个数据源无缝配合。

例如,可以通过简单运行 SQL 命令来创建一个 apriori 模型,如下所示,来自madlib.apache.org/docs/latest/group__grp__assoc__rules.html:

SELECT * FROM madlib.assoc_rules(.25,            -- Support 
                                  .5,             -- Confidence 
                                  'trans_id',     -- id col 
                                  'product',      -- Product col 
                                  'test_data',    -- Input data 
NULL,           -- Output schema 
                                  TRUE            -- Verbose output 
); 

有关 Apache MADlib 的更多信息(下面显示了网站的截图)可在madlib.apache.org.找到。

机器学习即服务

与其他云资源集成的基于云的机器学习平台也在不断增加。一些知名的平台包括 AzureML、BigML、IBM Watson 等。

下面的截图来自 IBM Watson,这是一个最知名的机器学习和人工智能平台。该平台在 2011 年赢得 Jeopardy 冠军后声名鹊起[来源:www.techrepublic.com/article/ibm-watson-the-inside-story-of-how-the-jeopardy-winning-supercomputer-was-born-and-what-it-wants-to-do-next/]。当时,机器学习趋势处于萌芽阶段,Watson 是第一个让世界大吃一惊的 AI 技术之一。它证明了 AI 可以是强大和有能力的资产。今天,用户可以通过在该网站上注册账户来利用 IBM Watson 的一些相同的计算能力www.ibm.com/watson/

企业基础设施解决方案

正确的基础设施选择也在决定组织数据科学平台的效率方面发挥关键作用。太少的话,算法执行时间会太长;太多的话,可能会有很多资源闲置。因此,后者比太少更可取,因为太少会阻碍进展,影响任何机器学习研究人员有效执行任务的能力。

云计算

在过去的 5-7 年里,组织逐渐将资源转移到云平台,如 Amazon Web Services、Microsoft Azure 和 Google Compute Engine。今天,所有这些平台都包含非常复杂和广泛的架构,以支持企业级的机器学习、数据挖掘和一般数据科学,以满足各种规模组织的需求。

此外,images的概念,比如 Amazon 的 AWS 中的 AMI images,允许用户启动一个预先构建的 OS 快照,带有预安装的组件。因此,用户几乎可以完全避免在尝试新平台之前的设置开销。

Hadoop 和 map-reduce 操作在 AWS 中也得到了广泛支持。AWS 中的EMRElastic Map Reduce,以及 Azure 中的 HDInsight,是两个知名且非常受欢迎的大数据框架。

本章末尾的教程将演示如何设置 AWS 账户并开始使用一个示例 AMI Image。

虚拟化

虚拟化——在更大的主机内创建隔离的、自包含的环境的过程,使组织能够 consolodate 服务器并大幅减少数据中心的占地面积。例如,如果一个组织为他们的网站利用了六台服务器,其中有两台经常被利用,而其他的大部分时间负载较低,可能可以将所有服务器合并到一台或两台服务器上。在这方面,戴尔 EMC 的技术,如 VxBLOCK,是在物理数据中心中使用的知名企业虚拟化硬件。这也使公司能够创建自己的私有云基础设施。然而,这可能相当昂贵,并需要对成本效益比进行适当评估。

Openstack 是用于创建公共和私有云的开源软件。它是一个企业级生态系统,具有多种产品,可以在 Openstack 平台内无缝运行。有关 Openstack 的更多详细信息,请访问www.openstack.org:

用户可能熟悉 Oracle Virtualbox,它本质上也是一种虚拟化软件,允许用户创建隔离的环境。这使用户可以在 Windows 中运行 Linux,反之亦然。

专门的软件或硬件,称为 hypervisors,用于管理和管理虚拟机。

容器——Docker、Kubernetes 和 Mesos

容器和虚拟化一样,创建了隔离的客户系统,但是,虚拟机创建了一个完全独立的环境,而容器与主机系统共享相同的内核,因此被认为更接近硬件。虚拟化和容器都因为在主机和客户操作系统之间的功能转换而产生性能损失。然而,总体而言,容器的性能水平更高,因为它们依赖并直接使用客户操作系统的特性,而不是创建一个单独的操作系统生态系统。

流行的容器包括 Docker、CoreOS 等。今天,容器主要用于大规模管理与网络相关的服务。容器可以根据需要更容易地启动和关闭,比虚拟机更容易,流行的云提供商已经为容器添加了专门的支持,使得用几行代码就可以轻松启动数千个容器来处理网络请求。像 Kubernetes 这样的编排软件提供了企业级的容器管理能力。此外,像 Mesos 这样的平台不仅提供了管理容器的支持,还增加了管理其他传统硬件的能力,用于应用感知调度和其他服务:

本地硬件

最后,传统数据中心等本地硬件在现代计算中仍然有一席之地。使用物理数据中心,用户不必为基于云的服务支付重复费用。对于没有大量行政开销的中小型组织,或者不需要高性能/专门计算能力的组织来说,本地系统完全能够提供成本效益高、永久的解决方案。

像 ScaleMP 这样的公司提供用于高性能计算的专门硬件。这类硬件的消费者通常有无法由基于云的供应商提供的特定要求:

下面总结了本地和基于云的系统之间的一些区别:

本地
拥有硬件 租用硬件
需要全面维护 维护由云托管提供商管理
需要 IT 资源来管理计算硬件资源 在管理计算硬件资源方面的开销要少得多,因为可以根据需求在云中添加
对于中小规模环境来说成本效益高,没有或很低的数据中心运营成本 对于希望简化数据中心运营成本的大型组织来说成本效益高
使用硬件没有重复成本,除了管理它们所需的资源 使用硬件有重复成本;使用订阅模式定价
主要是静态架构;Hadoop 的新需求将需要完整的新购买范围 极其灵活;公司可以根据需求提供数千台服务器,运行多个操作系统
得到组织、法律和相关部门的欢迎 面临障碍,特别是来自法律部门,因为管理被委托给第三方/云托管提供商

企业大数据

大型组织中大数据实施的整体策略取决于组织的特定需求。今天,在大数据、数据科学、机器学习以及最近的人工智能提供商之间有数百种选择。

因此,在大型组织中实施大数据时有两个主要考虑因素:

  • 技术:选择适当的软件和硬件堆栈

  • 运营:管理组织数据,制定正式的数据治理策略,创建适当的数据管理框架

除此之外,招聘合适的人才,可能为公司的大数据/数据科学实施创建明确定义的角色也是额外但同样重要的任务。

在制定这样一个策略时,一些关键问题包括:

  • 软件/硬件许可是基于大小还是核心?如果基于数据大小,我的数据大小增加了,我的 3 年/5 年成本将是多少?

  • 解决方案是否有企业支持?

  • 我们是否需要聘请外部资源?

  • 新的能力将回答哪些业务问题?

  • 我们是否进行了短期和长期的成本效益分析?

  • 新解决方案可以回答组织目前未满足的需求是什么?

  • 解决方案是否具有足够的可扩展性,以满足我未来潜在的需求?

在技术需求方面,尽管市场上有许多解决方案,但在实践中进行使用真实数据的测试或概念验证是非常重要的。发现声称具有重大能力但未达到期望的解决方案并不罕见。换句话说,收集彻底的实证结果至关重要,不要仅仅基于营销宣传而购买。

最后,由于大数据/数据科学不断发展,解决方案的长期可扩展性和适应性需要得到适当评估。应考虑基于云的选项,因为它提供了一种有效的方式来轻松、经济地访问和使用新兴解决方案。

教程 - 在云中使用 RStudio

以下教程将演示如何在AWS(亚马逊云服务)上创建帐户,加载 RStudio 的 AMI 镜像,然后使用 RStudio,全部免费。有经验的云平台用户可能会觉得这些说明非常基础。对其他用户来说,教程应该提供有关使用 AWS 的有用初始指导。

在继续之前,请阅读下面的警告信息。

警告:请注意,AWS 需要信用卡进行注册。用户必须小心,只选择免费层级的选项。AWS 协议允许亚马逊对已产生的费用进行计费。因此,用户应该谨慎使用平台,以避免因未关闭的服务器或服务而产生潜在昂贵的意外费用

截至目前,Azure 和 Google Cloud 提供了用户注册的规定,以避免意外收费。但是,AWS 在所有云供应商中市场份额最高,用户在大多数工作场所可能会遇到 AWS。因此,本教程重点介绍 AWS 而不是其他选择。

教程结束时还提供了如何关闭您的帐户的说明,如果您希望停止使用 AWS(从而也防止任何费用):

  1. 转到aws.amazon.com/,然后单击右上角的Create an AWS Account按钮:

  1. AWS 账户通常包括 12 个月的初始免费使用。输入您的信息,然后单击继续:

  1. 选择您的账户类型(例如个人),然后输入您的联系信息:

  1. 输入付款信息。AWS 要求注册时使用信用卡。请注意,用户必须非常小心和审慎地使用 AWS 资源,以确保没有意外的费用:

  1. 一旦付款信息已验证,您将收到确认:

  1. 选择基本计划(免费):

选择基本计划后的确认页面如下:

  1. 使用您的凭据登录 AWS:

  1. 第一页显示了 AWS 中的一些服务。右上角显示了实例的区域。AWS 支持多个区域,用户可以从多个地理位置选择:

  1. 单击Services顶部左侧的下拉菜单将显示可用的不同服务。这里突出显示了一些重要的服务:

  1. 单击 EC2:

  1. AWS 提供了启动多个不同操作系统的选项。虽然我们可以选择一个选定的操作系统从头开始启动一个新实例,但我们将使用一个 AMI 镜像。AMI 是预先配置的带有安装软件的镜像。请注意,本教程中需要使用 AMI 镜像,但在本教程中使用了一个:

  1. 在左侧菜单栏上单击Community AMIs,然后搜索RStudio。选择第一个选项,然后单击选择按钮:

  1. 选择免费套餐选项(t2.micro),然后单击Next: Configure Instance Details

  1. 选择下一页上的默认选项,然后单击Next: Add Storage**:

  1. 选择默认存储选项,然后单击添加标签:

  1. 单击Next: Configure Security Group**:

  1. 安全组指定服务器的网络访问规则。对于我们的教程,我们将选择所有 TCP 并单击Review and Launch

  1. 单击Launch

  1. 选择创建新的密钥对,然后单击Download Key Pair。密钥下载完成后,单击Launch Instances按钮:

  1. 单击实例 ID:

  1. 一旦实例 ID 的状态显示为运行中,复制服务器的名称,可以在底部面板中查看:

  1. 打开一个新的浏览器,输入服务器名称作为 URL,然后按 Enter。这将打开 RStudio。使用 ID rstudio 和密码 rstudio 登录:

  1. 这将打开 RStudio 控制台。这是一个完整的 R 环境,您可以像在本地安装的 R 和 RStudio 中一样执行 R 代码:

  1. 完成使用 R Studio 后,请确保“终止”实例。终止将停止计费过程。即使我们使用的是免费套餐帐户,一旦完成工作,停止或终止实例是一个良好的做法:

  1. 点击“登出”以退出 AWS 控制台:

Azure 还提供免费帐户注册,网址为azure.microsoft.com/en-us/free/,如下截图所示:

谷歌的免费云注册表格可在cloud.google.com/free/找到,如下截图所示:

摘要

在本章中,我们讨论了在软件和硬件层面部署企业级数据科学基础设施的要求。我们在管理层面分享了关于这些倡议的关键常见问题。接着是一个关于大型组织中用于数据挖掘和机器学习的关键企业解决方案的广泛部分。

本教程涉及在亚马逊网络服务(一种基于云的系统)上启动 RStudio 服务器。AWS 已成为当今世界领先的云服务提供商,该练习展示了在几秒钟内启动整个机器可以有多简单。还提到了关于明智和谨慎使用 AWS 以防止非常昂贵的费用的适当的利弊。

下一章和最后一章将包括一些总结思考,下一步的计划,以及有关本书讨论的主题的更多学习资源的链接。

第十章:关于大数据的结束思考

到目前为止,我们已经涵盖了广泛的主题。我们已经研究了用于大数据、数据科学和机器学习的技术。我们已经了解了公司如何实施其大数据企业战略。在这个过程中,我们还开发了一些真实世界的应用程序。

本章讨论了公司在大数据或数据科学倡议中的实际考虑。该领域不断发展,引入了新技术、新的开源工具和数据挖掘中的新概念。因此,各种规模的组织都面临着共同的挑战。

数据科学的成功故事在媒体上随处可见。事实上,今天发生的大部分,如果不是全部的技术投资都与数据科学的某些方面有关。事实上,它已经成为 IT 发展中不可或缺的和整合的方面。

在本章中,我们将讨论实施数据科学的一些共同主题,共同的挑战,以及您可以采取什么措施使您的倡议成功。此外,我们将看一下数据科学的主要成功案例,以及数据科学未能实现其承诺的例子。我们还将提供一系列资源链接,您可以在那里了解更多相关主题。

本章将涵盖以下主题:

  • 企业大数据和数据科学战略

  • 道德考虑

  • 硅谷和数据科学

  • 人为因素

  • 进一步阅读的链接

企业大数据和数据科学战略

你在报纸上读到它,你在晚间新闻中看到它,你从朋友那里听说过它 - 大数据和数据科学无处不在,它们已经到来并且会一直存在。

来自硅谷的成功故事使这种影响更加显著。谁会想到一款共享和叫车的手机应用 Uber,会成为估值接近 700 亿美元的世界上最受欢迎的公司之一。像 Airbnb 这样的网站和应用将公寓共享变成了一个蓬勃发展的业务,成为估值第二高的公司,达到 300 亿美元。

这些以及其他类似事件将大数据和数据科学的主题从纯理论和技术主题转变为人们已经将其与无限投资成功联系起来的常见术语。

由于几乎所有主要技术供应商都开始添加被归类为“大数据”的功能,今天投资技术的几乎所有公司都在知情或不知情地使用大数据的某些方面。

然而,实施的过程非常宽泛。因此,除了也许是 Hadoop 之外,没有明确定义的框架,Hadoop 已成为大多数公司采用的事实框架。高级管理层通常意识到大局,即大数据可以为他们的组织带来的价值。然而,实现愿景的道路具有挑战性,因此没有一个可以保证成功的明确解决方案。

广义上说,实施有三个阶段:

  • 休眠:当公司尚未建立明确的授权,但正在讨论大数据时

  • 被动:讨论开始变得更加正式,通常会导致委派一个团队/多个团队来评估对组织的影响和价值

  • 活跃:公司开始评估技术并进行积极实施

大数据和/或数据科学战略的所有权可能有些混乱。这是因为该领域涵盖了分析和技术两个方面。前者,分析,通常由组织的面向业务的部门拥有,而技术则由 IT 部门拥有。然而,在数据科学中,两个方面都是必需的。了解领域非常好并且有领域中使用的数据的经验的数据专家可能是很好的业务主题专家。他们还可能能够全面地确定理想的用例以及如何最好地利用数据。然而,如果没有强大的技术知识,将很难确定实现愿景的正确工具。

在类似的情况下,IT 经理可能对与大数据相关的技术非常了解,但需要业务利益相关者的反馈,以有效确定哪种解决方案将满足组织的特定即时和长期需求。

换句话说,多个跨学科流需要合作,以实施真正有效的组织大数据生态系统。

实现战略的过程通常是自上而下或自下而上的。然而,与其采用严格的方向性方法,不如采用协作、迭代和敏捷的过程通常是最佳解决方案。在评估大数据需求的过程中,将根据新需求和发现做出决策和更改决策,并且可能需要修改先前的评估以满足修改后的目标。

自下而上的方法涉及从 IT 层面开始制定决策。自上而下的方法,可以说更常见,涉及从管理层开始制定决策。通常都不是最佳选择。理想的方法是一个连续的反馈循环,根据发现的过程调整需求:

相比之下,自下而上的方法如下:

无论自下而上还是自上而下的方法都不是成功的大数据计划的最佳选择。更好的选择是一个协作过程,考虑到不同部门的不断变化的需求和多样化的要求,这些部门将受益于大数据平台的实施:

伦理考虑

大数据通常涉及收集可能包含用户个人信息的大量数据。像 Facebook 和 Google 这样的公司通过分析个人信息来定位广告和执行其他类型的营销而蓬勃发展。这显然带来了伦理困境。个人数据应该被收集到什么程度?太多是多少?当然,这些问题没有正确答案。黑客攻击的兴起导致数亿用户帐户的信息被泄露,这种情况如此普遍,以至于我们对后果几乎变得麻木。

2017 年 10 月,雅虎披露,事实上,雅虎的每一个帐户都遭受了数据泄露。Equifax,美国最大的信用报告公司之一,遭受了一次数据泄露,泄露了超过 1.4 亿消费者的个人详细信息。还有许多类似的事件,而所有这些事件的共同点是所有公司都收集了一定程度的用户个人信息,无论是直接还是通过第三方。

实质上,每当涉及用户相关信息时,都需要实施适当的 IT 安全措施,以确保数据不会被泄露。后果不仅仅是数据丢失,还有声誉和信誉的影响,除了主要事实,即真实的人涉及到其数据被泄露。

因此,涉及敏感信息和/或任何个人信息的大数据安全变得至关重要。云服务提供商,如 AWS 和 Azure,部分原因是它们具有非常严格的安全标准和允许组织将责任转移给可信赖和强大实体的认证。

欧盟的《通用数据保护条例》(GDPR),自 2018 年 5 月生效,是保护其公民个人数据的重要一步。简而言之,GDPR 规定了任何个人数据的使用。在这种情况下,任何一词非常广泛,甚至包括个人的姓名。违反规定的人将被罚款高达 2,000 万欧元,或者违规组织全球营业额的 4%。

尽管这显然会减少大数据数据集的可用性,特别是那些涉及个人数据的数据集,但这也可能引发一场关于如何在约束条件下最好地利用数据的辩论和创新,也就是说,在不使用个人信息的情况下从数据中获取价值。

另一方面,美国等国家一直在放松有关个人数据收集的法律。2017 年初,美国取消了互联网服务提供商收集个人信息的隐私保护,并实际上使像 AT&T 这样的 ISP 不仅可以收集而且可以出售用户的浏览和应用程序数据合法化。

硅谷和数据科学

今天我们看到的许多大数据的关键创新都来自硅谷。这个地区几十年来一直是科技中心,推出了一些最成功的公司,如苹果、谷歌、Facebook 和 eBay。加州大学伯克利分校等大学的存在使得人才的获取相对容易。

也就是说,该地区的生活成本已经飙升,尤其是在大数据和数据科学行业增长的背景下。如今,一居室公寓的平均租金已经超过每月 3,500 美元,甚至比纽约市还要昂贵。

然而,硅谷与成功是同义词,许多新创业者被吸引到这个地区。初创公司如雨后春笋般涌现,其中许多公司获得了数千万美元的风险投资。然而,创业者应该注意统计警告,因为初创企业的高失败率。拥有一个伟大的想法,具有潜在的高商业价值是一回事。将这个想法变成商业成功需要不同类型的技能和商业头脑。

对于感兴趣的人,Crunchbase 网站提供了对初创企业领域活动的非常全面的视图。以下图片显示了在任何 7 天内发生的投资的平均数字,可能达到数十亿美元:

人的因素

尽管大数据和数据科学的显著优势,以及它们的成功和突破性增长,但仍然重要的是要记住人类思维在所有努力中的重要性。

大数据技术将使我们能够更有效地分析数据。但我们仍然需要正确的判断来决定我们的理想用例。这并不是微不足道的。大公司发现倡议同样具有挑战性(尽管规模更大),就像经验丰富的大数据专业人员一样。

同样,数据科学和机器学习可以让我们借助复杂的算法和代码进行预测和预见。然而,用户仍然有责任评估结果并不仅仅基于预测输出做出决定。用户应该在做出这样的评估时运用常识和经验。如果 GPS 指示司机在下雪的冬夜走某条路,而司机知道那条路不会被除雪车清理,盲目遵循 GPS 指示是不明智的。

一个最近的例子说明了这个概念,就是在 2016 年选举期间人与机器之间的脱节。使用非常复杂的算法估计出克林顿赢得选举的高概率的广泛模型都被证明是错误的。杰出的数据科学家和领先的统计组织估计克林顿当选的概率为 80-90%。我们都错过了做决定的人的因素。我们过于依赖模型的复杂性,而不是试图了解人们真正的感受,以及他们对候选人的最终选择和真实感受是否与他们在非正式调查中的断言一致。

成功项目的特点

数据科学项目本质上需要很长时间才能实现投资回报。特别是,很难准确衡量涉及长期预测的项目的成功。正如前面的章节所述,为了推动数据科学事业的发展,部门必须展示早期的成功。一般来说,项目的关键因素包括:a)短期;b)有可衡量的结果;c)可以受益并将被广泛用户使用。这些因素有助于建立可信度并确保数据科学相关项目的成功。

这样一个项目的例子是 Arterys,这是一家云公司,于 2016 年末开发了一种深度学习算法,可以在短时间内评估血液流向心脏,与传统扫描仪相比。它符合成功的关键标准。好处几乎立即显而易见,该算法提供了直接可衡量的结果,因为您可以将结果与扫描仪的结果进行比较,并且对广泛的用户,即患者,非常有用。此外,这个主题非常直观。

任何接受过血液检测的人都能直观地理解血流的测量。这种产品的好处也是非常明显的。能够在短时间内获得结果可以帮助挽救生命。2016 年 11 月,FDA 批准了这个算法。这是一个里程碑式的成就。

总结

总的来说,虽然通往大数据和数据科学成功的道路可能看起来艰难,但希望前面的章节已经全面概述了大数据的各种主题。我们讨论了数据挖掘和机器学习,了解了各自学科中的各种工具和技术,并在真实世界数据上开发了应用程序,并提供了关于组织大数据和数据科学倡议的微妙之处的离别思考。

接下来的几页列出了一些资源链接,读者可能会发现对于学习更多关于各自主题领域有用的。

第十一章:外部数据科学资源

该书涵盖了非常广泛的材料,从 Hadoop 到 NoSQL 和机器学习到企业数据科学。信息已经非常详尽,但由于空间限制,我们没有深入研究任何一个特定领域。

在接下来的几节中,我们提供了外部材料的链接,供您进一步阅读,如果您想了解更多有关各自主题的信息,这可能会对您有所帮助。

这里的一些解决方案要么是开源的,要么是企业软件的社区版本。如果您正在考虑大数据和/或数据科学的企业解决方案,后者可能特别有用。

大数据资源

Apache Hadoop:

hadoop.apache.org

Apache Spark:

spark.apache.org

Databricks Spark:访问 Spark 集群的社区:

community.cloud.databricks.com/

NoSQL 产品

Redis:内存键值 NoSQL 数据库:

redis.io

Cassandra:最强大的生产 NoSQL 系统之一:

cassandra.apache.org

MongoDB:基于文档的 NoSQL 数据库:

www.mongodb.com

Vertica:社区版:

www.vertica.com/try/

Teradata:Aster 社区版:

aster-community.teradata.com/community/download

语言和工具

开源 R:

www.r-project.org

Microsoft Open R(具有企业附加功能):

mran.microsoft.com/open

RStudio:R 的开发界面:

www.rstudio.com

开源 Python:

www.python.org

Anaconda Python:预装有数据科学和其他重要软件包的 Python:

anaconda.org

创建仪表板

R Shiny:R 中的仪表板:

www.rstudio.com/products/shiny/

Dash:Python 中的仪表板:

plot.ly/products/dash/

笔记本

Jupyter:R、Python 和其他各种语言的笔记本界面:

jupyter.org

Beaker Notebook:类似于 Jupyter 但使用不如广泛:

beakernotebook.com

可视化库

Bokeh:Python 的出色绘图库:

bokeh.pydata.org/en/latest/

Plotly:仪表板和报告:企业和开源:

plot.ly

RCharts:R 中广泛使用的绘图包:

ramnathv.github.io/rCharts/

HTMLWidgets:使用 JavaScript 在 R 中进行交互式仪表板:

www.htmlwidgets.org

ggplot2:终极 R 图形库:

ggplot2.tidyverse.org

R 课程

edX 上的 R 课程:

www.edx.org/course?search_query=R+programming

简明的 R 教程:

www.cyclismo.org/tutorial/R/

Coursera:大数据和 R 课程:

www.coursera.org/specializations/big-data

www.coursera.org/courses?languages=en&query=r+programming

机器学习课程

哈佛 CS109:使用 Python 的最全面的机器学习课程(作者观点):

cs109.github.io/2015/pages/videos.html

加州理工学院《从数据中学习》:机器学习理论上最全面的慕课:

work.caltech.edu/telecourse.html

Coursera:关于机器学习的各种课程:

www.coursera.org/learn/machine-learning

Stanford:Trevor Hastie 和 Rob Tibshirani 的统计学习:

lagunita.stanford.edu/courses/HumanitiesSciences/StatLearning/Winter2016/about

Andrew Ng 的《机器学习》:最广为人知的机器学习 MOOC 之一:

www.coursera.org/learn/machine-learning

机器学习和深度学习链接

Scikit-Learn:Python 中最全面的机器学习包:

scikit-learn.org/stable/

Tensorflow:谷歌的深度学习解决方案:

www.tensorflow.org

MLPACK:使用 C++和 Unix 命令行的机器学习:

www.mlpack.org

Word2Vec:自然语言处理中众所周知的软件包之一:

deeplearning4j.org/word2vec

Vowpal Wabbit:在许多 Kaggle 比赛中使用的优秀机器学习软件:

github.com/JohnLangford/vowpal_wabbit/wiki/Tutorial

LIBSVM 和 LIBLINEAR:备受推崇的命令行机器学习工具:

www.csie.ntu.edu.tw/~cjlin/libsvm/

www.csie.ntu.edu.tw/~cjlin/liblinear/

LIBFM:矩阵分解:

www.libfm.org

PaddlePaddle:百度的深度学习:

github.com/PaddlePaddle/Paddle

CuDNN:NVIDIA 的深度学习/神经网络解决方案:

developer.nvidia.com/cudnn

Caffe:伯克利的深度学习框架:

caffe.berkeleyvision.org

Theano:Python 中的 GPU 启用机器学习:

deeplearning.net/software/theano/

Torch:Lua 中的高性能机器学习:

torch.ch

Keras:开源神经网络应用:

keras.io

基于 Web 的机器学习服务

AzureML:Microsoft Azure 云中的机器学习:

azure.microsoft.com/en-us/services/machine-learning/

H2O:高性能机器学习平台:与 R、Python 等配合使用:

www.h2o.ai

BigML:外观吸引人的基于 Web 的机器学习平台:

bigml.com

电影

《模仿游戏》:关于艾伦·图灵的电影:

www.imdb.com/title/tt2084970/

《美丽心灵》:关于约翰·纳什的电影:

www.imdb.com/title/tt0268978/

《2001 太空漫游》:

www.imdb.com/title/tt0062622/

《金球》:关于运动数据分析的电影:

www.imdb.com/title/tt1210166/

《Ex Machina》:关于人工智能的电影:

www.imdb.com/title/tt0470752/

《终结者 2》:一部获得了文化地位的电影:

www.imdb.com/title/tt0103064/

Packt 的机器学习书籍

Giancarlo Zaccone 的《Tensorflow 入门》:

www.packtpub.com/big-data-and-business-intelligence/getting-started-tensorflow

Sebastian Raschka 的《机器学习和深度学习》:

www.amazon.com/Python-Machine-Learning-scikit-learn-TensorFlow/dp/1787125939

Brett Lantz 的《R 语言机器学习》:

www.amazon.com/Machine-Learning-techniques-predictive-modeling/dp/1784393908

休闲阅读书籍

关于逻辑和数学的经典著作:

www.amazon.com/Gödel-Escher-Bach-Eternal-Golden/dp/0465026567

Gödel 不完备定理的简单解释:

www.amazon.com/Gödels-Proof-Ernest-Nagel/dp/0814758371/

罗杰·彭罗斯关于人工智能等等:

www.amazon.com/Emperors-New-Mind-Concerning-Computers/dp/0198784929/

posted @ 2024-05-21 12:53  绝不原创的飞龙  阅读(45)  评论(0编辑  收藏  举报