《Python數(shù)據(jù)分析》(Python for Data Analysis, 2nd Edition)第二版出了藐翎,目前還沒有中文版材蹬,這版的代碼適用于Python 3.6 实幕。
AZW3下載(英文): https://github.com/iamseancheney/pythonbooks/blob/master/Python%20for%20Data%20Analysis%202nd.azw3
GitHub代碼:https://github.com/wesm/pydata-book
舊版是Python 2.7的,有的代碼已經(jīng)不能運(yùn)行堤器。
第一版 AZW3(中文):https://github.com/iamseancheney/pythonbooks/blob/master/Python%20for%20Data%20Analysis%201st.azw3
AZW3是Kindle的文件格式昆庇,PC端可以用Calibre閱讀器打開。
第一章 準(zhǔn)備工作
下載本書:http://www.reibang.com/p/fad9e41c1a42(更新為GitHub鏈接)
下載本書代碼:https://github.com/wesm/pydata-book(建議把代碼下載下來(lái)之后闸溃,安裝好Anaconda 3.6整吆,在目錄文件夾中用Jupyter notebook打開)
本書是2017年10月20號(hào)正式出版的,和第1版的不同之處有:
包括Python教程內(nèi)的所有代碼升級(jí)為Python 3.6(第1版使用的是Python 2.7)
更新了Anaconda和其它包的Python安裝方法
更新了Pandas為2017最新版
新增了一章辉川,關(guān)于更高級(jí)的Pandas工具表蝙,外加一些tips
簡(jiǎn)要介紹了使用StatsModels和scikit-learn
對(duì)有些內(nèi)容進(jìn)行了重新排版。(譯者注1:最大的改變是把第1版附錄中的Python教程乓旗,單列成了現(xiàn)在的第2章和第3章府蛇,并且進(jìn)行了擴(kuò)充∮煊蓿可以說(shuō)欲诺,本書第2版對(duì)新手更為友好了C祓小)
(譯者注2:毫無(wú)疑問(wèn)扰法,本書是學(xué)習(xí)Python數(shù)據(jù)分析最好的參考書。本來(lái)想把書名直接譯為《Python數(shù)據(jù)分析》毅厚,這樣更簡(jiǎn)短塞颁。但是為了尊重第1版的翻譯,考慮到繼承性吸耿,還是用老書名祠锣。這樣讀過(guò)第一版的老讀者可以方便的用之前的書名檢索到第二版。作者在寫第二版的時(shí)候咽安,有些文字是照搬第一版的伴网。所以第二版的翻譯也借鑒copy了第一版翻譯:即,如果第二版中有和第一版相同的文字妆棒,則copy第一版的中文譯本澡腾,覺得不妥的地方會(huì)稍加修改,剩下的不同的內(nèi)容就自己翻譯糕珊。這樣做也是為讀過(guò)第一版的老讀者考慮——相同的內(nèi)容可以直接跳過(guò)动分。)
1.1 本書的內(nèi)容
本書講的是利用Python進(jìn)行數(shù)據(jù)控制、處理红选、整理长赞、分析等方面的具體細(xì)節(jié)和基本要點(diǎn)弦讽。我的目標(biāo)是介紹Python編程和用于數(shù)據(jù)處理的庫(kù)和工具環(huán)境撩轰,掌握這些,可以讓你成為一個(gè)數(shù)據(jù)分析專家迹辐。雖然本書的標(biāo)題是“數(shù)據(jù)分析”,重點(diǎn)確實(shí)Python編程甚侣、庫(kù)右核,以及用于數(shù)據(jù)分析的工具。這就是數(shù)據(jù)分析要用到的Python編程渺绒。
什么樣的數(shù)據(jù)贺喝?
當(dāng)書中出現(xiàn)“數(shù)據(jù)”時(shí),究竟指的是什么呢宗兼?主要指的是結(jié)構(gòu)化數(shù)據(jù)(structured data)躏鱼,這個(gè)故意含糊其辭的術(shù)語(yǔ)代指了所有通用格式的數(shù)據(jù),例如:
表格型數(shù)據(jù)殷绍,其中各列可能是不同的類型(字符串染苛、數(shù)值、日期等)主到。比如保存在關(guān)系型數(shù)據(jù)庫(kù)中或以制表符/逗號(hào)為分隔符的文本文件中的那些數(shù)據(jù)茶行。
多維數(shù)組(矩陣)。
通過(guò)關(guān)鍵列(對(duì)于SQL用戶而言登钥,就是主鍵和外鍵)相互聯(lián)系的多個(gè)表畔师。
間隔平均或不平均的時(shí)間序列。
這絕不是一個(gè)完整的列表牧牢。大部分?jǐn)?shù)據(jù)集都能被轉(zhuǎn)化為更加適合分析和建模的結(jié)構(gòu)化形式看锉,雖然有時(shí)這并不是很明顯。如果不行的話塔鳍,也可以將數(shù)據(jù)集的特征提取為某種結(jié)構(gòu)化形式伯铣。例如,一組新聞文章可以被處理為一張?jiān)~頻表轮纫,而這張?jiān)~頻表就可以用于情感分析腔寡。
大部分電子表格軟件(比如Microsoft Excel,它可能是世界上使用最廣泛的數(shù)據(jù)分析工具了)的用戶不會(huì)對(duì)此類數(shù)據(jù)感到陌生掌唾。
1.2 為什么要使用Python進(jìn)行數(shù)據(jù)分析
許許多多的人(包括我自己)都很容易愛上Python這門語(yǔ)言放前。自從1991年誕生以來(lái),Python現(xiàn)在已經(jīng)成為最受歡迎的動(dòng)態(tài)編程語(yǔ)言之一郑兴,其他還有Perl犀斋、Ruby等。由于擁有大量的Web框架(比如Rails(Ruby)和Django(Python))情连,自從2005年,非常流行使用Python和Ruby進(jìn)行網(wǎng)站建設(shè)工作览效。這些語(yǔ)言常被稱作腳本(scripting)語(yǔ)言却舀,因?yàn)樗鼈兛梢杂糜诰帉懞?jiǎn)短而粗糙的小程序(也就是腳本)虫几。我個(gè)人并不喜歡“腳本語(yǔ)言”這個(gè)術(shù)語(yǔ),因?yàn)樗孟裨谡f(shuō)這些語(yǔ)言無(wú)法用于構(gòu)建嚴(yán)謹(jǐn)?shù)能浖彀巍T诒姸嘟忉屝驼Z(yǔ)言中辆脸,由于各種歷史和文化的原因,Python發(fā)展出了一個(gè)巨大而活躍的科學(xué)計(jì)算(scientific computing)社區(qū)螃诅。在過(guò)去的10年啡氢,Python從一個(gè)邊緣或“自擔(dān)風(fēng)險(xiǎn)”的科學(xué)計(jì)算語(yǔ)言,成為了數(shù)據(jù)科學(xué)术裸、機(jī)器學(xué)習(xí)倘是、學(xué)界和工業(yè)界軟件開發(fā)最重要的語(yǔ)言之一。
在數(shù)據(jù)分析袭艺、交互式計(jì)算以及數(shù)據(jù)可視化方面搀崭,Python將不可避免地與其他開源和商業(yè)的領(lǐng)域特定編程語(yǔ)言/工具進(jìn)行對(duì)比,如R猾编、MATLAB瘤睹、SAS、Stata等答倡。近年來(lái)轰传,由于Python的庫(kù)(例如pandas和scikit-learn)不斷改良,使其成為數(shù)據(jù)分析任務(wù)的一個(gè)優(yōu)選方案瘪撇。結(jié)合其在通用編程方面的強(qiáng)大實(shí)力绸吸,我們完全可以只使用Python這一種語(yǔ)言構(gòu)建以數(shù)據(jù)為中心的應(yīng)用。
Python作為膠水語(yǔ)言
Python能變?yōu)槌晒Φ目茖W(xué)計(jì)算工具的部分原因是设江,它能夠輕松地集成C锦茁、C++以及Fortran代碼。大部分現(xiàn)代計(jì)算環(huán)境都利用了一些Fortran和C庫(kù)來(lái)實(shí)現(xiàn)線性代數(shù)叉存、優(yōu)選码俩、積分、快速傅里葉變換以及其他諸如此類的算法歼捏。許多企業(yè)和國(guó)家實(shí)驗(yàn)室也利用Python來(lái)“粘合”那些已經(jīng)用了多年的遺留軟件系統(tǒng)稿存。
大多數(shù)軟件都是由兩部分代碼組成的:少量需要占用大部分執(zhí)行時(shí)間的代碼,以及大量不經(jīng)常執(zhí)行的“膠水代碼”瞳秽。大部分情況下瓣履,膠水代碼的執(zhí)行時(shí)間是微不足道的。開發(fā)人員的精力幾乎都是花在優(yōu)化計(jì)算瓶頸上面练俐,有時(shí)更是直接轉(zhuǎn)用更低級(jí)的語(yǔ)言(比如C)袖迎。
解決“兩種語(yǔ)言”問(wèn)題
很多組織通常都會(huì)用一種類似于領(lǐng)域特定的計(jì)算語(yǔ)言(如SAS和R)對(duì)新的想法進(jìn)行研究、原型構(gòu)建和測(cè)試,然后再將這些想法移植到某個(gè)更大的生產(chǎn)系統(tǒng)中去(可能是用Java燕锥、C#或C++編寫的)辜贵。人們逐漸意識(shí)到,Python不僅適用于研究和原型構(gòu)建归形,同時(shí)也適用于構(gòu)建生產(chǎn)系統(tǒng)托慨。為什么一種語(yǔ)言就夠了,卻要使用兩個(gè)語(yǔ)言的開發(fā)環(huán)境呢暇榴?我相信越來(lái)越多的企業(yè)也會(huì)這樣看厚棵,因?yàn)檠芯咳藛T和工程技術(shù)人員使用同一種編程工具將會(huì)給企業(yè)帶來(lái)非常顯著的組織效益。
為什么不選Python
雖然Python非常適合構(gòu)建分析應(yīng)用以及通用系統(tǒng)蔼紧,但它對(duì)不少應(yīng)用場(chǎng)景適用性較差婆硬。
由于Python是一種解釋型編程語(yǔ)言,因此大部分Python代碼都要比用編譯型語(yǔ)言(比如Java和C++)編寫的代碼運(yùn)行慢得多歉井。由于程序員的時(shí)間通常都比CPU時(shí)間值錢柿祈,因此許多人也愿意在這里做一些權(quán)衡。但是哩至,在那些要求延遲非常小或高資源利用率的應(yīng)用中(例如高頻交易系統(tǒng))躏嚎,耗費(fèi)時(shí)間使用諸如C++這樣更低級(jí)、更低生產(chǎn)率的語(yǔ)言進(jìn)行編程也是值得的菩貌。
對(duì)于高并發(fā)卢佣、多線程的應(yīng)用程序而言(尤其是擁有許多計(jì)算密集型線程的應(yīng)用程序),Python并不是一種理想的編程語(yǔ)言箭阶。這是因?yàn)镻ython有一個(gè)叫做全局解釋器鎖(Global Interpreter Lock虚茶,GIL)的組件,這是一種防止解釋器同時(shí)執(zhí)行多條Python字節(jié)碼指令的機(jī)制仇参。有關(guān)“為什么會(huì)存在GIL”的技術(shù)性原因超出了本書的范圍嘹叫。雖然很多大數(shù)據(jù)處理應(yīng)用程序?yàn)榱四茉谳^短的時(shí)間內(nèi)完成數(shù)據(jù)集的處理工作都需要運(yùn)行在計(jì)算機(jī)集群上,但是仍然有一些情況需要用單進(jìn)程多線程系統(tǒng)來(lái)解決诈乒。
這并不是說(shuō)Python不能執(zhí)行真正的多線程并行代碼罩扇。例如,Python的C插件使用原生的C或C++的多線程怕磨,可以并行運(yùn)行而不被GIL影響喂饥,只要它們不頻繁地與Python對(duì)象交互。
1.3 重要的Python庫(kù)
考慮到那些還不太了解Python科學(xué)計(jì)算生態(tài)系統(tǒng)和庫(kù)的讀者肠鲫,下面我先對(duì)各個(gè)庫(kù)做一個(gè)簡(jiǎn)單的介紹员帮。
NumPy
NumPy(Numerical Python的簡(jiǎn)稱)是Python科學(xué)計(jì)算的基礎(chǔ)包。本書大部分內(nèi)容都基于NumPy以及構(gòu)建于其上的庫(kù)导饲。它提供了以下功能(不限于此):
快速高效的多維數(shù)組對(duì)象ndarray捞高。
用于對(duì)數(shù)組執(zhí)行元素級(jí)計(jì)算以及直接對(duì)數(shù)組執(zhí)行數(shù)學(xué)運(yùn)算的函數(shù)氯材。
用于讀寫硬盤上基于數(shù)組的數(shù)據(jù)集的工具。
-
線性代數(shù)運(yùn)算棠枉、傅里葉變換浓体,以及隨機(jī)數(shù)生成泡挺。
-成熟的C API辈讶, 用于Python插件和原生C、C++娄猫、Fortran代碼訪問(wèn)NumPy的數(shù)據(jù)結(jié)構(gòu)和計(jì)算工具贱除。
除了為Python提供快速的數(shù)組處理能力,NumPy在數(shù)據(jù)分析方面還有另外一個(gè)主要作用媳溺,即作為在算法和庫(kù)之間傳遞數(shù)據(jù)的容器月幌。對(duì)于數(shù)值型數(shù)據(jù),NumPy數(shù)組在存儲(chǔ)和處理數(shù)據(jù)時(shí)要比內(nèi)置的Python數(shù)據(jù)結(jié)構(gòu)高效得多悬蔽。此外扯躺,由低級(jí)語(yǔ)言(比如C和Fortran)編寫的庫(kù)可以直接操作NumPy數(shù)組中的數(shù)據(jù),無(wú)需進(jìn)行任何數(shù)據(jù)復(fù)制工作蝎困。因此录语,許多Python的數(shù)值計(jì)算工具要么使用NumPy數(shù)組作為主要的數(shù)據(jù)結(jié)構(gòu),要么可以與NumPy進(jìn)行無(wú)縫交互操作禾乘。
pandas
pandas提供了快速便捷處理結(jié)構(gòu)化數(shù)據(jù)的大量數(shù)據(jù)結(jié)構(gòu)和函數(shù)澎埠。自從2010年出現(xiàn)以來(lái),它助使Python成為強(qiáng)大而高效的數(shù)據(jù)分析環(huán)境始藕。本書用得最多的pandas對(duì)象是DataFrame蒲稳,它是一個(gè)面向列(column-oriented)的二維表結(jié)構(gòu),另一個(gè)是Series伍派,一個(gè)一維的標(biāo)簽化數(shù)組對(duì)象江耀。
pandas兼具NumPy高性能的數(shù)組計(jì)算功能以及電子表格和關(guān)系型數(shù)據(jù)庫(kù)(如SQL)靈活的數(shù)據(jù)處理功能。它提供了復(fù)雜精細(xì)的索引功能诉植,以便更為便捷地完成重塑祥国、切片和切塊、聚合以及選取數(shù)據(jù)子集等操作倍踪。因?yàn)閿?shù)據(jù)操作系宫、準(zhǔn)備、清洗是數(shù)據(jù)分析最重要的技能建车,pandas是本書的重點(diǎn)扩借。
作為一點(diǎn)背景,我是在2008年初開始開發(fā)pandas的缤至,那時(shí)我任職于AQR Capital Management潮罪,一家量化投資管理公司康谆,我有許多工作需求都不能用任何單一的工具解決:
有標(biāo)簽軸的數(shù)據(jù)結(jié)構(gòu),支持自動(dòng)或清晰的數(shù)據(jù)對(duì)齊嫉到。這可以防止由于數(shù)據(jù)不對(duì)齊客税,和處理來(lái)源不同的索引不同的數(shù)據(jù)状答,造成的錯(cuò)誤。
集成時(shí)間序列功能。
相同的數(shù)據(jù)結(jié)構(gòu)用于處理時(shí)間序列數(shù)據(jù)和非時(shí)間序列數(shù)據(jù)锯七。
保存元數(shù)據(jù)的算術(shù)運(yùn)算和壓縮代箭。
靈活處理缺失數(shù)據(jù)儒鹿。
合并和其它流行數(shù)據(jù)庫(kù)(例如基于SQL的數(shù)據(jù)庫(kù))的關(guān)系操作倦逐。
我想只用一種工具就實(shí)現(xiàn)所有功能,并使用通用軟件開發(fā)語(yǔ)言疫赎。Python是一個(gè)不錯(cuò)的候選語(yǔ)言盛撑,但是此時(shí)沒有集成的數(shù)據(jù)結(jié)構(gòu)和工具來(lái)實(shí)現(xiàn)。我一開始就是想把pandas設(shè)計(jì)為一款適用于金融和商業(yè)分析的工具捧搞,pandas專注于深度時(shí)間序列功能和工具抵卫,適用于時(shí)間索引化的數(shù)據(jù)。
對(duì)于使用R語(yǔ)言進(jìn)行統(tǒng)計(jì)計(jì)算的用戶胎撇,肯定不會(huì)對(duì)DataFrame這個(gè)名字感到陌生介粘,因?yàn)樗醋杂赗的data.frame對(duì)象。但與Python不同创坞,data frames是構(gòu)建于R和它的標(biāo)準(zhǔn)庫(kù)碗短。因此,pandas的許多功能不屬于R或它的擴(kuò)展包题涨。
pandas這個(gè)名字源于panel data(面板數(shù)據(jù)偎谁,這是多維結(jié)構(gòu)化數(shù)據(jù)集在計(jì)量經(jīng)濟(jì)學(xué)中的術(shù)語(yǔ))以及Python data analysis(Python數(shù)據(jù)分析)。
matplotlib
matplotlib是最流行的用于繪制圖表和其它二維數(shù)據(jù)可視化的Python庫(kù)纲堵。它最初由John D.Hunter(JDH)創(chuàng)建巡雨,目前由一個(gè)龐大的開發(fā)人員團(tuán)隊(duì)維護(hù)。它非常適合創(chuàng)建出版物上用的圖表席函。雖然還有其它的Python可視化庫(kù)铐望,matplotlib卻是使用最廣泛的,并且它和其它生態(tài)工具配合也非常完美茂附。我認(rèn)為正蛙,可以使用它作為默認(rèn)的可視化工具。
IPython和Jupyter
IPython項(xiàng)目起初是Fernando Pérez在2001年的一個(gè)用以加強(qiáng)和Python交互的子項(xiàng)目营曼。在隨后的16年中乒验,它成為了Python數(shù)據(jù)棧最重要的工具之一。雖然IPython本身沒有提供計(jì)算和數(shù)據(jù)分析的工具窖梁,它卻可以大大提高交互式計(jì)算和軟件開發(fā)的生產(chǎn)率肪虎。IPython鼓勵(lì)“執(zhí)行-探索”的工作流掠兄,區(qū)別于其它編程軟件的“編輯-編譯-運(yùn)行”的工作流。它還可以方便地訪問(wèn)系統(tǒng)的shell和文件系統(tǒng)。因?yàn)榇蟛糠值臄?shù)據(jù)分析代碼包括探索特铝、試錯(cuò)和重復(fù)赠幕,IPython可以使工作更快。
2014年莺治,F(xiàn)ernando和IPython團(tuán)隊(duì)宣布了Jupyter項(xiàng)目廓鞠,一個(gè)更寬泛的多語(yǔ)言交互計(jì)算工具的計(jì)劃帚稠。IPython web notebook變成了Jupyter notebook,現(xiàn)在支持40種編程語(yǔ)言床佳。IPython現(xiàn)在可以作為Jupyter使用Python的內(nèi)核(一種編程語(yǔ)言模式)滋早。
IPython變成了Jupyter龐大開源項(xiàng)目(一個(gè)交互和探索式計(jì)算的高效環(huán)境)中的一個(gè)組件。它最老也是最簡(jiǎn)單的模式砌们,現(xiàn)在是一個(gè)用于編寫杆麸、測(cè)試、調(diào)試Python代碼的強(qiáng)化shell浪感。你還可以使用通過(guò)Jupyter Notebook昔头,一個(gè)支持多種語(yǔ)言的交互式網(wǎng)絡(luò)代碼“筆記本”,來(lái)使用IPython影兽。IPython shell 和Jupyter notebooks特別適合進(jìn)行數(shù)據(jù)探索和可視化揭斧。
Jupyter notebooks還可以編寫Markdown和HTML內(nèi)容,提供了一種創(chuàng)建代碼和文本的富文本方法赢笨。其它編程語(yǔ)言也在Jupyter中植入了內(nèi)核未蝌,好讓在Jupyter中可以使用Python另外的語(yǔ)言。
對(duì)我個(gè)人而言,我的大部分Python都要用到IPython左冬,包括運(yùn)行桐筏、調(diào)試和測(cè)試代碼。
在本書的GitHub頁(yè)面拇砰,你可以找到包含各章節(jié)所有代碼實(shí)例的Jupyter notebooks梅忌。
SciPy
SciPy是一組專門解決科學(xué)計(jì)算中各種標(biāo)準(zhǔn)問(wèn)題域的包的集合,主要包括下面這些包:
scipy.integrate:數(shù)值積分例程和微分方程求解器除破。
scipy.linalg:擴(kuò)展了由numpy.linalg提供的線性代數(shù)例程和矩陣分解功能牧氮。
scipy.optimize:函數(shù)優(yōu)化器(最小化器)以及根查找算法。
scipy.signal:信號(hào)處理工具瑰枫。
scipy.sparse:稀疏矩陣和稀疏線性系統(tǒng)求解器踱葛。
scipy.special:SPECFUN(這是一個(gè)實(shí)現(xiàn)了許多常用數(shù)學(xué)函數(shù)(如伽瑪函數(shù))的Fortran庫(kù))的包裝器。
scipy.stats:標(biāo)準(zhǔn)連續(xù)和離散概率分布(如密度函數(shù)光坝、采樣器尸诽、連續(xù)分布函數(shù)等)、各種統(tǒng)計(jì)檢驗(yàn)方法盯另,以及更好的描述統(tǒng)計(jì)法性含。
NumPy和SciPy結(jié)合使用,便形成了一個(gè)相當(dāng)完備和成熟的計(jì)算平臺(tái)鸳惯,可以處理多種傳統(tǒng)的科學(xué)計(jì)算問(wèn)題商蕴。
scikit-learn
2010年誕生以來(lái)叠萍,scikit-learn成為了Python的通用機(jī)器學(xué)習(xí)工具包。僅僅七年绪商,就匯聚了全世界超過(guò)1500名貢獻(xiàn)者俭令。它的子模塊包括:
分類:SVM、近鄰部宿、隨機(jī)森林抄腔、邏輯回歸等等。
回歸:Lasso理张、嶺回歸等等赫蛇。
聚類:k-均值、譜聚類等等雾叭。
降維:PCA悟耘、特征選擇、矩陣分解等等织狐。
選型:網(wǎng)格搜索暂幼、交叉驗(yàn)證、度量移迫。
預(yù)處理:特征提取旺嬉、標(biāo)準(zhǔn)化。
與pandas厨埋、statsmodels和IPython一起邪媳,scikit-learn對(duì)于Python成為高效數(shù)據(jù)科學(xué)編程語(yǔ)言起到了關(guān)鍵作用。雖然本書不會(huì)詳細(xì)講解scikit-learn荡陷,我會(huì)簡(jiǎn)要介紹它的一些模型雨效,以及用其它工具如何使用這些模型。
statsmodels
statsmodels是一個(gè)統(tǒng)計(jì)分析包废赞,起源于斯坦福大學(xué)統(tǒng)計(jì)學(xué)教授Jonathan Taylor徽龟,他設(shè)計(jì)了多種流行于R語(yǔ)言的回歸分析模型。Skipper Seabold和Josef Perktold在2010年正式創(chuàng)建了statsmodels項(xiàng)目唉地,隨后匯聚了大量的使用者和貢獻(xiàn)者据悔。受到R的公式系統(tǒng)的啟發(fā),Nathaniel Smith發(fā)展出了Patsy項(xiàng)目渣蜗,它提供了statsmodels的公式或模型的規(guī)范框架屠尊。
與scikit-learn比較,statsmodels包含經(jīng)典統(tǒng)計(jì)學(xué)和經(jīng)濟(jì)計(jì)量學(xué)的算法耕拷。包括如下子模塊:
回歸模型:線性回歸讼昆,廣義線性模型,健壯線性模型,線性混合效應(yīng)模型等等浸赫。
方差分析(ANOVA)闰围。
時(shí)間序列分析:AR,ARMA既峡,ARIMA羡榴,VAR和其它模型。
非參數(shù)方法: 核密度估計(jì)运敢,核回歸校仑。
統(tǒng)計(jì)模型結(jié)果可視化。
statsmodels更關(guān)注與統(tǒng)計(jì)推斷传惠,提供不確定估計(jì)和參數(shù)p-值迄沫。相反的,scikit-learn注重預(yù)測(cè)卦方。
同scikit-learn一樣羊瘩,我也只是簡(jiǎn)要介紹statsmodels,以及如何用NumPy和pandas使用它盼砍。
1.4 安裝和設(shè)置
由于人們用Python所做的事情不同尘吗,所以沒有一個(gè)普適的Python及其插件包的安裝方案。由于許多讀者的Python科學(xué)計(jì)算環(huán)境都不能完全滿足本書的需要浇坐,所以接下來(lái)我將詳細(xì)介紹各個(gè)操作系統(tǒng)上的安裝方法睬捶。我推薦免費(fèi)的Anaconda安裝包。寫作本書時(shí)吗跋,Anaconda提供Python 2.7和3.6兩個(gè)版本侧戴,以后可能發(fā)生變化。本書使用的是Python 3.6跌宛,因此推薦選擇Python 3.6或更高版本。
Windows
要在Windows上運(yùn)行积仗,先下載Anaconda安裝包疆拘。推薦跟隨Anaconda下載頁(yè)面的Windows安裝指導(dǎo),安裝指導(dǎo)在寫作本書和讀者看到此文的的這段時(shí)間內(nèi)可能發(fā)生變化寂曹。
現(xiàn)在哎迄,來(lái)確認(rèn)設(shè)置是否正確。打開命令行窗口(cmd.exe
)隆圆,輸入python
以打開Python解釋器漱挚。可以看到類似下面的Anaconda版本的輸出:
C:\Users\wesm>python
Python 3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul 5 2016, 11:41:13)
[MSC v.1900 64 bit (AMD64)] on win32
>>>
要退出shell渺氧,按Ctrl-D(Linux或macOS上)旨涝,Ctrl-Z(Windows上),或輸入命令exit()
侣背,再按Enter白华。
Apple (OS X, macOS)
下載OS X Anaconda安裝包慨默,它的名字類似Anaconda3-4.1.0-MacOSX-x86_64.pkg。雙擊.pkg文件弧腥,運(yùn)行安裝包厦取。安裝包運(yùn)行時(shí),會(huì)自動(dòng)將Anaconda執(zhí)行路徑添加到.bash_profile
文件管搪,它位于/Users/$USER/.bash_profile
虾攻。
為了確認(rèn)成功,在系統(tǒng)shell打開IPython:
$ ipython
要退出shell,按Ctrl-D凌净,或輸入命令exit()
莽龟,再按Enter。
GNU/Linux
Linux版本很多朋沮,這里給出Debian、Ubantu缀壤、CentOS和Fedora的安裝方法樊拓。安裝包是一個(gè)腳本文件,必須在shell中運(yùn)行塘慕。取決于系統(tǒng)是32位還是64位筋夏,要么選擇x86 (32位)或x86_64 (64位)安裝包。隨后你會(huì)得到一個(gè)文件图呢,名字類似于Anaconda3-4.1.0-Linux-x86_64.sh
条篷。用bash進(jìn)行安裝:
$ bash Anaconda3-4.1.0-Linux-x86_64.sh
筆記:某些Linux版本在包管理器中有滿足需求的Python包,只需用類似apt的工具安裝就行蛤织。這里講的用Anaconda安裝赴叹,適用于不同的Linux安裝包,也很容易將包升級(jí)到最新版本指蚜。
接受許可之后乞巧,會(huì)向你詢問(wèn)在哪里放置Anaconda的文件。我推薦將文件安裝到默認(rèn)的home目錄摊鸡,例如/home/$USER/anaconda
绽媒。
Anaconda安裝包可能會(huì)詢問(wèn)你是否將bin/
目錄添加到$PATH
變量。如果在安裝之后有任何問(wèn)題免猾,你可以修改文件.bashrc
(或.zshrc
是辕,如果使用的是zsh shell)為類似以下的內(nèi)容:
export PATH=/home/$USER/anaconda/bin:$PATH
做完之后,你可以開啟一個(gè)新窗口猎提,或再次用~/.bashrc
執(zhí)行.bashrc
获三。
安裝或升級(jí)Python包
在你閱讀本書的時(shí)候,你可能想安裝另外的不在Anaconda中的Python包。通常石窑,可以用以下命令安裝:
conda install package_name
如果這個(gè)命令不行牌芋,也可以用pip包管理工具:
pip install package_name
你可以用conda update
命令升級(jí)包:
conda update package_name
pip可以用--upgrade
升級(jí):
pip install --upgrade package_name
本書中,你有許多機(jī)會(huì)嘗試這些命令松逊。
注意:當(dāng)你使用conda和pip二者安裝包時(shí)躺屁,千萬(wàn)不要用pip升級(jí)conda的包,這樣會(huì)導(dǎo)致環(huán)境發(fā)生問(wèn)題经宏。當(dāng)使用Anaconda或Miniconda時(shí)犀暑,最好首先使用conda進(jìn)行升級(jí)。
Python 2 和 Python 3
第一版的Python 3.x出現(xiàn)于2008年烁兰。它有一系列的變化耐亏,與之前的Python 2.x代碼有不兼容的地方。因?yàn)閺?991年P(guān)ython出現(xiàn)算起沪斟,已經(jīng)過(guò)了17年广辰,Python 3 的出現(xiàn)被視為吸取一些列教訓(xùn)的更優(yōu)結(jié)果。
2012年主之,因?yàn)樵S多包還沒有完全支持Python 3择吊,許多科學(xué)和數(shù)據(jù)分析社區(qū)還是在使用Python 2.x。因此槽奕,本書第一版使用的是Python 2.7〖妇Γ現(xiàn)在,用戶可以在Python 2.x和Python 3.x間自由選擇粤攒,二者都有良好的支持所森。
但是,Python 2.x在2020年就會(huì)到期(包括重要的安全補(bǔ)逗唤印)焕济,因此再用Python 2.7就不是好的選擇了。因此盔几,本書使用了Python 3.6吼蚁,這一廣泛使用、支持良好的穩(wěn)定版本问欠。我們已經(jīng)稱Python 2.x為“遺留版本”,簡(jiǎn)稱Python 3.x為“Python”粒蜈。我建議你也是如此顺献。
本書基于Python 3.6。你的Python版本也許高于3.6枯怖,但是示例代碼應(yīng)該是向前兼容的注整。一些示例代碼可能在Python 2.7上有所不同,或完全不兼容。
集成開發(fā)環(huán)境(IDEs)和文本編輯器
當(dāng)被問(wèn)到我的標(biāo)準(zhǔn)開發(fā)環(huán)境肿轨,我?guī)缀蹩偸腔卮稹癐Python加文本編輯器”寿冕。我通常在編程時(shí),反復(fù)在IPython或Jupyter notebooks中測(cè)試和調(diào)試每條代碼椒袍。也可以交互式操作數(shù)據(jù)驼唱,和可視化驗(yàn)證數(shù)據(jù)操作中某一特殊集合。在shell中使用pandas和NumPy也很容易驹暑。
但是玫恳,當(dāng)創(chuàng)建軟件時(shí),一些用戶可能更想使用特點(diǎn)更為豐富的IDE优俘,而不僅僅是原始的蕾西Emacs或Vim的文本編輯器京办。以下是一些IDE:
PyDev(免費(fèi)),基于Eclipse平臺(tái)的IDE帆焕;
JetBrains的PyCharm(商業(yè)用戶需要訂閱惭婿,開源開發(fā)者免費(fèi));
Visual Studio(Windows用戶)的Python Tools叶雹;
Spyder(免費(fèi))财饥,Anaconda附帶的IDE;
Komodo IDE(商業(yè))浑娜。
因?yàn)镻ython的流行佑力,大多數(shù)文本編輯器,比如Atom和Sublime Text 3筋遭,對(duì)Python的支持也非常好打颤。
1.5 社區(qū)和會(huì)議
除了在網(wǎng)上搜索,各式各樣的科學(xué)和數(shù)據(jù)相關(guān)的Python郵件列表是非常有幫助的漓滔,很容易獲得回答编饺。包括:
pydata:一個(gè)Google群組列表,用以回答Python數(shù)據(jù)分析和pandas的問(wèn)題响驴;
pystatsmodels: statsmodels或pandas相關(guān)的問(wèn)題透且;
scikit-learn和Python機(jī)器學(xué)習(xí)郵件列表,scikit-learn@python.org豁鲤;
numpy-discussion:和NumPy相關(guān)的問(wèn)題秽誊;
scipy-user:SciPy和科學(xué)計(jì)算的問(wèn)題;
因?yàn)檫@些郵件列表的URLs可以很容易搜索到琳骡,但因?yàn)榭赡馨l(fā)生變化锅论,所以沒有給出。
每年楣号,世界各地會(huì)舉辦許多Python開發(fā)者大會(huì)最易。如果你想結(jié)識(shí)其他有相同興趣的人怒坯,如果可能的話,我建議你去參加一個(gè)藻懒。許多會(huì)議會(huì)對(duì)無(wú)力支付入場(chǎng)費(fèi)和差旅費(fèi)的人提供財(cái)力幫助剔猿。下面是一些會(huì)議:
PyCon和EuroPython:北美和歐洲的兩大Python會(huì)議;
SciPy和EuroSciPy:北美和歐洲兩大面向科學(xué)計(jì)算的會(huì)議嬉荆;
PyData:世界范圍內(nèi)归敬,一些列的地區(qū)性會(huì)議,專注數(shù)據(jù)科學(xué)和數(shù)據(jù)分析员寇;
國(guó)際和地區(qū)的PyCon會(huì)議(http://pycon.org有完整列表) 弄慰。
1.6 本書導(dǎo)航
如果之前從未使用過(guò)Python,那你可能需要先看看本書的第2章和第3章蝶锋,我簡(jiǎn)要介紹了Python的特點(diǎn)陆爽,IPython和Jupyter notebooks。這些知識(shí)是為本書后面的內(nèi)容做鋪墊扳缕。如果你已經(jīng)掌握Python慌闭,可以選擇跳過(guò)。
接下來(lái)躯舔,簡(jiǎn)單地介紹了NumPy的關(guān)鍵特性驴剔,附錄A中是更高級(jí)的NumPy功能。然后粥庄,我介紹了pandas丧失,本書剩余的內(nèi)容全部是使用pandas、NumPy和matplotlib處理數(shù)據(jù)分析的問(wèn)題惜互。我已經(jīng)盡量讓全書的結(jié)構(gòu)循序漸進(jìn)布讹,但偶爾會(huì)有章節(jié)之間的交叉,有時(shí)用到的概念還沒有介紹過(guò)训堆。
盡管讀者各自的工作任務(wù)不同描验,大體可以分為幾類:
-
與外部世界交互
閱讀編寫多種文件格式和數(shù)據(jù)商店;
-
數(shù)據(jù)準(zhǔn)備
清洗坑鱼、修改膘流、結(jié)合、標(biāo)準(zhǔn)化鲁沥、重塑呼股、切片、切割画恰、轉(zhuǎn)換數(shù)據(jù)卖怜,以進(jìn)行分析;
-
轉(zhuǎn)換數(shù)據(jù)
對(duì)酒的數(shù)據(jù)集進(jìn)行數(shù)學(xué)和統(tǒng)計(jì)操作阐枣,生成新的數(shù)據(jù)集(例如马靠,通過(guò)各組變量聚類成大的表);
-
建模和計(jì)算
將數(shù)據(jù)綁定統(tǒng)計(jì)模型蔼两、機(jī)器學(xué)習(xí)算法甩鳄、或其他計(jì)算工具;
-
展示
創(chuàng)建交互式和靜態(tài)的圖表可視化和文本總結(jié)额划。
代碼示例
本書大部分代碼示例的輸入形式和輸出結(jié)果都會(huì)按照其在IPython shell或Jupyter notebooks中執(zhí)行時(shí)的樣子進(jìn)行排版:
In [5]: CODE EXAMPLE
Out[5]: OUTPUT
但你看到類似的示例代碼妙啃,就是讓你在in
的部分輸入代碼,按Enter鍵執(zhí)行(Jupyter中是按Shift-Enter)俊戳。然后就可以在out
看到輸出揖赴。
示例數(shù)據(jù)
各章的示例數(shù)據(jù)都存放在GitHub上:http://github.com/pydata/pydata-book。下載這些數(shù)據(jù)的方法有二:使用git版本控制命令行程序抑胎;直接從網(wǎng)站上下載該GitHub庫(kù)的zip文件燥滑。如果遇到了問(wèn)題,可以到我的個(gè)人主頁(yè)阿逃,http://wesmckinney.com/铭拧,獲取最新的指導(dǎo)。
為了讓所有示例都能重現(xiàn)恃锉,我已經(jīng)盡我所能使其包含所有必需的東西搀菩,但仍然可能會(huì)有一些錯(cuò)誤或遺漏。如果出現(xiàn)這種情況的話破托,請(qǐng)給我發(fā)郵件:wesmckinn@gmail.com肪跋。報(bào)告本書錯(cuò)誤的最好方法是O’Reilly的errata頁(yè)面,http://www.bit.ly/pyDataAnalysis_errata土砂。
引入慣例
Python社區(qū)已經(jīng)廣泛采取了一些常用模塊的命名慣例:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import statsmodels as sm
也就是說(shuō)州既,當(dāng)你看到np.arange時(shí),就應(yīng)該想到它引用的是NumPy中的arange函數(shù)瘟芝。這樣做的原因是:在Python軟件開發(fā)過(guò)程中易桃,不建議直接引入類似NumPy這種大型庫(kù)的全部?jī)?nèi)容(from numpy import *)。
行話
由于你可能不太熟悉書中使用的一些有關(guān)編程和數(shù)據(jù)科學(xué)方面的常用術(shù)語(yǔ)锌俱,所以我在這里先給出其簡(jiǎn)單定義:
數(shù)據(jù)規(guī)整(Munge/Munging/Wrangling)
指的是將非結(jié)構(gòu)化和(或)散亂數(shù)據(jù)處理為結(jié)構(gòu)化或整潔形式的整個(gè)過(guò)程猴蹂。這幾個(gè)詞已經(jīng)悄悄成為當(dāng)今數(shù)據(jù)黑客們的行話了榜苫。Munge這個(gè)詞跟Lunge押韻。
偽碼(Pseudocode)
算法或過(guò)程的“代碼式”描述,而這些代碼本身并不是實(shí)際有效的源代碼铃芦。
語(yǔ)法糖(Syntactic sugar)
這是一種編程語(yǔ)法,它并不會(huì)帶來(lái)新的特性冕茅,但卻能使代碼更易讀落午、更易寫。
第2章 Python語(yǔ)法基礎(chǔ)鲫咽,IPython和Jupyter Notebooks
當(dāng)我在2011年和2012年寫作本書的第一版時(shí)签赃,可用的學(xué)習(xí)Python數(shù)據(jù)分析的資源很少谷异。這部分上是一個(gè)雞和蛋的問(wèn)題:我們現(xiàn)在使用的庫(kù),比如pandas锦聊、scikit-learn和statsmodels歹嘹,那時(shí)相對(duì)來(lái)說(shuō)并不成熟。2017年孔庭,數(shù)據(jù)科學(xué)尺上、數(shù)據(jù)分析和機(jī)器學(xué)習(xí)的資源已經(jīng)很多,原來(lái)通用的科學(xué)計(jì)算拓展到了計(jì)算機(jī)科學(xué)家圆到、物理學(xué)家和其它研究領(lǐng)域的工作人員怎抛。學(xué)習(xí)Python和成為軟件工程師的優(yōu)秀書籍也有
因?yàn)檫@本書是專注于Python數(shù)據(jù)處理的,對(duì)于一些Python的數(shù)據(jù)結(jié)構(gòu)和庫(kù)的特性難免不足芽淡。因此马绝,本章和第3章的內(nèi)容只夠你能學(xué)習(xí)本書后面的內(nèi)容。
在我來(lái)看吐绵,沒有必要為了數(shù)據(jù)分析而去精通Python迹淌。我鼓勵(lì)你使用IPython shell和Jupyter試驗(yàn)示例代碼,并學(xué)習(xí)不同類型己单、函數(shù)和方法的文檔唉窃。雖然我已盡力讓本書內(nèi)容循序漸進(jìn),但讀者偶爾仍會(huì)碰到?jīng)]有之前介紹過(guò)的內(nèi)容纹笼。
本書大部分內(nèi)容關(guān)注的是基于表格的分析和處理大規(guī)模數(shù)據(jù)集的數(shù)據(jù)準(zhǔn)備工具。為了使用這些工具廷痘,必須首先將混亂的數(shù)據(jù)規(guī)整為整潔的表格(或結(jié)構(gòu)化)形式兄猩。幸好淹真,Python是一個(gè)理想的語(yǔ)言讶迁,可以快速整理數(shù)據(jù)。使用Python越熟練核蘸,越容易準(zhǔn)備新的數(shù)據(jù)集以進(jìn)行分析巍糯。
本書中使用的工具最好在IPython和Jupyter中親自嘗試啸驯。當(dāng)你學(xué)會(huì)了如何啟用Ipython和Jupyter,我建議你跟隨示例代碼進(jìn)行練習(xí)鳞贷。與任何鍵盤驅(qū)動(dòng)的操作環(huán)境一樣坯汤,記住常見的命令也是學(xué)習(xí)曲線的一部分。
筆記:本章沒有介紹Python的某些概念搀愧,如類和面向?qū)ο缶幊蹋憧赡軙?huì)發(fā)現(xiàn)它們?cè)赑ython數(shù)據(jù)分析中很有用疆偿。
為了加強(qiáng)Python知識(shí)咱筛,我建議你學(xué)習(xí)官方Python教程,https://docs.python.org/3/杆故,或是通用的Python教程書籍迅箩,比如:
Python Cookbook,第3版处铛,David Beazley和Brian K. Jones著(O’Reilly)
流暢的Python饲趋,Luciano Ramalho著 (O’Reilly)
高效的Python,Brett Slatkin著 (Pearson)
2.1 Python解釋器
Python是解釋性語(yǔ)言撤蟆。Python解釋器同一時(shí)間只能運(yùn)行一個(gè)程序的一條語(yǔ)句奕塑。標(biāo)準(zhǔn)的交互Python解釋器可以在命令行中通過(guò)鍵入python
命令打開:
$ python
Python 3.6.0 | packaged by conda-forge | (default, Jan 13 2017, 23:17:12)
[GCC 4.8.2 20140120 (Red Hat 4.8.2-15)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 5
>>> print(a)
5
>>>
提示輸入代碼。要退出Python解釋器返回終端家肯,可以輸入exit()
或按Ctrl-D龄砰。
運(yùn)行Python程序只需調(diào)用Python的同時(shí),使用一個(gè).py
文件作為它的第一個(gè)參數(shù)讨衣。假設(shè)創(chuàng)建了一個(gè)hello_world.py
文件换棚,它的內(nèi)容是:
print('Hello world')
你可以用下面的命令運(yùn)行它(hello_world.py
文件必須位于終端的工作目錄):
$ python hello_world.py
Hello world
一些Python程序員總是這樣執(zhí)行Python代碼的,從事數(shù)據(jù)分析和科學(xué)計(jì)算的人卻會(huì)使用IPython反镇,一個(gè)強(qiáng)化的Python解釋器固蚤,或Jupyter notebooks,一個(gè)網(wǎng)頁(yè)代碼筆記本歹茶,它原先是IPython的一個(gè)子項(xiàng)目夕玩。在本章中,我介紹了如何使用IPython和Jupyter辆亏,在附錄A中有更深入的介紹风秤。當(dāng)你使用%run
命令,IPython會(huì)同樣執(zhí)行指定文件中的代碼扮叨,結(jié)束之后缤弦,還可以與結(jié)果交互:
$ ipython
Python 3.6.0 | packaged by conda-forge | (default, Jan 13 2017, 23:17:12)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: %run hello_world.py
Hello world
In [2]:
IPython默認(rèn)采用序號(hào)的格式In [2]:
,與標(biāo)準(zhǔn)的>>>
提示符不同彻磁。
2.2 IPython基礎(chǔ)
在本節(jié)中碍沐,我們會(huì)教你打開運(yùn)行IPython shell和jupyter notebook狸捅,并介紹一些基本概念。
運(yùn)行IPython Shell
你可以用ipython
在命令行打開IPython Shell累提,就像打開普通的Python解釋器:
$ ipython
Python 3.6.0 | packaged by conda-forge | (default, Jan 13 2017, 23:17:12)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: a = 5
In [2]: a
Out[2]: 5
你可以通過(guò)輸入代碼并按Return(或Enter)尘喝,運(yùn)行任意Python語(yǔ)句。當(dāng)你只輸入一個(gè)變量斋陪,它會(huì)顯示代表的對(duì)象:
In [5]: import numpy as np
In [6]: data = {i : np.random.randn() for i in range(7)}
In [7]: data
Out[7]:
{0: -0.20470765948471295,
1: 0.47894333805754824,
2: -0.5194387150567381,
3: -0.55573030434749,
4: 1.9657805725027142,
5: 1.3934058329729904,
6: 0.09290787674371767}
前兩行是Python代碼語(yǔ)句朽褪;第二條語(yǔ)句創(chuàng)建一個(gè)名為data
的變量,它引用一個(gè)新創(chuàng)建的Python字典无虚。最后一行打印data
的值缔赠。
許多Python對(duì)象被格式化為更易讀的形式,或稱作pretty-printed
友题,它與普通的print
不同嗤堰。如果在標(biāo)準(zhǔn)Python解釋器中打印上述data
變量,則可讀性要降低:
>>> from numpy.random import randn
>>> data = {i : randn() for i in range(7)}
>>> print(data)
{0: -1.5948255432744511, 1: 0.10569006472787983, 2: 1.972367135977295,
3: 0.15455217573074576, 4: -0.24058577449429575, 5: -1.2904897053651216,
6: 0.3308507317325902}
IPython還支持執(zhí)行任意代碼塊(通過(guò)一個(gè)華麗的復(fù)制-粘貼方法)和整段Python腳本的功能度宦。你也可以使用Jupyter notebook運(yùn)行大代碼塊踢匣,接下來(lái)就會(huì)看到。
運(yùn)行Jupyter Notebook
Jupyter項(xiàng)目的重要組件之久就是notebook戈抄,它是一個(gè)代碼离唬、文本(有標(biāo)記或無(wú)標(biāo)記)、數(shù)據(jù)可視化或其它輸出的交互式文檔呛凶。Jupyter Notebook需要與內(nèi)核互動(dòng)男娄,內(nèi)核是Jupyter與其它編程語(yǔ)言的交互編程協(xié)議。Python的Jupyter內(nèi)核是使用IPython漾稀。要啟動(dòng)Jupyter模闲,在命令行中輸入jupyter notebook
:
$ jupyter notebook
[I 15:20:52.739 NotebookApp] Serving notebooks from local directory:
/home/wesm/code/pydata-book
[I 15:20:52.739 NotebookApp] 0 active kernels
[I 15:20:52.739 NotebookApp] The Jupyter Notebook is running at:
http://localhost:8888/
[I 15:20:52.740 NotebookApp] Use Control-C to stop this server and shut down
all kernels (twice to skip confirmation).
Created new window in existing browser session.
在多數(shù)平臺(tái)上,Jupyter會(huì)自動(dòng)打開默認(rèn)的瀏覽器(除非指定了--no-browser
)崭捍∈郏或者,可以在啟動(dòng)notebook之后殷蛇,手動(dòng)打開網(wǎng)頁(yè)http://localhost:8888/
实夹。圖2-1展示了Google Chrome中的notebook。
筆記:許多人使用Jupyter作為本地的計(jì)算環(huán)境粒梦,但它也可以部署到服務(wù)器上遠(yuǎn)程訪問(wèn)亮航。這里不做介紹,如果需要的話匀们,鼓勵(lì)讀者自行到網(wǎng)上學(xué)習(xí)缴淋。
要新建一個(gè)notebook,點(diǎn)擊按鈕New,選擇“Python3”或“conda[默認(rèn)項(xiàng)]”重抖。如果是第一次露氮,點(diǎn)擊空格,輸入一行Python代碼钟沛。然后按Shift-Enter執(zhí)行畔规。
當(dāng)保存
notebook時(shí)(File目錄下的Save and Checkpoint),會(huì)創(chuàng)建一個(gè)后綴名為.ipynb
的文件恨统。這是一個(gè)自包含文件格式叁扫,包含當(dāng)前筆記本中的所有內(nèi)容(包括所有已評(píng)估的代碼輸出)⌒舐瘢可以被其它Jupyter用戶加載和編輯陌兑。要加載存在的notebook,把它放到啟動(dòng)notebook進(jìn)程的相同目錄內(nèi)由捎。你可以用本書的示例代碼練習(xí),見圖2-3饿凛。
雖然Jupyter notebook和IPython shell使用起來(lái)不同狞玛,本章中幾乎所有的命令和工具都可以通用。
Tab補(bǔ)全
從外觀上涧窒,IPython shell和標(biāo)準(zhǔn)的Python解釋器只是看起來(lái)不同心肪。IPython shell的進(jìn)步之一是其它IDE和交互計(jì)算分析環(huán)境都有的tab補(bǔ)全功能。在shell中輸入表達(dá)式纠吴,按下Tab硬鞍,會(huì)搜索已輸入變量(對(duì)象、函數(shù)等等)的命名空間:
In [1]: an_apple = 27
In [2]: an_example = 42
In [3]: an<Tab>
an_apple and an_example any
在這個(gè)例子中戴已,IPython呈現(xiàn)除了之前兩個(gè)定義的變量和Python的關(guān)鍵字和內(nèi)建的函數(shù)any
固该。當(dāng)然,你也可以補(bǔ)全任何對(duì)象的方法和屬性:
In [3]: b = [1, 2, 3]
In [4]: b.<Tab>
b.append b.count b.insert b.reverse
b.clear b.extend b.pop b.sort
b.copy b.index b.remove
同樣也適用于模塊:
In [1]: import datetime
In [2]: datetime.<Tab>
datetime.date datetime.MAXYEAR datetime.timedelta
datetime.datetime datetime.MINYEAR datetime.timezone
datetime.datetime_CAPI datetime.time datetime.tzinfo
在Jupyter notebook和新版的IPython(5.0及以上)糖儡,自動(dòng)補(bǔ)全功能是下拉框的形式伐坏。
筆記:注意,默認(rèn)情況下握联,IPython會(huì)隱藏下劃線開頭的方法和屬性桦沉,比如魔術(shù)方法和內(nèi)部的“私有”方法和屬性,以避免混亂的顯示(和讓新手迷惑=鹈觥)這些也可以tab補(bǔ)全纯露,但是你必須首先鍵入一個(gè)下劃線才能看到它們。如果你喜歡總是在tab補(bǔ)全中看到這樣的方法代芜,你可以IPython配置中進(jìn)行設(shè)置埠褪。可以在IPython文檔中查找方法。
除了補(bǔ)全命名组橄、對(duì)象和模塊屬性荞膘,Tab還可以補(bǔ)全其它的。當(dāng)輸入看似文件路徑時(shí)(即使是Python字符串)玉工,按下Tab也可以補(bǔ)全電腦上對(duì)應(yīng)的文件信息:
In [7]: datasets/movielens/<Tab>
datasets/movielens/movies.dat datasets/movielens/README
datasets/movielens/ratings.dat datasets/movielens/users.dat
In [7]: path = 'datasets/movielens/<Tab>
datasets/movielens/movies.dat datasets/movielens/README
datasets/movielens/ratings.dat datasets/movielens/users.dat
結(jié)合%run
羽资,tab補(bǔ)全可以節(jié)省許多鍵盤操作。
另外遵班,tab補(bǔ)全可以補(bǔ)全函數(shù)的關(guān)鍵詞參數(shù)(包括等于號(hào)=)屠升。見圖2-4。
我們來(lái)仔細(xì)看看函數(shù)狭郑。
自省
在變量前后使用問(wèn)號(hào)腹暖?,可以顯示對(duì)象的信息:
In [8]: b = [1, 2, 3]
In [9]: b?
Type: list
String Form:[1, 2, 3]
Length: 3
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
In [10]: print?
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type: builtin_function_or_method
這可以作為對(duì)象的自省翰萨。如果對(duì)象是一個(gè)函數(shù)或?qū)嵗椒ㄔ啻穑x過(guò)的文檔字符串,也會(huì)顯示出信息亩鬼。假設(shè)我們寫了一個(gè)如下的函數(shù):
def add_numbers(a, b):
"""
Add two numbers together
Returns
-------
the_sum : type of arguments
"""
return a + b
然后使用?符號(hào)殖告,就可以顯示如下的文檔字符串:
In [11]: add_numbers?
Signature: add_numbers(a, b)
Docstring:
Add two numbers together
Returns
-------
the_sum : type of arguments
File: <ipython-input-9-6a548a216e27>
Type: function
使用??會(huì)顯示函數(shù)的源碼:
In [12]: add_numbers??
Signature: add_numbers(a, b)
Source:
def add_numbers(a, b):
"""
Add two numbers together
Returns
-------
the_sum : type of arguments
"""
return a + b
File: <ipython-input-9-6a548a216e27>
Type: function
?還有一個(gè)用途,就是像Unix或Windows命令行一樣搜索IPython的命名空間雳锋。字符與通配符結(jié)合可以匹配所有的名字黄绩。例如,我們可以獲得所有包含load的頂級(jí)NumPy命名空間:
In [13]: np.*load*?
np.__loader__
np.load
np.loads
np.loadtxt
np.pkgload
%run命令
你可以用%run
命令運(yùn)行所有的Python程序玷过。假設(shè)有一個(gè)文件ipython_script_test.py
:
def f(x, y, z):
return (x + y) / z
a = 5
b = 6
c = 7.5
result = f(a, b, c)
可以如下運(yùn)行:
In [14]: %run ipython_script_test.py
這段腳本運(yùn)行在空的命名空間(沒有import和其它定義的變量)爽丹,因此結(jié)果和普通的運(yùn)行方式python script.py
相同辨液。文件中所有定義的變量(import乌妒、函數(shù)和全局變量,除非拋出異常)喇颁,都可以在IPython shell中隨后訪問(wèn):
In [15]: c
Out [15]: 7.5
In [16]: result
Out[16]: 1.4666666666666666
如果一個(gè)Python腳本需要命令行參數(shù)(在sys.argv
中查找)嚼隘,可以在文件路徑之后傳遞诽里,就像在命令行上運(yùn)行一樣。
筆記:如果想讓一個(gè)腳本訪問(wèn)IPython已經(jīng)定義過(guò)的變量飞蛹,可以使用
%run -i
谤狡。
在Jupyter notebook中,你也可以使用%load
卧檐,它將腳本導(dǎo)入到一個(gè)代碼格中:
>>> %load ipython_script_test.py
def f(x, y, z):
return (x + y) / z
a = 5
b = 6
c = 7.5
result = f(a, b, c)
中斷運(yùn)行的代碼
代碼運(yùn)行時(shí)按Ctrl-C墓懂,無(wú)論是%run或長(zhǎng)時(shí)間運(yùn)行命令,都會(huì)導(dǎo)致KeyboardInterrupt
霉囚。這會(huì)導(dǎo)致幾乎左右Python程序立即停止捕仔,除非一些特殊情況。
警告:當(dāng)Python代碼調(diào)用了一些編譯的擴(kuò)展模塊,按Ctrl-C不一定將執(zhí)行的程序立即停止榜跌。在這種情況下闪唆,你必須等待,直到控制返回Python解釋器钓葫,或者在更糟糕的情況下強(qiáng)制終止Python進(jìn)程悄蕾。
從剪貼板執(zhí)行程序
如果使用Jupyter notebook,你可以將代碼復(fù)制粘貼到任意代碼格執(zhí)行础浮。在IPython shell中也可以從剪貼板執(zhí)行帆调。假設(shè)在其它應(yīng)用中復(fù)制了如下代碼:
x = 5
y = 7
if x > 5:
x += 1
y = 8
最簡(jiǎn)單的方法是使用%paste
和%cpaste
函數(shù)。%paste
可以直接運(yùn)行剪貼板中的代碼:
In [17]: %paste
x = 5
y = 7
if x > 5:
x += 1
y = 8
## -- End pasted text --
%cpaste
功能類似豆同,但會(huì)給出一條提示:
In [18]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:x = 5
:y = 7
:if x > 5:
: x += 1
:
: y = 8
:--
使用%cpaste
番刊,你可以粘貼任意多的代碼再運(yùn)行。你可能想在運(yùn)行前影锈,先看看代碼芹务。如果粘貼了錯(cuò)誤的代碼,可以用Ctrl-C中斷鸭廷。
鍵盤快捷鍵
IPython有許多鍵盤快捷鍵進(jìn)行導(dǎo)航提示(類似Emacs文本編輯器或UNIX bash Shell)和交互shell的歷史命令锄禽。表2-1總結(jié)了常見的快捷鍵。圖2-5展示了一部分靴姿,如移動(dòng)光標(biāo)。
Jupyter notebooks有另外一套龐大的快捷鍵磁滚。因?yàn)樗目旖萱I比IPython的變化快佛吓,建議你參閱Jupyter notebook的幫助文檔。
魔術(shù)命令
IPython中特殊的命令(Python中沒有)被稱作“魔術(shù)”命令垂攘。這些命令可以使普通任務(wù)更便捷维雇,更容易控制IPython系統(tǒng)。魔術(shù)命令是在指令前添加百分號(hào)%前綴晒他。例如吱型,可以用%timeit
(這個(gè)命令后面會(huì)詳談)測(cè)量任何Python語(yǔ)句,例如矩陣乘法陨仅,的執(zhí)行時(shí)間:
In [20]: a = np.random.randn(100, 100)
In [20]: %timeit np.dot(a, a)
10000 loops, best of 3: 20.9 μs per loop
魔術(shù)命令可以被看做IPython中運(yùn)行的命令行津滞。許多魔術(shù)命令有“命令行”選項(xiàng),可以通過(guò)灼伤?查看:
In [21]: %debug?
Docstring:
::
%debug [--breakpoint FILE:LINE] [statement [statement ...]]
Activate the interactive debugger.
This magic command support two ways of activating debugger.
One is to activate debugger before executing code. This way, you
can set a break point, to step through the code from the point.
You can use this mode by giving statements to execute and optionally
a breakpoint.
The other one is to activate debugger in post-mortem mode. You can
activate this mode simply running %debug without any argument.
If an exception has just occurred, this lets you inspect its stack
frames interactively. Note that this will always work only on the last
traceback that occurred, so you must call this quickly after an
exception that you wish to inspect has fired, because if another one
occurs, it clobbers the previous one.
If you want IPython to automatically do this on every exception, see
the %pdb magic for more details.
positional arguments:
statement Code to run in debugger. You can omit this in cell
magic mode.
optional arguments:
--breakpoint <FILE:LINE>, -b <FILE:LINE>
Set break point at LINE in FILE.
魔術(shù)函數(shù)默認(rèn)可以不用百分號(hào)触徐,只要沒有變量和函數(shù)名相同。這個(gè)特點(diǎn)被稱為“自動(dòng)魔術(shù)”狐赡,可以用%automagic
打開或關(guān)閉撞鹉。
一些魔術(shù)函數(shù)與Python函數(shù)很像,它的結(jié)果可以賦值給一個(gè)變量:
In [22]: %pwd
Out[22]: '/home/wesm/code/pydata-book
In [23]: foo = %pwd
In [24]: foo
Out[24]: '/home/wesm/code/pydata-book'
IPython的文檔可以在shell中打開,我建議你用%quickref
或%magic
學(xué)習(xí)下所有特殊命令鸟雏。表2-2列出了一些可以提高生產(chǎn)率的交互計(jì)算和Python開發(fā)的IPython指令享郊。
集成Matplotlib
IPython在分析計(jì)算領(lǐng)域能夠流行的原因之一是它非常好的集成了數(shù)據(jù)可視化和其它用戶界面庫(kù),比如matplotlib孝鹊。不用擔(dān)心以前沒用過(guò)matplotlib炊琉,本書后面會(huì)詳細(xì)介紹。%matplotlib
魔術(shù)函數(shù)配置了IPython shell和Jupyter notebook中的matplotlib惶室。這點(diǎn)很重要温自,其它創(chuàng)建的圖不會(huì)出現(xiàn)(notebook)或獲取session的控制,直到結(jié)束(shell)皇钞。
在IPython shell中悼泌,運(yùn)行%matplotlib
可以進(jìn)行設(shè)置,可以創(chuàng)建多個(gè)繪圖窗口夹界,而不會(huì)干擾控制臺(tái)session:
In [26]: %matplotlib
Using matplotlib backend: Qt4Agg
在JUpyter中馆里,命令有所不同(圖2-6):
In [26]: %matplotlib inline
2.3 Python語(yǔ)法基礎(chǔ)
在本節(jié)中,我將概述基本的Python概念和語(yǔ)言機(jī)制可柿。在下一章鸠踪,我將詳細(xì)介紹Python的數(shù)據(jù)結(jié)構(gòu)、函數(shù)和其它內(nèi)建工具复斥。
語(yǔ)言的語(yǔ)義
Python的語(yǔ)言設(shè)計(jì)強(qiáng)調(diào)的是可讀性营密、簡(jiǎn)潔和清晰。有些人稱Python為“可執(zhí)行的偽代碼”目锭。
使用縮進(jìn)评汰,而不是括號(hào)
Python使用空白字符(tab和空格)來(lái)組織代碼,而不是像其它語(yǔ)言痢虹,比如R被去、C++、JAVA和Perl那樣使用括號(hào)奖唯〔依拢看一個(gè)排序算法的for
循環(huán):
for x in array:
if x < pivot:
less.append(x)
else:
greater.append(x)
冒號(hào)標(biāo)志著縮進(jìn)代碼塊的開始,冒號(hào)之后的所有代碼的縮進(jìn)量必須相同丰捷,直到代碼塊結(jié)束坯墨。不管是否喜歡這種形式,使用空白符是Python程序員開發(fā)的一部分病往,在我看來(lái)畅蹂,這可以讓python的代碼可讀性大大優(yōu)于其它語(yǔ)言。雖然期初看起來(lái)很奇怪荣恐,經(jīng)過(guò)一段時(shí)間液斜,你就能適應(yīng)了累贤。
筆記:我強(qiáng)烈建議你使用四個(gè)空格作為默認(rèn)的縮進(jìn),可以使用tab代替四個(gè)空格少漆。許多文本編輯器的設(shè)置是使用制表位替代空格臼膏。某些人使用tabs或不同數(shù)目的空格數(shù),常見的是使用兩個(gè)空格示损。大多數(shù)情況下渗磅,四個(gè)空格是大多數(shù)人采用的方法,因此建議你也這樣做检访。
你應(yīng)該已經(jīng)看到始鱼,Python的語(yǔ)句不需要用分號(hào)結(jié)尾。但是脆贵,分號(hào)卻可以用來(lái)給同在一行的語(yǔ)句切分:
a = 5; b = 6; c = 7
Python不建議將多條語(yǔ)句放到一行医清,這會(huì)降低代碼的可讀性。
外物皆對(duì)象
Python語(yǔ)言的一個(gè)重要特性就是它的對(duì)象模型的一致性卖氨。每個(gè)數(shù)字会烙、字符串、數(shù)據(jù)結(jié)構(gòu)筒捺、函數(shù)柏腻、類、模塊等等系吭,都是在Python解釋器的自有“盒子”內(nèi)五嫂,它被認(rèn)為是Python對(duì)象。每個(gè)對(duì)象都有類型(例如肯尺,字符串或函數(shù))和內(nèi)部數(shù)據(jù)贫导。在實(shí)際中,這可以讓語(yǔ)言非常靈活蟆盹,因?yàn)楹瘮?shù)也可以被當(dāng)做對(duì)象使用。
注釋
任何前面帶有井號(hào)#的文本都會(huì)被Python解釋器忽略闺金。這通常被用來(lái)添加注釋逾滥。有時(shí),你會(huì)想排除一段代碼败匹,但并不刪除寨昙。簡(jiǎn)便的方法就是將其注釋掉:
results = []
for line in file_handle:
# keep the empty lines for now
# if len(line) == 0:
# continue
results.append(line.replace('foo', 'bar'))
也可以在執(zhí)行過(guò)的代碼后面添加注釋。一些人習(xí)慣在代碼之前添加注釋掀亩,前者這種方法有時(shí)也是有用的:
print("Reached this line") # Simple status report
函數(shù)和對(duì)象方法調(diào)用
你可以用圓括號(hào)調(diào)用函數(shù)舔哪,傳遞零個(gè)或幾個(gè)參數(shù),或者將返回值給一個(gè)變量:
result = f(x, y, z)
g()
幾乎Python中的每個(gè)對(duì)象都有附加的函數(shù)槽棍,稱作方法捉蚤,可以用來(lái)訪問(wèn)對(duì)象的內(nèi)容抬驴。可以用下面的語(yǔ)句調(diào)用:
obj.some_method(x, y, z)
函數(shù)可以使用位置和關(guān)鍵詞參數(shù):
result = f(a, b, c, d=5, e='foo')
后面會(huì)有更多介紹缆巧。
變量和參數(shù)傳遞
當(dāng)在Python中創(chuàng)建變量(或名字)布持,你就在等號(hào)右邊創(chuàng)建了一個(gè)對(duì)這個(gè)變量的引用∩滦考慮一個(gè)整數(shù)列表:
In [8]: a = [1, 2, 3]
假設(shè)將a賦值給一個(gè)新變量b:
In [9]: b = a
在有些方法中题暖,這個(gè)賦值會(huì)將數(shù)據(jù)[1, 2, 3]也復(fù)制。在Python中捉超,a和b實(shí)際上是同一個(gè)對(duì)象胧卤,即原有列表[1, 2, 3](見圖2-7)。你可以在a中添加一個(gè)元素拼岳,然后檢查b:
In [10]: a.append(4)
In [11]: b
Out[11]: [1, 2, 3, 4]
理解Python的引用的含義枝誊,數(shù)據(jù)是何時(shí)、如何裂问、為何復(fù)制的侧啼,是非常重要的。尤其是當(dāng)你用Python處理大的數(shù)據(jù)集時(shí)堪簿。
筆記:賦值也被稱作綁定痊乾,我們是把一個(gè)名字綁定給一個(gè)對(duì)象。變量名有時(shí)可能被稱為綁定變量椭更。
當(dāng)你將對(duì)象作為參數(shù)傳遞給函數(shù)時(shí)哪审,新的局域變量創(chuàng)建了對(duì)原始對(duì)象的引用,而不是復(fù)制虑瀑。如果在函數(shù)里綁定一個(gè)新對(duì)象到一個(gè)變量湿滓,這個(gè)變動(dòng)不會(huì)反映到上一層。因此可以改變可變參數(shù)的內(nèi)容舌狗。假設(shè)有以下函數(shù):
def append_element(some_list, element):
some_list.append(element)
然后有:
In [27]: data = [1, 2, 3]
In [28]: append_element(data, 4)
In [29]: data
Out[29]: [1, 2, 3, 4]
動(dòng)態(tài)引用叽奥,強(qiáng)類型
與許多編譯語(yǔ)言(如JAVA和C++)對(duì)比,Python中的對(duì)象引用不包含附屬的類型痛侍。下面的代碼是沒有問(wèn)題的:
In [12]: a = 5
In [13]: type(a)
Out[13]: int
In [14]: a = 'foo'
In [15]: type(a)
Out[15]: str
變量是在特殊命名空間中的對(duì)象的名字朝氓,類型信息保存在對(duì)象自身中。一些人可能會(huì)說(shuō)Python不是“類型化語(yǔ)言”主届。這是不正確的赵哲,看下面的例子:
In [16]: '5' + 5
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-f9dbf5f0b234> in <module>()
----> 1 '5' + 5
TypeError: must be str, not int
在某些語(yǔ)言中,例如Visual Basic君丁,字符串‘5’可能被默許轉(zhuǎn)換(或投射)為整數(shù)枫夺,因此會(huì)產(chǎn)生10。但在其它語(yǔ)言中绘闷,例如JavaScript橡庞,整數(shù)5個(gè)能被投射成字符串较坛,結(jié)果是聯(lián)結(jié)字符串‘55’。在這個(gè)方面毙死,Python被認(rèn)為是強(qiáng)類型化語(yǔ)言燎潮,意味著每個(gè)對(duì)象都有明確的類型(或類),默許轉(zhuǎn)換只會(huì)發(fā)生在特定的情況下扼倘,例如:
In [17]: a = 4.5
In [18]: b = 2
# String formatting, to be visited later
In [19]: print('a is {0}, b is {1}'.format(type(a), type(b)))
a is <class 'float'>, b is <class 'int'>
In [20]: a / b
Out[20]: 2.25
知道對(duì)象的類型很重要确封,最好能讓函數(shù)可以處理多種類型的輸入。你可以用isinstance
函數(shù)檢查對(duì)象是某個(gè)類型的實(shí)例:
In [21]: a = 5
In [22]: isinstance(a, int)
Out[22]: True
isinstance
可以用類型元組再菊,檢查對(duì)象的類型是否在元組中:
In [23]: a = 5; b = 4.5
In [24]: isinstance(a, (int, float))
Out[24]: True
In [25]: isinstance(b, (int, float))
Out[25]: True
屬性和方法
Python的對(duì)象通常都有屬性(其它存儲(chǔ)在對(duì)象內(nèi)部的Python對(duì)象)和方法(對(duì)象的附屬函數(shù)可以訪問(wèn)對(duì)象的內(nèi)部數(shù)據(jù))爪喘。可以用obj.attribute_name
訪問(wèn)屬性和方法:
In [1]: a = 'foo'
In [2]: a.<Press Tab>
a.capitalize a.format a.isupper a.rindex a.strip
a.center a.index a.join a.rjust a.swapcase
a.count a.isalnum a.ljust a.rpartition a.title
a.decode a.isalpha a.lower a.rsplit a.translate
a.encode a.isdigit a.lstrip a.rstrip a.upper
a.endswith a.islower a.partition a.split a.zfill
a.expandtabs a.isspace a.replace a.splitlines
a.find a.istitle a.rfind a.startswith
也可以用getattr
函數(shù)纠拔,通過(guò)名字訪問(wèn)屬性和方法:
In [27]: getattr(a, 'split')
Out[27]: <function str.split>
在其它語(yǔ)言中秉剑,訪問(wèn)對(duì)象的名字通常稱作“反射”。本書不會(huì)大量使用getattr
函數(shù)和相關(guān)的hasattr
和setattr
函數(shù)稠诲,使用這些函數(shù)可以高效編寫原生的侦鹏、可重復(fù)使用的代碼。
鴨子類型
經(jīng)常地臀叙,你可能不關(guān)心對(duì)象的類型略水,只關(guān)心對(duì)象是否有某些方法或用途。這通常被稱為“鴨子類型”劝萤,來(lái)自“走起來(lái)像鴨子渊涝、叫起來(lái)像鴨子,那么它就是鴨子”的說(shuō)法床嫌。例如跨释,你可以通過(guò)驗(yàn)證一個(gè)對(duì)象是否遵循迭代協(xié)議,判斷它是可迭代的厌处。對(duì)于許多對(duì)象鳖谈,這意味著它有一個(gè)__iter__
魔術(shù)方法,其它更好的判斷方法是使用iter
函數(shù):
def isiterable(obj):
try:
iter(obj)
return True
except TypeError: # not iterable
return False
這個(gè)函數(shù)會(huì)返回字符串以及大多數(shù)Python集合類型為True
:
In [29]: isiterable('a string')
Out[29]: True
In [30]: isiterable([1, 2, 3])
Out[30]: True
In [31]: isiterable(5)
Out[31]: False
我總是用這個(gè)功能編寫可以接受多種輸入類型的函數(shù)阔涉。常見的例子是編寫一個(gè)函數(shù)可以接受任意類型的序列(list缆娃、tuple、ndarray)或是迭代器。你可先檢驗(yàn)對(duì)象是否是列表(或是NUmPy數(shù)組),如果不是的話短蜕,將其轉(zhuǎn)變成列表:
if not isinstance(x, list) and isiterable(x):
x = list(x)
引入
在Python中昏翰,模塊就是一個(gè)有.py
擴(kuò)展名、包含Python代碼的文件它碎。假設(shè)有以下模塊:
# some_module.py
PI = 3.14159
def f(x):
return x + 2
def g(a, b):
return a + b
如果想從同目錄下的另一個(gè)文件訪問(wèn)some_module.py
中定義的變量和函數(shù)函荣,可以:
import some_module
result = some_module.f(5)
pi = some_module.PI
或者:
from some_module import f, g, PI
result = g(5, PI)
使用as
關(guān)鍵詞显押,你可以給引入起不同的變量名:
import some_module as sm
from some_module import PI as pi, g as gf
r1 = sm.f(pi)
r2 = gf(6, pi)
二元運(yùn)算符和比較運(yùn)算符
大多數(shù)二元數(shù)學(xué)運(yùn)算和比較都不難想到:
In [32]: 5 - 7
Out[32]: -2
In [33]: 12 + 21.5
Out[33]: 33.5
In [34]: 5 <= 2
Out[34]: False
表2-3列出了所有的二元運(yùn)算符。
要判斷兩個(gè)引用是否指向同一個(gè)對(duì)象傻挂,可以使用is
方法乘碑。is not
可以判斷兩個(gè)對(duì)象是不同的:
In [35]: a = [1, 2, 3]
In [36]: b = a
In [37]: c = list(a)
In [38]: a is b
Out[38]: True
In [39]: a is not c
Out[39]: True
因?yàn)?code>list總是創(chuàng)建一個(gè)新的Python列表(即復(fù)制),我們可以斷定c是不同于a的金拒。使用is
比較與==
運(yùn)算符不同兽肤,如下:
In [40]: a == c
Out[40]: True
is
和is not
常用來(lái)判斷一個(gè)變量是否為None
,因?yàn)橹挥幸粋€(gè)None
的實(shí)例:
In [41]: a = None
In [42]: a is None
Out[42]: True
可變與不可變對(duì)象
Python中的大多數(shù)對(duì)象绪抛,比如列表资铡、字典、NumPy數(shù)組幢码,和用戶定義的類型(類)笤休,都是可變的。意味著這些對(duì)象或包含的值可以被修改:
In [43]: a_list = ['foo', 2, [4, 5]]
In [44]: a_list[2] = (3, 4)
In [45]: a_list
Out[45]: ['foo', 2, (3, 4)]
其它的症副,例如字符串和元組店雅,是不可變的:
In [46]: a_tuple = (3, 5, (4, 5))
In [47]: a_tuple[1] = 'four'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-47-b7966a9ae0f1> in <module>()
----> 1 a_tuple[1] = 'four'
TypeError: 'tuple' object does not support item assignment
記住,可以修改一個(gè)對(duì)象并不意味就要修改它贞铣。這被稱為副作用闹啦。例如,當(dāng)寫一個(gè)函數(shù)咕娄,任何副作用都要在文檔或注釋中寫明亥揖。如果可能的話,我推薦避免副作用圣勒,采用不可變的方式费变,即使要用到可變對(duì)象。
標(biāo)量類型
Python的標(biāo)準(zhǔn)庫(kù)中有一些內(nèi)建的類型圣贸,用以處理數(shù)值數(shù)據(jù)挚歧、字符串、布爾值吁峻,和日期時(shí)間滑负。這些單值類型被稱為標(biāo)量類型,本書中稱其為標(biāo)量用含。表2-4列出了主要的標(biāo)量矮慕。日期和時(shí)間處理會(huì)另外討論,因?yàn)樗鼈兪菢?biāo)準(zhǔn)庫(kù)的datetime
模塊提供的啄骇。
數(shù)值類型
Python的主要數(shù)值類型是int
和float
痴鳄。int
可以存儲(chǔ)任意大的數(shù):
In [48]: ival = 17239871
In [49]: ival ** 6
Out[49]: 26254519291092456596965462913230729701102721
浮點(diǎn)數(shù)使用Python的float
類型。每個(gè)數(shù)都是雙精度(64位)的值缸夹。也可以用科學(xué)計(jì)數(shù)法表示:
In [50]: fval = 7.243
In [51]: fval2 = 6.78e-5
不能得到整數(shù)的除法會(huì)得到浮點(diǎn)數(shù):
In [52]: 3 / 2
Out[52]: 1.5
要獲得C-風(fēng)格的整除(去掉小數(shù)部分)痪寻,可以使用底除運(yùn)算符//:
In [53]: 3 // 2
Out[53]: 1
字符串
許多人是因?yàn)镻ython強(qiáng)大而靈活的字符串處理而使用Python的螺句。你可以用單引號(hào)或雙引號(hào)來(lái)寫字符串:
a = 'one way of writing a string'
b = "another way"
對(duì)于有換行符的字符串,可以使用三引號(hào)橡类,'''或"""都行:
c = """
This is a longer string that
spans multiple lines
"""
字符串c
實(shí)際包含四行文本蛇尚,"""后面和lines后面的換行符」嘶可以用count
方法計(jì)算c
中的新的行:
In [55]: c.count('\n')
Out[55]: 3
Python的字符串是不可變的取劫,不能修改字符串:
In [56]: a = 'this is a string'
In [57]: a[10] = 'f'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-57-5ca625d1e504> in <module>()
----> 1 a[10] = 'f'
TypeError: 'str' object does not support item assignment
In [58]: b = a.replace('string', 'longer string')
In [59]: b
Out[59]: 'this is a longer string'
經(jīng)過(guò)以上的操作,變量a
并沒有被修改:
In [60]: a
Out[60]: 'this is a string'
許多Python對(duì)象使用str
函數(shù)可以被轉(zhuǎn)化為字符串:
In [61]: a = 5.6
In [62]: s = str(a)
In [63]: print(s)
5.6
字符串是一個(gè)序列的Unicode字符亲雪,因此可以像其它序列勇凭,比如列表和元組(下一章會(huì)詳細(xì)介紹兩者)一樣處理:
In [64]: s = 'python'
In [65]: list(s)
Out[65]: ['p', 'y', 't', 'h', 'o', 'n']
In [66]: s[:3]
Out[66]: 'pyt'
語(yǔ)法s[:3]
被稱作切片,適用于許多Python序列义辕。后面會(huì)更詳細(xì)的介紹虾标,本書中用到很多切片。
反斜杠是轉(zhuǎn)義字符灌砖,意思是它備用來(lái)表示特殊字符璧函,比如換行符\n或Unicode字符。要寫一個(gè)包含反斜杠的字符串基显,需要進(jìn)行轉(zhuǎn)義:
In [67]: s = '12\\34'
In [68]: print(s)
12\34
如果字符串中包含許多反斜杠蘸吓,但沒有特殊字符,這樣做就很麻煩撩幽。幸好库继,可以在字符串前面加一個(gè)r,表明字符就是它自身:
In [69]: s = r'this\has\no\special\characters'
In [70]: s
Out[70]: 'this\\has\\no\\special\\characters'
r表示raw窜醉。
將兩個(gè)字符串合并宪萄,會(huì)產(chǎn)生一個(gè)新的字符串:
In [71]: a = 'this is the first half '
In [72]: b = 'and this is the second half'
In [73]: a + b
Out[73]: 'this is the first half and this is the second half'
字符串的模板化或格式化,是另一個(gè)重要的主題榨惰。Python 3拓展了此類的方法拜英,這里只介紹一些。字符串對(duì)象有format
方法琅催,可以替換格式化的參數(shù)為字符串居凶,產(chǎn)生一個(gè)新的字符串:
In [74]: template = '{0:.2f} {1:s} are worth US${2:d}'
在這個(gè)字符串中,
{0:.2f}
表示格式化第一個(gè)參數(shù)為帶有兩位小數(shù)的浮點(diǎn)數(shù)藤抡。{1:s}
表示格式化第二個(gè)參數(shù)為字符串侠碧。{2:d}
表示格式化第三個(gè)參數(shù)為一個(gè)整數(shù)。
要替換參數(shù)為這些格式化的參數(shù)缠黍,我們傳遞format
方法一個(gè)序列:
In [75]: template.format(4.5560, 'Argentine Pesos', 1)
Out[75]: '4.56 Argentine Pesos are worth US$1'
字符串格式化是一個(gè)很深的主題弄兜,有多種方法和大量的選項(xiàng),可以控制字符串中的值是如何格式化的。推薦參閱Python官方文檔挨队。
這里概括介紹字符串處理,第8章的數(shù)據(jù)分析會(huì)詳細(xì)介紹蒿往。
字節(jié)和Unicode
在Python 3及以上版本中盛垦,Unicode是一級(jí)的字符串類型,這樣可以更一致的處理ASCII和Non-ASCII文本瓤漏。在老的Python版本中腾夯,字符串都是字節(jié),不使用Unicode編碼蔬充。假如知道字符編碼蝶俱,可以將其轉(zhuǎn)化為Unicode〖⒙看一個(gè)例子:
In [76]: val = "espa?ol"
In [77]: val
Out[77]: 'espa?ol'
可以用encode
將這個(gè)Unicode字符串編碼為UTF-8:
In [78]: val_utf8 = val.encode('utf-8')
In [79]: val_utf8
Out[79]: b'espa\xc3\xb1ol'
In [80]: type(val_utf8)
Out[80]: bytes
如果你知道一個(gè)字節(jié)對(duì)象的Unicode編碼榨呆,用decode
方法可以解碼:
In [81]: val_utf8.decode('utf-8')
Out[81]: 'espa?ol'
雖然UTF-8編碼已經(jīng)變成主流,庸队,但因?yàn)闅v史的原因积蜻,你仍然可能碰到其它編碼的數(shù)據(jù):
In [82]: val.encode('latin1')
Out[82]: b'espa\xf1ol'
In [83]: val.encode('utf-16')
Out[83]: b'\xff\xfee\x00s\x00p\x00a\x00\xf1\x00o\x00l\x00'
In [84]: val.encode('utf-16le')
Out[84]: b'e\x00s\x00p\x00a\x00\xf1\x00o\x00l\x00'
工作中碰到的文件很多都是字節(jié)對(duì)象,盲目地將所有數(shù)據(jù)編碼為Unicode是不可取的彻消。
雖然用的不多竿拆,你可以在字節(jié)文本的前面加上一個(gè)b:
In [85]: bytes_val = b'this is bytes'
In [86]: bytes_val
Out[86]: b'this is bytes'
In [87]: decoded = bytes_val.decode('utf8')
In [88]: decoded # this is str (Unicode) now
Out[88]: 'this is bytes'
布爾值
Python中的布爾值有兩個(gè),True和False宾尚。比較和其它條件表達(dá)式可以用True和False判斷丙笋。布爾值可以與and和or結(jié)合使用:
In [89]: True and True
Out[89]: True
In [90]: False or True
Out[90]: True
類型轉(zhuǎn)換
str、bool煌贴、int和float也是函數(shù)御板,可以用來(lái)轉(zhuǎn)換類型:
In [91]: s = '3.14159'
In [92]: fval = float(s)
In [93]: type(fval)
Out[93]: float
In [94]: int(fval)
Out[94]: 3
In [95]: bool(fval)
Out[95]: True
In [96]: bool(0)
Out[96]: False
None
None是Python的空值類型。如果一個(gè)函數(shù)沒有明確的返回值崔步,就會(huì)默認(rèn)返回None:
In [97]: a = None
In [98]: a is None
Out[98]: True
In [99]: b = 5
In [100]: b is not None
Out[100]: True
None也常常作為函數(shù)的默認(rèn)參數(shù):
def add_and_maybe_multiply(a, b, c=None):
result = a + b
if c is not None:
result = result * c
return result
另外稳吮,None不僅是一個(gè)保留字,還是唯一的NoneType的實(shí)例:
In [101]: type(None)
Out[101]: NoneType
日期和時(shí)間
Python內(nèi)建的datetime
模塊提供了datetime
井濒、date
和time
類型灶似。datetime
類型結(jié)合了date
和time
,是最常使用的:
In [102]: from datetime import datetime, date, time
In [103]: dt = datetime(2011, 10, 29, 20, 30, 21)
In [104]: dt.day
Out[104]: 29
In [105]: dt.minute
Out[105]: 30
根據(jù)datetime
實(shí)例瑞你,你可以用date
和time
提取出各自的對(duì)象:
In [106]: dt.date()
Out[106]: datetime.date(2011, 10, 29)
In [107]: dt.time()
Out[107]: datetime.time(20, 30, 21)
strftime
方法可以將datetime格式化為字符串:
In [108]: dt.strftime('%m/%d/%Y %H:%M')
Out[108]: '10/29/2011 20:30'
strptime
可以將字符串轉(zhuǎn)換成datetime
對(duì)象:
In [109]: datetime.strptime('20091031', '%Y%m%d')
Out[109]: datetime.datetime(2009, 10, 31, 0, 0)
表2-5列出了所有的格式化命令酪惭。
當(dāng)你聚類或?qū)r(shí)間序列進(jìn)行分組,替換datetimes的time字段有時(shí)會(huì)很有用者甲。例如春感,用0替換分和秒:
In [110]: dt.replace(minute=0, second=0)
Out[110]: datetime.datetime(2011, 10, 29, 20, 0)
因?yàn)?code>datetime.datetime是不可變類型,上面的方法會(huì)產(chǎn)生新的對(duì)象。
兩個(gè)datetime對(duì)象的差會(huì)產(chǎn)生一個(gè)datetime.timedelta
類型:
In [111]: dt2 = datetime(2011, 11, 15, 22, 30)
In [112]: delta = dt2 - dt
In [113]: delta
Out[113]: datetime.timedelta(17, 7179)
In [114]: type(delta)
Out[114]: datetime.timedelta
結(jié)果timedelta(17, 7179)
指明了timedelta
將17天鲫懒、7179秒的編碼方式嫩实。
將timedelta
添加到datetime
,會(huì)產(chǎn)生一個(gè)新的偏移datetime
:
In [115]: dt
Out[115]: datetime.datetime(2011, 10, 29, 20, 30, 21)
In [116]: dt + delta
Out[116]: datetime.datetime(2011, 11, 15, 22, 30)
控制流
Python有若干內(nèi)建的關(guān)鍵字進(jìn)行條件邏輯窥岩、循環(huán)和其它控制流操作甲献。
if、elif和else
if是最廣為人知的控制流語(yǔ)句颂翼。它檢查一個(gè)條件晃洒,如果為True,就執(zhí)行后面的語(yǔ)句:
if x < 0:
print('It's negative')
if
后面可以跟一個(gè)或多個(gè)elif
朦乏,所有條件都是False時(shí)球及,還可以添加一個(gè)else
:
if x < 0:
print('It's negative')
elif x == 0:
print('Equal to zero')
elif 0 < x < 5:
print('Positive but smaller than 5')
else:
print('Positive and larger than or equal to 5')
如果某個(gè)條件為True,后面的elif
就不會(huì)被執(zhí)行呻疹。當(dāng)使用and和or時(shí)吃引,復(fù)合條件語(yǔ)句是從左到右執(zhí)行:
In [117]: a = 5; b = 7
In [118]: c = 8; d = 4
In [119]: if a < b or c > d:
.....: print('Made it')
Made it
在這個(gè)例子中,c > d
不會(huì)被執(zhí)行刽锤,因?yàn)榈谝粋€(gè)比較是True:
也可以把比較式串在一起:
In [120]: 4 > 3 > 2 > 1
Out[120]: True
for循環(huán)
for循環(huán)是在一個(gè)集合(列表或元組)中進(jìn)行迭代际歼,或者就是一個(gè)迭代器。for循環(huán)的標(biāo)準(zhǔn)語(yǔ)法是:
for value in collection:
# do something with value
你可以用continue使for循環(huán)提前姑蓝,跳過(guò)剩下的部分鹅心。看下面這個(gè)例子纺荧,將一個(gè)列表中的整數(shù)相加旭愧,跳過(guò)None:
sequence = [1, 2, None, 4, None, 5]
total = 0
for value in sequence:
if value is None:
continue
total += value
可以用break
跳出for循環(huán)。下面的代碼將各元素相加宙暇,直到遇到5:
sequence = [1, 2, 0, 4, 6, 5, 2, 1]
total_until_5 = 0
for value in sequence:
if value == 5:
break
total_until_5 += value
break只中斷for循環(huán)的最內(nèi)層输枯,其余的for循環(huán)仍會(huì)運(yùn)行:
In [121]: for i in range(4):
.....: for j in range(4):
.....: if j > i:
.....: break
.....: print((i, j))
.....:
(0, 0)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
(2, 2)
(3, 0)
(3, 1)
(3, 2)
(3, 3)
如果集合或迭代器中的元素序列(元組或列表),可以用for循環(huán)將其方便地拆分成變量:
for a, b, c in iterator:
# do something
While循環(huán)
while循環(huán)指定了條件和代碼占贫,當(dāng)條件為False或用break退出循環(huán)桃熄,代碼才會(huì)退出:
x = 256
total = 0
while x > 0:
if total > 500:
break
total += x
x = x // 2
pass
pass是Python中的非操作語(yǔ)句。代碼塊不需要任何動(dòng)作時(shí)可以使用(作為未執(zhí)行代碼的占位符)型奥;因?yàn)镻ython需要使用空白字符劃定代碼塊瞳收,所以需要pass:
if x < 0:
print('negative!')
elif x == 0:
# TODO: put something smart here
pass
else:
print('positive!')
range
range函數(shù)返回一個(gè)迭代器,它產(chǎn)生一個(gè)均勻分布的整數(shù)序列:
In [122]: range(10)
Out[122]: range(0, 10)
In [123]: list(range(10))
Out[123]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range的三個(gè)參數(shù)是(起點(diǎn)厢汹,終點(diǎn)螟深,步進(jìn)):
In [124]: list(range(0, 20, 2))
Out[124]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
In [125]: list(range(5, 0, -1))
Out[125]: [5, 4, 3, 2, 1]
可以看到,range產(chǎn)生的整數(shù)不包括終點(diǎn)烫葬。range的常見用法是用序號(hào)迭代序列:
seq = [1, 2, 3, 4]
for i in range(len(seq)):
val = seq[i]
可以使用list來(lái)存儲(chǔ)range在其他數(shù)據(jù)結(jié)構(gòu)中生成的所有整數(shù)界弧,默認(rèn)的迭代器形式通常是你想要的凡蜻。下面的代碼對(duì)0到99999中3或5的倍數(shù)求和:
sum = 0
for i in range(100000):
# % is the modulo operator
if i % 3 == 0 or i % 5 == 0:
sum += i
雖然range可以產(chǎn)生任意大的數(shù),但任意時(shí)刻耗用的內(nèi)存卻很小垢箕。
三元表達(dá)式
Python中的三元表達(dá)式可以將if-else語(yǔ)句放到一行里划栓。語(yǔ)法如下:
value = true-expr if condition else false-expr
true-expr
或false-expr
可以是任何Python代碼。它和下面的代碼效果相同:
if condition:
value = true-expr
else:
value = false-expr
下面是一個(gè)更具體的例子:
In [126]: x = 5
In [127]: 'Non-negative' if x >= 0 else 'Negative'
Out[127]: 'Non-negative'
和if-else一樣条获,只有一個(gè)表達(dá)式會(huì)被執(zhí)行茅姜。因此,三元表達(dá)式中的if和else可以包含大量的計(jì)算月匣,但只有True的分支會(huì)被執(zhí)行。
雖然使用三元表達(dá)式可以壓縮代碼奋姿,但會(huì)降低代碼可讀性锄开。