从 SQL 数据库导入表并按日期过滤行时,将 Pandas 列解析为 Datetime

Posted

技术标签:

【中文标题】从 SQL 数据库导入表并按日期过滤行时,将 Pandas 列解析为 Datetime【英文标题】:Parse a Pandas column to Datetime when importing table from SQL database and filtering rows by date 【发布时间】:2013-04-30 23:55:13 【问题描述】:

我有一个DataFrame,其列名为date。我们如何将“日期”列转换/解析为DateTime 对象?

我使用 sql.read_frame() 从 Postgresql 数据库中加载了日期列。 date 列的一个示例是 2013-04-04

我要做的是选择数据框中的所有行,其日期列在特定时期内,例如在2013-04-01 之后和2013-04-04 之前。

我在下面的尝试给出了错误'Series' object has no attribute 'read'

尝试

import dateutil

df['date'] = dateutil.parser.parse(df['date'])

错误

AttributeError                            Traceback (most recent call last)
<ipython-input-636-9b19aa5f989c> in <module>()
     15 
     16 # Parse 'Date' Column to Datetime
---> 17 df['date'] = dateutil.parser.parse(df['date'])
     18 
     19 # SELECT RECENT SALES

C:\Python27\lib\site-packages\dateutil\parser.pyc in parse(timestr, parserinfo, **kwargs)
    695         return parser(parserinfo).parse(timestr, **kwargs)
    696     else:
--> 697         return DEFAULTPARSER.parse(timestr, **kwargs)
    698 
    699 

C:\Python27\lib\site-packages\dateutil\parser.pyc in parse(self, timestr, default, ignoretz, tzinfos, **kwargs)
    299             default = datetime.datetime.now().replace(hour=0, minute=0,
    300                                                       second=0, microsecond=0)
--> 301         res = self._parse(timestr, **kwargs)
    302         if res is None:
    303             raise ValueError, "unknown string format"

C:\Python27\lib\site-packages\dateutil\parser.pyc in _parse(self, timestr, dayfirst, yearfirst, fuzzy)
    347             yearfirst = info.yearfirst
    348         res = self._result()
--> 349         l = _timelex.split(timestr)
    350         try:
    351 

C:\Python27\lib\site-packages\dateutil\parser.pyc in split(cls, s)
    141 
    142     def split(cls, s):
--> 143         return list(cls(s))
    144     split = classmethod(split)
    145 

C:\Python27\lib\site-packages\dateutil\parser.pyc in next(self)
    135 
    136     def next(self):
--> 137         token = self.get_token()
    138         if token is None:
    139             raise StopIteration

C:\Python27\lib\site-packages\dateutil\parser.pyc in get_token(self)
     66                 nextchar = self.charstack.pop(0)
     67             else:
---> 68                 nextchar = self.instream.read(1)
     69                 while nextchar == '\x00':
     70                     nextchar = self.instream.read(1)

AttributeError: 'Series' object has no attribute 'read'

df['date'].apply(dateutil.parser.parse) 给我错误AttributeError: 'datetime.date' object has no attribute 'read'

df['date'].truncate(after='2013/04/01') 给出错误TypeError: can't compare datetime.datetime to long

df['date'].dtype 返回dtype('O')。它已经是datetime 对象了吗?

【问题讨论】:

请在您的date 专栏中发布一些示例!因为 pandas 实际上应该识别一个日期时间对象,所以查看该列的实际格式会很有帮助 @RyanSaxe 我使用 sql.read_frame() 从 Postgresql 数据库中加载了日期列。 date 列的一个示例是 2013-04-04。如何检查列的 dtype? df['date'].dtype 返回dtype('O') 【参考方案1】:

Pandas 知道对象日期时间,但是当您使用某些导入函数时,它会被视为字符串。因此,您需要做的是确保将列设置为日期时间类型而不是字符串。然后,您可以进行查询。

df['date']  = pd.to_datetime(df['date'])
df_masked = df[(df['date'] > datetime.date(2012,4,1)) & (df['date'] < datetime.date(2012,4,4))]

【讨论】:

【参考方案2】:

你可能需要apply,比如:

df['date'] = df['date'].apply(dateutil.parser.parse)

如果没有该专栏的示例,我不能保证这会奏效,但在这个方向上的一些东西应该可以帮助您继续前进。

【讨论】:

谢谢,我试过df['date'].apply(dateutil.parser.parse),它给出了错误。 AttributeError: 'datetime.date' object has no attribute 'read'。该列的一个示例是2013-04-04。整个数据框是使用 sql.readframe() 从 PostgreSQL 数据库加载的。【参考方案3】:

pandas 已经将其读取为 datetime 对象!所以你想要的是选择两个日期之间的行,你可以通过屏蔽来做到这一点:

df_masked = df[(df.date > '2012-04-01') & (df.date < '2012-04-04')]

因为你说你因为某种原因从字符串中得到一个错误,试试这个:

df_masked = df[(df.date > datetime.date(2012,4,1)) & (df.date < datetime.date(2012,4,4))]

【讨论】:

df = df[df.date &gt; '2012-01-01'] 给我一个错误TypeError: can't compare datetime.date to str 我一直用这个!这很奇怪......您的问题与我提出的问题非常相似,我得到了这个答案并且它有效。 See it here 是的..当我手动创建数据框时它可以工作...但是如果我使用sql.read_frame从SQL数据库创建数据框,'2012-01-01'会被视为字符串? 尝试df[df.date &gt; dateutil.parser.parse('2013-01-01') ]给了我TypeError: can't compare datetime.datetime to datetime.date df.date 是类型对象,但我认为 2013-01-01 被视为字符串。当我使用dateutil.parser.parse() 如上面的cmets 时,错误从str 变为datetime.date【参考方案4】:

不要将 datetime.date 与 Pandas pd.Timestamp 混淆

“熊猫datetime 系列”包含pd.Timestamp 元素, datetime.date 元素。 Pandas 的推荐解决方案:

s = pd.to_datetime(s)    # convert series to Pandas
mask = s > '2018-03-10'  # calculate Boolean mask against Pandas-compatible object

热门答案有问题:

@RyanSaxe 接受的答案的第一次尝试不起作用;第二个答案是低效的。 从 Pandas v0.23.0 开始,@Keith 高度赞成的答案不起作用;它给了TypeError

任何好的 Pandas 解决方案必须确保:

    该系列是 Pandas datetime 系列,而不是 object dtype。 datetime 系列与兼容对象进行比较,例如pd.Timestamp,或格式正确的字符串。

这是一个带有基准测试的演示,证明一次性转换成本可以通过一次操作立即抵消:

from datetime import date

L = [date(2018, 1, 10), date(2018, 5, 20), date(2018, 10, 30), date(2018, 11, 11)]
s = pd.Series(L*10**5)

a = s > date(2018, 3, 10)             # accepted solution #2, inefficient
b = pd.to_datetime(s) > '2018-03-10'  # more efficient, including datetime conversion

assert a.equals(b)                    # check solutions give same result

%timeit s > date(2018, 3, 10)                  # 40.5 ms
%timeit pd.to_datetime(s) > '2018-03-10'       # 33.7 ms

s = pd.to_datetime(s)

%timeit s > '2018-03-10'                       # 2.85 ms

【讨论】:

【参考方案5】:

您应该遍历项目并独立解析它们,然后构造一个新列表。

df['date'] = [dateutil.parser.parse(x) for x in df['date']]

【讨论】:

以上是关于从 SQL 数据库导入表并按日期过滤行时,将 Pandas 列解析为 Datetime的主要内容,如果未能解决你的问题,请参考以下文章

比较两个 MYSQL 表并按列返回缺失的日期和分组

SQL QUERY - 从头开始​​过滤日期

将excel数据导入sql server数据库表并在gridview中显示

具有特定条件计数的 Mongodb 聚合并按输出投影的日期范围过滤不能按预期工作

如何按日期过滤并按代码进行表单查询?

SQLAlchemy:如何按两个字段分组并按日期过滤