精通数据科学:从线性回归到深度学习

978-7-115-47910-5
作者: 唐亘
译者:
编辑: 张爽

图书目录:

详情

本书是全面讲解了数据科学的相关知识,从数学统计学,讲到机器学习、深度学习中用到的算法及模型,借鉴经济学视角给出模型的相关解释,深入探讨模型的可用性,并结合大量的实际案例和代码帮助读者学以致用,将具体的应用场景和现有的模型相结合,从而更好地发现模型的潜在应用场景。

图书摘要

版权信息

书名:精通数据科学:从线性回归到深度学习

ISBN:978-7-115-47910-5

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

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

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

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

著    唐 亘

责任编辑 张 爽

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

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

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

读者服务热线:(010)81055410

反盗版热线:(010)81055315


本书全面讲解了数据科学的相关知识,从统计分析学到机器学习、深度学习中用到的算法及模型,借鉴经济学视角给出模型的相关解释,深入探讨模型的可用性,并结合大量的实际案例和代码帮助读者学以致用,将具体的应用场景和现有的模型相结合,从而更好地发现模型的潜在应用场景。

本书可作为数据科学家和数据工程师的学习用书,也适合对数据科学有强烈兴趣的初学者使用,同时也可作为高等院校计算机、数学及相关专业的师生用书和培训学校的教材。


我与本书作者素不相识,读完作者发来的电子书稿后,感受到了以往在读技术类书籍时从未有过的惊喜。国内已有不少介绍大数据和机器学习的教科书和参考书,但这本书与众不同,它的重点不是传统教科书式的概念导入和各种机器学习算法的罗列,而是强调统计学、机器学习和计算机科学3门学科的融会贯通,试图呈现给读者关于数据科学较全面的知识体系。特别是对常用的统计和机器学习软件的详细说明,对提高在校大学生、研究生的动手能力和企业科技人员解决实际问题的能力大有裨益。

中国工程院院士,第三世界科学院院士,曾任中国科学院计算技术研究所所长

李国杰


回首30年的新兴产业的来路,我们看到的或许是遵循着摩尔定律飞速增长的集成电路,或许是从互联网到移动互联网,再到物联网的更广泛的互联互通。但其背后,数据作为新兴产业的血液,其价值得到了广泛的认知和关注。早在2011年,我们完成了4篇大数据行业的前瞻报告,撰写《大数据时代的历史机遇》分析了大数据时代的产业机会与变革。后来又同申万宏源的计算机首席分析师刘洋一起勾勒了大数据产业的版图和发展路径。

如今作为一个大数据产业的实践者,我们看到大数据产业正如我们所预期的那样,成为了人工智能、虚拟现实以及区块链等新一轮新兴产业浪潮的核心,成为了传统产业转型升级的必备资源,成为了企业保持领先抑或实现弯道超车的必争之地。然而数据资源怎么用,数据模型如何建立,算法模型如何运用,成为了学界、产业界、资本界都在关注的关键问题。

本书站在数据学科的角度,融合了数学、计算机科学、计量经济学的精髓。不仅从“道”的层面为读者阐释了数据科学所要解决的核心问题——数据模型、算法模型的理论内涵和适用范围,而且从“术”的层面以常用的IT工具——Python为基础,教会读者如何建模以及通过算法实现数据模型,具有很强的实操性。在此基础之上,本书还为读者详解了分布式机器学习、神经网络、深度学习等大数据和人工智能的前沿技术。相信本书将成为数据科学工作者、数据工程师、数据产业实践者的必备手册,以及想要了解和学习数据科学的人员的首选教材。

易选股金融智能证券董事长,键桥通讯董事

易欢欢


As a computer scientist living in North America for almost 40 years, I barely read any technical books written in Chinese. When Gen Tang sent me this book, I was worried whether it could be too dry for me to read it or whether I can really understand it. To my surprise and excitement, this book has immediately attracted my attention. It is a unique book that blends data science, statistics, machine learning and computer science nicely together, introducing the foundations as well as very frontier of data science and deep learning in an enjoyable and easily accessible way. Besides, it also provides many, very handy and concrete programming tutorials.

By reading it, one can learn not only the general data science principles and very trendy machine learning algorithms, but also hands-on programming exercises on implementing them. This book will benefit data science researcher, graduate students, as well as those who really want to put data science principles into practical implementations. I love reading this book and recommend it highly to everyone who wants to learn data science!

ACM Fellow and IEEE Fellow, Abel Bliss Professor,
Department of Computer Science, University of
Illinois at Urbana-ChampaignJiawei Han


和武侠世界里有少林和武当两大门派一样,数据科学领域也有两个不同的学派:以统计分析为基础的统计学派,以及以机器学习为基础的人工智能派。虽然这两个学派的目的都是从数据中挖掘价值,但彼此“都不服气”。注重模型预测效果的人工智能派认为统计学派“固步自封”,研究和使用的模型都只是一些线性模型,太过简单,根本无法处理复杂的现实数据。而注重假设和模型解释的统计学派则认为人工智能派搭建的模型缺乏理论依据、无法解释,很难帮助我们通过模型去理解数据。

从历史上来看,一门学科出现相互对立的学派通常意味着这门学科处于爆发的前夜,比如20世纪初的经济学,凯恩斯学派和新古典经济学派的长期论战极大地促进了宏观经济学的发展,并深刻地影响了各国政府的经济政策,并由此改变了人们的生活方式。现在数据科学也处在这样相似的位置和时间节点,它已经开始并将继续改变我们的世界。

抛开这些学术上的纷争,在实际工作中应该采用哪个学派的方法来解决数据挖掘的问题呢?答案是两者都需要,而且两者都重要。在某些应用场景中,比如图像识别领域,人工智能模型有非常惊艳的表现。虽然人们还没弄清楚这些模型的工作原理,但并不妨碍它们在现实中发挥作用。事实上,人类在很多其他领域里也是这种实践先行的状态。

但在更多的应用场景中,统计学派的方法则显得更为重要。我曾在欧洲的一家保险公司里参与过一个车险定价的项目,在这个项目里,数据科学家们主要尝试了两类模型,一类是很容易解释的逻辑回归和决策树模型,另一类是较为复杂的随机森林模型。随机森林模型的预测效果更好,如果将其投入生产中,仅在法国每年就能产生数千万欧元的利润。但问题是随机森林模型难以解释,监管部门根本不接受,所以只能退而求其次,使用效果较差但更易解释的决策树模型。抛开监管层的要求不说,模型的可解释性也是非常重要的。试想一下,顾客去保险公司购买车险时,被告知需要比别人花更多的钱,而对方提供的理由是,有一个不好解释的模型预测出顾客需要付更多钱,我想大部分顾客会难以接受这样的理由和做法吧。

上述的两种建模方式虽然在处理数据的方法上有很大差异,但它们有一个共同的“物质基础”—计算机。只有借助计算机强大的运算能力,我们才能在工程上实现搭建好的模型,使之发挥作用。因此,数据科学是统计学、机器学习以及计算机科学3门学科的交叉,涉及的知识点和技能点很庞大且复杂。如果能将这3门学科融会贯通,那么就能描绘出有关数据科学的全景图,进而搭建起一个完整的知识体系,而这正是我编写本书的初衷。

本书按照结构共分为13章,主要内容如下。

第1~3章主要介绍数据科学要解决的问题、常用的IT工具Python以及数据科学所涉及的数学基础。

第4~7章主要讨论数据模型,包含3部分内容:一是统计中经典的线性回归和逻辑回归模型;二是计算机估算模型参数的随机梯度下降法,这是模型工程实现的基础;三是来自计量经济学的启示,主要涉及特征提取的方法以及模型的稳定性。

第8~10章主要讨论算法模型,也就是机器学习领域比较经典的模型,各章依次讨论了监督式学习、生成式模型以及非监督式学习。

目前数据科学的两个前沿领域分别是大数据和人工智能。

第11章介绍大数据中很重要的分布式机器学习。

第12~13章讨论人工智能领域的神经网络和深度学习。

本书除基础知识外,按照主题亦可分为3部分。

第1部分主要讨论统计学派的模型和对数据的处理方法,涉及第4、5、7章。

第2部分主要讨论人工智能学派的方法,涉及第8、9、10、12、13章。 第3部分主要介绍数据科学的工程实现,涉及第6、11章。

在每一章的讨论中,一般会通过一个简单的例子引出模型,然后讲解模型的理论基础,接着展示模型实现的核心代码,最后讨论模型的优缺点以及与其他模型的比较。这样既能很直观地展示模型,也能结合实际代码较深入地讨论它的细节,从而帮助读者更好地掌握和使用模型。

针对本书,最好的阅读方法是对照每一章的示例代码,动手实现所讨论的模型。这样会极大加深读者对模型的理解,提高实践能力,否则就会像读小说一样,阅读时感觉不错,但实际使用时就无从下手了。

本书配套代码的下载地址为https://github.com/GenTang/intro_ds,供读者借鉴和使用。

需要注意的是,为了在正文中节省篇幅,突出重点,本书所展示的代码是基于Linux系统下的Python 2.7,而提供下载的配套代码则是兼容Python 3和Windows系统的。

本书中部分插图中含有未翻译的英文专有名词,原因如下。

一方面,目前相关的参考文献中没有明确且权威的中文名称与之对应,如强行翻译,难保准确,且易给读者造成误解。另一方面,对于数据科学这门学科,英文名词可能是大家更加熟悉的称呼,翻译为中文后也许会使读者在理解上更加困难。

在此说明,望各位读者理解和支持。

由于作者知识水平有限,书中难免存在纰漏之处,敬请各位读者朋友批评指正。请发送邮件到作者的电子邮箱tgbaggio@hotmail.com或本书编辑的电子邮箱zhangshuang@ptpress.com.cn。

感谢潘健辉博士,他从行文风格和数学细节上为我提出了很多宝贵的意见。感谢我的太太安恺业女士以及我的父母,他们在本书的编写期间给了我很多鼓励。感谢李国杰院士、林晓东教授、杨卫东教授、张溪梦(Simon Zhang)先生、易欢欢先生、贾真先生、张益军先生、彭耀先生、谢佳女士以及赵甘晶女士为本书提供的帮助。感谢我的初中数学老师吴献女士对我的谆谆教诲。感谢本书的编辑张爽女士为本书的顺利出版所做的工作。需要感谢的人还有很多,限于篇幅,这里就不一一列举了。


本书为异步社区出品的图书,在社区(https://www.epubit.com/)上为您提供以下资源与服务。

本书源代码请到异步社区的本书购买页面中下载。

请在异步社区本书页面中点击,跳转到下载界面,按提示进行操作即可。注意:为保证正常购书用户的权益,会要求您输入提取码进行验证。

作者和编辑尽最大努力来确保书中内容的准确性,但难免还会存在差错。欢迎您将发现的问题告诉我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区主页https://www.epubit.com/,搜索到本书页面,点击 “提交勘误”,输入勘误信息,最后单击“提交”按钮即可。之后本书的作者和编辑会对您提交的勘误进行审核。确认并接受后,您将获赠异步社区的100积分。积分可用于在社区兑换优惠券,以及兑换样书或奖品之用。

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请发邮件到此邮箱,邮件标题中请注明本书书名。

如果您有兴趣出版图书、录制教学视频,或参与图书翻译、技术审校等工作,可以发邮件,有意出版图书的作者还可以到异步社区在线提交投稿:

www.epubit.com/selfpublish/submission

如果您是学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,请发邮件联系我们。

如果您在网上发现有针对异步图书的各种形式的盗版行为,包括图书或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的举动是对作者权益的保护,我们也由此才能继续为您带来有价值的内容。

异步社区是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT技术图书和相关学习产品,为作译者提供优质出版服务,社区创办于2015年8月,提供超过1000种图书、近1000种电子书,以及众多技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

异步图书是由异步社区编辑团队策划出版的精品IT专业图书品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,在封面上印有异步图书的LOGO。我们的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。

异步社区

微信服务号


The purpose of computing is insight,not numbers.

(计算的目的不在于数字,而在于洞察事物。)

——Richard Hamming

1.1 挑战

1.2 机器学习

1.3 统计模型

1.4 关于本书

随着云计算和人工智能的发展,数据科学这门新的综合学科被越来越多的人所熟知,业界也普遍看好其在未来的发展前景。体现在就业市场上,与这个行业相关的数据科学家和数据工程师[1]成为了“21世纪最吸引人的职业”[2]

就像“一千个人眼里有一千个哈姆雷特”一样,对于什么是数据科学也有很多种不同的解读,并由此衍生出很多相关概念,比如数据驱动(data driven)、大数据(big data)、分布式计算(distributed computing)等。这些概念虽然各有侧重点,但它们都毫无争议地围绕着同一个主题:如何从实际的生活中提取出数据,然后利用计算机的运算能力和模型算法从这些数据中找出一些有价值的内容,为商业决策提供支持。这正是数据科学的核心内涵。

传统的数据分析手段是所谓的商业智能(business intelligence)。这种方法通常将数据按不同的维度交叉分组,并在此基础上,利用统计方法分析每个组别里的信息。比如商业智能中最常见的问题是:“过去3个月,通过搜索引擎进入网站并成功完成注册的新用户里,年龄分布情况如何?若将上面的用户群按年龄段分组,各组中有多大比例的用户在完成注册后,完成了至少一次消费?”

这样的分析是非常有用的,能揭示一些数据的直观信息。但这样的方法如同盲人摸象,只能告诉我们数据在某个局部的情况,而不能给出数据的全貌。而且对于某些问题,这样的结果显得有些不够用。比如用户注册之后完成消费的比例与哪些因素相关?又比如对于某个客户,应该向他推荐什么样的商品?在这些场景下,我们就需要更加精细的数据分析工具——机器学习和统计模型。在我看来,这些内容是数据科学的核心内容,也是本书介绍的重点。

在数据科学实践中,我们将使用较为复杂的机器学习或统计模型对数据做精细化的分析和预测。这在工程实现和模型搭建两方面都提出了挑战,如图1-1所示。

图1-1

数据科学在工程上的挑战可以大致分为3类:特征提取、矩阵运算和分布式机器学习。

(1)一个建模项目的成功在很大程度上依赖于建模前期的特征提取。它包含数据清洗、数据整合、变量归一化等。经过处理后,原本搅作一团的原始数据将被转换为能被模型使用的特征。这些工作需要大量的自动化程序来处理,特别是面对大数据时,因为这些大数据无法靠“人眼”来检查。在一个典型的建模项目中,这部分花费的时间远远大于选择和编写模型算法的时间。

(2)对于一个复杂的数学模型,计算机通常需要使用类似随机梯度下降法的最优化算法来估算它的模型参数。这个过程需要大量的循环,才能使参数到达收敛值附近。因此即使面对的是很小的数据集,复杂的模型也需要很长时间才能得到正确的参数估计。而且模型在结构上越复杂,需要估计的参数也就越多。对这些大量的模型参数同时做更新,在数学上对应着矩阵运算。但传统的CPU架构并不擅长做这样的运算,这导致模型训练需要耗费大量的时间。为了提高模型的训练速度,需要将相应的矩阵运算(模型参数的估算过程)移植到GPU或者特制的计算芯片上,比如TPU。

(3)近年来,随着分布式系统的流行和普及,存储海量数据成为了业界的标配。为了能在这海量的数据上使用复杂模型,需要将原本在一台机器上运行的模型算法改写成能在多台机器上并行运行,这也是分布式机器学习的核心内容。

数据科学对模型搭建的要求也可以总结为3点:模型预测效果好、模型参数是稳定且“正确”的、模型结果容易解释。

(1)模型的预测效果好,这是数据科学成功的关键。而一个模型的预测效果取决于它的假设是否被满足。从数学上来看,任何一个模型除去假设部分,它的其他推导都是严谨的数学演算,是无懈可击的。因此模型假设就像模型的阿喀琉斯之踵[3],是它唯一的薄弱环节。当问题场景或数据满足模型假设时,模型的效果一定不会差,反之,则预测效果就无法保证了。但在实际生产中,针对一个具体的问题,几乎不可能找到一个模型,它的假设被百分之百地满足。这时就需要避重就轻,通过特征提取等手段,尽量避免违反那些对结果影响很大的假设。这就是为什么说“所有模型都是错的,但是,其中有一些是有用的”[4]

(2)除了被用来对未知数据做预测外,模型另一个重要的功能就是对已有数据做分析,比如哪个变量对结果的影响最大或者某个变量对结果到底是正向影响还是负向影响等。这些分析结果在很大程度上依赖于模型参数的估计值,后者的准确与否直接决定分析结果的质量。但问题是,模型参数的估计值是不太“可靠”的。例如从训练数据中随机抽取两个不完全一样的数据子集AB,然后用这两个数据集分别训练同一个模型。得到的参数估计值几乎不可能完全一样。从数学的角度来看,这说明模型参数的估计值其实是一个随机变量,具体的值取决于训练模型时使用的数据。于是我们要求这些估计值是“正确”的:围绕参数真实值上下波动(也就是说它们的期望等于参数真实值)。我们还要求这些估计值是稳定的:波动的幅度不能太大(也就是说它们的方差比较小)。这样就可以把参数估计值的“不可靠性”控制在可接受的范围内。

(3)数据科学家将模型搭建好,并不是一个数据科学项目的终点。为了充分发挥数据的价值,需要将模型结果应用到实际的生产中,比如为手机银行APP架设实时反欺诈系统,或者将利用新搭建的车祸风险模型为汽车保险定价等。参与这个过程的不仅有懂模型的数据科学家,还有更多非技术的业务人员。而后者往往是使用模型的主力,比如根据反欺诈系统的结果,对可疑用户进行人工审核,又或者向客户解释为什么他的车险比别人贵。为了帮助他们更好地理解模型结果,需要将复杂深奥的模型翻译成直观的普通语言。这要求模型是能被解释的,而且是容易被解释的。

在对数据搭建模型时,有两种截然不同的思路,如图1-2所示。

图1-2

一种是所谓的数据模型(data model),也就是传统的统计模型[5]。这种思路假设数据的产生过程是已知的(或者是可以假设的),可以通过模型去理解整个过程。因此,这类模型通常具有很好的可解释性,分析其稳定性的数学工具也很多,能很好地满足上面提到的后两点。但是在实际生产中,这些模型的预测效果并不好,或者更准确地说,单独使用时,预测效果并不理想。

另一种是所谓的算法模型(algorithm model),也就是机器学习。这类模型是人工智能的核心内容,它们假设数据的产生过程是复杂且未知的。建模的目的是尽可能地从结构上“模仿”数据的产生过程,从而达到较好的预测效果。但代价是模型的可解释性很差,而且模型稳定性的分析方法也不多。

正如上面的分析,统计学和机器学习在某些方面具有极好的互补性。因此在实际的生产中,为了将一个数据科学项目做得尽可能完美,我们需要将这两种思路结合起来使用。比如使用机器学习的模型对数据建模,然后借鉴数据模型的分析工具,分析模型的稳定性和给出模型结果的直观解释。

在讨论机器学习之前,我们先来总结一下人是怎么学习的:在面对一个具体的问题时,人首先会根据已有的经验和当前的信息做出反应行动,然后按照行动获得的反馈去修正自己的经验,并不断重复这个过程。

机器学习就是通过程序让计算机“学会”人的学习过程。换句话说,机器学习是一个计算机程序,这个程序能够根据“经验”自我完善。那么问题来了,既然都是程序,机器学习和传统编程有什么不同呢?

首先,通过一个假想的例子来体会这两者之间的差异。假设我们需要构建一个能区分老虎和斑马图片的系统,而这个任务被交给了程序员小李和数据科学家小胡。

程序员小李拿到这个任务之后,他首先总结了两条分辨这两种动物的经验:

然后,小李将上面的两条经验总结成规则:如果图中的动物有黄色毛发或者耳朵比较小,那么图中的动物是老虎,反之则为斑马。

最后,他将规则翻译成程序代码交给计算机去执行。

数据科学家小胡的做法则完全不同。他并不去总结区别这两种动物的规则,而是假设毛发颜色和耳朵大小能区别这两者。于是小胡将这个逻辑翻译成学习程序运行在计算机上。与此同时,他还从网络上收集了一大堆老虎和斑马的图片,并将这些图片做好标记,即每张图片对应的动物是什么。然后小胡将数据(图片+标记)输入给之前编写好的学习程序,而后者就可以根据数据不断累积经验和总结规则,这个过程被称为模型训练。经过一段时间的训练后,学习程序最后得到了一个模型(以代码的形式存在)。这个得到的模型和小李自己编写的程序一样,可以用来区分老虎和斑马的图片。

小李和小胡各自的工作流程如图1-3所示。从编程的角度来看,机器学习是一种能自动生成程序的特殊程序。

图1-3

也许上面的例子有点过于抽象了,下面再来看一个简单而具体的例子。假设我们想通过一个成年人的身高(用变量表示)来预测他的体重(用变量表示)。这项工作同样被交给了小李和小胡。

小李拿到问题之后,首先上网查阅了成年人身高与体重的相关研究资料。他发现这两者的关系可以用如下的公式表示。

(1-1)

接着他将公式(1-1)转换为程序里面的函数,这个函数的输入参数是身高,输出是预测的体重。

小胡接到任务后,首先假设身高和体重的关系可以用线性回归模型来表示,也就是公式(1-2),其中为未知的模型参数

(1-2)

同图片识别中的做法类似,小胡接下来收集了大量的人体身高和体重的数据。他将这些数据输入给模型,而模型将根据得到的数据估计未知参数。估计的原则是使得模型预测值与实际值的差距达到最小。经过计算之后,得到参数的估计值为。也就是说经过模型训练后,小胡得到了如公式(1-3)所示的程序

(1-3)

图1-4所示是小李和小胡各自提供的解决方案。

图1-4

总结一下,传统的编程方式是人类自己积累经验,并将这些经验转换为规则或数学公式,然后就是用编程语言去表示这些规则和公式。而机器学习可以被看作一种全新的编程方式。在进行机器学习时,人类不需要总结具体的规则或公式,只需制订学习的步骤,然后将大量的数据输入给计算机。后者可以根据数据和人类提供的学习步骤自己总结经验,自动升级。计算机“学习”完成之后会得到一个模型程序,而这个由程序生成的程序可以达到甚至超过人类自身的水平。

机器学习根据所用的训练数据可以分为两类。一类是监督式学习,这类模型的特点是训练数据里有标注,也就是常说的被预测量。1.2.1节里讨论的两个例子都是监督式学习。监督式学习按标注的类型又可以细分为两类:分类和回归。如果数据里的标注表示事物的类别,也就是说标注是离散的,那么相应的模型就属于分类,比如1.2.1节里动物图片识别的例子。如果标注表示具体的数量,也就是说标注的是连续的,那么相应的模型就属于回归,比如1.2.1节里通过身高预测体重的例子。

另一类是非监督式学习,这类模型所用的训练数据里并没有标注,只有自变量。非监督式学习根据用途又可以分为两类:聚类和降维。把“距离”相近的点归于一类叫作聚类,而将高维空间里的数据映射到低维度空间叫作降维,具体内容见图1-5。

图1-5

从上面的例子中可以看到,机器学习非常依赖所用的训练数据。但是数据就百分之百可靠吗?下面就来看两个数据“说谎”的例子。

如图1-6所示,我们将某APP每月的用户注册数表示在图中。图1-6a给人的直观印象是每月的安装数是大致差不多的,没有明显的增长。而图1-6b给人不同的印象,从3月份开始,用户注册数大幅度增长。但其实两幅图的数据是一模一样的,给人不同的感觉是因为图1-6a中纵轴的起点是0,而且使用了对数尺度;而图1-6b的纵轴是从17 000开始的,而且使用的是线性尺度。

(a)                     (b)
图1-6

读者可能会觉得上面这个例子太过简单了,只需要使用一些简单的统计指标,比如平均值或每个月的增长率,就可以避免错误的结论。那么下面来看一个复杂一点的例子。

当得到如图1-7所示的两组数据时,我们应该如何用模型去描述数据的变化规律呢?

(a)                     (b)
图1-7

根据上面的分析结果,可以得出如下的结论,图1-7a中的之间是二次函数关系,而图1-7b的之间是线性关系。但其实两幅图中的变量都是与无关的随机变量,只是因为观察窗口较小,收集的数据样本太少,让我们误以为它们之间存在某种关系。如果增大观察窗口,收集更多的数据,则可以得到完全不同的结论。如图1-8所示,如果将收集的样本数从20增加到200,会发现图1-8a中的数据图形更像是一个向下开口的抛物线,这与图1-7a中的结论完全相反。而图1-8b中也不再是向下的直线,而与开口向上的抛物线更加相似。

(a)                     (b)
图1-8

上面的例子就是所谓的模型幻觉:表面上找到了数据变动的规律,但其实只是由随机扰动引起的数字巧合。因此在对搭建模型时,必须时刻保持警惕,不然很容易掉进数据的“陷阱”里,被数据给骗了,而这正是统计学的研究重点。这门学科会“小心翼翼”地处理它的各种模型,以确保模型能摆脱数据中随机因素的干扰,得到稳定且正确的结论,正好弥补机器学习在这方面的不足。

数据科学涉及计算机编程和数学建模这两个方面。它们之间的交集并不多,所强调的技能也有很大区别。这体现在实际生产中就是懂模型的人不懂编程,懂编程的人不懂模型,两者兼备的人才非常稀缺。本书的第一个目的就是将这两者的鸿沟弥补起来,注重模型假设和数学推导的同时,强调如何用代码实现模型。

对于数据科学中的模型搭建,统计学和机器学习是其最重要的组成部分。这两门学科的侧重点并不相同,在很多方面它们是彼此很好的补充。在面对一个实际问题时,若能将两者的方法相结合,能更好地挖掘数据的内在规律,从而更大程度地发挥数据的价值。这是本书的第二个目的。

当前,数据科学有两个最热门的前沿领域:分布式机器学习和深度学习。本书有专门的章节讨论它们,展示这两个领域想要解决的问题和目前最好(或最流行)的解决方案。这是本书的第三个目的:从宏观的角度向读者展示什么是数据科学,想要解决的问题、主要的方法以及未来的发展方向。

本书并不试图成为机器学习或统计学的参考书。在之后的章节里,有关模型的数学推导都只是简略讲解,并不做详细证明(本书也不会为了迎合行文简便,一味地回避这些难点[6])。本书讨论的重点是数据科学的整个工作流程(Pipeline):不止是搭建模型、用数据去训练模型,而是如何对数据进行预处理,初步分析数据、搭建并评估模型以及根据结果分析模型的缺点进而改进模型。

[1] 数据科学家(data scientist)的主要工作是为数据搭建模型,要求具有扎实的数学以及统计知识;数据工程师(data engineer)的主要工作是利用计算机分析数据和实现数据科学家设计好的模型,要求具有良好的编程实现能力。实际上这两种职业的工作内容有很多重叠的部分,因此要求从业者同时具备较好的数理知识和工程实现能力。

[2] Davenport T H, Patil D J. Data Scientist: The Sexiest Job of the 21st Century[J]. Harvard Business Review, 2012, 90(10):70-76.

[3] 阿喀琉斯是希腊神话中的一个人物。除了未被冥河浸泡过的脚后跟外,他全身近乎刀枪不入,有“希腊第一勇士”之称。在特洛伊战争中,阿喀琉斯被箭射中脚后跟而死去。因此阿喀琉斯之踵欲指某事物的最大或者唯一弱点。

[4] 出自英国统计学家George Edward Pelham Box。

[5] Breiman L. [Statistical Modeling: The Two Cultures]: Rejoinder[J]. Statistical Science, 2001, 16(3):199-231.

[6] 伟大的法国天才数学家,抽象代数的奠基人,埃瓦里斯特•伽罗瓦(Évariste Galois)曾说过:“一个作家对读者做的最大的恶就是隐藏难点(un auteur ne nuit jamais tant à ses lecteurs que quand il dissimule une difficulté)。”这也是本书在编写时遵循的原则之一:直面数据科学领域里的难点,但用通俗的语言讲解它们。


If you are immune to boredom, there is literally nothing you cannot accomplish.

(如果你能忍耐乏味,你将无往不利。)

——David Foster Wallace

2.1 Python简介

2.2 Python安装

2.3 Python上手实践

2.4 本章小结

本章介绍数据科学中最常用的IT工具:Python以及相关第三方库。本书后面章节的代码示例和模型实现都基于此。正所谓“工欲善其事,必先利其器”,为了更深入地理解数据科学,读者需要确保已安装好所需的IT工具,并基本熟悉其使用方法。

如果读者对此已十分熟悉,可选择跳过本章。虽然如此,作者仍推荐阅读本章。

记得在几年前,数据科学刚刚兴起的时候,我有幸参加了一次行业里的聚会,探讨数据科学的内涵、机会以及难点等。其中有一页PPT给我留下了深刻的印象,如图2-1所示。

图2-1

当时看到后一笑而过,程序员总会强调自己使用的语言是最好的,比如著名的“PHP是世界上最好的语言”。这里用略带戏谑口吻的段子来强调Python语言的重要性,感觉很新颖。但是经过这几年的工作实践,我愈发感到:这虽然是个段子,却在很大程度上真实地描述了数据科学这个行业的工作状态,甚至可以说是直击痛点。

为了更形象地说明这个问题,我们不妨假设我们有个小伙伴叫小安。数学系毕业的她刚刚获得了一份数据科学相关的工作。上班的第一天,她满怀热情而且迫不及待地想接触这个崭新的行业。但是她很快就发现自己面临着一个巨大的困难:

工作所需要处理的数据并不存放在她的个人电脑里,而是都保存在远程服务器上,有的存放在传统的关系型数据库里,有的存放在Hadoop集群上。与个人电脑大多使用的Windows不同,远程服务器上使用的都是类Linux系统[1]。小安很不习惯这种操作系统,因为熟悉的图形化界面不见了。一切操作,比如最简单的读取文件都需要自己编程来实现。因此,小安很想找到一款书写简单、易学易用的编程语言。

更致命的是,小安所熟悉的数据建模软件,比如SPSS、MATLAB等在新的工作环境里都没办法使用了。而小安在平时的工作里会经常用到这些软件提供的一些基础的算法,比如线性回归、逻辑回归等。所以,她希望所找到的编程语言也有可以方便使用的算法库,当然最好是免费的。

小安的日常工作流程大致如图2-2所示。

图2-2

整个过程和小安最爱的乒乓球很像,把假设当成“球”发给数据,再根据数据的“回球”,做出调整,并重复上述的动作。因此,小安又在她的要求里多加了一条:编程语言能随时修改随时使用,不需要编译。最好能有个即时响应的命令窗口,方便她快速验证自己的想法。

经过一番搜索,小安激动地告诉大家,她找到了满足她所有要求的IT工具:Python。下面我们就让小安来给我们介绍一下她的选择。

Python(发音:/ˈpaɪθən/ ),是一种面向对象、解释型的计算机程序语言。它的语法简单,并且包含了一组功能完备的标准库,能够轻松完成很多常见的任务[2]。说起Python,它的诞生也颇有意思。1989年的圣诞假期,荷兰程序员Guido van Rossum待在家里,发现自己无所事事。于是为了打发“无聊”的时光,他编写了第一版的Python。

Python的使用范围非常广,根据开源社区GitHub的统计(见图2-3),在近10年它一直是最流行的编程语言之一,比传统的C、C++语言以及Windows系统下十分常用的C#都更为流行。

图2-3

小安在使用Python一段时间后,觉得它是一个专门为非专业程序员设计的编程语言。

总结起来就一句话:好学而且好用。

在掌握Python这门编程语言后,小安可以做很多有趣的事情:比如编写网络爬虫程序、从互联网上收集所需要的数据、开发任务调度系统、定时更新模型等。当然作为数据科学工作者的小安,她最常用Python做下面这4件事情,如图2-4所示。

图2-4

上述的4件事情也正是数据科学中最核心的4个步骤。这就难怪小安同其他大部分数据科学家一样,会选择Python为工具来完成自己的工作。

表2-1列举了在数据科学中最常用的Python库。

表2-1

数据预处理 NumPy 科学计算基础库。它提供高效的N维数组和向量运算
SciPy 科学计算库。它依赖于NumPy,提供高效的数值计算,以及用于函数最优化、数值积分等任务的模块
pandas 数据结构和数据分析库。包含高级数据结构和类SQL语句,让数据处理变得快速、简单
数据可视化 Matplotlib 数据可视化库。它提供大量专业数据图形制作工具
标准模型库 scikit-learn 标准机器学习库。它主要用于分类、回归和聚合等,依赖于NumPy、SciPy、Matplotlib
Statsmodels 标准统计模型库。它主要用于假设检验和参数置信区间分析
Spark ML 分布式机器学习算法库。它可在分布式集群上,如Hadoop,对大量数据建模。Spark ML由Scala开发,但提供Python API
TensorFlow 成熟的深度学习算法库。它提供GPU运算模块

后面的章节会陆续用到这些库,读者到时就可以更加直观地感受它们的“威力”。

介绍了这么多Python的好处,那我们赶紧安装它,亲自感受一下吧!

Python有两个主要的版本:Python 2和Python 3。Python 3是较高的版本,具有Python 2所没有的新特性。但由于Python 3在设计的时候没有考虑向下兼容,导致实际生产中仍以Python 2为主(虽然在本书编写时,Python 3已经发布快10年了)。因此这里推荐读者全新安装时仍使用Python 2,本书配套的代码兼容Python 2和Python 3,具体信息见前言。

下面介绍如何安装Python和2.1.3节中所列举的库。请读者按照自己使用的计算机系统,参考对应的安装指南。

需要说明的是,分布式机器学习库Spark ML涉及Java和Scala的安装,这里就暂不做介绍。具体的安装细节请见第11章。

作者并不推荐大家在Windows系统下做开发。原因有很多,其中最重要的一条是:在大数据时代,如前面小安提到,数据都存放在Linux系统下。因此,在生产上,数据科学家开发的程序最终将运行在Linux环境下。而Windows和Linux的兼容并不好,很容易导致在Windows下开发调试好的程序,在实际生产环境下没办法正常运行。

如果读者使用的计算机是Windows系统,可以选择安装Linux的虚拟机,然后在虚拟机上做开发。如果读者坚持使用Windows,由于TensorFlow在Windows下的限制,只能选择安装Python 3.5(截止本书编写时)。因此本小节下面的教程也有别于其他章节,使用的是Python 3。

在Windows环境下,最方便的方法就是安装第三方发行版Anaconda。它将Python和许多常用的库打包,包括本书将涉及的NumPy、SciPy、Matplotlib、scikit-learn和Statsmodels,方便读者直接使用。

1.Anaconda的安装步骤

(1)从网上下载Anaconda[3],如图2-5所示。

图2-5

(2)双击下载后的文件,按默认选项安装。如图2-6所示。

图2-6

2.验证安装是否成功

(1)打开“开始”→“应用”。

(2)在搜索栏中输入“cmd”,选择并打开“命令提示符”,如图2-7所示。

图2-7

(3)输入“python”并按回车键,如程序清单2-1所示。

程序清单2-1 Python shell on Windows

 1  |  C:\Users\you> python
 2  |  Python 3.6.0|Anaconda 4.3.1 (64-bit)| (default, Dec 23 2016, 11:57:41) [MSC v.
 3  |  1900 64 bit (AMD64) on win 32
 4  |  Type "help", "copyright", "credits" or "license" for more information.
 5  |  Anaconda is brought you to by Continuum Analytics.
 6  |  >>> [输入“exit()”退出Python返回命令行]

Anaconda在Windows下安装了好几个应用程序,如IPython、Jupyter、Conda和Spyder等。限于篇幅,这里只重点介绍其中的两个——Conda和Spyder。

图2-8

3.安装TensorFlow

(1)如上面所述,打开“命令提示符”。

(2)使用如下命令,安装Python 3.5。

程序清单2-2 在Windows下使用Conda安装Python 3.5

 1  |  C:\Users\you> conda install python=3.5
 2  |  C:\Users\you> python --version
 3  |  Python 3.5.3 :: Anaconda custom (64-bit)

(3)输入如下命令来创建一个TensorFlow的环境,并启动创建好的TensorFlow环境。

程序清单2-3 在Windows下安装TensorFlow

 1  |  C:\Users\you> conda create -n tensorflow
 2  |  C:\Users\you> activate tensorflow
 3  |  (tensorflow) C:\Users\you> [你的命令行将变成这样,以(tensorflow)开头]

(4)输入如下命令安装TensorFlow。TensorFlow分为CPU版本和GPU版本,这里推荐读者,特别是对GPU计算不太熟悉的读者安装CPU版本。

程序清单2-3 在Windows下安装TensorFlow

 4  |  [安装CPU计算框架的TensorFlow]
 5  |  (tensorflow) C:\Users\you> pip install --ignore-installed --upgrade https://mirrors.tuna.tsinghua.edu.cn/tensorflow/windows/cpu/tensorflow-1.0.1-cp35-cp35m-win_amd64.whl
 6  |  [或者安装GPU计算框架的TensorFlow]
 7  |  (tensorflow) C:\Users\you> pip install --ignore-installed --upgrade https://mirrors.tuna.tsinghua.edu.cn/tensorflow/windows/gpu/tensorflow_gpu-1.0.1-cp35-cp35m-win_amd64.whl

(5)验证TensorFlow安装是否成功。

程序清单2-3 在Windows下安装TensorFlow

 8  |  C:\Users\you> python
 9  |  >>> import tensorflow as tf
10  |  >>> tf.__version__
11  |  '1.0.1'

如上面Windows下的安装指南所示,可以选择安装第三方发行版Anaconda。具体的安装步骤这里就不展开了。请读者参考Windows下的说明和随书配套的代码。

如同Anaconda的Windows版本,Anaconda的Mac版本并不包含深度学习库TensorFlow,需要使用pip(Python软件包管理系统)来安装它。虽然使用pip需要用到命令行,但操作起来十分简单,甚至比安装Anaconda更容易。而且pip的应用更广泛,所以建议读者从一开始就尝试用pip来安装所需要的库。下面介绍不使用Anaconda的安装方法。

从Mac OS X 10.2版本开始,Mac预装了Python。如果是以学习为目的,可以选择直接使用预装版本的Python;如果是以开发为目的,预装的Python在安装第三方库时容易遇到问题,需要重新安装最新版本的Python。这里推荐读者重新安装Python。

1.安装最新版本的Python

(1)打开“应用程序”→“实用工具”→“终端”,如图2-9所示。

图2-9

(2)安装Mac OS缺失软件包管理器Homebrew。

程序清单2-4 在Mac上安装Python

 1  |  [localhost:~] you$ /usr/bin/ruby -e "$(curl -fsSL 
https://raw.githubusercontent.com/Homebrew/install/master/install)"
 2  |  [需要输入你的电脑密码]
 3  |  [localhost:~] you$ brew --version
 4  |  [Homebrew的版本信息]

(3)安装最新版本的Python2。

程序清单2-4 在Mac上安装Python

 5  |  [下面的命令将同时安装最新版本的Python2和pip]
 6  |  [localhost:~] you$ brew install python
 7  |  [同时按下Command和N打开一个新的终端窗口]
 8  |  [localhost:~] you$ python
 9  |  Python 2.7.13 (default, Jul 30 2016, 23:25:09)
10  |  [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
11  |  Type "help", "copyright", "credits" or "license" for more information.
12  |  >>> [同时按下 Control和D退出Python返回终端]
13  |  [localhost:~] you$ pip --version
14  |  [pip版本以及安装地址]

2.如果需要,单独安装pip

(1)打开“终端”。

(2)输入并执行如下命令。

程序清单2-5 在Mac上安装pip

 1  |  [localhost:~] you$ sudo easy_install pip
 2  |  [需要输入你的电脑密码]
 3  |  [localhost:~] you$ pip --version
 4  |  [pip版本以及安装地址]

3.安装需要的库

如果使用Mac预装的Python,可能会遇到报错。

(1)打开“终端”,安装NumPy。

程序清单2-6 在Mac上安装Python库

 1  |  [localhost:~] you$ pip install numpy
 2  |  [如果你在安装过程中遇到权限问题,使用下面的命令安装]
 3  |  [localhost:~] you$ sudo -H pip install numpy
 4  |  [你可以指定NumPy安装的版本,比如下面的命令安装1.11.0版本的NumPy]
 5  |  [localhost:~] you$ pip install numpy==1.11.0
 6  |  [你还可以使用如下命令更新NumPy到最新的版本]
 7  |  [localhost:~] you$ pip install --upgrade numpy

(2)安装SciPy、pandas、Matplotlib和scikit-learn。

程序清单2-6 在Mac上安装Python库

 8  |  [localhost:~] you$ pip install pandas
 9  |  [localhost:~] you$ pip install matplotlib
10  |  [localhost:~] you$ pip install pandas
11  |  [localhost:~] you$ pip install scikit-learn
12  |  [如果你遇到权限问题,或者想升级库的版本,请参考第一步Numpy的安装指南]

(3)安装Statsmodels。

程序清单2-6 在Mac上安装Python库

13  |  [localhost:~] you$ pip install --upgrade patsy
14  |  [localhost:~] you$ pip install statsmodels

(4)安装TensorFlow。推荐读者安装CPU版本的TensorFlow。

程序清单2-6 在Mac上安装Python库

15  |  [因为依赖的原理,使用如下命令卸载已安装的Tensorflow]
16  |  [localhost:~] you$ sudo pip uninstall tensorflow
17  |  [安装CPU计算框架的TensorFlow]
18  |  [localhost:~] you$ pip install tensorflow
19  |  [或者安装GPU计算框架的TensorFlow]
20  |  [localhost:~] you$ pip install tensorflow-gpu

(5)验证安装是否成功。

程序清单2-6 在Mac上安装Python库

21  |  [localhost:~] you$ python
22  |  >>> import numpy as np
23  |  >>> import scipy
24  |  >>> import pandas as pd
25  |  >>> import sklearn
26  |  >>> import matplotlib.pyplot as plt
27  |  >>> import statsmodels
28  |  >>> import tensorflow as tf
29  |  >>> [同时按下 Control和D退出Python返回终端]

4.安装IPython

IPython是一款基于Python的交互式解释器,能大大提高Python开发的效率。如果读者不理解交互式解释器这个名词,先不用担心,第2.3节将做详细的介绍。安装IPython的步骤如下。

程序清单2-6 在 Mac上安装Python库

30  |  [localhost:~] you$ pip install ipython
31  |  [localhost:~] you $ ipython
32  |  Python 2.7.13 (default, Jul 30 2016, 23:25:09)
33  |  Type "copyright", "credits" or "license" for more information.
34  |  
35  |  IPython 5.3.0 -- An enhanced Interactive Python.
36  |  ?         -> Introduction and overview of IPython's features.
37  |  %quickref -> Quick reference.
38  |  help      -> Python's own help system.
39  |  object?   -> Details about 'object', use 'object??' for extra details.
40  |  
41  |  In [1]: exit
42  |  [localhost:~] you$

同Mac相似,Anaconda也提供Linux版本。具体的安装步骤请参考Windows下的说明和随书配套的代码。

Linux的版本很多,但限于篇幅,这里只介绍在Ubuntu上的安装。下面的安装指南或许也能在其他版本的Linux上运行,但我们只在Ubuntu 14.04或者更高的版本上测试过这些安装步骤。

虽然Ubuntu有预装的Python,但版本比较陈旧,推荐安装较新版本的Python。

1.安装Python

(1)打开“搜索”,输入“terminal”,打开终端,如图2-10所示。

图2-10

(2)在“终端”里面输入并运行下面的命令。

程序清单2-7 在Ubuntu上安装Python

 1  |  [更新apt-get的下载列表]
 2  |  you@you:~$ sudo apt-get install software-properties-common
 3  |  [需要输入你的电脑密码]
 4  |  you@you:~$ sudo add-apt-repository ppa:fkrull/deadsnakes-python2.7
 5  |  you@you:~$ sudo apt-get update
 6  |  [使用apt-get下载最新版的Python2]
 7  |  you@you:~$ sudo apt-get install python2.7
 8  |  you@you:~$ python --version
 9  |  [安装的Python版本]

2.安装pip

pip是Python软件包管理系统,方便我们安装所需的第三方库。安装pip的步骤如下。

(1)打开“终端”。

(2)输入并运行如下代码。

程序清单2-8 在Ubuntu上安装pip

 1  |  [使用apt-get安装pip以及相应的依赖]
 2  |  you@you:~$ sudo apt-get install python-pip
 3  |  [升级pip到较新的版本]
 4  |  you@you:~$ sudo -H pip install --upgrade pip==9.0.1
 5  |  you@you:~$ pip --version
 6  |  'pip 9.0.1 from /usr/local/lib/python2.7/dist-packages (python 2.7)'

3.安装所需要的库

(1)打开“终端”,安装NumPy、SciPy、Matplotlib、pandas和Statsmodels。

程序清单2-9 在Ubuntu上安装Python库

 1  |  you@you:~$ sudo apt-get install python-numpy
 2  |  you@you:~$ sudo apt-get install python-scipy
 3  |  you@you:~$ sudo apt-get install python-matplotlib
 4  |  [下面这个命令将同时安装pandas和Statsmodels]
 5  |  you@you:~$ sudo apt-get install python-pandas

(2)上面所安装的Python库版本比较陈旧,请升级版本。

程序清单2-9 在Ubuntu上安装Python库

 6  |  you@you:~$ sudo -H pip install --upgrade numpyscipy matplotlib pandas statsmodels

(3)安装scikit-learn和TensorFlow。推荐读者安装CPU版本的TensorFlow。

程序清单2-9 在Ubuntu上安装Python库

 7  |  [预防编码错误]
 8  |  you@you:~$ export LC_ALL=C
 9  |  [安装scikit-learn]
10  |  you@you:~$ sudo -H pip install scikit-learn
11  |  [安装CPU计算框架的TensorFlow]
12  |  you@you:~$ sudo apt-get install python-dev
13  |  you@you:~$ sudo -H pip install tensorflow
14  |  [或者安装GPU计算框架的TensorFlow]
15  |  you@you:~$ sudo -H pip install tensorflow-gpu

(4)验证安装是否成功。

程序清单2-9 在Ubuntu上安装Python库

16  |  you@you:~$ python
17  |  >>> import numpy as np
18  |  >>> import scipy
19  |  >>> import pandas as pd
20  |  >>> import sklearn
21  |  >>> import matplotlib.pyplot as plt
22  |  >>> import statsmodels
23  |  >>> import tensorflow as tf
24  |  >>> [输入exit退出]

4.安装IPython

如同在Mac系统上一样,安装IPython,具体说明请参考2.2.2节。

程序清单2-9 在Ubuntu上安装Python库

25  |  you@you:~$ sudo -H pip install ipython
26  |  you@you:~$ ipython
27  |  Python 2.7.12 (default, Jul 18 2016, 23:25:09)
28  |  Type "copyright", "credits" or "license" for more information.
29  |  
30  |  IPython 5.3.0 -- An enhanced Interactive Python.
31  |  ?         -> Introduction and overview of IPython's features.
32  |  %quickref -> Quick reference.
33  |  help      -> Python's own help system.
34  |  object?   -> Details about 'object', use 'object??' for extra details.
35  |  
36  |  In [1]: exit
37  |  you@you:~$

现在,我们已经安装好Python了,是不是已经有点迫不及待想要试试它?下面让我们开始动手实践吧。

Python作为一款动态语言,通常有两种使用方法:可以把它当脚本解释器,运行已编辑好的程序脚本;同时Python提供一个实时交互的命令窗口(Python shell),可以在其中输入并运行任何Python语句,如图2-11所示。这让学习、调试和测试Python语句变得十分容易。

图2-11

如程序清单2-10所示,在终端(Linux或Mac)或者命令提示符(Windows)里输入“python”启动Python shell。

(1)可以在Python shell里面对变量赋值,然后对使用变量进行计算。而且只要不关闭shell,就可以一直使用这些变量。如第1~3行代码所示。值得注意的是,Python是所谓的动态类型语言,所以在变量赋值的时候不需要声明变量的类型。

(2)Python shell里面可以运行任意的Python语句,如第5行代码所示,因此甚至有人把它当作计算器。

(3)也可以在shell中导入并使用第三方库,如第7、8行代码所示。需要注意的是,如第7行代码所示,在导入第三方库“numpy”的同时可以给它取一个别名,如“np”。在后面需要使用“numpy”时,就用“np”代替,减少字符输入量。

(4)下面介绍3个特别实用的小技巧。

当对所使用的对象不是很熟悉时,这3个方法可以帮助我们迅速地了解它们。

程序清单2-10 Python shell

 1  |  >>> a = 1
 2  |  >>> b = 2
 3  |  >>> print a + b
 4  |  3
 5  |  >>> 10 / 2.0
 6  |  5
 7  |  >>> import numpy as np
 8  |  >>> np.max([1, 2, 3])
 9  |  3
10  |  >>> type(a)
11  |  <type 'int'>[a的类型]
12  |  >>> dir(np)
13  |  [np所有的类变量和方法]
14  |  >>> print np.max.__doc__
15  |  [np.max方法说明]
16  |  >>> help(np.max)
17  |  [np.max方法说明,按q键退出]

在之前的安装步骤中,我们安装了交互式解释器IPython。它与上面介绍的Python shell相似,但提供了更为强大的编辑和交互功能,比如自动补齐功能(Tab键)。类似地,在终端输入“ipython”就能启动它,推荐读者使用。

在以往的IT类书籍中,介绍一种编程语言的第一个程序都是“Hello World”。但本书针对数据科学,所以第一个Python程序也与时俱进地改为了大数据版的“Hello World”:“Word Count”。完整的程序脚本放在随书配套的代码/ch02-python/word_count.py。在终端里执行“python word_count.py”命令就可以运行这个程序了,下面让我们来仔细看看这个程序的代码。

程序清单2-11 Word Count

 1  |  # -*- coding: UTF-8 -*-
 2  |
 3  |  def wordCount(data):
 4  |      """
 5  |      输入一个字符串列表,统计列表中字符串出现的次数
 6  |
 7  |      参数
 8  |      ----
 9  |      data : list[str], 需要统计的字符串列表
10  |
11  |      返回
12  |      ----
13  |      re : dict, 结果hash表,key为字符串,value为对应的出现次数
14  |      """
15  |      re = {}
16  |      for i in data:
17  |          re[i] = re.get(i, 0) + 1
18  |      return re
19  |
20  |
21  |  if __name__ == "__main__":
22  |      data = ["ab", "cd", "ab", "d", "d"]
23  |      print "The result is %s" % wordCount(data)
24  |      # The result is {'ab': 2, 'd': 2, 'cd': 1}

(1)程序脚本的第一行表示这个脚本的编码为UTF-8。如果脚本需要用到中文字符,不要忘记在脚本开头加上这一句。

(2)程序清单2-11的第3~18行代码在定义wordCount函数。这个函数有一个参数“data”。正如前面介绍的,读者可以看到Python 不使用大括号,而使用缩进来定义语句块,如图2-12所示。因此在书写Python代码时,需要特别关注代码的对齐。这是为什么在程序员中流传着开发Python代码需要购买游标卡尺的说法。当然这只是个玩笑话,常见的开发工具如Vim、IPython、Spyder等都提供代码自动对齐功能。

图2-12

(3)函数名的下面是一个字符串,如第4~14行代码所示。它是函数的说明文档,记录着函数功能的描述,以及函数参数和返回值的定义。这个字符串虽然对函数功能没有任何影响,甚至可以不写,但它对Python程序工程化非常重要。假设你和小安是同事,在某个项目中,你需要调用小安开发的函数A。而小安在开发时为图简单,并没有给函数A写上说明文档。由于Python的语法规定一个函数在定义时,既不需要声明参数类型,也不需要定义返回值的个数和它们的类型,无法做静态类型检查。你沮丧地发现,即使通读一遍小安的源代码,也很难知晓如何使用这个函数,甚至不知道应该传送怎样的参数,会得到什么样的返回。于是,你要求小安按照如上面的格式补充说明文档。小安按要求修改后,你就可以在使用时,通过命令“A.__doc__”来阅读对应的说明文档(参考2.3.1节)。

(4)如果读者以前接触过其他编程语言(比如Java),会觉得奇怪:A不是一个函数么,为什么函数也有属性“__doc__”呢?这是Python的另外一个特性。在Python中,所有东西都是对象,连函数也是对象,所以A作为函数也有自己的属性。

(5)在函数说明文档下面,我们定义了一个空的dict类型变量“re”。dict类型可以翻译为字典类型,是Python的5个基本类型之一。现实中的字典里面记录了字和对应的解释。从结构上看,字典其实是一堆键值对(key value pair),字为键(key),而对应的解释为值(value)。而dict也一样,是一个键值对的集合。如果读者对数据结构比较了解,会发现dict其实就是一个Hash表。如果使用Python开发,就会发现dict十分灵活、实用。它也是作者最喜欢的数据类型。

(6)在Python中,dict的书写形式如下:用“{}”将所有值括起来,键与值之间用“:”隔空,键值对之间用“,”隔开,如第24行代码所示。

(7)在程序清单2-11里,我们使用“re”来记录word count的结果,即键为字符串,值为对应的出现次数。所以在定义完“re”之后,我们遍历“data”列表中的每一个字符串,并对“re”中对应的值加1(如果字符串x是第一次出现,则在“re”中插入键值对(x: 1))。

(8)程序清单2-11的第21~23行代码是脚本的测试部分。我们在这里创建了一个字符串列表,并将它传给定义好的函数wordCount。

(9)为什么说它是测试代码呢?正如第(4)点中提到的那样,在Python中,所有内容都是对象。脚本本身也被当作模板(modules)对象,而模板对象有一个内置属性“__name__”(值得注意的是,“name”前后也是双下划线)。这个属性的赋值依赖于用户怎么使用它:如果直接运行它,比如“python wordCount.py”,“wordCount.py”的“__name__”属性就等于“__main__”。如果把它作为库,在其他程序使用“import wordCount”时,wordCount.py的“__name__”属性就等于“wordCount”。因此大家常常使用这个技巧来做简单的测试,或者把它作为程序的主入口,比如Java中的main函数。

读到这里,希望读者已经能理解word_count.py中的Python代码了。下面将讨论更多Python编程的基础知识。

本小节将介绍Python的3个常用的基本数据类型:dict、list和tuple,Python特色的lambda表达式以及内置函数map、reduce和filter。

1.Python的基本数据类型

(1)dict类型在上一节已经见过。下面是它的基本操作代码展示。最好的学习方法就是动手实践,所以鼓励读者打开Python shell,跟着本书一起练习。

程序清单2-12 Python基本数据类型——dict

 1  |  # dict基本操作
 2  |  ## 初始化一个dict类型变量x
 3  |  >>> x = {"a": 1, "b": 2, "c": 3}
 4  |  >>> print x
 5  |  {'a': 1, 'c': 3, 'b': 2}
 6  |  >>>
 7  |  ## 读取x中的一个元素,直接读取或者使用”get方法
 8  |  >>> print x["a"], ",", x.get("a")
 9  |  1 , 1
10  |  ## 读取x中不存在的一个元素,注意直接读取会报错
11  |  >>> print x["d"]
12  |  Traceback (most recent call last):
13  |    File "<stdin>", line 2, in <module>
14  |  KeyError: 'd'
15  |  ## 使用”get方法返回None值;可以在”get方法中使用默认值
16  |  >>> print x.get("d")
17  |  None
18  |  >>> print x.get("d", "No such key")
19  |  No such key
20  |  >>>
21  |  ## 修改dict
22  |  >>> x["c"] = 4
23  |  ## 插入新的键值对
24  |  >>> x["d"] = "5"
25  |  >>> print x
26  |  {'a': 1, 'c': 4, 'b': 2, 'd': '5'}
27  |  ## 删除键值对
28  |  >>> del x["c"]
29  |  >>> print x
30  |  {'a': 1, 'b': 2, 'd': '5'}

(2)list就是列表类型,可以将任意元素放进一个列表里。

程序清单2-13 Python基本数据类型——list

 1  |  # list基本操作
 2  |  ## 初始化一个list类型变量y
 3  |  >>> y = ["A", "B", "C", "a", "b", "c"]
 4  |  >>> print y
 5  |  ['A', 'B', 'C', 'a', 'b', 'c']
 6  |  >>>
 7  |  ## 读取y中的元素
 8  |  >>> print y[0]
 9  |  A
10  |  >>> print y[-1]
11  |  c
12  |  >>> print y[0: 3]
13  |  ['A', 'B', 'C']
14  |  ## 查找y中的元素
15  |  >>> print y.index("a")
16  |  3
17  |  >>>
18  |  ## 修改list
19  |  >>> y[0] = 4
20  |  >>> print y
21  |  [4, 'B', 'C', 'a', 'b', 'c']
22  |  ## 在y的最后面插入新元素
23  |  >>> y.append(5)
24  |  >>> print y
25  |  [4, 'B', 'C', 'a', 'b', 'c', 5]
26  |  ## 在指定位置插入新元素
27  |  >>> y.insert(3, "new")
28  |  >>> print y
29  |  [4, 'B', 'C', 'new', 'a', 'b', 'c', 5]
30  |  ## 两个list合并,注意和append的区别
31  |  >>> print y + ["d", "e"]
32  |  [4, 'B', 'C', 'new', 'a', 'b', 'c', 5, 'd', 'e']
33  |  >>> y.append(["d", "e"])
34  |  >>> print y
35  |  [4, 'B', 'C', 'new', 'a', 'b', 'c', 5, ['d', 'e']]
36  |  ## 删除y里面的元素
37  |  >>> y.remove("B")
38  |  >>> print y
39  |  [4, 'C', 'new', 'a', 'b', 'c', 5, ['d', 'e']]

(3)tuple也称为元祖类型,与列表功能非常相似,不同之处是元祖里面的元素不能被修改。

程序清单2-14 Python基本数据类型——tuple

 1  |  # tuple基本操作
 2  |  ## 初始化一个tuple类型变量z
 3  |  >>> z = ("a", "b", "c", "d", "e")
 4  |  >>> print z
 5  |  ('a', 'b', 'c', 'd', 'e')
 6  |  >>>
 7  |  ## 读取z中的元素,与list类似
 8  |  >>> print z[0]
 9  |  a
10  |  >>> print z[-1]
11  |  e
12  |  >>> print z[0: 3]
13  |  ('a', 'b', 'c')

2.lambda表达式和内置函数map、reduce、filter

在Python中,lambda表达式类似于函数。它以关键字“lambda”开头,之后就是函数的参数列表,并以“:”结尾。紧接着就是表达式主体,整个只是一行语句。这样说可能很抽象,我们来看下面这个具体的例子。比如下面的f和g是等价的。f是普通定义的函数,而g是lambda表达式。

程序清单2-15 lambda表达式和常用内置函数

 1  |  >>> def f(a, b):
 2  |  ...     return a + b
 3  |  ...
 4  |  >>> print f(1, 2)
 5  |  3
 6  |  >>> g = lambda x, y: x + y
 7  |  >>> print g(1, 2)
 8  |  3

有的读者可能会有疑问,既然g与函数f等价,那什么时候会用到lambda表达式呢?答案是创建匿名函数时。我们先看下面这个例子:

程序清单2-15 lambda表达式和常用内置函数

 9  |  ## 内置map函数和lambda表达式
10  |  ## l是一个05的列表
11  |  >>> l = range(6)
12  |  >>> print l
13  |  [0, 1, 2, 3, 4, 5]
14  |  ## 下面的操作将生成一个新的列表,列表里面的元素为l里元素加1
15  |  >>> def addOne(data):
16  |  ...     re = []
17  |  ...     for i in data:
18  |  ...         re.append(i + 1)
19  |  ...     return re
20  |  ...
21  |  >>>
22  |  >>> print addOne(l)
23  |  [1, 2, 3, 4, 5, 6]
24  |  ## 通过内置的map函数和lambda表达式可以达到同样的效果
25  |  >>> print map(lambda x: x + 1, l)
26  |  [1, 2, 3, 4, 5, 6]
27  |  ## 达到同样功能的列表生成式
28  |  >>> print [i + 1 for i in l]
29  |  [1, 2, 3, 4, 5, 6]

内置的map函数有两个参数,第一个是一个函数;第二个是一个可遍历的对象,比如list、tuple和dict等。map函数将第二个参数里的每个元素依次传给作为第一个参数的函数,并将函数的返回值依顺序组成一个列表。

如第25行代码所示,map函数将“l”里面的每一个数字按顺序传给lambda表达式,得到加1后的值。并将这些值依次插入结果列表里面。计算过程和上面第15~19行代码定义的addOne函数一样。

在第25行代码中,lambda表达式就定义了一个匿名函数,因为它起到了函数的功能,但又没有任何标识符来代表它,所以很形象地被命令为匿名函数。

上面的第28行代码是一种很简洁的书写方式,被称为“列表生成式”。在实际的Python开发中,应用也特别广泛。对于第一次接触Python的读者来说,这样的书写方式显得怪怪的。不过慢慢地,你就会发现它的好处并爱上它。比如下面的这个例子。

程序清单2-15 lambda表达式和常用内置函数

30  |  ## 计算l中每个元素的两倍和平方,并将两种组成一个列表
31  |  ## lambda表达式和Python函数一样,也可以接受函数作为参数
32  |  >>> twoTimes = lambda x: x * 2
33  |  >>> square = lambda x: x ** 2
34  |  >>> print [map(lambda x: x(i), [twoTimes, square]) for i in l]
35  |  [[0, 0], [2, 1], [4, 4], [6, 9], [8, 16], [10, 25]]

一行Python语句就搞定了,是不是很方便呢?最后,我们来看看filter和reduce的用法。

程序清单2-15 lambda表达式和常用内置函数

36  |  ## 内置filter函数,选择l中的偶数
37  |  >>> filter(lambda x: x % 2 == 0, l)
38  |  [0, 2, 4]
39  |  ## 内置reduce函数,计算l的和
40  |  >>> reduce(lambda accumValue, newValue: accumValue + newValue, l, 0)
41  |  15

filter函数和map函数非常相似。只不过filter函数是用来做筛选的。它会根据作为第1个参数的函数返回值来剔除掉返回值为0的元素。而reduce函数是用来做聚合运算的。以上面的代码为例,第1个参数是相加函数,第2个参数是需要求和的列表“l”,第3个(可选)参数为初始值0。

以上就是Python编程的基础知识。

本节将讨论Python项目的工程结构。这部分内容对初学者来讲,可能比较抽象。如果读者发现下面的文字生涩难懂,可先跳过此节,这并不影响本书其他章节的阅读。

假设小安已经开发好了一些脚本,并把它们放在某个文件目录下。现在,作为读者的你在开发新项目的时候,希望能像使用NumPy这种第三方库一样复用之前的代码。这应该如何实现呢?答案是创建充满“魔力”的__init__.py文件。具体来看下面这个例子[4]

首先创建一个mini_project的目录,下面有两个子目录:components和tests。而components下面有两个Python脚本,即counter.py和selecter.py,如图2-13a所示。

(1)在counter.py脚本中定义了wordCount函数。

(2)在selecter.py中定义了getFrequentItem函数。这个函数依赖于上面提到的wordCount函数,因此在脚本的开头部分使用如下命令来导入它:

1 |  from mini_project.components.counter import wordCount

(3)tests/test_selecter.py是程序的入口,也就是将被直接运行的脚本,这个脚本会调用getFrequentItem函数。类似地,在此脚本开头导入getFrequentItem。

1 |  from mini_project.components.selecter import getFrequentItem

如果这时使用“python test_selecter.py”命令来运行程序,将会得到如下的错误提示:

1 |  ImportError: No module named mini_project.components.selecter

这是因为Python并没有将目录mini_project当成一个可以使用的程序库,所以导入失败。想要修复这个bug,只需如图2-13b一样在各个目录下创建一个空的__init__.py文件。

(a)                        (b)
图2-13

从本质上讲,Python的库其实就是一个包含__init__.py文件的目录。__init__.py定义了这个库的属性和方法。当我们使用import命令导入一个库时,其实是在导入__init__.py这个文件。通常情况下,不需要在它里面定义任何内容,只需一个空文件即可,Python会自动按默认设置处理。但如果没有这个文件,Python就不会把对应目录当作第三方库,我们也就没办法导入和使用它了。

另外值得提醒的是,当要导入一个库时,需要确保它对应的目录在系统路径下可见。说得通俗一点就是在“sys.path”下面能找到对应的库目录。如果没有,则需要将相应的路径加到“sys.path”里(读者有没有发现,“sys.path”其实就是一个list。)。

本章我们介绍了数据科学的常用IT工具——Python和相关的第三方开源库,主要内容包括安装指南、编程基础和Python的工程结构。

本章的目的是让大家对Python有大致的了解,为后面的章节做准备。不知道你是否已达到这个目的?如果你仍有疑惑,不必担心,在之后的章节里,我们会结合具体例子讲解更多Python语言的细节,不断地重复和动手练习。相信读者在读完本书后,能比较熟练地使用Python。

当然Python编程还有很多内容,本书并不是Python编程教程,所以这里就不做更多的介绍。有兴趣的读者可以阅读其他Python书籍,比如Dive into Python

[1] 关系型数据库(Relational Database),用比较学术的语言表述:它是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。关系型数据库从直观上来看,它用二维网状表来表示数据,有点类似于数学中的矩阵,每一行表示一个个体,每一列表示一个属性。在实践中,常用的标准数据查询语言SQL来操作关系型数据库里的数据。比较常见的数据库有Oracle、DB2、MSSQL等。

Apache Hadoop是一款开源的分布式数据系统。它包括资源管理、存储和计算3部分,支持在大型计算机集群上运行应用程序。目前,Hadoop已形成一个强大的“生态圈”,是流行较广的大数据储存和处理软件。

Linux是一款开源的操作系统,它的作用与Windows类似,是管理计算机硬件与软件资源的计算机程序。由于Linux的开放性,是目前使用最为广泛的操作系统,特别是远程服务器和其他大型平台上。比如世界上前500台速度最快的超级计算机90%以上运行类Linux系统。

以上简介均参考自维基百科。

[2] 引自维基百科。

[3] 具体网址和步骤请参考随书配套的代码/ch02-python/python安装补充说明.html。

[4] 完整的实现请参考随书配套的代码/ch02-python/mini_project/。


相关图书

ChatGPT原理与应用开发
ChatGPT原理与应用开发
深度学习的数学——使用Python语言
深度学习的数学——使用Python语言
深度学习:从基础到实践(上、下册)
深度学习:从基础到实践(上、下册)
动手学深度学习(PyTorch版)
动手学深度学习(PyTorch版)
深度学习与医学图像处理
深度学习与医学图像处理
深度强化学习实战:用OpenAI Gym构建智能体
深度强化学习实战:用OpenAI Gym构建智能体

相关文章

相关课程