从numpy.datetime64转换为pandas.tslib.Timestamp错误?

时间:2013-02-04 20:44:55

标签: python numpy python-2.7 timestamp pandas

我有一个python模块,可以直接将数据加载到numpy.ndarray的dict中,以便在pandas.Dataframe中使用。但是,我注意到“NA”值存在问题。我的文件格式表示NA值s -9223372036854775808(boost :: integer_traits :: const_min)。我的非NA值按预期(使用正确的值)加载到pandas.Dataframe中。我相信发生的事情是我的模块加载到numpy.datetime64 ndarray,然后转换为pandas.tslib.Timestamp列表。此转换似乎不保留'const_min'整数。请尝试以下方法:

>>> pandas.tslib.Timestamp(-9223372036854775808)
NaT
>>> pandas.tslib.Timestamp(numpy.datetime64(-9223372036854775808))
<Timestamp: 1969-12-31 15:58:10.448384>

这是熊猫虫吗?我想我可以让我的模块避免在这种情况下使用numpy.ndarray,并使用Pandas不会绊倒的东西(可能预先分配tslib.Timestamp本身的列表。)

以下是发生意外情况的另一个例子:

>>> npa = numpy.ndarray(1, dtype=numpy.datetime64)
>>> npa[0] = -9223372036854775808
>>> pandas.Series(npa)
0   NaT
>>> pandas.Series(npa)[0]
<Timestamp: 1969-12-31 15:58:10.448384>

根据杰夫的评论,我有更多关于出了什么问题的信息。

>>> npa = numpy.ndarray(2, dtype=numpy.int64)
>>> npa[0] = -9223372036854775808
>>> npa[1] = 1326834000090451
>>> npa
array([-9223372036854775808,     1326834000090451])
>>> s_npa = pandas.Series(npa, dtype='M8[us]')
>>> s_npa
0                          NaT
1   2012-01-17 21:00:00.090451

耶!该系列保留了NA和我的时间戳。但是,如果我尝试从该系列创建一个DataFrame,NaT就会消失。

>>> pandas.DataFrame({'ts':s_npa})
                      ts
0 1969-12-31 15:58:10.448384
1 2012-01-17 21:00:00.090451

乏味。一时兴起,我尝试将我的整数解释为超过纪元的纳秒。令我惊讶的是,DataFrame正常工作:

s2_npa = pandas.Series(npa, dtype='M8[ns]')
>>> s2_npa
0                             NaT
1   1970-01-16 08:33:54.000090451
>>> pandas.DataFrame({"ts":s2_npa})
                             ts
0                           NaT
1 1970-01-16 08:33:54.000090451

当然,我的时间戳不对。我的观点是pandas.DataFrame在这里行为不一致。为什么在使用dtype ='M8 [ns]'时保留NaT,但在使用'M8 [us]'时却没有?

我目前正在使用此解决方法来转换a,这会让事情变得相当缓慢,但有效:

>>> s = pandas.Series([1000*ts if ts != -9223372036854775808 else ts for ts in npa], dtype='M8[ns]')
>>> pandas.DataFrame({'ts':s})
                          ts
0                        NaT
1 2012-01-17 21:00:00.090451

(几个小时后......)

好的,我有进步。我已深入研究代码,意识到Series上的 repr 函数最终会调用'_format_datetime64',它会检查'isnull'并打印出'NaT',这解释了这两者之间的区别。

>>> pandas.Series(npa)
0   NaT
>>> pandas.Series(npa)[0]
<Timestamp: 1969-12-31 15:58:10.448384>

似乎以表示NA,但它只在打印时才这样做。我想可能有其他的pandas函数调用'isnull'并根据答案行事,在这种情况下,这似乎可能部分适用于NA时间戳。但是,我知道由于元素零的类型,系列是不正确的。它是时间戳,但应该是 NaTType 。我的下一步是深入了解Series的构造函数,以确定pandas在构造期间何时/如何使用 NaT 值。据推测,当我指定dtype ='M8 [us]'时,它会丢失一个案例......(更多内容)。

根据Andy在评论中的建议,我尝试使用pandas时间戳来解决问题。它没用。以下是这些结果的示例:

>>> npa = numpy.ndarray(1, dtype='i8')
>>> npa[0] = -9223372036854775808
>>> npa
array([-9223372036854775808])
>>> pandas.tslib.Timestamp(npa.view('M8[ns]')[0]).value
-9223372036854775808
>>> pandas.tslib.Timestamp(npa.view('M8[us]')[0]).value
-28909551616000

1 个答案:

答案 0 :(得分:2)

答案:否

从技术上讲,就是这样。我在github上发布了这个bug并得到了回复: https://github.com/pydata/pandas/issues/2800#issuecomment-13161074

“索引等目前不支持除纳秒以外的单位。这应该严格执行”

我用'ns'而不是'us'运行的所有测试都运行正常。我期待着将来的发布。

对于任何感兴趣的人,我修改了我的C ++ python模块来迭代我从磁盘加载的int64_t数组,并将所有内容乘以1000,除了NA值(boost :: integer_traits :: const_min)。我担心性能,但加载时间的差异对我来说很小。 (在Python中做同样的事情非常非常慢。)