【问题标题】:Find all "neighbors" for element in multidimensional array, wrapping around the boundaries查找多维数组中元素的所有“邻居”,环绕边界
【发布时间】:2018-06-10 14:43:52
【问题描述】:

假设我使用 2D/3D numpy 数组来建模由单元格组成的框。单元格被标记为从 0 开始递增的数字。在此之前,这可以通过

box = np.arange(np.prod(n_cells))
box = box.reshape(n_cells)

其中n_cells 是一个 np.array,它存储盒子在每个维度中应具有的单元格数量,基本上是以单元格计数的盒子的维度。

现在,对我来说,困难的部分是找到一种智能方法来找到每个单元格的邻居。我的目标是设置一个数组或列表,其中包含每个单元格的邻居 - 理想情况下,让我们看一个小的 2D 示例。

0   1   2   3
4   5   6   7
8   9   10 11
12  13  14 15 

在这里,没有周期性边界条件的邻居是

0: 1, 4, 5
1: 0, 2, 4, 5, 6
2: 1, 5, 6, 7, 3
...

但我希望它具有周期性边界条件,例如

0: 1, 4, 5, 3, 7, 12, 13, 15
1: 0, 2, 4, 5, 6, 12, 13, 14

这样,每个元素在 2D 中都有 8 个邻居。 理想情况下,我希望能够为任何维度创建这样的列表/数组,但如果没有通用解决方案,我对 2D/3D 尤其感兴趣。

另一个问题,我必须解决的是这样,我计算所有对两次,即 0 是 1 的邻居,1 是 0 的邻居。这是一些东西,我也需要摆脱但这不是主要问题。

【问题讨论】:

标签: python numpy multidimensional-array boundary


【解决方案1】:

这可以通过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]] 只列出那些数字大于单元格本身的人。

【讨论】:

  • 产品采用了一个稍微清晰的重复参数
  • 多么美丽!非常感谢,正是我想要的东西,简洁明了,解释得很好。
猜你喜欢
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-04
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 2010-10-13
相关资源
最近更新 更多