【问题标题】:Sum of 8 neighbors in 2d array二维数组中 8 个邻居的总和
【发布时间】:2016-08-26 04:21:10
【问题描述】:

我需要找到一个单元格的所有相邻元素的总和,比如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 库来查找给定单元格旁边的所有元素的总和?

【问题讨论】:

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

标签: python numpy matrix


【解决方案1】:

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

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() 消费

  • 遍历生成器对象剩余元素,计算和赋值 如果索引不是,则矩阵索引并将值添加到总计 负数(出于显而易见的原因)并在指数为 超出范围(索引错误)

  • 函数要求用户在基于手指的索引中输入单元格位置 并且需要扣除 -1 才能将值转换为基于 0 的索引

【讨论】:

    【解决方案2】:

    刚刚创建了这个功能来完成这项工作

    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, ... 变量?
    【解决方案3】:

    您可以使用切片和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 的存在是因为负起始索引会触发不同的切片。

    【讨论】:

      【解决方案4】:

      如果不介意对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]])
      

      【讨论】:

      • @dan-man:我猜“更容易”在旁观者的眼中。在这种情况下uniform_filter的有效内核是[[1/9, 1/9, 1/9], [1/9, 1/9, 1/9], [1/9, 1/9, 1 /9]]。因此,要获得所需的结果,您必须将输入或输出缩放 9,并减去原始数组。在我看来,这并不比我所展示的更容易。
      【解决方案5】:

      解决方案

      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 之前和之后按行分割A,在j 之前和之后列。在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 我相信这就是我提供的。我将添加一个演示。
      • 哎呀。不知道为什么我第一次运行它时它返回错误的输出。无论如何,很抱歉造成误解。并感谢您的回答。
      猜你喜欢
      • 1970-01-01
      • 2021-05-23
      • 2017-10-04
      • 2010-10-13
      • 2013-04-08
      • 1970-01-01
      • 2011-02-12
      • 2017-12-23
      相关资源
      最近更新 更多