在PyTables中存储和提取numpy日期时间

MRo*_*lin 8 python datetime numpy pytables

我想将numpy datetime64数据存储在PyTables中Table.我想在不使用熊猫的情况下这样做.

到目前为止我尝试过的

建立

In [1]: import tables as tb
In [2]: import numpy as np
In [3]: from datetime import datetime
Run Code Online (Sandbox Code Playgroud)

创建数据

In [4]: data = [(1, datetime(2000, 1, 1, 1, 1, 1)), (2, datetime(2001, 2, 2, 2, 2, 2))]
In [5]: rec = np.array(data, dtype=[('a', 'i4'), ('b', 'M8[us]')])
In [6]: rec  # a numpy array with my data
Out[6]: 
array([(1, datetime.datetime(2000, 1, 1, 1, 1, 1)),
       (2, datetime.datetime(2001, 2, 2, 2, 2, 2))], 
      dtype=[('a', '<i4'), ('b', '<M8[us]')])
Run Code Online (Sandbox Code Playgroud)

使用Time64Col描述符打开PyTables数据集

In [7]: f = tb.open_file('foo.h5', 'w')  # New PyTables file
In [8]: d = f.create_table('/', 'bar', description={'a': tb.Int32Col(pos=0), 
                                                    'b': tb.Time64Col(pos=1)})
In [9]: d
Out[9]: 
/bar (Table(0,)) ''
  description := {
  "a": Int32Col(shape=(), dflt=0, pos=0),
  "b": Time64Col(shape=(), dflt=0.0, pos=1)}
  byteorder := 'little'
  chunkshape := (5461,)
Run Code Online (Sandbox Code Playgroud)

将NumPy数据附加到PyTables数据集

In [10]: d.append(rec)
In [11]: d
Out[11]: 
/bar (Table(2,)) ''
  description := {
  "a": Int32Col(shape=(), dflt=0, pos=0),
  "b": Time64Col(shape=(), dflt=0.0, pos=1)}
  byteorder := 'little'
  chunkshape := (5461,)
Run Code Online (Sandbox Code Playgroud)

我的约会时间怎么了?

In [12]: d[:]
Out[12]: 
array([(1, 0.0), (2, 0.0)], 
      dtype=[('a', '<i4'), ('b', '<f8')])
Run Code Online (Sandbox Code Playgroud)

我知道HDF5不提供日期时间的原生支持.我希望PyTables覆盖的额外元数据可以处理这个问题.

我的问题

如何在PyTables中存储包含日期时间的numpy记录数组?如何有效地将PyTables表中的数据提取回NumPy数组并保留我的日期时间?

常见答案

我经常得到这个答案:

使用熊猫

我不想使用Pandas,因为我没有索引,我不希望存储在我的数据集中,并且Pandas不允许你没有/存储索引(请参阅此问题)

Phi*_*oud 5

首先,将值放入时Time64Col,它们必须为float64。您可以通过调用来完成此操作astype,如下所示:

new_rec = rec.astype([('a', 'i4'), ('b', 'f8')])
Run Code Online (Sandbox Code Playgroud)

然后您需要将列b从纪元转换为秒,这意味着您需要除以1,000,000,因为我们以微秒为单位:

new_rec['b'] = new_rec['b'] / 1e6
Run Code Online (Sandbox Code Playgroud)

然后打电话 d.append(new_rec)

当您将阵列读回到内存中时,进行相反的操作并乘以1,000,000。在放入任何东西之前,您必须确保一切都在微秒内,这由astype('datetime64[us]')numpy> = 1.7.x 自动处理

我使用了以下问题的解决方案:如何从numpy.datetime64获取Unix时间戳

这是您的示例的有效版本:

In [4]: data = [(1, datetime(2000, 1, 1, 1, 1, 1)), (2, datetime(2001, 2, 2, 2, 2, 2))]

In [5]: rec = np.array(data, dtype=[('a', 'i4'), ('b', 'M8[us]')])

In [6]: new_rec = rec.astype([('a', 'i4'), ('b', 'f8')])

In [7]: new_rec
Out[7]:
array([(1, 946688461000000.0), (2, 981079322000000.0)],
      dtype=[('a', '<i4'), ('b', '<f8')])

In [8]: new_rec['b'] /= 1e6

In [9]: new_rec
Out[9]:
array([(1, 946688461.0), (2, 981079322.0)],
      dtype=[('a', '<i4'), ('b', '<f8')])

In [10]: f = tb.open_file('foo.h5', 'w')  # New PyTables file

In [11]: d = f.create_table('/', 'bar', description={'a': tb.Int32Col(pos=0),
   ....:                                             'b': tb.Time64Col(pos=1)})

In [12]: d.append(new_rec)

In [13]: d[:]
Out[13]:
array([(1, 946688461.0), (2, 981079322.0)],
      dtype=[('a', '<i4'), ('b', '<f8')])

In [14]: r = d[:]

In [15]: r['b'] *= 1e6

In [16]: r.astype([('a', 'i4'), ('b', 'datetime64[us]')])
Out[16]:
array([(1, datetime.datetime(2000, 1, 1, 1, 1, 1)),
       (2, datetime.datetime(2001, 2, 2, 2, 2, 2))],
      dtype=[('a', '<i4'), ('b', '<M8[us]')])
Run Code Online (Sandbox Code Playgroud)