簡體   English   中英

Python-將HDF5數據集讀入列表與numpy數組

[英]Python - Reading HDF5 dataset into a list vs numpy array

我一直在探索HDF5及其python接口(h5py),所以我嘗試將HDF5文件(一億個整數的一維數組)讀入:一個普通列表,另一個時間讀取到numpy數組。 與我嘗試將數據集轉換為普通python列表時相比,將數據集轉換為numpy的速度非常快(實際上,使用列表進行處理花費了很長時間,因此我不得不在完成之前將其殺死)。

有誰能幫助我了解內部發生的事情,這使得將HDF5數據集轉換為numpy數組的速度比使用普通列表快得多嗎? 它與numpy的h5py兼容性有關嗎?

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'])

謝謝您的幫助!

使用我最近創建的測試文件:

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數組。

然后,要獲取列表,您必須將數組轉換為列表。 對於一維數組, 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 ,則首先必須將其轉換為數組。

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相比非常快速。

我不確定您看到的差異是特定於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進行了略微簡化,numpy將它們“按原樣”存儲為一塊內存,而列表為每個項目創建了一個python對象。 在這種情況下,python對象由值,指向其類型對象的指針和引用計數組成。 因此,總而言之,numpy實際上只能復制一個內存塊,而list必須分配並創建所有這些對象和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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM