熊猫内存管理问题

时间:2017-07-26 15:34:39

标签: python pandas csv memory

我遇到了Pandas占用太多内存的问题。我有一个5.5gb的文件,其中包含2列,我想简单地保存第一列中的所有唯一值,如下所示:

Main File
    Follower    Friend
0   12          260009730
1   12          17568791
2   12          22512883
3   12          15808761
4   12          10135072
5   12          988
6   12          22424855
7   13          9163182
8   14          22990962
9   15          7681662
10  15          17289517

Result File
     User
0    12
1    13
2    14
3    15

由于RAM限制,我将主文件导入30个部分,尝试从内存中清除数据帧,每次只附加结果文件。经过两次迭代(三十次)后,结果文件为13.5mb。但它在第6次迭代后一直崩溃,我可以在我的进程管理中看到python占用了4.5GB的RAM。我试图打电话给垃圾收集器但显然不能正常工作,你们可以帮帮我吗?我的代码如下:

i = 0
userRelation = pd.DataFrame(columns=['User'])
Location = 'file.txt'
while i < 30:
    userRelationHelp = pd.DataFrame(columns=['User'])
    print(str(i))
    network = pd.read_csv(Location, sep="\t", header=None, encoding='Latin', low_memory=False, skiprows=(i * math.ceil(284884514/30)), nrows=(((i+1) * math.ceil(284884514/30))), names=['Follower', 'Friend'])

    userRelationHelp['User'] = network['Follower'].unique()
    userRelation = userRelation.append(userRelationHelp)
    lst = [userRelationHelp, network]
    del lst
    gc.collect()
    i += 1

从我读过i + = 1之前的最后3行起,应该用来清除内存中较大的文件。在每次迭代之后,我可以看到我在循环开始时使用的RAM不断增加~200mb,并且在循环期间它会逐渐增加每次运行。

在运行上面代码之前使用基本的Python RAM: 76MB

周期开始时的近似Python RAM使用情况

0: 300
1: 800
2: 1000
3: 1300

周期结束时的近似Python RAM使用情况

0: 633
1: 2000
2: 2900
3: 3700

可以想象指出我正在做或假设不正确的事情吗?

2 个答案:

答案 0 :(得分:3)

@ypnos gave you a perfect description of how it should be done in Pandaic way.

这是我尝试编写代码:

生成样本数据并将其写入CSV:

fn = r'c:/temp/data.csv'

pd.DataFrame(np.random.randint(1001, 9999, (10**5, 2))) \
  .to_csv(fn, sep='\t', index=False, header=None)

仅处理我们需要的CSV中的那些列:

chunksize=10**2  # you may want to use 10**7 as a chunk size
reader = pd.read_csv(fn, sep='\t', usecols=[0], names=['Follower'], 
                     chunksize=chunksize, squeeze=True)

df = pd.DataFrame(np.unique(np.concatenate([ser.unique() for ser in reader])),
                  columns=['User'])

结果:

In [62]: df
Out[62]:
      User
0     1001
1     1002
2     1003
3     1004
4     1005
5     1006
6     1007
7     1008
8     1009
9     1010
...    ...
8988  9989
8989  9990
8990  9991
8991  9992
8992  9993
8993  9994
8994  9995
8995  9996
8996  9997
8997  9998

[8998 rows x 1 columns]

答案 1 :(得分:2)

分割大文件的方式非常低效。当您使用skiprows参数时,阅读器需要逐行浏览文件,计算行结束字符,直到请求的行数已经过去。因此,在最后一次迭代中,整个文件再次读取 之后已经多次查看

请顺便提一下,您对nrows的使用对我来说也是错误的。我希望nrows=math.ceil(284884514/30)。我相信这是你记忆问题的解释。

您需要的是一种迭代方式来运行文件一次,这是由chunksize参数提供的。 Pandas IO Tools docs中很好地说明了chunksize的使用情况。

示例性代码示例:

userRelation = pd.DataFrame(columns=['User'])
Location = 'file.txt'
chunksize = math.ceil(284884514/30)

reader = pd.read_csv(Location, sep="\t", header=None, encoding='Latin', low_memory=False, chunksize=chunksize, names=['Follower', 'Friend'])
for network in reader:
    userRelationHelp = pd.DataFrame(columns=['User'])
    userRelationHelp['User'] = network['Follower'].unique()
    userRelation = userRelation.append(userRelationHelp)
    lst = [userRelationHelp, network]