【问题标题】:How to find the sum of number layer in ndarray如何在ndarray中找到数字层的总和
【发布时间】:2014-12-24 15:40:47
【问题描述】:

我有一个 10*10 的数组。我需要找到所有层的总和。下图将清除我的问题:

我怎样才能轻松做到这一点?

【问题讨论】:

  • 你在使用 numpy 吗?
  • 是的..我正在使用 numpy

标签: python numpy multidimensional-array


【解决方案1】:

只是添加另一个答案...虽然从外部正方形中减去内部正方形的一般想法可能是最好的方法,但如果您想要性能,那么所提供的任何实现都不会做得太好,因为它们会不断添加相同的数字和结束。为了加快计算速度,您可以使用图像处理中的积分图像:

>>> int_arr = np.cumsum(np.cumsum(arr, axis=0), axis=1)
>>> int_arr
array([[  8,   8,  15,  19,  22,  22,  22,  29,  35,  44],
       [ 16,  17,  24,  34,  40,  44,  46,  54,  64,  79],
       [ 24,  30,  46,  62,  76,  80,  82,  91, 104, 119],
       [ 27,  35,  59,  84, 103, 115, 123, 137, 156, 178],
       [ 33,  48,  77, 103, 123, 135, 148, 163, 191, 213],
       [ 41,  65,  98, 129, 158, 177, 190, 205, 233, 259],
       [ 48,  81, 120, 158, 191, 217, 235, 251, 286, 316],
       [ 54,  95, 136, 180, 214, 249, 275, 296, 333, 364],
       [ 63, 105, 147, 194, 235, 276, 310, 331, 376, 414],
       [ 65, 115, 163, 213, 260, 306, 340, 364, 410, 456]])

从这个辅助数组中,您可以计算任何矩形子数组的面积,加上两个条目并减去另外两个条目,例如:

>>> np.sum(arr[1:-1, 1:-1])
286
>>> int_arr[-2,-2] + int_arr[0, 0] - int_arr[-2, 0] - int_arr[0, -2]
286

有了这个,你可以很容易地计算你的总和,例如:

sums = [int_arr[-1, -1]]
top = 0
bot = len(arr) - 2
while top < bot:
    new_sum = (int_arr[bot, bot] + int_arr[top, top] -
               int_arr[top, bot] - int_arr[bot, top])
    sums[-1] -= new_sum
    sums.append(new_sum)
    top += 1
    bot -= 1

>>> sums
[170, 122, 85, 62, 17]

【讨论】:

    【解决方案2】:

    这是一个解决方案,无需重复对相同元素求和,也无需中间数组(只是蛮力索引的乐趣),它适用于正方形 n by n 数组,用于奇数或偶数 n

    import numpy as np
    
    def sum_shells(a):
        n = len(a)
        no2 = n // 2
        shell_sums = []
        for i in range(no2):
            shell_sums.append(np.sum(a[i,i:n-i]) + np.sum(a[n-i-1,i:n-i]) +
                              np.sum(a[i+1:n-i-1,i]) + np.sum(a[i+1:n-i-1,n-i-1]))
        if n % 2:
            shell_sums.append(a[no2, no2])
        return shell_sums
    
    a = np.array([
      [8, 0, 7, 4, 3, 0, 0, 7, 6, 9],
      [8, 1, 0, 6, 3, 4, 2, 1, 4, 6],
      [8, 5, 9, 6, 8, 0, 0, 1, 3, 0],
      [3, 2, 8, 9, 5, 8, 6, 5, 6, 7],
      [6, 7, 5, 1, 1, 0, 5, 1, 9, 0],
      [8, 9, 4, 5, 9, 7, 0, 0, 0, 4],
      [7, 9, 6, 7, 4, 7, 5, 1, 7, 4],
      [6, 8, 2, 6, 1, 9, 8, 5, 2, 1],
      [9, 1, 1, 3, 7, 6, 8, 0, 8, 7],
      [2, 8, 6, 3, 6, 5, 0, 3, 1, 8] ])
    
    b = np.array([[9, 5, 8, 6, 5],
                  [1, 1, 0, 5, 1],
                  [5, 9, 7, 0, 0],
                  [7, 4, 7, 5, 1],
                  [9, 5, 0, 2, 3] ])
    print(sum_shells(a))
    print(sum_shells(b))
    

    生产:

    [170, 122, 85, 62, 17]
    [67, 31, 7]
    

    【讨论】:

    • 你实际上是在创建许多小的中间数组......当你这样做时,例如sum(a[i,i:n-i] + a[n-i-1,i:n-i]),numpy 分配一个新的 n-2*i 项目数组并用两个切片的元素总和填充它。这当然很容易避免,速度可能不可忽略,通过在将每个切片相加之前将它们单独相加。您还应该使用np.sum 而不是标准库的sum
    • @Jaime - 你是对的,当然:我在这里有点粗心。我已经编辑了建议的代码。谢谢。
    【解决方案3】:

    如果你知道如何得到中间一个(2n)*(2n)的平方和,那么很简单:取(2n)*(2n)平方的和,然后减去其中的(2n-2)*(2n-2)平方的和;不同的是边框上的元素之和(即在外方但不在内方):

    import numpy
    
    # let x be a 10 * 10 array
    x = numpy.array([
      [8, 0, 7, 4, 3, 0, 0, 7, 6, 9],
      [8, 1, 0, 6, 3, 4, 2, 1, 4, 6],
      [8, 5, 9, 6, 8, 0, 0, 1, 3, 0],
      [3, 2, 8, 9, 5, 8, 6, 5, 6, 7],
      [6, 7, 5, 1, 1, 0, 5, 1, 9, 0],
      [8, 9, 4, 5, 9, 7, 0, 0, 0, 4],
      [7, 9, 6, 7, 4, 7, 5, 1, 7, 4],
      [6, 8, 2, 6, 1, 9, 8, 5, 2, 1],
      [9, 1, 1, 3, 7, 6, 8, 0, 8, 7],
      [2, 8, 6, 3, 6, 5, 0, 3, 1, 8],
    ])
    
    for i in xrange(1, 6): # loop with i = 1,...,5
      # find the sum of the (2i)*(2i) square in the middle
      a = numpy.sum(x[5-i:5+i, 5-i:5+i])
    
      # find the sum of the (2i-2)*(2i-2) square in the middle
      b = numpy.sum(x[6-i:4+i, 6-i:4+i])
    
      # the difference gives the sum of the elements on the border
      s = a - b
      print s
    

    17
    62
    85
    122
    170

    【讨论】:

      【解决方案4】:

      下面的代码计算每一层,然后从中减去较小的层。它非常通用,因此任何大小为 N*N 的数组都应该能够传递给它,只要 N 是偶数(我认为)。

      import numpy as np
      
      arr = np.array([[8, 0, 7, 4, 3, 0, 0, 7, 6, 9],
                      [8, 1, 0, 6, 3, 4, 2, 1, 4, 6],
                      [8, 5, 9, 6, 8, 0, 0, 1, 3, 0],
                      [3, 2, 8, 9, 5, 8, 6, 5, 6, 7],
                      [6, 7, 5, 1, 1, 0, 5, 1, 9, 0],
                      [8, 9, 4, 5, 9, 7, 0, 0, 0, 4],
                      [7, 9, 6, 7, 4, 7, 5, 1, 7, 4],
                      [6, 8, 2, 6, 1, 9, 8, 5, 2, 1],
                      [9, 1, 1, 3, 7, 6, 8, 0, 8, 7],
                      [2, 8, 6, 3, 6, 5, 0, 3, 1, 8]])
      
      N = len(arr)
      
      def sum_layer(arr, M, N=N):
          """Function to return the sum of a layer."""
          return arr[M:N-M, M:N-M].sum()
      
      # Each of the layers.
      layers = [sum_layer(arr, i) for i in range(N - N//2)]
      
      # Subtract the smaller areas from the larger, to get the margins.
      result = [layers[i] - layers[i+1] for i in range(N//2 - 1)]
      
      # Need to add the final, smallest layer on.
      result.append(layers[-1])
      
      print(result)
      # [170, 122, 85, 62, 17]
      

      【讨论】:

        【解决方案5】:

        我有个主意。首先找到整个 10*10 数组的总和,然后找到内部 9*9 数组的总和。那么减法就是外层相加的结果。

        for i in range(len(A)/2):
            B = A[1:-1, 1:-1]
            print sum(A)-sum(B)
            A = B
        

        一个循环会找到所有的总和。

        可能有更好的方法来做到这一点..

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-16
          • 1970-01-01
          相关资源
          最近更新 更多