由于您在每个位置的索引未对齐,您可以创建一个掩码或花哨的索引来提取所需的元素。由于提取的值将是平坦的,因此您必须重新调整它们。
以下是创建蒙版的方法:
K = 50
mask = np.zeros((M, N, P + 1), dtype=np.int8)
np.put_along_axis(mask, array2, 1, axis=-1)
np.put_along_axis(mask, array2 + K, -1, axis=-1)
mask.cumsum(axis=-1, out=mask)
mask = mask[..., :-1].view(bool)
我们使用np.int8 和np.bool_ 具有相同的项目大小这一事实,并使用np.cumsum 将初始掩码位置传播到每个轴的最终位置。
剩下的就很简单了:
array3 = array1[mask].reshape(M, N, K)
您可以通过绕过np.put_along_axis 并在适当的情况下使用带有剪辑的直接索引来避免额外的元素:
mask = np.zeros_like(array1, dtype=np.int8)
r = np.tile(np.arange(M)[:, None, None], (1, N, 1))
c = np.tile(np.arange(N)[None, :, None], (M, 1, 1))
clip_mask = array2 + K < P
mask[r, c, array2] = 1
mask[r[clip_mask], c[clip_mask], array2[clip_mask] + K] = -1
mask = np.cumsum(mask, axis=-1, out=mask).view(bool)
这非常浪费:要获得一个形状为(M, N, K) 的数组,您正在创建一个大小为(M, N, P) 的布尔掩码以及一些大小为(M, N, 1) 的索引数组,另一个大小为(M, N, 1) 的掩码,然后这些索引数组的一些掩码版本。在这里使用for 循环真的没有错,只要你编译它们,例如使用 cython 或 numba。