python/pandas 和大左外连接的 MemoryError
MemoryError with python/pandas and large left outer joins
我对 Python 和 Pandas 都很陌生,我正在尝试找出在具有大约 1100 万行的左数据集和一个右侧数据集约有 16 万行和四列。这应该是多对一的情况,但如果右侧有重复的行,我希望连接不会引发错误。我在具有 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")
这适用于小文件,但在我的系统上产生内存错误,文件大小比我实际需要合并的文件大小小两个数量级。
我一直在浏览相关问题 (one, two, three),但是 none 的答案确实解决了这个基本问题 - 或者即使他们解决了,也没有解释得足够好,我无法识别潜在的解决方案。接受的答案没有帮助。我已经在 64 位系统上使用最新稳定版本的 Canopy(1.5.5 64 位,使用 Python 2.7.10)。
避免此 MemoryError 问题的最快and/or 最 pythonic 方法是什么?
为什么不直接将右侧文件读入 pandas(或什至是一个简单的字典),然后使用 csv
模块循环读取、扩展和写入每一行的左侧文件?处理时间是否是一个重要的限制因素(相对于您的开发时间)?
这种方法最终奏效了。这是我的代码模型:
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)
通过将左侧数据集拆分为多个块,将右侧数据集每个非键列转换为一个字典,并向左侧数据集添加列(使用字典和键匹配填充它们),脚本成功地做到了在大约四分钟内完成整个左边的连接,没有记忆问题。
也感谢用户miku who provided the chunk generator code in a comment on this post。
就是说:我非常怀疑这是执行此操作的最有效方法。如果有人有改进此方法的建议,请开火。
如另一个问题 "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')
我对 Python 和 Pandas 都很陌生,我正在尝试找出在具有大约 1100 万行的左数据集和一个右侧数据集约有 16 万行和四列。这应该是多对一的情况,但如果右侧有重复的行,我希望连接不会引发错误。我在具有 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")
这适用于小文件,但在我的系统上产生内存错误,文件大小比我实际需要合并的文件大小小两个数量级。
我一直在浏览相关问题 (one, two, three),但是 none 的答案确实解决了这个基本问题 - 或者即使他们解决了,也没有解释得足够好,我无法识别潜在的解决方案。接受的答案没有帮助。我已经在 64 位系统上使用最新稳定版本的 Canopy(1.5.5 64 位,使用 Python 2.7.10)。
避免此 MemoryError 问题的最快and/or 最 pythonic 方法是什么?
为什么不直接将右侧文件读入 pandas(或什至是一个简单的字典),然后使用 csv
模块循环读取、扩展和写入每一行的左侧文件?处理时间是否是一个重要的限制因素(相对于您的开发时间)?
这种方法最终奏效了。这是我的代码模型:
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)
通过将左侧数据集拆分为多个块,将右侧数据集每个非键列转换为一个字典,并向左侧数据集添加列(使用字典和键匹配填充它们),脚本成功地做到了在大约四分钟内完成整个左边的连接,没有记忆问题。
也感谢用户miku who provided the chunk generator code in a comment on this post。
就是说:我非常怀疑这是执行此操作的最有效方法。如果有人有改进此方法的建议,请开火。
如另一个问题 "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')