为什么从文件读取的numpy narray占用如此多的内存?

6
该文件包含2000000行数据,每一行包含208个用逗号分隔的列,如下所示:
0.0863314058048,0.0208767447842,0.03358010485,0.0,1.0,0.0,0.314285714286,0.336293217457,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0
程序将此文件读入numpy数组,我原本预计它会消耗大约(2000000 * 208 * 8B) = 3.2GB的内存。但是,在程序读取该文件时,我发现程序占用了约20GB的内存。
我对为什么我的程序会消耗如此多的内存感到困惑?

你能展示一下从文件中读取数据的确切代码行吗?如果我们只能猜测,那么很难回答。 - Bas Swinckels
@BasSwinckels 谢谢,我使用 np.loadtxt() 读取数据。Saullo Castro 指出了问题并大致解释了这个问题。 - 祝方泽
2个回答

2
我正在使用Numpy 1.9.0,发现np.loadtxt()np.genfromtxt()的内存效率问题与它们基于临时列表存储数据有关。具体来说,这里是np.loadtxt()的代码(链接),这里是np.genfromtxt()的代码(链接)。如果您事先知道数组的shape,可以考虑使用相应的dtype存储数据的文件读取器,这将消耗非常接近理论内存量(对于此案例为3.2 GB)的内存量。
def read_large_txt(path, delimiter=None, dtype=None):
    with open(path) as f:
        nrows = sum(1 for line in f)
        f.seek(0)
        ncols = len(f.next().split(delimiter))
        out = np.empty((nrows, ncols), dtype=dtype)
        f.seek(0)
        for i, line in enumerate(f):
            out[i] = line.split(delimiter)
    return out

看到了样例行,如果使用稀疏矩阵,可能会有巨大的内存节省,不是吗? - user3666197
当然,OP问题似乎是内存绑定的,因此这是一个方向,可以通过CPU绑定的努力来权衡潜在的阻塞内存绑定问题,从而使输入本身和进一步处理在更大的数据集上变得可行(我的直觉告诉我OP不是在寻找一行代码或几个SLOC,而是在寻找一种可行的方法来使用numpy轻松输入和处理类似批量的数据,因此将支付稍微聪明的输入预处理的成本)。 - user3666197
@user3666197 我在这里进行了测试,np.loadtxt()np.genfromtxt() 的问题是不知道形状,被迫使用临时列表和 list.append()(参见这里这里)。 - Saullo G. P. Castro
1
那是毋庸置疑的,Saullo,正如你在答案中所提到的,这是一个与输入处理器相关的问题。请原谅我的话语,它只是触及到了数据集的适当(更高效的)矩阵表示形式。 - user3666197
@user3666197 我想使用这个文件中的数据来训练一个机器学习分类器,因此内存中的数据不能被压缩。感谢您的仔细观察。 - 祝方泽
显示剩余4条评论

0

我认为你应该尝试使用pandas来处理大数据(文本文件)。pandas就像Python中的Excel。它内部使用numpy来表示数据。

HDF5文件也是将大数据保存到HDF5二进制文件的另一种方法。

这个问题会给出一些关于如何处理大文件的想法 - "使用pandas进行大数据工作流程"


我还没有使用过pandas,谢谢你的建议,我会学习它的。 - 祝方泽

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接