在学习大熊猫的过程中,我试图解决这个问题的答案已有好几个月了。我使用 SAS 进行日常工作,这非常适合它的核心支持。然而,由于其他许多原因,SAS 作为一款软件非常糟糕。
有一天,我希望用 python 和 pandas 替换我对 SAS 的使用,但我目前缺乏大型数据集的核心工作流程。我不是在谈论需要分布式网络的 “大数据”,而是说文件太大而无法容纳在内存中,但又足够小以适应硬盘驱动器。
我的第一个想法是使用HDFStore
在磁盘上保存大型数据集,并仅将我需要的部分拉入数据帧进行分析。其他人提到 MongoDB 是一种更容易使用的替代品。我的问题是:
有哪些最佳实践工作流程可用于完成以下任务:
真实世界的例子将非常受欢迎,尤其是那些在 “大数据” 上使用熊猫的人。
编辑 - 我希望如何工作的示例:
我正在尝试找到执行这些步骤的最佳实践方法。阅读关于 pandas 和 pytables 的链接似乎附加一个新列可能是个问题。
编辑 - 特别回应杰夫的问题:
if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'
。这些操作的结果是我的数据集中每条记录的新列。 我很少会在数据集中添加行。我几乎总是会创建新的列(统计 / 机器学习用语中的变量或特征)。
我通常以这种方式使用数十亿字节的数据,例如我在磁盘上有表格,我通过查询读取,创建数据并追加。
值得阅读文档,并在本主题的后期提供有关如何存储数据的若干建议。
详细信息将影响您存储数据的方式,例如:
尽可能多地提供细节; 我可以帮你建立一个结构。
读取chunk-by-chunk和多个表查询的 迭代文件 。
由于 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 hmay 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)
当您准备好进行 post_processing 时:
# 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'])
在最终报告生成阶段,它们可能对您最感兴趣(实质上,数据列与其他列隔离,如果您定义了很多,这可能会影响效率)。
您可能还想:
如果您有疑问,请告诉我!
我认为上面的答案缺少一个我发现非常有用的简单方法。
当我的文件太大而无法加载到内存中时,我会将文件分解为多个较小的文件(按行或列)
示例:如果 30 天大小的交易数据为 30 天,我将其分成每天约 1GB 大小的文件。我随后分别处理每个文件并在最后汇总结果
其中一个最大的优点是它允许并行处理文件(多个线程或进程)
另一个优点是文件操作(如在示例中添加 / 删除日期)可以通过常规 shell 命令来完成,这在更高级 / 复杂的文件格式中是不可能的
这种方法并不涵盖所有场景,但在很多场景中非常有用
如果您的数据集在 1 到 20GB 之间,那么您应该得到一个具有 48GB RAM 的工作站。然后 Pandas 可以将整个数据集保存在 RAM 中。我知道这不是你在这里寻找的答案,但在 4GB 内存的笔记本电脑上进行科学计算是不合理的。