使用正则表达式过滤熊猫

Posted

技术标签:

【中文标题】使用正则表达式过滤熊猫【英文标题】:Filtering in pandas using regex expression 【发布时间】:2017-06-18 19:46:07 【问题描述】:

我正在使用 pandas 和 python 在 excel 中做一些工作。我有这样的东西。

  ID         Actual Date
738564     01/21/2016
274628     02/12/2016
571749     03/30/2016
718563     10/01/2016
984739     11/30/2016
938511     12/24/2016
103216     07/16/2014
446754     08/06/2015
135654     02/01/2017
135614     01/16/2017
133346     01/16/2011
234682        N/A
238756       (none)

所以我需要按日期过滤,但我只需要过滤 2016 年 11 月之前的年份日期(所以我需要过滤 2014 年、2015 年以及 2016 年 1 月和 10 月之间)。所以基本上在过滤器之后我会有这样的东西

      ID       Actual Date
   738564   01/21/2016
   274628   02/12/2016
   571749   03/30/2016
   718563   10/01/2016
   103216   07/16/2014
   446754   08/06/2015
   133346   01/16/2011
   234682        N/A
   238756       (none)

我使用的代码是:

    regex = r"[0-9]2/[0-9]2/2016"
df = pd.read_csv("Request.csv", keep_default_na=False)
df1 = df.loc[(df["Actual Date"].str.contains(r'[0-9]2/[0-9]2/2016') &
             (df["Actual Date"].str.contains("2015")) & 
             (df["Actual Date"].str.contains("2014")) &
             (df["Actual Date"].str.contains("2011")) &
             (df["Actual Date"].str.contains("(None)")) &
             (df["Actual Date"].str.contains("N/A"))))]                 

但是当我运行代码时,我只收到 2011、2014 和 2015 年。正则表达式不适用于 2016 年的日期。 非常感谢您的帮助,对于英语不好表示抱歉

【问题讨论】:

【参考方案1】:

RegEx 是非常强大的工具,但在这种情况下有更好的方法:

In [180]: df
Out[180]:
        ID  ActualDate
0   738564  01/21/2016
1   274628  02/12/2016
2   571749  03/30/2016
3   718563  10/01/2016
4   984739  11/30/2016
5   938511  12/24/2016
6   103216  07/16/2014
7   446754  08/06/2015
8   135654  02/01/2017
9   135614  01/16/2017
10  133346  01/16/2011
11  234682         NaN
12  238756      (none)

让我们转换它datetime dtype:

In [181]: df['ActualDate'] = pd.to_datetime(df['ActualDate'], errors='coerce')

In [182]: df
Out[182]:
        ID ActualDate
0   738564 2016-01-21
1   274628 2016-02-12
2   571749 2016-03-30
3   718563 2016-10-01
4   984739 2016-11-30
5   938511 2016-12-24
6   103216 2014-07-16
7   446754 2015-08-06
8   135654 2017-02-01
9   135614 2017-01-16
10  133346 2011-01-16
11  234682        NaT
12  238756        NaT

使用boolean indexing进行过滤:

In [184]: df[(df['ActualDate'] < '2016-11-01') | df['ActualDate'].isnull()]
Out[184]:
        ID ActualDate
0   738564 2016-01-21
1   274628 2016-02-12
2   571749 2016-03-30
3   718563 2016-10-01
6   103216 2014-07-16
7   446754 2015-08-06
10  133346 2011-01-16
11  234682        NaT
12  238756        NaT

使用.query()方法过滤:

In [186]: df.query("ActualDate < '2016-11-01' or ActualDate != ActualDate")
Out[186]:
        ID ActualDate
0   738564 2016-01-21
1   274628 2016-02-12
2   571749 2016-03-30
3   718563 2016-10-01
6   103216 2014-07-16
7   446754 2015-08-06
10  133346 2011-01-16
11  234682        NaT
12  238756        NaT

更新:如果您想在字符串 dtype 中保留原始 Date

In [190]: df
Out[190]:
        ID Actual Date
0   738564  01/21/2016
1   274628  02/12/2016
2   571749  03/30/2016
3   718563  10/01/2016
4   984739  11/30/2016
5   938511  12/24/2016
6   103216  07/16/2014
7   446754  08/06/2015
8   135654  02/01/2017
9   135614  01/16/2017
10  133346  01/16/2011
11  234682         NaN
12  238756      (none)

首先添加一个新的datetime 列:

In [191]: df['Date'] = pd.to_datetime(df['Actual Date'], errors='coerce')

In [192]: df
Out[192]:
        ID Actual Date       Date
0   738564  01/21/2016 2016-01-21
1   274628  02/12/2016 2016-02-12
2   571749  03/30/2016 2016-03-30
3   718563  10/01/2016 2016-10-01
4   984739  11/30/2016 2016-11-30
5   938511  12/24/2016 2016-12-24
6   103216  07/16/2014 2014-07-16
7   446754  08/06/2015 2015-08-06
8   135654  02/01/2017 2017-02-01
9   135614  01/16/2017 2017-01-16
10  133346  01/16/2011 2011-01-16
11  234682         NaN        NaT
12  238756      (none)        NaT

过滤:

In [194]: df.drop('Date', 1).loc[(df['Date'] < '2016-11-01') | df['Date'].isnull()]
Out[194]:
        ID Actual Date
0   738564  01/21/2016
1   274628  02/12/2016
2   571749  03/30/2016
3   718563  10/01/2016
6   103216  07/16/2014
7   446754  08/06/2015
10  133346  01/16/2011
11  234682         NaN
12  238756      (none)


In [196]: df.query("Date < '2016-11-01' or Date != Date").drop('Date', 1)
Out[196]:
        ID Actual Date
0   738564  01/21/2016
1   274628  02/12/2016
2   571749  03/30/2016
3   718563  10/01/2016
6   103216  07/16/2014
7   446754  08/06/2015
10  133346  01/16/2011
11  234682         NaN
12  238756      (none)

【讨论】:

好的,我认为最好的办法是将日期转换为日期时间,但是某些命运值是 None 或 NA,我也需要显示这些值。任何选择,因为我认为 datetime 不接受字符串。代码是这样的 @CarlosArronteBello,您是否希望在结果数据集中(过滤后)包含DateNoneNaN 的行? 是的,我需要 None 和 NA 以及 2016 年 10 月之前的所有日期(包括 octuber)。非常感谢你 ok 看起来对我有用,让我试试代码,只是一个简单的问题,返回将是 NaT 或将是 None 和 Na 的字符串,日期格式也可以成为mm/dd/yyyy,抱歉打扰,我基本上是新来的。并感谢您的帮助 如果您希望能够在ActualDate 列上使用矢量化(快速读取)操作,那么您希望将其设为datetime64 dtype。这也意味着您将拥有NaT(不是时间)而不是所有无法转换为日期的值,并且您将拥有默认表示形式(它在屏幕上显示的方式):yyyy-mm-dd .您可以使用任何您想要的格式将其转换为字符串,但是您将失去灵活性并且您将不得不使用字符串...

以上是关于使用正则表达式过滤熊猫的主要内容,如果未能解决你的问题,请参考以下文章

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

如何使用正则表达式或熊猫过滤 NLTK 的 FreqDist 计数器

如何在熊猫过滤器函数中反转正则表达式

如何使用选择性正则表达式在熊猫系列中执行替换?

熊猫使用正则表达式选择列并按值除

使用熊猫根据正则表达式分离列数据