【问题标题】:Nearest neighbors最近的邻居
【发布时间】:2013-11-14 18:19:23
【问题描述】:

我正在编写一段代码来打印矩阵元素的最近邻居。我得到一个

"invalid index" error

当我尝试打印邻居列表时(最后一行)。你能找出原因吗?

代码如下:

neighbours = ndarray((ran_x-2, ran_y-2,8),int)
for i in range(0, ran_x):
    for j in range(0, ran_y):
        if 1 < i < ran_x-1:
           if 1 < j < ran_y-1:
              neighbours = ([matrix[i-1,j-1],matrix[i-1,j],matrix[i-1,j+1],matrix[i,j-1],matrix[i,j+1],matrix[i+1,j-1],matrix[i+1,j],matrix[i+1,j+1]])
neighbours = np.array(neighbours)
for l in range(1, ran_x-1):
    for m in range(1, ran_y-1):                
        print neighbours[l,m]

【问题讨论】:

  • if i in range(1, ran_x-1) 之类的语句令人困惑且效率极低。写if 0 &lt; i &lt; ran_x - 1会更快(更清晰)。
  • 实际上,如果你做了for i in range(1, ran_x-1),对j 做同样的事情,并去掉if 语句,会更清楚。更好的是,使用xrangerange 的惰性版本)来提高效率。

标签: python numpy nearest-neighbor


【解决方案1】:

看看你的数组的大小,它是一个(ran_x - 2) * (ran_y - 2)元素数组:

neighbours = ndarray((ran_x-2, ran_y-2,8),int)

并且您尝试访问索引ran_x-1ran_y-1 处超出范围的元素。

【讨论】:

  • 谢谢。 for l in range(0, ran_x-2): for m in range(0, ran_y-2): print neighbours[l,m] 我仍然遇到同样的错误
  • 你确定你之前没有问题吗?由于您使用for i in range(0, ran_x): 并使用i 作为索引。
【解决方案2】:

滑动窗口 stride_tricks 非常适合这个 (https://*.com/a/11000193/541038)

import numpy as np
from numpy.lib.stride_tricks import as_strided

def sliding_window(arr, window_size):
    """ Construct a sliding window view of the array"""
    arr = np.asarray(arr)
    window_size = int(window_size)
    if arr.ndim != 2:
        raise ValueError("need 2-D input")
    if not (window_size > 0):
        raise ValueError("need a positive window size")
    shape = (arr.shape[0] - window_size + 1,
             arr.shape[1] - window_size + 1,
             window_size, window_size)
    if shape[0] <= 0:
        shape = (1, shape[1], arr.shape[0], shape[3])
    if shape[1] <= 0:
        shape = (shape[0], 1, shape[2], arr.shape[1])
    strides = (arr.shape[1]*arr.itemsize, arr.itemsize,
               arr.shape[1]*arr.itemsize, arr.itemsize)
    return as_strided(arr, shape=shape, strides=strides)

def cell_neighbors(arr, i, j, d):
    """Return d-th neighbors of cell (i, j)"""
    w = sliding_window(arr, 2*d+1)

    ix = np.clip(i - d, 0, w.shape[0]-1)
    jx = np.clip(j - d, 0, w.shape[1]-1)

    i0 = max(0, i - d - ix)
    j0 = max(0, j - d - jx)
    i1 = w.shape[2] - max(0, d - i + ix)
    j1 = w.shape[3] - max(0, d - j + jx)

    return w[ix, jx][i0:i1,j0:j1].ravel()

x = np.arange(8*8).reshape(8, 8)
print x

for d in [1, 2]:
    for p in [(0,0), (0,1), (6,6), (8,8)]:
        print "-- d=%d, %r" % (d, p)
        print cell_neighbors(x, p[0], p[1], d=d)

【讨论】:

    【解决方案3】:

    问题是您不断将 neighbours 重新分配给长度为 8 的一维数组。相反,您应该将邻居数据分配给您已经创建的数组的 slice

    for i in range(1, ran_x-1):
        for j in range(1, ran_y-1):
            neighbours[i-1,j-1,:] = [matrix[i-1,j-1],matrix[i-1,j],matrix[i-1,j+1],matrix[i,j-1],matrix[i,j+1],matrix[i+1,j-1],matrix[i+1,j],matrix[i+1,j+1]]
    

    请注意,我更改了范围,因此您不需要 if 语句。您的代码会更快并且(可以说)更整洁,如下所示:

    neighbours = np.empty((ran_x-2, ran_y-2, 8), int)
    
    # bool array to extract outer ring from a 3x3 array:
    b = np.array([[1,1,1],[1,0,1],[1,1,1]], bool)
    
    for i in range(ran_x-2):
        for j in range(ran_y-2):
            neighbours[i,j,:] = matrix[i:i+3, j:j+3][b]
    

    当然,如果您需要的话,直接打印邻居而不存储它们会更快。

    【讨论】: