- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在处理大型 3D 数组,我经常需要以各种方式对其进行切片以进行各种数据分析。一个典型的“立方体”大约为 100GB(将来可能会变得更大)
似乎python中大型数据集的典型推荐文件格式是使用HDF5(h5py或pytables)。我的问题是:与将它们存储在简单的平面二进制文件中相比,使用 HDF5 来存储和分析这些多维数据集在速度或内存使用方面是否有任何好处? HDF5 是否更适合表格数据,而不是像我正在使用的大型数组?我看到 HDF5 可以提供很好的压缩,但我对处理速度和处理内存溢出更感兴趣。
我经常只想分析多维数据集的一个大子集。 pytables 和 h5py 的一个缺点是,当我取数组的一部分时,我总是得到一个 numpy 数组,从而耗尽内存。但是,如果我将平面二进制文件的 numpy memmap 切片,我可以获得一个 View ,它将数据保存在磁盘上。因此,似乎我可以更轻松地分析数据的特定部分,而不会超出我的内存。
我已经探索了 pytables 和 h5py,到目前为止还没有看到它们对我的目的的好处。
最佳答案
HDF5 优点:组织性、灵活性、互操作性
HDF5 的一些主要优点是它的层次结构(类似于文件夹/文件)、与每个项目一起存储的可选的任意元数据,以及它的灵活性(例如压缩)。这种组织结构和元数据存储可能听起来微不足道,但在实践中却非常有用。
HDF 的另一个优点是数据集可以是固定大小的,也可以是灵活大小的。因此,可以轻松地将数据附加到大型数据集,而无需创建全新的副本。
此外,HDF5 是一种标准化格式,其库几乎可用于任何语言,因此在 Matlab、Fortran、R、C 和 Python 之间共享磁盘数据非常容易,使用 HDF。 (公平地说,使用大的二进制数组也不是太难,只要您知道 C 与 F 的排序并知道存储数组的形状、dtype 等。)
大型阵列的 HDF 优势:任意切片的更快 I/O
就像 TL/DR:对于约 8GB 的 3D 阵列,使用分块的 HDF5 数据集沿任何轴读取“完整”切片需要约 20 秒,对于相同数据的 memapped 阵列需要 0.3 秒(最佳情况)到三个多小时(最坏情况) .
除了上面列出的内容之外,“分块”* 磁盘数据格式(例如 HDF5)还有另一个很大的优势:读取任意切片(强调任意)通常会快得多,因为磁盘数据在平均。*
(HDF5 不必是分块数据格式。它支持分块,但不需要它。事实上,如果我没记错的话,在 h5py
中创建数据集的默认设置不是分块。)
基本上,对于数据集的给定切片,最佳情况下的磁盘读取速度和最坏情况下的磁盘读取速度将与分块 HDF 数据集相当接近(假设您选择了合理的块大小或让库为您选择一个)。使用简单的二进制数组,最好的情况会更快,但最坏的情况要糟糕得多。
一个警告,如果你有一个 SSD,你可能不会注意到读/写速度的巨大差异。但是,对于普通硬盘,顺序读取比随机读取快得多。 (即普通硬盘驱动器的 seek
时间很长。)HDF 在 SSD 上仍然具有优势,但更多是由于其其他功能(例如元数据、组织等)而不是原始速度。
首先,为了消除混淆,访问 h5py
dataset 返回一个对象,它的行为与 numpy 数组非常相似,但在数据被切片之前不会将数据加载到内存中。 (类似于 memmap,但不完全相同。)查看 h5py
introduction了解更多信息。
切片数据集会将数据的一个子集加载到内存中,但大概您想用它做一些事情,此时无论如何您都需要在内存中使用它。
如果你确实想做核外计算,你可以很容易地使用 pandas
来处理表格数据。或 pytables
.可以使用 h5py
(对于大型 N 维数组更好),但您需要下降到较低的级别并自己处理迭代。
然而,类似 numpy 的核外计算的 future 是 Blaze。 Have a look at it如果你真的想走那条路。
“未解决”的案例
首先,考虑一个写入磁盘的 3D C 序数组(我将通过调用 arr.ravel()
来模拟它并打印结果,以使事情更明显):
In [1]: import numpy as np
In [2]: arr = np.arange(4*6*6).reshape(4,6,6)
In [3]: arr
Out[3]:
array([[[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[ 12, 13, 14, 15, 16, 17],
[ 18, 19, 20, 21, 22, 23],
[ 24, 25, 26, 27, 28, 29],
[ 30, 31, 32, 33, 34, 35]],
[[ 36, 37, 38, 39, 40, 41],
[ 42, 43, 44, 45, 46, 47],
[ 48, 49, 50, 51, 52, 53],
[ 54, 55, 56, 57, 58, 59],
[ 60, 61, 62, 63, 64, 65],
[ 66, 67, 68, 69, 70, 71]],
[[ 72, 73, 74, 75, 76, 77],
[ 78, 79, 80, 81, 82, 83],
[ 84, 85, 86, 87, 88, 89],
[ 90, 91, 92, 93, 94, 95],
[ 96, 97, 98, 99, 100, 101],
[102, 103, 104, 105, 106, 107]],
[[108, 109, 110, 111, 112, 113],
[114, 115, 116, 117, 118, 119],
[120, 121, 122, 123, 124, 125],
[126, 127, 128, 129, 130, 131],
[132, 133, 134, 135, 136, 137],
[138, 139, 140, 141, 142, 143]]])
In [4]: arr.ravel(order='C')
Out[4]:
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143])
In [5]: arr[0,:,:]
Out[5]:
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]])
seek
操作。如果我们要阅读的只是沿该轴的不同切片,那么这就是完美的文件结构。
In [6]: arr[:,:,0]
Out[6]:
array([[ 0, 6, 12, 18, 24, 30],
[ 36, 42, 48, 54, 60, 66],
[ 72, 78, 84, 90, 96, 102],
[108, 114, 120, 126, 132, 138]])
seek
的数量和大小业务增长迅速。对于以这种方式存储并通过
memmap
读取的大型(~10Gb)3D 阵列,即使使用现代硬件,沿“最差”轴读取完整切片也很容易花费数十分钟。同时,沿最佳轴的切片可能需要不到一秒钟的时间。为简单起见,我仅沿单个轴显示“完整”切片,但完全相同的事情发生在数据的任何子集的任意切片上。
nx, ny, nz = arr.shape
slices = []
for i in range(0, nx, 2):
for j in range(0, ny, 2):
for k in range(0, nz, 2):
slices.append((slice(i, i+2), slice(j, j+2), slice(k, k+2)))
chunked = np.hstack([arr[chunk].ravel() for chunk in slices])
chunked
:
array([ 0, 1, 6, 7, 36, 37, 42, 43, 2, 3, 8, 9, 38,
39, 44, 45, 4, 5, 10, 11, 40, 41, 46, 47, 12, 13,
18, 19, 48, 49, 54, 55, 14, 15, 20, 21, 50, 51, 56,
57, 16, 17, 22, 23, 52, 53, 58, 59, 24, 25, 30, 31,
60, 61, 66, 67, 26, 27, 32, 33, 62, 63, 68, 69, 28,
29, 34, 35, 64, 65, 70, 71, 72, 73, 78, 79, 108, 109,
114, 115, 74, 75, 80, 81, 110, 111, 116, 117, 76, 77, 82,
83, 112, 113, 118, 119, 84, 85, 90, 91, 120, 121, 126, 127,
86, 87, 92, 93, 122, 123, 128, 129, 88, 89, 94, 95, 124,
125, 130, 131, 96, 97, 102, 103, 132, 133, 138, 139, 98, 99,
104, 105, 134, 135, 140, 141, 100, 101, 106, 107, 136, 137, 142, 143])
arr
的 2x2x2 块,请注意这些是
chunked
的前 8 个值:
In [9]: arr[:2, :2, :2]
Out[9]:
array([[[ 0, 1],
[ 6, 7]],
[[36, 37],
[42, 43]]])
h5py
的分块数组
h5py
不会在磁盘上创建分块的 HDF 文件(相比之下,我认为
pytables
会)。如果您指定
chunks=True
但是,在创建数据集时,您将在磁盘上获得一个分块数组。
import numpy as np
import h5py
data = np.random.random((100, 100, 100))
with h5py.File('test.hdf', 'w') as outfile:
dset = outfile.create_dataset('a_descriptive_name', data=data, chunks=True)
dset.attrs['some key'] = 'Did you want some metadata?'
chunks=True
告诉
h5py
自动为我们选择一个块大小。如果您对最常见的用例了解更多,则可以通过指定形状元组来优化块大小/形状(例如,上面简单示例中的
(2,2,2)
)。这使您可以更高效地沿特定轴读取或优化特定大小的读取/写入。
hdf
文件)。我无法轻松共享此处使用的数据,但您可以通过相同形状的零数组(
621, 4991, 2600)
和类型
np.uint8
)来模拟它。
chunked_hdf.py
看起来像这样:
import sys
import h5py
def main():
data = read()
if sys.argv[1] == 'x':
x_slice(data)
elif sys.argv[1] == 'z':
z_slice(data)
def read():
f = h5py.File('/tmp/test.hdf5', 'r')
return f['seismic_volume']
def z_slice(data):
return data[:,:,0]
def x_slice(data):
return data[0,:,:]
main()
memmapped_array.py
是类似的,但为了确保切片实际加载到内存中具有更高的复杂性(默认情况下,将返回另一个
memmapped
数组,这不会是一个苹果对苹果的比较)。
import numpy as np
import sys
def main():
data = read()
if sys.argv[1] == 'x':
x_slice(data)
elif sys.argv[1] == 'z':
z_slice(data)
def read():
big_binary_filename = '/data/nankai/data/Volumes/kumdep01_flipY.3dv.vol'
shape = 621, 4991, 2600
header_len = 3072
data = np.memmap(filename=big_binary_filename, mode='r', offset=header_len,
order='F', shape=shape, dtype=np.uint8)
return data
def z_slice(data):
dat = np.empty(data.shape[:2], dtype=data.dtype)
dat[:] = data[:,:,0]
return dat
def x_slice(data):
dat = np.empty(data.shape[1:], dtype=data.dtype)
dat[:] = data[0,:,:]
return dat
main()
jofer at cornbread in ~
$ sudo ./clear_cache.sh
jofer at cornbread in ~
$ time python chunked_hdf.py z
python chunked_hdf.py z 0.64s user 0.28s system 3% cpu 23.800 total
jofer at cornbread in ~
$ sudo ./clear_cache.sh
jofer at cornbread in ~
$ time python chunked_hdf.py x
python chunked_hdf.py x 0.12s user 0.30s system 1% cpu 21.856 total
jofer at cornbread in ~
$ sudo ./clear_cache.sh
jofer at cornbread in ~
$ time python memmapped_array.py z
python memmapped_array.py z 0.07s user 0.04s system 28% cpu 0.385 total
jofer at cornbread in ~
$ sudo ./clear_cache.sh
jofer at cornbread in ~
$ time python memmapped_array.py x
python memmapped_array.py x 2.46s user 37.24s system 0% cpu 3:35:26.85 total
关于python - 将 HDF5 用于大型阵列存储(而不是平面二进制文件)是否具有分析速度或内存使用优势?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27710245/
我正在运行一个辅助角色,并检查 Azure 上托管的存储中是否存在数据。当我将连接字符串用于经典类型的存储时,我的代码可以正常工作,但是当我连接到 V2 Azure 存储时,它会抛出此异常。 “远程服
在我的应用程序的主页上,我正在进行 AJAX 调用以获取应用程序各个部分所需的大量数据。该调用如下所示: var url = "/Taxonomy/GetTaxonomyList/" $.getJSO
大家好,我正在尝试将我的商店导入我的 Vuex Route-Gard。 路由器/auth-guard.js import {store} from '../store' export default
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我的 Windows 计算机上的本地文件夹中有一些图像。我想将所有图像上传到同一容器中的同一 blob。 我知道如何使用 Azure Storage SDKs 上传单个文件BlockBlobServi
我尝试发出 GET 请求来获取我的 Azure Blob 存储帐户的帐户详细信息,但每次都显示身份验证失败。谁能判断形成的 header 或签名字符串是否正确或是否存在其他问题? 代码如下: cons
这是用于编写 JSON 的 NeutralinoJS 存储 API。是否可以更新 JSON 文件(推送数据),而不仅仅是用新的 JS 对象覆盖数据。怎么做到的??? // Javascript
我有一个并行阶段设置,想知道是否可以在嵌套阶段之前运行脚本,所以像这样: stage('E2E-PR-CYPRESS') { when { allOf {
我想从命令行而不是从GUI列出VirtualBox VM的详细信息。我对存储细节特别感兴趣。 当我在GUI中单击VM时,可以看到包括存储部分在内的详细信息: 但是到目前为止,我还没有找到通过命令行执行
我有大约 3500 个防洪设施,我想将它们表示为一个网络来确定流动路径(本质上是一个有向图)。我目前正在使用 SqlServer 和 CTE 来递归检查所有节点及其上游组件,只要上游路径没有 fork
谁能告诉我 jquery data() 在哪里存储数据以及何时删除以及如何删除? 如果我用它来存储ajax调用结果,会有性能问题吗? 例如: $("body").data("test", { myDa
有人可以建议如何为 Firebase 存储中的文件设置备份。我能够备份数据库,但不确定如何为 firebase 存储中的文件(我有图像)设置定期备份。 最佳答案 如何进行 Firebase 存储的本地
我最近开始使用 firebase 存储和 firebase 功能。现在我一直在开发从功能到存储的文件上传。 我已经让它工作了(上传完成并且文件出现在存储部分),但是,图像永远保持这样(永远在右侧加载)
我想只允许用户将文件上传到他们自己的存储桶中,最大文件大小为 1MB,仍然允许他们删除文件。我添加了以下内容: match /myusers/{userId}/{allPaths=**} { al
使用生命周期管理策略将容器的内容从冷访问层移动到存档。我正在尝试以下策略,希望它能在一天后将该容器中的所有文件移动到存档层,但事实并非如此在职的。我设置了选择标准“一天未使用后”。 这是 json 代
对于连接到 Azure 存储端点,有 http 和 https 两个选项。 第一。 https 会带来开销,可能是 5%-10%,但我不支付同一个数据中心的费用。 第二。 http 更快,但 Auth
有人可以帮我理解这一点吗?我创建了Virtual Machine in Azure running Windows Server 2012 。我注意到 Azure 自动创建了一个存储帐户。当我进入该存
我是一名优秀的程序员,十分优秀!