二维数组中8个相邻元素的和

14

我需要找到一个单元格周围所有相邻元素的总和,比如getsumofneighbors(matrix, i, j):

'M*N matrix'
[[0 1 0]
 [2 0 1]
 [0 4 0]
 [0 0 0]]

[0][0]附近元素的和为3

[1][0]处为5,[1][1]处为8

是否有Python库可以找到给定单元格旁边所有元素的总和?


最简单(也可能最快)的方法是将其视为一个3x3内核的卷积,该内核由1s组成,可以使用scipy中的uniform_filter完成,也可能使用其他方法...哦,您必须从原始矩阵中减去中心值以避免包含3x3内核中心处的值。 - dan-man
你也可以使用索引来对8个偏移版本求和,但这有点混乱,并需要在内存中多次传递数据。out = np.zeros_like(A); out[1:,1:] += A[:-1,:-1];等。 - dan-man
@dan-man,你在描述一个解决方案,而这个方案在你的评论之前已经发布了2个小时。 - piRSquared
@piRSquared - 你是在指你的解决方案吗?那不是我所说的。我的两个建议都试图同时评估数组中所有条目的总和(即矢量化),而你的答案一次只给出一个条目的总和(这实际上可能是OP想要的)。 - dan-man
5个回答

17

如果您不介意依赖于scipy,可以使用scipy.ndimage.convolve函数,如下所示:

In [475]: a
Out[475]: 
array([[0, 1, 0],
       [2, 0, 1],
       [0, 4, 0],
       [0, 0, 0]])

In [476]: kernel
Out[476]: 
array([[1, 1, 1],
       [1, 0, 1],
       [1, 1, 1]])

In [477]: from scipy.ndimage import convolve

In [478]: c = convolve(a, kernel, mode='constant')

In [479]: c
Out[479]: 
array([[3, 3, 2],
       [5, 8, 5],
       [6, 3, 5],
       [4, 4, 4]])

3
我猜“更容易”是因人而异的。在这种情况下,uniform_filter函数的有效卷积核为[[1/9, 1/9, 1/9], [1/9, 1/9, 1/9], [1/9, 1/9, 1/9]]。因此,要获得所需的结果,您需要将输入或输出按9缩放,并减去原始数组。在我看来,这并不比我展示的更容易。 - Warren Weckesser

5
你可以使用切片和np.sum来计算特定区域的总和:
def getsumofneighbors(matrix, i, j):
    region = matrix[max(0, i-1) : i+2,
                    max(0, j-1) : j+2]
    return np.sum(region) - matrix[i, j] # Sum the region and subtract center

请注意,max的存在是因为负数起始索引会触发不同的切片操作。


1

解决方案

def sum_neighbors(A, i, j):
    rows, columns = A.shape
    r0, r1 = max(0, i-1), min(rows-1, i+1)
    c0, c1 = max(0, j-1), min(columns-1, j+1)
    rs = list({r0, i, r1})
    cs = [[c] for c in list({c0, j, c1})]

    return A[rs, cs].sum() - A[i, j]

解释

将行在i之前和之后,列在j之前和之后的切片A。取总和并减去单元格ij。所有其他代码都是为了处理边缘情况。

演示

import numpy as np

mxn = np.array([[0, 1, 0],
                [2, 0, 1],
                [0, 4, 0],
                [0, 0, 0]])

for i, j in [(0, 0), (1, 0), (1, 1)]:
    s = "sum of neigbors for i={} and j={} is {}"
    print s.format(i, j, sum_neighbors(mxn, i, j))

sum of neigbors for i=0 and j=0 is 3
sum of neigbors for i=1 and j=0 is 5
sum of neigbors for i=1 and j=1 is 8

我相信@Sanjeeth所要求的是最近单元格(水平,垂直,对角线)的总和。而不是你的代码返回的所有其他单元格的总和。 - kanayamalakar
@kanayamalakar 我相信我已经提供了这个。我会添加一些演示。 - piRSquared
糟糕。不知道为什么第一次运行时返回了错误的输出。无论如何,很抱歉误解了。感谢您的回答。 - kanayamalakar

0

以下函数应该完成查找单元格相邻元素总和的任务:

def sum_around(matrix, r, c):
    total = 0
    offset = (0, 1, -1)
    indices = ((i, j) for i in offset for j in offset)

    next(indices, None)

    for rec in indices:
        try:
            row = r - 1 + rec[0]
            col = c - 1 + rec[1]
            total += matrix[row][col] if 0 <= row and 0 <= col else 0
        except IndexError:
            continue
    return total

关键点:

  • offsets 定义了给定索引需要的相对变化,以获取周围元素(包括给定索引本身的位置,因为相对变化 [0] [0] 不会改变索引)

  • 由于偏移量中元素的顺序,索引生成器对象是这样创建的,即第一项是 (0, 0)。第一项被 next() 消耗。

  • 循环遍历生成器对象的剩余元素,计算并分配值给矩阵索引,并在索引不为负数(出于明显原因)时将值添加到总和中,在索引超出范围(IndexError)时继续执行。

  • 函数期望用户输入基于手指的索引和扣除 -1 以将值转换为基于 0 的索引。


-3
刚刚创建了这个函数,它可以完成任务。
def sumofnieghbors(MatrixObj, indexR, indexC):
    upperleft = 0
    if not (indexR < 1) or (indexC < 1):
        upperleft = MatrixObj[indexR - 1][indexC - 1]
    upper = 0
    if not (indexR < 1):
        upper = MatrixObj[indexR - 1][indexC]
    upperright = 0
    if not ((indexR < 1) or (indexC >= NbofCol)):
        upperright = MatrixObj[indexR - 1][indexC + 1]
    right = 0
    if not (indexC >= NbofCol):
        right = MatrixObj[indexR][indexC + 1]
    rightdown = 0
    if not ((indexR >= NbofRow) or (indexC >= NbofCol)):
        rightdown = MatrixObj[indexR + 1][indexC + 1]
    down = 0
    if not (indexR >= NbofRow):
        down = MatrixObj[indexR + 1][indexC]
    leftdown = 0
    if not ((indexR >= NbofRow) or (indexC < 1)):
        leftdown = MatrixObj[indexR + 1][indexC - 1]
    left = 0
    if not (indexC < 1):
        left = MatrixObj[indexR][indexC - 1]
    return (upperleft + upper + upperright + right + rightdown + down + leftdown + left)

请检查您的缩进并解释一下您在做什么?看起来像是一些手动迭代,迭代什么?为什么要使用 left,... 变量? - MSeifert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接