在更新到panda v0.25.2之后,一个脚本在一个大的 Dataframe 上的许多列上执行groupby操作不再起作用。我得到一个内存错误
MemoryError: Unable to allocate array with shape (some huge number...,) and data type int64
我做了一些研究,发现Git的早期版本报告了问题(#14942
import numpy as np
import pandas as pd
df = pd.DataFrame({
'cat': np.random.randint(0, 255, size=3000000),
'int_id': np.random.randint(0, 255, size=3000000),
'other_id': np.random.randint(0, 10000, size=3000000),
'foo': 0
})
df['cat'] = df.cat.astype(str).astype('category')
# killed after 6 minutes of 100% cpu and 90G maximum main memory usage
grouped = df.groupby(['cat', 'int_id', 'other_id']).count()
运行这段代码(在0.25.2版本上)也会出现内存错误。是我做错了什么(Pandasv0.25中的语法改变了吗?),还是这个标记为已解决的问题又回来了?
2条答案
按热度按时间9jyewag01#
使用
observed=True
来修复它,并防止groupby展开所有可能的因子变量组合:有一个相关的 *GitHub问题 *:PERF: groupby with many empty groups memory blowup .
tcbh2hod2#
虽然所提出的解决方案解决了该问题,但是当处理较大的数据集时,可能会出现另一个问题。
pandas groupby
速度慢并且需要存储器;可能需要5 - 10倍的数据集内存。一个更有效的解决方案是使用一个数量级更快、内存消耗更少并且seamlessly integrates with pandas
;它直接从 Dataframe 内存中读取。不需要数据往返,通常也不需要大量的数据分块。我选择的新的快速数据聚合工具是https://duckdb.org。它直接获取你现有的 Dataframe df并对其进行查询,甚至不需要将其导入数据库。下面是一个使用你的 Dataframe 生成代码的最终结果示例。请注意,总时间是0.45秒。不知道为什么Pandas不使用DuckDB进行幕后的groupby。
db对象是使用这个小 Package 器类创建的,您只需键入db = DuckDB(),就可以浏览任何项目中的数据。您可以进一步扩展它,甚至可以使用% sql简化它。在这里输入链接描述。2顺便说一句,sql返回一个 Dataframe ,所以你也可以做db. sql(...). pivot_table(...)就是这么简单。
注:DuckDB很好但并不完美,但它比Dusk甚至PySpark更稳定,设置也更简单。对于更大的数据集,您可能需要一个真正的数据库,但对于可以容纳在内存中的数据集,这是很好的。关于内存使用,如果您有一个更大数据集,请确保使用杂注限制DuckDB,因为它会立即将其全部吃掉。限制只是将额外的数据放到磁盘上,而不处理数据分块。也不要假设这是一个数据库。假设这是内存中的数据库,如果你需要存储一些结果,然后将它们导出到 parquet 中,而不是保存数据库。因为不同版本之间的格式不稳定,所以无论如何都必须导出到parquet才能从一个版本移动到下一个版本。
我把这个数据框扩展到3亿条记录,所以总共有大约12亿条记录或大约9GB。它仍然完成了你的groupby和其他总结统计在32GB的机器上18GB仍然是免费的。