2017-07-06 99 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