在日期上过滤Pandas数据框

345

我有一个Pandas DataFrame,其中有一个“date”列。现在我需要过滤掉DataFrame中所有日期超出未来两个月的行。本质上,我只需要保留在未来两个月内的行。

如何最好地实现这一目标?

16个回答

467
如果日期列是索引,则使用.loc进行基于标签的索引或.iloc进行基于位置的索引。
例如:
df.loc['2014-01-01':'2014-02-01']

详细信息请参见此处

如果列不是索引,则有两种选择:

  1. 将其设置为索引(如果是时间序列数据,则可以是暂时或永久的)
  2. df[(df['date'] > '2013-01-01') & (df['date'] < '2013-02-01')]

有关一般解释,请参见此处

注意:.ix已弃用。


4
谢谢,我会阅读。在我的情况下,日期是一个单独的列而不是索引。我应该在一开始就提供这些信息。我的问题不太具体。 - AMM
80
这里也可以使用querydf.query('20130101 < date < 20130201') - Phillip Cloud
2
与此相同:https://dev59.com/bHHYa4cB1Zd3GeqPN6n9 这也很有用。 - Union find
16
你应该提到在你的示例中,通过 .loc.ix 进行索引过滤和列过滤是不等价的。 df.ix ['2014-01-01':'2014-02-01'] 包括 2014-02-01,而 df [(df ['date']> '2013-01-01')&(df ['date'] <'2013-02-01')] 不包括 2013-02-01,它只匹配到 2013-01-31 的行。 - Rafael Barbosa
7
如果一个人不想按日期范围进行过滤,而是按多个日期时间进行过滤,该怎么办? - Salem
显示剩余8条评论

90

根据我的经验,先前的回答是不正确的,您不能将简单字符串传递给它,需要传递一个日期时间对象。因此:

import datetime 
df.loc[datetime.date(year=2014,month=1,day=1):datetime.date(year=2014,month=2,day=1)]

24
我可以毫无问题地传递一个字符串。 - Ninjakannon
10
ix索引器已被弃用,请使用loc - http://pandas.pydata.org/pandas-docs/stable/indexing.html#ix-indexer-is-deprecated - Nick
6
Pandas将转换任何“datetime”字符串为datetime对象。因此这是正确的。 - janscas
15
使用这个代码时,我收到以下错误提示:TypeError: '<' not supported between instances of 'int' and 'datetime.date'。 - Michael Norman

70

如果您的日期是通过导入datetime包进行标准化的,那么您可以简单地使用:

df[(df['date']>datetime.date(2016,1,1)) & (df['date']<datetime.date(2016,3,1))]  

使用datetime包标准化日期字符串的方法如下:

import datetime
datetime.datetime.strptime

17
建议使用 df[(df['date']>pd.Timestamp(2016,1,1)) & (df['date']<pd.Timestamp(2016,3,1))] 进行筛选。 - So S

53

如果你已经使用pd.to_datetime将字符串转换为日期格式,那么你可以直接使用:

df = df[(df['Date'] > "2018-01-01") & (df['Date'] < "2019-07-01")]

该代码的作用是从名为df的数据框中选择符合日期在“2018-01-01”和“2019-07-01”之间的记录。


37

按日期筛选数据框的最短方法: 假设您的日期列是datetime64[ns]类型

# filter by single day
df_filtered = df[df['date'].dt.strftime('%Y-%m-%d') == '2014-01-01']

# filter by single month
df_filtered = df[df['date'].dt.strftime('%Y-%m') == '2014-01']

# filter by single year
df_filtered = df[df['date'].dt.strftime('%Y') == '2014']

对于大量数据框来说,“short”虽然短小,但因为需要将每个日期转换为字符串,所以速度较慢。 - fantabolous

33

如果你的 Pandas datetime 列是 datetime64[ns] 类型,为了进行正确的过滤,你需要使用 pd.Timestamp 对象,例如:

from datetime import date

import pandas as pd

value_to_check = pd.Timestamp(date.today().year, 1, 1)
filter_mask = df['date_column'] < value_to_check
filtered_df = df[filter_mask]

26
如果日期在索引中,那么只需:
df['20160101':'20160301']

编辑:虽然简短,但这种风格现在已经被弃用(至少在pandas 1.5.3中),推荐的风格是df.loc['20160101':'20160301'](如其他答案所示)。


20

您可以使用pd.Timestamp对查询和本地引用进行操作。

import pandas as pd
import numpy as np

df = pd.DataFrame()
ts = pd.Timestamp

df['date'] = np.array(np.arange(10) + datetime.now().timestamp(), dtype='M8[s]')

print(df)
print(df.query('date > @ts("20190515T071320")')

输出结果

                 date
0 2019-05-15 07:13:16
1 2019-05-15 07:13:17
2 2019-05-15 07:13:18
3 2019-05-15 07:13:19
4 2019-05-15 07:13:20
5 2019-05-15 07:13:21
6 2019-05-15 07:13:22
7 2019-05-15 07:13:23
8 2019-05-15 07:13:24
9 2019-05-15 07:13:25


                 date
5 2019-05-15 07:13:21
6 2019-05-15 07:13:22
7 2019-05-15 07:13:23
8 2019-05-15 07:13:24
9 2019-05-15 07:13:25

请查看Pandas文档中关于DataFrame.query的部分,具体涉及使用@前缀引用本地变量。在这种情况下,我们使用本地别名ts引用pd.Timestamp,以便能够提供时间戳字符串。


你能提供一下 @ts 函数的文档链接吗? - Glen Moutrie
1
这里可能不需要使用 pd.TimeStampdf.query('date > 20190515071320') 看起来可以正常工作。 - ChaimG
是的,@ChaimG 它运行得很好!不需要使用 pd.TimeStamp。Pandas query() 非常灵活:接受整数 df.query('date > 20190515071320') 或字符串 df.query('date > "20190515071320"')。如果您想要易于阅读的方式:df.query('date > "2019-05-15 07:13:20"') - A.Sommerh
带有 "T" 的吗?好的:............................................................ df.query('date > "20190515T071320"') df.query('date > "2022-11-06 T 20:32:00"') - A.Sommerh
只需要日期而不需要时间部分?没问题: df.query('date > "20190515"') df.query('date > "2019-05-15"') df.query('date > 20190515')

即使是日期整数,也不要将其与带有日期+时间的整数混淆。足够智能!

- A.Sommerh

13

我目前不能写评论,所以我会写一个回答,如果有人能够读完所有的回答并看到这一个。

如果数据集的索引是日期时间,而你想要根据月份来进行筛选,你可以按照以下方式操作:

df.loc[df.index.month == 3]

那将会在三月份为你过滤数据集。


2
我认为有一个小错误,应该是 df.loc[df.index.month == 3] - Alberto
迄今为止最佳答案。如果您的列是一个Series,它可能会抛出一个错误,那么您可以尝试使用df.loc[df.ColumnName.dt.month == 3] - Faraz Zaidi

11

因此,在加载csv数据文件时,我们需要将日期列现在设置为索引,如下所示,以便根据日期范围过滤数据。现在废弃的方法pd.DataFrame.from_csv()不再需要这样做。

如果您只想显示2020年1月至2月的两个月数据,例如2020-01-01到2020-02-29,可以这样做:

import pandas as pd
mydata = pd.read_csv('mydata.csv',index_col='date') # or its index number, e.g. index_col=[0]
mydata['2020-01-01':'2020-02-29'] # will pull all the columns
#if just need one column, e.g. Cost, can be done:
mydata['2020-01-01':'2020-02-29','Cost'] 

这已经在Python 3.7上进行了测试并且可行。希望您会发现它有用。


1
index_col has to be a string not a list. mydata = pd.read_csv('mydata.csv',index_col='date') - ANUBIS

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