混合pandas,datetime和numpy timedelta时的不稳定行为(bug?)

时间:2017-06-07 16:16:43

标签: python pandas datetime numpy

我偶然注意到,在datetime上的一些操作(a> b)应该给出相同的(明确定义的)结果实际上给出不同的结果(一些是正确的,一些是错误的,一些只是抛出一个错误)取决于是否我在熊猫数据框架上或在numpy中执行它们。我试着在下面给出一个小例子。为简洁起见,我使用了dateutile.parser.parse函数,但我认为这个问题出现在datetime,pandas和numpy包之间的相互作用中,特别是在使用pandas时#39; DatetimeIndex。

首先我尝试用np.timedelta64创建一个df,并且我无法与单个np.timedelta64进行比较。这是一个干净的错误,我认为没问题:

import numpy as np
import pandas as pd
from dateutil.parser import parse
a1 = np.array([np.datetime64(parse('20200101')),np.datetime64(parse('20150101'))]).reshape((1,-1))
a2 = np.array([np.datetime64(parse('20100101')),np.datetime64(parse('20180101'))]).reshape((-1,1))
df1 = pd.DataFrame(a1-a2)
df1 > np.timedelta64(1000,'D')

以上df1是:

    0                       1
0   3652 days 00:00:00  1826 days 00:00:00
1   730 days 00:00:00   -1096 days +00:00:00

并且第二个命令抛出错误" TypeError:ufunc' isnan'不支持输入类型,并且根据投射规则' safe''"""'""'到目前为止,非常好。

但是,如果我写:

a3 = pd.DatetimeIndex(a1.flatten()).values.reshape((1,-1))
df2 = pd.DataFrame(a3 - a2)

然后结果看起来类似:df2 =

    0           1
0   3652 days   1826 days
1   730 days    -1096 days

但在这种情况下,df2 > np.timedelta64(1000,'D')不仅不会抛出错误,而且会给出错误的答案:

    0       1
0   True    True
1   True    False

另一方面,如果不是pd.DataFrame(a3-a2) > np.timedelta64(1000,'D'),而是pd.DataFrame(a3-a2 > np.timedelta64(1000,'D')),我们会得到很好的答案:

    0       1
0   True    True
1   False   False

鉴于这种情况,我想某处肯定会有一个错误,虽然我不太确定在哪里。也许我只是误解了一些符号,但无论如何这种行为有点令人费解。一些问题可能来自以下事实:在上述定义中,一些dtypes(例如df1)以微秒为单位,其他一些(例如df2)以纳秒为单位;但是,我希望这些应该被正确对待,因为输出正确地转换为天......

供参考,我使用的是Python 3.5,numpy版本1.12.1,pandas版本0.18.0和python-dateutil版本2.5.1。

编辑:经过进一步测试,并考虑到Paul的答案如下:

  • Pandas版本0.19.2显然已经解决了这个错误。保罗在下面的代码片段,以及上面关于df2的代码,已经过测试,保罗在Linux,Python3.5,Pandas 0.19.2下正确工作,我也在Linux和Windows下检查过它们, Python2.7和Python3.5,Pandas 0.20.2。

  • 在0.18.2中,Paul的下面的代码片段给出了与上面df2相同(错误)的答案。

  • 但是,在我的测试中,同样在0.20.2中,上面的第一个代码(此问题上的df1)给出了错误的答案,给出了所有的错误。这可能是因为pandas将日期存储为微秒(因为Paul的显式转换解决了问题),而numpy则为纳秒,因此存在1000的静默因子。不过,我认为这应该是自动照顾......

1 个答案:

答案 0 :(得分:1)

这种行为显然不一致,因为我无法在最新版本的pandas上重新创建您的问题,但似乎两种情况之间的主要区别在于df1是存储np.dtype('timedelta64[us]')个对象,df2存储np.dtype('timedelta64[ns]')个对象。

我不确定为什么你认为df1 > np.timedelta64(1000, 'D')应该失败 - 我的直觉是它没有任何类型转换问题。也就是说,至少从版本0.19.2开始,如果您始终确保将数据框投射到np.timedelta64[ns],那么您将不会遇到此问题:

import pandas as pd
import numpy as np
from datetime import datetime

a1 = np.array([np.datetime64(datetime(2020, 1, 1)),
               np.datetime64(datetime(2015, 1, 1))]).reshape((1,-1))
a2 = np.array([np.datetime64(datetime(2010,1,1)),
               np.datetime64(datetime(2018,1,1))]).reshape((-1,1))

df1 = pd.DataFrame(a1 - a2).astype(np.dtype('timedelta64[ns]'))
kiloday = np.timedelta64(1000, 'D')

df1 > kiloday
#        0      1
# 0   True   True
# 1  False  False