如何在不复制数组的情况下合并同一numpy数组的两个视图?
问题解答
首先直接给结论:你想要的无复制拼接是不可行的,原因和numpy的视图机制密切相关,下面详细拆解:
为什么np.concatenate必须复制数据
numpy的视图(比如你创建的mat_1和mat_2)本质是对原数组内存块的"观察窗口",它依赖于连续的内存区域或者有固定步长的内存布局。而mat[:i,:]和mat[j:,:]在原数组的内存里是被mat[i:j,:]这一段隔开的,两者的内存地址完全不连续——numpy没办法用一个单一的视图对象来表示这种非连续的内存片段,所以np.concatenate必须把这两个视图的数据复制到一块新的连续内存里,生成mat_s这个新数组。
替代方案:避免复制的可行思路
既然拼接必然会复制,我们可以换个思路绕过拼接操作:
1. 修改函数接受多个数组输入
如果func是你自己可以修改的,直接让它接受多个数组参数,分别处理两个视图即可,完全不需要复制:
# 示例:修改后的func def func(arr1, arr2): # 分别处理两个视图,比如做统计计算 res1 = arr1.mean(axis=0) res2 = arr2.mean(axis=0) # 按需合并结果 return np.hstack((res1, res2)) # 调用时直接传入两个视图 result = func(mat_1, mat_2)
这样既没有复制数据,又能保证原数组不会被修改(只要func里不对传入的数组做赋值操作)。
2. 给视图添加只读保护(可选)
如果你担心func误修改数组,可以给视图加上只读属性,从根源上避免意外修改原数据:
mat_1.flags.writeable = False mat_2.flags.writeable = False
这样如果func里尝试修改数组,numpy会直接抛出错误,杜绝误操作。
补充:关于掩码索引的误区
可能有人会想到用布尔掩码标记需要保留的行,但要注意:掩码索引返回的是副本而非视图,所以这种方式依然会复制数据,仅当你需要多次复用这个子集时才值得考虑:
mask = np.ones(mat.shape[0], dtype=bool) mask[i:j] = False # mat[mask]是副本,仍会复制数据 result = func(mat[mask])
内容的提问来源于stack exchange,提问作者faidros
相关产品推荐
相关产品推荐

