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

Posted

技术标签:

【中文标题】在 Python2.7 中比较 Timestamp 和 datetime64 时的奇怪行为【英文标题】:Strange behaviour when comparing Timestamp and datetime64 in Python2.7 【发布时间】:2019-01-21 16:18:50 【问题描述】:

有没有人遇到过类似的情况,如果我们让aTimestampbdatetime64,那么比较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】:

这是一个有趣的问题。我已经进行了一些挖掘并尽力解释了其中的一些内容,尽管我仍然不明白的一件事是为什么我们得到pandas 抛出错误而不是numpy 当我们这样做时@ 987654329@。

关于您的问题:

如果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__ (&lt;) 方法,无论其他值是什么,都始终返回 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

令我惊讶的是,我认为问题在于nanoseconds 不在时间戳中,即使您执行以下操作,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 行的结果。如果您将==True 用于!=,它们将返回False,而不实际比较这些值。

编辑nanosecond 功能已添加到版本 0.23.0。所以你可以做类似pd.Timestamp('2013-03-23T05:33:00.000000022', unit='ns')的事情。所以是的,当您比较 np.datetime64 时,它将转换为 pd.Timestampns 精度。

请注意,pd.Timestamp 应该是 python 的日期时间的替代品:

Timestamp 是 python 的 Datetime 的 pandas 等价物 并且在大多数情况下可以与它互换。

但是 python 的日期时间不支持纳秒 - 很好的答案在这里解释了为什么 SO_Datetime.pd.Timestamp 支持两者之间的比较,即使你的 Timestamp 有纳秒。当您将datetime 对象与pd.Timestamp 对象与ns 进行比较时,它们将使用_compare_outside_nanorange 进行比较。

回到np.datetime64,这里要注意的一件事,正如这篇文章SO 中很好解释的那样,它是int64 类型的包装器。所以如果我执行以下操作就不足为奇了:

1 > a
a > 1

两者都会出现错误Cannot compare type 'Timestamp' with type 'int'

因此,当您执行b &gt; a 时,大多数情况下在int 级别上进行比较,此比较将由np.greater() 函数np.greater 完成 - 还请查看ufunc_docs。

注意:我无法确认这一点,numpy 文档太复杂,无法阅读。如果任何 numpy 专家可以对此发表评论,那将很有帮助。

如果是这种情况,如果np.datetime64 的比较是基于int,那么上面带有a == bb == a 的示例是有意义的。因为当我们执行b == a 时,我们将bint 值与pd.Timestamp 进行比较,这对于== 将始终返回Flase,对于!= 将始终返回True

和say123 == '123'一样,这个操作不会失败,只会返回False

【讨论】:

非常感谢 gyx-hh!您的回答解释了我的大部分“对 ,== 运算符的误解”!回到纳秒问题,那么 np.datetime64 和 pd.Timestamp 的兼容性似乎有一个“特征”?看到你的“a== b, b == a”代码块的结果,我有点震惊…… @Min 我刚刚用一些额外的信息更新了我的答案 非常感谢!非常感谢您的回答!

以上是关于在 Python2.7 中比较 Timestamp 和 datetime64 时的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

在 Python2.7 中忽略没有 continue 语句的 IndexError

Python2.7-difflib

python2.7.18输入三个数取中间值

windows 系统上Anaconda3.7 配置python2.7环境

python2.7练习小例子

python2.7入门---break语句&continue语句&pass空语句