pandas字符串操作

1、字符串對象方法

對於大部分字符串處理應用而言,內置的字符串方法已經能夠滿足要求了。

(1)split       以逗號分隔的字符串可以用split拆分成數段

val = 'a,b,guido'
val.split(',')
Out[3]: ['a', 'b', 'guido']

(2)strip     split結合strip(用於修剪空白符(包括換行符))一起使用:

pieces = [x.strip() for x in val.split(',')]
pieces
Out[5]: ['a', 'b', 'guido']

(3)加法     連接子字符串

first + '//'+second+'//'+third
Out[8]: 'a//b//guido'

向字符串“//”的join方法傳入一個列表或元組:

'::'.join(pieces)
Out[9]: 'a::b::guido'

(4)子串定位      檢測子串的最佳方式是利用Python的in關鍵字,也可以使用index和find

val.index(',')
Out[11]: 1

val.find(',')
Out[12]: 1

val.find(':')
Out[13]: -1

注意:find和index的區別:如果找不到字符串,index將會引發一個異常(而不是返回-1)

(5)count函數      返回指定子串的出現次數

val.count(',')
Out[15]: 2

(6)replace        用於將指定模式替換爲另一個模式,也常常用於刪除模式:傳入空字符串

val.replace(',','::')
Out[16]: 'a::b::guido'

val.replace(',','')
Out[17]: 'abguido'
Python內置的字符串方法
                方法                                     說明
count 返回子串在字符串中的出現次數(非重疊)
endswith、startswith 如果字符串以某個後綴結尾(以某個前綴開頭),則返回True
join 將字符串用作連接其他字符串序列的分隔符
index 如果在字符串中找到子串,則返回子串第一個字符所在的位置。如果沒有找到,則引發ValueError
find 如果在字符串中找到子串,則返回第一個發現的子串的第一個字符所在的位置。如果沒有找到,則返回-1
rfind 如果在字符串中找到子串,則返回最後一個發現的子串的第一個字符所在的位置。如果沒有找到,則返回-1
replace 用另一個字符串替換指定子串
strip、rstrip、lstrip 去除空白符(包括換行符),相當於對各個元素執行x.strip()(以及rstrip、lstrip)
split 通過指定的分隔符將字符串拆分爲一組子串
lower、upper 分別將字母字符轉換爲大寫或小寫
ljust、rjust 用空格(或其他字符)填充字符串的空白側以返回符合最低寬度的字符串

2、正則表達式

re模塊的函數可以分爲三個大類:模式匹配、替換以及拆分。

一個regex描述了需要在文本中定位的一個模式,假設我想要拆分一個字符串,分隔符爲數量不定的一組空白符(製表符、空格、換行符),描述一個或多個空白符的regex是\s+:

調用re.split('\s+',text)時,正則表達式會先被編譯,然後再在text上調用其split方法。可以用re.compile自己編譯regex以得到一個可重用的regex對象:如果打算對許多字符串應用同一條正則表達式,強烈建議通過re.compile創建regex對象。

regex = re.compile('\s+')
regex.split(text)

①如果只希望得到匹配regex的所有模式,則可以使用findall方法:

regex.findall(text)
Out[22]: [' ', '\t ', ' \t']

注意:如果想避免正則表達式中不需要的轉義(\),則可以使用原始字符串字面量如r'C:\x'(也可以編寫其等價式'C:\\x')

②match和search跟findall功能類似

findall返回的是字符串中所有的匹配項,而search則只返回第一個匹配項。match更加嚴格,只匹配字符串的首部。

例子:假設有一段文本以及一條能夠識別大部分電子郵件地址的正則表達式。

import re
text="""Dave [email protected]
Steve [email protected]
Rob [email protected]
Ryan [email protected]
"""
pattern = r'[A-Z0-9.-]+@[A-Z0=9.-]+\.[A-Z]{2,4}'
regex = re.compile(pattern,flags=re.IGNORECASE)#re.IGNORECASE的作用是使正則表達式對大小寫不敏感
regex.findall(text)#對text使用findall將得到一組電子郵件地址
Out[32]: ['[email protected]', '[email protected]', '[email protected]', '[email protected]']

search返回的是文本中第一個電子郵件地址(以特殊的匹配項對象形式返回),對於上面那個regex,匹配項對象只能告訴我們模式在原字符串中的起始和結束位置:

m = regex.search(text)
m
Out[34]: <_sre.SRE_Match object; span=(5, 20), match='[email protected]'>

text[m.start():m.end()]
Out[35]: '[email protected]'

regex.match則將返回None,因爲它只匹配出現在字符串開頭的模式:

print(regex.match(text))
None

另外還有一個sub方法,它會將匹配到的模式替換爲指定字符串,並返回所得到的新字符串:

print(regex.sub('REDACTED',text))
Dave REDACTED
Steve REDACTED
Rob REDACTED
Ryan REDACTED

假設不僅找出電子郵件地址,還想將各個地址分爲3個部分:用戶名、域名以及域後綴。要想實現此功能,只需將待分段的模式的各部分用括號包起來即可:

pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9._]+)\.([A-Z]{2,4})'
regex = re.compile(pattern,flags=re.IGNORECASE)

由這種正則表達式所產生的匹配項對象,可以通過其groups方法返回一個由模式各段組成的元組:

m = regex.match('[email protected]')
m.groups()
Out[5]: ('wesm', 'bright', 'net')

對於帶有分組功能的模式,findall會返回一個元組列表:

regex.findall(text)
Out[6]: 
[('dave', 'google', 'com'),
 ('steve', 'gmail', 'com'),
 ('rob', 'gmail', 'com'),
 ('ryan', 'yahoo', 'com')]

sub還能通過諸如\1、\2之類的特殊符號訪問各匹配項中的分組:

print(regex.sub(r'Username:\1,Domain:\2,Suffix:\3',text))
Dave Username:dave,Domain:google,Suffix:com
Steve Username:steve,Domain:gmail,Suffix:com
Rob Username:rob,Domain:gmail,Suffix:com
Ryan Username:ryan,Domain:yahoo,Suffix:com

由這種正則表達式所產生的匹配項對象可以得到一個簡單易用的帶有分組名稱的字典:

m = regex.match('[email protected]')
m.groupdict()
Out[10]: {'username': 'wesm', 'domain': 'bright', 'suffix': 'net'}
正則表達式方法
方法 說明
findall、finditer 返回字符串中所有的非重疊匹配模式。findall返回的是由所有模式組成的列表,而finditer則通過一個迭代器逐個返回
match 從字符串起始位置匹配模式,還可以對模式各部分進行分組。如果匹配到模式,則返回一個匹配項對象,否則返回None
search 掃描整個字符串以匹配模式。如果找到則返回一個匹配項對象。跟match不同,其匹配項可以位於字符串的任意位置,而不僅僅是起始處
split 根據找到的模式將字符串拆分爲數段
sub、subn 將字符串中所有的(sub)或前n個(subn)模式替換爲指定表達式。在替換字符串中可以通過\1、\2的符號表示各項分組項

3、pandas中矢量化的字符串函數

清理待分析的散亂數據時,常常需要做一些字符串規整化工作。更爲複雜的情況是,含有字符串的列有時還含有缺失數據:

data = {'Dave':'[email protected]','Steve':'[email protected]','Rob':'[email protected]','Wes':np.nan}
data = pd.Series(data)
data
Out[20]: 
Dave     [email protected]
Steve    [email protected]
Rob        [email protected]
Wes                  NaN
dtype: object

data.isnull()
Out[21]: 
Dave     False
Steve    False
Rob      False
Wes       True
dtype: bool

(1)Series中有一些能夠跳過NA值得字符串操作方法

通過Series的str屬性即可訪問這些方法。例如通過str.contains檢查各個電子郵件地址是否含有“gmail”:

data.str.contains('gmail')
Out[23]: 
Dave     False
Steve     True
Rob       True
Wes        NaN
dtype: object

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

pattern
Out[24]: '([A-Z0-9._%+-]+)@([A-Z0-9._]+)\\.([A-Z]{2,4})'

data.str.findall(pattern,flags=re.IGNORECASE)
Out[25]: 
Dave     [(dave, google, com)]
Steve    [(steve, gmail, com)]
Rob        [(rob, gmail, com)]
Wes                        NaN
dtype: object

(2)實現矢量化的元素獲取操作

①str.get    ②在str屬性上使用索引

矢量化的字符串方法
方法 說明
cat 實現元素級的字符串連接操作,可指定分隔符
contains 返回表示各字符串是否含有指定模式的布爾型數組
count 模式的出現次數
endswith、startswith 相當於對各個元素執行w.endswith(pattern)或x.startswith(pattern)
findall 計算各字符串的模式列表
get 獲取各元素的第i個字符
join 根據指定的分隔符將Series中各元素的字符串連接起來
len 計算各字符串的長度
lower、upper 轉換大小寫。相當於對各個元素執行x.lower()或x.upper()
match 根據指定的正則表達式對各個元素執行re.match
pad 在字符串的左邊、右邊或左右兩邊添加空白符
center 相當於pad(side='both')
repeat 重複值。例如,s.str.repeat(3)相當於對各個字符串執行x*3
replace 用指定字符串替換找到的模式
slice 對Series中的各個字符串進行子串截取
split 根據分隔符或正則表達式對字符串進行拆分
strip、rstrip、lstrip 去除空白符,包括換行符。相當於對各個元素執行x.strip()、x.rstrip()、x.lstrip()

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章