Pandas / Python内存在读取3.2 GB文件时出现峰值

时间:2016-07-20 17:43:57

标签: python csv pandas memory

所以我一直在尝试使用pandas read_csv函数读取内存中的3.2GB文件,但是我继续遇到某种内存泄漏,我的内存使用率会高峰90%+

作为替代品

  1. 我尝试定义dtype以避免将内存中的数据保留为字符串,但看到了类似的行为。

  2. 尝试了numpy读取csv,认为我会得到一些不同的结果但是肯定是错误的。

  3. 逐行尝试阅读遇到了同样的问题,但确实很慢。

  4. 我最近搬到了python 3,所以认为可能会有一些bug,但在python2 + pandas上看到了类似的结果。

  5. 有问题的文件是kaggle competition grupo bimbo

    中的train.csv文件

    系统信息:

    RAM: 16GB, Processor: i7 8cores

    如果您想了解其他任何内容,请与我们联系。

    谢谢:)

    编辑1:内存飙升!不是泄漏(对不起,我的坏。)

    编辑2:csv文件的样本

    Semana,Agencia_ID,Canal_ID,Ruta_SAK,Cliente_ID,Producto_ID,Venta_uni_hoy,Venta_hoy,Dev_uni_proxima,Dev_proxima,Demanda_uni_equil
    3,1110,7,3301,15766,1212,3,25.14,0,0.0,3
    3,1110,7,3301,15766,1216,4,33.52,0,0.0,4
    3,1110,7,3301,15766,1238,4,39.32,0,0.0,4
    3,1110,7,3301,15766,1240,4,33.52,0,0.0,4
    3,1110,7,3301,15766,1242,3,22.92,0,0.0,3
    

    编辑3:文件 74180465

    中的行数

    其他一个简单的pd.read_csv('filename', low_memory=False)

    我试过了

    from numpy import genfromtxt
    my_data = genfromtxt('data/train.csv', delimiter=',')
    

    更新 下面的代码工作正常,但我仍然想要解决这个问题的根源,一定有什么问题。

    import pandas as pd
    import gc
    data = pd.DataFrame()
    data_iterator = pd.read_csv('data/train.csv', chunksize=100000)
    for sub_data in data_iterator:
        data.append(sub_data)
        gc.collect()
    

    enter image description here

    enter image description here

    编辑:一段有效的代码。 感谢所有帮助人员,我通过添加python dtypes而不是numpy来搞砸了我的dtypes。一旦我修复了下面的代码就像一个魅力。

    dtypes = {'Semana': pd.np.int8,
              'Agencia_ID':pd.np.int8,
              'Canal_ID':pd.np.int8,
              'Ruta_SAK':pd.np.int8,
              'Cliente_ID':pd.np.int8,
              'Producto_ID':pd.np.int8,
              'Venta_uni_hoy':pd.np.int8,
              'Venta_hoy':pd.np.float16,
              'Dev_uni_proxima':pd.np.int8,
              'Dev_proxima':pd.np.float16,
              'Demanda_uni_equil':pd.np.int8}
    data = pd.read_csv('data/train.csv', dtype=dtypes)
    

    这将内存消耗降至4Gb以下

2 个答案:

答案 0 :(得分:1)

作为文本存储在存储器中的文件不像压缩二进制格式那样紧凑,但是它在数据方面相对紧凑。如果它是一个简单的ascii文件,除了任何文件头信息外,每个字符只有1个字节。 Python字符串具有类似的关系,其中内部python内容有一些开销,但每个额外的字符只添加1个字节(来自__sizeof__的测试)。一旦开始转换为数字类型和集合(列表,数组,数据框等),开销就会增加。例如,列表必须存储每个位置的类型和值,而字符串仅存储值。

>>> s = '3,1110,7,3301,15766,1212,3,25.14,0,0.0,3\r\n'
>>> l = [3,1110,7,3301,15766,1212,3,25.14,0,0.0,3]
>>> s.__sizeof__()
75
>>> l.__sizeof__()
128

进行一些测试(假设__sizeof__是准确的):

import numpy as np
import pandas as pd

s = '1,2,3,4,5,6,7,8,9,10'
print ('string: '+str(s.__sizeof__())+'\n')
l = [1,2,3,4,5,6,7,8,9,10]
print ('list: '+str(l.__sizeof__())+'\n')
a = np.array([1,2,3,4,5,6,7,8,9,10])
print ('array: '+str(a.__sizeof__())+'\n')
b = np.array([1,2,3,4,5,6,7,8,9,10], dtype=np.dtype('u1'))
print ('byte array: '+str(b.__sizeof__())+'\n')
df = pd.DataFrame([1,2,3,4,5,6,7,8,9,10])
print ('dataframe: '+str(df.__sizeof__())+'\n')

返回:

string: 53

list: 120

array: 136

byte array: 106

dataframe: 152

答案 1 :(得分:1)

根据您的第二个图表,看起来好像您的机器会分配额外的4.368 GB内存,这大约相当于您的3.2 GB数据集的大小(假设1 GB开销,这可能是一段时间) )。

我试图找到一个可能发生这种情况的地方并且没有超级成功。但是,如果你有动力,也许你可以找到它。这是我走的路径:

This line读到:

def read(self, nrows=None):
    if nrows is not None:
        if self.options.get('skip_footer'):
            raise ValueError('skip_footer not supported for iteration')

    ret = self._engine.read(nrows)

此处,_engine引用PythonParser

反过来,调用_get_lines()

调用数据source

它看起来像是从相对标准的字符串形式读取(请参阅here),如TextIOWrapper

所以事情正在以标准文本的形式被读入并转换,这解释了缓慢的斜坡。

穗怎么样?我认为这是由these lines解释的:

ret = self._engine.read(nrows)

if self.options.get('as_recarray'):
    return ret

# May alter columns / col_dict
index, columns, col_dict = self._create_index(ret)

df = DataFrame(col_dict, columns=columns, index=index)

ret成为数据框的所有组成部分。

self._create_index()将这些组件分开ret

def _create_index(self, ret):
    index, columns, col_dict = ret
    return index, columns, col_dict

到目前为止,所有内容都可以通过引用完成,并且对DataFrame()的调用会继续这种趋势(请参阅here)。

所以,如果我的理论是正确的,DataFrame()要么在某处复制数据,要么_engine.read()在我已经确定的路径上的某个地方复制。

相关问题