Python - 将 HDF5 数据集读入列表与 numpy 数组
Python - Reading HDF5 dataset into a list vs numpy array
我一直在探索 HDF5 及其 python 接口 (h5py),所以我尝试将 HDF5 文件(一亿个整数的一维数组)读入:一个普通列表,另一次读入一个 numpy大批。与我尝试将其转换为普通 python 列表时相比,将数据集转换为 numpy 非常快(实际上使用列表进行操作花费了很长时间,我不得不在它完成之前将其杀死)。
任何人都可以帮助我理解内部发生了什么,使得将 HDF5 数据集转换为 numpy 数组比使用普通列表更快吗?是否与 h5py 与 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'])
感谢您的帮助!
HDF5 是一种用于存储大量科学阵列数据的文件格式。它可以存储多个数据集,并提供多个即时压缩模型,使具有重复模式的数据能够更有效地存储。
通常使用 Pandas 或 Numpy 解析它会更快,因为它们以矢量化形式处理压缩,而本机 Python list
通过嵌套处理压缩,这非常重要较慢。
基本上就是这样。
下面是一个使用pandas
和Numpy
的实验,在后台生成一个包含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
相比非常快。
使用我最近创建的测试文件:
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
)。例如,它不能存储对象数据类型数组。如果要将列表保存为 HDF5
,首先必须将其转换为数组。
我不确定您看到的差异是否特定于 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 将它们 'as they are' 存储为内存块,而列表会为每个项目创建一个 python 对象。本例中的 python 对象由值、指向其类型对象的指针和引用计数组成。因此,总而言之,numpy 本质上只能复制一块内存,而 list 必须分配和创建所有这些对象和列表容器。
不利的一面是,从列表访问单个元素更快,因为 - 除其他事项外 - 现在数组必须创建一个 python 对象,而列表可以简单地 return 它的对象已存储:
>>> 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
我一直在探索 HDF5 及其 python 接口 (h5py),所以我尝试将 HDF5 文件(一亿个整数的一维数组)读入:一个普通列表,另一次读入一个 numpy大批。与我尝试将其转换为普通 python 列表时相比,将数据集转换为 numpy 非常快(实际上使用列表进行操作花费了很长时间,我不得不在它完成之前将其杀死)。
任何人都可以帮助我理解内部发生了什么,使得将 HDF5 数据集转换为 numpy 数组比使用普通列表更快吗?是否与 h5py 与 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'])
感谢您的帮助!
HDF5 是一种用于存储大量科学阵列数据的文件格式。它可以存储多个数据集,并提供多个即时压缩模型,使具有重复模式的数据能够更有效地存储。
通常使用 Pandas 或 Numpy 解析它会更快,因为它们以矢量化形式处理压缩,而本机 Python list
通过嵌套处理压缩,这非常重要较慢。
基本上就是这样。
下面是一个使用pandas
和Numpy
的实验,在后台生成一个包含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
相比非常快。
使用我最近创建的测试文件:
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
)。例如,它不能存储对象数据类型数组。如果要将列表保存为 HDF5
,首先必须将其转换为数组。
我不确定您看到的差异是否特定于 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 将它们 'as they are' 存储为内存块,而列表会为每个项目创建一个 python 对象。本例中的 python 对象由值、指向其类型对象的指针和引用计数组成。因此,总而言之,numpy 本质上只能复制一块内存,而 list 必须分配和创建所有这些对象和列表容器。
不利的一面是,从列表访问单个元素更快,因为 - 除其他事项外 - 现在数组必须创建一个 python 对象,而列表可以简单地 return 它的对象已存储:
>>> 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