【问题标题】:How to filter rows in pandas by regex如何通过正则表达式过滤熊猫中的行
【发布时间】:2013-02-25 20:07:16
【问题描述】:

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

举一个人为的例子:

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

这让我人为地将一个组放入正则表达式中,似乎可能不是干净的方法。有没有更好的方法来做到这一点?

【问题讨论】:

  • 如果你不喜欢正则表达式,foo[foo.b.str.startswith("f")] 可以工作。
  • 恕我直言,我认为foo[foo.b.str.match('(f.*)').str.len() > 0] 是一个相当不错的解决方案!比startswith更可定制和更有用,因为它包含了正则表达式的多功能性。
  • 这可能有点晚,但在新版本的 pandas 中,问题已得到解决。 foo[foo.b.str.match('f.*')] 行适用于我的 pandas 0.24.2。

标签: python regex pandas


【解决方案1】:

改用contains

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

【讨论】:

  • 布尔值如何反转?找到它:stackoverflow.com/questions/15998188/…
  • 是否可以只获取那些具有 True 的行?
  • @shockwave 你应该使用:df.loc[df.b.str.contains('^f'), :]
  • @shockwave 你也可以使用df[df.b.str.contains('^f'), :]
【解决方案2】:

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

结果:

    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等值时的Errors

【讨论】:

  • 我对此进行了修改,它对我有用df[~df.CITY.str.contains('~.*', regex= True, na=False)]
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    使用数据框进行多列搜索:

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

    【讨论】:

    • frame?和'C:\test\test.txt'?好像你在回答一个不同的问题。
    • 帧是 df。它与同一个问题有关,但它回答了如何在一行代码中过滤多个列(“文件名”和“文件路径”)。
    【解决方案5】:

    user3136169the great answer 为基础,下面是一个示例,说明如何同时删除 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)]
    

    您还可以将正则表达式添加为 arg:

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

    【讨论】:

    • 谢谢,因此我想出了一种通过任意谓词过滤列的方法。
    【解决方案6】:

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

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

    【讨论】:

      【解决方案7】:

      使用str切片

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

      【讨论】:

        【解决方案8】:

        使用 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 可能是一个更好的主意:)

        【讨论】:

          猜你喜欢
          • 2017-07-13
          • 2017-06-18
          • 2018-09-06
          • 2019-07-18
          • 2016-01-15
          • 2017-04-25
          • 2018-01-11
          • 2021-08-09
          • 2021-06-11
          相关资源
          最近更新 更多