Python MemoryError:无法分配数组内存

Posted

技术标签:

【中文标题】Python MemoryError:无法分配数组内存【英文标题】:Python MemoryError: cannot allocate array memory 【发布时间】:2013-12-23 21:03:57 【问题描述】:

我需要读取一个 250 MB 的 CSV 文件,其中包含 ~7000 行和 ~9000 列。每一行代表一个图像,每一列是一个像素(灰度值0-255)

我从一个简单的np.loadtxt("data/training_nohead.csv",delimiter=",") 开始,但这给了我一个内存错误。我觉得这很奇怪,因为我运行的是 64 位 Python 并安装了 8 GB 内存,但它在仅使用大约 512 MB 后就死机了。

此后我尝试了其他几种策略,包括:

    import fileinput 一次读取一行,并将它们附加到一个数组中 np.fromstring读入整个文件后 np.genfromtext 手动解析文件(因为所有数据都是整数,这很容易编码)

每种方法都给了我相同的结果。 MemoryError 大约 512 MB。想知道 512MB 是否有什么特别之处,我创建了一个简单的测试程序,它会填满内存直到 python 崩溃:

str = " " * 511000000 # Start at 511 MB
while 1:
    str = str + " " * 1000 # Add 1 KB at a time

这样做直到大约 1 场演出才崩溃。我也只是为了好玩,尝试过:str = " " * 2048000000(填满 2 个演出)——这运行顺利。填满了 RAM,从不抱怨。所以问题不在于我可以分配的 RAM 总量,而在于我可以分配多少次内存...

我在谷歌上搜索无果,直到找到这篇文章:Python out of memory on large CSV file (numpy)

我完全复制了答案中的代码:

def iter_loadtxt(filename, delimiter=',', skiprows=0, dtype=float):
    def iter_func():
        with open(filename, 'r') as infile:
            for _ in range(skiprows):
                next(infile)
            for line in infile:
                line = line.rstrip().split(delimiter)
                for item in line:
                    yield dtype(item)
        iter_loadtxt.rowlength = len(line)

    data = np.fromiter(iter_func(), dtype=dtype)
    data = data.reshape((-1, iter_loadtxt.rowlength))
    return data

这次调用iter_loadtxt("data/training_nohead.csv") 给出了一个稍微不同的错误:

MemoryError: cannot allocate array memory

谷歌搜索这个错误我只发现了一个,没有太大帮助,发帖:Memory error (MemoryError) when creating a boolean NumPy array (Python)

因为我运行的是 Python 2.7,所以这不是我的问题。任何帮助将不胜感激。

【问题讨论】:

您是否尝试过分两次完成?第一遍:计算数组维度nxm 和dtypes。第二遍:将数据放入 preallocated 数组中(指定 dtype, countnp.fromiter() 可能就足够了) 我其实已经知道数组尺寸(7049 x 9146),所以我会试试这个。编辑 - 9246,而不是 9146。虽然无关紧要 成功了!请张贴作为答案,以便我接受。加分点:它跑了 8 秒!我非常惊讶。 你可以post your own answer。你已经完成了所有的工作。请添加避免 MemoryError 的小代码示例。 【参考方案1】:

在@J.F. 的帮助下。 Sebastian 我开发了以下答案:

train = np.empty([7049,9246])
row = 0
for line in open("data/training_nohead.csv")
    train[row] = np.fromstring(line, sep=",")
    row += 1

当然,这个答案假设事先知道行数和列数。如果您事先没有此信息,则计算行数总是需要一段时间,因为您必须读取整个文件并计算\n 字符。像这样就足够了:

num_rows = 0
for line in open("data/training_nohead.csv")
    num_rows += 1

对于列数,如果每一行都有相同的列数,那么你可以只计算第一行,否则你需要跟踪最大值。

num_rows = 0
max_cols = 0
for line in open("data/training_nohead.csv")
    num_rows += 1
    tmp = line.split(",")
    if len(tmp) > max_cols:
        max_cols = len(tmp)

此解决方案最适合数字数据,因为包含逗号的字符串确实会使事情复杂化。

【讨论】:

注意:您可以在此处使用 for i, line in enumerate(file)ncols = max(ncols, len(line.split(','))) 内置函数。通常(不是在这种情况下),一个 cvs 行可能跨越多个物理行,即枚举 csv 行的正确方法是:for i, row in enumerate(csv.reader(file))【参考方案2】:

这是一个古老的讨论,但可能对现在的人有所帮助。

我想我知道为什么str = str + " " * 1000str = " " * 2048000000 更失败

当运行第一个时,我相信操作系统需要在内存中分配新对象str + " " * 1000,然后才引用名称str。在将名称“str”引用到新对象之前,它无法摆脱第一个对象。 这意味着操作系统需要同时分配两次“str”对象,使其能够为 1 gig 而不是 2 gig 分配。 我相信使用下一个代码将从您的操作系统中获得与单次分配相同的最大内存:

str = " " * 511000000
while(1):
    l = len(str)
    str = " "
    str = " " * (len + 1000)

如果我错了,请随时与我联系

【讨论】:

以上是关于Python MemoryError:无法分配数组内存的主要内容,如果未能解决你的问题,请参考以下文章

我可以找出导致我的 Python MemoryError 的分配请求吗?

MemoryError:内存分配失败Micropython

如何解决 MemoryError:Micropython 的内存分配失败?

创建非常大的numpy数组时出现MemoryError [重复]

继承自 int 的 Cython 扩展类型导致 MemoryError

如何克服 numpy.unique 的 MemoryError