Numpy:从非常大的内存映射 Numpy 数组中删除列

Numpy: delete column from very big memory mapped Numpy Array

假设我有一个非常大的 numpy 内存映射数组:

fp = np.memmap("bigarray.mat", dtype='float32', mode='w+', shape=(5000000,5000))

现在经过一些操作等,我想删除第 10 列:

fp = np.delete(fp,10,1)

这会导致 内存不足错误,因为 (??) 返回的数组是内存数组。我想要的是纯内存映射删除操作。

在全内存映射模式下删除列的最有效方法是什么?

免责声明:我总是把行和列弄得一团糟,所以我可能会在这个答案中漏嘴......

一个重要的问题是删除不连续的数据块是一件非常重要的事情。例如,考虑一个更小的例子:

fp = np.memmap("bigarray.mat", dtype='float32', mode='w+', shape=(1000000,10000))

这个 memmap 将有 10**10 个元素,每个元素 4 个字节。这意味着这个结构将接近 40GB。它不适合我的笔记本电脑内存,所以可以使用它。

以下将移动所有行,有效删除第 10 行:

for i in range(10, 999999):
    fp[i, :] = fp[i+1, :]

这有效(几乎要杀死我的 OS,但有效)。然而,以下内容将破坏一切:

for i in range(10, 9999):
    fp[:, i] = fp[:, i+1]

这是因为要更改第 11 列,您需要更改所有行。默认情况下,文件(和内存)中的布局是基于行的。这意味着您必须访问很多不同的地方才能获得所有需要的号码才能更新。

我尝试这样做的经验是,当内存开始放不下时,一切都会停止,我不知道它是在交换还是在做一些缓存。但是,有效的行为是:它突然停止并且什么都不做。

当然你可以为内存访问制定一些更好的算法,不需要在内存中保存完整的行等等,但这是我通常不会期望的优化级别,因为它非常实施起来很麻烦,会 非常 慢(大量随机访问磁盘,如果你没有 SSD 你就死定了)并且不是很常见的情况。

如果您必须使用列,您可能需要在构建 memmap 时更改 order 参数。 Fortran 使用基于列而不是行的内存布局,因此这将修复列删除示例。但是,在该数据结构中,删除一行将是中断操作。

这个order参数在numpy documentation的几个地方都有解释:

[parameter: order, either 'C' or 'F'] Specify the order of the ndarray memory layout: row-major, C-style or column-major, Fortran-style. This only has an effect if the shape is greater than 1-D. The default order is ‘C’.


但是请注意,如果您执行 "deletion",您将移动大量 GB。因为你不能在内存中这样做(它不适合),你将需要有效地修改文件。这将是一项巨大的操作,而且会非常缓慢。我会说你可能想要某种额外的逻辑来执行 "mask" 或类似的东西。但是在更高的层次上,而不是在 numpy 的层次上(尽管它可能有一些封装了它的视图 class,我不完全确定)。你没有告诉你的用例,所以我只能猜测。但是...您正在处理大量数据,四处移动它是个坏主意 (TM)。