pandas與numpy中的字符串處理
問題解答
上次留了一個小問題,不知道大家想清楚了沒有?
其實np.apply_along_axis實現(xiàn)的也是軸上的操作,對軸上的值統(tǒng)一用函數(shù)進行處理,然后返回值。
import numpy as np
array = np.array([['hello world','sssimon yang']])
np.apply_along_axis(lambda a:[i.split(' ')[0] for i in a],axis=0,arr=array)
out:
array([['hello', 'sssim']], dtype='<U5')
在這一步中,處理的是第一個軸,第一個軸有1個值,剩下的還有一個軸,維度為2,所以處理了兩次。
應該記住,每次指定的axis都是可能要發(fā)生改變的軸,指定的軸有1個值,所以送入函數(shù)的有1個值,剩下的維度就是送入的次數(shù)。
所以函數(shù)每次拿到的是長度為1的一個list,print一下也可以看出來。
np.apply_along_axis(lambda a:print(a),axis=0,arr=array)
['hello world']
['sssimon yang']
out:
array([None, None], dtype=object)
用下面的例子會看的更容易些。
data = np.arange(0, 24).reshape((2,3,4))
np.apply_along_axis(lambda a:print(a),axis=1,arr=data)
[0 4 8]
[1 5 9]
[ 2 6 10]
[ 3 7 11]
[12 16 20]
[13 17 21]
[14 18 22]
[15 19 23]
out:
array([[None, None, None, None],
[None, None, None, None]], dtype=object)
處理的是第二個軸,每次送入三個值,剩下的維度為2X4,所以送入8次,這8次的每三個值都是依次遍歷第一層1,2和最后一層1,2,3,4提取組成的。最后再組成一個2X4的ndarray。
data = np.arange(0, 24).reshape((2,3,4))
np.apply_along_axis(lambda a:np.mean(a),axis=1,arr=data)
out:
array([[ 4., 5., 6., 7.],
[16., 17., 18., 19.]])
回到之前。
np.apply_along_axis(lambda a:[i.split(' ')[0] for i in a],axis=1,arr=array)
out:
array([['hello', 'sssimon']], dtype='<U7')
axis=1時,顯然送入函數(shù)的就是一個長度為2的list,送入了一次。
那么問題就出在處理的次數(shù)上。
在axis=0的時候,兩個字符串是分兩次處理的,在第一次返回['hello']的時候,因為函數(shù)只返回一個值,所以numpy從中提取'hello'并由此獲知返回的數(shù)據(jù)類型為<U5,<是小端存儲的意思,U表明該字符串為unicode字符,5表明長度為5,而我們知道numpy中所有的數(shù)據(jù)類型都是一致的。所以當?shù)诙畏祷?code>['sssimon']的時候,numpy也拿到了'sssimon'并存儲了,但是由于numpy在輸出的時候是根據(jù)數(shù)據(jù)類型進行輸出的,類型為<U5,所以只輸出了5個字符。
而axis=1的時候,返回的是列表['hello', 'sssimon'],numpy自動根據(jù)列表里最長的字符串進行類型推斷,為<U7,也就不會出現(xiàn)輸出時的截斷操作。 這就是造成兩者差異的原因,其實從給出的dtype中也可以看出來一些線索。
字符串處理
pandas和numpy中都有字符串處理的模塊,pandas在pd.Series.str模塊里,而numpy在np.char模塊里。
data = pd.DataFrame({'name':['sssimon yang','edward wang'],'age':[18,22]})
pd.Series.str是直接可以用切片操作的。
data.name.str[-4:]
out:
0 yang
1 wang
Name: name, dtype: object
str模塊實現(xiàn)了例如endswith,startswith,len,strip等基礎(chǔ)字符串的常用函數(shù)。
當然我比較常用的就是replace,里面還可以用正則表達式。
data.name.str.replace('.ang','zhang')
out:
0 sssimon zhang
1 edward zhang
Name: name, dtype: object
我們可以用內(nèi)置的split完成類似之前的拆分。
data.name.str.split()
out:
0 [sssimon, yang]
1 [edward, yang]
Name: name, dtype: object
拆分后返回的是list,dtype為object,我們可以借用str的切片操作來提取一下第一個值。
data.name.str.split().str[0]
out:
0 sssimon
1 edward
Name: name, dtype: object
成功了!
當然其實用apply函數(shù)更簡單直觀一點。
data.name.apply(lambda x:x.split()[0])
out:
0 sssimon
1 edward
Name: name, dtype: object
pandas中字符串處理只在series中可用,而numpy沒有這個限制,因為numpy內(nèi)部存儲的全都是同一種類型。
np.char模塊也實現(xiàn)了常用的lower,strip,replace,decode,encode,add等函數(shù),其本質(zhì)上都是對單元素或者多元素調(diào)用函數(shù),函數(shù)比較少,感覺不如pandas中的字符串處理靈活性大。
最后
字符串處理在數(shù)據(jù)分析中常用于數(shù)據(jù)清洗過程,例如在分析轉(zhuǎn)專業(yè)數(shù)據(jù)時,我拿到的pdf識別后的excel并沒有那么整潔,會出現(xiàn)下面這種情況。

這種情況看似比較棘手,但是用正則就很容易。
data.loc['當前學院'] = data['當前學院'].str.replace('學$','學院')
你,學會了嗎?