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

hea*_*n00 6 python memory csv pandas

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

所以还有替代方案

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

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

  3. 尝试逐行阅读遇到了同样的问题,但速度非常慢。

  4. 我最近转向 python 3,所以认为那里可能存在一些错误,但在 python2 + pandas 上看到了类似的结果。

有问题的文件是来自 Kaggle 竞赛的 train.csv 文件组 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
Run Code Online (Sandbox Code Playgroud)

编辑3:文件中的行数74180465

其他则简单pd.read_csv('filename', low_memory=False)

我努力了

from numpy import genfromtxt
my_data = genfromtxt('data/train.csv', delimiter=',')
Run Code Online (Sandbox Code Playgroud)

更新 下面的代码刚刚工作,但我仍然想弄清楚这个问题的根源,一定有什么问题。

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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在此输入图像描述

编辑:一段有效的代码。 感谢所有帮助人员,我通过添加 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)
Run Code Online (Sandbox Code Playgroud)

这将内存消耗降低到略低于 4Gb

Aar*_*ron 2

作为文本存储在内存中的文件不像压缩的二进制格式那么紧凑,但它在数据方面相对紧凑。如果是一个简单的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
Run Code Online (Sandbox Code Playgroud)

一点点测试(假设__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')
Run Code Online (Sandbox Code Playgroud)

返回:

string: 53

list: 120

array: 136

byte array: 106

dataframe: 152
Run Code Online (Sandbox Code Playgroud)