这可以通过numpy.roll 来完成,它沿着给定的轴“滚动”数组,完全符合您想要的那种环绕。例如,滚动 (-1, -1) 将所有内容向左和向上移动,因此数组变为
[[ 5, 6, 7, 4],
[ 9, 10, 11, 8],
[13, 14, 15, 12],
[ 1, 2, 3, 0]]
这样,我们就为每个点找到了东南邻域。剩下的就是展平这个列表 (ravel),对 9 个偏移量中的每一个重复该过程(包括 (0, 0) 表示数字本身),然后堆叠结果。该解决方案适用于任意维度的数组b:
dim = len(b.shape) # number of dimensions
offsets = [0, -1, 1] # offsets, 0 first so the original entry is first
columns = []
for shift in itertools.product(offsets, repeat=dim): # equivalent to dim nested loops over offsets
columns.append(np.roll(b, shift, np.arange(dim)).ravel())
neighbors = np.stack(columns, axis=-1)
输出(neighbors的值):
[[ 0, 1, 3, 4, 5, 7, 12, 13, 15],
[ 1, 2, 0, 5, 6, 4, 13, 14, 12],
[ 2, 3, 1, 6, 7, 5, 14, 15, 13],
[ 3, 0, 2, 7, 4, 6, 15, 12, 14],
[ 4, 5, 7, 8, 9, 11, 0, 1, 3],
[ 5, 6, 4, 9, 10, 8, 1, 2, 0],
[ 6, 7, 5, 10, 11, 9, 2, 3, 1],
[ 7, 4, 6, 11, 8, 10, 3, 0, 2],
[ 8, 9, 11, 12, 13, 15, 4, 5, 7],
[ 9, 10, 8, 13, 14, 12, 5, 6, 4],
[10, 11, 9, 14, 15, 13, 6, 7, 5],
[11, 8, 10, 15, 12, 14, 7, 4, 6],
[12, 13, 15, 0, 1, 3, 8, 9, 11],
[13, 14, 12, 1, 2, 0, 9, 10, 8],
[14, 15, 13, 2, 3, 1, 10, 11, 9],
[15, 12, 14, 3, 0, 2, 11, 8, 10]]
在每一行中,第一个条目是原始编号,其他条目是它的邻居。
要让每个条目-邻居对只列出一次,您可以屏蔽冗余条目,例如使用 NaN:
np.where(neighbors >= neighbors[:, [0]], neighbors, np.nan)
[[ 0., 1., 3., 4., 5., 7., 12., 13., 15.],
[ 1., 2., nan, 5., 6., 4., 13., 14., 12.],
[ 2., 3., nan, 6., 7., 5., 14., 15., 13.],
[ 3., nan, nan, 7., 4., 6., 15., 12., 14.],
[ 4., 5., 7., 8., 9., 11., nan, nan, nan],
[ 5., 6., nan, 9., 10., 8., nan, nan, nan],
[ 6., 7., nan, 10., 11., 9., nan, nan, nan],
[ 7., nan, nan, 11., 8., 10., nan, nan, nan],
[ 8., 9., 11., 12., 13., 15., nan, nan, nan],
[ 9., 10., nan, 13., 14., 12., nan, nan, nan],
[ 10., 11., nan, 14., 15., 13., nan, nan, nan],
[ 11., nan, nan, 15., 12., 14., nan, nan, nan],
[ 12., 13., 15., nan, nan, nan, nan, nan, nan],
[ 13., 14., nan, nan, nan, nan, nan, nan, nan],
[ 14., 15., nan, nan, nan, nan, nan, nan, nan],
[ 15., nan, nan, nan, nan, nan, nan, nan, nan]])
这个想法是neighbors >= neighbors[:, [0]] 只列出那些数字大于单元格本身的人。