如何在pandas过滤函数中反转正则表达式

16

我有以下的Pandas数据框df(实际上只是一个更大数据框的最后几行):

df如下:

                           count
gene                            
WBGene00236788                56
WBGene00236807                 3
WBGene00249816                12
WBGene00249825                20
WBGene00255543                 6
__no_feature            11697881
__ambiguous                 1353
__too_low_aQual                0
__not_aligned                  0
__alignment_not_unique         0

我可以使用filterregex选项,仅获取以两个下划线开头的行:

df.filter(regex="^__", axis=0)

这将返回以下内容:

                           count
gene                            
__no_feature            11697881
__ambiguous                 1353
__too_low_aQual                0
__not_aligned                  0
__alignment_not_unique         0

实际上,我想要的是它的补集:只有不以两个下划线开头的行。

我可以用另一个正则表达式来做:df.filter(regex="^[^_][^_]", axis=0)

有没有更简单的方法来指定我想要最初正则表达式的反义?

基于这样的正则表达式的过滤效率高吗?

编辑:测试一些提出的解决方案

df.filter(regex="(?!^__)", axis=0)df.filter(regex="^\w+", axis=0)都返回所有行。

根据re模块文档,\w特殊字符实际上包括下划线,这解释了第二个表达式的行为。

我猜第一个方案不工作是因为(?!...)应用于后面的模式。在这里,"^"应该放在外面,就像下面提出的解决方案一样:

df.filter(regex="^(?!__).*?$", axis=0)有效。

使用df.filter(regex="^(?!__)", axis=0)也有效。


1
(?!^__) might be what you're looking for. Or, maybe even better: ^\w+ - Jan
你可以从带有下划线的数据框中获取索引,并将它们从原始数据框中排除。"新"索引可以像这样收集:[idx for idx in original_df.index if idx not in underscore_df.index] - blacksite
这个有太多的零匹配。更好的方式是:^(?!__).*?$ - Robin Koch
@RobinKoch:这里不需要使用懒惰的点星号,而且它非常耗费资源。 - Jan
1
(?!^__) 选择所有行,因为它匹配每个空字符串,该空字符串不是以换行符和两个下划线开头。所以基本上就是所有内容。 - Robin Koch
显示剩余3条评论
4个回答

16

我遇到了同样的问题,但我想要筛选列。所以我使用的是axis=1,但概念应该是相似的。

df.drop(df.filter(regex='my_expression').columns,axis=1)

7

匹配不以两个下划线开头的所有行:

^(?!__)

^ 匹配行的开头, (?!__) 确保该行(紧接着前面的 ^)不以两个下划线开头。

编辑: 删除了 .*?$ ,因为过滤行不需要它。


1
懒惰的点星非常昂贵,在这里不需要。 - Jan
1
^(?!__) 同样可行,避免了可能的昂贵的星号。 - bli
好的,我考虑匹配行而不是过滤。 - Robin Koch
有人能解释一下为什么这里需要分组括号吗? - Jazz Weisman
1
@JazzWeisman 它们属于“负向先行断言”。基本上 (?!pattern) 允许查找不跟随 pattern 的匹配项。如果省略括号,则表达式的含义完全不同:^?!__ 将匹配任何 !__(可能包括行的开头,但由于它是零宽度字符,所以没有区别)。 - Robin Koch

1
你有两种可能性:
(?!^__) # a negative lookahead
        # making sure that there are no underscores right at the beginning of the line

或者:

^\w+  # match word characters, aka a-z, A-Z, 0-9 at least once

奇怪的是,这两个都不起作用:所有行都被选中了。 - bli
我想我明白了为什么:请看我问题末尾的编辑。 - bli

0

反选多列(A、B、C)。

df.filter(regex=r'^(?!(A_|B_.*_|C_.*_.*_))',axis='columns')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接