如何在python中找到2D列表的邻居?

时间:2014-10-14 14:39:03

标签: python arrays list nearest-neighbor

我有一个只有1和0的2D列表:

Boundaries = [
[0,0,0,0,0],
[0,1,1,1,0],
[0,1,1,1,1],
[0,1,1,1,0],
[0,0,1,0,0]]

我需要测试此列表以检查是否有任何1被1个其他1包围(例如此列表中的中间1)。如果有一个被1包围的1作为邻居,那么它应该被改为0,这样在运行程序之后,上面的列表将返回如下:

[
[0,0,0,0,0],
[0,1,1,1,0],
[0,1,0,1,1],
[0,1,1,1,0],
[0,0,1,0,0]]

我试图只使用一个参数(1' s和0' s的矩阵)。出于某种原因,这是一个非常困难的事情。到目前为止,我的代码看起来像这样:

def tempBoundaries(matrixC):
    for i in matrixC:
        for j in i:
            if j == 1:
                try:
                    if matrixC[i-1]==1 or matrixC[i+1]==1:
                     .......

无论出于何种原因,这是一场真正的斗争,我似乎无法弄清楚该做什么,任何提示或帮助将不胜感激!感谢。

7 个答案:

答案 0 :(得分:10)

使用scipy,您可以执行以下操作

import numpy

boundaries = numpy.array([
                         [0,0,0,0,0],
                         [0,1,1,1,0],
                         [0,1,1,1,1],
                         [0,1,1,1,0],
                         [0,0,1,0,0]])

counts = scipy.signal.convolve2d(boundaries, numpy.ones((3,3)), mode='same')

# which gives you a matrix with counts of the number of 1s around each point
array([[ 1.,  2.,  3.,  2.,  1.],
       [ 2.,  4.,  6.,  5.,  3.],
       [ 3.,  6.,  9.,  7.,  4.],
       [ 2.,  5.,  7.,  6.,  3.],
       [ 1.,  3.,  4.,  3.,  1.]])

 # so then you just find the points where it's == 9
 counts == 9
 array([[False, False, False, False, False],
        [False, False, False, False, False],
        [False, False,  True, False, False],
        [False, False, False, False, False],
        [False, False, False, False, False]], dtype=bool)

 # so you can update those positions
 boundaries[counts == 9] = 0

所以整个操作很简单:

boundaries = numpy.array(Boundaries)
counts = scipy.signal.convolve2d(boundaries, numpy.ones((3,3)), mode='same')
boundaries[counts == 9] = 0

答案 1 :(得分:3)

由于后来添加了n numpy的要求,我觉得我应该添加一个纯粹的python答案。

你可以翻转算法。这个答案的灵感来自于计算机视觉特征提取中使用的霍夫变换(http://en.wikipedia.org/wiki/Hough_transform)。你不是在一个位置上狩猎,而是让位置投票支持他们所影响的事物。在你的情况下,每个有一个1的位置为自己及其所有邻居投票。

这是一种不同的方法,但它简化了围绕数据边缘的逻辑。你可以忽略这个方面,因为即使例如(-1,0)被投票,它也不会得到足够的投票来考虑。

更新

更改以便单元格不为自己投票。这允许我们在其他情况下使用它(通过搜索具有8票的单元格)。我将其拆分为一个函数,该函数查找被1包围的所有单元格以及执行翻转的操作(取决于您正在搜索的内容)。

import collections
import itertools


def neighbours_of(i, j):
    """Positions of neighbours (includes out of bounds but excludes cell itself)."""
    neighbours = list(itertools.product(range(i-1, i+2), range(j-1, j+2)))
    neighbours.remove((i, j))
    return neighbours


def find_surrounded(grid):
    """List of x,y positions in grid where the cell is surrounded by 1s."""

    votes = collections.defaultdict(int)

    for i, x in enumerate(grid):
        for j, y in enumerate(x):
            # we don't get to vote if not ...
            if y == 0:
                continue

            # vote for everyone in the 3x3 square around us
            for a, b in neighbours_of(i, j):
                votes[(a, b)] += 1

    # now the things we want to change are those that got 8 votes
    surrounded_positions = [pos for pos, count in votes.items() if count == 8]

    return surrounded_positions

def change_when_cell_type_surrounded(grid, cell_type):
    """Update grid inline to flip bits of cells of cell_type that are surrounded."""

    # we'll flip to the opposite of what we're looking for
    change_to = 1 - cell_type

    surrounded = find_surrounded(grid)    

    for i, j in surrounded:
        if grid[i][j] == cell_type:
            grid[i][j] = change_to


grid = [[0,0,0,0,0],
        [0,1,1,1,0],
        [0,1,1,1,1],
        [0,1,1,1,0],
        [0,0,1,0,0]]

change_when_cell_type_surrounded(grid, 1)
change_when_cell_type_surrounded(grid, 0)

答案 2 :(得分:2)

要简化代码,您应该移动代码以检查函数内的邻居。您还可以使用路线列表,然后遍历指示,如下所示:

directions = [(-1, -1), (0, -1), ...]
def check_neighbors(m, x, y):
    for direction in directions:
        dx, dy = direction
        # You should check here that (x+dx, y+dx) 
        # is still inside the matrix
        if ...:
            continue
        if matrix[x+dx][y+dy] == 0:
            return False
    return True

在主函数中,矩阵基本上是一个列表列表。由于您要操作索引,因此应使用range个可能的索引。

# Big assumption: all sublists have the same length
for x in range(len(matrixC)):
    for y in range(len(matrixC[0])):
        if check_neighbors(matrixC, x, y):
            # Do what you want here
            ...

答案 3 :(得分:1)

怎么样:

Boundaries = [
[0,0,0,0,0],
[0,1,1,1,0],
[0,1,1,1,1],
[0,1,1,1,0],
[0,0,1,0,0]]

tochange = []
for i in xrange(len(Boundaries)-3):
    for j in xrange(len(Boundaries)-3):
        for k in xrange(3):
            for l in xrange(3):
                if not Boundaries[i+k][j+k]:
                    break
            else:
                continue
            break
        else:
            tochange.append((i+1, j+1))

for i, j in tochange:
    Boundaries[i][j] = 0

答案 4 :(得分:0)

您可以使用numpy

from numpy import ones
from scipy.signal import convolve2d

kernel = ones((3, 3))
#you create a matrix like this
#1 1 1
#1 1 1
#1 1 1

image = array(Boundaries)
#your boundaries were converted to a bidimensional numpy array

convolved = convolve2d(image, kernel, mode="same")
#you will have an image like this:
#[
#    [1,2,3,2,1],
#    [2,4,6,4,3],
#    [3,6,9,7,4],
#    [2,4,6,4,3],
#    [1,2,3,2,1]
#]

然后你应该相应地改变图像:

for (x,y), value in numpy.ndenumerate(a):
    image[x, y] = image[x, y] if convolved[x, y] < 9 else 0

免责声明:此代码不会在边框中杀死1。你必须相应地改变它

答案 5 :(得分:0)

没有numpy

修改

我认为这是一个更好的解决方案,因为它一旦邻居就打破了内循环 等于零

def zero_one(input2d, r, c):
    for rr in (r-1, r, r+1):
        for cc in (c-1, c, c+1):
            if input2d[rr][cc] == 0 : return 1
    return 0

Boundaries = [[0,0,0,0,0],
              [0,1,1,1,0],
              [0,1,1,1,1],
              [0,1,1,1,0],
              [0,0,1,0,0]]

rows = 5
cols = 5
Output = []

for r in range(rows):
    Output.append([])
    for c in range(cols):
        if (r==0 or r==rows-1) or (c==0 or c==cols-1):
            Output[r].append(Boundaries[r][c])
        elif Boundaries[r][c] == 0:
            Output[r].append(0)
        else:
            Output[r].append(zero_one(Boundaries, r, c))

for line in Output:
    print line

执行上面的代码给出了

[0, 0, 0, 0, 0]
[0, 1, 1, 1, 0]
[0, 1, 0, 1, 1]
[0, 1, 1, 1, 0]
[0, 0, 1, 0, 0]

我以前的代码是在

之后

编辑结束

In [15]: Boundaries = [
[0,0,0,0,0],
[0,1,1,1,0],
[0,1,1,1,1],
[0,1,1,1,0],
[0,0,1,0,0]]

In [16]: Output = [
[0,0,0,0,0],
[0,1,1,1,0],
[0,1,1,1,1],
[0,1,1,1,0],
[0,0,1,0,0]]

In [17]: for i in (1, 2, 3):
    for j in (1,2,3):
        s = 0
        for m in (i-1, i, i+1):
            for n in (j-1, j, j+1):
                s = s+Boundaries[n][m]
        if s == 9 : Output[j][i] = 0
   ....:         

In [18]: Output
Out[18]: 
[[0, 0, 0, 0, 0],
 [0, 1, 1, 1, 0],
 [0, 1, 0, 1, 1],
 [0, 1, 1, 1, 0],
 [0, 0, 1, 0, 0]]

In [19]: 

答案 6 :(得分:0)

我创建了一个像这样的简单商品,您可以自定义

from itertools import product, starmap, islice
def findNeighbors(grid, x, y):
    xi = (0, -1, 1) if 0 < x < len(grid) - 1 else ((0, -1) if x > 0 else (0, 1))
    yi = (0, -1, 1) if 0 < y < len(grid[0]) - 1 else ((0, -1) if y > 0 else (0, 1))
    return islice(starmap((lambda a, b: grid[x + a][y + b]), product(xi, yi)), 1, None)

第一个示例:

grid = [[ 0,  1,  2,  3],
...     [ 4,  5,  6,  7],
...     [ 8,  9, 10, 11],
...     [12, 13, 14, 15]]
n = list(findNeighbors(grid, 2, 1))   # find neighbors of 9
print(n)

输出:     [8、10、5、4、6、13、12、14]

第二个示例:

grid = [[ 0,  1,  2,  3],
...     [ 4,  5,  6,  7],
...     [ 8,  9, 10, 11],
...     [12, 13, 14, 15]]
n1 = list(findNeighbors(grid, 3, 3))   # find neighbors of 15
print(n1)

输出:     [14,11,10]

让我知道您是否有任何疑问