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

5
假设我有一个非常大的numpy内存映射数组:
fp = np.memmap("bigarray.mat", dtype='float32', mode='w+', shape=(5000000,5000))

现在进行一些操作后,我想要删除第10列:

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

这会导致内存不足错误,因为返回的数组是一个内存中的数组。我想要的是一个纯内存映射的删除操作。
在完全内存映射模式下,最有效的方法是什么?

1
必须使用列吗?您能转置数据模型吗?您是否检查更改内存布局的“order”参数?删除列对内存非常不利,如果我没有弄错的话,这是numpy的默认设置。 - MariusSiuram
如果要删除的列数较少,则可以忽略它。只需在单独的数组中列出相关/不相关的列即可。如果要删除的列数很多,为什么不将剩余的列复制到一个新数组中呢?这样对齐就没问题了。 - roadrunner66
1个回答

3

免责声明:我总是在处理行和列时弄得一团糟,所以在回答中可能会有错误...

一个重要的问题是删除非连续的数据块并不是一件简单的事情。例如,考虑一个稍微小一点的例子:

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, :]

这个可以运行(几乎会卡死我的操作系统,但是可以运行)。然而下面的代码会破坏所有内容:
for i in range(10, 9999):
    fp[:, i] = fp[:, i+1]

这是因为要更改第11列,您需要更改所有行。文件(和内存)中的默认布局是基于行的。这意味着您必须访问许多不同的位置以获取所有所需数字以进行更新。
我的经验是,当事情开始不适合内存时,一切都变得停滞不前,我不知道它是否正在交换或执行某些缓存。但是,有效的行为是:它突然停止并且什么也不做。
当然,您可以制作一些更好的内存访问算法,它不需要在内存中保存完整的行等等,但这是一个优化级别,我通常不会期望,因为它非常繁琐实施,将是非常慢的(如果您没有SSD,您就死了),并且不是非常常见的场景。
如果必须使用列,则建立 memmap 时可能需要更改 order 参数。Fortran使用基于列而不是行的内存布局,因此这将修复列删除示例。但是,在该数据结构中,删除行将是破坏性操作。
order 参数在 numpy文档的几个地方都有解释:

[参数: order ,'C'或'F']指定ndarray内存布局的顺序:行主,C样式或列主,Fortran样式。仅在形状大于1-D时才会产生影响。默认顺序为'C'。

但是请注意,如果执行该“删除”,则将移动大量GB。并且因为您无法在内存中执行此操作(它不合适),所以您需要有效地修改文件。这将是一个巨大的操作,速度非常慢。我会说您可能需要一些额外的逻辑来执行“掩码”之类的操作。但是,在更高的级别上,而不是在numpy级别上(尽管也许它有一些视图类来封装它,我不完全确定)。您没有告诉您的用例,因此我只能猜测。但是...您正在处理大量数据,将其移动是不好的想法(TM)。

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