numpy的Loadtxt函数似乎占用了过多内存

7 投票
2 回答
3347 浏览
提问于 2025-04-17 05:04

当我使用numpy.loadtxt加载一个数组时,感觉占用的内存有点多。例如:

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

这会导致内存增加大约8MB(用htop查看,或者简单计算8字节*100万大约等于8MB)。另一方面,如果我先保存这个数组,然后再加载它,

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

我的内存使用量会增加大约100MB!同样,我是通过htop观察到的。这是在iPython环境下,以及使用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)

2 个回答

0

这是我最后解决这个问题的方法。即使你事先不知道数据的形状,它也能正常工作。这个方法先把数据转换成浮点数,然后再把数组合并(和@JohnLyon的回答不同,他是先合并字符串数组再转换成浮点数)。对我来说,这种方法使用的内存少了很多,虽然可能稍微慢一点。不过,我的内存实在不够用来使用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)
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。

撰写回答