假设我有一个非常大的numpy内存映射数组:
fp = np.memmap("bigarray.mat", dtype='float32', mode='w+', shape=(5000000,5000))
现在经过一些操作等,我想删除第10列:
fp = np.delete(fp,10,1)
这导致内存不足错误,因为(??)返回的数组是内存数组。我想要的是纯内存映射删除操作。
在完全内存映射模式下删除列的最有效方法是什么?
答案 0 :(得分: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就死了)并且不是很常见的情况。
如果您必须使用列,则可能需要在构建order
时更改memmap
参数。 Fortran使用基于列而不是行的内存布局,因此将修复列删除示例。但是,在该数据结构中,删除行将是中断操作。
在PHP Docs的几个地方解释了这个order
参数:
[parameter:
order
,'C'
或'F'
]指定ndarray内存布局的顺序:row-major,C-style或column-major,Fortran-style。这仅在形状大于1-D时有效。默认顺序为“C”。
但是要考虑到,如果你执行"删除",你将会移动很多GB。而且因为你不能在内存中做到这一点(它不适合),你需要有效地修改文件。这将是一个巨大的操作,这将是非常缓慢的。我会说你可能想要一些额外的逻辑来执行一个"掩码"或类似的东西。但是在更高级别,而不是在numpy级别(虽然它可能有一些视图类封装了它,但我并不完全确定)。你还没有告诉你的用例,所以我只能猜测。但是......你正在处理大量数据,转移它是Bad Idea(TM)。