numpy Loadtxt函数似乎消耗了太多内存

问题描述 投票:6回答:2

当我使用numpy.loadtxt加载数组时,似乎占用了太多内存。例如:

a = numpy.zeros(int(1e6))

导致内存增加大约8MB(使用htop,或仅增加8bytes * 1,000,000 \大约8MB)。另一方面,如果我保存然后加载此数组

numpy.savetxt('a.csv', a)
b = numpy.loadtxt('a.csv')

我的内存使用量增加了约100MB!我再次用htop观察了这一点。在iPython shell中,以及在使用Pdb ++逐步执行代码时都观察到了这一点。

你知道这是怎么回事吗?

阅读完Jozzas的答案后,我意识到,如果我提前知道了数组的大小,那么如果说'a'是一个mxn数组,那么有一种内存效率更高的处理方式:

b = numpy.zeros((m,n))
with open('a.csv', 'r') as f:
    reader = csv.reader(f)
    for i, row in enumerate(reader):
        b[i,:] = numpy.array(row)
python numpy out-of-memory
2个回答
5
投票

将此浮点数组保存到文本文件将创建一个24M文本文件。当您重新加载该文件时,numpy会逐行浏览文件,解析文本并重新创建对象。

我希望这段时间的内存使用量会激增,因为numpy在到达文件末尾之前不知道结果数组需要多大,所以我希望至少有24M + 8M +已使用的其他临时内存。

这是numpy代码的相关位,来自/lib/npyio.py

    # Parse each line, including the first
    for i, line in enumerate(itertools.chain([first_line], fh)):
        vals = split_line(line)
        if len(vals) == 0:
            continue
        if usecols:
            vals = [vals[i] for i in usecols]
        # Convert each value according to its column and store
        items = [conv(val) for (conv, val) in zip(converters, vals)]
        # Then pack it according to the dtype's nesting
        items = pack_items(items, packing)
        X.append(items)

    #...A bit further on
    X = np.array(X, dtype)

此额外的内存使用量不应该在意,因为这只是python的工作方式-尽管您的python进程似乎正在使用100M的内存,但它在内部维护了不再使用哪些项目的知识,并将重新使用该内存。例如,如果您要在一个程序中重新运行此保存加载过程(保存,加载,保存,加载),则内存使用量不会增加到200M。


0
投票

这是我最终要解决的问题。即使您不提前知道形状,它也可以工作。这将执行转换为先浮点运算,然后then合并数组(与@JohnLyon's answer相对,后者合并字符串数组,然后转换为浮点运算)。这对我来说使用的内存减少了一个数量级,尽管可能会慢一些。但是,我实际上没有使用np.loadtxt所需的内存,因此,如果您没有足够的内存,那会更好:

def numpy_loadtxt_memory_friendly(the_file, max_bytes = 1000000, **loadtxt_kwargs):
    numpy_arrs = []
    with open(the_file, 'rb') as f:
        i = 0
        while True:
            print(i)
            some_lines = f.readlines(max_bytes)
            if len(some_lines) == 0:
                break
            vec = np.loadtxt(some_lines, **loadtxt_kwargs)
            if len(vec.shape) < 2:
                vec = vec.reshape(1,-1)
            numpy_arrs.append(vec)
            i+=len(some_lines)
    return np.concatenate(numpy_arrs, axis=0)
© www.soinside.com 2019 - 2024. All rights reserved.