Pandas/Python在读取3.2 GB fi时内存峰值

2024-09-28 21:24:39 发布

您现在位置:Python中文网/ 问答频道 /正文

所以我一直试图用pandas read_csv函数读取内存中的一个3.2GB的文件,但是我不断地遇到某种内存泄漏,我的内存使用量会激增90%+。在

作为替代品

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

  2. 尝试了numpy read csv,以为我会得到一些不同的结果,但这是绝对错误的。

  3. 试着逐行阅读也遇到了同样的问题,但速度很慢。

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

有问题的文件是火车.csv来自kaggle竞赛的文件grupo bimbo

系统信息:

RAM: 16GB, Processor: i7 8cores

如果你还想知道其他情况,请告诉我。在

谢谢:)

编辑一:这是一个记忆高峰!一点也不漏(对不起我的错)

编辑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)

我试过了

^{pr2}$

更新 下面的代码刚刚起作用,但是我还是想弄清楚这个问题,一定是出了什么问题。在

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数据类型而不是numpy类型。有一次,我修复了以下代码的工作原理。在

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以下


Tags: 文件csv内存devid编辑readdata
2条回答

根据您的第二张图表,您的计算机可能会在短时间内分配额外的4.368GB内存,这大约相当于3.2GB数据集的大小(假设1GB的开销,这可能是一个扩展)。在

我试图找到一个可能发生这种情况的地方,但没有取得成功。不过,如果你有动力的话,也许你能找到它。我走的路是:

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引用^{}。在

反过来,调用^{}。在

调用数据^{}。在

它似乎以字符串的形式从一些相对标准的东西中读入(参见here),比如TextIOWrapper。在

所以东西被当作标准文本读入并转换,这就解释了慢斜坡的原因。在

扣球呢?我想这可以用these lines来解释:

^{pr2}$

ret成为数据帧的所有组件。在

self._create_index()ret分成以下几个部分:

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

到目前为止,一切都可以通过引用完成,对DataFrame()的调用延续了这一趋势(请参见here)。在

所以,如果我的理论是正确的,DataFrame()要么在某处复制数据,要么{}沿着我确定的路径在某处复制数据。在

以文本形式存储在内存中的文件不像压缩的二进制格式那样紧凑,但是它在数据方面相对紧凑。如果它是一个简单的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__是准确的):

^{pr2}$

退货:

string: 53

list: 120

array: 136

byte array: 106

dataframe: 152

相关问题 更多 >