pandas 字符串相關操作以及數據間的合並與重塑


一、字符串操作

Python內置的字符串操作和re正則模塊可以解決很多場景下的字符串操作需求。但是在數據分析過程中,它們有時候比較尷尬,比如:

In [143]: dic= {'one':'feixue', 'two':np.nan, 'three':'tom', 'five':'jerry@film'} In [144]: s = pd.Series(dic) In [145]: s Out[145]: one feixue two NaN three tom five jerry@film dtype: object

現在想將s中的字母都大寫,通過Python內置字符串方法,可能會這么設計:

In [159]: s.map(lambda x : x.upper()) --------------------------------------------------------------------------- AttributeError Traceback (most recent call last)

但是,彈出了異常,原因是數據有一個缺失值NaN,這個值不是字符串,沒有upper方法。

那怎么辦呢?Pandas為這一類整體性的操作,提供了專門的字符串函數,跳過缺失值等異常情況,對能夠進行操作的每個元素進行處理:

In [160]: s.str.upper() Out[160]: one FEIXUE two NaN three TOM five JERRY@FILM dtype: object

這就是Series的str屬性,在它的基礎上甚至可以使用正則表達式的函數。

下面是部分可用的Series.str的字符串操作方法,名字基本和Python字符串內置方法相同:

  • cat :粘合字符串
  • contains:是否包含的判斷
  • count:計數
  • extract:返回匹配的字符串組
  • endswith:以xx結尾判斷
  • startswith:以xx開始判斷
  • findall:查找
  • get:獲取
  • isalnum:類型判斷
  • isalpha:類型判斷
  • isdecimal:類型判斷
  • isdigit:類型判斷
  • islower:是否小寫
  • isnumeric:類型判斷
  • isupper:是否大寫
  • join:連接
  • len:長度
  • lower:小寫
  • upper:大寫
  • match:匹配
  • pad:將空白加到字符串的左邊、右邊或者兩邊
  • center:居中
  • repeat:重復
  • replace:替換
  • slice:切片
  • split:分割
  • strip:脫除
  • lstrip:左脫除
  • rstrip:右脫除

二、合並連接

可以通過多種方式將Pandas對象聯合到一起:

  • pandas.merge: 根據一個或多個鍵進行連接。類似SQL的連接操作
  • pandas.concat:使對象在軸向上進行粘合或者‘堆疊’
  • combine_first:將重疊的數據拼接在一起,使用一個對象中的值填充另一個對象中的缺失值

1.merge連接

merge方法將兩個pandas對象連接在一起,類似SQL的連接操作。默認情況下,它執行的是內連接,也就是兩個對象的交集。通過參數how,還可以指定外連接、左連接和右連接。參數on指定在哪個鍵上連接,參數left_onright_on分別指定左右對象的連接鍵。

  • 外連接:並集
  • 內連接:交集
  • 左連接:左邊對象全部保留
  • 右連接:右邊對象全部保留
In [23]: df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], ...: 'data1': range(7)}) ...: In [24]: df2 = pd.DataFrame({'key': ['a', 'b', 'd'], ...: 'data2': range(3)}) ...: In [25]: df1 Out[25]: key data1 0 b 0 1   b      1
2   a      2
3   c      3
4   a      4
5   a      5
6   b      6 In [26]: df2 Out[26]: key data2 0 a 0 1   b      1
2   d      2 In [27]: pd.merge(df1,df2) # 默認內鏈接,並智能地查找連接的鍵
Out[27]: key data1 data2 0 b 0 1
1   b      1      1
2   b      6      1
3   a      2 0 4   a      4 0 5   a      5 0 In [28]: pd.merge(df1,df2,on='key') # 最好是顯式地指定連接的鍵
Out[28]: key data1 data2 0 b 0 1
1   b      1      1
2   b      6      1
3   a      2 0 4   a      4 0 5   a      5 0 In [30]: pd.merge(df1, df2, how='outer') # 外連接
Out[30]: key data1 data2 0 b 0.0    1.0
1   b    1.0    1.0
2   b    6.0    1.0
3   a    2.0    0.0
4   a    4.0    0.0
5   a    5.0    0.0
6   c    3.0 NaN 7   d    NaN    2.0 In [31]: pd.merge(df1, df2, how='left')  # 左連接
Out[31]: key data1 data2 0 b 0 1.0
1   b      1    1.0
2   a      2    0.0
3   c      3 NaN 4   a      4    0.0
5   a      5    0.0
6   b      6    1.0 In [32]: pd.merge(df1, df2, how='right') #右連接
Out[32]: key data1 data2 0 b 0.0      1
1   b    1.0      1
2   b    6.0      1
3   a    2.0 0 4   a    4.0 0 5   a    5.0 0 6   d    NaN      2 In [33]: df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], ...: 'data1': range(7)}) ...: In [34]: df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'], ...: 'data2': range(3)}) ...: In [35]: pd.merge(df3, df4, left_on='lkey', right_on='rkey') # 指定兩邊的鍵
Out[35]: lkey data1 rkey data2 0 b 0 b 1
1    b      1    b      1
2    b      6    b      1
3    a      2 a 0 4    a      4 a 0 5    a      5    a      0

多對多的merge連接是行的笛卡兒積。比如左邊如果有3個‘b’行,右邊有2個‘b’行,那么結果是3x2,6個‘b’行。

也可以同時指定多個鍵進行連接:

In [36]: left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], ...: 'key2': ['one', 'two', 'one'], ...: 'lval': [1, 2, 3]}) In [37]: right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], ...: 'key2': ['one', 'one', 'one', 'two'], ...: 'rval': [4, 5, 6, 7]}) In [38]: pd.merge(left, right, on=['key1', 'key2'], how='outer') Out[38]: key1 key2 lval rval 0 foo one 1.0   4.0
1  foo  one   1.0   5.0
2  foo  two   2.0 NaN 3  bar  one   3.0   6.0
4  bar  two   NaN   7.0

merge操作中還有一個重疊列名的問題,比如上面的left和right兩個數據,為此,我們可以使用suffixes參數,手動指定為重復的列名添加后綴:

In [41]: pd.merge(left, right, on='key1') Out[41]: key1 key2_x lval key2_y rval 0 foo one 1    one     4
1  foo    one     1    one     5
2  foo    two     2    one     4
3  foo    two     2    one     5
4  bar    one     3    one     6
5  bar    one     3    two     7 In [42]: pd.merge(left, right, on='key1', suffixes=('_left', '_right')) Out[42]: key1 key2_left lval key2_right rval 0 foo one 1        one     4
1  foo       one     1        one     5
2  foo       two     2        one     4
3  foo       two     2        one     5
4  bar       one     3        one     6
5  bar       one     3        two     7

有時候,用於merge合並的鍵可能是某個對象的行索引:

In [43]: left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], ...: 'value': range(6)}) ...: In [44]: right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b']) In [45]: left1 Out[45]: key value 0 a 0 1   b      1
2   a      2
3   a      3
4   b      4
5   c      5 In [46]: right1 Out[46]: group_val a 3.5 b 7.0 In [47]: pd.merge(left1, right1, left_on='key', right_index=True) Out[47]: key value group_val 0 a 0 3.5
2   a      2        3.5
3   a      3        3.5
1   b      1        7.0
4   b      4        7.0 In [48]: pd.merge(left1, right1, left_on='key', right_index=True, how='outer') Out[48]: key value group_val 0 a 0 3.5
2   a      2        3.5
3   a      3        3.5
1   b      1        7.0
4   b      4        7.0
5   c      5        NaN

使用right_index=True參數顯式地指出,右邊的對象right1使用它的行索引作為連接的鍵。

事實上Pandas有一個join方法,可以幫助我們直接用行索引進行連接:

In [49]: left2 = pd.DataFrame([[1., 2.], [3., 4.], [5., 6.]], ...: index=['a', 'c', 'e'], ...: columns=['Ohio', 'Nevada']) ...: In [50]: right2 = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]], ...: index=['b', 'c', 'd', 'e'], ...: columns=['Missouri', 'Alabama']) ...: In [51]: left2 Out[51]: Ohio Nevada a 1.0     2.0 c 3.0     4.0 e 5.0     6.0 In [52]: right2 Out[52]: Missouri Alabama b 7.0      8.0 c 9.0     10.0 d 11.0     12.0 e 13.0     14.0 In [53]: pd.merge(left2, right2, how='outer', left_index=True, right_index=True) Out[53]: Ohio Nevada Missouri Alabama a 1.0     2.0 NaN NaN b NaN NaN 7.0      8.0 c 3.0     4.0       9.0     10.0 d NaN NaN 11.0     12.0 e 5.0     6.0      13.0     14.0 In [54]: left2.join(right2, how='outer') # 與上面的操作效果一樣
Out[54]: Ohio Nevada Missouri Alabama a 1.0     2.0 NaN NaN b NaN NaN 7.0      8.0 c 3.0     4.0       9.0     10.0 d NaN NaN 11.0     12.0 e 5.0     6.0      13.0     14.0

2.concat軸向連接

concat方法可以實現對象在軸向的的粘合或者堆疊。

In [55]: s1 = pd.Series([0, 1], index=['a', 'b']) In [56]: s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e']) In [57]: s3 = pd.Series([5, 6], index=['f', 'g']) In [58]: pd.concat([s1, s2, s3]) # 要以列表的方式提供參數
Out[58]: a 0 b 1 c 2 d 3 e 4 f 5 g 6 dtype: int64 In [59]: pd.concat([s1, s2, s3], axis=1) # 橫向堆疊,但出現警告信息
C:\ProgramData\Anaconda3\Scripts\ipython:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version of pandas will change to not sort by default. ...... Out[59]: 0 1    2 a 0.0 NaN NaN b 1.0 NaN NaN c NaN 2.0 NaN d NaN 3.0 NaN e NaN 4.0 NaN f NaN NaN 5.0 g NaN NaN 6.0 In [60]: pd.concat([s1, s2, s3], axis=1,sort=True) # 按人家的要求做
Out[60]: 0 1    2 a 0.0 NaN NaN b 1.0 NaN NaN c NaN 2.0 NaN d NaN 3.0 NaN e NaN 4.0 NaN f NaN NaN 5.0 g NaN NaN 6.0

對於DataFrame,默認情況下都是按行往下合並的,當然也可以設置axis參數:

In [66]: df1 = pd.DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'], ...: columns=['one', 'two']) ...: In [67]: df2 = pd.DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'], ...: columns=['three', 'four']) ...: In [68]: df1 Out[68]: one two a 0 1 b 2    3 c 4    5 In [69]: df2 Out[69]: three four a 5     6 c 7     8 In [71]: pd.concat([df1, df2], sort=True) Out[71]: four one three two a NaN 0.0    NaN  1.0 b NaN 2.0    NaN  3.0 c NaN 4.0    NaN  5.0 a 6.0  NaN    5.0 NaN c 8.0  NaN    7.0 NaN In [72]: pd.concat([df1, df2], axis=1, sort=True) Out[72]: one two three four a 0 1    5.0   6.0 b 2    3 NaN NaN c 4    5    7.0   8.0

3.combine_first聯合疊加

有這么種場景,某個對象里缺失的值,拿另外一個對象的相應位置的值來填補。在Numpy層面,可以這么做:

In [74]: a = pd.Series([np.nan, 2.5, 0, 3.5, 4.5, np.nan], ...: index=['f', 'e', 'd', 'c', 'b', 'a']) In [75]: b = pd.Series([0, np.nan, 2.1, np.nan, np.nan, 5], index=list('abcdef')) In [76]: a Out[76]: f NaN e 2.5 d 0.0 c 3.5 b 4.5 a NaN dtype: float64 In [77]: b Out[77]: a 0.0 b NaN c 2.1 d NaN e NaN f 5.0 dtype: float64 In [78]: np.where(pd.isnull(a), b, a) Out[78]: array([0. , 2.5, 0. , 3.5, 4.5, 5. ])

np.where(pd.isnull(a), b, a),這一句里,首先去pd.isnull(a)種判斷元素,如果是True,從b里拿數據,否則從a里拿,得到最終結果。

實際上,Pandas為這種場景提供了一個專門的combine_first方法:

In [80]: b.combine_first(a) Out[80]: a 0.0 b 4.5 c 2.1 d 0.0 e 2.5 f 5.0 dtype: float64

對於DataFrame對象,combine_first逐列做相同的操作,因此你可以認為它是根據你傳入的對象來‘修補’調用對象的缺失值。

In [81]: df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan], ...: 'b': [np.nan, 2., np.nan, 6.], ...: 'c': range(2, 18, 4)}) ...: In [82]: df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.], ...: 'b': [np.nan, 3., 4., 6., 8.]}) ...: In [83]: df1 Out[83]: a b c 0 1.0  NaN   2
1  NaN  2.0   6
2  5.0  NaN  10
3  NaN  6.0  14 In [84]: df2 Out[84]: a b 0 5.0 NaN 1  4.0  3.0
2  NaN  4.0
3  3.0  6.0
4  7.0  8.0 In [85]: df1.combine_first(df2) Out[85]: a b c 0 1.0  NaN   2.0
1  4.0  2.0   6.0
2  5.0  4.0  10.0
3  3.0  6.0  14.0
4  7.0  8.0   NaN

三、重塑

對表格型數據進行重新排列的操作,被稱作重塑。

使用多層索引進行重塑主要有stack和unstack操作,前面有介紹過。

In [93]: df = pd.DataFrame(np.arange(6).reshape(2,3), ...: index=pd.Index(['河南','山西'], name='省份'), ...: columns=pd.Index(['one','two','three'],name='number')) In [94]: df Out[94]: number one two three 省份 河南 0 1      2 山西 3    4      5 In [95]: result = df.stack() In [96]: result Out[96]: 省份 number 河南 one 0 two 1 three 2 山西 one 3 two 4 three 5 dtype: int32 In [97]: result.unstack() Out[97]: number one two three 省份 河南 0 1      2 山西 3    4      5

stack操作使得df的所有列都變成了分層行索引,產生了一個新的Series。

unstack默認情況下拆分最內層索引,然后將數據放入一個DataFrame中。可以傳入一個層級序號或名稱來拆分不同的層級。

In [98]: result.unstack(0) Out[98]: 省份 河南 山西 number one 0 3 two 1   4 three 2   5 In [99]: result.unstack('省份') Out[99]: 省份 河南 山西 number one 0 3 two 1   4 three 2   5

如果層級中的所有值並未有包含於每個子分組中,拆分可能會導致缺失值的產生:

In [100]: s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) In [101]: s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) In [102]: data2 = pd.concat([s1, s2], keys=['one', 'two']) In [103]: data2  # 注意concat的結果是一個分層索引
Out[103]: one a 0 b 1 c 2 d 3 two c 4 d 5 e 6 dtype: int64 In [104]: data2.unstack() Out[104]: a b c d e one 0.0  1.0  2.0  3.0 NaN two NaN NaN 4.0  5.0  6.0 In [105]: data2.unstack().stack() # 結果是可逆的
Out[105]: one a 0.0 b 1.0 c 2.0 d 3.0 two c 4.0 d 5.0 e 6.0 dtype: float64 In [106]: data2.unstack().stack(dropna=False) # 保留缺失值
Out[106]: one a 0.0 b 1.0 c 2.0 d 3.0 e NaN two a NaN b NaN c 4.0 d 5.0 e 6.0 dtype: float64

而在DataFrame對象拆堆時,被拆的層級會變成結果中最低的層級:

In [107]: df = pd.DataFrame({'left': result, 'right': result + 5}, ...: columns=pd.Index(['left', 'right'], name='side')) ...: In [108]: df Out[108]: side left right 省份 number 河南 one 0 5 two 1      6 three 2      7 山西 one 3      8 two 4      9 three 5     10 In [109]: df.unstack('省份') # 因為作死引入了中文,所以版式不太對齊
Out[109]: side left right 省份 河南 山西 河南 山西 number one 0 3     5   8 two 1  4     6   9 three 2  5     7  10


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM