Python - Reading HDF5 dataset into a list vs numpy array

时间:2018-04-18 18:10:22

标签: python list numpy hdf5 h5py

I've been exploring HDF5 and its python interface (h5py) so I tried to read a HDF5 file (one dimensional array of 100 million integers) into: a normal list and another time to a numpy array. Converting the dataset to a numpy was very fast comparing to when I tried to convert it to a normal python list (actually doing it with a list took a very long time that I had to kill it before it finished).

Can any one help me understand what happens internally that makes converting HDF5 dataset to a numpy array extremely faster than doing it with a normal list? Does it has to do with h5py compatibility with numpy?

import numpy as np
import hdf5

def readtolist(dataset):
    return "normal list count = {0}".format(len(list(dataset['1'])))

def readtonp(dataset):
    n1 = np.array(dataset)
    return "numpy count = {0}".format(len(n1))

f = h5py.File(path, 'r')    
readtolist(f['1'])
readtonp(f['1'])

Thanks for the help!

3 个答案:

答案 0 :(得分:2)

使用我最近创建的测试文件:

In [78]: f = h5py.File('test.h5')
In [79]: list(f.keys())
Out[79]: ['x']
In [80]: f['x']
Out[80]: <HDF5 dataset "x": shape (2, 5), type "<i8">
In [81]: x = f['x'][:]
In [82]: x
Out[82]: 
array([[0, 2, 4, 6, 8],
       [1, 3, 5, 7, 9]])
In [83]: alist = x.tolist()
In [84]: alist
Out[84]: [[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]]

HDF5中的数据存储类似于numpy数组。 h5py使用已编译的代码(cython)与HDF5基本代码进行交互。它将数据集加载为numpy数组。

要获取列表,您必须将数组转换为列表。对于1d数组,list(x)类似,但它很慢且不完整。 tolist()是正确的方法。

list()遍历数组的第一维:

In [85]: list(x)
Out[85]: [array([0, 2, 4, 6, 8]), array([1, 3, 5, 7, 9])]
In [86]: list(f['x'])
Out[86]: [array([0, 2, 4, 6, 8]), array([1, 3, 5, 7, 9])]

1211:~/mypy$ h5dump test.h5
HDF5 "test.h5" {
GROUP "/" {
   DATASET "x" {
      DATATYPE  H5T_STD_I64LE
      DATASPACE  SIMPLE { ( 2, 5 ) / ( 2, 5 ) }
      DATA {
      (0,0): 0, 2, 4, 6, 8,
      (1,0): 1, 3, 5, 7, 9
      }
   }
}
}

我应该补充一点,Python list是一个独特的数据结构。它包含指向内存中其他对象的指针,因此可以容纳所有类型的对象 - 数字,其他列表,字典,字符串,自定义类等。HDF5数据集,如numpy数组,拥有统一的数据类型(转储中的DATATYPE)。例如,它不能存储对象dtype数组。如果要将列表保存到HDF5,首先必须将其转换为数组。

答案 1 :(得分:1)

HDF5是一种用于存储大量科学数组数据的文件格式。它可以存储多个数据集,并提供多个动态压缩模型,使重复模式的数据能够更有效地存储。

通常使用Pandas或Numpy解析它会更快,因为它们以矢量化形式处理压缩,而本机Python list通过嵌套来处理它,这显然更慢。

这基本上就是简单的说法。

以下是使用pandasNumpy生成100000个条目的文件的实验,将其存储在HDF5中,然后再次解析。

生成数据

frame = pd.DataFrame({'a': np.random.randn(100000)})
store = pd.HDFStore('mydata.h5')
frame.to_hdf('mydata.h5', 'obj1', format='table')
store.close()

解析时间

%%timeit
df = pd.read_hdf('mydata.h5', 'obj1')

<强>输出

9.14 ms ± 240 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

list相比速度非常快。

答案 2 :(得分:0)

我不确定您看到的差异是否与hdf5有关。只使用字符串作为数据源就可以产生类似的效果:

>>> import numpy as np
>>> import string, random
>>> 
>>> from timeit import timeit    
>>> kwds = dict(globals=globals(), number=1000)
>>> 
>>> a = ''.join(random.choice(string.ascii_letters) for _ in range(1000000))
>>> 
>>> timeit("A = np.fromstring(a, dtype='S1')", **kwds)
0.06803569197654724
>>> timeit("L = list(a)", **kwds)
6.131339570041746

稍微简化一下,对于同类数据,numpy将它们作为内存块存储,而列表为每个项创建一个python对象。在这种情况下,python对象由值,指向其类型对象的指针和引用计数组成。因此,总而言之,numpy基本上只能复制一块内存,而list必须分配并创建所有这些对象和列表容器。

另一方面,从列表访问单个元素更快,因为 - 除其他外 - 现在数组必须创建一个python对象,而列表可以简单地返回它存储的那个:

>>> L = list(a)
>>> A = np.fromstring(a, dtype='S1')
>>> 
>>> kwds = dict(globals=globals(), number=100)
>>> 
>>> timeit("[L[i] for i in range(len(L))]", **kwds)
5.607562301913276
>>> timeit("[A[i] for i in range(len(A))]", **kwds)
13.343806453049183
相关问题