大数据、数据挖掘、机器学习和可视化,近来计算界的几件大事好像总也绕不开数据这个主角。从统计学家到软件开发人员,再到图形设计师,一下子所有人都对数据科学产生了兴趣。便宜的硬件、可靠的处理工具和可视化工具,以及海量的免费数据,这些资源的汇集使得我们能够比以往任何一个时期更加精准地、轻松地发现趋势、预测未来。
不过,你可能还未听说过的是,数据科学的这些希望与梦想都建立在乱七八糟的数据之上。在正式应用于我们认为是数据科学的核心的算法和可视化之前,这些数据往往需要经过迁移、压缩、清洗、打散、分片、分块以及其他多种转换处理。
本章内容将涵盖以下几个方面:
1 新视角
最近我们读报时发现《纽约时报》将数据清洗称为看门人工作,并称数据科学家百分之八十的时间都花费在了这些清洗任务上。从下图中我们可以看出,尽管数据清洗是很重要的工作,但它并没有像大数据、数据挖掘或是机器学习那样真正地引起公众的注意。
不会真的有人因为没有见过人们聚众讨论看门人的工作多么有趣、多么酷而开始评头论足吧?说起来还真是惭愧,这工作没比做家务强到哪里去,但话又说回来,与其对它弃之不理、抱怨不断、恶语相加,还不如先把活儿干完,这能让我们过得更好些。
还不相信是吗?那让我们打个比方,你不是数据看门人,而是数据大厨。现在有人交给你一个购物篮,里面装满了你从未见过的各种各样的漂亮蔬菜,每一样都产自有机农场,并在最新鲜的时候经过人工精挑细选出来。多汁的西红柿,生脆的莴苣,油亮的胡椒。你一定激动地想马上开启烹饪之旅,可再看看周围,厨房里肮脏不堪,锅碗瓢盆上尽是油污,还沾着大块叫不出名的东西。至于厨具,只有一把锈迹斑斑的切刀和一块湿抹布。水槽也是破破烂烂的。而恰恰就在此时,你发现从看似鲜美的莴苣下面爬出了一只甲虫。
即使是实习厨师也不可能在这样的地方烹饪。往轻了说,无外乎是暴殄天物,浪费了一篮子精美的食材。如果严重点儿讲,这会使人致病。再说了,在这种地方烹饪根本毫无乐趣可言,也许全天的时间都得浪费在用生锈的破刀切菜上面。
与厨房的道理一样,事先花费些时间清洗和准备好数据科学工作区、工具和原始数据,都是值得的。“错进,错出。”这句源于上20世纪60年代的计算机编程箴言,对如今的数据科学来说亦为真理。
2 数据科学过程
数据清洗是如何融入数据科学中的呢?简短的回答就是,清洗工作是关键的一步,它直接影响在它之前和之后的处理工作。
稍微长一些的回答就得围绕数据科学过程的六个步骤来描述了,请看下面的列表。数据清洗正好处于中间的位置,第三步。但是,请不要以纯线性方式看待这些步骤,简单地认为这是一个从头到尾执行的框架,其实在项目的迭代过程中,我们会根据具体情况,反复执行这些步骤。另外还需要指出的是,并不是每一个项目都会包含列表中所有的步骤。举个例子,有时候我们并不需要数据收集或可视化步骤。这完全取决于项目的实际情况。
(1) 第一步是问题陈述。识别出你要解决的问题是什么。
(2) 接下来要做的是数据收集与存储。数据从何而来?它们在哪里存放?格式又是什么?
(3) 然后是数据清洗。数据需要修改吗?有什么需要删除的吗?数据应该怎么调整才能适用于接下来的分析和挖掘?
(4) 数据分析和机器学习。数据需要哪些处理?需要什么样的转换?使用什么样的算法?运用什么公式?使用什么机器学习算法?顺序又是怎样的呢?
(5) 数据展现和可视化实现。数据处理结果应该怎样呈现出来呢?我们可以用一张或几张数据表来表现,也可以使用图画、图形、图表、网络图、文字云、地图等形式。但这是最佳的可视化方案吗?有没有更好的替代方案呢?
(6) 最后一步是问题决议。你在第一步里所提出的疑问或是问题的答案究竟是什么?数据处理结果还有哪些不足?这个方法能彻底解决问题吗?你还能找出别的什么办法吗?接下来要做的又是什么?
在数据分析、挖掘、机器学习或是可视化实现之前,做好相关的数据清洗工作意义重大。不过,请牢记,这是一个迭代的过程,因为在项目中我们可能需要不止一次地执行这些清洗操作。此外,我们所采用的挖掘或分析方法会影响清洗方式的选取。我们可以认为清洗工作包含了分析方法所能决定的各种任务,这有可能是交换文件的格式、字符编码的修改、数据提取的细节等。
数据清洗与数据收集和存储(第2步)的关系也十分密切。这意味着你得收集原始数据,对它们执行存储和清洗操作,之后再把清洗过的数据保存下来,接下来收集更多的数据,清洗新的数据并把清洗结果与前面处理完的结果数据结合起来,重新进行清洗、保存等操作,反反复复。正因为这个过程非常复杂,所以我们要么选择牢牢记住曾经做过的处理,并记录下那些可以根据需要反复执行的步骤,要么把工作的全部状况告知其他相关人员。
3 传达数据清洗工作的内容
六步处理过程是围绕着问题和解决方案这个故事线组织的,因此,在作为报表框架使用时,它的表现十分优秀。如果你已经决定使用六步框架来实现数据科学过程报表,将发现只有到了第三步你才会真正开始进行与清洗有关的工作。
哪怕你并不需要把数据科学过程制成正式的报告文档,你仍然会发现,认真地记录下曾经按什么顺序做了些什么事情,对以后的工作也是极有帮助的。
请记住,哪怕是规模再小、风险再低的项目,你也要面对至少两人规模的受众:现在的你和六个月之后的你。请相信我说的话,因为六个月之后的你基本上不会记得今天的你做过什么样的清洗工作,也不记得其中的缘由,更谈不上如何重新再做一次。
要解决这个问题,最简单的方案就是保留一份工作日志。这个日志应该包含链接、屏幕截图,或是复制粘贴你曾经运行过的具体的命令,并配上为什么要这样做的解释性文字。下面是一个关于小型文本挖掘项目的日志示例,其中记述了每个阶段输出的外部文件链接以及相关的清洗脚本链接。如果你对日志中提到的某些技术不太熟悉的话,也没有关系,因为这个示例的重点只是让你了解一下日志的样子而已。
(1) 我们写了一条SQL查询语句来检索出每条数据及其相关描述。
(2) 为了能在Python中进行词频分析,我们需要把数据调整成JSON格式。因此我们做了一个PHP脚本,用它来循环遍历查询结果,并以JSON格式保存到文件中(第一个版本的数据文件)。
(3) 这个文件里的数据有些格式上的错误,比如包含了没有转义的问号和一些多余的内嵌HTML标签。这些错误可以在第二个PHP脚本中修正。运行第二个脚本之后,我们就可以得到一份干净的JSON文件了(第二个版本的数据文件)。
这里需要注意的是,我们用日志来解释程序做过什么和这样做的原因。日志的内容可以很简短,但要尽可能地包含一些有用的链接。
另外,我们还可以选择许多更复杂的方案来传达信息。例如,如果你对软件项目管理中常用的版本控制系统比较熟悉的话,如Git或是Subversion,就可以好好地规划设计一番,想想怎么使用这些工具来跟踪数据清洗工作。不管你使用什么样的系统,最重要的事情是做好日志,哪怕只有一句话。来吧,学着把它用起来,别耽误进度了。
4 数据清洗环境
本书中涉及的数据清洗方法是通用的,适用范围非常广泛。你不需要任何高端专业的数据库产品或是数据分析产品(事实上,这些厂商和产品可能已经提供了数据清洗程序或是解决方法)。我围绕数据处理过程中的常见问题,设计了本书中的清洗教程。而我要展示的都是适用范围较为广泛的开源软件和技术,它们很容易在实际工作中获得和掌握。
下面列出了你需要准备的工具和技术。
几乎在每一章中,我们都会用到终端窗口和命令行界面,比如Mac OS X上的Terminal程序或者是Linux系统上的bash程序。而在Windows上,有些命令可以通过Windows的命令提示符运行,但其他的命令则需要通过功能更强的命令行程序来运行,比如CygWin。
几乎在每一章中,我们还会用到文本编辑器或者是适合程序员使用的编辑器,如Mac上的Text Wrangler,Linux上的vi或emacs,或是Windows上的Notepad++、Sublime编辑器等。
在绝大数章节里,我们需要使用Python 2.7版本的客户端程序,如Enthought Canopy,另外还需要足够的权限来安装一些包文件。其中大部分例子都可以直接在Python 3中运行,但有些不可以,所以如果你安装的是Python 3的话,可以考虑再安装一个2.7版本。
在第3章“数据清洗的老黄牛——电子表格和文本编辑器”中,我们需要使用电子表格程序(主要是Microsoft Excel和Google Spreadsheets)。
在第7章“RDBMS清洗技术”中,我们需要使用MySQL数据库和一个用于访问该数据库的客户端软件。
5 入门示例
准备好了吗?现在让我们磨好手里的厨刀并结合六步框架来解决一些简单的数据清洗问题吧。这个例子会用到对公众开放的安然(Enron)公司电子邮件数据集。这是一个非常有名的数据集,当中所有的往来邮件都源自现已停业的安然公司前雇员。作为美国政府调查安然公司账目欺诈的一部分,雇员之间的邮件已被公开并可供任何人下载。来自各个领域的研究人员已经发现,这些邮件有助于研究商务沟通、社交网络等问题。
你可以在维基百科http://en.wikipedia.org/wiki/Enron上阅读更多关于安然公司和导致它破产的金融丑闻。在另外一个页面http://en.wikipedia.org/wiki/Enron_Corpus上,你可以阅读关于安然公司电子邮件语料库的信息。
在这个例子当中,我们会采用六步框架来解决一个简单的数据科学问题。假设我们需要揭露在某一段时间里安然公司内部电子邮件的使用趋势和特征。先让我们按照日期来对安然雇员之间的往来邮件数量做个统计,然后再通过图形来显示统计出来的数据。
首先,我们需要按照http://www.ahschulz.de/enron-email-data/上面的指南下载一份MySQL版本的安然公司语料库。另一个(备份)源的地址是https://www.cs.purdue.edu/homes/jpfeiff/enron.html。根据指南,我们需要把数据导入到MySQL服务器中一个称为Enron的数据库模式中。导入之后的数据可以通过MySQL命令行界面或是基于网页的PHPMyAdmin工具进行查询。
这是我们的第一个数据统计查询,语句如下:
SELECT date(date) AS dateSent, count(mid) AS numMsg
FROM message
GROUP BY dateSent
ORDER BY dateSent;
从结果中我们马上就会注意到,许多邮件的日期都不正确。比如,很多日期要么早于或晚于公司的存续期(如1979),要么与事实逻辑不符(如0001或2044)。邮件虽旧,但也不至于那么旧!
下表是截取出来的一部分数据片段(完整的结果集长达约1300行)。这些数据的日期格式都是正确的。但是,有些日期值有着明显的错误。
dateSent | numMsg |
---|
0002-03-05
| 1
|
0002-03-07
| 3
|
0002-03-08
| 2
|
0002-03-12
| 1
|
1979-12-31
| 6
|
1997-01-01
| 1
|
1998-01-04
| 1
|
1998-01-05
| 1
|
1998-10-30
| 3
|
这些错误日期的产生很有可能是由邮件客户端配置不当导致的。这里,我们有三种处理方案可以选择。
什么都不处理:也许,我们可以选择忽略这些错误数据,直接开始构建线性图。但是,最小的错误日期始于0001年,最大的错误日期至2044年结束,所以我们可以想象,最终的线性图时间轴上将有1300个刻度线,每个刻度上面显示着1或者2。光是听起来就没有什么吸引人的地方,也没提供什么有用的信息,所以不处理就等同于数据毫无用处。
修正数据:我们可以尝试算出错误消息对应的正确日期,从而生成正确的数据集来创建图形。
扔掉受影响的邮件:我们可以做出一个明智的决定,放弃那些日期不在预定范围之内的邮件。
为了在选项二和选项三之间做个决断,我们需要先计算一下1999~2002年有多少封邮件会受到影响。为此,我们编写了下面的SQL语句:
SELECT count(*) FROM message
WHERE year(date) < 1998 or year(date) > 2002;Result: 325
结果显示一共有325封邮件包含日期错误,乍一看确实有点多,但请等一下,实际上这些数据只是占了全部数据量的百分之一。现在需要好好斟酌一下了,或许我们可以手工修复这些日期,但也可以假定不在乎这百分之一的损失。那就干脆扔掉这些数据直接选择第三个方案吧。下面是调整后的查询语句:
SELECT date(date) AS dateSent, count(mid) AS numMsg
FROM message
WHERE year(date) BETWEEN 1998 AND 2002GROUP BY dateSent
ORDER BY dateSent;
数据清洗完成之后一共生成了1211条结果,每一行都有其对应的邮件数量。下面的内容截取自新的数据结果集:
dateSent | numMsg |
---|
1998-01-04
| 1
|
1998-01-05
| 1
|
1998-10-30
| 3
|
1998-11-02
| 1
|
1998-11-03
| 1
|
1998-11-04
| 4
|
1998-11-05
| 1
|
1998-11-13
| 2
|
在新的数据中,1998年1月的两个日期看起来有些问题,因为其他邮件都始于10月,而且10月之后的邮件数量更为规律一些。这很奇怪,同时也反映了另一个问题:我们是否还有必要在x轴上标记每一个日期,即使这一天一封邮件都没有发出?
如果我们的答案是肯定的话,那就需要显示每一个日期,即使它对应的邮件数量是0。这意味着我们需要再做一轮数据清洗工作,生成那些没有邮件往来的日期所对应的数据。
但是请等一下,对于这个问题的处理,我们可以稍微变通一下。是不是真的要在原始数据中加入零数据,其实这取决于我们用什么样的工具来创建图表以及图表的种类。举个例子来说,Google的Spreadsheets就能在初始数据中缺少日期的情况下,在 x 轴上自动进行零值数据补齐,创建线性图或是条状图。在我们的数据中,这些需要补齐的零值就是1998年所缺失的日期。
下面的三幅图演示了这些工具所呈现的结果,并反映出它们是如何处理日期轴上的零值数据的。请注意,Google Spreadsheets在头部和尾部所展现的长长的零值数据。
D3 JavaScript可视库也能完成同样的工作,零值数据也是自动补齐的,如下图所示。
关于如何使用D3完成一个简单的线性图,请参考教程:http://bl.ocks.org/mbostock/3883245。
Excel的线性图也有同样的数据补齐功能,如下所示。
接下来,我们需要考虑一下是否需要零值数据,要不要让它们在 x 轴上显示(数据查询结果总数为1211,而在指定的年限范围,即1998~2002年,一共有1822天)。或许显示零值日期并不会起到什么作用;此外,倘若图表过于拥挤,有些较小的空隙我们就看不到了。
为了比较两种图表之间的差别,我们可以快速地把相同的数据再次放入Google Spreadsheets(你也可以在Excel或D3中完成这个任务),但这次我们只需选择数量这一个字段来构建图表就可以了,这样一来,Google Spreadsheets就不会在 x 轴上显示日期了。最后生成的结果图表中只包含数量数据,零值数据不会被填充进来。长长的尾巴不见了,图表中各个重要的部分(中间部分)也都被保留了下来。
值得庆幸的是,这次生成的图表与之前的相比还是很像的,并省去了前后两端冗长的内容。根据比较结果和我们先前的计划(还记得我们要做的只是创建一个简单的条形图吧),现在终于可以继续下一步工作,不用烦恼是否需要创建零值数据了。
当一切都完成之后,最终的条形图会为我们显示出安然公司曾经的几次邮件峰值。最大的峰值出现在2001年10月和11月,恰好是丑闻被揭露的时候。还有两次较小一点的峰值发生在2001年6月26日和27日,以及2000年12月12日和13日,那时的安然也有新闻事件发生(分别是加利福尼亚州的能源危机事件和公司领导层的变动)。
如果数据分析已经让你开始兴奋的话,那么接下来你可以好好利用这些数据来发挥你的奇思妙想。愿这些清洗干净的数据可以让你的分析工作更上一层楼!
1.6 小结
当所有工作全都做完的时候,事实印证了《纽约时报》的报道。我们从这个简单的练习中可以看出,即便是回答一个小小的数据问题,数据清洗就占了整个过程80%的工作量(在这个全文共计900个单词的案例中,光是谈论数据清洗的基本原理和方案就用了700个单词)¹。数据清洗的的确确是数据科学过程的关键部分,它不仅涉及对技术问题的理解,同时还要求我们做出相应的价值判断。作为数据清洗工作的一部分,我们甚至需要在尚未完成分析与可视化步骤的时候,预先考虑它们的输出结果将是什么样子。
¹这里指的是英文原版字数统计。——译者注
重新审视数据清洗在这一章的工作中所扮演的角色,我们很容易发现,清洗效果的提升能够大幅减少后续处理的时间。
CIO之家 www.ciozj.com 公众号:imciow