pandas pytables 追加:性能和文件大小增加

3 投票
1 回答
3233 浏览
提问于 2025-04-18 01:51

我有超过500个PyTables文件,每个文件大约有300Mb的数据。我想把这些文件合并成一个大的文件,使用pandas的append方法,像下面的代码那样。

def merge_hdfs(file_list, merged_store):
    for file in file_list:
        store = HDFStore(file, mode='r')
        merged_store.append('data', store.data)
        store.close()

但是,使用append这个操作非常慢(把一个文件添加到merged_store里要花上10分钟),而且奇怪的是,merged_store的文件大小似乎每添加一个文件就增加1Gb。

我已经指明了预期的总行数,根据文档说这样应该能提高性能。我还看过提高pandas (PyTables?) HDF5表写入性能的内容,原本以为写入时间会很长,但每300Mb的数据几乎要10分钟,这似乎太慢了,而且我不明白为什么文件大小会增加。

我在想是不是我漏掉了什么?

另外,这里有一个500个PyTables中某一个的描述。

/data/table (Table(272734,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "values_block_0": Float64Col(shape=(6,), dflt=0.0, pos=1),
  "id": StringCol(itemsize=11, shape=(), dflt='', pos=2),
  "datetaken": Int64Col(shape=(), dflt=0, pos=3),
  "owner": StringCol(itemsize=15, shape=(), dflt='', pos=4),
  "machine_tags": StringCol(itemsize=100, shape=(), dflt='', pos=5),
  "title": StringCol(itemsize=200, shape=(), dflt='', pos=6),
  "country": StringCol(itemsize=3, shape=(), dflt='', pos=7),
  "place_id": StringCol(itemsize=18, shape=(), dflt='', pos=8),
  "url_s": StringCol(itemsize=80, shape=(), dflt='', pos=9),
  "url_o": StringCol(itemsize=80, shape=(), dflt='', pos=10),
  "ownername": StringCol(itemsize=50, shape=(), dflt='', pos=11),
  "tags": StringCol(itemsize=505, shape=(), dflt='', pos=12)}
  byteorder := 'little'
  chunkshape := (232,)

1 个回答

3

这基本上就是我最近回答的一个问题的答案,详细内容可以在这里找到。

简单来说,你需要在创建存储的时候关闭索引功能,使用 store.append('df',df,index=False)。然后在最后再进行索引。

而且在合并表格的时候,也要关闭压缩功能。

索引操作是比较耗费资源的,而且如果我没记错的话,它只会使用一个处理器。

最后,确保在创建合并文件的时候使用 mode='w',因为后面的操作都是追加内容,你想要从一个干净的新文件开始。

我也不建议你提前指定 chunksize。相反,在你创建完最终索引后,使用 ptrepack 来进行压缩,并指定 chunksize=auto,这样系统会自动计算这个值。我认为这不会影响写入性能,但会优化查询性能。

你也可以尝试把 appendchunksize 参数调大一些(这是写入的块大小)。

当然,要确保每个追加的表格结构完全相同(如果不相同会报错)。

我为这个问题创建了一个改进建议,想要在内部实现这个功能:https://github.com/pydata/pandas/issues/6837

撰写回答