使用pandas.to_datetime转换时指定日期格式

30

我有一个csv文件,其中日期以标准英国格式的字符串存储- %d/%m/%Y,这意味着它们看起来像:

12/01/2012
30/01/2012

上述示例代表的是2012年1月12日和2012年1月30日。

当我使用pandas版本0.11.0导入这些数据时,我进行了以下转换:

import pandas as pd
...
cpts.Date = cpts.Date.apply(pd.to_datetime)

但是它的日期转换不一致。以我现有的例子为例,12/01/2012会被转换为代表2012年12月1日的日期时间对象,但30/01/2012则会被转换为我想要的2012年1月30日。

在查看这个问题后,我尝试了:

cpts.Date = cpts.Date.apply(pd.to_datetime, format='%d/%m/%Y')

但是结果完全相同。 源代码 表明我做得没错,所以我不知道问题出在哪里。有人知道我做错了什么吗?


2
你使用了 read_csv 吗?因为在读取时,你可以直接这样做。 - joris
但回到你最初的问题(因为这也应该可以工作),你使用了哪个版本?对我而言它是有效的。 - joris
@AndyHayden 但显然只适用于序列,我尝试在一个(单列)数据帧上使用它,结果成功了。 - joris
@joris 很抱歉失联了一段时间。我的理解是,我正在传递的 pd.DataFrame 的单个列是一个 pd.Series?这也就是为什么我的调用目前无法工作的原因吗? - cms_mgr
1
是的,访问单个列将返回一个 Series。因此,您可以尝试 cpts[['Date']].apply(pd.to_datetime, ...) 作为一种解决方法(由于双重 [,它将返回一个带有一个列的 dataframe)。但请注意,它也应该在 Series 上工作(它不起作用是一个 bug),更简单的方法就是直接在列上调用 pd.to_datetime(..),如 @AndyHayden 在他的答案中指出的那样,或者在 read_csv 中进行转换。 - joris
显示剩余2条评论
2个回答

29
你可以使用read_csv中的parse_dates选项在读取数据时直接进行转换。
这里的诀窍是使用dayfirst=True来指示你的日期从日开始而不是月开始。更多信息请参见:http://pandas.pydata.org/pandas-docs/dev/generated/pandas.io.parsers.read_csv.html 当你的日期必须成为索引时:
>>> import pandas as pd
>>> from StringIO import StringIO
>>> s = StringIO("""date,value
... 12/01/2012,1
... 12/01/2012,2
... 30/01/2012,3""")
>>> 
>>> pd.read_csv(s, index_col=0, parse_dates=True, dayfirst=True)
            value
date             
2012-01-12      1
2012-01-12      2
2012-01-30      3

或者当你的日期只在特定的一列中:

>>> s = StringIO("""date
... 12/01/2012
... 12/01/2012
... 30/01/2012""")
>>> 
>>> pd.read_csv(s, parse_dates=[0], dayfirst=True)
                 date
0 2012-01-12 00:00:00
1 2012-01-12 00:00:00
2 2012-01-30 00:00:00

3
你也可以设置自定义解析器,以下是我的解况:df = pd.read_csv("file.csv", parse_dates=['date_column'], date_parser=lambda d: pd.to_datetime(d, format="%Y/%m/%d", errors="coerce")) - ruloweb

18

我认为你说得没错,我已经在 Github 上发布了这个问题

您可以直接指定要转换的日期时间格式到 to_datetime 函数中,例如:

In [1]: s = pd.Series(['12/1/2012', '30/01/2012'])

In [2]: pd.to_datetime(s, format='%d/%m/%Y')
Out[2]:
0   2012-01-12 00:00:00
1   2012-01-30 00:00:00
dtype: datetime64[ns]

更新:正如提问者正确指出的,这种方法无法处理NaN。如果你接受 dayfirst=True 这种方式(它也可用于NaN):

Update: 正如提问者正确指出的,这种方法无法处理NaN。如果你接受 dayfirst=True 这种方式(它也可用于NaN):

s.apply(pd.to_datetime, dayfirst=True)

需要注意的是,使用dayfirst时必须小心(它比指定精确格式更容易),因为dayfirst不是严格的


1
谢谢,这个解决方案很有吸引力,但它目前无法处理缺失数据。我怀疑在dev中,pd.to_datetimecoerce 参数可以解决这个问题,但在稳定版本发布之前,我无法升级我的工作环境。 - cms_mgr
1
我很抱歉,它仍然在调整日期。看起来这是一个错误 - 我想这可能是我发现的第一个错误! - cms_mgr
4
要是有人制定了一个国际通用的日期格式就好了。哦,等等,原来已经有了(参见http://xkcd.com/1179/)。 - cms_mgr
@cms_mgr 哈,比较一下 pd.to_datetime(s[0], format='%d/%m/%Y', dayfirst=True)pd.to_datetime(s[0], format='%d/%m/%Y'),肯定是个 bug,也许是整个 bug。 - Andy Hayden
谢谢Andy,我已经点赞了你的回答,但是我接受了Joris的回答,因为他先提出了。 - cms_mgr
显示剩余3条评论

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