机器学习与数据科学(基于R的统计学习方法)

978-7-115-45240-5
作者: 【美】Daniel D. Gutierrez(古铁雷斯)
译者: 施翊
编辑: 陈冀康

图书目录:

详情

本书通过8章内容,由浅入深地介绍了机器学习、数据处理、数据再加工、数据分析、回归分析、数据分类、模型性能评估以及无监督学习等内容。可谓是每一章都是当前最新颖最有探索价值的专题,对于想要了解机器学习和数据科学相关内容的读者,一定是必读之选。

图书摘要

版权信息

书名:机器学习与数据科学(基于R的统计学习方法)

ISBN:978-7-115-45240-5

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    [美] Daniel D. Gutierrez

    译    施 翊

    责任编辑 陈冀康

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

    邮编 100164  电子邮件 315@ptpress.com.cn

    网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

    反盗版热线:(010)81055315


Simplified Chinese translation copyright ©2017 by Posts and Telecommunications Press

ALL RIGHTS RESERVED

Machine Learning and Data Science, an Introduction to Statistical Learning Methods with R, by Daniel D. Gutierrez ISBN 9781634620963

Copyright © 2016 by Technics Publications, LLC

本书中文简体版由Technics Publications授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。

版权所有,侵权必究。


 

当前,机器学习和数据科学都是很重要和热门的相关学科,需要深入地研究学习才能精通。

本书试图指导读者掌握如何完成涉及机器学习的数据科学项目。本书将为数据科学家提供一些在统计学习领域会用到的工具和技巧,涉及数据连接、数据处理、探索性数据分析、监督机器学习、非监督机器学习和模型评估。本书选用的是R统计环境,书中所有代码示例都是用R语言编写的,涉及众多流行的R包和数据集。

本书适合数据科学家、数据分析师、软件开发者以及需要了解数据科学和机器学习方法的科研人员阅读参考。


 

在我的童年时代,我十分喜爱著名科幻作家、教授艾萨克·阿西莫夫(Asimov Isaac)的《基地三部曲》。故事的主角叫作Hari Seldon,他是一位开创了“心理历史学”的数学教授,这门学科涉及历史学、社会学和数理统计,可以用来预测未来事件发生的概率。因此,我从小就迷上了预测这一概念。很自然地,我长大后成为了一名数据科学家。我把机器学习类比为Seldon的素数辐射法(Prime Radiant),是一个存储“心理历史学方程”的工具,可以用来展示人类未来发展前景。

远在“数据科学”这一概念问世之前,我就已经成为(或者假装成为)一名数据科学家(data scientist)很多年了。“数据科学家”这一头衔经历了数十年职业演化才建立,对此我表示十分欣喜。最近在业内论坛上,人们针对“数据科学”是否能恰当描述这一领域展开了激烈的辩论。我认为这个术语确实做出了了不起的贡献,因为数据科学家所做的事情实际上大多都是实验,这对我日复一日的基础工作毫无疑问是有效的科学方法(scientific method)。我个人认为“数据科学”比“数据挖掘”(data mining)或者“商业智能”(business intelligence)更精确、描述得更好。随着时间的流逝,后两种表述经历了严格的技术成熟度曲线。我对“数据科学家”这一称呼很满意,因为我真切地感受到自己是一个用数据进行实验的科学家。

这里讲讲我是如何理解数据科学用科学方法来解决问题的。

机器学习是数据科学家用来做预测和检验假设有效性的基本工具集。让我们继续简要地了解一下机器学习是什么、数据科学家用它来做什么。“机器学习”这一表述代表了多学科的融合:计算机科学(computer science)、数理统计、概率论和数据可视化。在接下去的章节中,我们将会看到机器学习有两大基本类型:监督学习(supervised learning)用于预测,非监督学习(unsupervised learning)用于发现。如果你真的想深入理解各种机器学习算法的奥秘,必须明白多个数学领域的原理,例如数理统计、概率论(probability theory)、计算学、线性代数(linear algebra)、偏微分方程(partial differential equations)和组合数学(combinatorics)。好在,在本书中我们使用了R语言,所以无需钻研算法的基本原理。我们只需要学习如何使用它们。

本书希望能带领读者走进一个涉及机器学习的数据科学项目。并不是说我在这里提供的是学习机器学习的唯一方法,而是我认为这是数据科学家工作的典型方式。这一方法多年来对我十分受用,我希望通过本书把我的经验传授给大家。以下是本书的分章介绍。

在介绍机器学习的过程中,为了让读者的学习过程尽可能简单和直截了当,我确定了几个基本原则。

本书的目标受众相当广泛。如果你是一名分析师,不论在私人企业还是公众部门,需要通过从一些工具(如Excel)中得到的特征集来扩展你的分析技巧,那么这本书适合你;如果你是一位软件开发者,需要在代码中实现机器学习,那么这本书适合你;如果你是一名学术科研人员,需要了解数据科学和机器学习方法的最新进展,那么这本书适合你。这些细分读者的共同点是:诚心诚意地想要学习这一领域基础知识,并想快速地做出一些成绩。我希望各行各业的读者都能在本书中有所收获,因此书里使用的案例涉及各个领域。

我假设你已经了解了R程序设计,或者通过本书给出的一些材料能快速的学会它。我们不教授R语言,而是把R作为一个快速上手机器学习的工具。好消息是本书只使用了一些很基本的R语言;坏消息是,众所周知,R语言对初学者来说十分晦涩难懂。书中使用的大部分R代码脚本十分直白,在有必要的情况下,我会在代码中添加注释来解释。我不会浪费时间用复杂棘手的代码来介绍机器学习的概念。我希望你有足够的动力来面对快速了解机器学习这一挑战。本书会提供学习的大纲,同时下面也会给出很多附加的学习资源来帮助你完成这一过程。

本书不需要任何其他附加的硬件或者软件,很显然,你需要R统计编程环境。好在,它是开源的,可以免费使用。你可以通过访问www.r-project.org来获取R软件。它可以在各种UNIX平台、Windows和MacOS环境下安装运行。当你在访问www.r-project.org网站时,请尽可能利用上面所有的学习资源,包括R手册、R期刊、图书和其他关于R的文档。

在学习本书的过程中,另一个强烈推荐使用的软件是RStudio集成开发环境(IDE)。访问www.rstudio.com来下载RStudio。RStudio是一个功能强大的R用户界面,免费开源,并且在Windows、Mac和Linux上都有很好的表现。在编写这本书的过程中,我频繁使用了RStudio,也推荐你这样做。虽然你可以使用R自带的基本编程环境来工作,但是RStudio包含了很多对程序员来说很有吸引力的特色:

在学习本书的过程中,你也需要一些额外的R包(拓展R的统计环境)。这些R包也是开源的,并且能在R内部进行下载和安装。当具体案例出现时,我会指导你如何下载、使用R包。

同时,我也有意地避免读者去寻找、下载和安装本书案例中用到的数据集。在大多数情况下,我尽量使用R自带的数据集;在一些情况下,我们可能使用特定的R包带有的数据集;在少数其他情况下,我使用了R之外的数据集,但是我会指导你如何连接这些数据集。

你会发现本书包含了很多R编程代码的示例,以及使用特定命令后R环境所返回的结果。为了在本书中展示代码,我将把熟悉的“>”符号放在R控制台输入的所有命令之前。我们也会使用一种特殊的“代码字体”(courier new)以便和本书正文区分。此外,R的输出也会用同样的代码字体显示,但是前面没有“>”标识。在阅读本书的时候,我鼓励你们自行在R环境中输入所有的代码示例,以便获得使用这一环境的语感。改变不同的元素来实验每个代码示例,观察输出的不同结果,这同样也是一个不错的学习方法。

为了让你的学习经历尽可能愉快,我在出版社网站(https://technicspub. com/analytics/)上传了本书中使用的所有R源代码和注释。同时也收录了所有的图表(很多是彩色的),它们在正文中是以灰度图的形式存在的,这会使一些图表更易于理解。日后你可以访问这一资源库得到最新的代码。

一旦你读完了本书,你将需要一些指导,关于如何更进一步学习机器学习。好在,机器学习在过去的几年里逐渐演化完整,该领域正日益受到关注。因此,有很多资源能帮助你扩充知识面。学无止境,你只需要考虑自己想钻研到多深入。为了帮助你开始学习,这里有一个简短的资源列表。

你可以通过多种方式找到我。访问我的咨询公司网站www.amuletanalytics. com或者在LinkedIn上都可以。然而可能最容易找到我的地方是在Twitter上(@AMULETAnalytics)。在那里你可以订阅我,我会发布关于数据科学、机器学习和大数据的一些感想。


 

机器学习(Machine Learning)可以看成是从观察自然世界来推断结果和提取灵感的一套工具和方法。举个生活中常见的例子,你想通过房间数、卫生间数、建筑面积和地皮尺寸来预测一栋房子的价格,可以使用一个简单的机器学习算法(例如,线性回归),从现有的真实房地产销售数据集中学习,通过机器学习数据集中每栋房子的售价,可以预测尚未出售的房屋售价。事实上,这种预测需要海量数据(通常规模在TB以上)的支撑。同时,数据的质量对预测结果准确度起着十分重要的作用,就像数据科学界的一句耳熟能详的话说的那样:好算法不如大数据。

近年来,机器学习已经发展成一门很成熟的学科。它逐渐成为数据科学领域的促进者,反过来,数据科学的发展也带动了大数据(Big Data)的发展。然而,机器学习并不是一门全新的学科,它的基本原理在相当长时间前就已经深入人心了,只是使用了不同的名称,例如,“数据挖掘”“在数据库中的知识挖掘(knowledge discovery)”和“商业智能”,这些术语都是机器学习的传统叫法。在此之前,“统计”和“数据分析”都用来描述从数据中收集信息的过程。我相信机器学习是现在描述这个领域的最好术语。Machine Learning也因为大量引用而成为Twitter圈中的热门标签。考虑到通过数据对系统进行的建设和研究,机器学习也被看成是人工智能(artificial intelligence)的一个分支。现如今,机器学习的应用大多依赖云存储硬件和性能优异的并行框架,如Apache公司的Hadoop和AMP实验室的Spark。

“机器学习”第一次正式使用是在1959年,当时在IBM公司工作的Arthur Samuel把机器学习描述成赋予未设定程序的计算机学习能力。很快,到了1998年,卡耐基梅隆(Carnegie Mellon)大学机器学习系的系主任Tom Mitchell给学习程序下了一个定义:

如果一个计算机程序针对某类任务T的性能用P衡量,且根据经验E来自我完善,那么我们称这个计算机程序在从经验E中学习,针对某类任务T,它的性能用P来衡量。

Mitchell这个广为人知的定义适用范围非常广泛,能概括我们通常所说的大多数“学习”任务。在这一定义下,我们举一个机器学习问题的例子:考虑任务T是把垃圾邮件做分类,性能指标P是被正确分类的垃圾邮件的百分比,和训练集E是已经分好类(垃圾邮件或正常邮件)的邮件数据集。垃圾邮件分类器是机器学习解决现实商业问题的首批应用之一,如今它也应用在绝大部分邮件软件中。

启动一个新的机器学习项目时,另一条需要时刻谨记在心的公理是美国数学家John Tukey提出的,他因为在统计方式上的贡献和1977年开创性的著作《Exploratory Data Analysis》而受到统计学圈子的推崇:

拥有数据和对结果的渴求并不能确保从已知的数据中得到一个合理的结果。

这一准则意味着一个合格的机器学习从业者需要知道什么时候应该放弃,什么时候你拥有的数据不足以得出需要的答案。另一条耳熟能详的格言“输入无用数据,就会输出无用数据”同样也适用于机器学习领域。

本书会向读者介绍机器学习的基本原理。作为数据科学和大数据产业的主要推动力,机器学习在众多行业中广受关注,它可以为企业提供使公司数据资产增值的新方法。在本书中,我们会基于R语言统计环境学习机器学习算法的原理,包括两种基本类型:监督学习和非监督学习。

监督机器学习(Supervised machine learning)通常与预测有关,与每个观测值(也称为特征变量,feature variable)对应,都有一个结果值。监督学习的训练目标是根据响应模型准确预测未来的观测值对应的响应结果。很多传统的学习算法,诸如线性回归或逻辑回归,都属于监督学习的领域。

非监督机器学习(Unsupervised machine learning)是更开放性的一种类型。它不使用标记好的数据集,而是一套应用于程序上的统计工具,在大量的观测中只测量其中一组特征变量。在这种情况下,预测不再是学习的目标,因为数据集没有被标记,不存在可以监督分析行为的响应变量。事实上,非监督学习的目标是通过对特征变量的观测来挖掘一些有趣的事情。例如,你可以找到一个数据形象化的展现方式,或者发现数据集中隐藏的子群。

非监督学习技术的一个常用的场景是K-均值聚类,即在数据点集中找出“聚类”。另一种常用技术叫做主成分分析(PCA),用于降维,也就是说,在保持数据多样性的同时,减少特征变量,来简化学习算法中的数据复杂度,加快数据处理效率,并能降低所需的内存占用。

在本节内容中,我将向大家展示一些使用机器学习解决日常问题的例子。在学习这些案例之前,查看项目最初的需求,回顾数据集和每一个特征变量,并搞清楚如何判断解决方案是否成功,会让你的阅读事半功倍。阅读完本书之后,你甚至可以尝试自己的解决方案。为了做这些事情,我将特别推荐Kaggle(www.kaggle.com)的数据挑战赛,它的金钱奖励已经吸引了全世界成千上万的数据科学家进行挑战。

在这些数据科学挑战中,参赛者为了寻找成功的解决方案,需要考虑以下问题。

1.为谁解决问题?解决什么问题?

2.现在这个问题是怎么解决的(如果已经有解决方案的话)?

3.针对这个问题,可用的数据集是什么?这些数据集的来源是哪里?

4.解决方案的结果如何展现(如商业智能仪表盘、在线应用中引入算法、一份静态管理报告等等)?

5.这是什么类型的问题:为了降低收入流失(节流)还是增加收入(开源)?

在不同的比赛中,算法的评估方法也不尽相同。最常用的方法是将均方根误差(RMSE)的值降到最小,这一数值用于评价测试集的预测结果是否准确。RMSE评价法会在第7章进行更深入的解释。另一种常用的评估方法是AUC,即ROC曲线下的面积。

Kaggle挑战赛的一些赞助商也会参与比赛,有些为了获得产品或服务的新的发展方向,有些为了招聘比赛中的赢家。对于你,一个上升期的数据科学家来说,这些挑战赛可以当做是磨炼技能的优秀训练场。

品牌商为了吸引新客户购买商品,经常举办打折活动。在最初的激励性购买后,重复购买商品的回头客对品牌方来说是最有价值的。有足够多的购物记录之后,可以预测在一次促销活动中,哪些顾客会再次购买商品。然而,在第一次购物之前就鉴别哪些顾客会成为忠诚的买主,这是一项更有挑战性的工作。

预测回头客挑战赛(Acquire Valued Shoppers Challenge)需要挑战者预测哪些顾客最可能成为回头客。为了增强算法的准确性,参赛的数据科学家得到了参与促销活动的大量顾客的完整购物记录,包括购买产品的类型和价格。比赛组织者也为顾客提供了初次购物和再次购物的激励。这个比赛的奖金是30000美元。

这个项目提供了超过30万名匿名顾客的将近3亿5千行交易记录数据,解压后达到22GB,大大超过了普通笔记本电脑的容量。在这一量级下,这个项目可以看做是“大数据”项目,所以,一个著名的供应商为参赛者提供了一个特别的工具。Revolution Analytics(Microsoft)公司为参赛者免费提供了亚马逊云服务(AWS,Amazon Web Services)下的R集成开发环境。有了AWS下的Linux机器的助力,内存容量可达到64GB,参赛者可以使用R集成开发环境下的并行外部存储算法。这个挑战赛是现实生活中数据项目的大小指数型增长带来的挑战的一个体现。

在图1-1的散点图中,展示了客户重复去商店的次数,x轴是商品的报价,数据点通过商场地理位置的不同来进行着色。

图1-1 使用预测回头客挑战赛数据绘制的探索图

第一个著名的数据科学比赛可能是Netflix公司赞助的。这个著名的Netflix奖力图大幅度地提升预测的精确度:基于用户的观影偏好,预测他喜爱一部电影的程度。在2009年9月21日,Netflix公司给BellKor’s Pragmatic Chaos队授予了100万美元的特等奖。BellKor队险胜The Ensemble队,他们的获胜作品在这个接近3年的比赛结束前的24分钟才提交。

用来解决Netflix奖的机器学习算法以均方根误差(RMSE,root mean square error)来衡量算法的好坏。均方根误差除了是一个众所周知的度量标准和数值之外,还有一个有用的性质:它可以放大极端误差带来的影响,无论是假阳性还是假阴性。这是理解任何推荐系统的重要性质。当然,简单的预测精度指标并不能概括在做推荐时很多其他重要的方面。举个例子,它不能预测推荐的顺序。不过,该队使用了特别的措施来降低均方根误差来赢得比赛。最终,获胜的解决方案将Netflix的推荐算法精确度提升了10%。

BellKor队的Netflix奖的解决方案涉及了很多机器学习的高新技术:协同滤波、用时间动力学进行矩阵分解、受限的玻尔兹曼机(RBM,Restricted Boltzmann Machines)、一个基于梯度提升决策树(GBDT,Gradient Boosted Decision Trees)的混合算法和一些用于特征工程的持久算法。这些方法超出了本书的讨论范围,但是通过看入围方案,你能学到很多。你可以在www.netflixprize.com下载介绍前4名入围方案的论文。

有趣的是,获得Netflix奖的解决方案事实上没有部署成功。因为在生产环境下,该算法的伸缩性不好。它无法及时处理庞大的Netflix数据集以获得结果。但是Netflix奖的无功而返让我们对一个可行的机器学习解决方案的组成要素有了更深刻的理解——虽然精确度显然是很重要的,但它必须在生产中衡量才有意义。最后,公司发现为了提升的精度将这一算法部署到生产环境中并不值得。

算法交易挑战赛(Algorithmic Trading Challenge)是一个预测比赛,致力于发掘新模型来预测股票市场在大额交易后的短期反应。参赛者被要求使用经验模型来预测在例如“流动性冲击”之后的买入和卖出行为。通过提高模拟“回溯测试”的实时性,对市场弹性进行建模,旨在提高交易策略的评估方式。现在的方案都是基于市场没有弹性的假设。这一挑战赛的解决方案需要对模型中各种各样的市场动态有明确的认识。

这个58天的挑战赛,在2012年1月结束,吸引了111支队伍争夺10 000美元奖金。这个挑战赛是资本市场合作研究中心赞助的,这是一个驻澳大利亚的集科研人员、高校师生和工业界合作伙伴于一体的集团。

参赛者为了寻找最优解使用了各种各样的机器学习算法:线性回归、K-最近邻、支持向量机、随机森林、k-均值和各种组合算法。参赛算法使用均方根误差对预测的性能进行评估,计算在流动性冲击之后,每次买入和卖出报价。获胜的是在整个预测集中累计的均方根误差最低的一个算法。获奖者叫Ildefons Magrans,是一名来自西班牙的机器学习博士后研究员,拥有电子工程博士学位。他使用了R中的随机森林来降低均方根误差指标。

这个机器学习难题可能是所有Kaggle挑战赛的“祖师爷”,因为参赛的队伍数目和获胜的奖金数目都十分惊人。HPN(Heritage Provider Network)赞助了该项目,旨在创造一个能帮助降低医疗服务成本的算法——显然这是全人类永恒的崇高追求。

根据美国医疗学会的最新调查显示,在美国,每年有超过7 100万人次住院。研究推断,仅在2006年一年中,就有超过300亿美元被花费在不必要的住院治疗中。有更好的方式吗?是否能够提早判断出高危患者,确保他们得到所需要的治疗?HPN相信这是可行的,并赞助了Kaggle挑战赛,以开发一个基于现有的患者数据来预测和减少不必要住院治疗的机器学习算法。

参赛者被要求创造一个算法来预测患者在一年中会住院多久。一旦知道这个,医疗服务人员就能建立新的关怀计划,在紧急事件出现之前就对病人实施医疗帮助,从而减少非必要的住院时间。这将会提高患者的健康水平,降低医疗服务费用。简言之,获胜方案将改变我们熟知的医疗保健服务,从救治病人转变为真正意义上的保持人类健康。

从2011年4月到2013年4月,这个比赛持续了两年。该比赛的第一名是一支名为POWERDOT的队伍,他们被授予了500 000美元的奖励。你可以在HPN的网站上找到这个比赛www.heritagehealthprize.com。在那里你可以下载到病人资料数据集以及一些具有重要意义的方案论文。最成功的解决方案涉及随机森林的集合,外加对特征变量的创造性选择。

除了上面介绍的Kaggle比赛的案例之外,下面还列举了许多能用机器学习解决的其他领域的问题(依然有很多没有提到的)。

到现在为止,我们已经看了不少机器学习的成功应用和潜在应用,让我们简要地回顾一个失败的机器学习案例,并思考它为什么没有成功。在2013年2月,谷歌流感趋势(GFT,Google Flu Trends)上了头条——但这不是谷歌高管或者这个流感跟踪系统的创造者所希望的事。《自然》杂志报道,GFT预测的感染者数量是美国疾控预防中心(Centers for Disease Control and Prevention,CDC)预测的数量的两倍多,而后者是基于全美实验室的检测报告来估算的。尽管GFT的创建目标是预测CDC的报告数据,这个令人大跌眼镜的情况还是发生了。鉴于GFT经常被认为是大数据应用的典范,我们可以从这个错误中吸取什么教训?

GFT试图根据人们在谷歌中使用的搜索关键字,如“我咳嗽了”,来预测某个时间地点的流感患者的比例。在这项研究的早期,预测的精度很好,很多人对GFT的未来十分乐观,因为使用谷歌的技术比CDC的方法划算多了。当时问题还没有显现,人们搜索的关键字会随着时间变化,此外,谷歌的搜索算法发生了改变,这些偏差影响了算法的表现并逐渐导致了预测精度跳水。

当在一个数据科学项目中工作时,总览机器学习的整个工作流程来决定应遵循的技术路线是十分有用的。在本节中,我会提供一个详细的工作流程,你可以在机器学习项目中使用它,它适用于几乎所有项目。如果你基于某些特定领域的需要,想对流程进行增改,请随意创造属于你的流程,以便未来重复使用。图1-2的简图描绘了一般情形下的工作 流程。

图1-2 机器学习项目中的数据科学流程

鉴于这是本书后续章节的模板,让我们一步步检查数据科学的流程。当你获得更多经验后,你会想要在此基础模型中增加更多细微的环节,但即使经过调整,流程在大体上还是一致的。

1.理解问题。深入理解问题范畴,寻求该领域专家的帮助,如解释商业考量、提供数据集、确定关键变量等。最重要的是明确项目的目标。例如,要预测或是发现什么。任何机器学习的项目,如果没有清晰的目标的话,将会后患无穷。如果项目的甲方只是简单地跟你说:“这里有一些数据,现在你可以用它来露一手了”。你可能会被吓跑,因为根据如此不现实的表述来提供结果是很困难的。相反,花时间执行流程的所有步骤,并且确保每一位项目相关人员都能参与进来,会使项目顺利进行。根据项目的不同,你可能需要与从事市场、金融、实业、IT甚至人力资源行业的人打交道。你将经常需要从多个部门获得资源。正确的接近数据科学的方法是,从一个对你的商业有着根深蒂固影响的问题开始,基于问题,反过来考虑数据分析和所需要的数据集。洞察力不会凭空产生,它们伴随着努力分析数据和为解决真实问题建模而到来。有时,商业问题和数据科学应用之间的关系十分清晰,就像在正确辨别信用卡欺诈交易的场景中一样。在其他情况下,分离商业问题和数据科学应用可能有多个步骤。一个数据科学工程的原始和最终驱动力,通常基于部门级需求(例如,金融、销售、市场等),并且不是源于IT部门的需求,虽然工厂部门可能需要向你提供用来做机器学习的数据集。

2.获得数据集。用于分析的数据可以从数据库或者数据集市中获得。在一些情况下,数据可能从生产系统中提取,例如,一个电子商务应用。最近越来越多的机器学习项目中使用的数据来自多种数据源,包括非结构化数据,例如社会媒体甚至是电子邮件。这就是为什么数据采集过程需要你具有创造力,并且有相关领域的专家提供帮助(诸如一个能给你提供销售数据或者薪资数据的主管)。这一步可能涉及IT部门,需要数据库工程师为你切分提取出数据。

3.处理数据。在项目的起始阶段,将数据进行清洗,并将原始数据转换成更适合机器学习的数据格式等数据处理任务是十分重要的。对于一些企业数据的状态来说(脏数据、数据不一致、数据缺失等),这一步可能要花费相当多的时间和精力。

4.使用探索性数据分析。使用统计方法和图表来发掘数据中有趣的特征和模式。有时,对原始数据(或者原始数据的采样)进行绘图,就能揭示出重要的信息,它能帮助你决定项目的研究方向,或者至少能在解释机器学习工程的结果时提供一个关键的思路。

5.执行特征工程。使用探索性数据分析决定最优的特征变量,在你准备使用的机器学习算法中应用。这个步骤可能需要与相关专家讨论在什么层面上进行探索性数据分析。当然,你需要明确地知道每个特征变量为算法预测精确度带来的提升程度。

6.选择一个模型。选择一个适合解决现有问题的机器学习算法,并把你的数据集分为训练集、交叉验证集和测试集(详细内容见第7章)。在现阶段,你需要确定将要使用的机器学习的类型。你想做一个定量的预测、定性的分类,还是仅仅使用聚类技术进行探索?当你在机器学习领域积累一些经验后,你将能更容易判断在某个应用中使用什么算法最合适。

7.验证模型。没有一个算法,在使用任何数据集的情况下都能打败其他任何算法。对于一个特定的数据集来说,某个算法可能有最好的结果,然而使用不同的数据集之后,其他算法可能效果更好。因此,对于任何给定的数据集,判断哪个方案能产生最好的结果,是一个非常重要的任务。在实践中,选择一个最好的方案是机器学习中最具有挑战性的部分之一。因此,对模型的性能评估(performance evaluation)是项目成功的关键。我们需要测定预测和实测数据的拟合程度,也就是说,我们需要将预测结果值和真实的响应值的接近程度进行量化。我们还需要确定过度拟合的程度,例如,给出的一个算法产生了少量的训练结果错误,但有大量的测试结果错误。特别地,我们还需要评估模型的适用性。更进一步,我们需要决定偏向减少方差还是减少偏差(这是第7章的一个主题)。在第7章中,我们将寻找同时满足低方差和低偏差的算法。

8.数据可视化(data visualization)。一个机器学习项目的最终结果用一个制作精良的可视化(能准确传达算法告诉我们关于数据的本质)来表示最易被理解。传达合适信息的数据可视化并不容易创造,可能需要多次尝试才能成功。事实上,建立有效的可视化需要一定程度的创造力和艺术天分。好在,互联网充满了大量有效可视化的例子,你可以用它们来想出你自己的方向。

9.交流结果。一旦你完成了数据科学部分的处理,你要准备和决策者讨论结果。为了使这一切行之有效,你需要成为一个“数据说书人”,基于数据展示的内容,能讲一个令人信服的故事。要知道大多数经理人没有在数据分析或统计方面的背景知识,你的工作是把结果展现成一个典型的商人可以理解的形式。为了能针对结果采取行动,决策者必须明确知道正在讨论什么——不是在数据科学意义上讲,而是在可行的商业智慧的意义上。这很不容易,但是讲数据的故事是成为一个数据科学家不可或缺的一部分。

10.部署到生产环境。一旦项目完成,下一步重要的工作是将机器学习解决方案部署到生产环境中。这个环境采用的形式取决于这个工程的目标。如果你在创造一个推荐系统,那么部署可能意味着给电商网站增加功能;如果你在创造一个客户流失率预测器,那么部署可能意味着营销系统的一个补充;或者如果你致力于一个帮助完成销售交易的网站,那么可能没有任何实际意义上的部署,而是在销售部门标准作业程序(SOP,Standard Operating Procedure)文件上的改变(例如,在7次电话后继续给潜在客户打电话,会带来收益递减)。在生产环境中部署基于R的机器学习解决方案,你也需要特殊的工具。本章后面会讨论这个内容。

在上面这些指引之后,对任何机器学习项目来说都有一些重要的目标。第一,算法的结果应该是可解释的;换言之,组织中的领域专家应该能理解(当然,在你的帮助下)该算法展示了数据的什么内容。接下来,结果需要足够简单,能够解释清楚,与一个极度复杂的解决方案相反,这其中的很大部分取决于你把技术翻译成可行的商业智能的能力。你经常要对精确度进行折衷,换句话说,你会牺牲一些精确度来提高可解释性和简单性吗?如果你牺牲了太多的精度,那么你可能需要重新考虑其他影响因素(例如,牺牲一些简单性换取精确度可能是值得的)。算法也必须快速。这意味着建立模型和用小样本测试它都应该是简易的。最后,算法应该是可伸缩的,这意味着它很快速或是能并行处理多个样本,易于应用在海量数据集中。

为了让这本书的受众尽可能广泛,我做了一个慎重的决定——省去数学。我对这个决定并不感到特别兴奋,因为我坚信彻底理解机器学习需要深入理解每个算法的数学原理。虽然在学习的初始阶段你不用数学也可以通过,但是我强烈期待在某些情况下,你想要回来重新学习每个算法,并钻研它背后的数学原理。依我看来,数学基础和机器学习方面的专业知识都是一个数据科学家必须的。在数学领域,你需要知道的包括数理统计(mathematical statistics)、概率论、微积分(calculus)、线性代数、偏微分方程和组合数学。

如果你在大学时没有数学背景,什么时候来打基础都不算晚。现如今有很多可利用的资源来帮助你了解机器学习中数学的最新进展:诸如Coursera、edX、MIT公开课(MIT OpenCourseWare)和可汗学院(Kahn Academy)这样的MOOC。在YouTube上搜索上面提到的每个数学领域,会找到很多高质量的讲座以进行关注和学习。

一旦你获得了数学上的观点,你将能够回答现在越来越多突然出现的问题:“机器学习真的是科学吗”?我在这个问题上的观点是坚决肯定的!数据科学是多学科的融合,每一学科都是基于之前提到的数学领域。利用这些原理,你可以有效地应用我在前言中提到的“科学方法”。

评估你在机器学习领域的职业规划时,你需要考虑成为一名数据科学家所需要的知识。你只需要查看这一职位最近的招聘公告就能理解这需要多方面的能力。很多公司在寻找在数学、统计建模、算法设计与验证、构建生产系统的软件工程、系统架构和管理、分布式计算机系统(例如:Hadoop和Spark)、云解决方案、存储系统和具有行业经验的候选人。再加上,这个人需要具有和首席高管讨论实验结果的能力。这样的候选人被称为“独角兽”(一种现实中不存在的神兽),或者,根据当前讨论的话题,称之为一名数据科学的超级英雄。事实上,这些职位说明描述了一个团队而不是一个个体,但是很多公司坚持数月甚至超过一年来寻找他们的“独角兽”并不肯妥协。

上面提到的各个领域的数据科学需要截然不同的技能、教育和训练。例如,假设一家公司想在上百万的保险索赔案例中定位异常值来鉴定欺诈,他们会需要一位在抽样和多变量统计分析上有经验的人。这家公司也可能想设计并实现一个软件解决方案为生产系统所用。这两种工作能由一人承担吗?这个人有统计的博士学位,同时也能写代码并且设计/配置硬件架构吗?或者反过来说,要让一个软件工程师做数理统计吗?不太可能——这些职责范围通常是互斥的。

对你来说更现实的是预先确定你想成为一个理论家(theorist)还是实验家(experimentalist)。理论家利用中等大小的数据集(或者从海量数据存储中抽样)执行标准的数据分析、数据清理、探索性数据分析、选择模型并验证,来建立项目的理论基础。这个人应该对机器学习及其背后数学原理有着深刻的理解。另一方面,实验家更多的是一名软件工程师或者在建立生产软件应用方面有经验的人。这个人应该理解机器学习的结构,以及如何把它部署到生产系统中。这个人可以建立Hadoop集群、写MapReduce代码、管理数据存储硬件、写高可用产品代码并处理对可扩展硬件架构的需求。

数据科学定义中包含以上所有特点,这使得雇主和应聘者的生活混乱不清。如果一家公司招聘数据科学家,他们期望找到一个能做复杂统计分析、处理海量数据并设计/建立可扩展软件系统的人吗?很多想要招聘数据科学家的公司确实坚持要找这样的“独角兽”,但是这就像是招聘一个建筑师,不但能设计房子,还需要他倒水泥并干一些钉钉子  的活。

一个解决方案是教育雇主和他们的HR团队:他们真的需要雇佣一个数据科学团队,把“数据科学家”这个职位拆分成专业特长,例如:

图1-3展示的数据科学韦恩图2.0并不是对重叠部分的精确描述,而只是一个形象化的指南。注意到中心的独角兽代表了所有学科的非常稀有的交叉点。

图1-3 数据科学韦恩图2.0

在过去的几年里,R统计环境在机器语言社区里面逐渐获得了相当突出的重要性。虽然有很多其他选择来执行与数据分析、数据建模和机器学习有关的任务,R成为了今天数据科学家最喜欢的工具。这归功于R在学术界的广泛应用,而不是像SAS和SPSS等商业化产品。最近,R用户社区和SAS及Python社区展开了激烈的辩论,焦点是对数据科学家来说,哪个是最好的工具。R有令人信服的理由,包括:免费、开源、可用性强;广泛使用的可扩展语言;在CRAN中大约有7000个R包用以拓展R功能;一流的可视化功能;一个繁荣的用户社区以及博客集合(例如r-bloggers.com)。

这里有一些关于R的简短事实,来证明它的普及和成长:

在这里,给出RStudio IDE的一个简要介绍是有益的。我强烈建议你使用RStudio来使用R开展机器学习工作。图1-4展示了一个典型的RStudio会话窗口。

图1-4 Rstudio IDE

RS的屏幕被分割为4个窗格。左上角是R脚本编辑器,你可以将你的R编程代码输入到不同的代码文件中。你可以同时打开多个代码文件,以便从一个脚本中复制代码到另一个脚本中。为了执行R代码行,你需要做的只是用鼠标把代码行进行高亮并在编辑器的工具栏单击Run。在执行代码时,这些行会显示在左下角的窗格中,也就是R控制台。代码的每一行都以“>”符号开始。在这里,你也能看到运行的代码的效果。举个例子,如果在控制台中输入了以下内容,你马上就能看到计算的反馈。

> mean(iris$Sepal.Length)

[1] 5.843333

在右上角,你能看到Environment标签,它包含两个部分:Data展示现在使用所有数据集,Variables展示你的R脚本创建的所有程序变量。注意,如果点击数据集的名称,一个新的数据浏览器会在左上角出现,这样就可以滚动查看数据集中的所有数据项了。

在右下方的窗格,你会看到许多不同的标签:Files、Plots、Packages、Help和Viewer。所有的图表特征结果都显示在这个窗格中,帮助信息也指向这里。你也能在这里找到R环境中所有在用的R包。

R以一种非常积极的方式拥抱开源,通过使用所谓的“包”来扩展软件的基本功能。有大量的通用包(当前大约是7000个),其中很多涉及有用的统计方法,也有特定领域的包:金融、天文学、分子生物学、生态学等。你可以用下面给出的R脚本来找到当下可用的R包数目:

> dim(available.packages())

R包贡献在综合R归档网(CRAN,The Comprehensive R Archive Network)中,这是一个由世界各地的专家维护的资源库。为了找到离你地理位置最近的CRAN镜像,请访问www.r-project.org,点击CRAN链接,选择你的国家/位置。在那里,你可以看到一页按名称排列的可用CRAN包。这个网页非常长,所以你需要使用浏览器的Find工具来通过关键词来搜索。例如,有6个R包的名字中含有关键词“金融(finance)”。也有一些在CEAN上找不到的私有R包,你可以用谷歌来查找并下载安装到你本地配置中。

一旦找到了满足你需求的R包,你需要在本地配置中安装它。例如,这是安装lubridate包的命令:

> install.packages("lubridate")

一个包只能安装一次。安装完成后,你需要做的是用library()把它加载到内存中。library()函数用来加载基础R配置中未包括的函数库(函数和数据集的集合)。

> library(lubridate)

一旦成功安装了一个新的包,你应该去访问CRAN上该R包的页面来下载参考手册和任何可能有帮助的简介。参考手册包括了简介和如何使用包中每个函数的示例,包含每个函数完整的参数列表。不过,手册只是用于参考,通常不适合作为学习材料。简介更像是一份学习指南或者在大学教育中使用的实际案例,因此在学习包的特征和使用方法时是非常有用的。遗憾的是,并不是所有的包都有简介。

对于本书中更深入的主题来说,R是机器学习资源中的一个宝库。在基础R环境以及许多针对机器学习算法的附加包中,你可以找到许多机器学习功能。举个例子,基础R包含有stats包,里面有常用算法,例如:lm()用来拟合一个简单的线性回归模型,glm()用来拟合广义的线性模型;如逻辑回归:hclust()用来做聚类分析,kmeans()用来做k均值聚类,prcomp()用来做基本的组成成分分析;还有其他很多功能。

除此之外,还有许多机器学习的附加包可以补充基础R包的功能。例如,class包中的knn()用来做k最近邻算法,tree包中的tree()用于拟合分类树或是回归树,randomForest包中的randomForest()用来实现随机树算法,e1071包中的svm()用来实现支持向量机,还有很多其他功能。

为了找到其他满足机器学习需求的R包,你可以使用谷歌。例如,你想寻找用来实现进化算法的包,可以搜索“R中的进化算法”。结果会告诉你参考DEoptim包,这个包中含有你需要的机器学习算法。

本书尽力教大家机器学习的方法,因为机器学习是关于数据的,所以我们需要大量的样本数据集以供在例子中使用。为了让事情简单一点(并且不需要你花费大量时间去寻找数据集),书中使用的大多数数据集都是R软件在安装时自带的。使用如下命令,查看可用的数据集列表:

> data()

你所能看到的列出的数据集,取决于你安装了什么包和你在内存中加载了什么包。R包中通常包含可以用来检验函数功能的数据集。可以使用如下命令,查看特定R包中包含的数据集:

> data(package="plyr")

要查看某个数据集中的更多内容,你可以使用在数据集名称前面加?的命令,就像下面展示的这样。R会给出数据集的简短介绍、观测(例子)的数目、变量名(特征)列表、代码示例和在很多情况下都有的每个变量的描述。图1-5展示了R给出的关于airquality数据集的帮助信息。本书会使用许多著名数据集,强烈建议你熟悉每个数据集中的每个变量。

> ? airquality

你可以使用以下命令来将某个数据集加载到内存中:

> data(iris)

你将在RStudio的Workspace标签页看到数据集的名称。

图1-5 关于airquality数据集的R帮助信息

当你用R完成了一个机器学习项目时,接踵而来的问题就是能否将解决方案部署到生产环境中去。答案通常是否定的。因为性能和内存限制,开源的R语言对生产系统来说通常不是一个好的选择。对于需要连接到特别大数据集的海量数据机器学习项目来说,性能和内存特别重要,所以除了使用其他语言,例如C++或者Python之外,还有其他选择吗?你可以从使用bigmemory包开始,它能帮助你创建、存储、连接和操纵大量矩阵。然后你可以通过添加biganalytics、bigalgebra、bigtabulate和bigpca包来获得更高级的功能。这些包可以在建立一个可行的生产系统之路上帮助你走得更远,但你依然可能在路上遭遇绊脚石。好在,有几个商业版本的R环境适合企业级应用。其中一个是Revolutions Analytics公司提供的Revolution R Enterprise(RRE)。另一个是TIBCO公司的TIBCO Enterprise Runtime for R(TERR)。这两个商业版本都能提供适合R机器学习算法的最佳版本,用以快速处理海量数据。

在本章中,我们对机器学习领域(也被称为统计学习)进行了介绍。另外,我们做好了开始一个数据科学项目的准备,并提供了一个路线图来作为本书的向导。建立一个机器语言解决方案的第1步是探索以各种常用格式连接数据集的方法。在第2章中,你将看到很多连接数据的例子,可以加入到你的数据科学工具箱中。

下面是本章知识点小结:


 

数据科学和它的使能技术机器学习一样,都是关于数据的,即使用海量数据训练算法,对未来事件作出预测;也会对存储的数据进行筛查,发现对商业有战略价值的模式。所以很自然地,机器学习过程中一个重要的部分就是从与待解决的问题相关的分散资源中访问数据内容。很多机器学习和数据分析讨论的前提是你已经有干净的数据,可以直接把它们应用在探索性数据分析工具中,然后选择一个合适的机器学习模型。遗憾的是,这种情况很少发生,更多的时候,你需要定位数据,确定它使用了哪种格式,找到一个有连接数据功能的R包,最后,连接数据并把它读入R数据框(data frame)中——这就是本章的全部主题。这一过程为下一个重要的步骤(数据处理)打下了基础,而后者是本书第3章的主题。

让我们后退一步,为“数据”下一个定义:

数据是属于同一群体的定性或定量的变量的值;是你感兴趣的一组对象的集合,其中的一个变量是对一项的特征的度量。

群体的例子是一种产品的销售数据、广告效果数据和制造过程数据。定性的变量的例子是销售价格、某个广告的点击数和一小时内一种产品的产量。在机器学习项目中,连接数据阶段的目标是定位并获取能为问题域提供帮助的数据源。

数据连接在机器学习项目中的重要性不容小觑。在和其他组织一起从事机器学习项目时,我学到的最重要的知识就是,人们天生愿意把数据存储在多个位置,并以多种格式存储,而这些数据都可以用于机器学习。从某种意义上来说,缺乏合适的数据方法决定了我们需要具备从各种数据源中灵活获取数据的能力。无论你在初创公司、大型企业还是科研机构工作,你都需要掌握多种连接数据集的方法。

在可用数据没这么多且我们从数据中学习的能力没有这么强时,这些都不是问题。所谓的“大数据”产业,就是以有效的方式利用不同来源的数据。数据源的种类和深度在不断提升,这个方面一个很好的例子是,非结构化社会媒体的数据使用量在不断增加。利用这些数据可以得到人气和信誉值,并结合交易数据集来达到空前的预测能力。

本章的目标是为你提供一个有用的连接数据的工具包,以便你在后续的机器学习项目中重复使用。在这里学到的连接数据的步骤,将成为你构建数据管道的第一步,数据管道将在第3章讨论。当一名数据科学家遇到一类全新的数据源时,他必须研究引入机制(和这里展示的相似),并把数据加入到本章提供的工具中。逐渐地,你将拥有一个不断完善的工具包,它的功能不断增强,并能连接常见的数据源。像R这种开源工具的优势是,给一些时间,就有人能开发出新的包来处理种类不断增加的数据源。实际上,这就是Twitter上所发生的事情。

在本章中,我们会学习一些连接各种类型的数据内容并将其引入到R环境中作为学习算法输入源的方法。这一步代表了机器学习方程的第一步。以下是本章的主题列表:

在R环境中开始一个新的机器学习项目时,一个基本的步骤是决定在哪里存储你的工作内容。工作目录用于储存各种组成你项目的文件,包括数据文件、R脚本、图表文件、RDATA文件,也包含你分析得出的文件(Word、PowerPoint等格式)。有些人使用工作目录下的“data”子文件夹来存储这些数据文件。

一旦创建了工作目录,你就需要在R环境中管理它的位置。R有两条命令来管理工作目录:getwd()用于检索目前的工作目录,setwd()用于创建新的工作目录。在打开RStudio时,你可以在R控制台中用setwd()函数来创建工作目录,下面是使用相对路径的方法:

> setwd("./MYPROJECT")
> getwd()
[1] "C:/Users/Dan/MYPROJECT"

使用绝对路径的方法,你可以使用以下语法:

> setwd("/Users/dan/MYPROJECT")
> getwd() 
[1] "C:/Users/dan/MYPROJECT"

如果你和我一样,也是Windows用户,希望使用Windows的语法,即使用反斜杠(\)指定路径名,那么你需要使用特殊的双反斜杠(\),如下所示:

> setwd("C:\\Users\\Dan\\MYPROJECT")
> getwd()
[1] "C:/Users/Dan/MYPROJECT"

管理工作目录的另一个方法是使用RStudio的功能:Session -> Set Working Directory -> Choose Directory来指向你需要的目录。

当你在进行一个机器学习项目时,定期保存工作目录下的工作文件是很有必要的。最简单的方式是在RStudio中使用Session -> Save Workspace As,然后为你的工作文件输入一个文件名,通常是你的项目名称,例如MYPROJECT.RData。工作空间的文件保存了目前工作环境、数据值和数据集的状态。以后,当重新加载RStudio时,你可以打开同一个工作文件来重载到之前的状态,然后你就可以从上次结束的地方继续工作了。你进行的每一个项目都应该有单独的工作目录和工作文件。

有很多类型的文件可以用做机器学习的数据集。数据科学家的工作是在R环境下,创造工具将来自不同数据源的数据集导入,并把它们合并成一致的结构。本章后面的小节会聚焦于特定的数据源类型,并演示如何将数据以R数据框的形式导入内存。一旦数据进入数据框,通常漫长的数据处理过程就开始了。下面是我们接下来会谈到的数据文件类型的列表:

你会发现用于机器学习项目的数据文件有多种可能来源。大多数情况下,你将从所效力的公司的领域专家那里得到数据集。给你提供数据集的可能是一个IT技术人员,可能是财务部门掌管公司Excel数据仓库的人,也可能是一个为公司管理社会媒体效果的咨询师。以下是其他的一些来源的列表。

当你继续学习机器学习的原理时,你应该时刻注意寻找新的数据来源,并考虑:应该如何在机器学习的帮助下使用这个数据集提取知识,从而创造价值?

就像在前面提到的,网络上有很多可供下载的机器学习数据源。其中对公众开放的一种数据类型是政府数据。为了演示怎样从网络中下载数据,如图2-1所示,访问San Francisco Data网站(data.sfgov.org),上面包含了大量的市政数据集。要用到的Parking Meter数据集,包含了多方面的仪表特征。目标是直接从网站上下载CSV文件格式的数据集。为此,我们将使用download.file()指令。这里需要注意的是,并不是网络上提供的所有数据集都以一个很好的结构化格式存在。例如,每一行包含与单次观察相关的多个变量。通常情况下,你在网络上找到的数据需要进行大量的再加工,将它转换成适用于数据分析和机器学习的格式。

图2-1 数据源实例——San Francisco Data,data.sfgov.org

下面的代码定义了一个变量fileURL,并且将数据集的URL(网址)分配给它。URL是从San Francisco Data网站上获取的。下一步,download.file()命令用于下载文件,将它存放在工作目录下的data子目录中。接下来使用list.files()函数来确认下载已经完成。注意相对路径./data的使用,这指的是当前工作目录下的子目录。

> fileURL <- "https://data.sfgov.org/api/views/7egw-qt89/rows. csv?accessType=DOWNLOAD"
> download.file(fileURL, destfile="./data/SFParkingMeters. csv")
> list.files("./data")
[1] "SFParkingMeters.csv"

下一步是使用read.table()函数将数据集读取到数据框中。然后我们可以使用head()来看看前几行数据,检查数据格式是否正确,同时也能熟悉数据元素:

> SFParkingMeters <- read.table("./data/SFParkingMeters.csv", sep=", ", header=TRUE)
> head(SFParkingMeters) 
  POST_ID     MS_ID MS_SPACEID CAP_COLOR METER_TYPE SMART_METE ACTIVESENS
1 354-20160   -     0.0        Grey      SS      Y        Y
2 354-21030   -     0.0        Green     SS      Y        Y
3 354-21160   -     0.0        Yellow    SS      Y        Y
4 363-05250   -     0.0        Grey      SS      N        N
5 363-05270   -     0.0        Grey      SS      N        N
6 464-04120   -     0.0        Grey      SS      Y        Y

   JURISDICTI ON_OFF_STR OSP_ID STREET_NUM  STREETNAME  STREET_SEG  RATEAREA
1  SFMTA   ON   0.0    2016.0   CHESTNUT ST   3977000.0   Area 5
2  SFMTA   ON   0.0    2103.0   CHESTNUT ST   3979000.0   Area 5
3  SFMTA   ON   0.0    2116.0   CHESTNUT ST   3979000.0   Area 5
4  SFMTA   ON   0.0    525.0    COLUMBUS AVE  4295000.0   Area 3
5  SFMTA   ON   0.0    527.0    COLUMBUS AVE  4295000.0   Area 3
6  SFMTA   ON   0.0    412.0    HAYES ST       6816000.0   Area 5
     SFPARKAREA         LOCATION
1    Marina             (37.800798, -122.43687)
2    Marina             (37.800522, -122.438067)
3    Marina             (37.800589, -122.438525)
4                       (37.800053, -122.409985)
5                       (37.800088, -122.410035)
6    Civic Center       (37.776878, -122.423512)

可能你遇到的最常见的数据文件类型是逗号分隔值(CSV)文件类型。这是因为CSV是数据科学社区的通用语言,并且很多软件应用导出的数据格式是CSV。同样地,大多数软件应用和环境(如R)能够读取CSV文件。如果你不熟悉一个CSV文件的样子,只要在诸如Windows记事本(Notepad)这样的工具中打开它即可。CSV文件的格式很简单:文件中的每一行代表了一个观测值,每一列代表一个变量(潜在的特征变量)。R能处理第一行包含一个变量名列表的情况,也能处理第一行丢失的情况(在这种情况下,R会任意分配变量名,你可以在之后重新命名变量)。

一旦你得到了CSV文件,第一步就是把它放进工作目录中。为了将CSV的内容读进内存中以便后续在R中使用,你可以用read.table()函数,这是R提供的把文件读入成为表格形式的一般方法,不单单适用于CSV格式。read.csv()的功能基本和read.table()相同,只不过它只能读取CSV格式,而这种格式通常是由Excel这样的电子表格应用导出的。不论使用哪个函数,文件都被读入数据框对象中。为了演示这部分内容,我们将读入前面的停车计时器数据集。

> SFParkingMeters <- read.csv("./data/SFParkingMeters.csv")

成功将文件读入之后,你可以用两种方法让内容显示在RStudio中,一种是在Workspace窗格中单击数据框的名称SFParkingMeters;另一种在控制台中输入指令view(SFParketingMeters)。图2-2显示了你将看见的结果。你可以像在电子表格中那样浏览数据,不同的是,这里不允许编辑。我们注意到,这个数据集有29 253条观测值和116个变量。如果你只想看这个数据框的前6行,也可以使用head(SFParkingMeters)。

图2-2 使用RStudio查看数据集

另一种有用的读入文件的方式是使用file.choose()函数,它可以嵌入到read.table()或者read.csv()中。这种读文件的方式会弹出一个提示框,提醒选择指向计算机中的哪个文件。

> SFParkingMeters <- read.csv(file.choose())

机器学习中另一种重要的文件类型是Excel。Excel是应用很广泛的电子表格软件,各种规模的企业都依赖这个工具来存储商业信息。这样一来,你希望在机器学习中使用存放在Excel中的数据就很容易理解了。

R提供了直接从Excel 2007电子表格文件中读取数据的工具:read.xlsx()和read.xlsx2()函数。read.xlsx2()函数通常能更快地处理大型电子表格。为了测试读取Excel文件,我们需要回到San Francisco Data网站去下载同一个Parking Meters数据集,但是这一次是下载XLSX格式的数据。注意到Excel文件是一个二进制文件而不是纯文本文档,我们需要为download.file()函数指定mode=“wb”(说明文件是二进制类型)。我们还需要使用library()函数来加载xlsx包,否则使用中会找不到包中的函数。最后,为了把Excel文件读入数据框中,我们将使用read.xlsx2(),并设定参数sheetIndex=1,这指示了读入Excel文件中的哪一个表单。

> fileUrl <- "https://data.sfgov.org/api/views/7egw-qt89/rows. xlsx?accessType=DOWNLOAD"
> download.file(fileUrl, destfile="./data/SFParkingMeters.  xlsx", mode="wb")
> library(xlsx)
> SFParkingMeters <- read.xlsx2("./data/SFParkingMeters.xlsx", sheetIndex=1)

这时,最终结果应该和2.5节读入CSV文件的结果一致。也就是说,数据存入了SFParkingMeters数据框。值得注意的是,Excel的很多企业用户以一种自由的方式使用这个工具,电子表格的内容中有很多变化,而不仅仅是简单的行和列。你可能需要提前对数据进行处理,简化数据结构,才能将Excel文件读入R。

另一种从数据源中读取信息的方式是通过文件连接。利用连接,你可以读入CSV文件,就像我们在前面看到的那样。不同的是,你也可以从文本文件中读取数据行。在数据不太规整的情况下,从文本文件中按行读取数据是有意义的。为此,R有一个有用的函数readLines(),可以和文件连接一同使用。在我们查看readLines()的例子之前,首先来看看文件连接是如何工作的。考虑下面的示例代码:

> con <- file("./data/SFParkingMeters.csv", "r")
> SFParkingMeters <- read.csv(con)
> close(con)
> head(SFParkingMeters)

前面的例子首先使用file()函数来建立CSV文件与命名为con的对象的连接。然后,我们调用read.csv()函数,使用连接对象作为参数,以读取文件的内容。最后,完成后关闭连接是很好的习惯。跟前面的一样,数据框SFParkingMeters包含了文件的内容。

现在让我们回到readLines()函数,然后做一些完全不一样的事情。这一次,数据源将会是一个网页,所以我们会使用url()函数来提供网页的地址。遵循和之前一样的步骤,但设定参数n=20,表示只读取网页的前20行(如果一次只想读取1行,取n=1)。

> con <- url("http://radicaldatascience.wordpress.com/", "r")
> RDS <- readLines(con, n=20)
> close(con)
> head(RDS)

在上文中,使用head(),展示了从我的博客上读取的HTML文本。

[1] "<!DOCTYPE html>"        "<!--[if IE 7]>"        
[3] "<html id=\"ie7\" lang=\"en\">" "<![endif]-->"         
[5] "<!--[if IE 8]>"        "<html id=\"ie8\" lang=\"en\">"

使用readLines()的一个很重要的方面是:数据行存储在特征向量而不是数据框中。你可以使用class()函数来查看:

> class(RDS)
[1] "character"

将文件中的文本行存储在向量中意味着你必须写R代码来处理数据,以解释数据的含义。举个例子,如果数据行中包含Twitter社交媒体内容,那么你可能希望开发一个算法来执行推文中的文本倾向性分析。

R中有很多其他函数涉及连接。要查看完整的列表,使用如下命令:

> ? connection

为机器学习项目读取数据时,另一种你可能遇到的数据文件类型是JSON,也就是JavaScript Object Notation。JSON是基于文本的开源标准,为创造人类可读的数据交换而设计。它经常和流行的Ajax网络编程技术一同使用。R有两个流行的包能够连接JSON数据文件:rjson和RJSONIO。rjson没有使用R的S3或S4系统,所以它不太容易扩展。同时,rjson也不使用向量化操作,这导致它处理重要数据时速度很慢。同样的,在将JSON数据读入R时,rjson也有点慢并且不能扩展到海量数据。因此,在本节中我们会使用RJSONIO。

我们提供了一个把JSON文件读进R的数据连接案例,第一步需要获得一个URL来下载SFParkingMeters数据集的JSON版本(JSON是San Francisco Data网站提供的另一种文件类型)。大多数的工作由RJSONIO包中的fromJSON()函数来完成。这个函数能将JSON数据内容转换成R对象,以便进行更深入的分析。

下面的R代码首先将JSON URL保存在变量fileURL中。下一步,我们在fromJSON()函数中提交URL,返回数据存储在一个嵌套列表的实体中,包括两个基本的部分:meta和data。我们只需要data部分,所以我们把它存储在列表实体parkdata中。这里的窍门是知道怎样将嵌套列表拆成变量的单独值。为了做到这一点,你需要用parkdata[[1]]来看第一行的观测值,尝试识别一些数据,然后标注这些值的索引,以便后续进行查阅来构造一个数据框。我们可以使用列表处理函数sapply()将数据从列表中抽取出来。最后,我们需要构造一个新的数据框park_df,里面包含初识JSON文件的3个变量:CAP_COLOR、METER_TYPE和STREETNAME。现在,JSON数据以一种合适的数据框的形式存在,我们可以对数据进行常用的分析:

> library(RJSONIO)
> fileURL <- "https://data.sfgov.org/api/views/7egw-qt89/rows. json?accessType=DOWNLOAD"
> parkdata <- fromJSON(fileURL)[[2]]
> park_df = data.frame(
 CAP_COLOR = sapply(parkdata, function(x) x[[12]]),
 METER_TYPE = sapply(parkdata, function(x) x[[13]]),
 STREETNAME = sapply(parkdata, function(x) x[[20]])  
)
> head(park_df)
    CAP_COLOR  METER_TYPE   STREETNAME
1   Grey        SS             CHESTNUT ST
2   Green       SS             CHESTNUT ST
3   Yellow      SS             CHESTNUT ST
4   Grey        SS             COLUMBUS AVE
5   Grey        SS             COLUMBUS AVE
6   Grey        SS             HAYES ST

将网站当成是一个数据源可能是个奇怪的想法,但是,一旦你想起网站是一组HTML文件,HTML可以更好地表示数据时,那么“读取”网站这一行为就会显得比较合理了。这一技术在需要的数据没有现成的CSV文件或者其他文件类型可供下载时特别有效。作为替代,我们可以直接从网页中“抓取”数据。

为了演示这一读取数据的工具,让我们来访问一个包含数据集的网站,并将其导入R进行处理。图2-3展示了制造业数据采购经理人指数(PMI,Purchasing Managers Index)的历史值。我们的目标是写一个R脚本,直接从网页中读取数据,然后将它载入数据框中进行更深入的分析。接着更进一步,将数据变形,转换成对我们的目标来说更容易使用的形式。

图2-3 我们希望从中抓取数据的网页

下面的代码首先下载两个包:XML和reshape2。XML包中有一个对抓取网页来说非常有用的函数:readHTMLTable(),它能将数据从HTML表格中提取出来。HTML表格通常是数据在网页中的展现形式。为了方便使用,我们将这一函数的返回数据列表转换成数据框的形式。使用head(df)展示了现在在数据框中的数据,我们可以看到,与网页中的数据相同。

> library(XML)
> library(reshape2)
> webdata <- readHTMLTable('http://www.ism.ws/ISMReport/ content.cfm?ItemNumber=10752')
> df <- data.frame(webdata[[1]])
> names(df)[1] <- 'Year' # Add a name for first column
> head(df)
  Year JAN   FEB   MAR  APR  MAY   JUN  JUL  AUG   SEP  OCT  NOV   DEC
1 2014 51.3                            
2 2013 52.3 53.1 51.5 50.0 50.0 52.5 54.9 56.3 56.0 56.6 57.0 56.5
3 2012 52.8 52.4 53.0 53.7 53.2 51.0 50.6 51.1 52.2 51.2 49.5 50.4
4 2011 59.0 59.3 59.1 58.9 53.7 56.6 52.9 53.0 52.8 51.8 52.1 53.1
5 2010 57.2 55.8 58.8 58.1 58.3 56.4 56.4 58.0 56.3 57.7 57.6 57.5
6 2009 34.9 35.5 36.0 39.5 41.7 45.8 49.9 53.5 54.4 56.0 54.4 55.3

让我们更进一步,改进从网页中抓取的数据。可以使用reshape2包中的melt()函数,它在快速转换数据框方面特别强大。在这种情况下,我们选择从网站中读入的列表格式,将其改造成有序三元组Year、Month和PMI。同时,也要将PMI转换成数值型,并移除PMI值为NA的观测行(有几个月的PMI没有值)。

> df <- melt(df,id.vars='Year')
> names(df) <- c('Year','Month','PMI')
> df$PMI <- as.numeric(df$PMI)
> df <- na.omit(PMI)

企业数据的常见来源是SQL数据库。SQL数据库是大大小小各种企业的生命线。很多情况下,数据存储在企业级的数据仓库或是部门级的数据集市中。虽然SQL数据库的应用相当广泛,但是最常用的思路是将数据存储在由行、列组成的“表格”中。事实上,大多数数据库应用软件将数据存储在多个表中。机器学习利用SQL数据的目的是写新的SQL查询语句(或者使用现有的)来得到一个平面文件,其中包含你在分析中想使用的数据。鉴于大多数SQL数据库处理工具将数据导成CSV格式,使用上面章节提到的工具来读取SQL数据库产生的CSV文件是一个有效的解决方案。但是,你可能会认为直接从SQL数据库中读取数据更吸引人。

在连接保存在SQL数据库中的数据内容时,有一个好消息是:R拥有几乎每一种数据库的驱动。这多亏了有各种各样的R包。即使你现在使用的是一个没有单独驱动的数据库,也可以使用一个通用的ODBC(开放数据库互联,Open Database Connectivity)进行连接。下面是一些比较流行的SQL数据库R包的列表:

为了展示从SQL数据库中读取数据的过程,我将使用容易获取的工具。早在2012年,我就用Kaggle.com网站中著名的Heritage Health Network机器学习比赛的数据集做过实验,当时用的是Microsoft SQL Server 2012 Express,这是Microsoft企业关系型数据库的一个免费版本。我选择将所有的原始数据文件读入SQL表格中,然后在SQL Server中做大部分的数据处理(这部分内容在第3章会进行讨论)。我使用了大量存储过程来管理这个过程,这是我建议大家在执行复杂连接时使用的方法,尽管复杂的数据转换最好是在R环境中进行。

这里概括了如何建立一个到SQL数据库的连接,执行了一个简单的SELECT查询来把数据从表格中提取出来,然后将数据保存在R数据框中。这些步骤应用到我使用的SQL数据库和开发环境中,也就是在Windows 7专业版笔记本电脑上运行的SQL Server 2012 Express。你必须仔细研究所用的SQL数据库和开发环境的细节,不过上面这些步骤至少能让你熟悉处理过程。鉴于SQL Server没有自己的R包,我使用了RODBC包进行处理。

1.在Administrative Tools下的Window Control Panel中,使用ODBC Data Source Administrator工具来创建一个用户DSN(数据源名字)。我将“Heritage”这个名字赋给用户DSN。

2.加载RODBC库。

3.使用odbcConnect()函数建立一个到DSN是“Heritage”的数据库的连接。

4.向数据库传递一个SQL SELECT查询语句,用sqlQuery()函数进行连接,然后将结果集保存在数据框中。

5.关闭连接。

下面是完成这些操作的所有R代码。最后,我们在结果数据框中展示所有的变量名,并计算选中变量PayDelayI的平均值,来展示从SQL数据库中传递过来的数据是完整的。

> library(RODBC)
> con <- odbcConnect("Heritage", uid="dan")
> df <- sqlQuery(con, "SELECT TOP 1000 [MemberID]
   ,[ProviderID]
   ,[Vendor]
           ,[PCP]
           ,[Year]
           ,[Specialty]
           ,[PlaceSvc]
           ,[PayDelay]
           ,[LengthOfStay]
           ,[DSFS]
           ,[PrimaryConditionGroup]
           ,[CharlsonIndex]
           ,[ProcedureGroup]
           ,[SupLOS]
           ,[dsfsI]
           ,[CharlsonIndexI]
           ,[LengthOfStayI]
           ,[PayDelayI]
           FROM [Heritage].[dbo].[Claims]")
> odbcClose(con)
> names(df)
[1]  "MemberID"       "ProviderID"              "Vendor"   
[4]  "PCP"            "Year"                 "Specialty"
[7]  "PlaceSvc"        "PayDelay"              "LengthOfStay"
[10] "DSFS"            "PrimaryConditionGroup" "CharlsonIndex"
[13] "ProcedureGroup" "SupLOS"               "dsfsI"      
[16] "CharlsonIndexI" "LengthOfStayI"        "PayDelayI"  
> mean(df$PayDelayI)
[1] 42.944

当我们谈及SQL数据库和R时,值得在这里绕一个“小远路”来演示如何在R数据框中执行SQL查询操作。如果你能熟练使用SQL,你可能会发现,在R中使用SQL来连接数据内容比使用R中一些更简洁的数据处理工具(我们会在第3章看到很多这部分内容)要更容易操作。在R中使用SQL的关键是sqldf包,它能帮助你像处理SQL表一样处理数据框,并能用标准SQL语法引用它们。即使你从来没有使用过SQL,你也可能对这个功能感兴趣,因为使用SQL能使一些高难度的R语言结构有更简单的用法。

让我们看一个在R中使用SQL的案例。这是一个典型的商业中关于订单和产品的应用。不引用现存的数据集,我们将通过两个数据框orders和product马上创建一些测试数据。orders数据框有3个变量:order_no、prod_id和qty,分别代表了订单编号、产品ID和订购数量。product数据框也有三个变量:product_id、desc和price,分别代表了产品ID、描述和产品单价。我们将使用SQL连接语句将两个数据框通过共同的关键字prod_id关联起来,然后创建一个新的数据框,其中是包含order_no、prod_id、qty和price的结果集。

> orders <- data.frame(order_no=c("10021","10022","10023", "10024","10025"), prod_id=c("AC-01","AC-01","AD-11","AE-21","AM-19"), qty=c(1,1,2,3,1))
> product <- data.frame(prod_id=c("AC-01","AD-11","AE-21", "AM-19","AG-40"), desc=c("Widget A","Widget B","Widget C","Widget D",  
"Widget E"), price=c(123.50,25,55,17.95,45.33))
> sqldf("SELECT o.*, p.price FROM orders o INNER JOIN product p ON o.prod_id = p.prod_id;")
   order_no   prod_id   qty   price
1  10021      AC-01     1     123.50
2  10022      AC-01     1     123.50
3  10023      AD-11     2     25.00
4  10024      AE-21     3     55.00
5  10025      AM-19     1     17.95

使用类似于SQL的功能,R有很多种方法能够连接保存在数据框中的数据集。如果你已经了解SQL,那么理解和SQL命令具有相同功能的、R用来操作数据的工具将会是很有用的。在本节中,我们将看到一些在连接数据时早晚会派上用场的工具。为了对这些工具进行举例说明,我们将使用在基础R系统里即可获得的CO2数据集。让我们看看这个数据集的结构和内容:

> data(CO2)
> head(CO2)
   Plant  Type     Treatment     conc   uptake
1  Qn1    Quebec   nonchilled    95     16.0
2  Qn1    Quebec   nonchilled    175    30.4
3  Qn1    Quebec   nonchilled    250    34.8
4  Qn1    Quebec   nonchilled    350    37.2
5  Qn1    Quebec   nonchilled    500    35.3
6  Qn1    Quebec   nonchilled    675    39.2

这个CO2数据集包含了84条观测值和5个变量:Plant、Type、Treatment、conc和uptake。通常,你要对数据集做的第一件事是基于一个过滤器筛选数据行。

SELECT * FROM CO2 WHERE conc>400 AND uptake>40

R中的等价表述使用了下面这种简单的语法:

CO2_subset <- CO2[CO2$conc>400 & CO2$uptake>40,]
head(CO2_subset)
    Plant  Type     Treatment     conc   uptake
12  Qn2    Quebec   nonchilled    500    40.6
13  Qn2    Quebec   nonchilled    675    41.4
14  Qn2    Quebec   nonchilled    1000   44.3
19  Qn3    Quebec   nonchilled    500    42.9
20  Qn3    Quebec   nonchilled    675    43.9
21  Qn3    Quebec   nonchilled    1000   45.5
> dim(CO2_subset)  # 8 observations selected
[1] 8 5

然后,我们将看一条SQL SELECT语句的ORDER BY子句。在这里,我们希望将结果集根据变量conc进行排列(升序序列),然后根据变量uptake进行排列(降序序列)。下面是SQL的表述:

SELECT * FROM CO2 ORDER BY conc, uptake DESC

R中的等价表述使用了下面这种简单的语法。我已经加了一些附加的R语句将结果限制在前20行,但是这只是为了方便起见,因为我们不想在这里展示CO2数据集全部的84行观测值。

> CO2[order(CO2$conc, -CO2$uptake),][1:20,]
    Plant  Type         Treatment     conc   uptake
15  Qn3    Quebec       nonchilled       95     16.2
1   Qn1    Quebec       nonchilled        95     16.0
36  Qc3    Quebec       chilled           95     15.1
22  Qc1    Quebec       chilled           95     14.2
8   Qn2    Quebec       nonchilled        95     13.6
50  Mn2    Mississippi  nonchilled       95     12.0
57  Mn3    Mississippi  nonchilled       95     11.3
43  Mn1    Mississippi  nonchilled       95     10.6
78  Mc3    Mississippi  chilled          95     10.6
64  Mc1    Mississippi  chilled          95     10.5
29  Qc2    Quebec       chilled           95     9.3
71  Mc2    Mississippi  chilled          95     7.7
16  Qn3    Quebec       nonchilled        175    32.4
2   Qn1    Quebec       nonchilled        175    30.4
9   Qn2    Quebec       nonchilled        175    27.3
30  Qc2    Quebec       chilled           175    27.3
23  Qc1    Quebec       chilled           175    24.1
51  Mn2    Mississippi  nonchilled       175    22.0
37  Qc3    Quebec       chilled           175    21.0
58  Mn3    Mississippi  nonchilled       175    19.4

另一个强大的SQL结构是GROUP BY子句,用来计算聚合值,例如平均值。在这种情况下,我们想要计算每个不同的Plant值对应的uptake的平均值。下面是完成这个是SQL表述:

SELECT Plant, AVG(uptake) FROM CO2 GROUP BY Plant

R中的等价表述基于aggregate函数,使用了下面的语法来主导处理过程。第一个自变量x,对于aggregate()来说是CO2[,c(“uptake”)],将uptake这一列从CO2的数据框中分离出来。第二个变量by,是data.frame(CO2$Plant),是一个组变量。最后,R函数中的FUN变量用于计算摘要统计量,在这个例子中,代表的是mean。

> aggregate(x=CO2[,c("uptake")], by=data.frame(CO2$Plant), FUN="mean")
     CO2.Plant    x
1    Qn1          33.22857
2    Qn2          35.15714
3    Qn3          37.61429
4    Qc1          29.97143
5    Qc3          32.58571
6    Qc2          32.70000
7    Mn3          24.11429
8    Mn2          27.34286
9    Mn1          26.40000
10   Mc2          12.14286
11   Mc3          17.30000
12   Mc1          18.00000

我们将举一个如何用R做SQL多表查询的例子来结束讨论。考虑这样一种情况:你想从一张标注了州和省的次表中查找国家。下面是完成这个任务的SQL语句:

SELECT c.Type,
c.Plant,
c.Treatment,
c.conc,
c.uptake,
g.country
FROM geo_map g
LEFT JOIN CO2 c ON(c.Type = g.Type)

R中的等价表述使用了下面这种基于merge()函数的语法。看看CO2数据集中的前几行观测数据,我们了解到变量Type中包含了植物最初生活的州或省。我们使用这个变量作为通用的键值。下一步,我们将创建一个新的数据框geo_map,它会扮演将国家和州/省配对的查找表的角色。然后,在为geo_map设定了合适的列名之后,使用merge()来生成和SQL多表查询得到的相同的结果集joinCO2。注意新的数据框含有一个变量country,它是基于Type的查找值。这和SQL多表查询有相同的效果。

> head(CO2)
   Plant  Type    Treatment    conc    uptake
1  Qn1    Quebec  nonchilled   95      16.0
2  Qn1    Quebec  nonchilled   175     30.4
3  Qn1    Quebec  nonchilled   250     34.8
4  Qn1    Quebec  nonchilled   350     37.2
5  Qn1    Quebec  nonchilled   500     35.3
6  Qn1    Quebec  nonchilled   675     39.2

> stateprov <- c("Mississippi", "California", "Victoria",   
"New South Wales", "Quebec", "Ontario")
> country <- c("United States", "United States", "Australia", "Australia", "Canada", "Canada")

> geo_map <- data.frame(country=country, stateprov=stateprov)
> geo_map
    country         Type
1   United States   Mississippi
2   United States   California
3   Australia       Victoria
4   Australia       New South Wales
5   Canada          Quebec
6   Canada          Ontario

> colnames(geo_map) <- c("country", "Type")
> joinCO2 <- merge(CO2, geo_map, by=c("Type"))
> head(joinCO2)
  Type        Plant Treatment   conc   uptake  country
1 Mississippi  Mn1    nonchilled  95     10.6     United States
2 Mississippi  Mn1    nonchilled  175    19.2     United States
3 Mississippi  Mn1    nonchilled  250    26.2     United States
4 Mississippi  Mn1    nonchilled  350    30.0     United States
5 Mississippi  Mn1    nonchilled  500    30.9     United States
6 Mississippi  Mn1    nonchilled  675    32.4     United States

鉴于数据科学正在快速演变,我们可以看到社交媒体中的非结构化数据正在为传统的数据源增添异彩。毋庸置疑的是,最流行的社交媒体数据源是Twitter。“非结构化”这一术语用于描述社交媒体数据,因为它不像典型的企业事务数据那样通常呈现表格形式。非结构化数据是自由格式,可能是纯文本,在推文中是140个字符、缩略语、控件、标签和特殊符号。就像其他所有数据源一样,使用这类数据的第一步是将它读进R环境。在本节中,我们将分步演示使用R读取推文的过程。

遗憾的是,使用Twitter作为数据源有点费劲,因为从2013年3月开始,安全要求成为了必备条件(在此之前,读取数据容易得多)。你必须拥有一个Twitter账户,并在你的R代码中提供对这个账户的身份验证。

首先,我们要安装twitteR包,来帮助读取推文。这是基于R的Twitter客户端,这个包提供了一个到Twittwe网页API的接口,也包括了ROAuth库(开放式身份验证),用Twitter对我们进行身份验证必须用到该库。

> install.packages("twitteR")  # Contains ROAuth
> library(twitteR)
> library(ROAuth)

下一步,我们将定义几个变量来存放几个特殊的URL,用于和Twitter进行通信:requestURL、accessURL和authURL。而且,如果你是一个Windows用户,需要从下面提供的URL中下载特殊的CA(社区驱动的证书颁发机构)证书文件。

> requestURL <- "https://api.twitter.com/oauth/request_token"
> accessURL <- "https://api.twitter.com/oauth/access_token"
> authURL <- "https://api.twitter.com/oauth/authorize"
> download.file(url="http://curl.haxx.se/ca/cacert.pem", destfile= "cacert.pem")

接下来,你要访问http://dev.twitter.com/apps/new ,用你的Twitter账户登录,创建一个Twitter应用。然后在页面上输入详细信息,才能通过Test Auth按钮得到用户关键字和用户秘钥。你需要将秘钥复制粘贴到你的R代码中。

> consumerKey <- "tu4dkb9fHLgLrNptaI2CA"
> consumerSecret <- "UzlhoMFyF9IZ6bxxG89DLdPB74VUzur3mBWcr6LcVE"
> Cred <- OAuthFactory$new(consumerKey=consumerKey,
             consumerSecret=consumerSecret,
             requestURL=requestURL,
             accessURL=accessURL, 
             authURL=authURL)

现在输入下面这行代码,要求Twitter提供一个数值型的PIN号码给你。你将看到R控制台的消息,指导你将控制台中展示的特殊URL复制粘贴到你的浏览器中(注意:如果你无法高亮显示控制台中的URL并将它复制到剪贴板中,需要升级RStudio了)。一旦你做完这个,Twitter API会展现一个网页,包含7位的PIN。你需要把这些数字打印到一直等待输入的控制台中。

> Cred$handshake(cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl") )

这时,可以使用save()函数将你的Twitter身份验证保存下来,便于以后使用。最后,你需要用twitteR包中的registerTwitterOAuth()函数注册你的Twitter身份验证。

> save(Cred, file="twitter authentication.Rdata")
> registerTwitterOAuth(Cred)
[1] TRUE

如果想在以后读取推文,只需要使用下面这段代码:

> load("twitter authentication.Rdata")
> registerTwitterOAuth(Cred)

最后,我们已经做好了读取推文的准备了。在下面这段代码中,我们使用了searchTwitter()函数,并给它传递了一个搜索关键字。在这个例子中,标签#MLB代表了美国职业棒球大联盟。Twitter API限制了你可以读取的推文最多是499条。推文以列表的形式返回,所以我们使用twListToDF()函数将它们转化成数据框的形式,便于后续分析。最后,我们可以将推文以CSV的格式写出,便于保存。

> MLB.list <- searchTwitter('#MLB', n=499, cainfo="cacert. pem") 
> MLB.df = twListToDF(MLB.list) 
> write.csv(MLB.df, file='MLBTweets.csv', row.names=F)

另一个非常有用的数据源是谷歌分析。很多公司使用谷歌的网站统计服务来观察网站的使用情况。谷歌分析的成熟程度是令人惊讶的,其中最大的优点是:这项服务是免费使用的。一旦植入到网站中(使用谷歌提供的一个可以添加到网站中的代码片段),就能收集大量数据,用于后续分析。虽然谷歌提供了一套令人印象深刻的工具来分析网站统计数据,你也可以直接连接数据,这样就能用这些数据执行自己定制的机器学习算法。在本节中,我们会介绍如何连接谷歌分析数据。

有两种方法连接谷歌分析数据。第一,你可以使用你用来跟踪网站的账户来登录谷歌分析。你运行的每一份报表都有一个Export按钮,可以用来下载报告中的原始数据。我们的想法是,用一段长时间范围的数据运行得到一份详细的报表,这样你就能得到一份优良的数据样本,可用于后续的机器学习分析。我们将在下面的案例中看到这样的示例。连接谷歌分析的另一种方法是使用RGoogleAnalytics包,其中包含了大量R函数,能帮助你使用谷歌分析Data Export API。我们也能在下面的例子中看见这种用法。

让我们首先用导出工具连接谷歌分析数据。在这个例子中,我用一个监控客户端网站的账号登录谷歌分析。我通过Traffic Sources -> Sources -> All Traffic这一路径选择一种标准报表。在查看了报表之后,我从顶端的水平菜单选择Export -> Excel(XLSX),将文件保存在工作目录下面的data文件夹中。谷歌分析生成的Excel文件有多个工作表,通常有一个Summary表和一个或多个Datasheets表。取决于你想用数据做什么事情,你必须决定把哪个表读入R中。谷歌分析使用的一些列名和xlsx包不兼容,所以你需要在Excel中打开文件,手动编辑一个或者多个可能造成冲突的列名。例如,你需要把列名Pages/Visit改成更适合R的表述,例如Pages_Visit。图2-4展示了一个准备读入到R中使用的表格:

> library(xlsx)
> GA <- read.xlsx2("./data/Analytics_All_Traffic.xlsx", sheetIndex=2)
> head(GA)
      Source_Medium Visits    Pages_Visit Avg_Visit_Duration
1    google / organic 1349.0 5.638991845811712 151.54558932542625
2    (direct) / (none) 562.0 4.119217081850533 114.98220640569394
3 fashiondistrict.org / referral 242.0 3.9214876033057853   
140. 30578512396696
4     yahoo / organic  73.0 3.6301369863013697 66.53424657534246
5     bing / organic  71.0 5.549295774647887 104.14084507042253
6    oohlaluxe.net / referral  36.0 4.361111111111111  
 116. 80555555555556
   Percent_New_Visits     Bounce_Rate
1  0.614529280948851      0.5181616011860638
2  0.597864768683274      0.5747330960854092
3  0.8099173553719008     0.45041322314049587
4  0.684931506849315      0.410958904109589
5  0.647887323943662      0.29577464788732394
6  0.8888888888888888     0.3611111111111111

现在让我们看看使用RGoogleAnalytics包中的RGoogleAnalytics API。在R中,你需要用OAuth2例行程序来认证你的身份,创建一个查询,并把结果保存在数据框中。在开始之前,RGoogleAnalytics库依赖于另外两个库:RCurl提供了在R中的https支持;RJSON提供了解析API返回的RJSON的功能。

图2-4 谷歌分析All Traffic Sources报表

> install.packages("RCurl")
> install.packages("RJSON")
> library("RGoogleAnalytics")

使用下面这段语句能打开一个浏览器窗口,这样就可以用谷歌的OAuth2认证身份。参照页面上的指示,将Access Token复制到剪贴板中,然后将它粘贴到R控制台中。

> query <- QueryBuilder()
> access_token <- query$authorize()

接下来,这段语句会使用你上面得到的access_token来创建一个新的谷歌分析API对象。

> ga <- RGoogleAnalytics()
> ga.profiles <- ga$GetProfileData(access_token)
> ga.profiles    # List the GA profiles

下面这段代码是将谷歌分析作为数据源读取过程的主要部分。你建立了一个查询字符串,并使用配置文件设置其索引值。

> query$Init(start.date = "2013-07-01",
      end.date = "2013-07-01",
      dimensions = "ga:date,ga:pagePath",
      metrics = "ga:visits,ga:pageviews,ga:timeOnPage",
      sort = "ga:visits",
      #filters="",
      #segment="",
      max.results = 99,
      table.id =
       paste("ga:",ga.profiles$id[1],sep="",collapse=","),
       access_token=access_token)

> ga.data <- ga$GetReportData(query)
[1] "Your query matched 88 results that are stored to dataframe ga.data"
> head(ga.data)
#  date     pagePath
1  20130701 /SearchResult.asp?Type=ALL&String=&CompanyID= 127&CategoryID=0
2  20130701 /SearchResult.asp?Type=ALL&String=&CompanyID= 130&CategoryID=0
3  20130701 /SearchResult.asp?Type=ALL&String=&CompanyID= 175&CategoryID=0
4  20130701 /SearchResult.asp?Type=ALL&String=&CompanyID= 181&CategoryID=0
5  20130701 /SearchResult.asp?Type=ALL&String=&CompanyID= 184&CategoryID=0
6  20130701 /SearchResult.asp?Type=ALL&String=&CompanyID= 186&CategoryID=0

    visits   pageviews   timeOnPage
1   0        3           11
2   0        4           20
3   0        2           13
4   0        1           1
5   0        2           11
6   0        3           6

在一个机器学习项目中工作时,虽然数据科学家做的通常都是将外部文件导入R中,但有时在R环境下把数据写到外部文件中也是很有必要的。好在,我们在本章中见过的很多用于数据连接的R包都提供了写文件的功能。例如,write.table()函数能写一个CSV文件。在下面的例子中,我们将用R移除数据框的第一列(变量POST_ID),并写出一个不包含这个变量的新版CSV文件。然后,仅仅为了证明它真的有效,我们将新的CSV文件读回R中,然后使用head()来展示它的前几行。

> tempDF <- SFParkingMeters[,-1]  # Remove POST_ID variable
> write.table(tempDF, file="./data/newSFParkingMeters.csv", sep=",")
> newSFParkingMeters <- read.table("./data/newSFParkingMeters.csv", sep=",")
> head(newSFParkingMeters)
  MS_ID MS_SPACEID CAP_COLOR METER_TYPE SMART_METE ACTIVESENS JURISDICTI ON_OFF_STR
1 -     0        Grey      SS     Y       Y    SFMTA    ON
2 -     0        Green     SS     Y       Y    SFMTA    ON
3 -     0        Yellow    SS     Y       Y    SFMTA    ON
4 -     0        Grey      SS     N       N    SFMTA    ON
5 -     0        Grey      SS     N       N    SFMTA    ON
6 -     0        Grey      SS     Y       Y    SFMTA    ON

   OSP_ID STREET_NUM  STREETNAME   STREET_SEG RATEAREA  SFPARKAREA
1  0      2016      CHESTNUT ST  3977000   Area 5  Marina
2  0      2103      CHESTNUT ST  3979000   Area 5  Marina
3  0      2116      CHESTNUT ST  3979000   Area 5  Marina
4  0      525       COLUMBUS AVE 4295000   Area 3      
5  0      527       COLUMBUS AVE 4295000   Area 3       
6  0      412        HAYES ST     6816000    Area 5  Civic Center

    LOCATION
1   (37.800798, -122.43687)
2   (37.800522, -122.438067)
3   (37.800589, -122.438525)
4   (37.800053, -122.409985)
5   (37.800088, -122.410035)
6   (37.776878, -122.423512)

同样地,xlsx包的write.xlsx()函数、rjson包的toJSON()等,都能实现类似的功能。

在本章中,我们了解了为何数据源是机器学习方程的命脉。我们介绍了许多连接原始数据并将其导入R环境中以用于机器学习算法的方法。下一步将会是“加工”这些原始数据,便于你选择的算法能够使用数据。这叫做“数据处理”,这是第3章的主题。

下面是本章主要内容的小结:


相关图书

ChatGPT原理与应用开发
ChatGPT原理与应用开发
动手学机器学习
动手学机器学习
机器学习与数据挖掘
机器学习与数据挖掘
机器学习公式详解 第2版
机器学习公式详解 第2版
自然语言处理迁移学习实战
自然语言处理迁移学习实战
AI医学图像处理(基于Python语言的Dragonfly)
AI医学图像处理(基于Python语言的Dragonfly)

相关文章

相关课程