有效地存储矩阵列表

时间:2017-03-29 15:57:13

标签: python numpy pickle pytables h5py

我有一大堆存储为numpy矩阵的图像。图像具有不同的大小,例如

import numpy as np
from numpy.random import rand

data = [rand(100,200), rand(1024, 768)]

我正在寻找一种方法来存储这个矩阵列表,以便可以快速读取(写入数据可能很慢)。我尝试了pickle / numpy.savez,但是读取数据比再次加载原始图像要慢。

我认为hdf5可能很快,但我无法弄清楚如何存储此列表。不是强制性的,但有用的数据格式允许附加数据,使列表不必作为整体存储在内存中。

修改 根据答案到目前为止,我试图提出一些建议

data = [rand(1024, 768) for i in np.arange(100)]
def timenp():
    np.savez("test.npz",*data)
    d=np.load('test.npz')
    loaded = [d[f] for f in d]

def timebinary():
    with file("tmp.bin","wb") as f:
        np.save(f, len(data))
        for img in data:
            np.save(f,img)

    with file("tmp.bin","rb") as f:
        n = np.load(f)
        loaded = []
        for i in np.arange(n):
            loaded.append(np.load(f))

import h5py
def timeh5py():
    with h5py.File('foo.hdf5','w') as f:
        dt = h5py.special_dtype(vlen=np.dtype('float32'))
        dset = f.create_dataset('data', (len(data),), dtype=dt)
        shapes = f.create_dataset('shapes', (len(data), 2), dtype='int32')
        dset[...] = [img.flatten() for img in data]
        shapes[...] = [img.shape for img in data]

    with h5py.File('foo.hdf5','r') as f:
        loaded=[]
        for (img, shape) in zip(f['data'],f['shapes']):
            loaded.append(np.reshape(img,shape))  
  

python -m cProfile timenp.py
           452906函数调用(451141基元调用)在9.256秒

  

python -m cProfile timebinary.py           73049函数调用(71340原始调用),时间为4.945秒

  

python -m cProfile timeh5py.py
          33151个函数调用(32568个原始调用)在4.384秒内

2 个答案:

答案 0 :(得分:0)

尝试使用numpy savez function,它包含压缩和未压缩版本。

答案 1 :(得分:0)

In [276]: alist=[np.arange(10), np.arange(3), np.arange(100)]

如果我将其保存为np.savez('test',alist),它会将列表保存为一个对象。如果我用*扩展列表,那么它将每个列表元素放在存档中的单独文件中。

In [277]: np.savez('test',*alist)
In [278]: d=np.load('test.npz')
In [279]: list(d.keys())
Out[279]: ['arr_2', 'arr_1', 'arr_0']
In [280]: d['arr_0']
Out[280]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

使用np.save(以及扩展名savez),数组以其自己的紧凑格式存储,该格式由具有形状信息的标题块和数据块组成,数据块本质上是一个字节副本它的数据缓冲区。因此,数组的np.save应该与任何其他方法一样有效。

如果你给np.save一个非数组对象,它将使用该对象的pickle方法。但请注意,数组的pickle方法是我刚才描述的save方法。因此,阵列的泡菜应该仍然有效。

请记住,npz文件是延迟加载的。

使用h5py,数组将保存到命名数据集。从某种意义上说,它就像上面的savez - 列表中的元素必须具有名称,无论是自动生成还是由代码生成。

我不知道h5py速度与save(z)的比较。

h5py可以处理一维中不规则的数组。我在以前的SO问题中探讨过这个问题。 Storing multidimensional variable length array with h5py

How to save list of numpy.arrays of different shape with h5py?