數據規整化:清理、轉換、合併、重塑

合併數據集

pandas對象中的數據可以通過一些內置的方式進行合併:

  • pandas.merge可根據一個或多個鍵將不同DataFrame中的行連接起來。SQL或其他關係型資料庫的用戶對此應該會比較熟悉,因為它實現的就是資料庫的連接操作。
  • pandas.concat可以沿著一條軸將多個對象堆疊到一起。
  • 實例方法combine_first可以將重複數據編接在一起,用一個對象中的值填充另一個對象中的缺失值。

資料庫風格的DataFrame合併

數據集的合併(merge)或連接(join)運算是通過一個或多個鍵將行連接起來的。這些運算是關係型資料庫的核心。pandas的merge函數是對數據應用這些演算法的主要切入點。

以一個簡單的例子開始:

  1. In [176]: df1 = pd.DataFrame({key:[b,b,a,c,a,a,b],
  2. ...: data1:range(7)})
  3. In [177]: df2 = pd.DataFrame({key:[a,b,d],
  4. ...: data2:range(3)})
  5. In [178]: df1
  6. Out[178]:
  7. data1 key
  8. 0 0 b
  9. 1 1 b
  10. 2 2 a
  11. 3 3 c
  12. 4 4 a
  13. 5 5 a
  14. 6 6 b
  15. In [179]: df2
  16. Out[179]:
  17. data2 key
  18. 0 0 a
  19. 1 1 b
  20. 2 2 d
  21. In [180]: pd.merge(df1,df2)
  22. Out[180]:
  23. data1 key data2
  24. 0 0 b 1
  25. 1 1 b 1
  26. 2 6 b 1
  27. 3 2 a 0
  28. 4 4 a 0
  29. 5 5 a 0

注意,我們並沒有指明要用哪個列進行連接。如果沒有指明,merge就會將重疊列的列名當作鍵。不過,最好顯式指定一下:

  1. In [181]: pd.merge(df1,df2,on=key)
  2. Out[181]:
  3. data1 key data2
  4. 0 0 b 1
  5. 1 1 b 1
  6. 2 6 b 1
  7. 3 2 a 0
  8. 4 4 a 0
  9. 5 5 a 0

如果兩個對象的列名不同,也可以分別進行指定:

  1. In [182]: df3 = pd.DataFrame({lkey:[b,b,a,c,a,a,b],
  2. ...: data1:range(7)})
  3. In [183]: df4 = pd.DataFrame({rkey:[a,b,d],
  4. ...: data2:range(3)})
  5. In [184]: pd.merge(df3,df4,left_on=lkey,right_on=rkey)
  6. Out[184]:
  7. data1 lkey data2 rkey
  8. 0 0 b 1 b
  9. 1 1 b 1 b
  10. 2 6 b 1 b
  11. 3 2 a 0 a
  12. 4 4 a 0 a
  13. 5 5 a 0 a

可能你已經注意到,結果裡面c和d以及與之相關的數據消失了。默認情況下,merge做的是「inner」連接;結果中的鍵是交集。其他方式還有「merge」、「right」以及「outer」。外連接求取的是鍵的並集,組合了左連接和右連接的效果:

  1. In [185]: pd.merge(df1,df2,how=outer)
  2. Out[185]:
  3. data1 key data2
  4. 0 0.0 b 1.0
  5. 1 1.0 b 1.0
  6. 2 6.0 b 1.0
  7. 3 2.0 a 0.0
  8. 4 4.0 a 0.0
  9. 5 5.0 a 0.0
  10. 6 3.0 c NaN
  11. 7 NaN d 2.0

要根據多個鍵進行合併,傳入一個由列名組成的列表即可:

  1. In [186]: left = pd.DataFrame({key1:[foo,foo,bar],
  2. ...: key2:[one,two,one],
  3. ...: lval:[1,2,3]})
  4. In [187]: right = pd.DataFrame({key1:[foo,foo,bar,bar],
  5. ...: key2:[one,one,one,two],
  6. ...: rval:[4,5,6,7]})
  7. In [188]: pd.merge(left,right,on=[key1,key2],how=outer)
  8. Out[188]:
  9. key1 key2 lval rval
  10. 0 foo one 1.0 4.0
  11. 1 foo one 1.0 5.0
  12. 2 foo two 2.0 NaN
  13. 3 bar one 3.0 6.0
  14. 4 bar two NaN 7.0

結果中會出現哪些鍵組合取決於所選的合併方式,你可以這樣理解:多個鍵形成一系列元組,並將其當作單個連接鍵(當然,實際上不是這麼回事)。

對於合併運算需要考慮的最後一個問題是對重複列名的處理,merge有一個實用的suffixes選項,用於指定附加到左右兩個DataFrame對象的重疊列名上的字元串:

  1. In [191]: pd.merge(left,right,on=key1)
  2. Out[191]:
  3. key1 key2_x lval key2_y rval
  4. 0 foo one 1 one 4
  5. 1 foo one 1 one 5
  6. 2 foo two 2 one 4
  7. 3 foo two 2 one 5
  8. 4 bar one 3 one 6
  9. 5 bar one 3 two 7
  10. In [192]: pd.merge(left,right,on=key1,suffixes=(_left,_right))
  11. Out[192]:
  12. key1 key2_left lval key2_right rval
  13. 0 foo one 1 one 4
  14. 1 foo one 1 one 5
  15. 2 foo two 2 one 4
  16. 3 foo two 2 one 5
  17. 4 bar one 3 one 6
  18. 5 bar one 3 two 7

merge函數的參數

參數說明left參與合併的左側DataFrameright參與合併的右側DataFramehowinner、outer、left、right其中之一。默認為inneron用於連接的列名。必須存在於左右兩個DataFrame中。如果未指定,且其他連接鍵也未指定,則以left和right列名的交集作為連接鍵left_on左側DataFrame中用作連接鍵的列right_on右側DataFrame中用作連接鍵的列left_index將左側的行索引用作器連接鍵right_index類似於 left_inexsort根據連接鍵對合併後的數據進行排序,默認為Truesuffixes字元串值元組,用於追加到重疊列名的末尾,默認為(x,y)copy設置為False,可以在某些特殊情況下避免將數據複製到結果數據結構中。默認總是複製。

索引上的合併

DataFrame的連接鍵也可能位於其索引中。在這種情況下,你可以傳入left_index=True或 right_index=True(或兩個都傳)以說明索引應該被用作連接鍵:

  1. In [7]: left1 = pd.DataFrame({key:[a,b,a,a,b,c],
  2. ...: value:range(6)})
  3. In [8]: right1 = pd.DataFrame({group_val:[3.5,7]},index=[a,b])
  4. In [9]: left1
  5. Out[9]:
  6. key value
  7. 0 a 0
  8. 1 b 1
  9. 2 a 2
  10. 3 a 3
  11. 4 b 4
  12. 5 c 5
  13. In [10]: right1
  14. Out[10]:
  15. group_val
  16. a 3.5
  17. b 7.0
  18. In [11]: pd.merge(left1,right1,left_on=key,right_index=True)
  19. Out[11]:
  20. key value group_val
  21. 0 a 0 3.5
  22. 2 a 2 3.5
  23. 3 a 3 3.5
  24. 1 b 1 7.0
  25. 4 b 4 7.0

由於merge方法默認的是求連接鍵的交集,也可以通過外連接的方式得到它們的並集:

  1. In [12]: pd.merge(left1,right1,left_on=key,right_index=True,how="outer")
  2. Out[12]:
  3. key value group_val
  4. 0 a 0 3.5
  5. 2 a 2 3.5
  6. 3 a 3 3.5
  7. 1 b 1 7.0
  8. 4 b 4 7.0
  9. 5 c 5 NaN

對於層次化索引的數據,就更複雜點:

  1. In [13]: lefth = pd.DataFrame({key1:[Ohio,Ohio,Ohio,Nevada,Nevada],
  2. ...: key2:[2000,2001,2002,2001,2002],
  3. ...: data:np.arange(5)})
  4. In [14]: righth = pd.DataFrame(np.arange(12).reshape(6,2),index=[[Neveda,Nevada,Ohio,Ohio,Ohio,Ohio],[2001,2000,2000,2000,2001,2002]],columns=[event1,event2])
  5. In [15]: lefth
  6. Out[15]:
  7. data key1 key2
  8. 0 0 Ohio 2000
  9. 1 1 Ohio 2001
  10. 2 2 Ohio 2002
  11. 3 3 Nevada 2001
  12. 4 4 Nevada 2002
  13. In [16]: righth
  14. Out[16]:
  15. event1 event2
  16. Neveda 2001 0 1
  17. Nevada 2000 2 3
  18. Ohio 2000 4 5
  19. 2000 6 7
  20. 2001 8 9
  21. 2002 10 11

這種情況下,必須以列表的形式指明用作合併鍵的多個列(注意對重複索引值的處理):

  1. In [17]: pd.merge(lefth,righth,left_on=[key1,key2],right_index=True)
  2. Out[17]:
  3. data key1 key2 event1 event2
  4. 0 0 Ohio 2000 4 5
  5. 0 0 Ohio 2000 6 7
  6. 1 1 Ohio 2001 8 9
  7. 2 2 Ohio 2002 10 11
  8. In [18]: pd.merge(lefth,righth,left_on=[key1,key2],right_index=True,how="outer")
  9. Out[18]:
  10. data key1 key2 event1 event2
  11. 0 0.0 Ohio 2000 4.0 5.0
  12. 0 0.0 Ohio 2000 6.0 7.0
  13. 1 1.0 Ohio 2001 8.0 9.0
  14. 2 2.0 Ohio 2002 10.0 11.0
  15. 3 3.0 Nevada 2001 NaN NaN
  16. 4 4.0 Nevada 2002 NaN NaN
  17. 4 NaN Neveda 2001 0.0 1.0
  18. 4 NaN Nevada 2000 2.0 3.0

同時使用合併雙方的索引也沒問題:

  1. In [19]: left2 = pd.DataFrame([[1,2],[3,4],[5,6]],index=[a,c,e],
  2. ...: columns=[Ohio,Nevada])
  3. In [20]: right2 = pd.DataFrame([[7,8],[9,10],[11,12],[13,14]],index=[b,c,d,e],columns=[Missouri,Alabama])
  4. In [21]: left2
  5. Out[21]:
  6. Ohio Nevada
  7. a 1 2
  8. c 3 4
  9. e 5 6
  10. In [22]: right2
  11. Out[22]:
  12. Missouri Alabama
  13. b 7 8
  14. c 9 10
  15. d 11 12
  16. e 13 14
  17. In [23]: pd.merge(left2,right2,left_index=True,right_index=True,how="outer")
  18. Out[23]:
  19. Ohio Nevada Missouri Alabama
  20. a 1.0 2.0 NaN NaN
  21. b NaN NaN 7.0 8.0
  22. c 3.0 4.0 9.0 10.0
  23. d NaN NaN 11.0 12.0
  24. e 5.0 6.0 13.0 14.0

DataFrame還有一個join實例方法,它能更為方便地實現按索引合併。它還可用於合併多個帶有相同或相似索引地DataFrame對象,而不管它們之間地沒有重疊的列。在上面的例子,我們可以編寫:

  1. In [24]: left2.join(right2,how="outer")
  2. Out[24]:
  3. Ohio Nevada Missouri Alabama
  4. a 1.0 2.0 NaN NaN
  5. b NaN NaN 7.0 8.0
  6. c 3.0 4.0 9.0 10.0
  7. d NaN NaN 11.0 12.0
  8. e 5.0 6.0 13.0 14.0

DataFrame的join方法是在連接鍵上做左連接。它還支持參數DataFrame的索引跟調用者DataFrame的某個列之間的連接:

  1. In [26]: left1.join(right1,on="key")
  2. Out[26]:
  3. key value group_val
  4. 0 a 0 3.5
  5. 1 b 1 7.0
  6. 2 a 2 3.5
  7. 3 a 3 3.5
  8. 4 b 4 7.0
  9. 5 c 5 NaN

最後,對於簡單的索引合併,你還可以向join傳入一組DataFrame(後面我們會介紹更為通用的concat函數,它也能實現此功能):

  1. In [27]: another = pd.DataFrame([[7,8],[9,10],[11,12],[16,17]],
  2. ...: index=[a,c,e,f],columns=[New York,Oregon])
  3. In [28]: left2.join([right2,another])
  4. Out[28]:
  5. Ohio Nevada Missouri Alabama New York Oregon
  6. a 1 2 NaN NaN 7 8
  7. c 3 4 9.0 10.0 9 10
  8. e 5 6 13.0 14.0 11 12
  9. In [29]: left2.join([right2,another],how=outer)
  10. Out[29]:
  11. Ohio Nevada Missouri Alabama New York Oregon
  12. a 1.0 2.0 NaN NaN 7.0 8.0
  13. b NaN NaN 7.0 8.0 NaN NaN
  14. c 3.0 4.0 9.0 10.0 9.0 10.0
  15. d NaN NaN 11.0 12.0 NaN NaN
  16. e 5.0 6.0 13.0 14.0 11.0 12.0
  17. f NaN NaN NaN NaN 16.0 17.0

軸向連接

另一種數據合併運算也被稱作連接(concatenation)、綁定(binding)或堆疊(stacking)。NumPy有一個用於合併原始NumPy數組的concatenation函數:

  1. In [33]: arr = np.arange(12).reshape(3,4)
  2. In [34]: arr
  3. Out[34]:
  4. array([[ 0, 1, 2, 3],
  5. [ 4, 5, 6, 7],
  6. [ 8, 9, 10, 11]])
  7. In [35]: np.concatenate([arr,arr],axis=1)
  8. Out[35]:
  9. array([[ 0, 1, 2, 3, 0, 1, 2, 3],
  10. [ 4, 5, 6, 7, 4, 5, 6, 7],
  11. [ 8, 9, 10, 11, 8, 9, 10, 11]])

對於pandas對象(如Series和DataFrame),帶有標籤的軸使你能夠進一步推廣數組的連接運算。具體點說,你還需要考慮以下這些東西:

  • 如果各對象其他軸上的索引不同,那些軸應該是做並集還是交集?
  • 結果對象中的分組需要各不相同嗎?
  • 用於連接的軸重要嗎?

pandas的concat函數提供了一種能夠解決這些問題的可靠方式。假設有三個沒有重疊索引的Series:

  1. In [36]: s1 = pd.Series([0,1],index=[a,b])
  2. In [37]: s2 = pd.Series([2,3,4],index=[c,d,e])
  3. In [38]: s3 = pd.Series([5,6],index=[f,g])
  4. In [39]: pd.concat([s1,s2,s3])
  5. Out[39]:
  6. a 0
  7. b 1
  8. c 2
  9. d 3
  10. e 4
  11. f 5
  12. g 6
  13. dtype: int64

默認情況下,concat是在axis=0上工作的,最終產生一個新的Series。如果傳入axis=1,則結果就會變成DataFrame(axis=1是列):

  1. In [40]: pd.concat([s1,s2,s3],axis=1)
  2. Out[40]:
  3. 0 1 2
  4. a 0.0 NaN NaN
  5. b 1.0 NaN NaN
  6. c NaN 2.0 NaN
  7. d NaN 3.0 NaN
  8. e NaN 4.0 NaN
  9. f NaN NaN 5.0
  10. g NaN NaN 6.0

這種情況下,另外一條軸上沒有重疊,從索引的有序並集(外連接)上就可以看出來。傳入join=inner即可得到它們的交集:

  1. In [47]: s4 = pd.concat([s1*5,s3])
  2. In [48]: pd.concat([s1,s4],axis=1)
  3. Out[48]:
  4. 0 1
  5. a 0.0 0
  6. b 1.0 5
  7. f NaN 5
  8. g NaN 6
  9. In [50]: pd.concat([s1,s4],axis=1,join=inner)
  10. Out[50]:
  11. 0 1
  12. a 0 0
  13. b 1 5

可以通過join_axes指定要在其他軸上使用的索引:

  1. In [51]: pd.concat([s1,s4],axis=1,join_axes=[[a,c,b,e]])
  2. Out[51]:
  3. 0 1
  4. a 0.0 0.0
  5. c NaN NaN
  6. b 1.0 5.0
  7. e NaN NaN

不過有個問題,參與連接的片段在結果中區分不開。假設你想要在連接軸上創建一個層次化索引。使用keys參數即可達到這個目的:

  1. In [52]: result = pd.concat([s1,s1,s3],keys=[one,two,three])
  2. In [53]: result
  3. Out[53]:
  4. one a 0
  5. b 1
  6. two a 0
  7. b 1
  8. three f 5
  9. g 6
  10. dtype: int64
  11. result.unstack()
  12. Out[54]:
  13. a b f g
  14. one 0.0 1.0 NaN NaN
  15. two 0.0 1.0 NaN NaN
  16. three NaN NaN 5.0 6.0

如果沿著axis=1對Series進行合併,則keys就會成為DataFrame的列頭:

  1. In [60]: pd.concat([s1,s2,s3],axis=1,keys=[one,two,three])
  2. Out[60]:
  3. one two three
  4. a 0.0 NaN NaN
  5. b 1.0 NaN NaN
  6. c NaN 2.0 NaN
  7. d NaN 3.0 NaN
  8. e NaN 4.0 NaN
  9. f NaN NaN 5.0
  10. g NaN NaN 6.0

同樣的邏輯對DataFrame對象也是一樣:

  1. In [61]: df1 = pd.DataFrame(np.arange(6).reshape(3,2),index=[a,b,c],
  2. ...: columns=[one,two])
  3. In [62]: df2 = pd.DataFrame(5+np.arange(4).reshape(2,2),index=[a,c],columns=[three,four])
  4. In [63]: pd.concat([df1,df2],axis=1,keys=[level1,level2])
  5. Out[63]:
  6. level1 level2
  7. one two three four
  8. a 0 1 5.0 6.0
  9. b 2 3 NaN NaN
  10. c 4 5 7.0 8.0

最後一個需要考慮的問題是,和當前分析工作無關的DataFrame行索引:

  1. In [69]: df1 = pd.DataFrame(np.random.randn(3,4),columns=[a,b,c,d])
  2. In [70]: df2 = pd.DataFrame(np.random.randn(2,3),columns=[b,d,a])
  3. In [71]: df1
  4. Out[71]:
  5. a b c d
  6. 0 2.240595 -0.978214 -2.582510 1.166495
  7. 1 -1.069589 1.448100 -0.511939 -0.047077
  8. 2 0.744933 1.829291 0.782055 -1.012039
  9. In [72]: df2
  10. Out[72]:
  11. b d a
  12. 0 -1.259407 -1.117981 1.036470
  13. 1 2.338679 -0.140818 -0.167361
  14. In [73]: pd.concat([df1,df2],ignore_index=True)
  15. Out[73]:
  16. a b c d
  17. 0 2.240595 -0.978214 -2.582510 1.166495
  18. 1 -1.069589 1.448100 -0.511939 -0.047077
  19. 2 0.744933 1.829291 0.782055 -1.012039
  20. 3 1.036470 -1.259407 NaN -1.117981
  21. 4 -0.167361 2.338679 NaN -0.140818
  22. In [74]: pd.concat([df1,df2])
  23. Out[74]:
  24. a b c d
  25. 0 2.240595 -0.978214 -2.582510 1.166495
  26. 1 -1.069589 1.448100 -0.511939 -0.047077
  27. 2 0.744933 1.829291 0.782055 -1.012039
  28. 0 1.036470 -1.259407 NaN -1.117981
  29. 1 -0.167361 2.338679 NaN -0.140818

concat函數的參數

參數說明objs參與連接的pandas對象的列表或字典。唯一必需的參數axis指明連接的軸向,默認為0joininner、outer其中之一,默認為outerjoin_axes指明用於其他n-1條軸的索引,不執行並集/交集運算keys與連接對象有關的值,用於形成連接軸向上的層次化索引。可以是任意值的列表或數組、元組數組、數組列表levels指定用作層次化索引各級別上的索引,如果設置了keys的話names用於創建分層級別的名稱,如果設置了keys和(或)levels的話verify_integrity檢查結果對象新軸上的重複情況,如果發現則引發異常。默認False允許重複ignore_index不保留連接軸上的索引,產生一組新索引range(total_length)

合併重疊數據

還有一種數據組合問題不能用簡單的合併(merge)或連接(concatenation)運算來處理。比如說,你可能有索引全部或部分重疊的兩個數據集。給這個例子增加一點啟發性,我們使用NumPy的where函數,它用於表達一種矢量化的if-else:

  1. In [75]: a = pd.Series([np.nan,2.5,np.nan,3.5,4.5,np.nan],
  2. ...: index=[f,e,d,c,b,a])
  3. In [76]: b = pd.Series(np.arange(len(a),dtype=np.float64),index=[f,e,d,c,b,a])
  4. In [77]: b[-1] = np.nan
  5. In [78]: a
  6. Out[78]:
  7. f NaN
  8. e 2.5
  9. d NaN
  10. c 3.5
  11. b 4.5
  12. a NaN
  13. dtype: float64
  14. In [79]: b
  15. Out[79]:
  16. f 0.0
  17. e 1.0
  18. d 2.0
  19. c 3.0
  20. b 4.0
  21. a NaN
  22. dtype: float64
  23. In [80]: np.where(pd.isnull(a),b,a)
  24. Out[80]: array([ 0. , 2.5, 2. , 3.5, 4.5, nan])

Series有一個combine_first方法,實現的也是一樣的功能,而且會進行數據對齊:

  1. In [83]: b[:-2].combine_first(a[:2])
  2. Out[83]:
  3. c 3.0
  4. d 2.0
  5. e 1.0
  6. f 0.0
  7. dtype: float64

對於DataFrame,combine_first自然也會在列上做同樣的事情,因此可以將其看作:用參數對象中的數據為調用者對象的缺失數據「打補丁」:

  1. In [86]: df1 = pd.DataFrame({a:[1,np.nan,5,np.nan],b:[np.nan,2,np.nan,6],
  2. ...: c:range(2,18,4)})
  3. In [87]: df2 = pd.DataFrame({a:[5,4,np.nan,3,7],
  4. ...: b:[np.nan,3,4,6,8]})
  5. In [88]: df1.combine_first(df2)
  6. Out[88]:
  7. a b c
  8. 0 1.0 NaN 2.0
  9. 1 4.0 2.0 6.0
  10. 2 5.0 4.0 10.0
  11. 3 3.0 6.0 14.0
  12. 4 7.0 8.0 NaN

重塑和軸向轉換

有許多用於重新排列表格型數據的基礎運算。這些函數也稱作重塑(reshape)或軸向旋轉(pivot)運算。

重塑層次化索引

層次化索引為DataFrame數據的重排任務提供了一種具有良好一致性的方式。主要功能有二:

  • stack:將數據的列「旋轉」為行
  • unstack:將數據的行「旋轉」為列

將通過一系列的範例來講解這些操作。

  1. In [92]: data = pd.DataFrame(np.arange(6).reshape(2,3),index=pd.Index([Ohio,Colorado],name=state),columns=pd.Index([one,two,three],name=number))
  2. In [93]: data
  3. Out[93]:
  4. number one two three
  5. state
  6. Ohio 0 1 2
  7. Colorado 3 4 5

使用該數據的stack方法即可將列轉換為行,得到一個Series:

  1. In [94]: result = data.stack()
  2. In [95]: result
  3. Out[95]:
  4. state number
  5. Ohio one 0
  6. two 1
  7. three 2
  8. Colorado one 3
  9. two 4
  10. three 5
  11. dtype: int32

對於一個層次化索引的Series,你可以用unstack將其重排為一個DataFrame:

  1. In [96]: result.unstack()
  2. Out[96]:
  3. number one two three
  4. state
  5. Ohio 0 1 2
  6. Colorado 3 4 5

默認情況下,unstack操作的是最內層(stack也是如此)。傳入分層級別的編號或名稱即可對其他級別進行unstack操作:

  1. In [97]: result.unstack(0)
  2. Out[97]:
  3. state Ohio Colorado
  4. number
  5. one 0 3
  6. two 1 4
  7. three 2 5
  8. In [98]: result.unstack(state)
  9. Out[98]:
  10. state Ohio Colorado
  11. number
  12. one 0 3
  13. two 1 4
  14. three 2 5

如果不是所有的級別值都能在各分組中找到的話,則unstack操作可能會引入缺失數據:

  1. In [99]: s1 = pd.Series([0,1,2,3],index=[a,b,c,d])
  2. In [100]: s2 = pd.Series([4,5,6],index=[c,d,e])
  3. In [101]: data2 = pd.concat([s1,s2],keys=[one,two])
  4. In [102]: data2
  5. Out[102]:
  6. one a 0
  7. b 1
  8. c 2
  9. d 3
  10. two c 4
  11. d 5
  12. e 6
  13. dtype: int64
  14. In [103]: data2.unstack()
  15. Out[103]:
  16. a b c d e
  17. one 0.0 1.0 2.0 3.0 NaN
  18. two NaN NaN 4.0 5.0 6.0

stack默認會濾除缺失數據,因此該運算是可逆的:

  1. In [104]: data2.unstack().stack()
  2. Out[104]:
  3. one a 0.0
  4. b 1.0
  5. c 2.0
  6. d 3.0
  7. two c 4.0
  8. d 5.0
  9. e 6.0
  10. dtype: float64
  11. In [105]: data2.unstack().stack(dropna=False)
  12. Out[105]:
  13. one a 0.0
  14. b 1.0
  15. c 2.0
  16. d 3.0
  17. e NaN
  18. two a NaN
  19. b NaN
  20. c 4.0
  21. d 5.0
  22. e 6.0
  23. dtype: float64

在對DataFrame進行unstack操作時,作為旋轉軸的級別將會成為結果中的最低級別:

  1. In [110]: df.unstack(state)
  2. Out[110]:
  3. side left right
  4. state Ohio Colorado Ohio Colorado
  5. number
  6. one 0 3 5 8
  7. two 1 4 6 9
  8. three 2 5 7 10
  9. In [111]: df.unstack(state).stack(side)
  10. Out[111]:
  11. state Colorado Ohio
  12. number side
  13. one left 3 0
  14. right 8 5
  15. two left 4 1
  16. right 9 6
  17. three left 5 2
  18. right 10 7

pivot函數是一個快捷方式:用set_index創建層次化索引,再用unstack重塑。

數據轉換

移除重複數據

DataFrame中常常會出現重複行。

  1. In [122]: data = pd.DataFrame({k1:[one]*3 + [two]*4,
  2. ...: k2:[1,1,2,3,3,4,4]})
  3. In [123]: data
  4. Out[123]:
  5. k1 k2
  6. 0 one 1
  7. 1 one 1
  8. 2 one 2
  9. 3 two 3
  10. 4 two 3
  11. 5 two 4
  12. 6 two 4
  13. In [124]: data.duplicated()
  14. Out[124]:
  15. 0 False
  16. 1 True
  17. 2 False
  18. 3 False
  19. 4 True
  20. 5 False
  21. 6 True
  22. dtype: bool

DataFrame的duplicated方法返回一個布爾型Series,表示各行是否是重複行。

drop_duplicates方法可以返回一個移除了重複行的DataFrame:

  1. In [125]: data.drop_duplicates()
  2. Out[125]:
  3. k1 k2
  4. 0 one 1
  5. 2 one 2
  6. 3 two 3
  7. 5 two 4

以上的兩個方法會默認判斷全部列,你也可以指定部分列進行重複項判斷。假設你還有一列,且只希望根據k1過濾重複項:

  1. In [128]: data[v1] = range(7)
  2. In [129]: data
  3. Out[129]:
  4. k1 k2 v1
  5. 0 one 1 0
  6. 1 one 1 1
  7. 2 one 2 2
  8. 3 two 3 3
  9. 4 two 3 4
  10. 5 two 4 5
  11. 6 two 4 6
  12. In [130]: data.drop_duplicates([k1])
  13. Out[130]:
  14. k1 k2 v1
  15. 0 one 1 0
  16. 3 two 3 3

duplicated和drop_duplicates默認保留第一個出現的值組合。

利用函數或映射進行數據轉換

在對數據集進行轉換時,你可能希望根據數組、Series或DataFrame列中的值來實現該轉換工作。來看一個例子:

  1. In [133]: data = pd.DataFrame({food:[bacon,pulled pork,bacon,Pastrami,conrned beef,Bacon,pastrami,honey ham,nova lox],
  2. ...: ounces:[4,3,12,6,7.5,8,3,5,6]})
  3. In [134]: data
  4. Out[134]:
  5. food ounces
  6. 0 bacon 4.0
  7. 1 pulled pork 3.0
  8. 2 bacon 12.0
  9. 3 Pastrami 6.0
  10. 4 conrned beef 7.5
  11. 5 Bacon 8.0
  12. 6 pastrami 3.0
  13. 7 honey ham 5.0
  14. 8 nova lox 6.0

假設你想要添加一列表示該肉類食物來源的動物類型。先編寫一個肉類到動物的映射:

  1. In [135]: meat_to_animal = {
  2. ...: bacon:pig,
  3. ...: pulled pork:pig,
  4. ...: pastrami:cow,
  5. ...: corned beef:cow,
  6. ...: honey ham:pig,
  7. ...: nova lox:salmon
  8. ...: }

Series的map方法可以接受一個函數或含有映射關係的字典型對象。

  1. In [136]: data[animal] = data[food].map(str.lower).map(meat_to_animal)
  2. In [137]: data
  3. Out[137]:
  4. food ounces animal
  5. 0 bacon 4.0 pig
  6. 1 pulled pork 3.0 pig
  7. 2 bacon 12.0 pig
  8. 3 Pastrami 6.0 cow
  9. 4 corned beef 7.5 cow
  10. 5 Bacon 8.0 pig
  11. 6 pastrami 3.0 cow
  12. 7 honey ham 5.0 pig
  13. 8 nova lox 6.0 salmon

也可以傳入一個能夠完成全部這些工作的函數:

  1. In [145]: data[food].map(lambda x:meat_to_animal[x.lower()])
  2. Out[145]:
  3. 0 pig
  4. 1 pig
  5. 2 pig
  6. 3 cow
  7. 4 cow
  8. 5 pig
  9. 6 cow
  10. 7 pig
  11. 8 salmon
  12. Name: food, dtype: object

使用 map是一種實現元素級轉換以及其他數據清理工作的便捷方式。

替換值

利用fillna方法填充缺失數據可以看作值替換的一種特殊情況。雖然前面提到的map可用於修改對象的數據子集,而replace則提供了一種實現該功能的更簡單、更靈活的方式。

  1. In [146]: data = pd.Series([1,-999,2,-999,-1000,3])
  2. In [147]: data
  3. Out[147]:
  4. 0 1
  5. 1 -999
  6. 2 2
  7. 3 -999
  8. 4 -1000
  9. 5 3
  10. dtype: int64
  11. In [148]: data.replace(-999,np.nan)
  12. Out[148]:
  13. 0 1.0
  14. 1 NaN
  15. 2 2.0
  16. 3 NaN
  17. 4 -1000.0
  18. 5 3.0
  19. dtype: float64

如果你希望一次性替換多個值,可以傳入一個由待替換值組成的列表以及一個替換值:

  1. In [149]: data.replace([-999,-1000],np.nan)
  2. Out[149]:
  3. 0 1.0
  4. 1 NaN
  5. 2 2.0
  6. 3 NaN
  7. 4 NaN
  8. 5 3.0
  9. dtype: float64

如果你希望對不同的值進行不同的替換,則傳入一個由替換關係組成的列表或字典即可:

  1. In [150]: data.replace([-999,-1000],[np.nan,0])
  2. Out[150]:
  3. 0 1.0
  4. 1 NaN
  5. 2 2.0
  6. 3 NaN
  7. 4 0.0
  8. 5 3.0
  9. dtype: float64
  10. In [151]: data.replace({-999:np.nan,-1000:0})
  11. Out[151]:
  12. 0 1.0
  13. 1 NaN
  14. 2 2.0
  15. 3 NaN
  16. 4 0.0
  17. 5 3.0
  18. dtype: float64

重命名軸索引

和Series中的值一樣,軸標籤也可以通過函數或映射進行轉換,從而得到一個新對象。軸還可以被就地修改,而無需新建一個數據結構。

  1. In [152]: data = pd.DataFrame(np.arange(12).reshape(3,4),index=[Ohio,Colorado,New York],
  2. ...: columns=[one,two,three,four])
  3. In [153]: data
  4. Out[153]:
  5. one two three four
  6. Ohio 0 1 2 3
  7. Colorado 4 5 6 7
  8. New York 8 9 10 11
  9. In [154]: data.index.map(str.upper)
  10. Out[154]: Index([OHIO, COLORADO, NEW YORK], dtype=object)
  11. In [155]: data.index = data.index.map(str.upper)
  12. In [156]: data
  13. Out[156]:
  14. one two three four
  15. OHIO 0 1 2 3
  16. COLORADO 4 5 6 7
  17. NEW YORK 8 9 10 11

如果想要創建數據集的轉換版(而不是修改原始數據),比較實用的方法是rename:

  1. In [157]: data.rename(index=str.title,columns=str.upper)
  2. Out[157]:
  3. ONE TWO THREE FOUR
  4. Ohio 0 1 2 3
  5. Colorado 4 5 6 7
  6. New York 8 9 10 11

rename可以結合字典型對象實現對部分軸標籤的更新:

  1. In [159]: data.rename(index={OHIO:INDIANA},
  2. ...: columns={three:peekaboo})
  3. Out[159]:
  4. one two peekaboo four
  5. INDIANA 0 1 2 3
  6. COLORADO 4 5 6 7
  7. NEW YORK 8 9 10 11

rename幫我們實現了:複製DataFrame並對其索引和列標籤進行賦值。如果希望就地修改某個數據集,傳入inplace=True即可。

離散化和面元劃分

為了便於分析,連續數據常常被離散化或拆分為「面元」(bin)。假設有一組人員數據,而你希望將它們劃分為不同的年齡組:

  1. In [3]: ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]

接下來將這些數據劃分為「18到25」、「26到35」、「35到60」以及「60以上」幾個面元。要實現該功能,你需要使用pandas的cut函數:

  1. In [4]: bins = [18, 25, 35, 60, 100]
  2. In [5]: cats = pd.cut(ages,bins)
  3. In [6]: cats
  4. Out[6]:
  5. [(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
  6. Length: 12
  7. Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]

pandas返回的是一個特殊的Categorical對象。結果展示了pandas.cut劃分的面元。你可以將其看做一組表示面元名稱的字元串。它的底層含有一個表示不同分類名稱的類型數組,以及一個codes屬性中的年齡數據的標籤:

  1. In [9]: cats.codes
  2. Out[9]: array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
  3. In [10]: cats.categories
  4. Out[10]:
  5. IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]]
  6. closed=right,
  7. dtype=interval[int64])
  8. In [11]: pd.value_counts(cats)
  9. Out[11]:
  10. (18, 25] 5
  11. (35, 60] 3
  12. (25, 35] 3
  13. (60, 100] 1
  14. dtype: int64

跟「區間」的數學符號一樣,圓括弧表示開端,而方括弧則表示閉端(包括)。哪邊是閉端可以通過right=False進行修改:

  1. In [12]: pd.cut(ages, [18, 26, 36, 61, 100], right=False)
  2. Out[12]:
  3. [[18, 26), [18, 26), [18, 26), [26, 36), [18, 26), ..., [26, 36), [61, 100), [36, 61), [36, 61), [26, 36)]
  4. Length: 12
  5. Categories (4, interval[int64]): [[18, 26) < [26, 36) < [36, 61) < [61, 100)]

可以通過傳遞一個列表或數組到labels,設置自己的面元名稱:

  1. In [13]: group_names = [Youth, YoungAdult, MiddleAged, Senior]
  2. In [14]: pd.cut(ages, bins, labels=group_names)
  3. Out[14]:
  4. [Youth, Youth, Youth, YoungAdult, Youth, ..., YoungAdult, Senior, MiddleAged, MiddleAged, YoungAdult]
  5. Length: 12
  6. Categories (4, object): [Youth < YoungAdult < MiddleAged < Senior]

如果向cut傳入的是面元的數量而不是確切的面元邊界,則它會根據數據的最小值和最大值計算等長面元。下面這個例子中,我們將一些均勻分布的數據分成四組:

  1. In [19]: data = np.random.rand(20)
  2. # precision=2,限定小數只有兩位
  3. In [20]: pd.cut(data, 4, precision=2)
  4. Out[20]:
  5. [(0.15, 0.36], (0.15, 0.36], (0.36, 0.57], (0.79, 1.0], (0.36, 0.57], ..., (0.57, 0.79], (0.79, 1.0], (0.79, 1.0], (0.57, 0.79], (0.57, 0.79]]
  6. Length: 20
  7. Categories (4, interval[float64]): [(0.15, 0.36] < (0.36, 0.57] < (0.57, 0.79] < (0.79, 1.0]]

qcut是一個非常類似於cut的函數,它可以根據樣本分位數對數據進行面元劃分。根據數據的分布情況,cut可能無法使各個面元中含有相同數量的數據點。而qcut由於使用的是樣本分位數,因此可以得到大小基本相等的面元:

  1. In [21]: data = np.random.randn(1000)
  2. In [22]: cats = pd.qcut(data, 4)
  3. In [23]: cats
  4. Out[23]:
  5. [(0.608, 2.892], (0.608, 2.892], (-2.985, -0.695], (-0.0327, 0.608], (0.608, 2.892], ..., (0.608, 2.892], (-0.0327, 0.608], (-0.0327, 0.608], (-0.695, -0.0327], (0.608, 2.892]]
  6. Length: 1000
  7. Categories (4, interval[float64]): [(-2.985, -0.695] < (-0.695, -0.0327] < (-0.0327, 0.608] < (0.608, 2.892]]
  8. In [24]: pd.value_counts(cats)
  9. Out[24]:
  10. (0.608, 2.892] 250
  11. (-0.0327, 0.608] 250
  12. (-0.695, -0.0327] 250
  13. (-2.985, -0.695] 250
  14. dtype: int64

與cut類似,你也可以傳遞自定義的分位數(0到1之間的數值,包含端點):

  1. In [25]: pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.])
  2. Out[25]:
  3. [(0.147, 0.288], (0.288, 0.694], (0.288, 0.694], (0.694, 0.98], (0.288, 0.694], ..., (0.288, 0.694], (0.694, 0.98], (0.98, 0.998], (0.694, 0.98], (0.288, 0.694]]
  4. Length: 20
  5. Categories (4, interval[float64]): [(0.147, 0.288] < (0.288, 0.694] < (0.694, 0.98] < (0.98, 0.998]]

檢測和過濾異常值

異常值的過濾或變換運算在很大程度上其實就是數組運算。看一個例子:

  1. In [177]: np.random.seed(12345)
  2. In [178]: data = pd.DataFrame(np.random.randn(1000,4))
  3. In [179]: data.describe()
  4. Out[179]:
  5. 0 1 2 3
  6. count 1000.000000 1000.000000 1000.000000 1000.000000
  7. mean -0.067684 0.067924 0.025598 -0.002298
  8. std 0.998035 0.992106 1.006835 0.996794
  9. min -3.428254 -3.548824 -3.184377 -3.745356
  10. 25% -0.774890 -0.591841 -0.641675 -0.644144
  11. 50% -0.116401 0.101143 0.002073 -0.013611
  12. 75% 0.616366 0.780282 0.680391 0.654328
  13. max 3.366626 2.653656 3.260383 3.927528

假設你想找出某列中絕對值大於3的值:

  1. In [181]: col[np.abs(col) > 3]
  2. Out[181]:
  3. 97 3.927528
  4. 305 -3.399312
  5. 400 -3.745356
  6. Name: 3, dtype: float64

要選出全部含有「超過3或-3的值」的行,可以利用布爾型DataFrame以及any方法:

  1. In [184]: data[(np.abs(data)>3).any(1)]
  2. Out[184]:
  3. 0 1 2 3
  4. 5 -0.539741 0.476985 3.248944 -1.021228
  5. 97 -0.774363 0.552936 0.106061 3.927528
  6. 102 -0.655054 -0.565230 3.176873 0.959533
  7. 305 -2.315555 0.457246 -0.025907 -3.399312
  8. 324 0.050188 1.951312 3.260383 0.963301
  9. 400 0.146326 0.508391 -0.196713 -3.745356
  10. 499 -0.293333 -0.242459 -3.056990 1.918403
  11. 523 -3.428254 -0.296336 -0.439938 -0.867165
  12. 586 0.275144 1.179227 -3.184377 1.369891
  13. 808 -0.362528 -3.548824 1.553205 -2.186301
  14. 900 3.366626 -2.372214 0.851010 1.332846

根據這些條件,可以輕鬆地對值進行設置。下面地代碼可以將值限制在區間-3到3以內:

  1. In [190]: data[np.abs(data)>3] = np.sign(data) * 3
  2. In [191]: data.describe()
  3. Out[191]:
  4. 0 1 2 3
  5. count 1000.000000 1000.000000 1000.000000 1000.000000
  6. mean -0.067623 0.068473 0.025153 -0.002081
  7. std 0.995485 0.990253 1.003977 0.989736
  8. min -3.000000 -3.000000 -3.000000 -3.000000
  9. 25% -0.774890 -0.591841 -0.641675 -0.644144
  10. 50% -0.116401 0.101143 0.002073 -0.013611
  11. 75% 0.616366 0.780282 0.680391 0.654328
  12. max 3.000000 2.653656 3.000000 3.000000

排列和隨機採樣

利用numpy.random.permutation函數可以輕鬆實現對Series或DataFrame的列的排列工作。通過需要排列的軸的長度調用permutation,可產生一個表示新順序的整數數組:

  1. In [196]: df = pd.DataFrame(np.arange(5*4).reshape(5,4))
  2. In [197]: sampler = np.random.permutation(5)
  3. In [198]: sampler
  4. Out[198]: array([1, 0, 2, 3, 4])
  5. In [199]: df
  6. Out[199]:
  7. 0 1 2 3
  8. 0 0 1 2 3
  9. 1 4 5 6 7
  10. 2 8 9 10 11
  11. 3 12 13 14 15
  12. 4 16 17 18 19
  13. In [200]: df.take(sampler)
  14. Out[200]:
  15. 0 1 2 3
  16. 1 4 5 6 7
  17. 0 0 1 2 3
  18. 2 8 9 10 11
  19. 3 12 13 14 15
  20. 4 16 17 18 19

要通過替換的方式產生樣本,最快的方式是通過np.random.randint得到一組隨機整數:

  1. In [201]: bag = np.array([5,7,-1,6,4])
  2. In [202]: sampler = np.random.randint(0,len(bag),size=10)
  3. In [203]: sampler
  4. Out[203]: array([2, 4, 4, 4, 4, 2, 2, 2, 0, 3])
  5. In [204]: draws = bag.take(sampler)
  6. In [205]: draws
  7. Out[205]: array([-1, 4, 4, 4, 4, -1, -1, -1, 5, 6])

計算指標/啞變數

另一種常用於統計建模或機器學習的轉換方式是:將分類變數(categorical variable)轉換為「啞變數」或「指標矩陣」。

如果DataFrame的某一列中含有k個不同的值,則可以派生出一個k列矩陣或DataFrame(其值全為1和0)。pandas有一個get_dummies函數可以實現該功能(其實自己動手做一個也不難)。使用之前的一個DataFrame例子:

  1. In [27]: df = pd.DataFrame({key: [b, b, a, c, a, b],data1: range(6)})
  2. In [28]: df
  3. Out[28]:
  4. data1 key
  5. 0 0 b
  6. 1 1 b
  7. 2 2 a
  8. 3 3 c
  9. 4 4 a
  10. 5 5 b
  11. In [29]: pd.get_dummies(df[key])
  12. Out[29]:
  13. a b c
  14. 0 0 1 0
  15. 1 0 1 0
  16. 2 1 0 0
  17. 3 0 0 1
  18. 4 1 0 0
  19. 5 0 1 0

有時候,你可能想給指標DataFrame的列加上一個前綴,以便能夠跟其他數據進行合併。get_dummies的prefix參數可以實現該功能:

  1. In [30]: dummies = pd.get_dummies(df[key], prefix=key)
  2. In [31]: df_with_dummy = df[[data1]].join(dummies)
  3. In [32]: df_with_dummy
  4. Out[32]:
  5. data1 key_a key_b key_c
  6. 0 0 0 1 0
  7. 1 1 0 1 0
  8. 2 2 1 0 0
  9. 3 3 0 0 1
  10. 4 4 1 0 0
  11. 5 5 0 1 0

一個對統計應用有用的秘訣是:結合get_dummies和諸如cut之類的離散化函數:

  1. In [33]: np.random.seed(12345)
  2. In [34]: values = np.random.rand(10)
  3. In [35]: values
  4. Out[35]:
  5. array([ 0.92961609, 0.31637555, 0.18391881, 0.20456028, 0.56772503,
  6. 0.5955447 , 0.96451452, 0.6531771 , 0.74890664, 0.65356987])
  7. In [36]: bins = [0, 0.2, 0.4, 0.6, 0.8, 1]
  8. In [37]: pd.get_dummies(pd.cut(values, bins))
  9. Out[37]:
  10. (0.0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1.0]
  11. 0 0 0 0 0 1
  12. 1 0 1 0 0 0
  13. 2 1 0 0 0 0
  14. 3 0 1 0 0 0
  15. 4 0 0 1 0 0
  16. 5 0 0 1 0 0
  17. 6 0 0 0 0 1
  18. 7 0 0 0 1 0
  19. 8 0 0 0 1 0
  20. 9 0 0 0 1 0

字元串操作

大部分文本運算都直接做成了字元串對象的內置方法。對於更為複雜的模式匹配和文本操作,則可能需要用到正則表達式。。pandas對此進行了加強,它能使你能夠對整組數據應用字元串表達式和正則表達式,而且能處理煩人的缺失數據。

字元串對象方法

Python內置的字元串方法

方法說明count返回字串在字元串中出現的次數(非重疊)endswith、startswith如果字元串以某個後綴結尾(以某個前綴開頭),則返回Truejoin將字元串用作連接其他字元串序列的分隔符index如果在字元串中找到子串,則返回子串第一個字元所在的位置。如果沒有找到,則引發ValuleErrorfind如果在字元串中找到子串,則返回第一個發現的子串的第一個字元所在的位置。如果沒有找到,則返回-1rfind如果在字元串中找到子串,則返回最後一個發現的子串的第一個字元所在的位置。如果沒有找到,則返回-1replace用另一字元串替換指定子串strip、rstrip、lstrip去除空白符(包括換行符)split通過指定的分隔符將字元串拆分為一組子串lower、upper分別將字母字元轉換為小寫或大寫ljust、rjust用空格(或其他字元)填充字元串的空白側以返回符合最低寬度的字元串

正則表達式

正則表達式方法

方法說明findall、finditer返回字元串中所有的非重疊匹配模式,findall返回的是由所有模式組成的列表,而finditer則返回一個迭代器逐個返回match從字元串起始位置匹配模式,還可以對模式各部分進行分組。如果匹配到模式,則返回一個匹配項對象,否則返回Nonesearch掃描整個字元串以匹配模式。如果找到則返回一個匹配項對象。和match不同,其匹配項可以位於字元串的任意位置,而不僅僅是起始處。split根據找到的模式將字元串拆分為數段sub、subn將字元串中所有的(sub)或前n各(subn)模式替換為指定表達式。

pandas中矢量化的字元串函數

通過map函數,所有字元串和正則表達式方法都能被應用於(傳入lambda表達式或其他函數)各個值,但是如果存在NA就會報錯。為了解決這個問題,Series有一些能夠跳過NA值得字元串操作方法。通過Series的str屬性即可訪問這些方法。例如,我們可以通過str.contains檢查各個電子郵件地址是否含有「gmail」:

  1. In [160]: data = {Dava:dave@google.com,Steve:steve@gmail.com,
  2. ...: Rob:rob@gmail.com,Wes:np.nan}
  3. In [161]: data = pd.Series(data)
  4. In [162]: data.str.contains(gmail)
  5. Out[162]:
  6. Dava False
  7. Rob True
  8. Steve True
  9. Wes NaN
  10. dtype: object

也可以使用正則表達式,還可以加上任意re選項(如IGNORECASE):

  1. In [163]: pattern = ([A-Z0-9._%+-]+)@([A-Z0-9.-]+).([A-Z]{2,4})
  2. In [164]: import re
  3. In [165]: data.str.findall(pattern,flags=re.IGNORECASE)
  4. Out[165]:
  5. Dava [(dave, google, com)]
  6. Rob [(rob, gmail, com)]
  7. Steve [(steve, gmail, com)]
  8. Wes NaN
  9. dtype: object

有兩個辦法可以實現矢量化的元素獲取操作:要麼使用str.get,要麼在str屬性上使用索引。

  1. In [171]: matches = data.str.match(pattern,flags=re.IGNORECASE)
  2. In [172]: matches
  3. Out[172]:
  4. Dava True
  5. Rob True
  6. Steve True
  7. Wes NaN
  8. dtype: object
  9. In [173]: matches.str.get(1)
  10. Out[173]:
  11. Dava NaN
  12. Rob NaN
  13. Steve NaN
  14. Wes NaN
  15. dtype: float64
  16. In [176]: data.str[:5]
  17. Out[176]:
  18. Dava dave@
  19. Rob rob@g
  20. Steve steve
  21. Wes NaN
  22. dtype: object

矢量化字元串方法


推薦閱讀:

使用 Python 求解拉普拉斯方程
方勢阱薛定諤方程
Python有哪些可以做帶約束的二次線性規劃的包?
Python科學計算與自動控制1-Python入門
和 C++ 相比,用 Fortran 編程是怎樣的體驗?

TAG:Python | 科学计算 |