在Pandas中连接两个大型数据集的最佳方法

23

我正在从两个不同的数据库中下载两个数据集,需要将它们连接起来。当我将它们分别存储为CSV文件时,每个文件的大小约为500MB。分别载入内存没有问题,但是当我同时载入两个文件时,有时会出现内存错误。当我使用pandas合并它们时,我肯定会遇到麻烦。

有什么最好的方法可以对它们进行外部连接(outer join),以避免内存错误?我手头没有任何数据库服务器,但如果有帮助的话,我可以在我的计算机上安装任何开源软件。理想情况下,我仍然希望仅使用pandas解决它,但不确定这是否可能。

为了澄清:合并指的是外部连接。每个表都有两行:产品和版本。我想检查左表、右表和两个表中都有哪些产品和版本。我用以下代码实现:

pd.merge(df1,df2,left_on=['product','version'],right_on=['product','version'], how='outer')

你正在使用哪个操作系统? - user2027202827
请更详细地说明您期望此程序执行什么操作,以及加入应在哪些字段上进行。最好的情况是,您可以将两个CSV文件合并在一起(逐行合并)。此外,如果您能发布导致内存错误的代码,这将非常有帮助。 - Simon Kirsten
我已经在原来的问题上添加了更多细节。 - Nickpick
2个回答

36
这似乎是dask设计出来的任务。基本上,dask可以在外部处理pandas操作,因此您可以处理无法装入内存的数据集。 dask.dataframe API是pandas API的一个子集,因此学习曲线不应该太陡峭。请参阅Dask DataFrame Overview页面获取一些附加的面向DataFrame的详细信息。
import dask.dataframe as dd

# Read in the csv files.
df1 = dd.read_csv('file1.csv')
df2 = dd.read_csv('file2.csv')

# Merge the csv files.
df = dd.merge(df1, df2, how='outer', on=['product','version'])

# Write the output.
df.to_csv('file3.csv', index=False)

假设只有'product''version'两列,替换merge可能更有效率的方法是:
df = dd.concat([df1, df2]).drop_duplicates()

我不确定这样做是否会更好,但显然在 dask 中没有在索引上完成的合并速度较慢,所以值得一试。


太好了,但如果df1也无法适应内存怎么办? - Nickpick
2
这就是 dask 的全部意义所在。它可以进行外部操作,因此您可以处理不适合内存的数据。它基本上将方便数据集的大小从“适合内存”扩展到“适合磁盘”。 - root
有没有办法使用大型数据框来制作数据透视表?Dask似乎没有提供这个功能。 - Nickpick
2
Dask 似乎非常容易出现错误。即使是简单的合并操作也会出现错误信息。列名以 \r 结尾等。有没有其他替代方案? - Nickpick
1
Dask正在开发中,它也不支持多索引。 :( - Diego Queiroz

1
我建议您使用像MySQL这样的关系型数据库管理系统来实现这个功能...
因此,您需要先将CSV文件加载到表格中。
之后,您可以执行以下检查:
哪些产品和版本仅在左侧表格中存在。
SELECT a.product, a.version
FROM table_a a
LEFT JOIN table_b b
ON a.product = b.product AND a.version = b.version
WHERE b.product IS NULL;

哪些产品和版本仅出现在右表中?
SELECT b.product, b.version
FROM table_a a
RIGHT JOIN table_b b
ON a.product = b.product AND a.version = b.version
WHERE a.product IS NULL;

双方都在
SELECT a.product, a.version
FROM table_a a
JOIN table_b b
ON a.product = b.product AND a.version = b.version;

配置你的MySQL服务器,使其至少使用2GB的RAM

您可能还想在表格中使用MyISAM引擎,在这种情况下,请查看这个链接

与Pandas相比,它可能工作得更慢,但您绝对不会遇到内存问题。

另一个可能的解决方案:

  • 增加RAM
  • 在多个集群节点上使用Apache Spark SQL(分布式DataFrame)- 尽管增加RAM要便宜得多

谢谢这个。但是为什么操作系统不能使用硬盘空间扩展RAM? - Nickpick
通常情况下,这应该是可能的(至少对于Windows和Linux,我没有Mac OS的经验),但它非常低效。 - MaxU - stand with Ukraine
我正在使用Windows,但它显然没有将我的SSD硬盘用作扩展。 - Nickpick
@nickpick,你是否将SSD硬盘配置为页面文件(交换文件)的单一来源?但正如我在答案中所说 - 最好使用MySQL或物理增加RAM。 - MaxU - stand with Ukraine
好的,那SQLite呢? - Nickpick
@nickpick,你可以尝试一下,但与MySQL相比,它非常差,特别是在处理大表时。这个链接可能对你有帮助:https://dev59.com/y1jUa4cB1Zd3GeqPOiRD - MaxU - stand with Ukraine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接