Pandas read_csv与chunksize内存泄漏

时间:2017-11-01 10:56:10

标签: python pandas csv

我通过使用pandas read_csv 以及500000的块大小并写入另一个csv文件来丰富一个拥有7.5亿行的csv。运行此操作后,我处理了大约1亿到1亿5千万行后,会出现'分段错误'

我跟踪处理的块数并更改了代码,因此它会跳过它已读取的块。监视进程内存消耗我发现即使我跳过这些块,它也会增加很多。这是我不能得到的部分。通过问题似乎是熊猫垃圾收集的问题,但这似乎与以前的版本有关。我使用Python 2.7 和pandas 0.21.0

我在具有30 GB RAM的r3.xlarge EC2实例上执行此操作,这应该足够了,即使考虑到高达6倍内存开销的pandas。

代码摘要:

i = 0
for chunk in pd.read_csv(filename,chunksize=500000,names=colnames):
    if  i <= 349500000: # Previously processed chunks
        i = i+chunksize
        print 'Skipping chunk ', i
        continue
    enriched_chunk = enrich_df(chunk, users_df)
    enriched_chunk.to_csv('enriched.csv', mode='a', header=False, index=False)


def enrich_df(c, users_df):
    d = pd.merge(c, users_df, how='left', left_on='user_id', right_on='userId')
    return d

表users_df是一个相对较小的表,保存在内存中。

1 个答案:

答案 0 :(得分:0)

我编写了一个简化的测试脚本,无法重现您的错误。我使用的是Python 3.6.1和Pandas 0.20.3。

测试脚本使用一个常量306 MB的RAM(至少对于前1亿行,它仍然在运行)。

RAM usage of test script

您可以尝试使用此脚本,看看它是否仍然会导致内存泄漏?它可以作为调试的起点。

import os
import time

import numpy as np
import pandas as pd
import matplotlib.pylab as plt

SOURCE = 'test.csv'
CHUNCKSIZE = int(5e5)

def main():

    if not os.path.exists(SOURCE):
        df = pd.DataFrame(np.random.rand(1000000, 4), columns=list('ABCD'))
        df.to_csv(SOURCE)
        del df
    print("df %s ready" %(SOURCE))

    i=0; lines=[]; timings = []
    while(i < int(7e8)): 
        t = time.time()
        print(i, end = ' ')
        i += CHUNCKSIZE
        chunk = pd.read_csv(SOURCE, chunksize=CHUNCKSIZE)
        chunk = pd.concat(chunk, ignore_index=True)
        chunk.to_csv('enriched.csv', mode='a', header=False, index=False)
        print(" in %.3f seconds" %(time.time() -t))
        lines.append(i)
        timings.append(time.time()-t)


    plt.figure(figsize=(10,5))
    plt.plot(lines, timings, 'o-')
    plt.xlabel("Nr of lines"); plt.ylabel("Time for last chunck")
    plt.show()




if __name__ == "__main__":
    st = time.time()
    main()
    print("--- total runtime %.3f seconds ---" %(time.time() - st))