Big Data Analytics 简明教程

Big Data Analytics - Quick Guide

Big Data Analytics - Overview

过去十年中,个人需要处理的数据量已经猛增至难以想象的程度,与此同时,数据存储的价格却在系统性地降低。私人公司和研究机构会获取海量数据,涵盖其用户的互动、业务、社交媒体,以及来自移动电话和汽车等设备的传感器。这个时代面临的挑战在于弄清楚这片数据海洋的意义。这就是 big data analytics 发挥作用的地方。

大数据分析在很大程度上涉及从不同来源收集数据,并对其进行整理以方便分析师使用,最后交付对组织业务有用的数据产品。

business organization

将从不同来源获取的大量非结构化原始数据转化为对组织有用的数据产品这一过程构成了大数据分析的核心。

Big Data Analytics - Data Life Cycle

Traditional Data Mining Life Cycle

为了提供一个框架来组织一个组织所需的工作,并从大数据中提供清晰的见解,将大数据视作具有不同阶段的周期是有用的。这绝不是线性的,这意味着所有阶段都相互关联。这个周期与 CRISP methodology 描述的更传统数据挖掘周期有表面的相似之处。

CRISP-DM Methodology

CRISP-DM methodology 代表数据挖掘的跨行业标准流程,是一个描述数据挖掘专家用来解决传统 BI 数据挖掘中问题的常用方法的周期。它仍在传统 BI 数据挖掘团队中使用。

请看下面的插图。它显示了 CRISP-DM 方法描述的周期的主要阶段以及它们之间的相互关系。

life cycle

CRISP-DM 最初产生于 1996 年,第二年,它作为在 ESPRIT 资助计划下的一个欧盟项目启动。该项目由五家公司牵头:SPSS、Teradata、Daimler AG、NCR Corporation 和 OHRA(一家保险公司)。该项目最终并入 SPSS。该方法极其注重详细说明如何制定数据挖掘项目的规范。

现在我们来进一步了解 CRISP-DM 生命周期中涉及的每个阶段 −

  1. Business Understanding − 这个初始阶段专注于从业务角度了解项目目标和要求,然后将这些知识转化为数据挖掘问题定义。设计一份初步计划来实现目标。可以用决策模型,特别是使用决策模型和符号标准构建的决策模型。

  2. Data Understanding − 数据理解阶段从初始数据收集开始,然后进行活动以熟悉数据、识别数据质量问题、发现对数据的初步见解或者检测有趣的子集以形成隐藏信息假设。

  3. Data Preparation − 数据准备阶段涵盖了从初始原始数据构建最终数据集(将输入到建模工具中的数据)的所有活动。数据准备任务可能会执行多次,并且没有规定顺序。任务包括表格、记录和属性选择以及转换和清理建模工具的数据。

  4. Modeling − 在此阶段,选择并应用各种建模技术,并将其参数校准为最优值。通常,对于相同的数据挖掘问题类型,有几种技术。某些技术对数据的形式有具体的要求。因此,通常需要退回到数据准备阶段。

  5. Evaluation − 在项目的这个阶段,你已构建了一个(或多个)从数据分析角度来看具有高质量的模型。在继续对模型进行最终部署之前,仔细评估模型并审查构建模型时执行的步骤非常重要,以确保它能正确地实现业务目标。一个主要目标是确定是否存在尚未充分考虑的一些重要业务问题。在这个阶段结束时,应就使用数据挖掘结果达成决策。

  6. Deployment − 创建模型通常不是项目的结束。即使模型的目的是增加对数据的了解,获得的知识也需要以对客户有用的方式进行组织和呈现。根据要求,部署阶段可以像生成报告一样简单,也可以像实施可重复的数据评分(例如,细分分配)或数据挖掘过程一样复杂。

在许多情况下,执行部署步骤的将是客户,而不是数据分析师。即使是分析师部署模型,客户在事先了解实际使用所创建模型需要采取的措施也很重要。

SEMMA Methodology

SEMMA 是 SAS 为数据挖掘建模开发的另一个方法。它的含义是*S*ample(样本)、*E*xplore(探索)、*M*odify(修改)、*M*odel(建模)和 *A*sses(评估)。以下是其阶段的简要说明 −

  1. Sample − 这个过程从数据抽样开始,例如,为建模选择数据集。数据集应足够大以包含要检索的信息,但又足够小以便有效使用。此阶段还处理数据分区。

  2. Explore − 此阶段涵盖通过发现变量之间的预期和意外关系以及异常,借助数据可视化来理解数据。

  3. Modify − 修改阶段包含用于选择、创建和转换变量以备数据建模的方法。

  4. Model − 在建模阶段,重点是应用各种建模(数据挖掘)技术到已准备好的变量上,以便创建可能提供所需结果的模型。

  5. Assess − 建模结果的评估显示了所创建模型的可靠性和有用性。

CRISM-DM 和 SEMMA 之间的主要区别在于 SEMMA 关注的是建模方面,而 CRISP-DM 更注重建模之前的周期阶段,例如了解待解决的业务问题、了解和预处理用作输入的数据(例如机器学习算法)。

Big Data Life Cycle

在当今大数据的背景下,以往的方法要么不完整,要么次优。例如,SEMMA 方法完全不考虑不同数据源的数据收集和预处理。这些阶段通常构成了大数据项目的绝大部分工作。

大数据分析周期可以用以下阶段描述——

  1. Business Problem Definition

  2. Research

  3. Human Resources Assessment

  4. Data Acquisition

  5. Data Munging

  6. Data Storage

  7. Exploratory Data Analysis

  8. 建模和评估的数据准备

  9. Modeling

  10. Implementation

在本节中,我们将对大数据生命周期中的每个阶段进行阐述。

Business Problem Definition

这是传统 BI 和大数据分析生命周期中一个共同点。通常,为大数据项目定义问题并正确评估其对组织的潜在收益是一个至关重要的阶段。虽然这似乎很明显,但必须评估该项目的预期收益和成本。

Research

分析其他公司在相同情况下所做的事情。这包括寻找对贵公司而言合理的解决方案,即使这需要根据贵公司的资源和要求来调整其他解决方案。在此阶段,应定义未来阶段的方法。

Human Resources Assessment

一旦问题得到定义,那么继续分析当前员工是否有能力成功完成项目是合理的。传统 BI 团队可能无法为所有阶段提供最优解决方案,因此在项目开始之前,应考虑是否有必要将项目的一部分外包出去或雇用更多人员。

Data Acquisition

本节在大数据生命周期中至关重要;它定义了传递最终数据产品所需的类型配置。数据收集是该过程中的非平凡步骤;它通常涉及从不同来源收集非结构化数据。举例来说,它可能涉及编写一个爬虫程序从某个网站获取评论。这涉及到处理文本(可能采用不同的语言),通常需要大量时间来完成。

Data Munging

一旦从网络中取回数据,例如,就需要以易于使用的方式存储数据。为了继续评论示例,让我们假设从不同的网站检索数据,而每个网站对数据的显示方式各不相同。

假设一个数据源以星级的形式提供评论,因此可以将其解读为响应变量 y ∈ {1, 2, 3, 4, 5} 的映射。另一个数据源使用双箭头系统提供评论,一个箭头表示向上投票,另一个箭头表示向下投票。这将暗示一个如下所示响应变量 y ∈ {positive, negative}

为了合并两个数据源,必须做出决策使这两个响应表示形式等效。这可能涉及将第一个数据源响应表示形式转换为第二个形式,将一颗星视为负面,五颗星视为正面。此过程通常需要大量的时间分配才能提供高质量的交付。

Data Storage

处理数据后,有时需要将数据存储在数据库中。大数据技术提供了许多关于这一点的替代方案。最常见的替代方案是使用 Hadoop 文件系统进行存储,该文件系统为用户提供了一个有限版本的 SQL,称为 HIVE 查询语言。从用户的角度来看,这允许以与在传统 BI 数据仓库中完成类似的方式完成大多数分析任务。要考虑的其他存储选项包括 MongoDB、Redis 和 SPARK。

该周期的这一阶段关乎人类资源的知识及其实现不同架构的能力。传统数据仓库的修改版本仍在大型应用程序中使用。例如,teradata 和 IBM 提供可以处理 TB 级数据的 SQL 数据库;开源解决方案(例如 postgreSQL 和 MySQL)仍然用于大型应用程序。

尽管不同的存储在后台工作的方式有所不同,但从客户端的角度来看,大多数解决方案都提供一个 SQL API。因此,对 SQL 有一个良好的理解仍然是大数据分析的一项关键技能。

这个阶段先验地似乎是最重要的主题,但实际上并非如此。它甚至不是一个必要的阶段。可以实现一个处理实时数据的大数据解决方案,所以,在这种情况下,我们只需要收集数据来开发模型,然后实时实施模型。因此,完全没有必要正式存储数据。

Exploratory Data Analysis

一旦以可以从中检索见解的方式清理和存储数据,那么数据探索阶段就必不可少了。此阶段的目标是了解数据,这通常是通过统计技术以及绘制数据图来完成的。这是一个评估问题定义是否有意义或是否可行的良好阶段。

Data Preparation for Modeling and Assessment

此阶段涉及对之前检索的已清理数据进行重新整形并使用统计预处理进行缺失值插补、异常值检测、规范化、特征提取和特征选择。

Modelling

前面的阶段应该为训练和测试(例如预测模型)生成了多个数据集。在这个阶段,需要尝试不同的模型并期待解决手头的业务问题。在实践中,通常希望该模型能够提供一些对业务的见解。最后,通过评估其在留出数据集上的性能,选择最佳模型或模型组合。

Implementation

在此阶段,开发中的数据产品将被实施到公司的 data pipeline 中。这包括在数据产品工作时建立一个验证方案,以跟踪其性能。例如,在实施预测模型的情况下,此阶段将涉及将模型应用于新数据,并在响应可用后评估该模型。

Big Data Analytics - Methodology

在方法论上,大数据分析与传统实验设计的统计方法有显著差异。分析从数据开始。通常,为了解释响应,我们会对数据进行建模。这种方法的目的在于预测响应行为或了解输入变量与响应的关系。通常在统计实验设计中,实验会得到发展,而数据会以结果的形式检索出来。这能通过一定假设(如独立性、正态性和随机化)的方式生成数据,供统计模型使用。

在大数据分析中,数据会展现在我们面前。我们无法设计一个实验来满足我们最偏爱的统计模型。在大规模分析应用中,大量的工作(通常是 80% 的精力)用于清理数据,以便机器学习模型使用。

在实际大规模应用中,我们没有独特的方法论可遵循。通常,在业务问题被定义之后,需要一个研究阶段来设计要使用的方法论。然而,一般性指导原则与几乎所有问题相关并适用于它们。

大数据分析中最重要的任务之一是 statistical modeling ,即监督式和非监督式分类或回归问题。当数据被清理和预处理并可用于建模时,应注意评估具有合理损失度量的不同模型,然后在模型被执行后,应报告进一步的评估和结果。预测建模中一个常见的陷阱只是执行模型而从不衡量其性能。

Big Data Analytics - Core Deliverables

如大数据生命周期所述,在大多数情况下,开发大数据产品所得出的数据产品属于以下产品中的一些——

  1. Machine learning implementation ——这可以是一种分类算法、回归模型或细分模型。

  2. Recommender system ——其目的是开发一种基于用户行为推荐选择的系统。 Netflix 是这种数据产品的典型示例,其中根据用户的评级推荐其他电影。

  3. Dashboard ——企业通常需要工具来可视化汇总数据。仪表板是一种图形机制,它可以使这些数据变得可获得。

  4. Ad-Hoc analysis ——通常,业务领域有疑问、假设或神话,可通过使用数据进行临时分析解答。

Big Data Analytics - Key Stakeholders

在大组织中,为了成功开发大数据项目,需要管理层支持项目。这通常涉及找到一个方法来展示该项目所具有的商业优势。我们没有一个解决寻找项目赞助商问题的独特方案,但以下给出了一些指导原则——

  1. 检查谁以及在哪里是与您感兴趣的项目类似的其他项目的赞助商。

  2. 与关键管理职位中有个人联系有助于获得帮助,因此,如果项目前景看好,可以进行任何联系。

  3. 谁会从您的项目中受益?您的客户,一旦项目步入正轨,将会是谁?

  4. 制定一项简单、清晰且令人兴奋的提案,并与您组织中的关键人物分享。

为项目找到赞助商的最佳方法是了解问题以及一旦实施后将产生什么数据产品。这种理解将帮助说服管理层理解大数据项目的重要性。

Big Data Analytics - Data Analyst

数据分析员具有面向报告的个人资料,他们有从传统数据仓库中使用 SQL 提取和分析数据的经验。他们的任务通常涉及数据存储或报告一般业务结果。数据仓储绝非简单,它只是与数据科学家所做的事情不同。

许多组织都在市场上艰苦地寻找称职的数据科学家。然而,一个好主意是选择预期数据分析员,并向他们传授成为数据科学家所需的技能。这绝非一项琐碎的任务,通常来说,涉及到该人员取得某个定量领域的硕士学位,但它无疑是一个可行的选择。一位称职的数据分析员必须具备的基本技能如下——

  1. Business understanding

  2. SQL programming

  3. Report design and implementation

  4. Dashboard development

Big Data Analytics - Data Scientist

数据科学家的作用通常与预测建模、开发细分算法、推荐系统、A/B 测试框架以及经常处理原始非结构化数据等任务相关。

他们工作的性质要求深入了解数学、应用统计学和编程。数据分析师和数据科学家之间有一些共同的技能,例如查询数据库的能力。两者都分析数据,但数据科学家的决策对组织的影响可能会更大。

以下是数据科学家通常需要具备的一组技能 −

  1. 使用统计软件包编程,例如:R、Python、SAS、SPSS 或 Julia

  2. 能够从不同来源清理、提取和探索数据

  3. 统计模型的研究、设计和实施

  4. 深入的统计学、数学和计算机科学知识

在数据大分析中,人们通常混淆数据科学家和数据架构师的角色。事实上,两者的差别非常简单。数据架构师定义工具和数据存储体系结构,而数据科学家使用这种体系结构。当然,数据科学家应该能够在特别项目需要时建立新工具,但基础设施定义和设计不应该是其工作的一部分。

Big Data Analytics - Problem Definition

通过本教程,我们将开发一个项目。本教程中每一后续章节都会在迷你项目部分处理大项目的一部分。这一部分被认为是一个应用教程部分,它将提供接触现实世界问题的经验。在这种情况下,我们将从该项目的定义问题开始。

Project Description

该项目的目的是开发一个机器学习模型,以预测人们使用其简历(CV)文本作为输入的小时工资。

使用上面定义的框架,定义问题很容易。我们可以将 X = {x1, x2, …, xn} 定义为用户的 CV,其中每个特征可能以最简单的方式出现,即此单词出现的次数。然后响应是有实值的,我们正试图预测个人每小时的工资,单位为美元。

这两个考虑足以得出结论,即可以通过监督回归算法解决所提出的问题。

Problem Definition

Problem Definition 可能是在大数据分析管道中最复杂、最容易被忽视的阶段之一。为了定义数据产品要解决的问题,经验是强制性的。大多数数据科学家准学者在这个阶段几乎没有或完全没有经验。

大多数大数据问题可以按以下方式分类−

  1. Supervised classification

  2. Supervised regression

  3. Unsupervised learning

  4. Learning to rank

现在让我们进一步了解这四个概念。

Supervised Classification

给定特征矩阵 X = {x1, x2, …​, xn},我们开发模型 M 来预测定义为 y = {c1, c2, …​, cn} 的不同类。例如:给定保险公司客户的交易数据,可以开发一个模型来预测客户是否会流失。后者是一个二元分类问题,其中有两个类或目标变量:流失和不流失。

其他问题涉及预测多个类,我们可能对识别数字感兴趣,因此响应向量将定义为:y = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},最先进的模型将卷积神经网络和特征矩阵将定义为图像像素。

Supervised Regression

在这种情况下,问题定义与前面的例子非常相似;区别在于响应。在回归问题中,响应 y ∈ ℜ,这意味着该响应是有实值的。例如,我们可以开发一个模型来预测给定简历语料库的情况下个人的每小时工资。

Unsupervised Learning

管理层常常渴望获得新的见解。分段模型可以提供此见解,以便营销部门为不同的细分开发产品。开发分段模型的一个好方法是选择与所需细分相关的特征,而不是考虑算法。

例如,在电信公司中,按手机使用情况对客户进行细分很有意思。这将涉及忽视与细分目标无关的特征,并且仅包含相关的特征。在这种情况下,这将选择诸如一个月内使用的短信数量、入站和出站分钟数等特征。

Learning to Rank

该问题可以被认为是一个回归问题,但它具有特殊特征,值得单独处理。该问题涉及给定我们寻求在给定查询的情况下查找最相关排序的文档集合。为了开发一个监督学习算法,需要标记给定查询的情况下排序的相关程度。

需要注意的是,为了开发一个监督学习算法,需要标记训练数据。这意味着为了训练一个例如能够从图像中识别数字的模型,我们需要手动标记大量示例。有一些 Web 服务可以加速此过程,并且通常用于此任务,例如 Amazon Mechanical Turk。事实证明,当提供更多数据时,学习算法可以提高其性能,因此在监督学习中实际上必须标记大量示例。

Big Data Analytics - Data Collection

数据收集在“大数据”周期中发挥着最重要的作用。Internet 几乎提供了无限的数据源,可用于各种主题。该领域的重要性取决于业务类型,但传统行业可以获取外部数据的多元化来源,并将这些数据与其交易数据相结合。

例如,让我们假设要构建一个推荐餐厅的系统。第一步是收集数据,在本例中,从不同网站收集餐厅评论,并将它们存储在数据库中。由于我们对原始文本感兴趣,并且会将其用于分析,因此在何处存储用于开发模型的数据并不是那么重要。这听起来可能与大数据主要技术相矛盾,但为了实现大数据应用程序,我们只需要让它实时运行即可。

Twitter Mini Project

定义问题后,接下来的阶段是收集数据。以下小项目的想法是对收集自网络的数据进行处理,并对其进行结构化,以便用于机器学习模型。我们将使用 R 编程语言从 Twitter Rest API 收集一些推文。

首先创建一个 Twitter 帐户,然后按照 twitteRvignette 中的说明创建一个 Twitter 开发者帐户。以下是这些说明的摘要——

  1. 转至 https://twitter.com/apps/new 并登录。

  2. 填写基本信息后,转到“设置”选项卡,然后选择“读取、编写和访问直接消息”。

  3. 执行此操作后,请务必单击保存按钮

  4. 在“详细信息”选项卡中,记下您的客户机密钥和客户机密

  5. 在 R 会话中,您将使用 API 密钥和 API 密文值

  6. 最后运行以下脚本。这将从其在 GitHub 上的存储库中安装 twitteR 包。

install.packages(c("devtools", "rjson", "bit64", "httr"))

# Make sure to restart your R session at this point
library(devtools)
install_github("geoffjentry/twitteR")

我们感兴趣的是,在其中包括字符串“big mac”的数据,并找出有关此字符串的突出主题。为此,第一步是从 Twitter 收集数据。以下是我们的 R 脚本,用于从 Twitter 收集所需数据。此代码也位于 bda/part1/collect_data/collect_data_twitter.R 文件中。

rm(list = ls(all = TRUE)); gc() # Clears the global environment
library(twitteR)
Sys.setlocale(category = "LC_ALL", locale = "C")

### Replace the xxx’s with the values you got from the previous instructions

# consumer_key = "xxxxxxxxxxxxxxxxxxxx"
# consumer_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# access_token = "xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# access_token_secret= "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Connect to twitter rest API
setup_twitter_oauth(consumer_key, consumer_secret, access_token, access_token_secret)

# Get tweets related to big mac
tweets <- searchTwitter(’big mac’, n = 200, lang = ’en’)
df <- twListToDF(tweets)

# Take a look at the data
head(df)

# Check which device is most used
sources <- sapply(tweets, function(x) x$getStatusSource())
sources <- gsub("</a>", "", sources)
sources <- strsplit(sources, ">")
sources <- sapply(sources, function(x) ifelse(length(x) > 1, x[2], x[1]))
source_table = table(sources)
source_table = source_table[source_table > 1]
freq = source_table[order(source_table, decreasing = T)]
as.data.frame(freq)

#                       Frequency
# Twitter for iPhone       71
# Twitter for Android      29
# Twitter Web Client       25
# recognia                 20

Big Data Analytics - Cleansing Data

一旦收集到数据,我们通常会有不同特征的多元化数据源。最直接的步骤是让这些数据源均质化,并继续开发我们的数据产品。然而,这取决于数据的类型。我们应该问自己,均质化数据是否可行。

也许数据源完全不同,并且如果将源均质化的话,信息丢失将会很大。在这种情况下,我们可以考虑替代方案。一个数据源可以帮助我构建回归模型,另一个数据源可以构建分类模型吗?是否可以利用我们的优势来处理异质性,而不是仅仅丢失信息?做出这些决策让分析变得有趣且具有挑战性。

对于评论而言,每个数据源都可以有一种语言。同样,我们有两个选择——

  1. Homogenization ——它涉及将不同语言翻译成我们拥有更多数据的语言。翻译服务的质量是可以接受的,但如果我们要使用 API 翻译海量数据,成本将很高。有可用于此任务的软件工具,但这也会很昂贵。

  2. Heterogenization ——是否可以针对每种语言开发一个解决方案?因为检测语料库的语言很简单,所以我们可以针对每种语言开发一个推荐器。这将涉及根据可用语言数量来调整每个推荐器的工作,但如果我们有少量的可用语言,这绝对是一个可行的选择。

Twitter Mini Project

在本例中,我们需要先清理非结构化数据,然后将其转换为数据矩阵,以便对它应用主题建模。一般来说,从 Twitter 获取数据时,有几个字符我们不想使用,至少在数据清理过程的第一阶段如此。

例如,在获得推特后,我们会得到以下奇怪字符:“<ed><U+00A0><U+00BD><ed><U+00B8><U+008B>”。这些可能是表情符号,因此为了清除数据,我们将使用以下脚本进行删除。此代码也在 bda/part1/collect_data/cleaning_data.R 文件中提供。

rm(list = ls(all = TRUE)); gc() # Clears the global environment
source('collect_data_twitter.R')
# Some tweets
head(df$text)

[1] "I’m not a big fan of turkey but baked Mac &
cheese <ed><U+00A0><U+00BD><ed><U+00B8><U+008B>"
[2] "@Jayoh30 Like no special sauce on a big mac. HOW"
### We are interested in the text - Let’s clean it!

# We first convert the encoding of the text from latin1 to ASCII
df$text <- sapply(df$text,function(row) iconv(row, "latin1", "ASCII", sub = ""))

# Create a function to clean tweets
clean.text <- function(tx) {
  tx <- gsub("htt.{1,20}", " ", tx, ignore.case = TRUE)
  tx = gsub("[^#[:^punct:]]|@|RT", " ", tx, perl = TRUE, ignore.case = TRUE)
  tx = gsub("[[:digit:]]", " ", tx, ignore.case = TRUE)
  tx = gsub(" {1,}", " ", tx, ignore.case = TRUE)
  tx = gsub("^\\s+|\\s+$", " ", tx, ignore.case = TRUE)
  return(tx)
}

clean_tweets <- lapply(df$text, clean.text)

# Cleaned tweets
head(clean_tweets)
[1] " WeNeedFeminlsm MAC s new make up line features men woc and big girls "
[1] " TravelsPhoto What Happens To Your Body One Hour After A Big Mac "

数据清理迷你项目的最后一步是清除可以转换为矩阵并应用算法的文本。通过存储在 clean_tweets 向量中的文本,我们可以轻松地将其转换为词袋矩阵并应用非监督学习算法。

Big Data Analytics - Summarizing Data

报告在大数据分析中非常重要。每个组织都必须定期提供信息以支持其决策过程。此任务通常由具有 SQL 和 ETL(提取、传输和加载)经验的数据分析师处理。

负责此任务的团队有责任将大数据分析部门生成的信息传播到组织的不同领域。

以下示例演示了数据摘要的含义。导航到文件夹 bda/part1/summarize_data ,然后在文件夹中双击 summarize_data.Rproj 文件以将其打开。然后,打开 summarize_data.R 脚本并查看代码,并按照提供的说明进行操作。

# Install the following packages by running the following code in R.
pkgs = c('data.table', 'ggplot2', 'nycflights13', 'reshape2')
install.packages(pkgs)

ggplot2 软件包非常适合数据可视化。 data.table 软件包是 R 中进行快速且节省内存的摘要的绝佳选择。最近的基准测试表明,它甚至比 pandas (用于类似任务的 Python 库)还要快。

bench mark

使用以下代码查看数据。此代码也可在 bda/part1/summarize_data/summarize_data.Rproj 文件中找到。

library(nycflights13)
library(ggplot2)
library(data.table)
library(reshape2)

# Convert the flights data.frame to a data.table object and call it DT
DT <- as.data.table(flights)

# The data has 336776 rows and 16 columns
dim(DT)

# Take a look at the first rows
head(DT)

#   year    month  day   dep_time  dep_delay  arr_time  arr_delay  carrier
# 1: 2013     1     1      517       2         830         11       UA
# 2: 2013     1     1      533       4         850         20       UA
# 3: 2013     1     1      542       2         923         33       AA
# 4: 2013     1     1      544      -1        1004        -18       B6
# 5: 2013     1     1      554      -6         812        -25       DL
# 6: 2013     1     1      554      -4         740         12       UA

#     tailnum  flight  origin   dest    air_time   distance    hour   minute
# 1:  N14228   1545     EWR      IAH      227        1400       5       17
# 2:  N24211   1714     LGA      IAH      227        1416       5       33
# 3:  N619AA   1141     JFK      MIA      160        1089       5       42
# 4:  N804JB    725     JFK      BQN      183        1576       5       44
# 5:  N668DN    461     LGA      ATL      116        762        5       54
# 6:  N39463   1696     EWR      ORD      150        719        5       54

以下代码有一个数据摘要的示例。

### Data Summarization
# Compute the mean arrival delay
DT[, list(mean_arrival_delay = mean(arr_delay, na.rm = TRUE))]
#        mean_arrival_delay
# 1:           6.895377
# Now, we compute the same value but for each carrier
mean1 = DT[, list(mean_arrival_delay = mean(arr_delay, na.rm = TRUE)),
   by = carrier]
print(mean1)
#      carrier    mean_arrival_delay
# 1:      UA          3.5580111
# 2:      AA          0.3642909
# 3:      B6          9.4579733
# 4:      DL          1.6443409
# 5:      EV         15.7964311
# 6:      MQ         10.7747334
# 7:      US          2.1295951
# 8:      WN          9.6491199
# 9:      VX          1.7644644
# 10:     FL         20.1159055
# 11:     AS         -9.9308886
# 12:     9E          7.3796692
# 13:     F9         21.9207048
# 14:     HA         -6.9152047
# 15:     YV         15.5569853
# 16:     OO         11.9310345

# Now let’s compute to means in the same line of code
mean2 = DT[, list(mean_departure_delay = mean(dep_delay, na.rm = TRUE),
   mean_arrival_delay = mean(arr_delay, na.rm = TRUE)),
   by = carrier]
print(mean2)

#       carrier    mean_departure_delay   mean_arrival_delay
# 1:      UA            12.106073          3.5580111
# 2:      AA             8.586016          0.3642909
# 3:      B6            13.022522          9.4579733
# 4:      DL             9.264505          1.6443409
# 5:      EV            19.955390         15.7964311
# 6:      MQ            10.552041         10.7747334
# 7:      US             3.782418          2.1295951
# 8:      WN            17.711744          9.6491199
# 9:      VX            12.869421          1.7644644
# 10:     FL            18.726075         20.1159055
# 11:     AS             5.804775         -9.9308886
# 12:     9E            16.725769          7.3796692
# 13:     F9            20.215543         21.9207048
# 14:     HA             4.900585         -6.9152047
# 15:     YV            18.996330         15.5569853
# 16:     OO            12.586207         11.9310345

### Create a new variable called gain
# this is the difference between arrival delay and departure delay
DT[, gain:= arr_delay - dep_delay]

# Compute the median gain per carrier
median_gain = DT[, median(gain, na.rm = TRUE), by = carrier]
print(median_gain)

Big Data Analytics - Data Exploration

Exploratory data analysis 是由 John Tuckey(1977 年)提出的一个概念,它包含一个新的统计学观点。塔基的想法是,在传统统计学中,数据没有以图形方式进行探索,它只是用于检验假设。开发工具的第一次尝试是在斯坦福进行的,该项目名为 prim9。该工具能够以九个维度可视化数据,因此它能够提供数据的多变量视角。

最近,探索性数据分析是必需的,并已纳入大数据分析生命周期。在组织中有效发现洞察并将其有效传达的能力得益于强大的 EDA 功能。

基于塔克的概念,贝尔实验室开发了 S programming language ,以提供交互式界面来进行统计。S 的想法是提供具有易于使用的语言的丰富图形功能。在当今基于 S 编程语言的 R 是最受欢迎的分析软件的世界,大数据背景下。

top analytic packages

以下程序演示了探索性数据分析的使用。

以下是一个探索性数据分析的示例。此代码也可用在 part1/eda/exploratory_data_analysis.R 文件中。

library(nycflights13)
library(ggplot2)
library(data.table)
library(reshape2)

# Using the code from the previous section
# This computes the mean arrival and departure delays by carrier.
DT <- as.data.table(flights)
mean2 = DT[, list(mean_departure_delay = mean(dep_delay, na.rm = TRUE),
   mean_arrival_delay = mean(arr_delay, na.rm = TRUE)),
   by = carrier]

# In order to plot data in R usign ggplot, it is normally needed to reshape the data
# We want to have the data in long format for plotting with ggplot
dt = melt(mean2, id.vars = ’carrier’)

# Take a look at the first rows
print(head(dt))

# Take a look at the help for ?geom_point and geom_line to find similar examples
# Here we take the carrier code as the x axis
# the value from the dt data.table goes in the y axis

# The variable column represents the color
p = ggplot(dt, aes(x = carrier, y = value, color = variable, group = variable)) +
   geom_point() + # Plots points
   geom_line() + # Plots lines
   theme_bw() + # Uses a white background
   labs(list(title = 'Mean arrival and departure delay by carrier',
      x = 'Carrier', y = 'Mean delay'))
print(p)

# Save the plot to disk
ggsave('mean_delay_by_carrier.png', p,
   width = 10.4, height = 5.07)

代码应产生如下图像 −

mean delay

Big Data Analytics - Data Visualization

为了理解数据,通常有用可视化方式。通常在大型数据应用中,乐趣在于发现洞察,而不仅仅是创建美观的图表。以下是使用图表理解数据的不同方法的示例。

为了开始分析航班数据,我们可以首先检查数值变量之间是否存在相关性。此代码也可用在 bda/part1/data_visualization/data_visualization.R 文件中。

# Install the package corrplot by running
install.packages('corrplot')

# then load the library
library(corrplot)

# Load the following libraries
library(nycflights13)
library(ggplot2)
library(data.table)
library(reshape2)

# We will continue working with the flights data
DT <- as.data.table(flights)
head(DT) # take a look

# We select the numeric variables after inspecting the first rows.
numeric_variables = c('dep_time', 'dep_delay',
   'arr_time', 'arr_delay', 'air_time', 'distance')

# Select numeric variables from the DT data.table
dt_num = DT[, numeric_variables, with = FALSE]

# Compute the correlation matrix of dt_num
cor_mat = cor(dt_num, use = "complete.obs")

print(cor_mat)
### Here is the correlation matrix
#              dep_time   dep_delay   arr_time   arr_delay    air_time    distance
# dep_time   1.00000000  0.25961272 0.66250900  0.23230573 -0.01461948 -0.01413373
# dep_delay  0.25961272  1.00000000 0.02942101  0.91480276 -0.02240508 -0.02168090
# arr_time   0.66250900  0.02942101 1.00000000  0.02448214  0.05429603  0.04718917
# arr_delay  0.23230573  0.91480276 0.02448214  1.00000000 -0.03529709 -0.06186776
# air_time  -0.01461948 -0.02240508 0.05429603 -0.03529709  1.00000000  0.99064965
# distance  -0.01413373 -0.02168090 0.04718917 -0.06186776  0.99064965  1.00000000

# We can display it visually to get a better understanding of the data
corrplot.mixed(cor_mat, lower = "circle", upper = "ellipse")

# save it to disk
png('corrplot.png')
print(corrplot.mixed(cor_mat, lower = "circle", upper = "ellipse"))
dev.off()

此代码生成以下相关矩阵可视化 −

correlation

我们可以在图表中看到,数据集中某些变量之间存在很强的相关性。例如,到达延迟和出发延迟似乎高度相关。我们可以看到这一点,因为椭圆显示了两个变量之间几乎线性关系;然而,从这个结果中发现因果关系并不容易。

我们不能说因为两个变量相关,一个变量就会影响另一个变量。我们还在图表中发现了飞行时间和距离之间的强相关性,这是相当合理的,因为随着距离的增加,飞行时间应该增加。

我们还可以对数据进行单变量分析。一种简单有效的可视化分布方式是 box-plots 。以下代码演示了如何使用 ggplot2 库生成箱线图和格子图。此代码也可用在 bda/part1/data_visualization/boxplots.R 文件中。

source('data_visualization.R')
### Analyzing Distributions using box-plots
# The following shows the distance as a function of the carrier

p = ggplot(DT, aes(x = carrier, y = distance, fill = carrier)) + # Define the carrier
   in the x axis and distance in the y axis
   geom_box-plot() + # Use the box-plot geom
   theme_bw() + # Leave a white background - More in line with tufte's
      principles than the default
   guides(fill = FALSE) + # Remove legend
   labs(list(title = 'Distance as a function of carrier', # Add labels
      x = 'Carrier', y = 'Distance'))
p
# Save to disk
png(‘boxplot_carrier.png’)
print(p)
dev.off()

# Let's add now another variable, the month of each flight
# We will be using facet_wrap for this
p = ggplot(DT, aes(carrier, distance, fill = carrier)) +
   geom_box-plot() +
   theme_bw() +
   guides(fill = FALSE) +
   facet_wrap(~month) + # This creates the trellis plot with the by month variable
   labs(list(title = 'Distance as a function of carrier by month',
      x = 'Carrier', y = 'Distance'))
p
# The plot shows there aren't clear differences between distance in different months

# Save to disk
png('boxplot_carrier_by_month.png')
print(p)
dev.off()

Big Data Analytics - Introduction to R

本节专门向用户介绍 R 编程语言。可从 cran website 下载 R。对于 Windows 用户, install rtoolsrstudio IDE 很有用。

R 背后的总体概念是充当已编译语言(例如 C、C++ 和 Fortran)编写的其他软件的界面,并为用户提供一个交互式工具来分析数据。

导航到图书 zip 文件的文件夹 bda/part2/R_introduction 并打开 R_introduction.Rproj 文件。这将打开一个 RStudio 会话。然后打开 01_vectors.R 文件。逐行运行脚本并遵循代码中的注释。为了学习,另一个有用的选择就是键入代码,这将帮助您习惯 R 语法。在 R 中,注释是用 # 符号编写的。

为了在图书中显示运行 R 代码的结果,在评估代码后,将注释返回的结果 R。通过这种方式,您可以在书中复制粘贴代码并直接在 R 中尝试其部分。

# Create a vector of numbers
numbers = c(1, 2, 3, 4, 5)
print(numbers)

# [1] 1 2 3 4 5
# Create a vector of letters
ltrs = c('a', 'b', 'c', 'd', 'e')
# [1] "a" "b" "c" "d" "e"

# Concatenate both
mixed_vec = c(numbers, ltrs)
print(mixed_vec)
# [1] "1" "2" "3" "4" "5" "a" "b" "c" "d" "e"

让我们分析一下之前代码中发生的情况。我们可以看到可以使用数字和字母创建向量。我们无需事先告诉 R 我们想要什么类型的数据类型。最后,我们能够创建带有数字和字母的向量。混合向量已将数字强制转换为字符,我们可以通过可视化如何将值打印在引号内来看到这一点。

以下代码显示了函数类返回的不同向量的类型。通常使用类函数来“询问”对象,询问他的类别是什么。

### Evaluate the data types using class

### One dimensional objects
# Integer vector
num = 1:10
class(num)
# [1] "integer"

# Numeric vector, it has a float, 10.5
num = c(1:10, 10.5)
class(num)
# [1] "numeric"

# Character vector
ltrs = letters[1:10]
class(ltrs)
# [1] "character"

# Factor vector
fac = as.factor(ltrs)
class(fac)
# [1] "factor"

R 也支持二维对象。在以下代码中,列出了 R 中使用最流行的两个数据结构的示例:矩阵和数据帧。

# Matrix
M = matrix(1:12, ncol = 4)
#      [,1] [,2] [,3] [,4]
# [1,]    1    4    7   10
# [2,]    2    5    8   11
# [3,]    3    6    9   12
lM = matrix(letters[1:12], ncol = 4)
#     [,1] [,2] [,3] [,4]
# [1,] "a"  "d"  "g"  "j"
# [2,] "b"  "e"  "h"  "k"
# [3,] "c"  "f"  "i"  "l"

# Coerces the numbers to character
# cbind concatenates two matrices (or vectors) in one matrix
cbind(M, lM)
#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
# [1,] "1"  "4"  "7"  "10" "a"  "d"  "g"  "j"
# [2,] "2"  "5"  "8"  "11" "b"  "e"  "h"  "k"
# [3,] "3"  "6"  "9"  "12" "c"  "f"  "i"  "l"

class(M)
# [1] "matrix"
class(lM)
# [1] "matrix"

# data.frame
# One of the main objects of R, handles different data types in the same object.
# It is possible to have numeric, character and factor vectors in the same data.frame

df = data.frame(n = 1:5, l = letters[1:5])
df
#   n l
# 1 1 a
# 2 2 b
# 3 3 c
# 4 4 d
# 5 5 e

如前一个示例所示,可以在同一对象中使用不同的数据类型。通常,这是如何在数据库中呈现数据,API 数据的一部分是文本或字符向量,另一部分是数字。分析人员的工作是确定要分配哪种统计数据类型,然后为其使用正确的 R 数据类型。在统计中,我们通常认为变量为以下类型 −

  1. Numeric

  2. Nominal or categorical

  3. Ordinal

在 R 中,向量可以属于以下类 −

  1. Numeric - Integer

  2. Factor

  3. Ordered Factor

R 为每种变量的统计类型提供数据类型。然而,有序因子很少使用,但可以通过因子函数或 ordered 函数创建。

以下部分讨论了索引的概念。这是一个非常常见的操作,并且处理选择对象的各个部分并对它们进行转换的问题。

# Let's create a data.frame
df = data.frame(numbers = 1:26, letters)
head(df)
#      numbers  letters
# 1       1       a
# 2       2       b
# 3       3       c
# 4       4       d
# 5       5       e
# 6       6       f

# str gives the structure of a data.frame, it’s a good summary to inspect an object
str(df)
#   'data.frame': 26 obs. of  2 variables:
#   $ numbers: int  1 2 3 4 5 6 7 8 9 10 ...
#   $ letters: Factor w/ 26 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ...

# The latter shows the letters character vector was coerced as a factor.
# This can be explained by the stringsAsFactors = TRUE argumnet in data.frame
# read ?data.frame for more information

class(df)
# [1] "data.frame"

### Indexing
# Get the first row
df[1, ]
#     numbers  letters
# 1       1       a

# Used for programming normally - returns the output as a list
df[1, , drop = TRUE]
# $numbers
# [1] 1
#
# $letters
# [1] a
# Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z

# Get several rows of the data.frame
df[5:7, ]
#      numbers  letters
# 5       5       e
# 6       6       f
# 7       7       g

### Add one column that mixes the numeric column with the factor column
df$mixed = paste(df$numbers, df$letters, sep = ’’)

str(df)
# 'data.frame': 26 obs. of  3 variables:
# $ numbers: int  1 2 3 4 5 6 7 8 9 10 ...
# $ letters: Factor w/ 26 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ...
# $ mixed  : chr  "1a" "2b" "3c" "4d" ...

### Get columns
# Get the first column
df[, 1]
# It returns a one dimensional vector with that column

# Get two columns
df2 = df[, 1:2]
head(df2)

#      numbers  letters
# 1       1       a
# 2       2       b
# 3       3       c
# 4       4       d
# 5       5       e
# 6       6       f

# Get the first and third columns
df3 = df[, c(1, 3)]
df3[1:3, ]

#      numbers  mixed
# 1       1     1a
# 2       2     2b
# 3       3     3c

### Index columns from their names
names(df)
# [1] "numbers" "letters" "mixed"
# This is the best practice in programming, as many times indeces change, but
variable names don’t
# We create a variable with the names we want to subset
keep_vars = c("numbers", "mixed")
df4 = df[, keep_vars]

head(df4)
#      numbers  mixed
# 1       1     1a
# 2       2     2b
# 3       3     3c
# 4       4     4d
# 5       5     5e
# 6       6     6f

### subset rows and columns
# Keep the first five rows
df5 = df[1:5, keep_vars]
df5

#      numbers  mixed
# 1       1     1a
# 2       2     2b
# 3       3     3c
# 4       4     4d
# 5       5     5e

# subset rows using a logical condition
df6 = df[df$numbers < 10, keep_vars]
df6

#      numbers  mixed
# 1       1     1a
# 2       2     2b
# 3       3     3c
# 4       4     4d
# 5       5     5e
# 6       6     6f
# 7       7     7g
# 8       8     8h
# 9       9     9i

Big Data Analytics - Introduction to SQL

SQL 代表结构化查询语言。它是从传统数据仓库和大数据技术中的数据库中提取数据的最广泛使用的语言之一。为了演示 SQL 的基础知识,我们将使用示例。为了专注于语言本身,我们将使用 R 中的 SQL。在编写 SQL 代码方面,这与在数据库中完成代码的方式完全相同。

SQL 的核心是三个语句:SELECT、FROM 和 WHERE。以下示例使用了 SQL 的最常见用例。导航到文件夹 bda/part2/SQL_introduction 并打开 SQL_introduction.Rproj 文件。然后打开 01_select.R 脚本。为了在 R 中编写 SQL 代码,我们需要安装 sqldf 包,如下面的代码所示。

# Install the sqldf package
install.packages('sqldf')

# load the library
library('sqldf')
library(nycflights13)

# We will be working with the fligths dataset in order to introduce SQL

# Let’s take a look at the table
str(flights)
# Classes 'tbl_d', 'tbl' and 'data.frame': 336776 obs. of  16 variables:

# $ year     : int  2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
# $ month    : int  1 1 1 1 1 1 1 1 1 1 ...
# $ day      : int  1 1 1 1 1 1 1 1 1 1 ...
# $ dep_time : int  517 533 542 544 554 554 555 557 557 558 ...
# $ dep_delay: num  2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
# $ arr_time : int  830 850 923 1004 812 740 913 709 838 753 ...
# $ arr_delay: num  11 20 33 -18 -25 12 19 -14 -8 8 ...
# $ carrier  : chr  "UA" "UA" "AA" "B6" ...

# $ tailnum  : chr  "N14228" "N24211" "N619AA" "N804JB" ...
# $ flight   : int  1545 1714 1141 725 461 1696 507 5708 79 301 ...
# $ origin   : chr  "EWR" "LGA" "JFK" "JFK" ...
# $ dest     : chr  "IAH" "IAH" "MIA" "BQN" ...
# $ air_time : num  227 227 160 183 116 150 158 53 140 138 ...
# $ distance : num  1400 1416 1089 1576 762 ...
# $ hour     : num  5 5 5 5 5 5 5 5 5 5 ...
# $ minute   : num  17 33 42 44 54 54 55 57 57 58 ...

select 语句用于从表中检索列并对列进行计算。最简单的 SELECT 语句在 ej1 中演示。我们还可以创建新变量,如 ej2 中所示。

### SELECT statement
ej1 = sqldf("
   SELECT
   dep_time
   ,dep_delay
   ,arr_time
   ,carrier
   ,tailnum
   FROM
   flights
")

head(ej1)
#    dep_time   dep_delay  arr_time  carrier  tailnum
# 1      517         2      830      UA       N14228
# 2      533         4      850      UA       N24211
# 3      542         2      923      AA       N619AA
# 4      544        -1     1004      B6       N804JB
# 5      554        -6      812      DL       N668DN
# 6      554        -4      740      UA       N39463

# In R we can use SQL with the sqldf function. It works exactly the same as in
a database

# The data.frame (in this case flights) represents the table we are querying
and goes in the FROM statement
# We can also compute new variables in the select statement using the syntax:

# old_variables as new_variable
ej2 = sqldf("
   SELECT
   arr_delay - dep_delay as gain,
   carrier
   FROM
   flights
")

ej2[1:5, ]
#    gain   carrier
# 1    9      UA
# 2   16      UA
# 3   31      AA
# 4  -17      B6
# 5  -19      DL

SQL 中最常用的功能之一是 group by 语句。这允许为另一个变量的不同组计算数值。打开脚本 02_group_by.R。

### GROUP BY

# Computing the average
ej3 = sqldf("
  SELECT
   avg(arr_delay) as mean_arr_delay,
   avg(dep_delay) as mean_dep_delay,
   carrier
   FROM
   flights
   GROUP BY
   carrier
")

#    mean_arr_delay   mean_dep_delay carrier
# 1       7.3796692      16.725769      9E
# 2       0.3642909       8.586016      AA
# 3      -9.9308886       5.804775      AS
# 4       9.4579733      13.022522      B6
# 5       1.6443409       9.264505      DL
# 6      15.7964311      19.955390      EV
# 7      21.9207048      20.215543      F9
# 8      20.1159055      18.726075      FL
# 9      -6.9152047       4.900585      HA
# 10     10.7747334      10.552041      MQ
# 11     11.9310345      12.586207      OO
# 12      3.5580111      12.106073      UA
# 13      2.1295951       3.782418      US
# 14      1.7644644      12.869421      VX
# 15      9.6491199      17.711744      WN
# 16     15.5569853      18.996330      YV

# Other aggregations
ej4 = sqldf("
   SELECT
   avg(arr_delay) as mean_arr_delay,
   min(dep_delay) as min_dep_delay,
   max(dep_delay) as max_dep_delay,
   carrier
   FROM
   flights
   GROUP BY
   carrier
")

# We can compute the minimun, mean, and maximum values of a numeric value
ej4
#      mean_arr_delay    min_dep_delay   max_dep_delay   carrier
# 1       7.3796692           -24           747          9E
# 2       0.3642909           -24          1014          AA
# 3      -9.9308886           -21           225          AS
# 4       9.4579733           -43           502          B6
# 5       1.6443409           -33           960         DL
# 6      15.7964311           -32           548         EV
# 7      21.9207048           -27           853         F9
# 8      20.1159055           -22           602         FL
# 9      -6.9152047           -16          1301         HA
# 10     10.7747334           -26          1137         MQ
# 11     11.9310345           -14           154         OO
# 12      3.5580111           -20           483         UA
# 13      2.1295951           -19           500         US
# 14      1.7644644           -20           653         VX
# 15      9.6491199           -13           471         WN
# 16     15.5569853           -16           387         YV

### We could be also interested in knowing how many observations each carrier has
ej5 = sqldf("
   SELECT
   carrier, count(*) as count
   FROM
   flights
   GROUP BY
   carrier
")

ej5
#      carrier  count
# 1       9E    18460
# 2       AA   32729
# 3       AS   714
# 4       B6   54635
# 5       DL   48110
# 6       EV   54173
# 7       F9   685
# 8       FL   3260
# 9       HA   342
# 10      MQ   26397
# 11      OO   32
# 12      UA   58665
# 13      US   20536
# 14      VX   5162
# 15      WN   12275
# 16      YV   601

SQL 最有用的功能是联接。联接意味着我们想要在表 A 和表 B 中的表 B 中使用一列来匹配两张表的值并将它们合并到一张表中。有不同类型的联接,实际操作中,以下联接将是最有用的:内部联接和左外部联接。

# Let’s create two tables: A and B to demonstrate joins.
A = data.frame(c1 = 1:4, c2 = letters[1:4])
B = data.frame(c1 = c(2,4,5,6), c2 = letters[c(2:5)])

A
# c1 c2
# 1  a
# 2  b
# 3  c
# 4  d

B
# c1 c2
# 2  b
# 4  c
# 5  d
# 6  e

### INNER JOIN
# This means to match the observations of the column we would join the tables by.
inner = sqldf("
   SELECT
   A.c1, B.c2
   FROM
   A INNER JOIN B
   ON A.c1 = B.c1
")

# Only the rows that match c1 in both A and B are returned
inner
# c1 c2
#  2  b
#  4  c

### LEFT OUTER JOIN
# the left outer join, sometimes just called left join will return the
# first all the values of the column used from the A table
left = sqldf("
  SELECT
   A.c1, B.c2
  FROM
   A LEFT OUTER JOIN B
   ON A.c1 = B.c1
")

# Only the rows that match c1 in both A and B are returned
left
#   c1    c2
#    1  <NA>
#    2    b
#    3  <NA>
#    4    c

Big Data Analytics - Charts & Graphs

分析数据的第一个方法是可视化分析数据。这样做通常是为了寻找变量之间的关系和变量的单变量描述。我们可以将这些策略分为 −

  1. Univariate analysis

  2. Multivariate analysis

Univariate Graphical Methods

Univariate 是一个统计术语。在实践中,这意味着我们希望独立于其他数据分析变量。允许有效执行此操作的图表有 −

Box-Plots

箱形图通常用于比较分布。这是一种直观检查分布之间是否存在差异的好方法。我们可以看看不同切工的钻石价格之间是否存在差异。

# We will be using the ggplot2 library for plotting
library(ggplot2)
data("diamonds")

# We will be using the diamonds dataset to analyze distributions of numeric variables
head(diamonds)

#    carat   cut       color  clarity  depth  table   price    x     y     z
# 1  0.23    Ideal       E      SI2    61.5    55     326     3.95  3.98  2.43
# 2  0.21    Premium     E      SI1    59.8    61     326     3.89  3.84  2.31
# 3  0.23    Good        E      VS1    56.9    65     327     4.05  4.07  2.31
# 4  0.29    Premium     I      VS2    62.4    58     334     4.20  4.23  2.63
# 5  0.31    Good        J      SI2    63.3    58     335     4.34  4.35  2.75
# 6  0.24    Very Good   J      VVS2   62.8    57     336     3.94  3.96  2.48

### Box-Plots
p = ggplot(diamonds, aes(x = cut, y = price, fill = cut)) +
   geom_box-plot() +
   theme_bw()
print(p)

在该图片中,我们可以看到不同类别的钻石价格分布有所不同。

box plots

Histograms

source('01_box_plots.R')

# We can plot histograms for each level of the cut factor variable using
facet_grid
p = ggplot(diamonds, aes(x = price, fill = cut)) +
   geom_histogram() +
   facet_grid(cut ~ .) +
   theme_bw()

p
# the previous plot doesn’t allow to visuallize correctly the data because of
the differences in scale
# we can turn this off using the scales argument of facet_grid

p = ggplot(diamonds, aes(x = price, fill = cut)) +
   geom_histogram() +
   facet_grid(cut ~ ., scales = 'free') +
   theme_bw()
p

png('02_histogram_diamonds_cut.png')
print(p)
dev.off()

上述代码的输出如下 -

histogram

Multivariate Graphical Methods

探索性数据分析中的多元图解方法旨在找到不同变量之间关系。实现此目的常用的方法有两种:绘制数字变量的相关性矩阵,或简单地将原始数据绘制成散点图矩阵。

为了演示这一点,我们将使用钻石数据集。要遵循代码,请打开脚本 bda/part2/charts/03_multivariate_analysis.R

library(ggplot2)
data(diamonds)

# Correlation matrix plots
keep_vars = c('carat', 'depth', 'price', 'table')
df = diamonds[, keep_vars]
# compute the correlation matrix
M_cor = cor(df)

#          carat       depth      price      table
# carat 1.00000000  0.02822431  0.9215913  0.1816175
# depth 0.02822431  1.00000000 -0.0106474 -0.2957785
# price 0.92159130 -0.01064740  1.0000000  0.1271339
# table 0.18161755 -0.29577852  0.1271339  1.0000000

# plots
heat-map(M_cor)

此代码将产生以下输出——

heat map

这是一份摘要,它告诉我们价格和克拉之间有很强的相关性,而其他变量之间的相关性不大。

当我们拥有大量变量时,相关性矩阵会非常有用,在这种情况下,绘制原始数据是不切实际的。如前所述,也可以显示原始数据 −

library(GGally)
ggpairs(df)

我们可以在绘图中看到,热图中显示的结果得到证实,价格和克拉变量之间的相关性为 0.922。

scatterplot

可以在散点图矩阵的 (3, 1) 索引中找到的价格-克拉散点图中形象化地显示该关系。

Big Data Analytics - Data Analysis Tools

各种工具可供数据科学家有效地分析数据。通常,数据分析的工程方面侧重于数据库,数据科学家重点关注可以实现数据产品的工具。下一部分讨论了不同工具的优点,重点是数据科学家最常在实践中使用的统计软件包。

R Programming Language

R 是一种专注于统计分析的开源编程语言。它在统计能力方面与 SAS、SPSS 等商业工具具有竞争力。它被认为是与 C、C++ 或 Fortran 等其他编程语言的接口。

R 的另一个优点是大量可用的开源库。在 CRAN 中,有 6000 多个可免费下载的软件包,在 Github 中提供各种 R 软件包。

在性能方面,对于密集操作,R 很慢,鉴于大量可用的库,代码的慢速部分是用编译语言编写的。但如果你打算执行需要编写深度循环的操作,那么 R 不会是你最好的选择。对于数据分析目的,有一些不错的库,如 data.table, glmnet, ranger, xgboost, ggplot2, caret ,它允许使用 R 作为更快速编程语言的接口。

Python for data analysis

Python 是一种通用编程语言,它包含大量的专门用于数据分析的库,如 pandas, scikit-learn, theano, numpyscipy

R 中的大多数功能也可以在 Python 中实现,但我们发现 R 更易于使用。如果你处理的是大型数据集,通常 Python 比 R 更合适。Python 可以非常有效地逐行清理和处理数据。这可以通过 R 实现,但对于脚本任务,它不如 Python 那么有效。

对于机器学习, scikit-learn 是一个很好的环境,它提供大量算法,可以无问题地处理中等规模的数据集。与 R 的等效库(caret)相比, scikit-learn 具有更清晰和更一致的 API。

Julia

Julia 是一种用于技术计算的高级、高性能动态编程语言。它的语法与 R 或 Python 非常相似,因此,如果你已经使用 R 或 Python,那么用 Julia 编写相同的代码应该相当简单。该语言相当新,并且在最近几年发展得非常显着,因此,它在目前肯定是一种选择。

我们建议使用 Julia 来对计算密集型算法(如神经网络)进行原型设计。它是一个非常好的研究工具。在生产中实现模型方面,Python 可能有更好的选择。然而,随着有 Web 服务来实施 R、Python 和 Julia 中的模型,这个问题正在变得不再那么严重。

SAS

SAS 是一种仍然用于商业智能的商业语言。它具有一个基本语言,允许用户编制各种应用程序。它包含一些商业产品,使非专家用户能够在不编程的情况下使用神经网络库等复杂工具。

除了商业工具显而易见的缺点之外,SAS 无法很好地扩展到大型数据集。即使是中等规模的数据集也会使 SAS 出现问题并导致服务器崩溃。只有当你使用小数据集并且用户不是专家数据科学家时,才推荐使用 SAS。对于高级用户,R 和 Python 提供了一个更高效的环境。

SPSS

SPSS 目前是 IBM 的统计分析产品。它主要用于分析调研数据,对于不会编程的用户来说,这是一种不错的替代方案。它的易用性可能与 SAS 相当,但在实现模型方面,它更简单,因为它提供了 SQL 代码来对模型进行评分。此代码通常效率不高,但这是一个开始,而 SAS 单独为每个数据库销售用于对模型进行评分的产品。对于小数据和没有经验的团队而言,SPSS 是与 SAS 一样好的一个选择。

但是,该软件的局限性相当大,有经验的用户使用 R 或 Python 的工作效率将高出几个数量级。

Matlab, Octave

还有其他工具可用,例如 Matlab 或其开源版本(Octave)。这些工具主要用于研究。就功能来说,R 或 Python 可以完成 Matlab 或 Octave 中的所有功能。如果您对他们提供的支持感兴趣的话,购买产品许可证才有意义。

Big Data Analytics - Statistical Methods

在分析数据时,可以采用统计方法。执行基本分析所需的基本工具为:

  1. Correlation analysis

  2. Analysis of Variance

  3. Hypothesis Testing

在处理大型数据集时,这些方法不涉及问题,因为这些方法在计算上并不密集,相关性分析除外。在这种情况下,始终可以抽取样本,并且结果应该是稳健的。

Correlation Analysis

相关性分析旨在找出数值变量之间的线性关系。这可能在不同情况下有用。一个常见的用途是探索性数据分析,在本书的第 16.0.2 节中有一个基本的示例。首先,所述示例中使用的相关性指标基于 Pearson coefficient 。但是,还有另一种不受异常值影响的有趣相关性指标。该指标称为 Spearman 相关性。

与 Pearson 方法相比, spearman correlation 指标对离群值的存在更鲁棒,当数据不呈正态分布时,它能更好地估计数值变量之间的线性关系。

library(ggplot2)

# Select variables that are interesting to compare pearson and spearman
correlation methods.
x = diamonds[, c('x', 'y', 'z', 'price')]

# From the histograms we can expect differences in the correlations of both
metrics.
# In this case as the variables are clearly not normally distributed, the
spearman correlation

# is a better estimate of the linear relation among numeric variables.
par(mfrow = c(2,2))
colnm = names(x)
for(i in 1:4) {
   hist(x[[i]], col = 'deepskyblue3', main = sprintf('Histogram of %s', colnm[i]))
}
par(mfrow = c(1,1))

从下图中的直方图中,我们可以期望两个指标的相关性存在差异。在这种情况下,由于变量明显不呈正态分布,因此 Spearman 相关性是数值变量之间线性关系的更好估计。

non normal distribution

要计算 R 中的相关性,请打开包含此代码部分的文件 bda/part2/statistical_methods/correlation/correlation.R

## Correlation Matrix - Pearson and spearman
cor_pearson <- cor(x, method = 'pearson')
cor_spearman <- cor(x, method = 'spearman')

### Pearson Correlation
print(cor_pearson)
#            x          y          z        price
# x      1.0000000  0.9747015  0.9707718  0.8844352
# y      0.9747015  1.0000000  0.9520057  0.8654209
# z      0.9707718  0.9520057  1.0000000  0.8612494
# price  0.8844352  0.8654209  0.8612494  1.0000000

### Spearman Correlation
print(cor_spearman)
#              x          y          z      price
# x      1.0000000  0.9978949  0.9873553  0.9631961
# y      0.9978949  1.0000000  0.9870675  0.9627188
# z      0.9873553  0.9870675  1.0000000  0.9572323
# price  0.9631961  0.9627188  0.9572323  1.0000000

Chi-squared Test

卡方检验允许我们测试两个随机变量是否独立。这意味着每个变量的概率分布不影响另一个变量。为了在 R 中评估检验,我们首先需要创建一个列联表,然后将该表传递给 chisq.test R 函数。

例如,让我们检查一下 diamond 数据集中变量 cut 和 color 之间是否存在关联。该检验的正式定义如下:

  1. H0:变量 cut 和 diamond 是独立的

  2. H1:变量切工和钻石并非独立

从这两个变量的名称来判断,我们会假设这两个变量之间存在一种关系,但检验可以给出一个客观“规则”,说明这个结果的重要性程度。

在以下代码片段中,我们发现检验的 p 值为 2.2e-16,在实际应用中该值为零。在运行 Monte Carlo simulation 检验之后,我们发现 p 值为 0.0004998,仍然比阈值 0.05 低。此结果意即我们拒绝原假设 (H0),我们相信变量 cutcolor 不是独立的。

library(ggplot2)

# Use the table function to compute the contingency table
tbl = table(diamonds$cut, diamonds$color)
tbl

#              D    E    F    G    H    I    J
# Fair       163  224  312  314  303  175  119
# Good       662  933  909  871  702  522  307
# Very Good 1513 2400 2164 2299 1824 1204  678
# Premium   1603 2337 2331 2924 2360 1428  808
# Ideal     2834 3903 3826 4884 3115 2093  896

# In order to run the test we just use the chisq.test function.
chisq.test(tbl)

# Pearson’s Chi-squared test
# data:  tbl
# X-squared = 310.32, df = 24, p-value < 2.2e-16
# It is also possible to compute the p-values using a monte-carlo simulation
# It's needed to add the simulate.p.value = TRUE flag and the amount of
simulations
chisq.test(tbl, simulate.p.value = TRUE, B = 2000)

# Pearson’s Chi-squared test with simulated p-value (based on 2000 replicates)
# data:  tbl
# X-squared = 310.32, df = NA, p-value = 0.0004998

T-test

t-test 的目的是评估数字变量 # 在标称变量的不同组之间的分布是否有所不同。为了展示这一点,我将选择因子变量切工的佳级和理想级,然后我们将比较这两个组之间的数字变量值。

data = diamonds[diamonds$cut %in% c('Fair', 'Ideal'), ]

data$cut = droplevels.factor(data$cut) # Drop levels that aren’t used from the
cut variable
df1 = data[, c('cut', 'price')]

# We can see the price means are different for each group
tapply(df1$price, df1$cut, mean)
# Fair    Ideal
# 4358.758 3457.542

t 检验在 R 中以 t.test 函数实现。公式接口到 t.test 是使用它的最简单方法,其原理是按组变量对数字变量进行解释。

例如: t.test(numeric_variable ~ group_variable, data = data) 。在上一个示例中, numeric_variablepricegroup_variablecut

从统计角度看,我们检验在两组之间数字变量的分布是否存在差异。从形式上讲,假设检验描述为一个原假设 (H0) 和一个备择假设 (H1)。

  1. H0:佳级和理想级组之间价格变量的分布没有差异

  2. H1:佳级和理想级组之间价格变量的分布有差异

以下内容可以用 R 中的如下代码实现:

t.test(price ~ cut, data = data)

# Welch Two Sample t-test
#
# data:  price by cut
# t = 9.7484, df = 1894.8, p-value < 2.2e-16
# alternative hypothesis: true difference in means is not equal to 0
# 95 percent confidence interval:
#   719.9065 1082.5251
# sample estimates:
#   mean in group Fair mean in group Ideal
#   4358.758            3457.542

# Another way to validate the previous results is to just plot the
distributions using a box-plot
plot(price ~ cut, data = data, ylim = c(0,12000),
   col = 'deepskyblue3')

我们可以通过检查 p 值是否低于 0.05 来分析检验结果。如果是,我们保留备择假设。这意味着我们发现切工因子的两个层级之间的价格有差异。根据层级的名称,我们会预料到此结果,但我们不会预料到不及格组的平均价格高于理想组。我们可以通过比较每个因子的均值来证明这一点。

plot 命令生成一个图,显示价格变量与切工变量之间的关系。它是一个箱形图;我们在第 16.0.1 节中已经介绍过这个图,但它基本显示了我们正在分析的两个切工等级的价格变量的分布。

different level cut

Analysis of Variance

方差分析 (ANOVA) 是一个统计模型,用于通过比较每个组的均值和方差来分析组分布之间的差异,该模型是由罗纳德·费舍尔开发的。ANOVA 提供了关于多个组均值是否相等的统计检验,因此它将 t 检验推广至两个以上组。

ANOVA 对于比较三个或更多个组的统计显著性非常有用,因为进行多个两样本 t 检验会增加犯统计 I 型错误的可能性。

在提供数学解释方面,需要了解以下内容才能理解此检验。

xij = x + (xi − x) + (xij − x)

它产生如下模型:

xij = μ + αi + ∈ij

其中 μ 是总体均值且 αi 是第 i 组均值。误差项 ∈ij 被假定从正态分布中独立同分布。检验的原假设为:

α1 = α2 = … = αk

就检验统计量的计算而言,我们需要计算两个值——

  1. 组间差异平方和——

SSD_B = \sum_{i}^{k} \sum_{j}^{n}(\bar{x_{\bar{i}}} - \bar{x})^2

  1. 组内平方和

SSD_W = \sum_{i}^{k} \sum_{j}^{n}(\bar{x_{\bar{ij}}} - \bar{x_{\bar{i}}})^2

其中 SSDB 的自由度为 k−1,SSDW 的自由度为 N−k。接着,我们可以为每个度量值定义均方差。

MSB = SSDB / (k - 1)

MSw = SSDw / (N - k)

最后,ANOVA 中的检验统计量定义为以上两个量的比值

F = MSB / MSw

其服从自由度为 k−1 和 N−k 的 F 分布。如果原假设为真,则 F 可能接近 1。否则,组间均方 MSB 可能较大,从而产生较大的 F 值。

基本上,ANOVA 会检验总方差的两种来源并查看哪一部分贡献更多。这就是为什么它被称为方差分析,尽管其目的是比较组均值。

就计算统计量而言,实际上在 R 中完成相当简单。以下示例将展示完成此操作并在结果中绘制图像的方法。

library(ggplot2)
# We will be using the mtcars dataset

head(mtcars)
#                    mpg  cyl disp  hp drat  wt  qsec   vs am  gear carb
# Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
# Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
# Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
# Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
# Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
# Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

# Let's see if there are differences between the groups of cyl in the mpg variable.
data = mtcars[, c('mpg', 'cyl')]
fit = lm(mpg ~ cyl, data = mtcars)
anova(fit)

# Analysis of Variance Table
# Response: mpg
#           Df Sum Sq Mean Sq F value    Pr(>F)
# cyl        1 817.71  817.71  79.561 6.113e-10 ***
# Residuals 30 308.33   10.28
# Signif. codes:  0 *** 0.001 ** 0.01 * 0.05 .
# Plot the distribution
plot(mpg ~ as.factor(cyl), data = mtcars, col = 'deepskyblue3')

此代码将产生以下输出——

variance analysis

我在示例中获得的 p 值显著小于 0.05,因此 R 会返回符号“ * ”以表示这一点。这意味着我们拒绝对原假设,并且发现不同组别的 cyl 变量的 mpg 均值之间存在差异。

Machine Learning for Data Analysis

机器学习是计算机科学的一个子领域,它涉及图案识别、计算机视觉、语音识别、文本分析等任务,并且与统计学和数学优化紧密相关。应用程序包括搜索引擎开发、垃圾邮件过滤、光学字符识别 (OCR) 等。数据挖掘、模式识别和统计学习领域之间的界限并不清晰,而且基本上都涉及类似问题。

机器学习可以分为两种类型的任务 −

  1. Supervised Learning

  2. Unsupervised Learning

Supervised Learning

监督学习是指一种问题,其中输入数据定义为矩阵 X,并且我们有兴趣预测响应 y。其中,X = {x1, x2, …, xn} 有 n 个预测变量并有 y = {c1, c2} 两个值。

一个示例应用程序是使用人口特征作为预测变量来预测网络用户点击广告的可能性。这通常称为预测点击率 (CTR)。然后,y = {点击,不点击},并且预测变量可能是用户的 IP 地址、他进入网站的那天、该用户的城市、国家以及可能的其他功能。

Unsupervised Learning

无监督学习解决的问题是查找组彼此相似,而无需学习课程。对于学习映射任务,有几种方法,从预测变量到查找每个组中共享相似实例并彼此不同的组。

无监督学习的一个示例应用是客户细分。例如,在电信行业,一项常见任务是根据用户使用手机的情况对用户进行细分。这将允许营销部门针对每组提供不同的产品。

Big Data Analytics - Naive Bayes Classifier

朴素贝叶斯是一种用于构建分类器的概率技术。朴素贝叶斯分类器的特征性假设是,在给定类别变量的情况下,某个特征的值独立于任何其他特征的值。

尽管有前面提到的过于简化的假设,但朴素贝叶斯分类器在复杂的现实世界情况下具有良好的结果。朴素贝叶斯的一个优势是,它只需要很少的训练数据来估计分类所需的各项参数,并且该分类器可以逐步训练。

朴素贝叶斯是一个条件概率模型:给定一个待分类的问题实例,由代表一些 n 个特征(自变量)的向量 x = (x1, …, xn)表示,它为该实例分配每个 K 个可能结果或类别的概率。

p(C_k|x_1,…​.., x_n)

上述公式的问题在于,如果特征数量 n 很大,或者某个特征可以取大量值,那么基于概率表构建这样的模型是不可行的。因此,我们重新制定模型以使其更简单。使用贝叶斯定理,条件概率可以分解为 −

p(C_k|x) = \frac{p(C_k)p(x|C_k)}{p(x)}

这意味着,在上述独立性假设下,类别变量 C 上的条件分布为 −

p(C_k|x_1,…​.., x_n)\: = \: \frac{1}{Z}p(C_k)\prod_{i = 1}^{n}p(x_i|C_k)

其中证据 Z = p( x ) 是仅依赖于 x1, …, xn 的缩放因子,如果特征变量的值已知,它是一个常数。一个共同的规则是选择概率最大的假设;这被称为最大后验或 MAP 决策规则。对应的分类器(贝叶斯分类器)是将类标签 $\hat{y} = C_k$ 分配给某个 k 的函数,如下所示 −

\hat{y} = argmax\: p(C_k)\prod_{i = 1}^{n}p(x_i|C_k)

用 R 实现该算法是一个简单的过程。以下示例演示了如何训练朴素贝叶斯分类器并在垃圾邮件过滤问题中使用它进行预测。

以下脚本可在 bda/part3/naive_bayes/naive_bayes.R 文件中找到。

# Install these packages
pkgs = c("klaR", "caret", "ElemStatLearn")
install.packages(pkgs)
library('ElemStatLearn')
library("klaR")
library("caret")

# Split the data in training and testing
inx = sample(nrow(spam), round(nrow(spam) * 0.9))
train = spam[inx,]
test = spam[-inx,]

# Define a matrix with features, X_train
# And a vector with class labels, y_train
X_train = train[,-58]
y_train = train$spam
X_test = test[,-58]
y_test = test$spam
# Train the model
nb_model = train(X_train, y_train, method = 'nb',
   trControl = trainControl(method = 'cv', number = 3))

# Compute
preds = predict(nb_model$finalModel, X_test)$class
tbl = table(y_test, yhat = preds)
sum(diag(tbl)) / sum(tbl)
# 0.7217391

从结果中可以看到,朴素贝叶斯模型的准确率为 72%。这意味着模型正确分类了 72% 的实例。

Big Data Analytics - K-Means Clustering

k 均值聚类旨在将 n 个观测值划分为 k 个簇,其中每个观测值属于具有最接近均值的簇,并充当该簇的原型。这导致数据空间划分为 Voronoi 单元。

给定一组观测值 (x1, x2, …, xn),其中每个观测值都是一个 d 维实向量,k 均值聚类旨在将 n 个观测值划分为 k 个组 G = {G1, G2, …, Gk},以便最小化如下定义的簇内平方和 (WCSS):

argmin \: \sum_{i = 1}^{k} \sum_{x \in S_{i}}\parallel x - \mu_{i}\parallel ^2

后一个公式显示了为了在 k 均值聚类中找到最佳原型而最小化的目标函数。该公式的直观含义是,我们希望找到彼此不同的组,并且每个组的每个成员都应与其所属簇的其他成员相似。

以下示例演示了如何在 R 中运行 k 均值聚类算法。

library(ggplot2)
# Prepare Data
data = mtcars

# We need to scale the data to have zero mean and unit variance
data <- scale(data)

# Determine number of clusters
wss <- (nrow(data)-1)*sum(apply(data,2,var))
for (i in 2:dim(data)[2]) {
   wss[i] <- sum(kmeans(data, centers = i)$withinss)
}

# Plot the clusters
plot(1:dim(data)[2], wss, type = "b", xlab = "Number of Clusters",
   ylab = "Within groups sum of squares")

为了为 K 找到一个好的值,我们可以为 K 的不同值绘制组内平方和。当添加更多组时,此度量通常会减少,我们希望找到组内平方和减少开始变慢的点。在图形中,此值由 K = 6 最佳表示。

number cluster

现在已经定义了 K 的值,需要使用该值运行该算法。

# K-Means Cluster Analysis
fit <- kmeans(data, 5) # 5 cluster solution

# get cluster means
aggregate(data,by = list(fit$cluster),FUN = mean)

# append cluster assignment
data <- data.frame(data, fit$cluster)

Big Data Analytics - Association Rules

令 I = i1, i2, …​, in 是称为项的 n 个二进制属性的集合。令 D = t1, t2, …​, tm 是称为数据库的事务集合。D 中的每笔交易具有唯一的交易 ID,并且包含 I 中项的子集。规则定义为形式为 X ⇒ Y 的蕴含,其中 X, Y ⊆ I 且 X ∩ Y = ∅。

项集(简称项集)X 和 Y 称为规则的前件(左侧或 LHS)和结果(右侧或 RHS)。

为了说明这些概念,我们使用超市领域的一个小示例。项集为 I = {牛奶、面包、黄油、啤酒},下表中显示了一个包含该项的小数据库。

Transaction ID

Items

1

milk, bread

2

bread, butter

3

beer

4

milk, bread, butter

5

bread, butter

超市的一个示例规则可以是 {牛奶、面包} ⇒ {黄油},这意味着如果购买牛奶和面包,顾客也会购买黄油。为了从所有可能的规则集中选择出有趣的规则,可以使用对各种重要性和兴趣度量要求约束。众所周知,对支持度和置信度的约束最低。

项集 X 的支持度 supp(X) 定义为包含该项集的数据集中事务的比例。在表 1 中的示例数据库中,项集 {牛奶、面包} 的支持度为 2/5 = 0.4,因为它出现在 40% 的所有交易中(5 笔交易中的 2 笔)。查找频繁项集可视为无监督学习问题的简化。

规则的置信度定义为 conf(X ⇒ Y ) = supp(X ∪ Y )/supp(X)。例如,规则 {牛奶、面包} ⇒ {黄油} 在表 1 中的数据库中的置信度为 0.2/0.4 = 0.5,这意味着在包含牛奶和面包的交易中,该规则在 50% 的交易中是正确的。置信度可解释为概率 P(Y|X) 的估计,即在这些事务也包含 LHS 的条件下,在事务中找到规则 RHS 的概率。

可以在 bda/part3/apriori.R 中找到用于实现 apriori algorithm 的代码。

# Load the library for doing association rules
# install.packages(’arules’)
library(arules)

# Data preprocessing
data("AdultUCI")
AdultUCI[1:2,]
AdultUCI[["fnlwgt"]] <- NULL
AdultUCI[["education-num"]] <- NULL

AdultUCI[[ "age"]] <- ordered(cut(AdultUCI[[ "age"]], c(15,25,45,65,100)),
   labels = c("Young", "Middle-aged", "Senior", "Old"))
AdultUCI[[ "hours-per-week"]] <- ordered(cut(AdultUCI[[ "hours-per-week"]],
   c(0,25,40,60,168)), labels = c("Part-time", "Full-time", "Over-time", "Workaholic"))
AdultUCI[[ "capital-gain"]] <- ordered(cut(AdultUCI[[ "capital-gain"]],
   c(-Inf,0,median(AdultUCI[[ "capital-gain"]][AdultUCI[[ "capitalgain"]]>0]),Inf)),
   labels = c("None", "Low", "High"))
AdultUCI[[ "capital-loss"]] <- ordered(cut(AdultUCI[[ "capital-loss"]],
   c(-Inf,0, median(AdultUCI[[ "capital-loss"]][AdultUCI[[ "capitalloss"]]>0]),Inf)),
   labels = c("none", "low", "high"))

为了使用 Apriori 算法生成规则,我们需要创建一个事务矩阵。以下代码展示了如何在 R 中执行此操作。

# Convert the data into a transactions format
Adult <- as(AdultUCI, "transactions")
Adult
# transactions in sparse format with
# 48842 transactions (rows) and
# 115 items (columns)

summary(Adult)
# Plot frequent item-sets
itemFrequencyPlot(Adult, support = 0.1, cex.names = 0.8)

# generate rules
min_support = 0.01
confidence = 0.6
rules <- apriori(Adult, parameter = list(support = min_support, confidence = confidence))

rules
inspect(rules[100:110, ])
# lhs                             rhs                      support     confidence  lift
# {occupation = Farming-fishing} => {sex = Male}        0.02856148  0.9362416   1.4005486
# {occupation = Farming-fishing} => {race = White}      0.02831579  0.9281879   1.0855456
# {occupation = Farming-fishing} => {native-country     0.02671881  0.8758389   0.9759474
                                       = United-States}

Big Data Analytics - Decision Trees

决策树是一种用于分类或回归等监督学习问题的算法。决策树或分类树是一种树,其中每个内部(非叶)节点都标记有输入特征。源自标记有某个特征的节点的弧线都标记有该特征的每个可能值。树的每个叶都标记有类别或类别概率分布。

可以通过基于属性值检验将源集拆分为子集来“学习”树。此过程在称为 recursive partitioning 的递归方式中对每个派生子集重复执行。当某个节点的子集具有目标变量的所有相同值,或当拆分不再为预测增加价值时,递归完成。这种由上至下归纳决策树的过程是贪心算法的一个示例,并且是学习决策树最常见的策略。

数据挖掘中使用的决策树主要有以下两种类型:

  1. Classification tree −当响应是名词变量时,例如电子邮件是否是垃圾邮件。

  2. Regression tree −当预测结果可以被认为是一个实数时(例如工人的工资)。

决策树是一种简单的方法,因此有一些问题。此问题之一是决策树产生的结果模型中的高方差。为了减轻此问题,开发了决策树集成方法。目前广泛使用两组集成方法−

  1. Bagging decision trees −这些树用于通过重复带替换地重新采样训练数据来构建多个决策树,并为共识预测投票树。此算法被称为随机森林。

  2. Boosting decision trees −梯度提升结合弱学习器;在此情况下,反复将决策树组合成一个单一的强学习器。它为数据拟合弱树,并通过迭代拟合弱学习器来校正前一个模型的误差。

# Install the party package
# install.packages('party')
library(party)
library(ggplot2)

head(diamonds)
# We will predict the cut of diamonds using the features available in the
diamonds dataset.
ct = ctree(cut ~ ., data = diamonds)

# plot(ct, main="Conditional Inference Tree")
# Example output
# Response:  cut
# Inputs:  carat, color, clarity, depth, table, price, x, y, z

# Number of observations:  53940
#
# 1) table <= 57; criterion = 1, statistic = 10131.878
#   2) depth <= 63; criterion = 1, statistic = 8377.279
#     3) table <= 56.4; criterion = 1, statistic = 226.423
#       4) z <= 2.64; criterion = 1, statistic = 70.393
#         5) clarity <= VS1; criterion = 0.989, statistic = 10.48
#           6) color <= E; criterion = 0.997, statistic = 12.829
#             7)*  weights = 82
#           6) color > E

#Table of prediction errors
table(predict(ct), diamonds$cut)
#            Fair  Good Very Good Premium Ideal
# Fair       1388   171        17       0    14
# Good        102  2912       499      26    27
# Very Good    54   998      3334     249   355
# Premium      44   711      5054   11915  1167
# Ideal        22   114      3178    1601 19988
# Estimated class probabilities
probs = predict(ct, newdata = diamonds, type = "prob")
probs = do.call(rbind, probs)
head(probs)

Big Data Analytics - Logistic Regression

逻辑回归是一种响应变量为分类变量的分类模型。它是一种来自统计学的算法,用于监督分类问题。在逻辑回归中,我们寻求找到使成本函数最小的以下方程中的参数向量 β。

logit(p_i) = ln \left ( \frac{p_i}{1 - p_i} \right ) = \beta_0 + \beta_1x_{1,i} + …​ + \beta_kx_{k,i}

以下代码演示如何在 R 中拟合逻辑回归模型。我们在这里将使用垃圾邮件数据集来演示逻辑回归,这与朴素贝叶斯所使用的数据集相同。

从准确率方面的预测结果中,我们发现回归模型在测试集中达到 92.5% 的准确率,而朴素贝叶斯分类器的准确率为 72%。

library(ElemStatLearn)
head(spam)

# Split dataset in training and testing
inx = sample(nrow(spam), round(nrow(spam) * 0.8))
train = spam[inx,]
test = spam[-inx,]

# Fit regression model
fit = glm(spam ~ ., data = train, family = binomial())
summary(fit)

# Call:
#   glm(formula = spam ~ ., family = binomial(), data = train)
#

# Deviance Residuals:
#   Min       1Q   Median       3Q      Max
# -4.5172  -0.2039   0.0000   0.1111   5.4944
# Coefficients:
# Estimate Std. Error z value Pr(>|z|)
# (Intercept) -1.511e+00  1.546e-01  -9.772  < 2e-16 ***
# A.1         -4.546e-01  2.560e-01  -1.776 0.075720 .
# A.2         -1.630e-01  7.731e-02  -2.108 0.035043 *
# A.3          1.487e-01  1.261e-01   1.179 0.238591
# A.4          2.055e+00  1.467e+00   1.401 0.161153
# A.5          6.165e-01  1.191e-01   5.177 2.25e-07 ***
# A.6          7.156e-01  2.768e-01   2.585 0.009747 **
# A.7          2.606e+00  3.917e-01   6.652 2.88e-11 ***
# A.8          6.750e-01  2.284e-01   2.955 0.003127 **
# A.9          1.197e+00  3.362e-01   3.559 0.000373 ***
# Signif. codes:  0 *** 0.001 ** 0.01 * 0.05 . 0.1  1

### Make predictions
preds = predict(fit, test, type = ’response’)
preds = ifelse(preds > 0.5, 1, 0)
tbl = table(target = test$spam, preds)
tbl

#         preds
# target    0   1
# email   535  23
# spam     46 316
sum(diag(tbl)) / sum(tbl)
# 0.925

Big Data Analytics - Time Series Analysis

时间序列是被日期或时间戳索引的分类或数字变量观测序列。时间序列数据的明显示例是股票价格的时间序列。在下表中,我们可以看到时间序列数据的基本结构。在这种情况下,每小时记录一次观测结果。

Timestamp

Stock - Price

2015-10-11 09:00:00

100

2015-10-11 10:00:00

110

2015-10-11 11:00:00

105

2015-10-11 12:00:00

90

2015-10-11 13:00:00

120

通常,时间序列分析的第一步是绘制序列,通常使用折线图进行。

时间序列分析最常见的应用是使用数据的时态结构预测数字值的未来值。这意味着,可用的观测值用于预测未来的值。

数据的时序顺序意味着传统的回归方法不起作用。为了构建稳健的预测,我们需要考虑数据时间排序的模型。

时间序列分析中使用最广泛的模型称为 Autoregressive Moving Average (ARMA)。该模型由两部分组成,即 autoregressive (AR) 部分和 moving average (MA) 部分。该模型通常称为 ARMA(p, q) 模型,其中 p 是自回归部分的阶数,q 是滑动平均部分的阶数。

Autoregressive Model

AR(p) 被解读为 p 阶自回归模型。在数学上,它写成 −

X_t = c + \sum_{i = 1}^{P} \phi_i X_{t - i} + \varepsilon_{t}

其中 {φ1, …, φp} 是要估计的参数,c 是常量,随机变量 εt 表示白噪声。对参数的值有一些必要的约束,以便模型保持平稳。

Moving Average

表示法 MA(q) 指 q 阶滑动平均模型 −

X_t = \mu + \varepsilon_t + \sum_{i = 1}^{q} \theta_i \varepsilon_{t - i}

其中 θ1, …​, θq 是模型的参数,μ 是 Xt 的期望,而 εt、εt − 1、…​ 是白噪声错误项。

Autoregressive Moving Average

ARMA(p, q) 模型结合了 p 个自回归项和 q 个移动平均项。在数学上,该模型用以下公式表示 −

X_t = c + \varepsilon_t + \sum_{i = 1}^{P} \phi_iX_{t - 1} + \sum_{i = 1}^{q} \theta_i \varepsilon_{t-i}

我们可以看到,ARMA(p, q) 模型是 AR(p) 和 MA(q) 模型的组合。

为了直观地了解该模型,请考虑公式的 AR 部分旨在估计 Xt − i 观测值的参数,以便预测 Xt 中变量的值。最终是对过去值的加权平均。MA 部分使用相同的方法,但使用先前观测的误差 εt − i。因此,最终,模型的结果是一个加权平均值。

以下代码片段演示如何在 R 中实现 ARMA(p, q)。

# install.packages("forecast")
library("forecast")

# Read the data
data = scan('fancy.dat')
ts_data <- ts(data, frequency = 12, start = c(1987,1))
ts_data
plot.ts(ts_data)

绘制数据通常是找出数据中是否存在时间结构的第一步。我们可以从图表中看到,每年的年底都有强劲的飙升。

time series plot

以下代码将 ARMA 模型拟合到数据。它运行了多个模型组合,并选择了误差最小的模型。

# Fit the ARMA model
fit = auto.arima(ts_data)
summary(fit)

# Series: ts_data
# ARIMA(1,1,1)(0,1,1)[12]
#    Coefficients:
#    ar1     ma1    sma1
# 0.2401  -0.9013  0.7499
# s.e.  0.1427   0.0709  0.1790

#
# sigma^2 estimated as 15464184:  log likelihood = -693.69
# AIC = 1395.38   AICc = 1395.98   BIC = 1404.43

# Training set error measures:
#                 ME        RMSE      MAE        MPE        MAPE      MASE       ACF1
# Training set   328.301  3615.374  2171.002  -2.481166  15.97302  0.4905797 -0.02521172

Big Data Analytics - Text Analytics

在本章中,我们将使用本书第 1 部分中抓取的数据。数据包含描述自由职业者资料的文本,以及他们以美元收取的时薪。下一部分的想法是拟合一个模型,根据自由职业者的技能,我们可以预测他们的时薪。

以下代码显示了如何将本例中的原始文本转换为词袋矩阵中的单词。为此,我们使用了一个名为 tm 的 R 库。这意味着对于语料库中的每个单词,我们都会创建变量,其中包含每个变量的出现次数。

library(tm)
library(data.table)

source('text_analytics/text_analytics_functions.R')
data = fread('text_analytics/data/profiles.txt')
rate = as.numeric(data$rate)
keep = !is.na(rate)
rate = rate[keep]

### Make bag of words of title and body
X_all = bag_words(data$user_skills[keep])
X_all = removeSparseTerms(X_all, 0.999)
X_all

# <<DocumentTermMatrix (documents: 389, terms: 1422)>>
#   Non-/sparse entries: 4057/549101
# Sparsity           : 99%
# Maximal term length: 80
# Weighting          : term frequency - inverse document frequency (normalized) (tf-idf)

### Make a sparse matrix with all the data
X_all <- as_sparseMatrix(X_all)

现在我们已经将文本表示为稀疏矩阵,我们可以拟合一个将提供稀疏解的模型。在这种情况下,一个很好的替代方法是使用 LASSO(最小绝对收缩和选择算子)。这是一个回归模型,能够选择预测目标的最相关特征。

train_inx = 1:200
X_train = X_all[train_inx, ]
y_train = rate[train_inx]
X_test = X_all[-train_inx, ]
y_test = rate[-train_inx]

# Train a regression model
library(glmnet)
fit <- cv.glmnet(x = X_train, y = y_train,
   family = 'gaussian', alpha = 1,
   nfolds = 3, type.measure = 'mae')
plot(fit)

# Make predictions
predictions = predict(fit, newx = X_test)
predictions = as.vector(predictions[,1])
head(predictions)

# 36.23598 36.43046 51.69786 26.06811 35.13185 37.66367
# We can compute the mean absolute error for the test data
mean(abs(y_test - predictions))
# 15.02175

现在我们有一个模型,可以根据一组技能预测自由职业者的时薪。如果收集更多数据,该模型的性能将得到提高,但实施此管道的代码将保持不变。

Big Data Analytics - Online Learning

在线学习是机器学习的一个子领域,它允许将监督学习模型扩展到海量数据集。基本思想是我们不需要在内存中读取所有数据来拟合模型,我们只需要一次读取每个实例。

在这种情况下,我们将展示如何使用逻辑回归来实现在线学习算法。与大多数监督学习算法一样,有一个要最小化的成本函数。在逻辑回归中,成本函数定义为−

J(\theta) \: = \: \frac{-1}{m} \left [ \sum_{i = 1} {m}y {(i)}log(h_{\theta}(x^{(i)})) + (1 - y^{(i)}) log(1 - h_{\theta}(x^{(i)})) \right ]

其中 J(θ) 表示成本函数,hθ(x) 表示假设。在逻辑回归的情况下,它由以下公式定义−

h_\theta(x) = \frac{1}{1 + e {\theta T x}}

现在我们已经定义了成本函数,我们需要找到一个算法来最小化它。实现这一点的最简单算法称为随机梯度下降。逻辑回归模型权重的算法更新规则定义如下−

\theta_j : = \theta_j - \alpha(h_\theta(x) - y)x

有几种实现以下算法的方法,但 vowpal wabbit 库中实现的方法是到目前为止最成熟的一种。该库允许训练大规模回归模型,并使用少量 RAM。用创建者自己的话说,它被描述为:“Vowpal Wabbit (VW) 项目是由 Microsoft Research 和(之前的)Yahoo! Research 赞助的快速 out-of-core 学习系统”。

我们将在 kaggle 竞赛中使用泰坦尼克号数据集。原始数据可以在 bda/part3/vw 文件夹中找到。在这里,我们有两个文件−

  1. 我们有训练数据(train_titanic.csv)和

  2. 未标记数据以进行新的预测 (test_titanic.csv)。

要将 csv 格式转换为 vowpal wabbit 输入格式,可以使用 csv_to_vowpal_wabbit.py python 脚本。很明显,你需要为此安装 python。导航到 bda/part3/vw 文件夹,打开终端并执行以下命令 −

python csv_to_vowpal_wabbit.py

请注意,对于此部分,如果你使用的是 Windows,你需要安装一个 Unix 命令行,进入 cygwin 网站。

打开终端,并在 bda/part3/vw 文件夹中执行以下命令 −

vw train_titanic.vw -f model.vw --binary --passes 20 -c -q ff --sgd --l1
0.00000001 --l2 0.0000001 --learning_rate 0.5 --loss_function logistic

让我们分解 vw call 的每个参数。

  1. -f model.vw − 表示我们在 model.vw 文件中保存模型以供稍后进行预测。

  2. --binary − 使用 -1,1 标记报告损失为二进制分类。

  3. --passes 20 − 数据用于学习权重 20 次。

  4. -c − 创建缓存文件。

  5. -q ff − 在 f 命名空间中使用二次特征。

  6. --sgd − 使用常规/经典/简单随机梯度下降更新,即非自适应、非归一化和非不变的。

  7. --l1 --l2 − L1 和 L2 范数正则化。

  8. --learning_rate 0.5 − 更新规则公式中定义的学习速率 αas。

以下代码显示了在命令行中运行回归模型的结果。在结果中,我们获得了平均对数损失和算法性能的一个小报告。

-loss_function logistic
creating quadratic features for pairs: ff
using l1 regularization = 1e-08
using l2 regularization = 1e-07

final_regressor = model.vw
Num weight bits = 18
learning rate = 0.5
initial_t = 1
power_t = 0.5
decay_learning_rate = 1
using cache_file = train_titanic.vw.cache
ignoring text input in favor of cache input
num sources = 1

average    since         example   example  current  current  current
loss       last          counter   weight    label   predict  features
0.000000   0.000000          1      1.0    -1.0000   -1.0000       57
0.500000   1.000000          2      2.0     1.0000   -1.0000       57
0.250000   0.000000          4      4.0     1.0000    1.0000       57
0.375000   0.500000          8      8.0    -1.0000   -1.0000       73
0.625000   0.875000         16     16.0    -1.0000    1.0000       73
0.468750   0.312500         32     32.0    -1.0000   -1.0000       57
0.468750   0.468750         64     64.0    -1.0000    1.0000       43
0.375000   0.281250        128    128.0     1.0000   -1.0000       43
0.351562   0.328125        256    256.0     1.0000   -1.0000       43
0.359375   0.367188        512    512.0    -1.0000    1.0000       57
0.274336   0.274336       1024   1024.0    -1.0000   -1.0000       57 h
0.281938   0.289474       2048   2048.0    -1.0000   -1.0000       43 h
0.246696   0.211454       4096   4096.0    -1.0000   -1.0000       43 h
0.218922   0.191209       8192   8192.0     1.0000    1.0000       43 h

finished run
number of examples per pass = 802
passes used = 11
weighted example sum = 8822
weighted label sum = -2288
average loss = 0.179775 h
best constant = -0.530826
best constant’s loss = 0.659128
total feature number = 427878

现在我们可以使用我们训练的 model.vw 来生成新数据的预测。

vw -d test_titanic.vw -t -i model.vw -p predictions.txt

在前面的命令中生成的预测未规范化以适合 [0, 1] 范围。为此,我们使用 sigmoid 转换。

# Read the predictions
preds = fread('vw/predictions.txt')

# Define the sigmoid function
sigmoid = function(x) {
   1 / (1 + exp(-x))
}
probs = sigmoid(preds[[1]])

# Generate class labels
preds = ifelse(probs > 0.5, 1, 0)
head(preds)
# [1] 0 1 0 0 1 0