我不能让头或尾:我有一个函数,从S3桶读取一堆csv文件,连接它们并返回DataFrame:
def create_df():
df1 = pd.read_csv(s3_path + 'file_1.csv')
df2 = pd.read_csv(s3_path + 'file_2.csv')
return pd.concat([df1, df2], ignore_index=True)
第二个函数执行聚合:
def aggregate_values(df):
columns = ['col_c', 'col_d']
new_df = df.groupby(columns, as_index=False)
.agg({'col_a': 'sum', 'col_b': 'mean'})
return new_df
aggregate_values函数失败,原因是内存不足。
df = create_df()
# OOM error !!!
new_df = aggregate_values(df)
奇怪的是,如果我将DataFrame写入本地文件系统,然后再将其读入,聚合在新DataFrame上工作时不会出现故障。
df = create_df()
df.to_csv('path_to_store/f.csv', index=False)
df2 = pd.read_csv('path_to_store/f.csv')
# works fine!!!
new_df = aggregate_values(df2)
我猜是create_df()返回的DataFrame有问题。通过把它写出来并在Pandas中读回来,某种程度上纠正了这个问题。但是我想找出到底是什么问题与DataFrame。
如何调试这个问题?
我在运行代码的机器上有32G RAM。DataFrame大约有200万条记录,占用大约0.5G的存储和内存空间。
你没有评论你的内存大小,也不是csv文件或数据帧的大小。但我可以大胆猜测一下。我有一些观察:
- 连接后,您有机会核困难& &;df2。只需将
None
分配给它们,即可回收一些RAM。 - .groupby()可能接受密集的numpy数组并产生更高开销的稀疏数组。你可能需要调查一下。
- 计算平均值可能会把例如
int8
变成float64
,这显然会占用更多的空间。 - 这里是最大的项目:.groupby()可能返回一个(可变)视图,而不是一个全新的numpy数组。到文件系统的往返可以修复这个问题,但是简单的.copy()也会有同样的效果,所以请尝试一下。
请在这里发表答案,让我们知道它是如何进行的。
我发现了问题,结果是一个好问题。
create_df()返回的DataFrame中的一个列具有dtype类别。不确定这是怎么来的,因为它是字符串。该列在grouper中用于聚合。通过将DataFrame写入本地文件系统,然后再将其读入,该列被Pandas正确地重新解释为字符串。
使用正确的数据类型,聚合可以快速运行和返回,并且不存在任何内存问题。我不明白为什么在分类列上分组会导致OOM错误——这是另一天的主题。