2017-07-06 133 views
4

選擇數據我有這樣使用正則表達式

import pandas as pd 

df = pd.DataFrame({'a': ['abc', 'r00001', 'r00010', 'rfoo', 'r', 'r1234'], 'b': range(6)}) 

     a b 
0  abc 0 
1 r00001 1 
2 r00010 2 
3 rfoo 3 
4 r
5 r1234 5 

我現在要選擇該數據幀,其中在列a啓動項與r其次是五個數字的所有列的數據幀。

From here我學會了一會怎麼做,如果它開始只是r沒有數字:

print df.loc[df['a'].str.startswith('r'), :] 

     a b 
1 r00001 1 
2 r00010 2 
3 rfoo 3 
4 r
5 r1234 5 

像這樣的事情

print df.loc[df['a'].str.startswith(r'[r]\d{5}'), :] 

做當然不行的。如何正確地做到這一點?

回答

5

選項1
pd.Series.str.match

df.a.str.match('^r\d{5}$') 

1  True 
2  True 
3 False 
4  True 
5 False 
Name: a, dtype: bool 

使用它作爲一個過濾器

df[df.a.str.match('^r\d{5}$')] 

     a b 
1 r00001 1 
2 r00010 2 
4 r

選項2
自定義列表理解使用字符串方法

f = lambda s: s.startswith('r') and (len(s) == 6) and s[1:].isdigit() 
[f(s) for s in df.a.values.tolist()] 

[False, True, True, False, True, False] 

使用它作爲一個過濾器

df[[f(s) for s in df.a.values.tolist()]] 

     a b 
1 r00001 1 
2 r00010 2 
4 r

定時

df = pd.concat([df] * 10000, ignore_index=True) 

%timeit df[[s.startswith('r') and (len(s) == 6) and s[1:].isdigit() for s in df.a.values.tolist()]] 
%timeit df[df.a.str.match('^r\d{5}$')] 
%timeit df[df.a.str.contains('^r\d{5}$')] 

10 loops, best of 3: 22.8 ms per loop 
10 loops, best of 3: 33.8 ms per loop 
10 loops, best of 3: 34.8 ms per loop 
+0

這樣的作品,upvoted。 – Cleb

+2

由於'str.match'正在使用're.match',因此模式可以更改爲''r \ d {5}'',因爲它默認匹配從字符串的開始處 – EdChum

+0

不是原始文章的一部分,但現在如何排除超過5個數字(或任何其他字符)的數字? – Cleb

5

您可以使用str.contains並傳遞一個正則表達式模式:

In[112]: 
df.loc[df['a'].str.contains(r'^r\d{5}')] 

Out[112]: 
     a b 
1 r00001 1 
2 r00010 2 
4 r

這裏的模式計算結​​果爲^r - 開始與r字符,然後\d{5}尋找5位

startswith尋找一個字符圖案,而不是一個正則表達式這就是爲什麼它失敗

關於str.containsstr.match之間的差異,它們是類似的,但str.contains使用re.search,而str.match使用re.match,這是更嚴格的,請參閱docs

編輯

爲了回答您的評論添加$,使其字符的具體數量匹配,請參閱related

In[117]: 
df = pd.DataFrame({'a': ['abc', 'r000010', 'r00010', 'rfoo', 'r', 'r1234'], 'b': range(6)}) 
df 

Out[117]: 
     a b 
0  abc 0 
1 r000010 1 
2 r00010 2 
3  rfoo 3 
4 r
5 r1234 5 


In[118]: 
df.loc[df['a'].str.match(r'r\d{5}$')] 

Out[118]: 
     a b 
2 r00010 2 
4 r
+0

這有效,upvoted。 – Cleb

+0

不是原始文章的一部分,但現在如何排除那些具有超過5個數字(或任何其他字符)的文章? – Cleb

+1

'r'^ r \ d {5} $'應該處理這個問題 – EdChum