在PyTables中存储和提取numpy日期时间
我想把numpy的datetime64
数据存储到PyTables的Table
里。我希望能做到这一点,而不使用Pandas。
我目前尝试过的
设置环境
In [1]: import tables as tb
In [2]: import numpy as np
In [3]: from datetime import datetime
创建数据
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]')])
用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,)
将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,)
我的日期时间数据去哪了?
In [12]: d[:]
Out[12]:
array([(1, 0.0), (2, 0.0)],
dtype=[('a', '<i4'), ('b', '<f8')])
我知道HDF5本身不支持日期时间格式。不过,我本以为PyTables会通过额外的元数据来处理这个问题。
我的问题
我该如何在PyTables中存储包含日期时间的numpy记录数组?我该如何高效地将这些数据从PyTables表中提取回NumPy数组,并保留我的日期时间数据?
常见回答
我经常得到这样的回答:
使用Pandas
我不想使用Pandas,因为我没有索引,我也不想在我的数据集中存储一个索引,而Pandas不允许你不使用或不存储索引(可以参考这个问题)
1 个回答
5
首先,当你把值放入一个 Time64Col
时,这些值需要是 float64
类型。你可以通过调用 astype
来实现,像这样:
new_rec = rec.astype([('a', 'i4'), ('b', 'f8')])
接下来,你需要把列 b
转换成自纪元以来的秒数,这意味着你需要把它除以 1,000,000,因为我们使用的是微秒:
new_rec['b'] = new_rec['b'] / 1e6
然后调用 d.append(new_rec)
。
当你把数组读回内存时,记得反向操作,乘以 1,000,000。在放入任何东西之前,你需要确保数据是以微秒为单位的,这个过程在 numpy 版本 >= 1.7.x 中会通过 astype('datetime64[us]')
自动处理。
我使用了这个问题的解决方案:如何从 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]')])