【翻譯】《利用Python進行數據分析·第2版》第5章(上)pandas入門
作者:SeanCheney Python愛好者社區專欄作者
簡書專欄:https://www.jianshu.com/u/130f76596b02公眾號:Python愛好者社區
前文傳送門:
【翻譯】《利用Python進行數據分析·第2版》第1章 準備工作
【翻譯】《利用Python進行數據分析·第2版》第2章(上)Python語法基礎,IPython和Jupyter
【翻譯】《利用Python進行數據分析·第2版》第2章(中)Python語法基礎,IPython和Jupyter
【翻譯】《利用Python進行數據分析·第2版》第2章(下)Python語法基礎,IPython和Jupyter
【翻譯】《利用Python進行數據分析·第2版》第3章(上)Python的數據結構、函數和文件
【翻譯】《利用Python進行數據分析·第2版》第3章(中)Python的數據結構、函數和文件
【翻譯】《利用Python進行數據分析·第2版》第3章(下)Python的數據結構、函數和文件
【翻譯】《利用Python進行數據分析·第2版》第4章(上)NumPy基礎:數組和矢量計算
【翻譯】《利用Python進行數據分析·第2版》第4章(中)NumPy基礎:數組和矢量計算
【翻譯】《利用Python進行數據分析·第2版》第4章(下)NumPy基礎:數組和矢量計算
pandas是本書後續內容的首選庫。它含有使數據清洗和分析工作變得更快更簡單的數據結構和操作工具。pandas經常和其它工具一同使用,如數值計算工具NumPy和SciPy,分析庫statsmodels和scikit-learn,和數據可視化庫matplotlib。pandas是基於NumPy數組構建的,特別是基於數組的函數和不使用for循環的數據處理。
雖然pandas採用了大量的NumPy編碼風格,但二者最大的不同是pandas是專門為處理表格和混雜數據設計的。而NumPy更適合處理統一的數值數組數據。
自從2010年pandas開源以來,pandas逐漸成長為一個非常大的庫,應用於許多真實案例。開發者社區已經有了800個獨立的貢獻者,他們在解決日常數據問題的同時為這個項目提供貢獻。
在本書後續部分中,我將使用下面這樣的pandas引入約定:
In [1]: import pandas as pd
因此,只要你在代碼中看到pd.,就得想到這是pandas。因為Series和DataFrame用的次數非常多,所以將其引入本地命名空間中會更方便:
In [2]: from pandas import Series, DataFrame
5.1 pandas的數據結構介紹
要使用pandas,你首先就得熟悉它的兩個主要數據結構:Series和DataFrame。雖然它們並不能解決所有問題,但它們為大多數應用提供了一種可靠的、易於使用的基礎。
Series
Series是一種類似於一維數組的對象,它由一組數據(各種NumPy數據類型)以及一組與之相關的數據標籤(即索引)組成。僅由一組數據即可產生最簡單的Series:
In [11]: obj = pd.Series([4, 7, -5, 3])
In [12]: objOut[12]:0 4
1 72 -53 3dtype: int64Series的字元串表現形式為:索引在左邊,值在右邊。由於我們沒有為數據指定索引,於是會自動創建一個0到N-1(N為數據的長度)的整數型索引。你可以通過Series 的values和index屬性獲取其數組表示形式和索引對象:
In [13]: obj.values
Out[13]: array([ 4, 7, -5, 3])In [14]: obj.index # like range(4)Out[14]: RangeIndex(start=0, stop=4, step=1)通常,我們希望所創建的Series帶有一個可以對各個數據點進行標記的索引:
In [15]: obj2 = pd.Series([4, 7, -5, 3], index=[d, b, a, c])
In [16]: obj2Out[16]: d 4b 7a -5c 3dtype: int64In [17]: obj2.indexOut[17]: Index([d, b, a, c], dtype=object)
與普通NumPy數組相比,你可以通過索引的方式選取Series中的單個或一組值:
In [18]: obj2[a]
Out[18]: -5In [19]: obj2[d] = 6In [20]: obj2[[c, a, d]]Out[20]: c 3a -5d 6dtype: int64
[c, a, d]是索引列表,即使它包含的是字元串而不是整數。
使用NumPy函數或類似NumPy的運算(如根據布爾型數組進行過濾、標量乘法、應用數學函數等)都會保留索引值的鏈接:
In [21]: obj2[obj2 > 0]
Out[21]: d 6b 7c 3dtype: int64In [22]: obj2 * 2Out[22]:
d 12b 14a -10c 6dtype: int64In [23]: np.exp(obj2)Out[23]: d 403.428793b 1096.633158a 0.006738
c 20.085537dtype: float64還可以將Series看成是一個定長的有序字典,因為它是索引值到數據值的一個映射。它可以用在許多原本需要字典參數的函數中:
In [24]: b in obj2
Out[24]: TrueIn [25]: e in obj2Out[25]: False如果數據被存放在一個Python字典中,也可以直接通過這個字典來創建Series:
In [26]: sdata = {Ohio: 35000, Texas: 71000, Oregon: 16000, Utah: 5000}
In [27]: obj3 = pd.Series(sdata)
In [28]: obj3Out[28]: Ohio 35000Oregon 16000Texas 71000Utah 5000dtype: int64如果只傳入一個字典,則結果Series中的索引就是原字典的鍵(有序排列)。你可以傳入排好序的字典的鍵以改變順序:
In [29]: states = [California, Ohio, Oregon, Texas]
In [30]: obj4 = pd.Series(sdata, index=states)In [31]: obj4Out[31]: California NaNOhio 35000.0Oregon 16000.0Texas 71000.0dtype: float64在這個例子中,sdata中跟states索引相匹配的那3個值會被找出來並放到相應的位置上,但由於"California"所對應的sdata值找不到,所以其結果就為NaN(即「非數字」(not a number),在pandas中,它用於表示缺失或NA值)。因為『Utah』不在states中,它被從結果中除去。
我將使用缺失(missing)或NA表示缺失數據。pandas的isnull和notnull函數可用於檢測缺失數據:
In [32]: pd.isnull(obj4)
Out[32]: California TrueOhio FalseOregon FalseTexas Falsedtype: boolIn [33]: pd.notnull(obj4)Out[33]: California FalseOhio TrueOregon TrueTexas Truedtype: boolSeries也有類似的實例方法:
In [34]: obj4.isnull()
Out[34]: California TrueOhio FalseOregon FalseTexas Falsedtype: bool我將在第7章詳細講解如何處理缺失數據。
對於許多應用而言,Series最重要的一個功能是,它會根據運算的索引標籤自動對齊數據:
In [35]: obj3
Out[35]: Ohio 35000Oregon 16000Texas 71000Utah 5000dtype: int64In [36]: obj4Out[36]: California NaNOhio 35000.0Oregon 16000.0Texas 71000.0dtype: float64In [37]: obj3 + obj4Out[37]: California NaNOhio 70000.0Oregon 32000.0Texas 142000.0Utah NaNdtype: float64數據對齊功能將在後面詳細講解。如果你使用過資料庫,你可以認為是類似join的操作。
Series對象本身及其索引都有一個name屬性,該屬性跟pandas其他的關鍵功能關係非常密切:
In [38]: obj4.name = population
In [39]: obj4.index.name = stateIn [40]: obj4Out[40]: stateCalifornia NaNOhio 35000.0Oregon 16000.0Texas 71000.0Name: population, dtype: float64Series的索引可以通過賦值的方式就地修改:
In [41]: obj
Out[41]: 0 41 72 -53 3dtype: int64In [42]: obj.index = [Bob, Steve, Jeff, Ryan]In [43]: objOut[43]: Bob 4Steve 7Jeff -5Ryan 3dtype: int64DataFrame
DataFrame是一個表格型的數據結構,它含有一組有序的列,每列可以是不同的值類型(數值、字元串、布爾值等)。DataFrame既有行索引也有列索引,它可以被看做由Series組成的字典(共用同一個索引)。DataFrame中的數據是以一個或多個二維塊存放的(而不是列表、字典或別的一維數據結構)。有關DataFrame內部的技術細節遠遠超出了本書所討論的範圍。
筆記:雖然DataFrame是以二維結構保存數據的,但你仍然可以輕鬆地將其表示為更高維度的數據(層次化索引的表格型結構,這是pandas中許多高級數據處理功能的關鍵要素,我們會在第8章討論這個問題)。
建DataFrame的辦法有很多,最常用的一種是直接傳入一個由等長列表或NumPy數組組成的字典:
data = {state: [Ohio, Ohio, Ohio, Nevada, Nevada, Nevada],
year: [2000, 2001, 2002, 2001, 2002, 2003], pop: [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}frame = pd.DataFrame(data)結果DataFrame會自動加上索引(跟Series一樣),且全部列會被有序排列:
In [45]: frame
Out[45]: pop state year0 1.5 Ohio 20001 1.7 Ohio 20012 3.6 Ohio 20023 2.4 Nevada 20014 2.9 Nevada 20025 3.2 Nevada 2003如果你使用的是Jupyter notebook,pandas DataFrame對象會以對瀏覽器友好的HTML表格的方式呈現。
對於特別大的DataFrame,head方法會選取前五行:
In [46]: frame.head()
Out[46]: pop state year0 1.5 Ohio 20001 1.7 Ohio 20012 3.6 Ohio 20023 2.4 Nevada 20014 2.9 Nevada 2002如果指定了列序列,則DataFrame的列就會按照指定順序進行排列:
In [47]: pd.DataFrame(data, columns=[year, state, pop])
Out[47]: year state pop0 2000 Ohio 1.51 2001 Ohio 1.72 2002 Ohio 3.63 2001 Nevada 2.44 2002 Nevada 2.95 2003 Nevada 3.2如果傳入的列在數據中找不到,就會在結果中產生缺失值:
In [48]: frame2 = pd.DataFrame(data, columns=[year, state, pop, debt],
....: index=[one, two, three, four, ....: five, six])In [49]: frame2Out[49]: year state pop debtone 2000 Ohio 1.5 NaNtwo 2001 Ohio 1.7 NaNthree 2002 Ohio 3.6 NaNfour 2001 Nevada 2.4 NaNfive 2002 Nevada 2.9 NaNsix 2003 Nevada 3.2 NaNIn [50]: frame2.columnsOut[50]: Index([year, state, pop, debt], dtype=object)通過類似字典標記的方式或屬性的方式,可以將DataFrame的列獲取為一個Series:
In [51]: frame2[state]
Out[51]: one Ohiotwo Ohiothree Ohiofour Nevadafive Nevadasix NevadaName: state, dtype: objectIn [52]: frame2.yearOut[52]: one 2000two 2001three 2002four 2001five 2002six 2003Name: year, dtype: int64筆記:IPython提供了類似屬性的訪問(即frame2.year)和tab補全。
frame2[column]適用於任何列的名,但是frame2.column只有在列名是一個合理的Python變數名時才適用。
注意,返回的Series擁有原DataFrame相同的索引,且其name屬性也已經被相應地設置好了。
行也可以通過位置或名稱的方式進行獲取,比如用loc屬性(稍後將對此進行詳細講解):
In [53]: frame2.loc[three]
Out[53]: year 2002state Ohiopop 3.6debt NaNName: three, dtype: object列可以通過賦值的方式進行修改。例如,我們可以給那個空的"debt"列賦上一個標量值或一組值:
In [54]: frame2[debt] = 16.5
In [55]: frame2Out[55]: year state pop debtone 2000 Ohio 1.5 16.5two 2001 Ohio 1.7 16.5three 2002 Ohio 3.6 16.5four 2001 Nevada 2.4 16.5five 2002 Nevada 2.9 16.5six 2003 Nevada 3.2 16.5In [56]: frame2[debt] = np.arange(6.)In [57]: frame2Out[57]: year state pop debtone 2000 Ohio 1.5 0.0two 2001 Ohio 1.7 1.0three 2002 Ohio 3.6 2.0four 2001 Nevada 2.4 3.0five 2002 Nevada 2.9 4.0six 2003 Nevada 3.2 5.0將列表或數組賦值給某個列時,其長度必須跟DataFrame的長度相匹配。如果賦值的是一個Series,就會精確匹配DataFrame的索引,所有的空位都將被填上缺失值:
In [58]: val = pd.Series([-1.2, -1.5, -1.7], index=[two, four, five])
In [59]: frame2[debt] = valIn [60]: frame2Out[60]: year state pop debtone 2000 Ohio 1.5 NaNtwo 2001 Ohio 1.7 -1.2three 2002 Ohio 3.6 NaNfour 2001 Nevada 2.4 -1.5five 2002 Nevada 2.9 -1.7six 2003 Nevada 3.2 NaN為不存在的列賦值會創建出一個新列。關鍵字del用於刪除列。
作為del的例子,我先添加一個新的布爾值的列,state是否為Ohio:
In [61]: frame2[eastern] = frame2.state == Ohio
In [62]: frame2Out[62]: year state pop debt easternone 2000 Ohio 1.5 NaN Truetwo 2001 Ohio 1.7 -1.2 Truethree 2002 Ohio 3.6 NaN Truefour 2001 Nevada 2.4 -1.5 Falsefive 2002 Nevada 2.9 -1.7 Falsesix 2003 Nevada 3.2 NaN False注意:不能用frame2.eastern創建新的列。
del方法可以用來刪除這列:
In [63]: del frame2[eastern]
In [64]: frame2.columnsOut[64]: Index([year, state, pop, debt], dtype=object)注意:通過索引方式返回的列只是相應數據的視圖而已,並不是副本。因此,對返回的Series所做的任何就地修改全都會反映到源DataFrame上。通過Series的copy方法即可指定複製列。
另一種常見的數據形式是嵌套字典:
In [65]: pop = {Nevada: {2001: 2.4, 2002: 2.9},
....: Ohio: {2000: 1.5, 2001: 1.7, 2002: 3.6}}如果嵌套字典傳給DataFrame,pandas就會被解釋為:外層字典的鍵作為列,內層鍵則作為行索引:
In [66]: frame3 = pd.DataFrame(pop)
In [67]: frame3Out[67]: Nevada Ohio2000 NaN 1.52001 2.4 1.72002 2.9 3.6你也可以使用類似NumPy數組的方法,對DataFrame進行轉置(交換行和列):
In [68]: frame3.T
Out[68]: 2000 2001 2002Nevada NaN 2.4 2.9Ohio 1.5 1.7 3.6內層字典的鍵會被合併、排序以形成最終的索引。如果明確指定了索引,則不會這樣:
In [69]: pd.DataFrame(pop, index=[2001, 2002, 2003])
Out[69]: Nevada Ohio2001 2.4 1.72002 2.9 3.62003 NaN NaN由Series組成的字典差不多也是一樣的用法:
In [70]: pdata = {Ohio: frame3[Ohio][:-1],
....: Nevada: frame3[Nevada][:2]}In [71]: pd.DataFrame(pdata)Out[71]: Nevada Ohio2000 NaN 1.52001 2.4 1.7表5-1列出了DataFrame構造函數所能接受的各種數據。
如果設置了DataFrame的index和columns的name屬性,則這些信息也會被顯示出來:
In [72]: frame3.index.name = year; frame3.columns.name = state
In [73]: frame3Out[73]: state Nevada Ohioyear2000 NaN 1.52001 2.4 1.72002 2.9 3.6跟Series一樣,values屬性也會以二維ndarray的形式返回DataFrame中的數據:
In [74]: frame3.values
Out[74]: array([[ nan, 1.5], [ 2.4, 1.7], [ 2.9, 3.6]])如果DataFrame各列的數據類型不同,則值數組的dtype就會選用能兼容所有列的數據類型:
In [75]: frame2.values
Out[75]:array([[2000, Ohio, 1.5, nan], [2001, Ohio, 1.7, -1.2], [2002, Ohio, 3.6, nan], [2001, Nevada, 2.4, -1.5], [2002, Nevada, 2.9, -1.7], [2003, Nevada, 3.2, nan]], dtype=object)索引對象
pandas的索引對象負責管理軸標籤和其他元數據(比如軸名稱等)。構建Series或DataFrame時,所用到的任何數組或其他序列的標籤都會被轉換成一個Index:
In [76]: obj = pd.Series(range(3), index=[a, b, c])
In [77]: index = obj.indexIn [78]: indexOut[78]: Index([a, b, c], dtype=object)In [79]: index[1:]Out[79]: Index([b, c], dtype=object)Index對象是不可變的,因此用戶不能對其進行修改:
index[1] = d # TypeError
不可變可以使Index對象在多個數據結構之間安全共享:
In [80]: labels = pd.Index(np.arange(3))
In [81]: labelsOut[81]: Int64Index([0, 1, 2], dtype=int64)In [82]: obj2 = pd.Series([1.5, -2.5, 0], index=labels)In [83]: obj2Out[83]: 0 1.51 -2.52 0.0dtype: float64In [84]: obj2.index is labelsOut[84]: True注意:雖然用戶不需要經常使用Index的功能,但是因為一些操作會生成包含被索引化的數據,理解它們的工作原理是很重要的。
除了類似於數組,Index的功能也類似一個固定大小的集合:
In [85]: frame3
Out[85]: state Nevada Ohioyear 2000 NaN 1.52001 2.4 1.72002 2.9 3.6In [86]: frame3.columnsOut[86]: Index([Nevada, Ohio], dtype=object, name=state)In [87]: Ohio in frame3.columnsOut[87]: TrueIn [88]: 2003 in frame3.indexOut[88]: False與python的集合不同,pandas的Index可以包含重複的標籤:
In [89]: dup_labels = pd.Index([foo, foo, bar, bar])
In [90]: dup_labelsOut[90]: Index([foo, foo, bar, bar], dtype=object)選擇重複的標籤,會顯示所有的結果
。
每個索引都有一些方法和屬性,它們可用於設置邏輯並回答有關該索引所包含的數據的常見問題。表5-2列出了這些函數。
推薦閱讀:
※泰坦尼克號存活率實踐筆記-排名3626
※5機器學習入門:Kaggle和泰坦尼克號預測
※2018數據分析實踐計劃
※詳解特徵工程與推薦系統及其實踐
※《專利審查指南修改草案》將圖形用戶界面(GUI)納入外觀設計專利範圍內,這改變意味著什麼?