我经常以这种方式使用数十 GB 的数据,例如,我在磁盘上有表,我通过查询读取、创建数据并附加回来。
值得阅读文档,并在此线程的后期获取有关如何存储数据的一些建议。
会影响您如何存储数据的详细信息,例如:
提供尽可能多的详细信息;我可以帮助你开发一个结构。
- 数据大小、行数、列数、列类型;你是追加行,还是只是列?
- 典型的操作会是什么样子。例如,对列进行查询以选择一堆行和特定列,然后执行操作(在内存中),创建新列,保存这些。
(举一个玩具例子可以让我们提供更具体的建议。)
- 处理完之后,你会做什么?第 2 步是临时的还是可重复的?
- 输入平面文件:多少,以 Gb 为单位的粗略总大小。这些是如何组织的,例如按记录?每个文件是否包含不同的字段,还是每个文件都有一些记录以及每个文件中的所有字段?
- 您是否曾经根据标准选择行(记录)的子集(例如选择字段 A > 5 的行)?然后做一些事情,或者你只是选择所有记录的字段A,B,C(然后做一些事情)?
- 您是否“处理”所有列(分组),或者是否有一个很好的比例只能用于报告(例如,您想保留数据,但不需要明确地拉入该列,直到最终结果时间)?
解决方案
确保您至少0.10.1
安装了 pandas。
逐块读取迭代文件和多个表查询。
由于 pytables 被优化为按行操作(这是您查询的内容),我们将为每组字段创建一个表。这种方式很容易选择一小组字段(这将适用于一个大表,但这样做更有效......我想我将来可能能够解决这个限制......这是无论如何更直观):(
以下是伪代码。)
import numpy as np
import pandas as pd
# create a store
store = pd.HDFStore('mystore.h5')
# this is the key to your storage:
# this maps your fields to a specific group, and defines
# what you want to have as data_columns.
# you might want to create a nice class wrapping this
# (as you will want to have this map and its inversion)
group_map = dict(
A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
B = dict(fields = ['field_10',...... ], dc = ['field_10']),
.....
REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),
)
group_map_inverted = dict()
for g, v in group_map.items():
group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))
读入文件并创建存储(主要是做什么append_to_multiple
):
for f in files:
# read in the file, additional options may be necessary here
# the chunksize is not strictly necessary, you may be able to slurp each
# file into memory in which case just eliminate this part of the loop
# (you can also change chunksize if necessary)
for chunk in pd.read_table(f, chunksize=50000):
# we are going to append to each table by group
# we are not going to create indexes at this time
# but we *ARE* going to create (some) data_columns
# figure out the field groupings
for g, v in group_map.items():
# create the frame for this group
frame = chunk.reindex(columns = v['fields'], copy = False)
# append it
store.append(g, frame, index=False, data_columns = v['dc'])
现在您在文件中拥有了所有表(实际上,如果您愿意,您可以将它们存储在单独的文件中,您可能必须将文件名添加到 group_map,但这可能不是必需的)。
这是获取列和创建新列的方式:
frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
# select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows
# do calculations on this frame
new_frame = cool_function_on_frame(frame)
# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)
当您准备好进行后期处理时:
# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)
关于 data_columns,您实际上不需要定义任何data_columns;它们允许您根据列子选择行。例如:
store.select(group, where = ['field_1000=foo', 'field_1001>0'])
在最终报告生成阶段,它们可能对您最感兴趣(本质上,一个数据列与其他列分离,如果您定义很多,这可能会在一定程度上影响效率)。
您可能还想:
- 创建一个函数,该函数采用字段列表,在 groups_map 中查找组,然后选择这些并连接结果,以便获得结果帧(这本质上是 select_as_multiple 所做的)。这样,结构对您来说将是非常透明的。
- 某些数据列的索引(使行子集更快)。
- 启用压缩。
有问题时告诉我!