MemoryError与python / pandas和大的左外连接

时间:2015-09-17 16:13:19

标签: python python-2.7 join pandas canopy

我对Python和Pandas都很陌生,并且试图找出在大约1,100万行的左数据集和具有~160K行和4的右数据集之间执行庞大的左外连接的最快方法列。这应该是多对一的情况,但如果右侧有重复的行,我希望联接不会出错。我在具有8 Gb RAM的Windows 7 64位系统上使用Canopy Express,我几乎坚持这一点。

这是我到目前为止所编写代码的模型:

import pandas as pd

leftcols = ['a','b','c','d','e','key']
leftdata = pd.read_csv("LEFT.csv", names=leftcols)

rightcols = ['x','y','z','key']
rightdata = pd.read_csv("RIGHT.csv", names=rightcols)

mergedata = pd.merge(leftdata, rightdata, on='key', how='left')
mergedata.to_csv("FINAL.csv")

这适用于小文件但在我的系统上产生MemoryError,文件大小比我实际需要合并的文件大小小两个数量级。

我一直在浏览相关问题(onetwothree),但没有一个答案真正解决了这个基本问题 - 或者如果他们这样做,那么&# #39;没有得到足够的解释,我无法识别潜在的解决方案。接受的答案没有帮助。我已经使用64位系统并使用最新的Canopy稳定版本(1.5.5 64位,使用Python 2.7.10)。

避免此MemoryError问题的最快和/或最pythonic方法是什么?

3 个答案:

答案 0 :(得分:2)

为什么不将你的正确文件读入pandas(甚至是简单的字典),然后使用csv模块遍历左侧文件来读取,扩展和写入每一行?处理时间是一个重要的约束(与开发时间相比)?

答案 1 :(得分:2)

这种方法最终起作用了。这是我的代码模型:

import csv

idata = open("KEY_ABC.csv","rU")
odata = open("KEY_XYZ.csv","rU")

leftdata = csv.reader(idata)
rightdata = csv.reader(odata)

def gen_chunks(reader, chunksize=1000000):
    chunk = []
    for i, line in enumerate(reader):
        if (i % chunksize == 0 and i > 0):
            yield chunk
            del chunk[:]
        chunk.append(line)
    yield chunk

count = 0

d1 = dict([(rows[3],rows[0]) for rows in rightdata])
odata.seek(0)    
d2 = dict([(rows[3],rows[1]) for rows in rightdata])
odata.seek(0)
d3 = dict([(rows[3],rows[2]) for rows in rightdata])

for chunk in gen_chunks(leftdata):
    res = [[k[0], k[1], k[2], k[3], k[4], k[5], k[6], 
                d1.get(k[6], "NaN")] for k in chunk]
    res1 = [[k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7], 
                d2.get(k[6], "NaN")] for k in res]
    res2 = [[k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7], k[8],
                d3.get(k[6], "NaN")] for k in res1]
    namestart = "FINAL_"
    nameend = ".csv"
    count = count+1
    filename = namestart + str(count) + nameend
    with open(filename, "wb") as csvfile:
        output = csv.writer(csvfile)
        output.writerows(res2)

通过将左侧数据集拆分为块,将每个非键列的右侧数据集转换为一个字典,并通过向左侧数据集添加列(使用词典和键匹配填充它们),脚本设法执行整个左连接大约四分钟没有内存问题。

还要感谢用户mikuthis post的评论中提供了块生成器代码。

那说:我非常怀疑这是最有效的方法。如果有人提出改进这种方法的建议,请离开。

答案 2 :(得分:0)

正如另一个问题"Large data" work flows using pandas所示,dask(http://dask.pydata.org)可能是一个简单的选择。

简单示例

import dask.dataframe as dd
df1 = dd.read_csv('df1.csv')
df2 = dd.read_csv('df2.csv')
df_merge = dd.merge(df1, df2, how='left')