数据整理实践指南

978-7-115-41102-0
作者: 【美】Q. Ethan McCallum(麦卡伦)
译者: 魏秀丽李妹芳
编辑: 陈冀康

图书目录:

详情

本书提供了如何处理不良数据,进行数据清理的案例。而这些工作,正是数据科学工作中最重要、核心的方面。本书适合数据科学家、数据处理和整理相关开发人员阅读。读者将在本书中所涵盖的多个主题中学会如何测试数据、如何分析数据以及其他处理工具及方法。

图书摘要

版权信息

书名:数据整理实践指南

ISBN:978-7-115-41102-0

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

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

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

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

• 著    [美] Q.Ethan McCallum

  译    魏秀丽 李妹芳

  责任编辑 陈冀康

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

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

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

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

  反盗版热线:(010)81055315


作者简介(按出现的先后顺序排列)

Kevin Fink 是一位经验丰富的商业科技经理人。他热衷于将数据转变成商业价值。他除了帮助一些公司成长外(在WhitePages.com 做过4年首席技术官[Chief Technology Officer,CTO]),还曾帮助两家公司上市(1999年在N2H2做CTO,2011年在Demand Media 做业务处理程序[ Service Processor,SVP]工程)。另外,他和夫人还在西雅图东部经营了Traumhof,一个进行马术训练和寄养的马场,作为夫妻共同的财产。在空余时间里,他喜欢远足,喜欢和儿子一起骑双人自行车,喜欢玩寻宝游戏。

Paul Murrell是位于新西兰的奥克兰大学统计系的一名高级讲师。他的研究领域是统计计算和制图学,也是R项目核心开发团队里的成员。他是R GraphicsIntroduction to Data Technologies的作者,还是美国统计协会的会员。

Josh Levy 是德克萨斯州奥斯丁的一位数据科学家。他从事内容推荐和文本挖掘系统的工作。他在北卡罗来纳大学获得博士学位。在那里他为医学图像分割研究了统计形状模型。他最喜欢的桌上足球射门方向是从守卫区斜飞着进球。

Adam Laiacano 在美国东北大学获得了电气工程理学学士学位。在加入有名的创建于纽约的新公司之前,他曾经花了多年时间为原子钟设计信号检测系统。

Jacob Perkins 是Weotta的CTO, 是自然语言工具包(Natural Language Toolkit,NLTK)的贡献者,是Python Text Processing with NLTK Cookbook的作者。他也创建了NLTK的示范产品和应用程序接口(Application Program Interface,API)站点text-processing.com,并且定期在streamhacker.com 发表博客。之前,他曾发明了冰箱。

Spencer Burns 是生活在旧金山的一位数据科学家/工程师。在过去的15年里他一直在进行着从混乱的数据中提取信息的工作,这些数据的范围从情报到计量金融和社交媒体。

Richard Cotton 是一位有着化学健康与安全背景的数据科学家。他对让非技术型用户有权使用统计模型的工具有着广泛的研究。他提出R包,可以为了确保函数有合理的API,检查变量和“签名”状态。他经营着一家名为The Damned Liars 的统计咨询公司。

Philipp K. Janert 在德国出生并长大,他于1997年在华盛顿大学获得理论物理学博士学位,并且从那时起就一直从事科技产业。他曾在Amazon.com工作4年,在那里他发起并主导了多个项目来完善亚马逊的订单处理流程。他写过两本关于数据分析方面的书,其中一本是畅销书Data Analysis with Open Source Tools(O’Reilly, 2010),而且他的作品也出现在Perl.com、IBM developerWorks、IEEE Software以及Linux杂志上。他对Perl综合典藏网(Comprehensive Perl Archive Network,CPAN)和其他开放源代码项目也做过贡献。他现在住在太平洋西北地区。

Jonathan Schwabish 是美国国会预算办公室的经济学家。他进行了关于不平等、移民、退休保障、数据测量、食品券和美国国家政策和其他方面的研究。他的作品在Journal of Human ResourceNational Tax Journal等报刊出版。他也是数据可视化的创建者,他对各种类型的主题进行设计,从食品券到卫生保健,再到教育。他的可视化作品曾在visualizaing.org 和visul.ly两个网站特载。他也曾针对数据可视化策略和最佳实践在许多政府机构和政策机构发言。他在麦迪逊的威斯康星大学获得经济学学士学位,在美国锡拉丘兹大学获得经济学博士学位。

Brett Goldstein 从2012年开始在芝加哥创新科技部做专员。在这之前他是芝加哥的首席数据官。在此期间,他引领这个城市利用数据改善政府为居民服务的方式。在来到市政厅做首席数据官之前,他成立并指挥芝加哥警察局预测分析小组。目的是预测在什么时候什么地点会发生犯罪活动。在进入公共部门之前,他是OpenTable的早期雇员,已经帮助公司运营7年之久。他在康涅狄格学院获得文学学士学位,在萨福克大学获得刑事司法的理学硕士学位,在芝加哥大学获得计算机科学的理学硕士学位。Brett目前正在伊利诺伊大学芝加哥校区向他的犯罪学、法律和司法学博士学位努力。他与妻子和3个孩子居住在芝加哥。

Bobby Norton 是Tested Minds 的联合创始人。Tested Minds 是一家以社交学习和快速反馈产品为重点的创新型公司。他已经为多家公司开发软件达十多年之久,比如洛克希德·马丁(美国一家航空航天制造商)、美国国家航空航天局、通用电气的全球研究部、ThoughtWorks(一家全球软件设计与定制领袖企业)、DRW Trading Group(一家自营性交易公司)以及Aurelius(一个具有长期投资意愿的工业投资公司,总部位于德国慕尼黑)。他的数据科学选择工具包括Java、Clojure、Ruby、Bash和R。Bobby在佛罗里达州立大学获得计算机科学的理学硕士学位。

Steve Francia是10gen(美国一家软件公司,现已更名为MongoDB Inc.)的首席宣传官。他负责MongoDB 数据库的用户体验。在去10gen之前,他在Opensky(一家提供技术信息服务的公司)、Portero(美国奢侈品网站)、Takkle(美国为高中运动员服务的网站)和Supernerd(一家传媒公司)做执行工程。他是一位非常受欢迎的演说家,他所涉及的主题广泛,包括云计算、大数据、电子商务、开发与数据库。他还是作家,曾发表过作品。他是辛迪加博主并且经常向行业刊物投稿。他的作品曾在纽约时报、英国卫报、Mashable(互联网新闻博客)、Read-WriteWeb(读写网)等报纸和网站受到关注。Steve长期为开放源码做着贡献。他享受用Vim(一种文本编辑器)编码并坚持流行的Vim发布。他与妻子和4个孩子在康涅狄格州生活。

Tim McNamara是一个提着手提电脑,怀揣着美好愿望的新西兰人。他是本地和全球开放数据社区活跃的参与者。他奔走于组织当地集会,从而协助全球危机公关运动。他作为程序员的技术是在帮助开发撒哈拉沙漠灾难管理系统时开始学习的,在帮助运行One Laptop Per Child XO 的Sugar Lab软件时取得了很大的进步。Tim最近刚刚转向了escience领域。在那里他的工作是支持研究社团对技术的理解与吸收。

Marck Vaisman 是一位数据科学家,也是一位顾问、企业家、投员大师和黑客。Marck 是DataXtract和LLC网站主要的数据学家。他帮助的客户非常多,从新创立的公司到世界500强,涵盖了各种各样的数据科学项目。他的工作经验横跨管理咨询、电信、网络、技术产业。他是Data Community DC(数据专业人和科学家社区)的联合创始人。Data Community DC 是一个通过组织聚会(包括Data Science DC 和 R Users DC)和其他举措来着力建立华盛顿数据社区并推动数据和统计科学的组织。他在范德堡大学获得MBA学位,在波士顿大学获得机械工程的理学学士学位。在他不做与数据相关的事情时,他会与他的家人、朋友一起学习、一起游泳、寻找新鲜有趣的游乐场所亦或是享受美味的啤酒。

Pete Warden是前苹果软件工程师,为O’Reilly写过Big Data GlossaryData Source Handbook。创建了开放源代码项目Data Science Toolkit和OpenHeatMap, 并且发布了苹果的iPhone位置跟踪文件。他是Jetpac的CTO和创始人。Jetpac是依照数据处理社交图片的应用商。至今,Jetpac已经分析了来自300万人的超过十亿张照片。

Jud Valeski 是Gnip的CEO和联合创始人。Gnip是为企业应用程序提供社交数据的领头羊。从面对产品的客户端消费者到大规模的后台基础设施项目,他已经从事技术工作20多年了。他曾经是IBM、美国网景公司(Netscape)、onebox.com、美国在线公司(AOL,American On Line)和me.dium的工程、产品以及企业并购团队中的一员。他曾在世界上数以千万的人们使用的产品中发挥了核心的作用。

Reid Draper 是一位函数程序员。他对分布式系统、编程语言,还有咖啡感兴趣。目前他正在为Basho做分布式数据库:Riak。

Ken Gleason 拥有20多年的技术工作经验,包括实时交易系统软件架构和开发以及零售金融服务应用程序设计。在过去的10年里,他在电子交易的数据驱动领域工作。在此期间他管理产品研发和高频率的交易策略。Ken在芝加哥大学布斯商学院获得MBA学位,在美国西北大学获得理学学士学位。

Q. Ethan McCallum 是一位专业的服务顾问。他的技术兴趣广泛,涵盖了从数据分析到软件,还有基础设施。他专业专注于通过实际的技术应用,帮助企业在减少风险、增加利润和进行明智的决策方面提高他们的能力。他的文字作品已在线上发表并且出版发行,其中包括Parallel R: Data Analysis in the Distributed World(O’Reilly, 2011)。

Q.Ethan McCallum 是一位顾问、作家和科技爱好者(顺序不论先后)。他的作品已经在The O’Relly Network 和Java.net上发表,并且发表示C/C++Users JournalDoctor Dobbs JournalLinux Magazine。他以专业人士的角色帮助企业做出明智的数据和技术决定。


本书的封面是一只细嘴雁,叫Ross’s goose(Chen rossii或Anser rossii)。它是一种北美的鸟类,得名于一个在加拿大西北地区雷索卢申堡工作的,叫Bernard R. Ross的哈德逊湾公司的代理人。还有北方人称其为“galoot”和“scabby-nosed wavey”。关于这种雁是属于Chen“白”雁类还是属于传统的Anser“灰”雁类还存在争议。它们的羽毛以白色为主,黑色翅尖,这令人想起雪雁,但比雪雁的体型要小40%。

不论它们属于哪个种类,这种鸟都在加拿大北部和北极中部进行繁殖,然后到远至美国南部、加州中部越冬,有时也去墨西哥北部越冬。在欧洲西部,这些鸟大部分在野生的鸟群里,但是这些逃离的或野生的鸟经常会遇到其它种类的野生雁(如加拿大雁、灰雁、黑雁)。


Copyright© 2013 by O’Reilly Media, Inc.

Simplified Chinese Edition, jointly published by O’Reilly Media, Inc. and Posts & Telecom Press, 2016. Authorized translation of the English edition, 2013 O’Reilly Media, Inc., the owner of all rights to publish and sell the same.

All rights reserved including the rights of reproduction in whole or in part in any form.

本书中文简体版由O’Reilly Media, Inc. 授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式复制或抄袭。

版权所有,侵权必究。


随着数据科学的热门,数据的优化、整理以及如何处理不良数据成为人们关注的重点。本书通过处理不良数据,进行数据清理的案例,向读者展示了处理数据的方法。

本书共有19章,向读者展示了使用和清理不良数据背后的理论和实践。第1部分是Grubby的动手实践指南,它向读者介绍了驾驭、提取数据的方法,如何处理文本数据中的数据以及Web开发中碰到的数据问题。第2部分是让人充满意外的数据,它向读者介绍了数据也会“撒谎”。第3部分是方法,它向读者介绍了处理不良数据的一些方法。第4部分是数据存储和基础设施,它向读者介绍了如何存储数据。第5部分是数据的商业化,它向读者介绍了如何避免数据处理的一些误差。第6部分是数据策略,它向读者介绍了如何追踪数据、评估数据质量以及构建数据质量相关平台等。

本书适合数据科学家、数据处理和整理相关开发人员阅读,也适合想要进入数据处理领域的读者阅读。


提示

 这个图标代表小窍门、建议或一般注解。

警告

 这个图标代表警示或警告。

本书是帮助你完成工作的。一般说来,你可以在没有我们许可的情况下,在程序和文件里使用本书中的代码,除非你在重复创建代码中极为重要的一部分。比如说,写一段程序要用好几段本书中的代码,不需要经过许可。而销售或发布来自O’Reilly书籍中配套的CD-ROM是需要经过许可的。通过引用本书内容和代码示例回答问题不需经过许可。但将来自本书的大量代码示例合并到你的产品文档时,必须经过许可。

如果能够标明引用的出处,我们将非常感激,但不做硬性要求。一个出处通常应包含题目、作者、出版社和国际标准图书编号(ISBN, International Standard Book Number)。例如:“Bad Data Handbook, Q. Ethan McCallum (Q’Reilly). Copyright 2013 Q. McCallum, 978-1-449-32188-8.”

如果你认为代码示例的使用已超出正常使用的范围或者超出了上面的许可范围,请使用permissions@oreilly.com随时联系我们。

  Safari 图书在线(www.safaribooksonline.com)是一种按需数字化图书馆。它提供的专业内容都来自科技和商业领域的世界顶级作者。既有书籍也有视频形式。

技术专业人员、软件开发人员、网页设计师以及商业和创新型人才将Safari 图书在线作为他们研究、处理问题、学习和认证培训的首选。

Safari图书在线为各种组织、政府机构和个人提供一系列的产品组合和计价程序。订阅者可以在完全可搜索的数据库中访问成千上万的书籍、培训视频以及出版前的手稿。这些数据库来自诸如O’Reilly Media、Prentice Hall Professional、Addison-Wesley Professional、Microsoft Press、Sams、Que、Peachpit Press、Focal Press、Cisco Press、FT Press、Apress、Manning、New Riders、McGraw-Hill、Jones & Bartlett、Course Technology等的很多其他来源。如想了解更多关于Safari图书在线的内容,请在线访问。

请将您对此书的评论及问题邮寄到出版社:

美国:

O’Reilly Media,Inc.

1005 Gravenstein Highway North

Sebastopol,CA 95472

中国:

北京市西城区西直门南大街2号成铭大厦C座807室(100035)

奥莱利技术咨询(北京)有限公司

本书有用来提供勘误表和其他相关信息的网页,网址为http://oreil.ly/bad_data_handbook

如有技术问题或对本书进行评论,请发至电子邮箱 bookquestions@oreilly.com。

如想了解关于本书更多的信息、课程、会议和新闻,请访问网站 http://www.oreilly.com

我们在Facebook上的网址:http://facebook.com/oreilly

我们在Twitter上的网址:http://twitter.com/oreillymedia

我们在YouTube上的网址:http://www.youtube.com/oreillymedia


出版商经常将致谢部分放在一个小角落里,真是很奇怪。这使读者很容易轻视成书的过程。如果你自己没有写过书或者参与出版,在你知道如何将思路转变成完整的图书时,会感到十分惊讶!

恕我直言,一本书是一件重要的事。要出版一本书意味着将要在一段时间里,有时按月计算有时甚至按年来计算,集中协调很多人。在这里,我希望清楚地阐明我对为此书的成功做过贡献的人们的感谢之情。

Mike Loukides:这一切都始于与Mike的一次随意的闲谈。我们的聊天发展成了头脑风暴,形成了一种理念,并最终成就了这本书。(我们要感谢这些意外的碰撞。我想知道如果我和Mike在不同的日期、不同的时间谈话,我们是否会有一本完全不同的书了呢?)

Meghan Blanchette:作为本书的编辑,Meghan使一切事情都秩序井然,保持正常工作。她不知疲倦地为我们提供了源源不断的好主意和反馈信息。一想到《数据整理实践指南》里只有一个主题是在她的监督之下完成的,就给人无比深刻的印象。我期待着下个项目能和她再次合作,不管是什么项目或在什么时候。

编著者和那些帮助我找到他们的人:我同其他18位作者共同完成了这本书,他们18位编者的部分涵盖了丰富的主题内容和故事。对于他们所付出的时间、努力和对此的适应,特别是他们对待我的反馈时的态度要表示深深的感谢。同时,我也要感谢帮助我联系可能参与的作者的每个人,没有他们,这本书不会有这么长,涵盖的范围没有这么广。

整个O’Reilly 团队:很高兴在写书的时候有O’Reilly团队的支持。整个过程是天衣无缝的:事情就这么成功了,这说明我得开始专注于写作了。感谢大家!


我们都口口声声说喜欢数据,实际上并非真的喜欢。

我们喜欢的只是洞察数据,这和喜欢数据本身并不一样。

实际上,很多人和我一样,甚至可以说并不关心数据本身。

什么是噪音数据(Bad Data)呢?很难给它下个准确的定义。有些人认为它纯粹属于经验上的、技术方面的问题:缺失值、记录格式不对或者是蹩脚的文件格式。当然,这些都属于噪音数据,但是实际上噪音数据涵盖的范围要比这广得多。噪音数据还包含那些浪费你的时间、导致你不得不在公司加班以及那些让你崩溃欲哭无泪的数据。那些你无法访问的、曾经拥有又丢失的以及发生了变更的数据,可能都属于噪音数据。

简而言之,噪音数据是那些“给你惹麻烦的数据”。有很多种情况都会产生噪音数据,比如蹩脚的存储、糟糕的说明,甚至是让人误解的策略。如果你从事数据科学这方面时间足够长,必定会遇到很多不同的噪音数据。

因此,我们想要编一本《数据整理实践指南》,一本关于“烦人的数据”大典。在本书中,19位来自不同领域的数据专家和我们分享关于噪音数据的故事,以及他们是如何从中走出来的痛苦经历。

下面是他们的故事。

Grubby的动手实践指南

通常不能假设一个新的数据集是干净的并且已经可以分析了。在第2章“是我的问题还是数据的问题”探讨了尝试驾驭数据的一些技术。

在电子表格中还有很多数据难以使用,电子表格格式过于纷繁复杂,对数据分析很不方便。在第3章“数据是给人看的不是给机器看的”中,Paul Murrel展示了一些提取数据的方法。

如果你和文本数据打交道,迟早会因为文字编码而“屡受重创”。在第4章“纯文本中潜在的噪音数据”阐述了存在哪些问题以及如何解决。

总而言之,在第5章“重组Web数据”帮你分析了在Web开发中会碰到的种种“坑”。

数据——让人充满意外

人们在网上评论时不会说真话,Jacob Perkins发现人们的撒谎方式很奇怪。在第6章“检测撒谎者以及相互矛盾网上评论的困惑”中揭示了Jacob的自然语言处理时如何揭露这股新的“撒谎力量”。

即使数据中的一切都会出错,我们还可以依赖唯一标志符吗?在第9章“当数据和现实不匹配”中,Spencer Burns分享了其在金融市场的经历,解释了为什么唯一标识符也不靠谱。

方法

目前工业界依然在努力准确定义“数据科学家”,但我们都知道写代码是其中的一部分。第8章“血、汗和尿”从软件开发者角度给出了一些充满智慧的建议。

第7章,Philipp K. Janert在“请噪音数据站出来”中分享了是否有真正的噪音数据。

你的数据可能有问题,而你却还蒙在鼓里。正如Jonathan A. Schwabish在第10章“偏差和误差的来源”中所述,收集数据的方法决定了数据会带给你什么样的麻烦。

在第11章“不要把完美和正确对立起来:噪音数据真是噪音吗”中,Brett J. Goldstein的一些回顾阐释了噪音数据如何给传统的统计训练带来实际的挑战。

数据存储和基础设施

如何存储数据对你如何分析数据影响至关重大。在第13章“卧库表,隐网络”中,Bobby Norton解释了如何查看关系数据库中的图形数据结构。

云计算的可扩展性和弹性使得它成为大规模数据分析的理想选择,在第14章“云计算神话”中,Steve Francia详细解释了其中一些概念和理念,以便你快速入门。

我们探讨关系数据库以及NoSQL、Mongo和Couch、某两个基于Hadoop的存储之间的区别。在第12章“数据库攻击:什么时候使用文件?”提供了另一种存储选择的探讨。

数据的商业化

有时聘请一名全职的数据科学家并不合适,或者需要一项你所不知道的技能。在第16章“如何雇佣机器学习专家”,Pete Warden阐述了如何把机器学习工作外包出去。

企业的官僚制度可能会成为你数据分析的障碍,使得你几乎无法分析数据。在第15章“数据科学的阴暗面”描述了应该避免的一些最差的方式。

数据策略

显然,你知道自己使用的方法,但是你真的理解这些数据图是怎么生成的吗?在第17章“数据的可追踪性”是对数据处理流程的思考。

当数据没有正确处理时会变得格外糟糕:想要的东西不存在,想要删掉的却还在那里。在第18章“社交媒体:是可以抹去的印记吗”中,Jud Valeski探讨了社交媒体的未来,并分享对不远的未来的一些思考。

在本书的最后,第19章“揭秘数据质量分析:了解数据什么时候足够优质”。第19章是第2章内容的补充,我们阐述了如何评估数据质量,以及如何构建数据质量相关平台。


Kevin Fink

假设给你一份未知来源的数据集,如何确定数据是否有用呢?

这种情况并不少见,给了你一份数据集,却无法提供关于数据来源、如何收集、字段含义等方面的诸多信息。事实上,收到这样的数据可能再正常不过了。在很多情况下,收到的数据可能经过了很多人的处理和加工,和收集的原始数据已经差别甚大,确实也没有人知道这些数据是什么含义了。在本章中,我将一步步引导你如何理解数据、验证数据并最终把数据集转换成可用的信息。特别地,我将探讨洞察数据的特殊方式,并给出一些示例,说明自己从中学到了什么。

首先,我先简单提一下自己的背景。在过去25年里,我一直在处理很多不同的数据。我编写代码,处理加速计和水听器信号,分析水坝和其他大型架构(哈维姆德学院工程专业的本科生);分析不同种类的蝙蝠叫声(华盛顿大学电子工程专业的研究生);构建对图像声纳数据进行可视化的系统(应用物理实验室的研究助理);利用大量的Web内容构建内容过滤系统(N2H2公司的联合创始人和CTO);为门户软件设计内网搜索系统(DataChannel),并且把多个目录辅助数据集结合到可搜索的网站中(WhitePages.com的CTO)。在过去5年的时间里,我在Demand Media公司花了大部分时间使用很多不同的数据源构建广告和内容推荐系统的优化系统,对大规模数据驱动的搜索引擎优化(SEO)和搜索引擎营销(SEM)有广泛涉猎。

大多数示例涉及我在广告优化、内容推荐、SEO和SEM方面相关的工作。和其他大多数领域一样,这些领域也有自己的术语,表2-1列出了一些相关术语的定义。

表2-1 术语定义

术语

定  义

PPC

“按点击付费”(Pay Per Click),这是一种互联网广告模式,基于广告的点击数来支付,从而驱动Web站点的流量。在数据世界中,它往往对应于“每次点击价格”(Price Per Click),即每次点击支付的金额

RPM

每千次展示收入(Revenue Per 1,000 Impressions),通常用于广告展示

CTR

点击转化率(Click Through Rate),即点击数/展现数,通常作为衡量广告或内容推荐是否成功的指标

XML

可扩展标记语言(Extensible Markup Language),基于文本的标记语言,设计上致力于人机都可读

JSON

JavaScript对象标识(JavaScript Object Notation)—轻量级的、基于文本的开放标准,是人类可读的数据交换格式。JavaScript内置支持它,因此通常适用于JavaScript Widget和后台服务器交互

CSV

每个字段用逗号分隔(Comma Separated Value),文本文件每行包含一条记录,字段之间用逗号分隔

当收到数据集时,第一个障碍往往是无法访问。不过,暂时忽略这些问题,假设可以读取该数据集所在的物理媒介,对它进行解压或通过其他方式抽取文件,把数据转换成某种可读形式。一旦完成这些,下一步是要理解数据结构。传输数据时,往往会使用很多不同的数据结构。庆幸的是,有很多数据结构实际使用并不频繁。我将重点讨论最常见(也是最容易处理)的几种格式:表格(Columnar)、XML、JSON和Excel。

最常见的格式是表格(也就是说,数据是按行和列存储的)。列可以由制表符(tab键)、逗号或其他字符分隔,这些列可以是固定长度。行一般由换行符和/或回车符分隔。对于某些较小的数据集,数据可能是某种专门格式,比如各种Excel版本所使用的格式,但是很容易通过适当软件将其转换成更简单的文本格式。我经常收到Excel电子表格,几乎总是马上把它们导出成tab分隔的文本文件中。

CSV格式的文件是最常见的。在这些文件中,每条记录一行,各个字段用逗号分隔。有些值或所有值(特别是字段内的逗号)可能会通过引号或其他字符引起来,以和分隔符逗号区别开。最常见的情况是,如果使用逗号作为分隔符,包含逗号的字符串就通过双引号引起来。有时,会把所有的字符串都引起来,有时只把那些包含分隔符的字符串引起来。Excel会自动加载CSV文件,大多数编程语言也都提供库处理这类文件。

注意

 在下面的例子中,会使用一些基本的UNIX命令:尤其是echo和cat命令。这只是为了简单说明示例数据。以$开头的行,表示在UNIX Shell终端下运行的命令。举个例子,由于制表符(\t)和空格在页面上看起来很相似,我会通过下面这种方式生成数据:

$ echo -e 'Field 1\tField 2\nRow 2\n'

该示例数据包含两行,第一行有两个字段,分隔符是\t。 我还会详细探讨绝大多数的管道,如下所示。

$ cat filename |

虽然在实践中,你可能是把文件名作为第一个命令的参数。也就是说,命令

$ cat filename | sed -e 's/cat/dog/'

和命令在功能上完全等价(而且后者更高效)。

$ sed -e 's/cat/dog/' filename

下面这行Perl代码从CSV文件中抽取第三个和第一个字段。

$ echo -e 'Column 1,"Column 2, protected","Column 3"'
Column 1,"Column 2, protected","Column 3"

$ echo -e 'Column 1,"Column 2, protected","Column 3"' | \
     perl -MText::CSV -ne '
     $csv = Text::CSV->new();
     $csv->parse($_); print join("\t",($csv->fields())[2,0]);'
Column 3     Column 1

下面这段Perl代码可读性更好。

use Text::CSV;

while(<>) {
 my $csv = Text::CSV->new();
 $csv->parse($_);
 my @fields = $csv->fields();
 print join("\t",@fields[2,0]),"\n";
}

大多数数据并不包含\t,因此它是一个很安全、很受欢迎的分隔符。以\t 分隔的文件通常不允许在数据中包含\t,因此不要用引号或转义字符,使得\t 分隔的文件比CSV文件更容易处理。使用UNIX命令行工具可以很容易地处理以\t分隔的文件,比如perl、awk、cut、join、comm等。很多简单的可视化工具(如Excel)可以半自动化方式导入\t分隔的文件,每个字段作为一列,很方便人工处理。

以下几个简单的示例,输出以\t 分隔的字符串的第一个字段和第三个字段。cut命令只会按出现的顺序输出数据,但其他工具可以重新组织数据。以下示例分别使用cutawkperl输出第一个和第三个字段。

  $ echo -e 'Column 1\tColumn 2\tColumn 3\n'
  Column 1 Column 2 Column 3
cut:

$ echo -e 'Column 1\tColumn 2\tColumn 3\n' | \
     cut -f1,3
  Column 1   Column 3
awk:

  $ echo -e 'Column 1\tColumn 2\tColumn 3\n' | \
       awk -F"\t" -v OFS="\t" '{ print $3,$1 }'
  Column 3   Column 1
perl:

  $ echo -e 'Column 1\tColumn 2\tColumn 3\n' | \
       perl -a -F"\t" -n -e '$OFS="\t"; print @F[2,0],"\n"'
  Column 3   Column 1

在某些场合,XML是常见的数据格式。虽然XML并没有真正非常流行,但一些数据库(比如BaseX)以XML作为内部存储格式,其他很多数据库支持直接以XML格式导出数据。对于CSV,很多语言提供库,可以把它解析成本地数据格式,对数据进行分析和转换。

以下是一行Perl代码,它从XML中抽取字段。

$ echo -e '<config>\n\t<key name="key1" value="value 1">
\n\t<description>Description 1</description>
\n\t</key>\n</config>'
<config>
   <key name="key1" value="value 1">
   <description>Description 1</description>
   </key>
</config>

$ echo '<config><key name="key1" value="value 1">
     <description>Description 1</description>
     </key></config>' | \
     perl -MXML::Simple -e 'my $ref = XMLin(<>);
     print $ref->{"key"}->{"description"}'
Description 1

下面这段Perl代码可读性更好。

use XML::Simple;

my $ref = XMLin(join('',<>));
print $ref->{"key"}->{"description"}';

虽然JSON主要是用于Web API,以在服务器和JavaScript客户端之间传输信息,但它有时也用于传输大量的数据。有很多数据库把JSON作为内部数据格式(如CouchDB)或使用了序列化的JSON格式(如MongoDB),因此从这些系统中导出的数据通常是JSON格式。

下面一行Perl代码从JSON文件中抽取一个节点信息。

$ echo '{"config": {"key1":"value 1","description":"Description 1"}}'
{"config": {"key1":"value 1","description":"Description 1"}}

$ echo '{"config": {"key1":"value 1","description":"Description 1"}}' | \
     perl -MJSON::XS -e 'my $json = decode_json(<>);
     print $json->{"config"}->{"description"}'
Description 1

下面这段Perl代码可读性更好。

use JSON::XS;

my $json = decode_json(join('',<>));
print $json->{"config"}->{"description"}';

一旦数据格式已经可读且可操作,下一步是要弄清楚数据的含义。在某些情况(遗憾的是,这种情况非常罕见)下,提供了关于数据的所有信息。通过需要对数据做一些探索。有些数据第一行可能会提供一些信息,有些数据可能每个字段都有一个键值,这些取决于数据的格式。幸运的话,这些数据可能稍有些冗余信息,你可以理解,或者至少你认识的一些人可以理解。关于这方面,我常常求助于一位俄罗斯藉QA。这是工作场所多样化的另一个优势。

一个常见的错误是误解字段的单位或含义。货币字段的单位可以是美元、美分甚至是0.000001元(如Google的AdSense API计量单位)。收入字段可能是毛收入,也可能是净收入。距离可以使英里、千米、米等。查看字段的定义和实际值可以避免因误解而得到错误的结论。

你还可以查看一些其他字段,确保它们在上下文中是有意义的。举个例子,字段PageView往往是个整数,而不会是小数或字符串。货币字段(价格、成本、PPC、RPM)往往是小数,通常小数点后有两位到四位。UserAgent字段包含的字符串应该看起来和常见的用户代理类似。IP地址应该是整数或以点号分隔的字符串。

数据集中的常见问题是缺失值或空值,这有时候不会出什么问题,有时会导致记录不准确。这些值可以通过很多方式来表示。我经常看到它们被表示为空(比如,若使用\t 分隔,则出现连续\t\t这种形式)、空串(单引号或双引号)、字符串NULL或未定义或N/A或NaN,还有以数值0表示。不管在你的数据集中是如何表示,要知道用什么表示缺失值或空值,并确定数据中确实是按此方式表示的,这样可以避免后期使用数据带来很多麻烦。

我经常把这些常规检查延伸到字段的真实校验。绝大多数的校验方式可以通过正则表达式实现。由于历史原因(我用了20多年),我通常用Perl写校验脚本,但是还有很多更好的选项。几乎每一门语言都实现了正则表达式。

对于枚举字段,所有值是否都落在正确的区间?举个例子,“month”字段只应该包含月份信息(从1~12的整数,字符串值只能是Jan、Feb…或者January、February…)。

my $valid_month = map { $_ => 1 } (0..12,
qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
January February March April May June July August
September October November December));
print "Invalid!" unless($valid_month{$month_to_check});

对于数值字段,所有值都是数值吗?下面这段代码检查字段是否指包含数字。

$ cat sample.txt
one     two     3
one     two     three
1       2       3
1       2        three

$ cat sample.txt | \
    perl -ape 'warn if $F[2] !~ /^\d+$/'
one     two      3
Warning: something's wrong at -e line 1, <> line 2.
one     two     three
1       2       3
Warning: something's wrong at -e line 1, <> line 4.
1       2       three

对于固定格式的字段,是否所有值都和正则表达式匹配?举个例子,IP地址通常是以点分隔的(比如127.0.0.1),可以通过这样的正则表达式匹配^\d+.\d+.\d+.\d+$(或者更严格的匹配)。

$ cat sample.txt
fink.com   127.0.0.1
bogus.com   1.2.3

$ cat sample.txt | \
    perl -ape 'warn "Invalid IP!" if $F[1] !~ /^\d+\.\d+\.\d+\.\d+$/'
fink.com   127.0.0.1
Invalid IP! at -e line 1, <> line 2.
bogus.com   1.2.3

对于数值字段,我想做些简单的统计检查。最小值在字段的上下文中是否有含义?计数器的最小值(点击数、网页浏览数PV等)的值应该是大于等于0的值,很多其他字段也是如此(比如PPC、CTR、CPM)。同样,最大值是否有意义?极少数字段在逻辑上值可以是10亿,在很多情况下,如果实际值远小于该值则没有意义。

根据实际的定义,类似于CTR的比率值应该小于1。当然,不管定义是什么,其值经常会超过1(毕竟本书探讨的是噪音数据),但是其值也不应该比1大太多。如果你看到CTR值是几百或几千,很可能有问题。

财务相关的字段值应该有一个合理的上限值。至少对于我所处理的数据,PPC或CPC字段值在数百美元可能还是有意义的,但如果是几千或更大值,就肯定不合理了。你可以接受的范围很可能不同,但不管数据值是多少,都应该检查数据,确保是合理的。

你还可以查看一个字段的平均值(如类似取模或中位数的简单统计),确保它看起来是合理的。举个例子,如果一个装饰物的售价在10美元左右,而在“装饰物”字段是999美元,那很可能是哪里出了差错。它也可以帮助校验数值的单位是否正确。如果该字段值的单位是美分,而不是美元,那值999就很合理了。

关于这些校验,幸运的是可以很容易通过自动化实现,这对于频繁更新的数据集,就非常便利。花上数个小时的时间查看新的数据集其实挺有意思,因为通过这个过程可以对数据有一些初步理解,但是多次做重复的事情就很让人烦了。如果你有一个小时的时间,可能宁可作为迪士尼的丛林巡航导游(“这真是太有趣了,再来一次吧!再来一次吧……”)。

我觉得特别有帮助的另一种技术是根据字段值创建直方图。这对于大规模数据集尤其有用,而前面提到的简单的统计方式只能看到数据的表面。直方图是每个值在数据集中出现次数的统计,因此直方图还适用于非数值字段,而统计方法就不适用。

举个例子,假设有个包含推荐关键字的数据集,这些关键字是使用Google、Bing或其他搜索引擎进行搜索的词,使用户能够浏览网站的网页。一个大型网站每天可以通过搜索引擎带来数百万的PV,其中搜索关键字可能有数百万,在一段时间后可能会有数十亿的唯一关键字。对于这些关键字,由于它们不是数值类型,而是字符串类型,所以不能使用传统的统计方法(如最小值、最大值或平均值)。

幸运的是,可以使用直方图对大规模的非数值数据集进行汇总。一阶直方图计算每个关键字的来源数。但是,如果数据集中有数十亿的关键字,直方图就会非常大,可能没什么用。可以执行一次聚合操作,使用每个关键字给网站带来的来源数作为值,结果就会小得多,而且汇总信息更有用。该直方图会显示每个关键字的来源数。由于对于来源数有的差别很小,可以通过分箱操作进一步汇总(比如来源数为1~10、11~20、21~29等)。当然,具体的分箱数取决于数据。

对于很多简单的数据集,一个命令管道就可以生成一个有用的直方图。比如,假设有个简单的文本文件(sample.txt),包含一些枚举字段(比如URLs、keywords、names和months)。为了快速生成数据直方图,可以运行如下命令。

$ cat sample.txt | sort | uniq –c

该命令如何工作呢?cat命令会读取文件,把内容发送给STDOUT。管道符号(|)会捕获到这些数据,把它发送给管道的下一个命令(因此使用管道符非常方便!),即sort命令,它实现期望的操作:对数据进行排序。在这个例子中,实际上并不关心数据是否有序,只是想把相同的行组合在一起,因为下一个命令uniq依赖于组合的结果。uniq命令(命名非常贴切,虽然不知道如何工作)每次只输出一条唯一的记录,如果指定-c选项,会在每行结果前面输出该行出现的次数。因此,该命令会最终显示文件中每行出现的次数:这就是直方图!

请看示例2-1。

示例2-1 生成字段Months的直方图

$ cat sample.txt
January
January
February
October
January
March
September
September
February

$ cat sample.txt | sort
February
February
January
January
January
March
October
September
September

$ cat sample.txt | sort | uniq -c
    2 February
    3 January
    1 March
    1 October
    2 September

对于稍微复杂的数据集,比如\t分隔的文件,只需要增加一个过滤器,提取想要的字段。提取字段的方法有多种,“最好”的方式取决于数据的特性以及筛选条件。最简单的方式可能是通过cut命令实现,尤其是对于\t分隔的数据,只需要通过命令行参数就可以指定要哪个字段或哪些字段。举个例子,假设有个文件,第一个字段是names,第二个字段是ages。如果想计算每个年龄有多少人,可以执行如下代码。

$ cat sample2.txt
Joe    14
Marci   17
Jim    16
Bob    17
Liz    15
Sam    14

$ cat sample2.txt | cut -f2 | sort | uniq -c

      2 14
      1 15
      1 16
      2 17

第一个字段表示计数,第二个字段表示年龄。从结果可以看出,14岁有2个,15岁有1个,16岁有1个,17岁有2个。

筛选列的另一种常用方法是使用AWK(AWK的功能要复杂得多),其语法稍微有些复杂。

$ cat sample2.txt | \
     awk '{print $2}' | sort | uniq -c
    2 14
    1 15
    1 16
    2 17

和所有文本处理一样,也可以使用Perl,下面是一些例子。

$ cat sample2.txt | \
     perl -ane 'print $F[1],"\n"' | sort | uniq -c
    2 14
    1 15
    1 16
    2 17
$ cat sample2.txt | \
     perl -ne 'chomp; @F = split(/\t/,$_); print $F[1],"\n"' | sort | uniq -c
    2 14
    1 15
    1 16
    2 17

对于真实的数据集(即包含大量数据点的数据集),直方图可以直观地展示数据的近似分布情况,可以便于评估。举个例子,你可能期望是个较平滑的函数,可能是直线或高斯分布(看起来像个钟形曲线),甚至可以呈指数形式衰减(长尾分布),但是应该特别重视图中的不连续点:它可能表示数据有问题。

关于直方图,其中一个有用的例子是对于两个约750万关键字的数据集,预估其竞价排名值。数据是由第三方收集的,关于如何收集,我了解甚少。数据文件是逗号分隔的文本文件,包含关键字和相应的竞价排名值。示例2-2为竞价排名数据文件。

示例2-2 竞价排名数据文件

waco tourism, $0.99
calibre cpa, $1.99,,,,,
c# courses,$2.99 ,,,,,
cad computer aided dispatch, $1.49 ,,,,,
cadre et album photo, $1.39 ,,,,,
cabana beach apartments san marcos, $1.09,,,
"chemistry books, a level", $0.99
cake decorating classes in san antonio, $1.59 ,,,,,
k & company, $0.50
p&o mini cruises, $0.99
c# data grid,$1.79 ,,,,,
advanced medical imaging denver, $9.99 ,,,,,
canadian commercial lending, $4.99 ,,,,,
cabin vacation packages, $1.89 ,,,,,
c5 envelope printing, $1.69 ,,,,,
mesothelioma applied research, $32.79 ,,,,,
ca antivirus support, $1.29 ,,,,,
"trap, toilet", $0.99
c fold towels, $1.19 ,,,,,
cabin rentals wa, $0.99

由于该数据集是CSV格式(引号括起来的字段内容包含逗号),前面给出的一些技巧这里不适用。一种快速解决的方式是把那些包含逗号的字段删掉,然后再使用前面给出的管道方式。下面通过忽略包含双引号字符的记录来实现。首先,检查一些会忽略多少条数据。

$ cat data*.txt | grep -c '"'
5505
$ cat data*.txt | wc -l
7533789

我们只是忽略了0.07%的记录,这不会影响统计结果。因此,通过管道实现如下。

$ cat ppc_data_sample.txt | grep -v '"' | cut -d, -f2 | sort | uniq -c | sort -k2
   1 $0.50
   3 $0.99
   1 $1.09
   1 $1.19
   1 $1.29
   1 $1.39
   1 $1.49
   1 $1.59
   1 $1.69
   1 $1.79
   1 $1.89
   1 $1.99
   1 $2.99
   1 $32.79
   1 $4.99
   1 $9.99

这看起来可能有些复杂,下面一步步对它进行探讨。首先,通过cat命令创建数据流。其次,通过grep命令匹配不包含引号的记录,−v选项表示删除包含双引号的记录,CSV格式会使用引号把字段内容包含分隔符(这里即逗号)的字段括起来。然后使用cut命令抽取出第二个字段(其中-d后面的逗号即表示字段分隔符)。再次,对结果记录进行排序,这样重复记录就会相邻。然后,使用uniq命令,其中-c选项会对相同行的出现次数进行计数。最后,根据第二个字段对结果输出进行排序(即竞价排名PPC)。

在实际数据中,其输出结果很凌乱,因为PPC值差别很大(有些在逗号和美元符$之间有空格,有些没有)。如果希望输出结果更干净,可以实现一段Perl脚本来清洗数据并对它们进行聚合,这往往也是更灵活的解决方案,代码如下。

use strict;
use warnings;

use Text::CSV_XS;

my $csv = Text::CSV_XS->new({binary=>1});
my %count;

while(<>) {
  chomp;
  s/\cM//;
  $csv->parse($_) || next;
  my $ppc = ($csv->fields())[1];
  $ppc =~ s/^[ \$]+//;
  $count{$ppc}++;
}

foreach my $ppc (sort {$a <=> $b} keys %count) {
  print "$ppc\t$count{$ppc}\n";
}

对于前面给出的样本数据集,这段代码会输出类似的结果,但多出两条之前被丢弃的$0.99记录,此外PPC值以实际值表示,而不是不同的字符串形式。

0.50     1
0.99     5
1.09     1
1.19     1
1.29     1
1.39     1
1.49     1
1.59     1
1.69     1
1.79     1
1.89     1
1.99     1
2.99     1
4.99     1
9.99     1
32.79    1

对于真实的数据集,输出结果如下。

0.05     1071347
0.06     2993
0.07     3359
0.08     3876
0.09     4803
0.10     443838
0.11     28565
0.12     32335
0.13     36113
0.14     42957
0.15     50026
...
23.97     1
24.64     1
24.82     1
25.11     1
25.93     1
26.07     1
26.51     1
27.52     1
32.79     1

值得一提的是,如果数据已经在SQL数据库,生成直方图就非常容易。举个例子,假定有个表名为MyTable,包含前面提到的数据,数据有两个字段,Term和PPC,可以通过如下SQL语句对PPC进行聚合。

SELECT PPC, COUNT(1) AS Terms
FROM MyTable
GROUP BY PPC
ORDER BY PPC ASC

不管如何生成数据,通过可视化是展示有趣的特征的最佳方式,如图2-1所示。

图2-1 PPC直方图概览

对于较小的PPC值,存在非常多的关键词,随着PPC值增长,数据量呈指数级衰减(注意,纵轴是以对数方式显示的)。尽管如此,可以看到在图的中间有个很大的“断面”!在$15.00和$15.88之间几乎没有PPC值,而在$15.89到$18.00之间的值比预期的多(基于图中的曲线可以看出),这让我猜想可能是生成数据的方法把$15.00和$15.88之间的数据值提升了大约$0.89。仔细查看数据集之后,发现两点:一是确实是因为生成测试PPC值的算法导致的,二是数据生成方不知道其算法存在这个问题!通过该数据分析,我们知道要避免把PPC值在$15.89到$18.00之间的数据映射到任何一个关键字,数据生成方也知道了要修正其算法。

关于该数据集,另一个有趣的特征是其最小值是$0.05。这可能是因为市场最低竞价值是$0.05,也可能是算法从$0.05开始预估竞价值,或者数据之前做过处理,删除了低于$0.05的竞价值,或者是由于其他原因。在这个例子中,最后发现是由于第一个原因,收集数据的市场的最低定价是5美分。实际上,如果直方图中PPC值较低的曲线放大显示(如图2-2所示),会发现另一个特征。虽然PPC值为$0.05的关键词超过100万条,却没有一条(更准确地说是少于3 000条)PPC值是$0.06到$0.09。而PPC值为$0.10的记录却不少(接近500 000),而值在$0.11以上的却很少(少于30 000)。因此,看起来市场上有两套不同的竞价方案,其依赖因素不确定。

图2-2 PPC值较小的直方图

使用直方图的另一个例子是查看搜索来源。当用户在Google搜索结果页中点击Web站点上的链接时,Google(有时)会把查询关键词和列表的“排名”(页面的第一条结果值为1,第二条结果值为2等)一起传给网站。这个信息对网站非常有价值,因为它表示对于不同关键词,该网站的内容在Google搜索结果中的排名。然而,它也可能是噪音数据。Google经常通过改变页面上的排名结果测试其算法和用户行为。结果排序还和用户的信息和行为有关,比如国家、过去的搜索和点击行为,甚至是好友推荐。因此,这种排序数据表示的是关键词/URL组合的多种排序中的一种,这通常会使人难于理解。有些人还认为Google故意把该数据弄得不可用。

为了查看该排名数据是否有用,我查看了一个大型网站的来源数据,它从Google的来源流量很大(每天有数百万条)。和常见的标准Web服务器日志文件的原始数据不同,这些数据已经保存在数据仓库中,已经从来源页的URL中抽取相应字段,包括日期、URL、来源关键词以及每次浏览的排序。我创建了一个直方图,显示每个Rank的PV数(如图2-3所示)。

图2-3 按Rank排序的搜索来源

从图2-3的直方图中可知,数据不是随机的,也不是很混乱。数据展现了一个非常清晰的模式,和期望的用户行为相关。举个例子,在排名10和排名11之间有一段很大的不连续性,同样,排名20和排名21之间也是,依此类推。这和Google的搜索结果默认每个页面展示10条结果对应。

在结果页中(除了首页,后面会讨论),可以看出更多用户对结果的点击,第一条大于第二条,第二条大于第三条……有趣的是,更多用户点击页面中的最后几条结果,而不是中间结果。通过其他方式也发现了这个行为,因此通过查看该细粒度的直方图,可以很大程度上证明数据的有效性。

那么,为什么这个模式对于第一个页面不适用呢?注意该数据并不表示CTR(点击率),它显示的是总浏览量。对于很多关键词,该网站的网页排在结果页中第一条的并不多,但是排在第二和第三的却很多。因此,虽然第一条结果的CTR是最高的(从其他页面中看出),但是在第一个页面中看不出来。在第三、第四以及后续的页面中,可以看出浏览量逐渐趋缓,因此PV值看起来和CTR相当。

到目前为止,我们已经探讨对字段值相同记录的计数构建直方图。正如我们所看到的,这在很多情况下很有用,但是对很多案例而言,这种方式粒度太细,导致无法查看有用的模式。举个例子,比如对于推荐模式的分析,可能是对用户的电影推荐,对某个产品推荐另一个产品等。在这个例子中,我将探讨文章推荐。假设有这样一个网站,内容丰富,包含数百万篇文章,涉及领域很广泛。为了帮助读者从当前文章导航到下一篇他们可能感兴趣的文章,该网站提供了一个简短的推荐列表,该列表是基于人工编辑、语义相似和/或过去的访问流量模式。

假定数据集包含推荐组合:每条记录表示一个推荐,第一个字段表示源文章的URL,第二个字段表示目标文章的URL。

示例2-3 推荐文件

http://example.com/fry_an_egg.html http://example.com/boil_an_egg.html
http://example.com/fry_an_egg.html http://example.com/fry_bacon.html
http://example.com/boil_an_egg.html http://example.com/fry_an_egg.html
http://example.com/boil_an_egg.html  http://example.com/make_devilled_eggs.html
http://example.com/boil_an_egg.html  http://example.com/color_easter_eggs.html
http://example.com/color_easter_eggs.html  http://example.com/boil_an_egg.html
...

对于正在学习如何煮鸡蛋的读者,会显示关于如何煮鸡蛋和煎培根的文章;对于正在学习如何煮鸡蛋的读者,会显示如何煮鸡蛋,如何在鸡蛋上画鬼脸,以及如何为复活节彩蛋着色。

对于一个大型网站,文件可能会变得非常大。我曾经工作过的一个网站有约330万篇文章,每篇文章有30条推荐,最后整个网站有约1亿条推荐。由于这些推荐内容是在夜间自动化生成的,要确保系统生成合理的推荐信息很重要,而且很富有挑战。手工检查统计学上大量样本会花费大量时间,因此需要依赖统计工具。比如,这些推荐的分布情况如何?是否有些文章被推荐了数千次,而有些文章从未被推荐过?

我们可以生成柱状图,显示每篇文章被推荐了多少次。

示例2-4 生成推荐目标直方图

$ cat recommendation_file.txt | cut -f2 | sort | uniq –c

2 http://example.com/boil_an_egg.html 1 http://example.com/fry_bacon.html 1 http://example.com/fry_an_egg.html 1 http://example.com/make_devilled_eggs.html 1 http://example.com/color_easter_eggs.html

“How to Boil an Egg(如何煮鸡蛋)”这篇文章被推荐了2次,而其他4篇文章只分别被推荐1次。这听起来没什么问题,但是有330万篇文章,在直方图中就需要有330万条记录,这样的直方图就会变得没什么可用性了。更糟糕的是,由于关键字是URL,无法像数值一样对它们执行分箱操作。为了更好地了解数据,可以进一步聚合,按示例创建一张直方图。

示例2-5 生成推荐目标计数直方图

$ cat recommendation_file.txt \
| cut -f2 \
| sort \
| uniq -c \
| sort -n \
| awk '{print $1}' \
| uniq –c

4 1
1 2

从结果可知,有四篇文章被推荐了一次,一篇文章被推荐了两次。

在3 300万条推荐的数据集上使用同样的技术(即每篇文章的前10条推荐),生成如图2-4所示的直方图。对于累积分布函数,得到结果如图2-5所示。

图2-4 推荐分布

注意图2-4的直方图运用重对数图尺,而图2-5的累积分布图呈线性垂直曲线。整体而言,数据集看起来很合理,曲线平滑,没有明显的不连续性。大多数文章被推荐次数很少,约300 000篇只被推荐1次。随着被推荐数的增加,文章的数量快速减少,约一半的文章被推荐数少于7。最流行的文章大约被推荐1 800次。

可以针对不同的算法生成的推荐集运行该分析,从而帮助我们理解算法行为。举个例子,如果一个新的算法产生的分布范围更广,就可以推断有很多文章被推荐的次数和其他文章差距很大。如果分布完全不同—比如推荐次数的平均值是一个钟形分布(在这个示例中为10)—那么可以推断出文章的推荐次数分布很均匀。

图2-5 推荐累积分布

尽管直方图对于时间序列数据通常没什么意义,类似的可视化技术可能会很有用,尤其当数据可以通过其他维度聚合时。举个例子,Web服务器日志可以每分钟、每小时或每天聚合统计PV数,然后把统计结果作为时间序列。这对于查找数据丢失特别有用,如果处理不当,对于某些数据分析会带来严重的倾斜。

很多网站负责人会仔细观察他们的网站流量,监测网站问题,包括市场营销活动、搜索引擎优化等。对于很多网站,由于受到和网站本身无关的一些因素的影响,流量的变化会变得非常复杂。其中一些原因,如季节性因素,某种程度上可以预测,这样当网站流量下降时也不至过于担心。尽管如此,季节性因素可能很复杂,因为它和网站类型有关,比如季节性因素对税务咨询网站的影响和园艺网站的影响会有很大差别。此外,常识并不总是正确,而且常识几乎不会有量化的指导作用。在周日流量下降30%会有意义吗?春天开学时,流量会有多少下降?对于有大量历史流量数据的网站,可以构建模型来预测(通过显式或隐式的“关系网知识”),但是对于一个新的站点或一个已有站点,如何构建模型呢?

为了解决这个问题,我尝试使用公开可用的维基百科日志来构建一个长期、大规模的季节性模型,预测不同语言的流量。维基百科服务每天有近5亿的页面,有一半多是英语。通过自动化程序对网页按语言(站点)、时间和页面进行聚合。正如任何自动化程序一样,它有时会失败,导致某个小时或某天的统计值变低。对于季节性模型,这会带来灾难,意味着流量的下降是不真实的。

第一次统计维基百科数据时,得到的是一些没有意义的值,比如在2011年6月7日这一天,PV值为1.06E69?这种值可以很容易知道是不真实的,可以丢弃掉。修剪掉一些异常值后,时间序列图如图2-6所示。

图2-6 维基百科按日统计图

你会发现,还是有一些异常值,有低的,也有高的。此外,整体形状很模糊。放大后(如图2-7所示),会发现其中一些模糊性是由于一周中每天的统计值变化。对于大多数信息类网站,在平时会比周日多出很多流量。

图2-7 维基百科按日统计图放大

由于关注的是网站流量变化的长期趋势,我选择查看每周的平均值,这样可以不受游离点以及一周中不同日期变化的影响(如图2-8所示)。

图2-8看起来清晰多了。在过去几年,整体流量一直趋于上升,和期望的一致。图2-8中还是有一些较大的倾角和尖峰,以及一年过程中的很多变化。由于数据是每小时以文件形式保存,检测脏数据的一种方式是统计每天有多少个小时的数据。显然,每天应该有24小时的数据(可能潜在一些时间点的细微差别,这取决于维基百科如何记录日志)。

在图2-8中添加小时数后,生成结果如图2-9所示,它显示了有很多天的数据小于24小时,还有两天的数据超过24小时(达到30小时!)。2009年5月11日有30小时的数据,5月12日有27小时的数据。进一步查看会发现很可能是因为数据重复。举个例子,2009-05-01 01这个时间点有两个文件,每个文件的PV数和00以及02这两个时间点一致。这很可能是因为系统程序在从原始Web日志生成这些文件时,复制了一些数据。

图2-8 维基百科7天平均值的统计图

图2-9 维基百科7天平均值(包含小时数信息)

示例2-6 维基百科2009-11-05这天英文页面的统计计数

$ grep -P '^en\t' pagecounts-20090511-*.gz.summary
pagecounts-20090511-000000.gz.summary:en 20090511 9419692
pagecounts-20090511-010000.gz.summary:en 20090511 9454193
pagecounts-20090511-010001.gz.summary:en 20090511 8297669 <== duplicate
pagecounts-20090511-020000.gz.summary:en 20090511 9915606
pagecounts-20090511-030000.gz.summary:en 20090511 9855711
pagecounts-20090511-040000.gz.summary:en 20090511 9038523
pagecounts-20090511-050000.gz.summary:en 20090511 8200638
pagecounts-20090511-060000.gz.summary:en 20090511 7270928
pagecounts-20090511-060001.gz.summary:en 20090511 7271485 <== duplicate
pagecounts-20090511-070000.gz.summary:en 20090511 6750575
pagecounts-20090511-070001.gz.summary:en 20090511 6752474 <== duplicate
pagecounts-20090511-080000.gz.summary:en 20090511 6392987
pagecounts-20090511-090000.gz.summary:en 20090511 6581155
pagecounts-20090511-100000.gz.summary:en 20090511 6641253
pagecounts-20090511-110000.gz.summary:en 20090511 6826325
pagecounts-20090511-120000.gz.summary:en 20090511 7433542
pagecounts-20090511-130000.gz.summary:en 20090511 8560776
pagecounts-20090511-130001.gz.summary:en 20090511 8548498 <== duplicate
pagecounts-20090511-140000.gz.summary:en 20090511 9911342
pagecounts-20090511-150000.gz.summary:en 20090511 9708457
pagecounts-20090511-150001.gz.summary:en 20090511 10696488<== duplicate
pagecounts-20090511-160000.gz.summary:en 20090511 11218779
pagecounts-20090511-170000.gz.summary:en 20090511 11241469
pagecounts-20090511-180000.gz.summary:en 20090511 11743829
pagecounts-20090511-190000.gz.summary:en 20090511 11988334
pagecounts-20090511-190001.gz.summary:en 20090511 10823951<==duplicate
pagecounts-20090511-200000.gz.summary:en 20090511 12107136
pagecounts-20090511-210000.gz.summary:en 20090511 12145627
pagecounts-20090511-220000.gz.summary:en 20090511 11178888
pagecounts-20090511-230000.gz.summary:en 20090511 10131273

删除重复条目可以使结果图表变得更合理,但并不会真正解决流量的大波动问题,也无法估计丢失的数据量。值得一提的是,从2010-06-12到2010-06-15,每天都有24个小时的数据文件,但是在图中该时间段呈现最大的PV降幅。同样,最大的正向影响的游离点是2010年10月的前3周的数据,每天的流量PV数从2.4亿上升到3.75亿,而这个时期并没有多出文件。因此,这些现状说明了我们必须对这些时间段做更深入的分析,并提醒我们从该数据集得出结论时需要小心。

我们得到的数据很少会打包整齐、质量有保证。实际上,当拿到数据时,通常没什么文档,不知道它来自哪里、如何收集,或者在使用时应该注意哪些。尽管如此,一些相对简单的分析技术可以让我们充分洞察数据集。这种分析方法往往可以帮助洞察一些感兴趣的领域。至少,这些“探嗅测试”为我们展示了要探索的领域和注意点。


相关图书

算者生存:商业分析的方法与实践
算者生存:商业分析的方法与实践
数据结构与算法(Rust语言描述)
数据结构与算法(Rust语言描述)
R语言医学多元统计分析
R语言医学多元统计分析
Python数据分析(第3版)
Python数据分析(第3版)
Python数据分析入门与实战
Python数据分析入门与实战
Python贝叶斯分析(第2版)
Python贝叶斯分析(第2版)

相关文章

相关课程