如何通过正则表达式过滤熊猫行

我想在其中一列上使用正则表达式干净地过滤数据框架。

举个例子:

In [210]: foo = pd.DataFrame({'a' : [1,2,3,4], 'b' : ['hi', 'foo', 'fat', 'cat']})
In [211]: foo
Out[211]:
a    b
0  1   hi
1  2  foo
2  3  fat
3  4  cat

我想使用正则表达式将行过滤为以f开头的行。第一:

In [213]: foo.b.str.match('f.*')
Out[213]:
0    []
1    ()
2    ()
3    []

这不是很有用。然而,这将得到我的布尔索引:

In [226]: foo.b.str.match('(f.*)').str.len() > 0
Out[226]:
0    False
1     True
2     True
3    False
Name: b

所以我可以通过以下方式进行限制:

In [229]: foo[foo.b.str.match('(f.*)').str.len() > 0]
Out[229]:
a    b
1  2  foo
2  3  fat

这让我人为地把一个组放入正则表达式中,这似乎不是一个干净的方法。还有更好的办法吗?

258350 次浏览

使用包含代替:

In [10]: df.b.str.contains('^f')
Out[10]:
0    False
1     True
2     True
3    False
Name: b, dtype: bool

使用dataframe进行多列搜索:

frame[frame.filename.str.match('*.'+MetaData+'.*') & frame.file_path.str.match('C:\test\test.txt')]

这可能有点晚,但现在在Pandas中通过调用Series.str.match更容易做到这一点。文档解释了matchfullmatchcontains之间的区别。

注意,为了将结果用于索引,请设置na=False参数(如果想在结果中包含nan,则设置True参数)。

已经有一个字符串处理函数Series.str.startswith()。 你应该试试foo[foo.b.str.startswith('f')]。< / p >

结果:

    a   b
1   2   foo
2   3   fat

我想你所期望的。

或者,您可以使用包含正则表达式选项。例如:

foo[foo.b.str.contains('oo', regex= True, na=False)]

结果:

    a   b
1   2   foo

na=False用于防止在nan, null等值的情况下出现错误

编写一个布尔函数检查正则表达式,并在列上使用apply

foo[foo['b'].apply(regex_function)]

通过user3136169构建伟大的答案,下面是一个示例,说明如何同时删除NoneType值。

def regex_filter(val):
if val:
mo = re.search(regex,val)
if mo:
return True
else:
return False
else:
return False


df_filtered = df[df['col'].apply(regex_filter)]

你也可以添加regex作为参数:

def regex_filter(val,myregex):
...


df_filtered = df[df['col'].apply(regex_filter,regex=myregex)]

使用str切片

foo[foo.b.str[0]=='f']
Out[18]:
a    b
1  2  foo
2  3  fat

使用Python内置的编写lambda表达式的能力,我们可以通过任意的正则表达式操作进行过滤,如下所示:

import re


# with foo being our pd dataframe
foo[foo['b'].apply(lambda x: True if re.search('^f', x) else False)]

通过使用re.search,你可以通过复杂的正则表达式风格的查询进行过滤,在我看来,这是更强大的。(因为str.contains相当有限)

同样重要的是:你想要你的字符串开始带一个小的'f'。通过使用正则表达式f.*,您可以在文本中的任意位置匹配f。通过使用^符号,可以显式地声明希望它位于内容的开头。所以使用^f可能是一个更好的主意:)

你可以将querycontains结合使用:

foo.query('b.str.contains("^f").values')

或者你也可以使用startswith:

foo.query('b.str.startswith("f").values')

然而,我更喜欢第一种选择,因为它允许你使用|操作符搜索多个模式。