将大型csv文件转换为hdf5格式

31

我有一个100M行的csv文件(实际上是许多单独的csv文件),总共84GB。我需要将其转换为一个带有单个浮点数据集的HDF5文件。在测试中,我使用了h5py而没有遇到任何问题,但现在我无法完成最终数据集,因为内存不足。

如何在不必将整个数据集存储在内存中的情况下写入HDF5?我希望看到实际的代码,因为它应该很简单。

我刚刚研究了pytables,但看起来数组类(对应于HDF5数据集)不能被迭代地写入。同样,pandas 在其io_tools中具有read_csvto_hdf方法,但我无法一次加载整个数据集,因此这种方法行不通。也许你可以通过pytables或pandas中的其他工具帮助我正确解决这个问题。

3个回答

39

to_hdf的调用中使用append=True:

import numpy as np
import pandas as pd

filename = '/tmp/test.h5'

df = pd.DataFrame(np.arange(10).reshape((5,2)), columns=['A', 'B'])
print(df)
#    A  B
# 0  0  1
# 1  2  3
# 2  4  5
# 3  6  7
# 4  8  9

# Save to HDF5
df.to_hdf(filename, 'data', mode='w', format='table')
del df    # allow df to be garbage collected

# Append more data
df2 = pd.DataFrame(np.arange(10).reshape((5,2))*10, columns=['A', 'B'])
df2.to_hdf(filename, 'data', append=True)

print(pd.read_hdf(filename, 'data'))
产出。
    A   B
0   0   1
1   2   3
2   4   5
3   6   7
4   8   9
0   0  10
1  20  30
2  40  50
3  60  70
4  80  90
请在第一次调用df.to_hdf时使用format='table'以使表可附加。否则,默认的格式为'fixed',这更快地读写,但会创建一个无法附加的表。
因此,您可以逐个处理每个CSV文件,使用append=True构建hdf5文件。然后覆盖DataFrame或使用del df允许旧的DataFrame被垃圾回收。
另外,您可以选择直接附加到HDFStore而不是调用df.to_hdf
import numpy as np
import pandas as pd

filename = '/tmp/test.h5'
store = pd.HDFStore(filename)

for i in range(2):
    df = pd.DataFrame(np.arange(10).reshape((5,2)) * 10**i, columns=['A', 'B'])
    store.append('data', df)

store.close()

store = pd.HDFStore(filename)
data = store['data']
print(data)
store.close()
产出。
    A   B
0   0   1
1   2   3
2   4   5
3   6   7
4   8   9
0   0  10
1  20  30
2  40  50
3  60  70
4  80  90

6
这可以通过PyTables实现。不过,您需要使用EArray类。
例如,以下是我编写的脚本示例,用于将分块训练数据从.npy文件导入到单个.h5文件中。
import numpy
import tables
import os

training_data = tables.open_file('nn_training.h5', mode='w')
a = tables.Float64Atom()
bl_filter = tables.Filters(5, 'blosc')   # fast compressor at a moderate setting

training_input =  training_data.create_earray(training_data.root, 'X', a,
                                             (0, 1323), 'Training Input',
                                             bl_filter, 4000000)
training_output = training_data.create_earray(training_data.root, 'Y', a,
                                             (0, 27), 'Training Output',
                                             bl_filter, 4000000)

for filename in os.listdir('input'):
    print "loading {}...".format(filename)
    a = numpy.load(os.path.join('input', filename))
    print "writing to h5"
    training_input.append(a)

for filename in os.listdir('output'):
    print "loading {}...".format(filename)
    training_output.append(numpy.load(os.path.join('output', filename)))

请查看文档以获取详细说明,但简要来说,create_earray函数需要以下参数:1)数据根或父节点;2)数组名称;3)数据类型原子;4)形状,其中在您想要扩展的维度中有一个0;5)详细描述;6)压缩过滤器;7)可扩展维度上预期的行数。只有前两个是必需的,但在实践中您可能会使用所有七个。该函数还接受一些其他可选参数;同样,请参阅文档以了解详情。
创建数组后,您可以按预期方式使用其append方法。

3

如果你有一个非常大的CSV文件,你可能想要将转换流到hdf,例如:

import numpy as np
import pandas as pd
from IPython.display import clear_output

CHUNK_SIZE = 5000000 

filename = 'data.csv'
dtypes = {'latitude': float, 'longitude': float}

iter_csv = pd.read_csv(
    filename, iterator=True,
    dtype=dtypes, encoding='utf-8', chunksize=CHUNK_SIZE)

cnt = 0
for ix, chunk in enumerate(iter_csv):
    chunk.to_hdf(
        "data.hdf", 'data', format='table', append=True)
    cnt += CHUNK_SIZE
    clear_output(wait=True)
    print(f"Processed {cnt:,.0f} coordinates..")

已测试使用64GB大小的CSV文件和4.5亿个坐标点(大约10分钟转换完成)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接