我偶然注意到,在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的静默因子。不过,我认为这应该是自动照顾......
答案 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