在Python2.7中比较Timestamp和datetime64时出现奇怪的行为

4

是否有人遇到过类似下面的情况,如果我们让a是一个Timestampb是一个datetime64,那么比较a < b是没有问题的,但是b < a会返回错误。

如果a可以与b进行比较,我认为我们应该能够反过来比较?

例如(Python 2.7):

>>> a
Timestamp('2013-03-24 05:32:00')
>>> b
numpy.datetime64('2013-03-23T05:33:00.000000000')
>>> a < b
False
>>> b < a
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "pandas\_libs\tslib.pyx", line 1080, in pandas._libs.tslib._Timestamp.__richcmp__ (pandas\_libs\tslib.c:20281)
TypeError: Cannot compare type 'Timestamp' with type 'long'

非常感谢您的帮助!

1个回答

1
这是一个有趣的问题。我做了一些调查并尽力解释了其中一些内容,尽管仍有一件事情我不明白,那就是当我们执行b<a时为什么会出现pandas抛出错误而不是numpy

关于你的问题:

如果a可以与b进行比较,我认为我们应该能够反过来比较?

这并不一定正确。这取决于比较运算符的实现方式。

以这个测试类为例:

class TestCom(int):
    def __init__(self, a):
    self.value = a

    def __gt__(self, other):
    print('TestComp __gt__ called')
    return True

    def __eq__(self, other):
    return self.a == other

在这里,我定义了我的__gt__<)方法,无论其他值如何,它始终返回true。而__eq__==)保持不变。

现在看看以下比较:

a = TestCom(9)
print(a)
# Output: 9

# my def of __ge__
a > 100

# Ouput: TestComp __gt__ called
# True

a > '100'
# Ouput: TestComp __gt__ called
# True

'100' < a

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-486-8aee1b1d2500> in <module>()
      1 # this will not use my def of __ge__
----> 2 '100' > a

TypeError: '>' not supported between instances of 'str' and 'TestCom'

回到你的情况。从timestamps_sourceCode可以看出,我唯一能想到的就是pandas.Timestamp进行了某些类型检查和转换。

当我们比较a和b(pd.Timestampnp.datetime64),Timestamp.__richcmp__函数进行比较,如果它是np.datetime64类型,则将其转换为pd.Timestamp类型并进行比较。

# we can do the following to have a comparison of say b > a
# this converts a to np.datetime64 - .asm8 is equivalent to .to_datetime64()
b > a.asm8

# or we can confert b to datetime64[ms]
b.astype('datetime64[ms]') > a

# or convert to timestamp
pd.to_datetime(b) > a

我觉得令人惊讶的是,我原以为问题在于纳秒而不是时间戳,但即使你执行以下操作,np.datetime64与pd.Timestamp之间的比较也会失败。
a = pd.Timestamp('2013-03-24 05:32:00.00000001')
a.nanosecond   # returns 10
# doing the comparison again where they're both ns still fails
b < a

从源代码来看,似乎我们可以使用==!=运算符。但是即使它们也不能按预期工作。请看下面的示例:

a = pd.Timestamp('2013-03-24 05:32:00.00000000')
b = np.datetime64('2013-03-24 05:32:00.00000000', 'ns')

b == a  # returns False

a == b  # returns True

我认为这是149-152行或163-166行的结果。如果您使用“==”,则返回False,如果使用!=,则返回True,而不实际比较值。 编辑: nanosecond功能是在版本0.23.0中添加的。因此,您可以执行以下操作:pd.Timestamp('2013-03-23T05:33:00.000000022',unit ='ns')。因此,当您比较np.datetime64时,它将转换为具有ns精度的pd.Timestamp
请注意,pd.Timestamp应该替代Python的datetime:

Timestamp是pandas中等价于Python的Datetime,并且在大多数情况下可以互换。

但是Python的datetime不支持纳秒-这里有一个很好的答案解释为什么SO_Datetimepd.Timestamp 支持比较两者,即使您的Timestamp中有纳秒。当您将一个datetime对象与带有nspd.Timestamp对象进行比较时,它们具有 _compare_outside_nanorange 来执行比较。

回到np.datetime64,需要注意的一点是,正如在这篇文章SO中很好地解释的那样,它是对int64类型的包装器。因此,如果我执行以下操作,这并不奇怪:

1 > a
a > 1

两者都会报错,错误信息为无法将类型“Timestamp”与类型“int”进行比较

因此,在执行b > a时,比较必须在int级别上进行,这个比较将由np.greater()函数 np.greater 来完成 - 也可以查看ufunc_docs

注意:我无法确认这一点,因为numpy文档过于复杂。如果有任何numpy专家能够发表评论,那将是有帮助的。

如果是这种情况,如果np.datetime64的比较基于int,那么上面使用a == bb == a的示例就有意义了。因为当我们执行b == a时,我们将bint值与pd.Timestamp进行比较,这将始终返回Flase(对于==)和True(对于!=)。这与执行123 == '123'相同,此操作不会失败,只会返回False

非常感谢gyx-hh!你的答案解释了我对“<,>,==运算符”的很多“误解”!回到纳秒问题上,看来np.datetime64和pd.Timestamp之间存在“兼容性”的特性?当看到你的“a == b,b == a”的代码块结果时,我有点震惊... - Min
@Min,我刚刚更新了我的答案,并添加了一些额外的信息。 - gyx-hh
非常感谢!非常感谢您的回答! - Min

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