书名:Python 3破冰人工智能:从入门到实战
ISBN:978-7-115-50496-8
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
著 黄海涛
责任编辑 张 爽
人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
读者服务热线:(010)81055410
反盗版热线:(010)81055315
本书创新性地从数学建模竞赛入手,深入浅出地讲解了人工智能领域的相关知识。本书内容基于Python 3.6,从人工智能领域的数学出发,到Python在人工智能场景下的关键模块;从网络爬虫到数据存储,再到数据分析;从机器学习到深度学习,涉及自然语言处理、机器学习、深度学习、推荐系统和知识图谱等。
此外,本书还提供了近140个代码案例和大量图表,全面系统地阐述了算法特性,个别案例算法来自于工作经验总结,力求帮助读者学以致用。
本书不仅适用于人工智能技术初学者,也适合具有一定经验的技术人员阅读,还可作为高等院校计算机等相关专业师生的参考用书。
2017年7月8日,国务院发布《新一代人工智能发展规划》,正式开启国内人工智能发展的新篇章。同年12月14日,工业和信息化部印发《促进新一代人工智能产业发展三年行动计划(2018-2020年)》的通知,明确提出要推动人工智能和实体经济深度融合,加快制造强国和网络强国建设。
“识时务者为俊杰”。人工智能蓬勃发展,要想在互联网的浪潮下立于不败之地,就必须了解当前的行业现状,不断追求新的技术方法,完善自己的专业技能,才能为胜任工作做好准备。
目前,人工智能人才供不应求,人工智能从业者薪资水平居IT行业前列,众多从业者也在考虑转行AI。虽然谁都想赶上AI的风口,但是好的学习样本并不多。本书恰似指路明灯,为读者照亮人工智能初学之路。它不仅讲知识,而且注重传授经验,既有学习计划,又侧重实战。
“不登高山,不知天之高”。一个人无论技术能力高低,都应以“满招损,谦受益”的求学态度,不断完善自己的知识储备。达尔文曾说过:“最有价值的知识是关于方法的知识。”本书是基于作者学习与工作经验总结而成的,构建了系统全面的人工智能学习结构。希望读者通过阅读本书,能够在寻找答案和方法的过程中,得到能力上的提升。这也是出版本书的意义。
黄海涛
2018年秋
作者在读本科和硕士期间,经常参加全国数学建模竞赛,而且成绩还不错,于是在闲暇之余,创建了一个数学建模交流网站,方便大家学习交流。网站创立至今,网友问得最多的都是数学建模方面的基础问题,而最受欢迎的答案,是来自实战的案例。
这是一本人工智能技术书籍,我是如何确定目标受众(Who)是哪些人,如何定位(What)本书内容的呢?
目标受众(Who)主要是哪些人?
我的老家在东北,每次回去,村里人都会问我:“在北京做什么工作呢?”当我第一次回答“人工智能”时,看到的是他们不解的神情;后来我说“数据”,他们好像懂了一些,之后说“互联网”,嗯嗯……这下他们就明白了。
真是隔行如隔山!这种现象深深地印在我的脑海里,于是我在动笔之前,明确了本书的受众是对人工智能感兴趣的读者。无论你是否从事人工智能相关工作,均可阅读。本书内容全面,并辅以大量图表,不同岗位、不同水平的读者通过阅读本书都会有不同程度的收获。
如何定位(What)这本书的内容?
本书是一本实战型人工智能技术书籍。其中,人工智能部分涉及数学知识、Python和算法。实战,指的是网络爬虫、数据储存、数据分析、自然语言处理、机器学习、推荐系统、深度学习部分的内容。
书中的每一章都提供了足够的数学知识和代码示例,帮助读者理解和掌握同深度的知识点,并更好地掌握其他知识点。
Python作为一种高级程序设计语言,凭借其简洁、易读及可扩展性,日渐成为程序设计领域备受推崇的语言,并成为人工智能背景下的首选语言之一。
本书基于Python 3.6构建了近140个代码案例,系统全面、循序渐进地介绍了Python在人工智能各方面的应用。本书主要包含以下四部分。
第一部分为从零认识AI:第1章,创新性地从数学建模竞赛角度介绍人工智能,同时简述了人工智能涉及的主要数学知识。
第二部分为入门AI做准备:第2~4章,循序渐进地讲解了AI工程中重要的Python常用模块,提取语言精要,进行有针对性的学习。
第三部分为Python基础实战:第5~7章,分别阐述了网络爬虫(线程、进程、协程)、数据库存储(SQL与NoSQL)和数据分析,帮助读者为进一步学习AI知识做好准备。
第四部分为实战部分:第8~14章,首先以自然语言处理(分词、关键词提取、词向量、word2vec)作为开篇;接着以4种基本的机器学习算法为例,阐述算法特性;然后介绍了算法的主要应用场景—推荐系统,以及协同过滤与知识图谱在推荐系统中的应用;最后以深度学习框架TensorFlow入门知识作为本书的结束。
本书内容结构清晰,示例完整,涵盖数学基础、编程语言、算法应用。无论是人工智能领域的新手,还是经验丰富的编程老手,都将从中获益。
由于作者水平有限,书中难免有错误和不当之处,欢迎读者指正,来函请发至作者邮箱hhtnan@163.com或本书编辑邮箱zhangshuang@ptpress.com.cn,我将不胜感激。如果读者遇到问题需要帮助,也欢迎交流(QQ:451005528),我期望与你共同成长。
感谢我的妻子李宝玲在本书编写过程中提供的大力支持!感谢数学博士冯真真对于本书部分数学翻译工作的支持。感谢我的父母,感谢他们的辛勤付出!感恩我遇到的众多良师益友!
本书由异步社区出品,社区(https://www.epubit.com/)为您提供相关资源和后续服务。
作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。
当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,点击“提交勘误”,输入勘误信息,单击“提交”按钮即可。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。
我们的联系邮箱是contact@epubit.com.cn。
如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。
如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/ selfpublish/submission即可)。
如果您是学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。
如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。
“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT技术图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT技术图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。
“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。
异步社区
微信服务号
为什么要把数学建模与当今火热的人工智能放在一起?
首先,数学建模在字面上可以分解成数学+建模,即运用统计学、线性代数和积分学等数学知识,构建算法模型,通过模型来解决问题。数学建模往往是没有对与错,只有“更好”(better),就好像让你评价两个苹果哪个更好吃,只有好吃、不好吃或者更好吃,没有对与错。
人工智能(Artificial Intelligence, AI),你可以将其理解为是一种“黑科技”,人类通过它,让计算机能够“更好”地像人一样思考。可以说“算法模型”是人工智能的“灵魂”,没有算法模型,一切都是“水中月”“镜中花”!
因此,本书将从数学建模入手,由浅入深地为读者揭开AI的神秘面纱。
数学建模是利用数学方法解决实际问题的一种实践。即通过抽象、简化、假设、引进变量等处理过程,将实际问题用数学方式表达,建立起数学模型,然后运用先进的数学方法及计算机技术进行求解。数学建模可以通俗地理解为数学+建模,即运用统计学、线性代数,积分学等数学知识,构建数学模型,通过模型解决问题。
按照传统定义,数学模型是对于一个现实对象,为了一个特定目的(实际问题),做出必要的简化假设(模型假设),根据对象的内在规律(业务逻辑、数据特征),运用适当的数学工具、计算机软件,得到的一个数学结构。
亚里士多德说,“智慧不仅仅存在于知识之中,而且还存在于应用知识的能力中”。数学建模就是对数学知识最好的应用,通过数学建模,你会发现,生活中很多有意思的事情都可以靠它来解决,其流程如图1-1所示。
▲图1-1 数学建模流程
对于普通大众来说,可能是近些年才对其有所了解,其实人工智能在几十年以前就被学者提出并得到一定程度的发展,伴随着大数据技术的迅猛发展而被引爆。
(1)人工智能的诞生
最初的人工智能其实是20世纪30至50年代初一系列科学研究进展交汇的产物。1943年,沃伦·麦卡洛克(Warren McCulloch)和瓦尔特·皮茨(Walter Pitts)首次提出“神经网络”概念。1950年,阿兰·图灵(Alan Turing)提出了著名的“图灵测试”,即如果一台机器能够与人类展开对话(通过电传设备)而不能被辨别出其机器身份,那么称这台机器则具有智能。直到如今,图灵测试仍然是人工智能的重要测试手段之一。1951年,马文·明斯基(Marvin Minsky)与他的同学一起建造了第一台神经网络机,并将其命名为 SNARC(Stochastic Neural Analog Reinforcement Calculator)。不过,这些都只是前奏,一直到1956年的达特茅斯会议,“Artificial Intelligence”(人工智能)这个词才被真正确定下来,并一直沿用至今,这也是目前AI诞生的一个标志性事件。
▲图1-2 达特茅斯会议参会者50年后聚首照[1]
在20世纪50年代,人工智能相关的许多实际应用一般是从机器的“逻辑推理能力”开始着手研究。然而对于人类来说,更高级的逻辑推理的基础是“学习能力”和“规划能力”,我们现在管它叫“强化学习”与“迁移学习”。可以想象,“逻辑推理能力”在一般人工智能系统中不能起到根本的、决定性的作用。当前,在数据、运算能力、算法模型、多元应用的共同驱动下,人工智能的定义正从用计算机模拟人类智能,演进到协助引导提升人类智能,如图1-3所示。
▲图1-3 下一代人工智能(图片来源《新一代人工智能发展白皮书》)
(2)人工智能的概念
人工智能(Artificial Intelligence),英文缩写为AI,它是研究开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的“容器”,也可能超过人的智能。
(3)人工智能、机器学习、深度学习
下面我们来介绍下主要与人工智能相关的几个概念,要搞清它们的关系,最直观的表述方式就是同心圆,如图1-4所示,最先出现的是理念,然后是机器学习,当机器学习繁荣之后就出现了深度学习,今天的人工智能大爆发是由深度学习驱动的。
▲图1-4 AI、机器学习、深度学习的关系
人工智能(AI)、机器学习(ML)、深度学习(DL)的关系为DL⊆ML⊆AI。
人工智能,即AI是一个宽泛的概念,人工智能的目的就是让计算机能够像人一样思考。机器学习是人工智能的分支,它是人工智能的重要核心,是使计算机具有智能的根本途径,其应用遍及人工智能的各个领域。深度学习是机器学习研究中的一个新领域,推动了机器学习的发展,并拓展了人工智能的领域范围。甚至有观点认为,深度学习可能就是实现未来强AI的突破口。
可以把人工智能比喻成孩子大脑,机器学习是让孩子去掌握认知能力的过程,而深度学习是这个过程中很有效率的一种教学体系。
因此可以这样概括:人工智能是目的、结果;深度学习、机器学习是方法、工具。
本书讲解了人工智能、机器学习、深度学习的相关应用,它们之间的关系,常见的机器学习算法等知识,希望你通过对本书的学习,深刻理解这些概念,并可以轻而易举地给别人讲解。
无论是数学建模还是人工智能,其核心都是算法,最终的目的都是通过某种形式来更好地为人类服务,解决实际问题。在研究人工智能过程中需要数学建模思维,所以数学建模对于人工智能非常关键。
下面通过模拟一个场景来了解人工智能与数学建模之间的关系。
某患者到医院就诊,在现实生活中,医生根据病人的一系列体征与症状,判断病人患了什么病。医生会亲切地询问患者的症状,通过各种专项检查,最后进行确诊。在人工智能下,则考虑通过相应算法来实现上述过程,如德国的辅助诊断产品Ada学习了大量病例来辅助提升医生诊病的准确率。
情景①:如果用数学建模方法解决,那么就通过算法构建一个恰当的模型,也就是通过图1-1所示的数学建模流程来解决问题。
情景②:如果用人工智能方法解决,那么就要制造一个会诊断疾病的机器人。机器人如何才能精准诊断呢?这就需要利用人工智能技术手段,比如采用一个“人工智能”算法模型,可能既用了机器学习算法,也用了深度学习算法,不管怎样,最终得到的是一个可以落地的疾病预测人工智能解决方案。让其具有思考、听懂、看懂、逻辑推理与运动控制能力,如图1-5所示。
▲图1-5 AI机器人
通过上面的例子可以看出,人工智能离不开数学建模。在解决一个人工智能的问题过程中,我们将模型的建立与求解进行了放大,以使其结果更加精准,如图1-6所示。
▲图1-6 AI下对数学建模的流程修正
可见,从数学建模的角度去学习人工智能不失为一种合适的方法。
美国数学建模竞赛(Mathematical Contest in Modeling,MCM)从1985年开始一直发展至今。中国大学生数学建模竞赛开展也有20余年,已逐渐成熟起来。下面我们通过历年赛题来了解到底什么是数学建模,数学建模可以解决哪些问题,如表1-1所示。
表1-1 数学建模竞赛题目
年份 | 赛题 | 题目 | 题目简述 |
---|---|---|---|
1998 | A | 投资的收益和风险 | 市场上面有n种投资,某公司如何投资 |
B | 灾情巡视路线 | 某地受灾,给出最佳巡视路线 | |
1999 | A | 自动化车床管理 | 连续加工零件,检查是否出现故障 |
B | 钻井布局 | 勘探部门在某地区找矿,如何利用旧井节约费用 | |
2000 | A | DNA序列分类问题 | 分析生老病死及遗传进化的DNA信息 |
B | 钢管订购和运输问题 | 铺设一条天然气的主管路,使费用最小 | |
2001 | A | 血管三维重建 | 计算管道的中轴线与半径 |
B | 公交车调度 | 设计便于操作的全天的公交车调度方案 | |
2002 | A | 车灯线光源的优化设计 | 在某一设计规范标准下确定线光源的长度 |
B | 彩票中的数学 | 分析彩票吸引彩民的因素,并构建新的彩票算法 | |
2003 | A | SARS的传播 | 搜集SARS数据,建立数学模型进行预测 |
B | 露天矿生产的车辆安排 | 计算出一个班次生产计划的快速算法 | |
2004 | A | 奥运会临时超市网点设计 | 合理设计奥运会临时超市的网点位置 |
B | 电力市场的输电阻塞管理 | 核心为输电阻塞的电力市场交易与调度一体化管理 | |
2005 | A | 长江水质的评价和预测 | 对长江近两年多的水质情况做出定量的综合评价 |
B | DVD在线租赁 | DVD预测、购买和分配 | |
2006 | A | 出版社的资源配置问题 | 合理分配出版社资源达到利润最大化 |
B | HIV病毒问题 | 预测HIV病毒治疗效果 | |
2007 | A | 中国人口增长预测 | 预测人口增长的中短期和长期趋势 |
B | 乘公交,看奥运 | 公交线路选择问题 | |
2008 | A | 数码相机定位 | 建立并给出两部固定相机相对位置的数学模型和算法 |
B | 高等教育学费标准探讨 | 对几类学校或专业的学费标准定量分析 | |
2009 | A | 制动器试验台的控制方法分析 | 电动机驱动电流的计算机控制方法 |
B | 眼科病床的合理安排 | 评价病床安排模型的优劣 | |
2010 | A | 储油罐的变位识别与罐容表标定 | 储油罐的变位识别与罐容表标定方法 |
B | 2010年上海世博会影响力的定量评估 | 建立数学模型,定量评估2010年上海世博会的影响力 | |
2011 | A | 城市表层土壤重金属污染分析 | 城市表层土壤重金属污染分析 |
B | 交巡警服务平台的设置与调度 | 巡警服务平台警力合理的调度方案 | |
2012 | A | 葡萄酒的评价 | 对葡萄酒质量的判别 |
B | 太阳能小屋的设计 | 光伏电池的优化铺设 | |
2013 | A | 车道被占用对城市道路通行能力的影响问题 | 分析突发事故对道路通行能力的影响 |
B | 碎纸片拼接复原问题 | 建立碎纸片拼接复原模型和算法 | |
2014 | A | 嫦娥三号软着陆轨道设计与控制策略 | 确定嫦娥三号在6个阶段的最优控制策略。 |
B | 创意平板折叠桌 | 折叠桌数学描述及设计 | |
2015 | A | 太阳影子定位 | 分析太阳影子变化,确定视频拍摄的地点和日期 |
B | “互联网+”时代的出租车资源配置 | 分析租车供求匹配,设计补贴方案并论证合理性 | |
2016 | A | 系泊系统的设计 | 设计算法,获得满意的系泊系统设计方案 |
B | 小区开放对道路通行的影响 | 小区道路开放对缓解交通拥堵压力的评估 | |
2017 | A | CT系统参数标定及成像 | CT系统安装存在误差,通过算法缩小误差,提高精度 |
B | 拍照赚钱任务定价 | App用户领取拍照任务,分析任务定价规律 | |
2018 | A | 高温作业专用服装设计 | 利用数学模型来确定假人皮肤外侧的温度变化情况 |
B | 智能RGV动态调度策略 | 通过数学模型对一个智能加工系统做动态调度策略 |
通过表1-1可以看出,数学建模竞赛中需要通过数学建模解决的问题涉及互联网、医疗、交通等多方面,下面选取部分题目,从常见问题进行更加深入的剖析。
分类问题解决的是目标对象属于哪个预定义的类。举个例子,判断一条评论是好评还是差评就是一个分类问题。
分类,是数学建模中最常用的方法之一,分类一般分为二分类(二值问题)或者是多分类问题。
2000年全国大学生数学建模竞赛A题就是一个典型的分类问题,原题目如下。
2000年A题 DNA序列分类
2000年6月,人类基因组计划中DNA全序列草图完成,预计2001年可以完成精确的全序列图,此后人类将拥有一本记录着自身生老病死及遗传进化的全部信息的“天书”。这本大自然写成的“天书”是由4个字符——A、T、C和G——按一定顺序排成的长约30亿字符的序列,其中没有“断句”也没有标点符号,除了这4个字符表示4种碱基以外,人们对它包含的“内容”知之甚少,难以读懂。破译这部世界上最巨量信息的“天书”是21世纪人类最重要的任务之一。研究DNA全序列结构,以及这4个字符排成的看似随机的序列中隐藏着的规律,是解读这部天书的基础,是生物信息学(Bioinformatics)最重要的课题之一。
虽然人类对这部“天书”知之甚少,但也发现了DNA序列中的一些规律性和结构。例如,在全序列中有一些用于编码蛋白质的序列片段,即由这4个字符组成的64种不同的3字符串,其中大多数用于编码构成蛋白质的20种氨基酸。又例如,在不用于编码蛋白质的序列片段中,A和T的含量特别多,于是以某些碱基特别丰富作为特征去研究DNA序列的结构也取得了一些结果。此外,利用统计的方法还发现序列的某些片段之间具有相关性,等等。这些发现让人们相信,DNA序列中存在着局部的和全局性的结构,充分发掘序列的结构对理解DNA全序列是十分有意义的。目前,在这项研究中最普通的思想是省略序列的某些细节,突出特征,然后将其表示成适当的数学对象。这种被称为粗粒化和模型化的方法,往往有助于研究规律性和结构。
作为研究DNA序列的结构的尝试,提出以下对序列集合进行分类的问题。
(1)下面有20个已知类别的人工制造的序列(见下页),其中序列标号1~10为A类,11~20为B类。请从中提取特征,构造分类方法,并用这些已知类别的序列,衡量你的方法是否足够好。然后用你认为满意的方法,对另外20个未标明类别的人工序列(标号21~40)进行分类,用序号(按从小到大的顺序)标明结果的类别(无法分类的不写入):
A类 ;B类 。
请详细描述你的方法,给出计算程序。如果你使用了某些现成的分类方法,也要将方法名称准确注明。
(2)在数据文件Nat-model-data 中给出了182个自然DNA序列,它们都较长。用你的分类方法对它们进行分类,并给出分类结果。
提示:衡量分类方法优劣的标准是分类的正确率。构造分类方法有许多途径,例如提取序列的某些特征,给出它们的数学表示:几何空间或向量空间的元素等,然后再选择或构造适合这种数学表示的分类方法;又例如构造概率统计模型,然后用统计方法分类。
以2005年全国大学生数学建模竞赛A题《长江水质的评价和预测》为例,这是一个典型的评价问题,原题目如下。
2005年A题 长江水质的评价和预测
水是人类赖以生存的资源,保护水资源就是保护我们自己,对于我国大江大河水资源的保护和治理应是重中之重。专家们呼吁:“以人为本,建设文明和谐社会,改善人与自然的环境,减少污染。”
长江是我国第一、世界第三大河流,长江水质的污染程度日趋严重,已引起了相关政府部门和专家们的高度重视。2004年10月,由全国政协与中国发展研究院联合组成“保护长江万里行”考察团,从长江上游宜宾到下游上海,对沿线21个重点城市做了实地考察,揭示了一幅长江污染的真实画面,其污染程度让人触目惊心。为此,专家们提出“若不及时拯救,长江生态10年内将濒临崩溃”,并发出了“拿什么拯救癌变长江”的呼唤。
附件3给出了长江沿线17个观测站(地区)近两年多主要水质指标的检测数据,以及干流上7个观测站近一年多的基本数据(站点距离、水流量和水流速)。通常认为一个观测站(地区)的水质污染主要来自于本地区的排污和上游的污水。一般说来,江河自身对污染物都有一定的自然净化能力,即污染物在水环境中通过物理降解、化学降解和生物降解等,使水中污染物的浓度降低。反映江河自然净化能力的指标被称为降解系数。事实上,长江干流的自然净化能力可以认为是近似均匀的,根据检测可知,主要污染物高锰酸盐指数和氨氮的降解系数通常介于0.1~0.5之间,比如可以考虑取0.2(单位:L/天)。附件4是“1995~2004年长江流域水质报告”给出的主要统计数据。下面的附表是国标(GB3838-2002)给出的《地表水环境质量标准》中4个主要项目标准限值,其中Ⅰ、Ⅱ、Ⅲ类为可饮用水。
请你们研究下列问题。
(1)对长江近两年多的水质情况做出定量的综合评价,并分析各地区水质的污染状况。
(2)研究、分析长江干流近一年多主要污染物高锰酸盐指数和氨氮的污染源主要在哪些地区?
(3)假如不采取更有效的治理措施,依照过去10年的主要统计数据,对长江未来水质污染的发展趋势做出预测分析,比如研究未来10年的情况。
(4)根据你的预测分析,如果未来10年内每年都要求长江干流的Ⅳ类和Ⅴ类水的比例控制在20%以内,且没有劣Ⅴ类水,那么每年需要处理多少污水?
(5)你对解决长江水质污染问题有什么切实可行的建议和意见。
2006年全国大学生数学建模竞赛B题《艾滋病疗法的评价及疗效的预测》,这是一个典型的预测问题,原题目如下。
2006年B题 艾滋病疗法的评价及疗效的预测
艾滋病是当前人类社会最严重的瘟疫之一,从1981年发现以来的20多年间,它已经吞噬了近3000万人的生命。
艾滋病的医学全名为“获得性免疫缺损综合症”,英文简称AIDS,它是由艾滋病毒(医学全名为“人体免疫缺损病毒”,英文简称HIV)引起的。这种病毒破坏人的免疫系统,使人体丧失抵抗各种疾病的能力,从而严重危害人的生命。人类免疫系统的CD4细胞在抵御HIV的入侵中起着重要作用,当CD4被HIV感染而裂解时,其数量会急剧减少,HIV将迅速增加,导致AIDS发作。
艾滋病治疗的目的,是尽量减少人体内HIV的数量,同时产生更多的CD4,至少要有效地降低CD4减少的速度,以提高人体免疫能力。
迄今为止,人类还没有找到能根治AIDS的疗法,目前的一些AIDS疗法不仅对人体有副作用,而且成本也很高。许多国家和医疗组织都在积极试验、寻找更好的AIDS疗法。
现在得到了美国艾滋病医疗试验机构ACTG公布的两组数据。ACTG320(见附件1)是同时服用zidovudine(齐多夫定)、lamivudine(拉美夫定)和indinavir(茚地那韦)3种药物的300多名病人每隔几周测试的CD4和HIV的浓度(每毫升血液里的数量)。193A(见附件2)是将1300多名病人随机地分为4组,每组按下述4种疗法中的一种服药,大约每隔8周测试的CD4浓度(这组数据缺HIV浓度,它的测试成本很高)。4种疗法的日用药分别为:600mg zidovudine或400mg didanosine(去羟基苷),这两种药按月轮换使用;600 mg zidovudine加2.25 mg zalcitabine(扎西他滨);600 mg zidovudine加400 mg didanosine;600 mg zidovudine加400 mg didanosine,再加400 mg nevirapine(奈韦拉平)。
请你完成以下问题。
(1)利用附件1的数据,预测继续治疗的效果,或者确定最佳治疗终止时间(继续治疗指在测试终止后继续服药,如果认为继续服药效果不好,则可选择提前终止治疗)。
(2)利用附件2的数据,评价4种疗法的优劣(仅以CD4为标准),并对较优的疗法预测继续治疗的效果,或者确定最佳治疗终止时间。
(3)艾滋病药品的主要供给商对不发达国家提供的药品价格如下:600mg zidovudine 1.60美元,400mg didanosine 0.85美元,2.25 mg zalcitabine 1.85美元,400 mg nevirapine 1.20美元。如果病人需要考虑4种疗法的费用,对(2)中的评价和预测(或者提前终止)有什么改变。
旅行商问题(Traveling Salesman Problem,TSP),是数学领域中的著名问题之一。2015全国研究生数学建模竞赛F题《旅游路线规划问题》就是一个典型的TSP问题,原题目如下。
2015年F题 旅游路线规划问题
旅游活动正在成为全球经济发展的重要动力之一,它加速国际资金流转和信息、技术管理的传播,创造高效率消费行为模式、需求和价值等。随着我国国民经济的快速发展,人们生活水平得到很大提升,越来越多的人积极参与有益于身心健康的旅游活动。
附件1提供了国家旅游局公布的201个5A级景区名单,一位自驾游爱好者拟按此景区名单制定旅游计划。该旅游爱好者每年有不超过30天的外出旅游时间,每年外出旅游的次数不超过4次,每次旅游的时间不超过15天;基于个人旅游偏好确定了在每个5A级景区最少的游览时间(见附件1)。基于安全考虑,行车时间限定于每天7:00至19:00之间,每天开车时间不超过8小时;在每天的行程安排上,若安排全天游览则开车时间控制在3小时内,安排半天景点游览,开车时间控制在5小时内;在高速公路上的行车平均速度为90公里/小时,在普通公路上的行车平均速度为40公里/小时。该旅游爱好者计划在每一个省会城市至少停留24小时,以安排专门时间去游览城市特色建筑和体验当地风土人情(不安排景区浏览)。景区开放时间统一为8:00至18:00。请考虑下面问题。
(1)在行车线路的设计上采用高速优先的策略,即先通过高速公路到达与景区邻近的城市,再自驾到景区。附件1给出了各景区到相邻城市的道路和行车时间参考信息,附件2给出了国家高速公路相关信息,附件3给出了若干省会城市之间高速公路路网相关信息。请设计合适的方法,建立数学模型,以该旅游爱好者的常住地在西安市为例,规划设计旅游线路,试确定游遍201个5A级景区至少需要几年?给出每一次旅游的具体行程(每一天的出发地、行车时间、行车里程、游览景区;若有必要,其他更详细表达请另列附件)。
(2)随着各种旅游服务业的发展,出行方式还可以考虑乘坐高铁或飞机到达与景区相邻的省会城市,而后采用租车的方式自驾到景区游览(租车费用300元/天,油费和高速过路费另计,租车和还车需在同一城市)。此种出行方式可以节省一些路途时间用于景区游览或休闲娱乐,但这种出行方式也会给旅游者带来一些不便,有时费用也会增加。该旅游爱好者根据个人旅游偏好确定在每一个景区最长逗留时间不超过附件1给出的最少时间的2倍。附件4给出了若干城市之间的高铁票价和相关信息(约定:选择高铁出行要求当天乘坐高铁的时间不超过6个小时,乘坐高铁或飞机的当天至多安排半天的景区游览);附件5给出了若干省会城市之间的机票全价价格信息(含机场建设费)。该旅游爱好者一家3人同行,综合考虑前述全程自驾、先乘坐高铁或飞机到达省会城市后再租车自驾到景区等出行方式(住宿费简化为省会城市和旅游景区200元/人•天,地级市150元/人•天,县城100元/人•天;高速公路的油耗加过路费平均为1元/公里,普通公路上油耗平均为0.6元/公里;附件1中给出了各景区所在地的信息,若景区位于某城市市区或近郊,则这类景区的市内交通费用已计入住宿费中,不再另计),建立数学模型设计一个十年游遍所有201个5A景区、费用最优、旅游体验最好的旅游线路,给出每一次旅游的具体线路(含每次具体出行方式;每一天的出发地、费用、路途时间、游览景区、每个景区的游览时间)。
(3)能否在第二问所建立的模型基础上加以推广,可以为全国的自驾游爱好者规划设计类似的旅游线路,进而给出常住地在北京市的自驾游爱好者的十年旅游计划;根据上述三问的结果给旅游爱好者和旅游有关部门提出建议。
(4)自2007年3月7日至2015年7月13日,全国旅游景区质量等级评定委员会分29批共批准了201家景区为国家5A级旅游景区。附件6是从国家旅游局官网上收集的国家5A级旅游景区评定的相关信息,附件7给出了国家旅游局官网上收集的国家4A级景区名单,请更为合理地规划该旅游爱好者的十年旅游计划。
以2000年全国大学生数学建模竞赛B题《钢管订购和运输》为例,这是一个典型的最优化问题,原题目如下。
2000年B题 钢管订购和运输
要铺设一条的输送天然气的主管道,如图1-7所示。经筛选后可以生产这种主管道钢管的钢厂有。图中粗线表示铁路,单细线表示公路,双细线表示要铺设的管道(假设沿管道或者原来有公路,或者建有施工公路),圆圈表示火车站,每段铁路、公路和管道旁的阿拉伯数字表示里程(单位为km)。
▲图1-7 《钢管订购和运输》题目原图一
为方便计算,1km主管道钢管称为1单位钢管。
一个钢厂如果承担制造这种钢管,至少需要生产500个单位。钢厂Si在指定期限内能生产该钢管的最大数量为Si个单位,钢管出厂销价1单位钢管为pi万元,如表1-2所示。
表1-2 《钢管订购和运输》题目原表
i |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
---|---|---|---|---|---|---|---|
Si |
800 |
800 |
1000 |
2000 |
2000 |
2000 |
3000 |
pi |
160 |
155 |
155 |
160 |
155 |
150 |
160 |
1000km以上每增加1km至100km运价增加5万元。
公路运输费用为1单位钢管每公里0.1万元(不足整公里部分按整公里计算)。
钢管可由铁路、公路运往铺设地点(不只是运到点,而是管道全线)。
(1)请制定一个主管道钢管的订购和运输计划,使总费用最小(给出总费用)。
(2)请就(1)的模型分析:哪个钢厂钢管的销价的变化对购运计划和总费用影响最大,哪个钢厂钢管的产量的上限的变化对购运计划和总费用的影响最大,并给出相应的数字结果。
(3)如果要铺设的管道不是一条线,而是一个树形图,铁路、公路和管道构成网络,请就这种更一般的情形给出一种解决办法,并对图1-8按(1)的要求给出模型和结果。
▲图1-8 《钢管订购和运输》题目原图二
本章主要介绍人工智能下经常用到的数学知识、常用的统计知识、基本的矩阵运算和高等数学基础知识,它们是后续章节讨论具体人工智能算法的基础,数学基础较好的读者可以直接跳过本章。
统计量是统计理论中用来对数据进行分析、检验的变量,下面介绍一些常用的统计量。
总体,是人们研究对象的全体,又称母体,如工厂一天生产的全部产品(按合格品及废品分类)、学校全体学生的身高,等等。
总体中的每一个基本单位称为个体,个体的特征用一个变量(如)来表示,如一件产品是合格品,记作,若是废品,记作;一个身高170cm的学生,记作。
从总体中随机产生的若干个个体的集合称为样本,或子样,如件产品、100名学生的身高,或者一根轴直径的10次测量。实际上这就是从总体中随机取得的一批数据,不妨记作x1, x2,…, xn,其中称为样本容量。
简单地说,统计的任务是由样本推断总体。
假设有一个容量为的样本(即一组数据),记作,需要对它进行一定的加工,才能提出有用的信息,用作对总体(分布)参数的估计和检验。统计量就是加工出来的、反映样本数量特征的函数,它不含任何未知量。
下面我们介绍几种常用的统计量。
(1)表示位置的统计量——算术平均值和中位数
算术平均值(简称均值)描述数据取值的平均位置,记作。
(1-1)
中位数是将数据由小到大排序后位于中间位置的那个数值。
(2)表示变异程度的统计量——标准差、方差和极差
标准差定义为:
(1-2)
它是各个数据与均值偏离程度的度量,这种偏离不妨称为变异。
方差是标准差的平方。
极差是的最大值与最小值之差。
你可能注意到,在标准差的定义式(1-2)中,对个的平方求和,却被除,这是出于无偏估计的要求。
(3)中心矩、表示分布形状的统计量——偏度和峰度
随机变量的阶中心矩为。随机变量的偏度和峰度,指的是的标准化变量的三阶中心矩和四阶中心矩,如下所示:
偏度反映分布的对称性,称为右偏态,此时位于均值右边的数据比位于左边的数据多;称为左偏态,情况相反;而接近0,则可认为分布是对称的。
峰度是分布形状的另一种度量,正态分布的峰度为3,若比3大得多,表示分布有沉重的尾巴,说明样本中含有较多远离均值的数据,因而峰度可以用作衡量偏离正态分布的尺度之一。
为了理解人工智能下的相关算法原理,需要了解一些高等数学与线性代数的知识,如果想把学术论文上的算法用代码实现,需要你有比较好的数学基础。本节介绍人工智能中比较常用的矩阵知识。
在算法场景中,我们经常提及几阶矩阵,也经常在函数方法中使用,一般关键字涉及matrix、array时,多是在处理矩阵形式。下面通过现实中的一个案例进行讲解。
在生产活动和日常生活中,我们常用数表表示一些量或关系,如工厂中的产量统计表、市场上的价目表,等等。例如,有某户居民第二季度每个月水(单位:吨)、电(单位:千瓦时)、天然气(单位:立方米)的使用情况,可以用一个3行3列的数表来表示:
由上面例子可以看到,对于不同的问题可以用不同的数表来表示,我们将这些数表统称为矩阵。
有m×n个数,排列成一个m行n列,并以中括号(或小括号)表示如下。
我们将其称为m行n列矩阵,简称mn矩阵。矩阵通常用大写字母A、B、C……表示。记作:
其中aij(= 1, 2, …, m;j = 1, 2, …, n )称为矩阵A的第行第j 列元素。特别地,当m = 1时,即:
我们称其为行矩阵,又称行向量。当n = 1时,即:
我们称其为列矩阵,又称列向量。当m = n时,即:
我们称其为n阶矩阵,或n阶方阵。
下面我们来介绍两种特殊的矩阵形式。
(1)零矩阵
零矩阵常常用于在算法中构建一个空矩阵,其形式如下:
=
所有元素全为0的mn矩阵,称为零矩阵,记作:或O。
(2)单位矩阵
单位矩阵往往在运算中担任“1”的作用,其形式如下:
,
对角线上的元素是1,其余元素全部是0的n阶矩阵,我们称其为n阶单位矩阵,记作:In或I。
(1)矩阵的相等
如果两个矩阵和满足以下。
1)行、列数相同,即。
2)对应元素相等,即aij = bij (= 1, 2, …, m;j = 1, 2, …, n ),则称矩阵A与矩阵B相等,记作:A = B。
由定义2可知,用等式表示两个mn矩阵相等,等价于元素之间的mn个等式,例如:
那么A = B,当且仅当:
a11 = 3,a12 = 0,a13 = −5,a21 = −2,a22 = 1,a23 = 4
而:
因为B和C这两个矩阵的列数不同,所以无论矩阵C中的元素c11、c12、c21、c22取什么数都不会与矩阵B相等。
(2)加法
设和是两个mn矩阵,则称矩阵:
为A与B的和,记作:
由定义可知,只有行数、列数分别相同的两个矩阵,才能做加法运算。
同样,我们可以定义矩阵的减法:
我们称D为A与B的差。
(3)数乘
设矩阵,为任意实数,则称矩阵为数与矩阵A的数乘,其中,记作:C =A。
由定义可知,数乘一个矩阵A,需要用数去乘矩阵A的每一个元素。特别是当= −1时,A = −A,得到A的负矩阵。
(4)乘积
设是一个ms矩阵,是一个sn矩阵,则称mn矩阵为矩阵A与B的乘积,记作:C = AB。其中cij = ai1b1 j + ai2b2 j + … + ai s bs j =(i= 1, 2, …, m;j = 1, 2, …, n )。
由乘积的定义可得如下结论。
(5)转置
把将一个mn矩阵的行和列按顺序互换得到的nm矩阵,称为A的转置矩阵,记作:
由定义可知,转置矩阵的第行第j列的元素,等于矩阵A的第j行第列的元素,简记为:
的(,j)元 = A的(j,)元
矩阵的转置满足下列运算规则:
,(k为实数)
(1)互斥事件与对立事件
互斥事件与对立事件相对来说比较好理解:不可能同时发生的叫互斥事件,其中必有一个发生的互斥事件叫对立事件。如果用概率的形式表示,事件A与事件B互斥,则表示为。对于事件A与事件B对立,即P(B)=1−P(A)。彼此之间的关系如图1-9所示,即对立事件一定是互斥事件,互斥事件不一定是对立事件。
▲图1-9 事件A与事件B之间关系
(2)独立事件与互斥事件
独立事件与互斥事件是概率学中的两个基础概念,也是容易混淆的概念,本章将结合一个实例,来阐述这两个概念的关系。
抛掷一颗骰子,记A为“落地向上的数为奇数”事件,B为“落地向上的数为偶数”事件,C为“落地向上的数为3的倍数”事件,D为“落地向上的数为大于3的数”事件,E为“落地向上的数为7”事件。判断下列每对事件是否为互斥事件?是否为对立事件?是否为相互独立事件?(1)A与B(2)A与C(3)B与C(4)A与D(5)A与E
答:根据一颗骰子所存在的点数,整理如下。
最终得到的结论如表1-3所示。
表1-3 抛掷骰子结论表
互斥 |
对立 |
相互独立 |
|
---|---|---|---|
A与B |
是 |
是 |
不 |
A与C |
不 |
不 |
是 |
B与C |
不 |
不 |
是 |
A与D |
不 |
不 |
不 |
A与E |
是 |
不 |
是 |
通过上面的案例,我们可以归纳得到以下3点结论。
1)对于事件A和B,若它们所含结果组成的集合彼此互不相交,则它们为互斥事件,其意义为事件A与B不可能同时发生。
2)对于事件A和B,若,则A和B为相互独立事件,其意义为事件A(或B)发生时,事件B(或A)发生的概率没有影响。从集合角度看,若,,则事件A和B所包含的结果一定相交。
3)若A和B为相互独立事件,则与、与B、与均为相互独立事件,事件为互斥事件。
对立事件与互斥之间存在着如下关系。
1)对于事件A和B,若A、B至少一个为不可能事件,则A、B一定互斥,也一定相互独立。
2)对于事件A和B,若P(A)、P(B)至少一个为0,则A、B一定相互独立,可能互斥,也可能不互斥。
3)对于事件A和B,若P(A)、P(B)都不为0:
(3)随机变量
概率论是从数量上来研究随机现象内在规律性,为了更方便有效地研究随机现象,要用到数学分析方法。为了便于数学上的推导和计算,需将任意的随机事件数量化,当把一些非数量表示的随机事件用数字来表示时,就建立起了随机变量的概念。图1-10是随机变量的划分,在AI项目中,一般主要集中在离散型与连续型变量间做研究。
▲图1-10 随机变量的划分
离散型是指随机变量所取的可能值是有限多个或无限可列个,其变量叫作离散型随机变量。
连续型是指随机变量所取的可能值可以连续地充满某个区间,其变量叫作连续型随机变量。
这里介绍4种常用的概率分布,在第12章中将会用到其中3种。
(1)伯努利分布
伯努利分布是一个离散型分布,为纪念瑞士科学家詹姆斯·伯努利(James Bernoulli)而命名,通常记作X~Bernoulli(p)。在介绍伯努利分布前,首先需要引入伯努利试验(Bernoulli trial)。伯努利试验是只有两种可能结果的单次随机试验,例如,伯努利分布的典型例子是扔一次硬币的概率分布:硬币正面朝上的概率p,而硬币反面朝上的概率为q。
伯努利分布(Bernoulli distribution)是两点分布或0~1分布的特殊情况,即它的随机变量只取x = 0(失败)或者x = 1(成功),各自的概率分别为1−p和 p。
其概率质量函数为:
其数学期望等于p,方差等于。
(2)二项分布
二项分布是n重伯努利分布。在同一条件下重复n次独立的试验,每次试验只有两个对立结果,A发生或者不发生,设在A发生的概率为p,不发生的概率为1−p。这时,在n次独立试验中,A出现的次数k是一个随机变量,且有:
则称该分布为二项分布,记作X~B(n,p)。二项分布的数学期望和方差分别为np和np(1−p)。
(3)多项式分布
把二项扩展为多项就得到了多项分布,通常记作X~Multinomial(n,p)。比如扔骰子,不同于扔硬币,骰子有6个面,对应6个不同的点数,这样单次每个点数朝上的概率都是 (对应p1~p6,它们的值不一定都是,只要和为1且互斥即可,比如一个形状不规则的骰子),重复扔 n次,有k次都是点数6朝上的概率就是:
以上介绍的都是离散型的概率分布。
(4)高斯分布
高斯分布(Gaussian distribution)又名正态分布(Normal distribution),是一个在数学、物理及工程等领域都非常重要的连续型随机变量概率分布,在统计学的许多方面有着重大的影响力。
若随机变量X服从一个数学期望为、标准方差为的高斯分布,记作X~N()。
高斯分布是现实生活中最为常见的分布形态,也是我们在使用朴素贝叶斯模型中最为常用的分布。
学习人工智能技术,高等数学知识是绕不开的。高等数学中的微积分,包含微分学和积分学两部分,而导数和微分是微分学的核心概念。导数反映了函数相对于自变量变化的快慢程度,微分则指明了当自变量有微小变化时,函数大体上变化了多少,即函数的局部改变量的估值。对于积分学,这里我们简单介绍不定积分和定积分,本小节在一元函数微积分下主要讨论相关常见知识点的概念、性质以及计算方法。这些入门知识为非数学专业的IT工程师准备,以方便从业者了解相关知识点,掌握其彼此之间的区别与联系。
下面在一元函数微积分下来介绍各个知识点。
(1)函数在一点处的导数
设函数在点的某邻域内有定义,自变量在处取得增量,且时,函数取得相应的增量,如果极限:
存在,那么称函数在点可导,并称此极限值为函数在点的导数,记作、、、,即。
(2)单侧导数
导数是由函数的极限来定义的,因为极限存在左、右极限,所以导数也存在左、右导数的定义。
设函数在点的某左邻域内有定义,当自变量在点左侧取得增量时,如果极限或存在,则称此极限值为在点的左导数,记作。
设函数在点的某右邻域内有定义,当自变量在点右侧取得增量时,如果极限或存在,则称此极限值为在点的右导数,记作。
(3)导函数
若函数在区间(可以是开区间、闭区间或半开半闭区间)上可导,且对于任意的,都对应着一个导数值,其是自变量的新函数,则称为在区间上的导函数,记作、、、。
或
注:
(1)在导函数的定义式中,虽然可以取区间上的任意值,但在求极限的过程中,是常数,和是变量。
(2)导函数也简称为导数,只要没有指明是特定点的导数时,所说的导数都是指导函数。显然函数在点处的导数就是导函数在点处的函数值,即:
设函数在某区间内有定义,及在此区间内,如果函数的增量:
可表示为:
其中,是不依赖于的常数,那么称函数在点是可微的,而叫作函数在点相应于自变量增量的微分,记作:
或
定理:函数在点可微的充要条件是函数在点可导,且当在点可微时,其微分一定是。
根据微分的定义和上述定理可得以下结论。
(1)函数在点处的微分就是当自变量产生增量时,函数的增量的主要部分(此时)。由于是的线性函数,故称微分是的线性主部。当很微小时,更加微小,从而有近似等式。
(2)函数的可导性与可微性是等价的,故求导法又称微分法。但导数与微分是两个不同的概念,导数是函数在处的变化率,其值只与有关;而微分是函数在处增量的线性主部,其值既与有关,也与有关。
函数在任意点处的微分,称为函数的微分,记作或,即:
通常把自变量的增量称为自变量的微分,记作,即。因此,函数的微分可以记作:
或
从而有:
或
因此,函数的微分与自变量的微分之商等于该函数的导数。
以上介绍的是一元函数微积分,相对于一元函数微积分,多元函数的情况要更加复杂,这里就不做过多介绍了。值得注意的是,偏微分和全微分的关系是,全微分等于偏微分之和。
不定积分的概念:有,,若存在函数,使得对任意均有或,则称为的一个原函数。
的全部原函数称为在区间上的不定积分,记作:
注:
(1)若连续,则必可积。
(2)若和均为的原函数,则。故不定积分的表达式不唯一。
不定积分主要有以下3点性质,以方便计算求解。
性质1:或。
性质2:或。
性质3:,α和β为非零常数。
不定积分的计算方法有换元法、分部积分法等,这里不做过多介绍。下面给出一个通过凑微分法求解过程,仅供参考。
求解。
解:
设函数∈C[a, b], 且>0。由曲线围成的图形称为曲边梯形,如何定义曲边梯形的面积?
答:将曲边梯形分割为许多细长条,分割得越细,误差越小。第i个细长条面积,曲边梯形面积为。
抛开上述过程的几何意义,将其数学过程定义为定积分。
如图1-11所示,设在[a, b]有定义,且有界。
(1)分割:用分点把[a, b]分割成n个小区间。
记,λ=max{Δxi,i=1,2,...,n}
(2)取点:在每个小区间上任取一点ξi,作为乘积。
(3)求和:。
(4)取极限:。
▲图1-11 定积分原理图
若极限存在,则其为在[a, b]上的定积分,记作,即 [a, b]为积分区间,a为积分下限,b为积分上限,为积分和式。
定理:若在[a, b]上连续,是的一个原函数,则
证明:是的一个原函数,也是的一个原函数,同一个函数的两个原函数之间相差一个常数,于是有
下面给出一个求解案例。
求解。
解:
在一元函数情况下,求微分实际上是求一个已知函数的导函数,而求积分是求已知导函数的原函数,所以微分与积分互为逆运算。
[1] 达特茅斯会议参会者50年后再聚首,左起:Trenchard More、John McCarthy、Marvin Minsky、Oliver Selfridge和Ray Solomonoff(摄于2006年),图片版权归原作者所有。
Python是谁?
你可能已经听说过很多种流行的编程语言,比如非常难学的C语言,非常流行的Java语言,可视化效果非常好的R语言,适合科学计算的Matlab,等等。Python也是一种计算机程序设计语言,于1991年发布,至今已经发展成为最受欢迎的编程语言之一。
虽然可以通过其官网安装Python,但本书推荐直接安装Anaconda。Anaconda是Python的科学计算环境,内置Python安装程序,其安装方法简单,并且配置了众多的科学计算包。Anaconda支持多种操作系统(Windows、Linux和Mac),集合了上百种的常用Python包,如NumPy、Pandas、SciPy和Matplotlib等。安装Anaconda时,这些包也会被一并安装,同时兼容Python多版本,支持多版本共存。
首先我们先从Anaconda官网下载对应自己系统版本的Anaconda,具体下载界面如图2-1所示。
▲图2-1 Anaconda下载界面
以64位Windows 10操作系统为例,下载对应版本的安装文件即可。这里要说明的是,本书的所有案例都是基于Anaconda的Python来完成的。
下载完成后,按照提示进行安装,如图2-2所示,安装完成之后如图2-3所示。运行开始菜单中的Anaconda Prompt,输入命令conda list,效果如图2-4所示,表示安装成功!
▲图2-2 Anaconda安装界面
▲图2-3 开始菜单中的Anaconda3
▲图2-4 conda list返回结果
当前选取的Linux环境是CentOS 6.5,其他环境安装方法仿照Anaconda官方操作进行安装。首先到下载Linux版本的Anaconda3-5.2.0-Linux-x86_64.sh界面,如图2-5所示。
▲图2-5 Anaconda3-5.2.0-Linux-x86_64.sh下载界面
下载完成之后进入文件下载目录,打开终端,根据版本输入下面的安装执行命令:
$ bash Anaconda3-5.2.0-Linux-x86_64.sh
输入完成之后得到的结果如下所示:
Welcome to Anaconda3 5.2.0
In order to continue the installation process, please review the license agreement.
Please, press ENTER to continue
>>>
按照提示,按回车键,接下来,它会提示你是否接受协议。这里直接输入“yes”,再按回车键即可(不要直接按回车键,这样默认是“no”)。
Do you accept the license terms? [yes|no]
[no] >>> Please answer 'yes' or 'no':'
>>>
选择“yes”,之后进入配置路径。
Anaconda3 will now be installed into this location:
/home/fileservice/anaconda3
- Press ENTER to confirm the location
- Press CTRL-C to abort the installation
- Or specify a different location below
[/home/fileservice/anaconda3]
>>>
这里输入“yes”,选择加入环境变量进行安装。继续按照提示操作,这里问你是否需要为Anaconda配置环境变量,如果选择“no”,需要到安装完成的Anaconda3/bin目录下才能执行Anaconda以及其他附属命令。
installation finished.
Do you wish the installer to prepend the Anaconda3 install location
to PATH in your /home/fileservice/.bashrc ? [yes|no]
[no] >>>
如果Anaconda的版本比较新(5.1以上),在安装完成后会提示你是否需要安装Microsoft VSCode这款编辑工具。由于配置其他编辑器会浪费过多时间,一般我在这里选择“yes”,安装VSCode。
Thank you for installing Anaconda3!
=============================================================
Anaconda is partnered with Microsoft! Microsoft VSCode is a streamlined
code editor with support for development operations like debugging, task
running and version control.
To install Visual Studio Code, you will need:
- Administrator Privileges
- Internet connectivity
Visual Studio Code License: https://code.visualstudio.com/license
Do you wish to proceed with the installation of Microsoft VSCode? [yes|no]
>>>
在命令行输入Python3命令,验证是否安装成功:
$ python3
显示结果如下所示,Python环境已经自动由Anaconda托管,以后就再也不用担心Python的包依赖问题啦!
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
如果说编程是程序员的手艺,那么IDE就是程序员的“饭碗”了。
IDE的全称是Integration Development Environment(集成开发环境),一般以代码编辑器为核心,包括一系列外围组件和附属功能。一个优秀的IDE,最重要的就是提供针对特定语言的各种快捷编辑功能,让程序员尽可能快捷、舒适、清晰地浏览、输入和修改代码。对于一个现代的IDE来说,语法着色、错误提示、代码折叠、代码完成、代码块定位、重构,与调试器、版本控制系统(VCS)的集成等都是重要的功能。以插件、扩展系统为代表的可定制框架,是现代IDE的另一个流行趋势。IDE并非功能越多越好,因为更多的功能往往意味着更高的复杂度,这不但会分散程序员的精力,而且还可能带来更多的错误。用最合适的工具做最合适的事情,因此只要基本功能满足需要,而且符合自己的使用习惯,那么它就是一款好的IDE。正因为如此,比起大而全的IDE,以单纯的文本编辑器结合独立的调试器、交互式命令行等外部小工具也是另一种开发方式。由于Python本身的简洁性,因此在写小的代码片段以及通过示例代码学习时,这种方式尤其适合。
Anaconda自带Spyder。安装好Python后,我们需要选择适合自己的IDE来学习,虽然利用Python默认的编辑器,或者直接文档编辑也可以进行基础的学习,但总归不是太方便。能够开发Python项目的IDE很多,如sublime text、PyCharm。本书代码均在PyCharm下完成。
世界上的第一个程序是“Hello World”,由Brian Kernighan创作,其中文意思是“你好,世界”。对于大多数程序语言,第一个入门编程代码便是“Hello World”。例2-1代码为使用Python输出“Hello World”。
【例2-1】Hello World程序
输入:
#!usr/bin/env python
#这是一个注释
print("Hello World")
输出:
Hello World
例2-1是一个print的例子,它并不会真的印什么东西在纸上,而是在屏幕上显示出Hello World。有些人以Hello World程序的简洁性来判断一种程序语言的品质,以这个标准来看,Python几乎做到了尽善尽美。
在大多数编程语言中,注释是一项很有用的功能。源代码的注释供人阅读,而不是供计算机执行,注释用自然语言告诉你某段代码的功能是什么。随着程序版本的更迭,程序越来越复杂,就应在其中添加说明,对程序所解决问题的方法进行大致的阐述。
每种语言都有其特有注释形式,下面来介绍Python中程序的行内注释。
(1)单行注释
在Python中,单行注释以井号(#)开头标识,井号后面的内容都会被Python解释器忽略,如例2-2所示。
【例2-2】单行注释
输入:
# 这是一个注释
print("Hello, World")
(2)多行注释
在Python中,多行注释用3个单引号(''')或者3个双引号(""")将注释括起来。用来解释更复杂的代码,如例2-3所示。
【例2-3】多行注释
输入:
'''
Created on May 10, 2018
@author: *****
'''
print("Hello, World")
使用注释有助于令程序更易于理解,因为即使是你自己编写的程序,如果不加注释,你在以后也可能看不懂。恰当的注释可以使其他人更容易与你在编程项目上合作,并凸显代码的价值。
小贴士:
在PyCharm中,选中需要注释的多行代码,然后按快捷键<Ctrl+/>,即可快速注释选中的多行代码。
(1)%操作符
%操作符可以实现字符串格式化。它将左边的参数作为类似sprintf()的格式化字符串,而将右边的代入,然后返回格式化后的字符串,如例2-4与例2-5所示。更多的格式化输出形式见表2-1。
【例2-4】%操作符
输入:
print("%o"% 10)
print("%d"% 10)
print("%f"% 10)
输出:
12
10
10.000000
浮点数输出过程中,经常需要控制保留小数位数,可以在现有格式化输出的基础上进行限制,比如%.2f,保留2位小数位;%.2e,保留2位小数位,使用科学计数法输出;%.2g,保留2位有效数字,使用小数或科学计数法输出。
同时也可以灵活地使用内置的round()函数,其函数形式为:
round(number, ndigits)
参数如下。
【例2-5】浮点数输出
输入:
print("%f" % 3.1415926)
输出:
3.141593
输入:
print("%.2f" % 3.1415926)
输出:
3.14
输入:
print(round(3.1415926,2))
输出:
3.14
表2-1 格式化输出规则
格式 |
描述 |
---|---|
%% |
百分号标记#就是输出一个% |
%c |
字符及其ASCII码 |
%s |
字符串 |
%d |
有符号整数(十进制) |
%u |
无符号整数(十进制) |
%o |
无符号整数(八进制) |
%x |
无符号整数(十六进制) |
%X |
无符号整数(十六进制大写字符) |
%e |
浮点数字(科学计数法) |
%E |
浮点数字(科学计数法,用E代替e) |
%f |
浮点数字(用小数点符号),默认保留小数点后面6位有效数字 |
%g |
浮点数字(根据值的大小采用%e或%f) |
%G |
浮点数字(类似于%g) |
%p |
指针(用十六进制打印值的内存地址) |
%n |
存储输出字符的数量放进参数列表的下一个变量中 |
(2)format格式化字符串
format是Python 2.6版本中新增的一个格式化字符串的方法,相对于老版的%格式方法,它有很多优点,也是官方推荐使用的方式,%方式将会被后面的版本淘汰。该函数把字符串当成一个模板,通过传入的参数进行格式化,并且使用大括号{}作为特殊字符代替%。
1)通过位置来填充
通过位置来填充,format会把参数按位置顺序来填充到字符串中,第一个参数是0,然后是1,不带编号,即{},通过默认位置来填充字符串,见例2-6。
【例2-6】format按位置输出
输入:
print("{} {}".format("hello","world"))
输出:
hello world
输入:
print("{0} {0} {1}".format("hello","world"))
输出:
hello hello world
同一个参数可以填充多次,这是format比%先进的地方。
2)通过索引
后面章节会讲到,列表、元组在程序中经常用到的最基本的数据结构是序列(sequence),当需要传递序列给format时,通过索引即可映射传递,如例2-7所示。
【例2-7】format索引输出
输入:
str="hello"
list=["hello","world" ]
tuple=("hello","world")
print("{0[1]}".format(str))
print("{0[0]},{0[1]}".format(list))
print("{0[0]},{0[1]}".format(tuple))
输出:
e
hello,world
hello,world
输入:
print("{p[1]}".format(p=str))
print("{p[0]},{p[1]}".format(p=list))
print("{p[0]},{p[1]}".format(p=tuple))
输出:
e
hello,world
hello,world
3)通过字典的key
在Python中,字典的使用频率非常之高,其经常由JSON类型转化得到。同时随着人工智能的发展,越来越多的数据需要字典类型的支持,比如MongoDB数据的形式就可以看成一种字典类型,还有推荐算法中的图算法也经常应用key-value形式来描述数据。format通过key形式输出,如例2-8所示。
【例2-8】format字典形式输出
输入:
Tom = {'age':27, 'gender': 'M'}
print("{0[age]}".format(Tom))
print("{p[gender]}".format(p=Tom))
输出:
27
M
4)通过对象的属性
format还可以通过对象的属性进行输出操作,如例2-9所示。
【例2-9】format通过对象属性输出
输入:
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return '{self.name} is {self.age} years old'.format
(self=self)
print(Person('Tom',18))
输出:
Tom is 18 years old
5)字符串对齐并且指定对齐宽度
有些时候我们需要输出形式符合某些规则,比如字符串对齐,填充常跟对齐一起使用,符号^、<、>分别是居中、左对齐、右对齐,后面带宽度,冒号后面带填充的字符,只能是一个字符。如果不指定,则默认是用空格填充,如例2-10所示。
【例2-10】字符串对齐并且指定对齐宽度输出
输入:
print('默认输出:{},{}'.format('hello','world'))
print('左右各取10位对齐:{:10s} , {:>10s}'.format('hello','world'))
print('取10位中间对齐:{:^10s},{:^10s}'.format('hello','world'))
print('取2位小数: {} is {:.2f}'.format(3.141592,3.141592))
print('数值的千位分割符:{} is {:,}'.format(123456789,1234567890))
输出:
默认输出:hello,world
左右各取10位对齐:hello , world
取10位中间对齐: hello , world
取2位小数: 3.141592 is 3.14
数值的千位分割符:123456789 is 1,234,567,890
表2-2与表2-3分别是整数与浮点数在字符串对齐与指定对齐宽度的案例。
表2-2 整数规则表
数字 |
格式 |
输出 |
描述 |
---|---|---|---|
5 |
{:0>2} |
05 |
数字补0(填充左边,宽度为2) |
5 |
{:x<4} |
5xxx |
数字补x(填充右边,宽度为4) |
10 |
{:x^4} |
x10x |
数字补x(填充两侧,宽度为4) |
13 |
{:10} |
13 |
右对齐(默认,宽度为10) |
13 |
{:<10} |
13 |
左对齐(宽度为10) |
13 |
{:^10} |
13 |
中间对齐(宽度为10) |
表2-3 浮点数规则表
数字 |
格式 |
输出 |
描述 |
---|---|---|---|
3.1415926 |
{:.2f} |
3.14 |
保留小数点后两位 |
3.1415926 |
{:+.2f} |
+3.14 |
带符号保留小数点后两位 |
−1 |
{:+.2f} |
−1.00 |
带符号保留小数点后两位 |
2.71828 |
{:.0f} |
3 |
不带小数 |
1000000 |
{:,} |
1,000,000 |
以逗号分隔的数字格式 |
0.25 |
{:.2%} |
25.00% |
百分比格式 |
1000000000 |
{:.2e} |
1.00E+09 |
指数记法 |
25 |
{0:b} |
11001 |
转换成二进制 |
25 |
{0:d} |
25 |
转换成十进制 |
25 |
{0:o} |
31 |
转换成八进制 |
25 |
{0:x} |
19 |
转换成十六进制 |
在Python中,最基本的数据结构是序列。Python包含6种内建的序列,即列表、元组、字符串、Unicode字符串、buffer对象和range对象。序列通用的操作包括:索引、长度、组合(序列相加)、重复(乘法)、分片、检查成员、遍历、最小值和最大值。序列中的每个元素被分配了一个序号,即元素的位置,称为索引。第一个索引是0,第二个是1,而倒数第一个元素可以标记为−1,倒数第二个为−2,依次类推。序列的元素可以是之前讲的所有基础数据类型,也可以是另一个序列,还可以是之后我们将要介绍的对象。最常用的序列有两类:元组(tuple)和列表(list)。列表可以修改,而元组不可以修改。
列表由一系列按特定顺序排列的元素组成。你可以创建包含字母表中所有字母、数字0~9或所有家庭成员姓名的列表,也可以将任何东西加入列表中,其中的元素之间可以没有任何关系。
(1)初始列表
Python中,使用方括号[]创建列表,各个元素通过逗号分隔,如下所示:
list1 = ['Python','AI']
list2 = [1,2,3,4,3]
list3 = ["p","y","t","h","o","n",['Python','AI']]
(2)列表函数和方法
如表2-4所示。
表2-4 列表函数和方法
基本操作 |
说明 |
示例 |
---|---|---|
len(list) |
返回列表元素个数 |
len(list2) ⇒ 5 |
max(list) |
返回列表元素中最大值 |
max(list2) ⇒ 4 |
min(list) |
返回列表元素最小值 |
min(list2) ⇒ 1 |
list.append(obj) |
在列表末尾添加新的对象 |
list2.append('a') ⇒ list2=[1, 2, 3, 4, 3, 'a'] |
list.count(obj) |
统计某个元素在列表中出现的次数 |
list2.count(3) ⇒ 2 |
list.extend(seq) |
在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) |
list1.extend(list2) ⇒list1=['Python', 'AI', 1, 2, 3, 4, 3] |
list.index(obj) |
从列表中找出某个值第一个匹配项的索引位置 |
list2.index(3) ⇒ 2 |
list.insert(index, obj) |
找到列表中index索引位置元素,并在此索引位置插入obj到列表中 |
list2.insert(2,"a") ⇒ list2=[1, 2, 'a', 3, 4, 3] |
list.pop([index=-1]]) |
移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 |
list2.pop(1) ⇒ list2=[1, 3, 4, 3] |
list.remove(obj) |
移除列表中某个值的第一个匹配项 |
list2.remove(3) ⇒ list2= [1, 2, 4, 3] |
list.reverse() |
反向列表中元素 |
list2.reverse()⇒ list2= [3, 4, 3, 2, 1] |
list.sort(cmp=None, key=None, reverse=False) |
对原列表进行排序 |
list2.sort()⇒ list2=[1, 2, 3, 3, 4] |
list.clear() |
清空列表 |
list2.clear()⇒ list2= [] |
list.copy() |
复制列表 |
list2.copy()⇒ [1, 2, 3, 4, 3] |
注:如果一个对象本身不是strascii或repr格式,那么可以使用!s、!a、!r,将其转成str、ascii以及repr。
列表非常适合用于存储在程序运行期间可能变化的数据集。列表是可以修改的,这对处理网站的用户列表或游戏中的角色列表至关重要。然而,有时可能需要创建一系列不可修改的元素,元组便可以满足这种需求。Python将不能修改的值称为不可变的,而不可变的列表被称为元组。
元组跟列表一样,属于序列的一员,不同的是它是不可变序列,即一旦被定义,其长度和内容就固定了。在Python中,使用小括号()创建元组,各个元素通过逗号分隔。
tuple1 = ('Python','AI')
tuple2 = (1,2,3,4,3)
tuple3 = "a", "b", "c", "d"; # 不需要括号也可以
元组中的元素值是不允许修改与删除的,但我们可以对元组进行连接组合:
tup = tuple1 +tuple3 ⇒ tup = ('Python', 'AI', 'a', 'b', 'c', 'd')
元组的内置函数参考列表的内置函数即可,即将list替换成tuple,同时列表与元组之间可以互相转化,由列表转化为元组通过tuple(list)完成,由元组转化为列表通过list(tuple)完成。
相比于列表,元组是更简单的数据结构。如果需要在程序的整个生命周期内存储一组不变的值,可使用元组。
小贴士:
元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运算符使用,如tup1 = (1)和tup2 = (1)。在tup1中没有使用逗号,其类型为int;tup2中加上了逗号,其类型为元组。
列表和元组同样属于Python下的序列,均支持序列操作。下面以列表为例进行说明,见表2-5。
表2-5 序列操作
操作 |
示例 |
---|---|
索引 |
list2[0] ⇒ 1 |
使用分片访问的是元素基本样式[下限:上限:步长],默认步长为1 |
list2[1:3] ⇒ [2, 3] |
赋值 |
list2[1]=a" ⇒ list2=[1, 'a', 3, 4, 3] |
序列相加 |
list1+list2 ⇒ ['Python', 'AI', 1, 2, 3, 4, 3] |
序列乘法 |
list1*3 ⇒ ['Python', 'AI', 'Python', 'AI', 'Python', 'AI'] |
序列的循环调用 |
for a in list1: |
本节主要介绍能够将相关信息关联起来的Python字典。在Python中,字典是一系列键-值(key-value)对。每个键都与一个值相关联,你可以使用键来访问与之相关联的值。与键相关联的值可存储任意类型对象,包括数字、字符串、列表甚至字典。事实上,可将任何Python对象用作字典中的值。
在Python中,字典用大括号{}中的一系列键-值对表示。字典的每个键-值对用冒号分隔,每个对之间用逗号分隔,格式为dict={key1:value1,key2: value2, key3:value3},创建字典的实例为dict1 = {'Name': 'Bob','Age': 21}。
下面来简单列举字典的基本操作,首先对于字典dict1,访问字典中的元素,获取与键相关联的值,可依次指定字典名和放在方括号内的键,如表2-6所示。
表2-6 字典基本操作
常见操作 |
说明 |
示例 |
---|---|---|
len(dict) |
计算字典元素个数,即键的总数 |
len(dict1) ⇒ 2 |
str(dict) |
输出字典,以可打印的字符串表示 |
str(dict1) ⇒{'gender': 'M', 'Name': 'Bill'}结果类型为字符类型 |
dict1[key] |
访问字典中键对应的值 |
dict1['Name'] ⇒ Bob |
dict1.get(key) |
访问字典中键对应的值 |
dict1.get("Name"⇒ Bob |
dict1[newkey]=value |
为字典增加一项,增加新的键值对 |
dict1["gender"]='M'⇒ dict1={'Age': 21, 'gender': 'M', 'Name': 'Bob'} |
dict1[key]=newvalue |
增加新的键-值对 |
dict1["Name"]="Bill"⇒ dict1={'Age': 21, 'gender': 'M', 'Name': 'Bill'} |
dict.pop(key [,default]) |
删除字典给定键所对应的值 |
dict1.pop("Age")⇒ {'Name': 'Bill', 'gender': 'M'} |
dict1.values() |
遍历字典的值,以列表返回一个字典所有的值 |
dict1.values()⇒ dict_values(['Bill', 'M']) |
dict1.keys() |
遍历字典的键,以列表返回一个字典所有的键 |
dict1.keys()⇒ dict_keys(['Name', 'gender']) |
dict1.items() |
遍历字典的项,以列表返回可遍历的(键、值)元组数组 |
dict1.items()⇒ dict_items([('Name', 'Bill'), ('gender', 'M')]) |
key in dict |
如果键在字典dict里,返回True,否则返回False |
'Name' in dict1⇒ True |
key not in dict |
如果键不在字典dict里,返回True,否则返回False |
'Name' not in dict1⇒ False |
以上列举了常见的字典操作。字典在Python中扮演着重要的角色,如果你想成为一名合格的Python使用者,不仅需要熟练掌握列表、元组与字典的基本操作,还需要对其比较复杂情况的处理有一定了解。比如在字典操作中出现镶嵌字典形式,只需要依据以上的基本操作进行扩展即可。
小贴士:
在Python中,字典中的键必须是唯一的,但值不必唯一。
Python中的条件语句一般是指if语句,if语句用于改变Python程序中的控制流。通过指定条件的真假结果,可以判断要执行哪条语句。Python中if语句的最简单形式如例2-11所示。
【例2-11】if语句基本形式
if condition1:
statement1
else:
statement2
在if…else条件句中,if条件判断语句所在行和else所在行都要以冒号结尾,而执行语句要缩进。从上述基本形式可以看出,condition1后面有冒号,statement1所在行有缩进,同时其后面是没有冒号的。如果表达式condition1执行结果为True,接下来执行statement1的代码,否则执行statement2处代码。如果判断条件有多个,则可以使用if…elif语句的形式,确切地说可以有多个elif分支,但只有一个else分支,else分支必须位于if语句的末尾,即其他elif分支不能跟随。见例2-12形式,同时为了方便理解,在例2-13中给出了具体的案例。
【例2-12】if多条件语句
if condition1:
statement1
elif condition2 :
statement2
…
elif conditionN :
statementN
else:
statement
【例2-13】if多条件案例
输入:
num = 3
if num > 0:
print("正数")
elif num == 0:
print("零")
else:
print("负数")
输出:
正数
三元运算符是软件编程中的一个固定格式,Python的条件语句还有更为简练的方式,所有代码都放置在一行中即可完成条件语句程序,即实现三元运算(三目运算)的过程,其形式见例2-14,具体案例见例2-15。
【例2-14】三元运算
[on_true] if [expression] else [on_false]
例2-14中表达的语义为:[on_true]是条件表达式为真时的结果,[on_false]是条件表达式为假时的结果。
【例2-15】三元运算案例
输入:
a = 1
b = 2
c = a-b if a>b else a+b
print(c)
输出:
3
许多编程语言必须具有能够重复执行一系列语句的构造。循环调用代码,即重复执行的代码被称为循环的主体。Python提供两种不同的循环:while循环和for循环。图2-6与2-7分别为两种循环流程图。
▲图2-6 while循环流程图
▲图2-7 for循环流程图
在Python中,while循环语句的形式见例2-16。
【例2-16】while循环语句的形式
while expression:
statements
statements可以是单个语句,也可以是语句块;expression表示判断条件,如果为真,则执行循环体语句。
像while循环一样,for循环也是一种编程语言语句,即迭代语句,它允许代码块重复一定次数。几乎所有编程语言中都存在for循环,但其风格各不相同,即语法和语义在不同的编程语言中都是不相同的。在Python中,for循环语句的形式见例2-17。
【例2-17】for循环语句的形式
for iterating_var in sequence:
statements(s)
在一个完整的工程项目中,经常会以不同形式使用条件控制和循环控制,为了方便灵活地执行代码,需要添加break、continue、pass等语句,如例2-17所示。
【例2-18】构建循环
#正常执行for循环
输入:
for i in range(5):
print("i=%d"%i)
输出:
i=0
i=1
i=2
i=3
i=4
break语句可用于跳出循环,终止循环语句,即循环条件没有False条件或者序列还没被完全递归完,也会停止执行循环语句。break所在的循环体已经结束,执行该循环语句下面的语句。break语句用在while和for循环中。例2-18是一个正常的for循环,例2-18.1是break跳出循环体操作。
【例2-18.1】break语句
输入:
for i in range(5):
if i==3:
break
print("i=%d"%i)
输出:
i=0
i=1
i=2
例2-18是一个简单的for循环,循环5次打印出0、1、2、3、4。例2-18.1代码的for循环中添加了关键字break,若i=3不成立,则继续循环,否则执行break语句,实际上程序只输出了0、1、2,便跳出循环体,终止循环语句。因此我们可以知道,break这个关键字的作用是让程序跳出循环体的同时终止循环。
break是跳出整个循环,而continue 语句则表示跳出本次循环,用来告诉Python停止本次循环,继续执行剩下的循环,即跳过当前循环的剩余语句,然后继续进行下一轮循环。continue语句用在while和for循环中。例2-18是一个正常的for循环,例2-18.2是continue停止本次循环的操作示例。
【例2-18.2】continue语句
输入:
for j in range(5):
if j==3:
continue
print("j=%d"%j)
输出:
i=0
i=1
i=2
j=4
与例2-18.1代码类似,例2-18原有的for循环代码基础上添加了关键字continue。通过运行结果,我们发现本循环中间有一次中断,j=3没有输出,也就是第四次中断了。但与break不同的是,接下去的循环依旧正常进行。由此我们可以知道,continue的作用是终止本次循环,但不跳出循环,后面的循环正常进行。
Python中的pass是空语句,是为了保持程序结构的完整性。pass不做任何事情,也就是说它是一个空操作,一般用于占位语句,如例2-19所示。
【例2-19】pass语句
def sample():
pass
例2-19定义了一个sample函数,该处的 pass占据一个位置,因为如果定义一个空函数,程序会报错。所以当你没有想好函数的内容时,可以用pass填充,以使程序正常运行。
lambda关键字在Python 表达式内创建匿名函数。然而Python句法限制了lambda 函数的定义体,只能使用纯表达式。换句话说,lambda函数的定义体中不能赋值,也不能使用while和try等Python语句。
Python使用lambda表达式来创建匿名函数。
lambda函数的一般语法非常简单,形式为:lambda argument_list: expression。
参数由逗号分隔的参数列表组成,表达式是使用这些参数的算术表达式。你可以将该函数分配给一个变量以赋予其名称。例2-20中lambda函数示例返回其两个参数的总和。
【例2-20】lambda函数案例
输入:
sum=lambda x,y:x+y
print(sum(3,4))
输出:
7
在例2-20中,sum函数可以通过使用以下常规函数定义来获得相同的效果。
def sum(x,y):
return x + y
map是Python的高级函数,为函数式编程提供便利,形式为 map(func, *iterables):第一个参数func是一个函数的名字;第二个参数为一个序列(例如一个列表)。map将函数func应用于序列的所有元素。在Python 3之前,map用于返回一个列表,其中结果列表的每个元素都是应用于列表或元组序列相应元素上的func结果。在Python 3中,map返回一个迭代器。
例2-21是一个最简单的例子,基于,map作用于list [1, 2, 3, 4, 5, 6, 7, 8, 9]后的结果,返回结果仍为list,其作用原理见图2-8。
▲图2-8 例2-21的工作原理
【例2-21】map示例
输入:
seq_list=[1, 2, 3, 4, 5, 6, 7, 8, 9]
F =list(map(lambda x:x**2,seq_list))
print(F)
输出:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
map可以应用于多个列表,列表不必具有相同的长度。map会将lambda函数应用于参数列表的元素,即它首先应用于具有第0个索引的元素,然后应用于具有第一个索引的元素,直到达到第n个索引,如例2-22所示。
【例2-22】map应用于多个列表
输入:
a = [1,2,3,4]
b = [5,6,7,8]
c = [5,6,7]
ab=list(map(lambda x,y:x + y,a,b))
print(ab)
输出:
[6, 8, 10, 12]
如果一个列表中的元素少于其他元素,则当最短列表消耗完时,map将停止,具体见例2-23。
【例2-23】map应用于多个列表不同元素情况
输入:
a = [1,2,3,4]
b = [5,6,7,8]
c = [5,6,7]
ac=list(map(lambda x,y:x + y,a,c))
print(ac)
输出:
[6, 8, 10]
对比例2-22与例2-23的输出结果,可以看出ac的结果元素个数只有3个,而ab的结果有4个。这表明如果一个列表中的元素少于其他元素,则map依据最短列表进行处理。
filter也是Python的高级函数,为函数式编程提供便利。其作用是对序列中的元素进行筛选,最终获取符合条件的序列,其一般形式为filter(function,iterable),函数提供了一种优雅的方式来过滤掉序列中的所有元素。
在例2-24中,我们先滤出前11个斐波那契数列的奇数和偶数元素。
【例2-24】filter示例
输入:
fibonacci = [0,1,1,2,3,5,8,13,21,34,55]
even_numbers = list(filter(lambda x: x%2==0,fibonacci))
print(even_numbers)
输出:
[0, 2, 8, 34]
小贴士:
在Python 3中,reduce()已经从Python的核心中被删除了,Python 2中的reduce()函数也是Python内置的一个高阶函数。在Python 3中,我们必须导入functools才能使用reduce,下面是对序列内所有元素进行累计操作的代码。
from functools import reduce
f = lambda a,b:a if(a> b) else b
print(reduce(f,[47,11,42,102,13]))
输出:102