gpt4 book ai didi

python - 为什么我的 hdf5 文件看起来太大了?

转载 作者:行者123 更新时间:2023-12-05 04:55:56 25 4
gpt4 key购买 nike

我正在处理一个巨大的数据集(数百 GB),其中约有 4000 万个标识符存储为 32 个字符的字符串,每个标识符都有数百或数千行数字数据。

为了节省空间并提高从磁盘读取数据的效率,似乎最好不要在数据集中一遍又一遍地重复标识符。比如一张数据表,看起来像

verylongstringidentifier1, 1.2
verylongstringidentifier1, 2.3
verylongstringidentifier1, 3.4
.
.
verylongstringidentifier2, 2.1
verylongstringidentifier2, 1.0
.
.

如果字符串标识符不重复,则可以更有效地存储。一种选择是为每个标识符保存单独的文件,我可能会走这条路,但拥有数百万个单独的小文件有点烦人,而且从磁盘 I/O 的角度来看可能效率低下。

我对 hdf5 完全陌生,但我读到的内容表明它应该适用于这种情况,因为数据集可以使用标识符作为键来存储。但是,当我保存到一个 hdf5 文件时,生成的文件大约比我简单地写入一个平面 csv 文件时得到的文件大 40 倍。我是否遗漏了有关 hdf5 文件存储方式的信息,或者我只是做错了什么?下面的测试代码是我用来验证(并尝试诊断)问题的代码。

# trying to figure out why hdf5 file sizes are so huge
import time
import string
import random
import numpy as np
import pandas as pd
from pandas import HDFStore

# generate 1000 random 32-character strings
strings = [''.join(random.choices(string.ascii_lowercase, k=32)) for _ in range(1000)]

# for each of these random strings, create 200 rows of three random floats
# concatenate into one big dataframe
df = pd.DataFrame()
for s in strings:
vars = np.random.rand(200,3)
ss = np.full((200,1),s)
s_data = np.concatenate((ss, vars), axis=1)
df = pd.concat([df, pd.DataFrame(s_data)], axis=0)

df.columns = ['string', 'v1', 'v2', 'v3']

# write to one big csv file
df.to_csv('/tmp/test.csv', index=False)

# write to compressed bzip2 file
df.to_csv('/tmp/test.csv.bz2', index=False, compression='bz2')

# write to separate csv files for each string
unique_strings = df.string.unique()
for s in unique_strings:
s_chunk = df[df.string == s]
fname = '/tmp/test_' + s + '.csv.bz2'
# don't need to store the string, since it can be retrieved as the filename
s_chunk[['v1', 'v2', 'v3']].to_csv(fname, index=False, compression='bz2')

# write to hdf5 file with strings as keys
# what I'm trying to do here is *not* save the strings in the datasets, but instead
# use the strings as the names (keys) for the datasets
# My understanding is this would enable me to retrieve the data for a given string
# with pd.read_hdf(h5data, key=<string for which I want data>)
h5data = HDFStore('/tmp/test.h5')
for s in unique_strings:
s_chunk = df[df.string == s]
# don't need to store the string, because we'll use it as the key
s_chunk[['v1', 'v2', 'v3']].to_hdf(h5data, key=s, format='table', complib='bzip2')
h5data.close()

生成的文件大小:

 18M  /tmp/test.csv
4.7M /tmp/test.csv.bz2
80M /tmp/test.h5

最佳答案

发生这种情况的原因可能是 Pandas 将每个组/数据集的大量无关信息转储到 HDF5 文件中。当我运行您的代码并使用 HDFView 检查文件时, 这很明显。

我更喜欢使用 h5py用于创建和管理 HDF5 文件的库,因为它允许更加简单和控制。

我尝试使用 h5py 构建文件,其中每个组都被命名为一个唯一的字符串,并且在每个组内是 DataFrame 的每一列的数据集。我在您的脚本中使用了以下内容来写入 HDF5:

with h5py.File("/tmp/test.h5", "w") as h5data:
for s in unique_strings:
s_chunk = df[df.string == s]
# create group with name = string
g = h5data.create_group(s)
# create datasets within group for each data column
dset_v1 = g.create_dataset("v1", data=s_chunk["v1"].values.astype(np.float32), compression="gzip")
dset_v2 = g.create_dataset("v2", data=s_chunk["v2"].values.astype(np.float32), compression="gzip")
dset_v3 = g.create_dataset("v3", data=s_chunk["v3"].values.astype(np.float32), compression="gzip")

结果(注意我使用的是 gzip 而不是 bz2):

 18M    /tmp/test.csv
5.2M /tmp/test.csv.bz2
11M /tmp/test.h5

进一步的优化是在每个组中只有一个数据集,该数据集是一个二维数组。在这种情况下,三个 create_dataset 调用将被一个替换:

dset = g.create_dataset("data", data=s_chunk[["v1", "v2", "v3"]].values.astype(np.float32), compression="gzip")

结果:

 18M    /tmp/test.csv
5.0M /tmp/test.csv.bz2
6.0M /tmp/test.h5

使用 bz2 作为压缩会进一步缩小。

关于python - 为什么我的 hdf5 文件看起来太大了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65119241/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com