Pandas入門

pandas的數據結構介紹

我們將使用下面的方式導入pandas:

  1. import pandas as pd
  2. from pandas import Series, DataFrame

Series

Series是一種類似於一維數組的對象,它由一組數據(各種NumPy數據類型)以及一組與之相關的數據標籤(即索引)組成。由一組數據就可產生最簡單的Series:

  1. In [6]: obj = pd.Series([4,7,-5,3])
  2. In [7]: obj
  3. Out[7]:
  4. 0 4
  5. 1 7
  6. 2 -5
  7. 3 3
  8. dtype: int64

Series的字元串表現為:索引在左邊,值在右邊。由於沒有為數據指定索引,於是會自動創建一個0到N-1(N為數據的長度)的整數索引。可以通過Series的values和index屬性獲取其數組表示形式和索引對象:

  1. In [8]: obj.values
  2. Out[8]: array([ 4, 7, -5, 3], dtype=int64)
  3. In [9]: obj.index
  4. Out[9]: RangeIndex(start=0, stop=4, step=1)

通常,我們希望創建的Series帶有一個可以對各個數據點進行標記的索引:

  1. In [10]: obj2 = pd.Series([4,7,-5,3],index=[d,b,a,c])
  2. In [12]: obj2
  3. Out[12]:
  4. d 4
  5. b 7
  6. a -5
  7. c 3
  8. dtype: int64

與普通NumPy數組相比,可以通過索引的方式選取Series中的單個或一組值:

  1. In [13]: obj2[a]
  2. Out[13]: -5
  3. In [15]: obj2[d] = 7
  4. In [18]: obj2[[c,a,d]]
  5. Out[18]:
  6. c 3
  7. a -5
  8. d 7
  9. dtype: int64

NumPy數組運算(如根據布爾型數組進行過濾、標量乘法、應用數學函數等)都會保留索引和值之間的連接:

  1. In [19]: obj2
  2. Out[19]:
  3. d 7
  4. b 7
  5. a -5
  6. c 3
  7. dtype: int64
  8. In [21]: obj2[obj2>0]
  9. Out[21]:
  10. d 7
  11. b 7
  12. c 3
  13. dtype: int64
  14. In [22]: obj2*2
  15. Out[22]:
  16. d 14
  17. b 14
  18. a -10
  19. c 6
  20. dtype: int64
  21. In [23]: np.exp(obj2)
  22. Out[23]:
  23. d 1096.633158
  24. b 1096.633158
  25. a 0.006738
  26. c 20.085537
  27. dtype: float64

還可以將Series看成是一個定長的有序字典,因為它是索引值到數據值的一個映射。

  1. In [24]: b in obj2
  2. Out[24]: True
  3. In [25]: e in obj2
  4. Out[25]: False

如果數據放在一個字典中,也可以通過這個字典來創建Series,索引就是原字典的鍵:

  1. In [26]: sdata = {Ohio:35000,Texas:71000,Oregon:16000,Utah:5000}
  2. In [27]: obj3 = pd.Series(sdata)
  3. In [28]: obj3
  4. Out[28]:
  5. Ohio 35000
  6. Oregon 16000
  7. Texas 71000
  8. Utah 5000
  9. dtype: int64

再看一個例子:

  1. In [30]: states = [California,Ohio,Oregon,Texas]
  2. In [31]: obj4 = pd.Series(sdata,index=states)
  3. In [32]: obj4
  4. Out[32]:
  5. California NaN
  6. Ohio 35000.0
  7. Oregon 16000.0
  8. Texas 71000.0
  9. dtype: float64

在這個例子中,sdata跟states索引相匹配的那3個值會被找出來並放到相應的位置上,但由於「California」所對應的sdata值找不到,所以其結果就為NaN(即「非數字」,在pandas中,它用於表示缺失或NA值)。pandas的 isnulllnotnull函數可用於檢測缺失數據:

  1. In [33]: pd.isnull(obj4)
  2. Out[33]:
  3. California True
  4. Ohio False
  5. Oregon False
  6. Texas False
  7. dtype: bool
  8. In [34]: pd.notnull(obj4)
  9. Out[34]:
  10. California False
  11. Ohio True
  12. Oregon True
  13. Texas True
  14. dtype: bool

對於許多應用而言,Series最重要的一個功能是:它在算術運算中會自動對齊不同索引的數據。

  1. In [35]: obj3
  2. Out[35]:
  3. Ohio 35000
  4. Oregon 16000
  5. Texas 71000
  6. Utah 5000
  7. dtype: int64
  8. In [36]: obj4
  9. Out[36]:
  10. California NaN
  11. Ohio 35000.0
  12. Oregon 16000.0
  13. Texas 71000.0
  14. dtype: float64
  15. In [37]: obj3 + obj4
  16. Out[37]:
  17. California NaN
  18. Ohio 70000.0
  19. Oregon 32000.0
  20. Texas 142000.0
  21. Utah NaN
  22. dtype: float64

Series對象本身及其索引都有一個name屬性,該屬性跟pandas其他的關鍵功能關係非常密切:

  1. In [38]: obj4.name = population
  2. In [39]: obj4.index.name = state
  3. In [40]: obj4
  4. Out[40]:
  5. state
  6. California NaN
  7. Ohio 35000.0
  8. Oregon 16000.0
  9. Texas 71000.0
  10. Name: population, dtype: float64

Series的索引可以通過賦值的方式就地修改:

  1. In [43]: obj.index = [Bob,Steve,Jeff,Ryan]
  2. In [44]: obj
  3. Out[44]:
  4. Bob 4
  5. Steve 7
  6. Jeff -5
  7. Ryan 3
  8. dtype: int64

DataFrame

DataFrame是一個表格型的數據結構,它含有一組有序的列,每列可以是不同的值類型(數值、字元串、布爾值等)。DataFrame既有行索引也有列索引,它可以被看作由Series組成的字典(共用同一個索引)。

構造DataFrame的方法有很多,最常用的一種是直接傳入一個由等長列表或NumPy數組組成的字典:

  1. In [49]: data = {state:[Ohio,Ohio,Ohio,Nevada,Nevada],
  2. ...: ...: year:[2000,2001,2002,2001,2002],
  3. ...: ...: pop:[1.5,1.7,3.6,2.4,2.9]}
  4. In [50]: frame = pd.DataFrame(data)

DataFrame會自動加上索引(和Series一樣),且全部列會被有序排列:

  1. In [51]: frame
  2. Out[51]:
  3. pop state year
  4. 0 1.5 Ohio 2000
  5. 1 1.7 Ohio 2001
  6. 2 3.6 Ohio 2002
  7. 3 2.4 Nevada 2001
  8. 4 2.9 Nevada 2002

如果指定了列序列,則DataFrame的列就會按照指定順序進行排列:

  1. In [52]: pd.DataFrame(data,columns=[year,state,pop])
  2. Out[52]:
  3. year state pop
  4. 0 2000 Ohio 1.5
  5. 1 2001 Ohio 1.7
  6. 2 2002 Ohio 3.6
  7. 3 2001 Nevada 2.4
  8. 4 2002 Nevada 2.9

和Series一樣,如果傳入的列在數據中找不到,就會產生NA值:

  1. In [56]: frame2 = pd.DataFrame(data,columns=[year,state,pop,
  2. ...: debt],index=[one,two,three,four,five])
  3. In [57]: frame2
  4. Out[57]:
  5. year state pop debt
  6. one 2000 Ohio 1.5 NaN
  7. two 2001 Ohio 1.7 NaN
  8. three 2002 Ohio 3.6 NaN
  9. four 2001 Nevada 2.4 NaN
  10. five 2002 Nevada 2.9 NaN
  11. In [58]: frame2.columns
  12. Out[58]: Index([year, state, pop, debt], dtype=object)

通過類似字典標記的方式或屬性的方式,可以將DataFrame的列獲取為一個Series:

  1. In [59]: frame2[state]
  2. Out[59]:
  3. one Ohio
  4. two Ohio
  5. three Ohio
  6. four Nevada
  7. five Nevada
  8. Name: state, dtype: object
  9. In [60]: frame2.year
  10. Out[60]:
  11. one 2000
  12. two 2001
  13. three 2002
  14. four 2001
  15. five 2002
  16. Name: year, dtype: int64

返回的Series擁有原DataFrame相同的索引,且其name屬性也已經被相應地設置好了。行也可以通過位置或名稱地方式進行獲取、比如用索引欄位loc。

  1. In [62]: frame2.loc[three]
  2. Out[62]:
  3. year 2002
  4. state Ohio
  5. pop 3.6
  6. debt NaN
  7. Name: three, dtype: object
  8. In [64]: frame2.iloc[0]
  9. Out[64]:
  10. year 2000
  11. state Ohio
  12. pop 1.5
  13. debt NaN
  14. Name: one, dtype: object

列可以通過賦值的方式進行修改。例如,我們可以給空的"debt"列賦上一個標量值或一組值:

  1. In [65]: frame2[debt] = 16.5
  2. In [66]: frame2
  3. Out[66]:
  4. year state pop debt
  5. one 2000 Ohio 1.5 16.5
  6. two 2001 Ohio 1.7 16.5
  7. three 2002 Ohio 3.6 16.5
  8. four 2001 Nevada 2.4 16.5
  9. five 2002 Nevada 2.9 16.5
  10. In [67]: frame2[debt] = np.arange(5)
  11. In [68]: frame2
  12. Out[68]:
  13. year state pop debt
  14. one 2000 Ohio 1.5 0
  15. two 2001 Ohio 1.7 1
  16. three 2002 Ohio 3.6 2
  17. four 2001 Nevada 2.4 3
  18. five 2002 Nevada 2.9 4

將列表或數組賦值給某個列時,其長度必須跟DataFrame的長度相匹配。若賦值的是一個Series,就會精確匹配DataFrame的索引,所有的空位都會被填上缺失值:

  1. In [71]: val = pd.Series([-1.2,-1.5,-1.7],index=[two,four,five])
  2. In [72]: frame2[debt] = val
  3. In [73]: frame2
  4. Out[73]:
  5. year state pop debt
  6. one 2000 Ohio 1.5 NaN
  7. two 2001 Ohio 1.7 -1.2
  8. three 2002 Ohio 3.6 NaN
  9. four 2001 Nevada 2.4 -1.5
  10. five 2002 Nevada 2.9 -1.7

為不存在的列賦值會創建出一個新列。關鍵字del用於刪除列:

  1. In [82]: frame2[eastern] = frame2.state == Ohio
  2. In [83]: frame2
  3. Out[83]:
  4. year state pop debt eastern
  5. one 2000 Ohio 1.5 NaN True
  6. two 2001 Ohio 1.7 -1.2 True
  7. three 2002 Ohio 3.6 NaN True
  8. four 2001 Nevada 2.4 -1.5 False
  9. five 2002 Nevada 2.9 -1.7 False
  10. In [84]: del frame2[eastern]
  11. In [85]: frame2.columns
  12. Out[85]: Index([year, state, pop, debt], dtype=object)

通過索引方式返回的列是相應數據的視圖,不是副本。

另一種常見的數據形式是嵌套字典:

  1. In [86]: pop = {Nevada:{2001:2.4,2002:2.9},
  2. ...: Ohio:{2000:1.5,2001:1.7,2002:3.6}}
  3. In [87]: frame3 = pd.DataFrame(pop)
  4. In [88]: frame3
  5. Out[88]:
  6. Nevada Ohio
  7. 2000 NaN 1.5
  8. 2001 2.4 1.7
  9. 2002 2.9 3.6

外層字典的鍵作為列,內層鍵作為行索引

由Series組成的字典差不多也是一樣的用法:

  1. In [95]: pdata = {Ohio:frame3[Ohio][:-1],
  2. ...: Nevada:frame3[Nevada][:2]}
  3. In [96]: pd.DataFrame(pdata)
  4. Out[96]:
  5. Nevada Ohio
  6. 2000 NaN 1.5
  7. 2001 2.4 1.7

可以輸入給DataFrame構造器的數據:

如果設置了DataFrame的index和columns的name屬性,這些信息也會被顯示出來:

  1. In [97]: frame3.index.name = year
  2. In [98]: frame3.columns.name = state
  3. In [99]: frame3
  4. Out[99]:
  5. state Nevada Ohio
  6. year
  7. 2000 NaN 1.5
  8. 2001 2.4 1.7
  9. 2002 2.9 3.6

跟Series一樣,values屬性也會以二維ndarray的形式返回DataFrame中的數據。

索引對象

pandas的索引對象負責管理軸標籤和其他元數據(比如軸名稱等)。構建Series或DataFrame時,所用到的任何數組或其他序列的標籤都會被轉換成一個Index:

  1. In [4]: obj = pd.Series(range(3),index=[a,b,c])
  2. In [5]: index = obj.index
  3. In [6]: index
  4. Out[6]: Index([a, b, c], dtype=object)
  5. In [7]: index[1:]
  6. Out[7]: Index([b, c], dtype=object)

Index對象時不可修改的,因此用戶不能對其進行修改。

除了長得像數組,Index的功能也類似一個固定大小的集合。

Index的方法和屬性:

基本功能

介紹操作Series和DataFrame中的數據的基本手段。

重新索引

pandas對象的一個重要方法是reindex,其作用是創建一個適應新索引的新對象

  1. In [11]: obj = pd.Series([-4.5,7.2,-5.3,3.6],index=[d,b,a,c])
  2. In [12]: obj
  3. Out[12]:
  4. d -4.5
  5. b 7.2
  6. a -5.3
  7. c 3.6
  8. dtype: float64
  9. In [13]: obj2 = obj.reindex([a,b,c,d,e])
  10. In [14]: obj2
  11. Out[14]:
  12. a -5.3
  13. b 7.2
  14. c 3.6
  15. d -4.5
  16. e NaN
  17. dtype: float64
  18. In [15]: obj.reindex([a,b,c,d,e],fill_value=0)
  19. Out[15]:
  20. a -5.3
  21. b 7.2
  22. c 3.6
  23. d -4.5
  24. e 0.0
  25. dtype: float64

如果某個索引值當前不存在,就引入缺失值。

對於時間序列這樣的有序數據,重新索引時可能需要做一些插值處理,method選項即可達到此目的。

  1. In [16]: obj3 = pd.Series([blue,purple,yellow],index=[0,2,4])
  2. In [17]: obj3.reindex(range(6),method=ffill)
  3. Out[17]:
  4. 0 blue
  5. 1 blue
  6. 2 purple
  7. 3 purple
  8. 4 yellow
  9. 5 yellow
  10. dtype: object

reindex的(插值)method選項:

參數說明ffill或pad前向填充(或搬運)值bfill或backfill後向填充(或搬運)值

對於DataFrame,reindex可以修改(行)索引、列,或兩個都修改。如果僅傳入一個序列則會重新索引行:

  1. In [25]: frame2 = frame.reindex([a,b,c,d])
  2. In [26]: frame = pd.DataFrame(np.arange(9).reshape((3,3)),index=[a,c,d],
  3. ...: columns=[Ohio,Texas,California])
  4. In [27]: frame2 = frame.reindex([a,b,c,d])
  5. In [29]: frame2
  6. Out[29]:
  7. Ohio Texas California
  8. a 0.0 1.0 2.0
  9. b NaN NaN NaN
  10. c 3.0 4.0 5.0
  11. d 6.0 7.0 8.0

用columns關鍵字即可重新索引列,也可同時對行和列進行重新索引,而插值則只能按行應用(即軸0)。

利用loc的標籤索引功能,重新索引任務可以變得更簡潔:

  1. In [33]: states = [Texas,Utah,California]
  2. In [34]: frame.loc[[a,b,c,d],states]
  3. Out[34]:
  4. Texas Utah California
  5. a 1.0 NaN 2.0
  6. b NaN NaN NaN
  7. c 4.0 NaN 5.0
  8. d 7.0 NaN 8.0

reindex函數的參數:

丟棄指定軸上的項

丟棄某條軸上一個或多個項很簡單,只要一個索引數組或列表即可。使用drop方法返回的是一個在指定軸上刪除了指定值得新對象:

  1. In [37]: obj = pd.Series(np.arange(5),index=[a,b,c,d,e])
  2. In [38]: obj
  3. Out[38]:
  4. a 0
  5. b 1
  6. c 2
  7. d 3
  8. e 4
  9. dtype: int32
  10. In [39]: new_obj = obj.drop(c)
  11. In [40]: new_obj
  12. Out[40]:
  13. a 0
  14. b 1
  15. d 3
  16. e 4
  17. dtype: int32
  18. In [41]: obj.drop([d,c])
  19. Out[41]:
  20. a 0
  21. b 1
  22. e 4
  23. dtype: int32

對於DataFrame,可以刪除任意軸上的索引值:

  1. In [42]: data = pd.DataFrame(np.arange(16).reshape((4,4)),
  2. ...: index=[Ohio,Colorado,Utah,New York],
  3. ...: columns=[one,two,three,four])
  4. In [43]: data
  5. Out[43]:
  6. one two three four
  7. Ohio 0 1 2 3
  8. Colorado 4 5 6 7
  9. Utah 8 9 10 11
  10. New York 12 13 14 15
  11. In [44]: data.drop([Colorado,Ohio])
  12. Out[44]:
  13. one two three four
  14. Utah 8 9 10 11
  15. New York 12 13 14 15
  16. In [45]: data.drop(two,axis=1)
  17. Out[45]:
  18. one three four
  19. Ohio 0 2 3
  20. Colorado 4 6 7
  21. Utah 8 10 11
  22. New York 12 14 15
  23. In [46]: data.drop([two,four],axis=1)
  24. Out[46]:
  25. one three
  26. Ohio 0 2
  27. Colorado 4 6
  28. Utah 8 10
  29. New York 12 14

函數應用和映射

NumPy的ufuncs(元素級數組方法)也可以用於pandas對象:

  1. In [254]:frame = pd.DataFrame(np.random.randn(4,3),columns=list(bde),index=[Utah,Ohio,Texas,Oregon])
  2. In [255]:frame
  3. Out[255]:
  4. b d e
  5. Utah 0.990385 -0.544831 -1.963969
  6. Ohio 1.031441 -0.072482 -1.041419
  7. Texas -0.152213 1.202226 -2.117903
  8. Oregon -0.265797 0.199725 1.618044
  9. In [255]:np.abs(frame)
  10. Out[256]:
  11. b d e
  12. Utah 0.990385 0.544831 1.963969
  13. Ohio 1.031441 0.072482 1.041419
  14. Texas 0.152213 1.202226 2.117903
  15. Oregon 0.265797 0.199725 1.618044

另一個常見的操作是,將函數應用到由列或行形成的一維數組上。DataFrame的apply方法即可實現此功能。

  1. In [257]:f = lambda x:x.max() - x.min()
  2. In [258]:frame.apply(f)
  3. Out[258]:
  4. b 1.297238
  5. d 1.747057
  6. e 3.735947
  7. dtype: float64
  8. In [259]:frame.apply(f,axis=1)
  9. Out[259]:
  10. Utah 2.954354
  11. Ohio 2.072860
  12. Texas 3.320129
  13. Oregon 1.883841
  14. dtype: float64

許多常見的數組統計功能都被實現成DataFrame的方法(如sum和mean),因此無需使用apply方法。

除標量值外,傳遞給apply的函數還可以返回由多個值組成的Series:

  1. In [260]: def f(x):
  2. ...: return pd.Series([x.max(), x.min()],index=[max,min])
  3. ...:
  4. In [261]: frame.apply(f)
  5. Out[261]:
  6. b d e
  7. max 1.031441 1.202226 1.618044
  8. min -0.265797 -0.544831 -2.117903

元素級Python函數也是可以用的。假如你想得到frame中各個浮點值的格式化字元串,使用applymap即可:

  1. In [262]: format = lambda x: %.2f % x
  2. In [263]: frame.applymap(format)
  3. Out[263]:
  4. b d e
  5. Utah 0.99 -0.54 -1.96
  6. Ohio 1.03 -0.07 -1.04
  7. Texas -0.15 1.20 -2.12
  8. Oregon -0.27 0.20 1.62

之所以叫applymap是因為Series有一個應用於元素級函數的map方法:

  1. In [265]: frame[e].map(format)
  2. Out[265]:
  3. Utah -1.96
  4. Ohio -1.04
  5. Texas -2.12
  6. Oregon 1.62
  7. Name: e, dtype: object

排序和排名

根據條件對數據集排序,要對行或列索引進行排序(按字典排序)可使用sort_index方法,其返回一個已排序的新對象:

  1. In [266]: obj = pd.Series(np.arange(4),index=[d,a,b,c])
  2. In [267]: obj
  3. Out[267]:
  4. d 0
  5. a 1
  6. b 2
  7. c 3
  8. dtype: int32
  9. In [268]: obj.sort_index()
  10. Out[268]:
  11. a 1
  12. b 2
  13. c 3
  14. d 0
  15. dtype: int32

對於DataFrame,則可以根據任意一個軸上的索引進行排序:

  1. In [273]: frame = pd.DataFrame(np.arange(8).reshape(2,4),index=[three,one],columns=[d,a,b,c])
  2. In [274]: frame
  3. Out[274]:
  4. d a b c
  5. three 0 1 2 3
  6. one 4 5 6 7
  7. In [275]: frame.sort_index()
  8. Out[275]:
  9. d a b c
  10. one 4 5 6 7
  11. three 0 1 2 3
  12. In [276]: frame.sort_index(axis=1)
  13. Out[276]:
  14. a b c d
  15. three 1 2 3 0
  16. one 5 6 7 4

數據默認是按升序排序,但也可以降序排序:

  1. In [277]: frame.sort_index(axis=1,ascending=False)
  2. Out[277]:
  3. d c b a
  4. three 0 3 2 1
  5. one 4 7 6 5

若要按值對Series進行排序,可使用sort_values方法:

  1. In [285]: obj = pd.Series([4,7,-3,2])
  2. In [286]: obj.sort_values()
  3. Out[286]:
  4. 2 -3
  5. 3 2
  6. 0 4
  7. 1 7
  8. dtype: int64

排序時,缺失值默認會被放到Series的末尾:

  1. In [287]: obj = pd.Series([4,7,np.nan,-3,2])
  2. In [288]: obj.sort_values()
  3. Out[288]:
  4. 3 -3.0
  5. 4 2.0
  6. 0 4.0
  7. 1 7.0
  8. 2 NaN
  9. dtype: float64

在DataFrame上,你可能希望根據一個或多個列中的值進行排序。將一個或多個列的名字傳給by選項即可達到目的:

  1. In [289]: frame = pd.DataFrame({b:[4,7,-3,2],a:[0,1,0,1]})
  2. In [290]: frame
  3. Out[290]:
  4. a b
  5. 0 0 4
  6. 1 1 7
  7. 2 0 -3
  8. 3 1 2
  9. In [291]: frame.sort_values(by=b)
  10. Out[291]:
  11. a b
  12. 2 0 -3
  13. 3 1 2
  14. 0 0 4
  15. 1 1 7

要給多個列進行排序,傳入名稱列表即可:

  1. In [292]: frame.sort_values(by=[a,b])
  2. Out[292]:
  3. a b
  4. 2 0 -3
  5. 0 0 4
  6. 3 1 2
  7. 1 1 7

排名(ranking)跟排序關係密切,它會增設一個排名值(從1開始,一直到數組中有效數據的數量)。Series和DataFrame的rank方法。默認情況是通過「為各組分配一個平均排名」的方式破壞平級關係的。

  1. In [300]: obj = pd.Series([7,-5,7,4,2,0,4])
  2. In [301]: obj.rank()
  3. Out[301]:
  4. 0 6.5
  5. 1 1.0
  6. 2 6.5
  7. 3 4.5
  8. 4 3.0
  9. 5 2.0
  10. 6 4.5
  11. dtype: float64

也可以根據值在原數據中出現的順序給出排名:

  1. In [304]: obj.rank(method=first)
  2. Out[304]:
  3. 0 6.0
  4. 1 1.0
  5. 2 7.0
  6. 3 4.0
  7. 4 3.0
  8. 5 2.0
  9. 6 5.0
  10. dtype: float64

method選項

method說明average默認:在相等分組中,為各個值分配平均排名min使用整個分組的最小排名max使用整個分組的最大排名first按值在原始數據中的出現順序分配排名

帶有重複值的軸索引

雖然許多pandas函數(如reindex)都要求標籤唯一,但並不是強制性的。

  1. In [306]: obj
  2. Out[306]:
  3. a 0
  4. a 1
  5. b 2
  6. b 3
  7. c 4
  8. dtype: int32

索引的is_unique屬性可以告訴你它的值是否是唯一的:

  1. obj.index.is_unique
  2. Out[307]: False

對於帶有重複值索引,數據選取的行為將會有些不同。如果某個索引對應多個值,則返回一個Series,而對應單個值得,則返回一個標量值。

  1. In [308]: obj[a]
  2. Out[308]:
  3. a 0
  4. a 1
  5. dtype: int32
  6. In [309]: obj[c]
  7. Out[309]: 4

對DataFram的行進行索引亦是如此:

  1. df = pd.DataFrame(np.random.randn(4,3),index=[a,a,b,b])
  2. In [315]: df
  3. Out[315]:
  4. 0 1 2
  5. a 1.003668 -2.084179 0.230573
  6. a 0.405376 0.677472 -0.489013
  7. b 0.674649 0.366657 0.026477
  8. b -1.128948 0.664332 0.792995
  9. In [316]: df.loc[a]
  10. Out[316]:
  11. 0 1 2
  12. a 1.003668 -2.084179 0.230573
  13. a 0.405376 0.677472 -0.489013

匯總和計算描述統計

方法說明count非NA值的數量describe針對Series或各DataFrame列計算匯總統計max,min計算最小值和最大值argmin,argmax計算能夠獲取到最小值和最大值的索引位置(整數)idxmin,idxmax計算能夠獲取到最小值和最大值的索引值quantile計算樣本的分位數(0到1)sum值的總和mean值的平均數median值的算術中位數mad根據平均值計算平均絕對離差var樣本值的方差std樣本值得標準差skew樣本值的偏度(三階矩)kurt樣本值得峰度(四階矩)cumsum樣本值的累計和cummin,cummax樣本值的累計最大值和累計最小值cumprod樣本的累計積diff計算一階差分pct_change計算百分數變化

唯一值、值計數以及成員資格

還有一類方法可以從一維Series的值中抽取信息。以下面這個Series為例:

  1. In [8]: obj = pd.Series([c,a,d,a,a,b,b,c,c])

第一個函數是 unique,可以得到Series中的唯一值數組:

  1. In [9]: uniques = obj.unique()
  2. In [10]: uniques
  3. Out[10]: array([c, a, d, b], dtype=object)

返回的唯一值是未排序的,需要的話,可以對結果再次進行排序( uniques.sort()原地排序)。 value_counts()用於計算一個Series中各值出現的頻率:

  1. In [13]: obj.value_counts()
  2. Out[13]:
  3. c 3
  4. a 3
  5. b 2
  6. d 1
  7. dtype: int64

value_counts是一個頂級pandas方法,可用於任何數組或序列:

  1. In [14]: pd.value_counts(obj.values,sort=False)
  2. Out[14]:
  3. b 2
  4. d 1
  5. a 3
  6. c 3
  7. dtype: int64

最後是 isin,用於判斷矢量化集合的成員資格,可用於選取Series中或DataFrame列中數據的子集:

  1. In [18]: mask = obj.isin([b,c])
  2. In [19]: mask
  3. Out[19]:
  4. 0 True
  5. 1 False
  6. 2 False
  7. 3 False
  8. 4 False
  9. 5 True
  10. 6 True
  11. 7 True
  12. 8 True
  13. dtype: bool
  14. In [20]: obj[mask]
  15. Out[20]:
  16. 0 c
  17. 5 b
  18. 6 b
  19. 7 c
  20. 8 c
  21. dtype: object

唯一值、值計數、成員資格方法

方法說明isin計算一個表示「Series各值是否包含於傳入的值序列中」的布爾型數組unique計算Series中的唯一值數組,按發現的順序返回value_counts返回一個Series,其索引為唯一值,其值為頻率,按計數值降序排列

有時,你可能希望得到DataFrame中多個相關列的一張柱狀圖,例如:

  1. In [21]: data = pd.DataFrame({Qu1:[1,3,4,3,4],
  2. ...: Qu2:[2,3,1,2,3],
  3. ...: Qu3:[1,5,2,4,4]})
  4. In [22]: data
  5. Out[22]:
  6. Qu1 Qu2 Qu3
  7. 0 1 2 1
  8. 1 3 3 5
  9. 2 4 1 2
  10. 3 3 2 4
  11. 4 4 3 4

pandas.value_counts傳給該DataFrame的apply函數,就會出現:

  1. In [23]: result = data.apply(pd.value_counts).fillna(0)
  2. In [24]: result
  3. Out[24]:
  4. Qu1 Qu2 Qu3
  5. 1 1.0 1.0 1.0
  6. 2 0.0 2.0 1.0
  7. 3 2.0 2.0 0.0
  8. 4 2.0 0.0 2.0
  9. 5 0.0 0.0 1.0

處理缺失數據

pandas使用浮點值NaN(Not a Number)表示浮點和非浮點數組中的缺失數據。它只是一個便於被檢測出來的標記而已:

  1. In [26]: string_data = pd.Series([aardvark,artichoke,np.nan,avocado])
  2. In [27]: string_data
  3. Out[27]:
  4. 0 aardvark
  5. 1 artichoke
  6. 2 NaN
  7. 3 avocado
  8. dtype: object
  9. In [28]: string_data.isnull()
  10. Out[28]:
  11. 0 False
  12. 1 False
  13. 2 True
  14. 3 False
  15. dtype: bool

Python內置的None值也會被當做NA處理:

  1. In [30]: string_data[0] = None
  2. In [31]: string_data.isnull()
  3. Out[31]:
  4. 0 True
  5. 1 False
  6. 2 True
  7. 3 False
  8. dtype: bool

NA處理方法

方法說明dropna根據各標籤的值中是否存在缺失數據對軸標籤進行過濾,可通過閾值調節對缺失值的容忍度fillna用指定值或者插值法(如ffill或bfill)填充缺失數據isnull返回一個含有布爾值的對象,這些布爾值表示哪些值是缺失值/NA,該對象類型與源類型一樣notnullisnull的否定式

濾除缺失數據

過濾掉缺失數據的辦法由很多種,純手工操作永遠都是一個辦法,但dropna可能會更實用一些。對於一個Series,dropna返回一個僅含非空數據和索引值的Series:

  1. In [32]: from numpy import nan as NA
  2. ...:
  3. In [33]: data = pd.Series([1,NA,3.5,NA,7])
  4. In [34]: data
  5. Out[34]:
  6. 0 1.0
  7. 1 NaN
  8. 2 3.5
  9. 3 NaN
  10. 4 7.0
  11. dtype: float64
  12. In [35]: data.dropna()
  13. Out[35]:
  14. 0 1.0
  15. 2 3.5
  16. 4 7.0
  17. dtype: float64

也可以通過布爾型索引達到這個目的:

  1. In [36]: data[data.notnull()]
  2. Out[36]:
  3. 0 1.0
  4. 2 3.5
  5. 4 7.0
  6. dtype: float64

而對於DataFrame對象,事情就有點複雜了。你可能希望丟棄全NA或含有NA的行或列。 dropna默認丟棄任何含有缺失值的行:

  1. In [37]: data = pd.DataFrame([[1,6.5,3],[1,NA,NA],[NA,NA,NA],
  2. ...: [NA,6.5,3]])
  3. In [38]: cleaned = data.dropna()
  4. In [39]: cleaned
  5. Out[39]:
  6. 0 1 2
  7. 0 1.0 6.5 3.0
  8. In [40]: data
  9. Out[40]:
  10. 0 1 2
  11. 0 1.0 6.5 3.0
  12. 1 1.0 NaN NaN
  13. 2 NaN NaN NaN
  14. 3 NaN 6.5 3.0

傳入 how=all將只丟棄全為NA的那些行:

  1. In [41]: data.dropna(how=all)
  2. Out[41]:
  3. 0 1 2
  4. 0 1.0 6.5 3.0
  5. 1 1.0 NaN NaN
  6. 3 NaN 6.5 3.0

要用這種方式丟棄列,只需傳入axis=1即可:

  1. In [42]: data[4] = NA
  2. In [43]: data
  3. Out[43]:
  4. 0 1 2 4
  5. 0 1.0 6.5 3.0 NaN
  6. 1 1.0 NaN NaN NaN
  7. 2 NaN NaN NaN NaN
  8. 3 NaN 6.5 3.0 NaN
  9. In [44]: data.dropna(axis=1,how=all)
  10. Out[44]:
  11. 0 1 2
  12. 0 1.0 6.5 3.0
  13. 1 1.0 NaN NaN
  14. 2 NaN NaN NaN
  15. 3 NaN 6.5 3.0

另一個濾除DataFrame行的問題涉及時間序列數據。假設你只想留下一部分觀測數據,可以用thresh參數實現此目的:

  1. In [45]: df = pd.DataFrame(np.random.randn(7,3))
  2. In [46]: df.iloc[:4,1] = NA
  3. In [47]: df.iloc[:2,2] = NA
  4. In [48]: df
  5. Out[48]:
  6. 0 1 2
  7. 0 0.104567 NaN NaN
  8. 1 0.518986 NaN NaN
  9. 2 -0.142659 NaN 1.049138
  10. 3 -0.384427 NaN -0.313821
  11. 4 0.298793 0.428673 -0.504281
  12. 5 -1.708273 0.550135 -0.573248
  13. 6 0.939368 0.931789 1.381717
  14. In [49]: df.dropna(thresh=3)
  15. Out[49]:
  16. 0 1 2
  17. 4 0.298793 0.428673 -0.504281
  18. 5 -1.708273 0.550135 -0.573248
  19. 6 0.939368 0.931789 1.381717

填充缺失數據

你可能不想過濾缺失數據(有可能會捨棄與它相關的其他數據),而希望補填那些「空洞」。 fillna函數就是最主要的函數,通過一個常數調用 fillna就會將缺失值替換為那個常數值:

  1. In [52]: df.fillna(0)
  2. Out[52]:
  3. 0 1 2
  4. 0 0.104567 0.000000 0.000000
  5. 1 0.518986 0.000000 0.000000
  6. 2 -0.142659 0.000000 1.049138
  7. 3 -0.384427 0.000000 -0.313821
  8. 4 0.298793 0.428673 -0.504281
  9. 5 -1.708273 0.550135 -0.573248
  10. 6 0.939368 0.931789 1.381717

若是通過一個字典調用fillna,就可以實現對不同列填充不同的值:

  1. In [53]: df.fillna({1:0.5,3:-1})
  2. Out[53]:
  3. 0 1 2
  4. 0 0.104567 0.500000 NaN
  5. 1 0.518986 0.500000 NaN
  6. 2 -0.142659 0.500000 1.049138
  7. 3 -0.384427 0.500000 -0.313821
  8. 4 0.298793 0.428673 -0.504281
  9. 5 -1.708273 0.550135 -0.573248
  10. 6 0.939368 0.931789 1.381717

fillna默認會返回新對象,也可以對現有對象進行就地修改:

  1. In [59]: _ = df.fillna(0,inplace=True)
  2. In [60]: df
  3. Out[60]:
  4. 0 1 2
  5. 0 0.104567 0.000000 0.000000
  6. 1 0.518986 0.000000 0.000000
  7. 2 -0.142659 0.000000 1.049138
  8. 3 -0.384427 0.000000 -0.313821
  9. 4 0.298793 0.428673 -0.504281
  10. 5 -1.708273 0.550135 -0.573248
  11. 6 0.939368 0.931789 1.381717

reindex有效的那些插值方法也可用於 fillna:

  1. In [64]: df = pd.DataFrame(np.random.randn(6,3))
  2. In [65]: df.iloc[2:,1] = NA
  3. In [66]: df.iloc[4:,2] = NA
  4. In [67]: df
  5. Out[67]:
  6. 0 1 2
  7. 0 1.271795 2.199552 0.013219
  8. 1 -0.976690 -0.139820 0.084507
  9. 2 -0.757627 NaN -1.986518
  10. 3 -0.169319 NaN 0.912791
  11. 4 0.488452 NaN NaN
  12. 5 0.870533 NaN NaN
  13. In [68]: df.fillna(method=ffill)
  14. Out[68]:
  15. 0 1 2
  16. 0 1.271795 2.199552 0.013219
  17. 1 -0.976690 -0.139820 0.084507
  18. 2 -0.757627 -0.139820 -1.986518
  19. 3 -0.169319 -0.139820 0.912791
  20. 4 0.488452 -0.139820 0.912791
  21. 5 0.870533 -0.139820 0.912791
  22. In [69]: df.fillna(method=ffill,limit=2)
  23. Out[69]:
  24. 0 1 2
  25. 0 1.271795 2.199552 0.013219
  26. 1 -0.976690 -0.139820 0.084507
  27. 2 -0.757627 -0.139820 -1.986518
  28. 3 -0.169319 -0.139820 0.912791
  29. 4 0.488452 NaN 0.912791
  30. 5 0.870533 NaN 0.912791

fillna函數的參數

參數說明value用於填充缺失值的標量值或字典對象method插值方式。默認為「ffill」axis待填充的軸,默認axis=0inplace修改調用者而不產生副本limit(對於前向和後向填充)可以連續填充的最大數量

層次化索引

層次化索引是pandas一項重要功能,它使你能在一個軸上擁有多個(兩個以上)索引級別。抽象點說,它使你能以低維度形式處理高緯度數據。先看一個簡單的例子:創建一個Series,並用一個由列表或數組組成列表作為索引。

  1. In [70]: data = pd.Series(np.random.randn(10),
  2. ...: index=[[a,a,a,b,b,b,c,c,d,
  3. ...: d],[1,2,3,1,2,3,1,2,2,3]])
  4. In [71]: data
  5. Out[71]:
  6. a 1 -0.774308
  7. 2 -1.116404
  8. 3 0.956191
  9. b 1 -0.744595
  10. 2 -1.806086
  11. 3 0.471932
  12. c 1 0.989313
  13. 2 0.532067
  14. d 2 0.964238
  15. 3 0.129724
  16. dtype: float64

這就是帶有MultiIndex索引的Series的格式化輸出形式。索引之間的「間隔」表示「直接使用上面的標籤」:

  1. In [72]: data.index
  2. Out[72]:
  3. MultiIndex(levels=[[a, b, c, d], [1, 2, 3]],
  4. labels=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 2]])

對於也給層次化索引的對象,選取數據子集的操作很簡單:

  1. In [73]: data[b]
  2. Out[73]:
  3. 1 -0.744595
  4. 2 -1.806086
  5. 3 0.471932
  6. dtype: float64
  7. In [74]: data[b:c]
  8. Out[74]:
  9. b 1 -0.744595
  10. 2 -1.806086
  11. 3 0.471932
  12. c 1 0.989313
  13. 2 0.532067
  14. dtype: float64
  15. In [75]: data.loc[[b,d]]
  16. Out[75]:
  17. b 1 -0.744595
  18. 2 -1.806086
  19. 3 0.471932
  20. d 2 0.964238
  21. 3 0.129724
  22. dtype: float64

有時甚至還可以在「內層」中進行選取:

  1. In [76]: data[:,2]
  2. Out[76]:
  3. a -1.116404
  4. b -1.806086
  5. c 0.532067
  6. d 0.964238
  7. dtype: float64

層次化索引在數據重塑和基於分組的操作(如透視表生成)中扮演著重要的角色。比如說,這段數據可以通過 unstack方法被重新安排到一個DataFrame中:

  1. In [78]: data.unstack()
  2. Out[78]:
  3. 1 2 3
  4. a -0.774308 -1.116404 0.956191
  5. b -0.744595 -1.806086 0.471932
  6. c 0.989313 0.532067 NaN
  7. d NaN 0.964238 0.129724

unstack的逆運算是 stack:

  1. In [80]: data.unstack().stack()
  2. Out[80]:
  3. a 1 -0.774308
  4. 2 -1.116404
  5. 3 0.956191
  6. b 1 -0.744595
  7. 2 -1.806086
  8. 3 0.471932
  9. c 1 0.989313
  10. 2 0.532067
  11. d 2 0.964238
  12. 3 0.129724
  13. dtype: float64

對於也給DataFrame,每條軸都可以有分層索引:

  1. In [81]: frame = pd.DataFrame(np.arange(12).reshape(4,3),
  2. ...: index=[[a,a,b,b],[1,2,1,2]],
  3. ...: columns = [[Ohio,Ohio,Colorado],
  4. ...: [Green,Red,Green]])
  5. In [82]: frame
  6. Out[82]:
  7. Ohio Colorado
  8. Green Red Green
  9. a 1 0 1 2
  10. 2 3 4 5
  11. b 1 6 7 8
  12. 2 9 10 11

各層都可以有名字(可以是字元串,也可以是別的Python對象)。如果指定了名稱,就會顯示在控制台輸出中:

  1. In [83]: frame.index.names = [key1,key2]
  2. In [84]: frame.columns.names = [state,color]
  3. In [85]: frame
  4. Out[85]:
  5. state Ohio Colorado
  6. color Green Red Green
  7. key1 key2
  8. a 1 0 1 2
  9. 2 3 4 5
  10. b 1 6 7 8
  11. 2 9 10 11

有了分部的列索引,就可以輕鬆選取分組:

  1. In [86]: frame[Ohio]
  2. Out[86]:
  3. color Green Red
  4. key1 key2
  5. a 1 0 1
  6. 2 3 4
  7. b 1 6 7
  8. 2 9 10

以及:

  1. In [88]: frame.loc[a]
  2. Out[88]:
  3. state Ohio Colorado
  4. color Green Red Green
  5. key2
  6. 1 0 1 2
  7. 2 3 4 5
  8. In [89]: frame.loc[a,Ohio]
  9. Out[89]:
  10. color Green Red
  11. key2
  12. 1 0 1
  13. 2 3 4

可以單獨創建MultiIndex然後復用。上面那個DataFrame中的(分級的)可以這樣創建:

  1. In [94]: from pandas import MultiIndex
  2. In [95]: MultiIndex.from_arrays([[Ohio,Ohio,Colorado],
  3. ...: [Green,Red,Green]],names=[state,color])
  4. Out[95]:
  5. MultiIndex(levels=[[Colorado, Ohio], [Green, Red]],
  6. labels=[[1, 1, 0], [0, 1, 0]],
  7. names=[state, color])
  8. In [96]: frame
  9. Out[96]:
  10. state Ohio Colorado
  11. color Green Red Green
  12. key1 key2
  13. a 1 0 1 2
  14. 2 3 4 5
  15. b 1 6 7 8
  16. 2 9 10 11

重排分級順序

有時,你需要重新調整某條軸上各級別的順序,或根據指定級別上的值對數據進行排序。 swaplevel接受兩個級別編號或名稱,並返回一個互換了級別的新對象(但數據不會發生變化):

  1. In [98]: frame.swaplevel(key1,key2)
  2. Out[98]:
  3. state Ohio Colorado
  4. color Green Red Green
  5. key2 key1
  6. 1 a 0 1 2
  7. 2 a 3 4 5
  8. 1 b 6 7 8
  9. 2 b 9 10 11

sort_index則根據單個級別中的值對數據進行排序(穩定的)。交換級別時,常常也會用到 sort_index,這樣最終結果就是有序的了:

  1. In [104]: frame.sort_index(level=1)
  2. Out[104]:
  3. state Ohio Colorado
  4. color Green Red Green
  5. key1 key2
  6. a 1 0 1 2
  7. b 1 6 7 8
  8. a 2 3 4 5
  9. b 2 9 10 11
  10. In [105]: frame.swaplevel(0,1).sort_index(level=0)
  11. Out[105]:
  12. state Ohio Colorado
  13. color Green Red Green
  14. key2 key1
  15. 1 a 0 1 2
  16. b 6 7 8
  17. 2 a 3 4 5
  18. b 9 10 11

根據級別匯總統計

許多對DataFrame和Series的描述和匯總統計都有一個level選項,用於指定在某條軸上求和級別。以上面那個DataFrame為例,我們可以根據行或列上的級別來進行求和,如下所示:

  1. In [106]: frame
  2. Out[106]:
  3. state Ohio Colorado
  4. color Green Red Green
  5. key1 key2
  6. a 1 0 1 2
  7. 2 3 4 5
  8. b 1 6 7 8
  9. 2 9 10 11
  10. In [107]: frame.sum(level=key2)
  11. Out[107]:
  12. state Ohio Colorado
  13. color Green Red Green
  14. key2
  15. 1 6 8 10
  16. 2 12 14 16
  17. In [108]: frame.sum(level=color,axis=1)
  18. Out[108]:
  19. color Green Red
  20. key1 key2
  21. a 1 2 1
  22. 2 8 4
  23. b 1 14 7
  24. 2 20 10

這其實利用了pandas的groupby功能。

使用DataFrame的列

人們經常想要將DataFrame的一個或多個列當作行索引來用,或者可能希望將行索引變成DataFrame的列,舉個例子:

  1. In [113]: frame = pd.DataFrame({a:np.arange(7),b:range(7,0,-1),
  2. ...: c:[one,one,one,two,two,two,two],
  3. ...: d:[0,1,2,0,1,2,3]})
  4. In [114]: frame
  5. Out[114]:
  6. a b c d
  7. 0 0 7 one 0
  8. 1 1 6 one 1
  9. 2 2 5 one 2
  10. 3 3 4 two 0
  11. 4 4 3 two 1
  12. 5 5 2 two 2
  13. 6 6 1 two 3

DataFrame的 set_index函數會將其一個或多個列轉換為行索引,並創建一個新DataFrame:

  1. In [115]: frame2 = frame.set_index([c,d])
  2. In [116]: frame2
  3. Out[116]:
  4. a b
  5. c d
  6. one 0 0 7
  7. 1 1 6
  8. 2 2 5
  9. two 0 3 4
  10. 1 4 3
  11. 2 5 2
  12. 3 6 1

默認情況下,那些列會從DataFrame中移除,但也可以保留下來:

  1. In [117]: frame.set_index([c,d],drop=False)
  2. Out[117]:
  3. a b c d
  4. c d
  5. one 0 0 7 one 0
  6. 1 1 6 one 1
  7. 2 2 5 one 2
  8. two 0 3 4 two 0
  9. 1 4 3 two 1
  10. 2 5 2 two 2
  11. 3 6 1 two 3

reset_index的功能和 set_index剛好相反,層次化索引的級別會被轉移到列裡面:

  1. In [119]: frame2.reset_index()
  2. Out[119]:
  3. c d a b
  4. 0 one 0 0 7
  5. 1 one 1 1 6
  6. 2 one 2 2 5
  7. 3 two 0 3 4
  8. 4 two 1 4 3
  9. 5 two 2 5 2
  10. 6 two 3 6 1

推薦閱讀:

擴散方程
Python有哪些可以做帶約束的二次線性規劃的包?
如何正確地/有趣地使用Matlab手機版?
Windows下有什麼辦法提高conda install的速度?
Python裡面的scipy庫如何計算線性規劃問題呢?

TAG:Python | 科学计算 |