【问题标题】:Extract blocks or patches from NumPy Array从 NumPy 数组中提取块或补丁
【发布时间】:2015-10-10 05:45:58
【问题描述】:

我有一个二维 numpy 数组,如下所示:

a = np.array([[1,5,9,13],
              [2,6,10,14],
              [3,7,11,15],
              [4,8,12,16]]

我想在不重复元素的情况下将其提取为 2 x 2 大小的补丁。

答案应该完全一样。这可以是具有相同元素顺序的 3-d 数组或列表,如下所示:

[[[1,5],
 [2,6]],   

 [[3,7],
 [4,8]],

 [[9,13],
 [10,14]],

 [[11,15],
 [12,16]]]

如何轻松做到?

在我的实际问题中,a 的大小是 (36, 72)。我不能一一做。我想要程序化的方式。

【问题讨论】:

  • 我在stackoverflow.com/questions/26871083/… 更新了我的答案。鉴于这个问题和stackoverflow.com/questions/31494190/…,我认为我们可以将这个问题作为骗子关闭。
  • @WarrenWeckesser 你能在这里告诉我,当我在我的问题中手动提取补丁时,你将如何提取补丁?
  • @WarrenWeckesser 这不是像 oyur 回答那样计算平均值
  • 我已经改进了我对stackoverflow.com/questions/26871083/… 的答案如何工作的解释。你看到以“To generalize ...”开头的部分了吗?有两个步骤:将数组重塑为 4 维数组,然后平均。重塑部分与您所要求的相同,所以我不想在这里重复。
  • @WarrenWeckesser 我认为你的答案足以让他概括为一个答案(你给出了确切的公式哈哈)。这绝对让我的小宝贝 python 编码器感到羞耻。我很高兴看到它。

标签: numpy scipy scikit-learn scikit-image


【解决方案1】:

使用 scikit-image:

import numpy as np
from skimage.util import view_as_blocks

a = np.array([[1,5,9,13],
              [2,6,10,14],
              [3,7,11,15],
              [4,8,12,16]])

print(view_as_blocks(a, (2, 2)))

【讨论】:

    【解决方案2】:

    您可以通过np.reshapenp.swapaxes 的组合来实现它,就像这样 -

    def extract_blocks(a, blocksize, keep_as_view=False):
        M,N = a.shape
        b0, b1 = blocksize
        if keep_as_view==0:
            return a.reshape(M//b0,b0,N//b1,b1).swapaxes(1,2).reshape(-1,b0,b1)
        else:
            return a.reshape(M//b0,b0,N//b1,b1).swapaxes(1,2)
    

    可以看出,有两种使用方法 - 关闭keep_as_view 标志(默认一种)或打开。使用keep_as_view = False,我们将交换轴重塑为3D 的最终输出,而使用keep_as_view = True,我们将其保持为4D,这将是输入数组的视图,因此在运行时几乎是免费的。我们将在稍后运行一个示例案例来验证它。

    示例案例

    让我们使用一个示例输入数组,就像这样 -

    In [94]: a
    Out[94]: 
    array([[2, 2, 6, 1, 3, 6],
           [1, 0, 1, 0, 0, 3],
           [4, 0, 0, 4, 1, 7],
           [3, 2, 4, 7, 2, 4],
           [8, 0, 7, 3, 4, 6],
           [1, 5, 6, 2, 1, 8]])
    

    现在,让我们使用一些块大小进行测试。让我们使用 (2,3) 的块大小并关闭和打开视图标志 -

    In [95]: extract_blocks(a, (2,3)) # Blocksize : (2,3)
    Out[95]: 
    array([[[2, 2, 6],
            [1, 0, 1]],
    
           [[1, 3, 6],
            [0, 0, 3]],
    
           [[4, 0, 0],
            [3, 2, 4]],
    
           [[4, 1, 7],
            [7, 2, 4]],
    
           [[8, 0, 7],
            [1, 5, 6]],
    
           [[3, 4, 6],
            [2, 1, 8]]])
    
    In [48]: extract_blocks(a, (2,3), keep_as_view=True)
    Out[48]: 
    array([[[[2, 2, 6],
             [1, 0, 1]],
    
            [[1, 3, 6],
             [0, 0, 3]]],
    
    
           [[[4, 0, 0],
             [3, 2, 4]],
    
            [[4, 1, 7],
             [7, 2, 4]]],
    
    
           [[[8, 0, 7],
             [1, 5, 6]],
    
            [[3, 4, 6],
             [2, 1, 8]]]])
    

    keep_as_view=True验证view

    In [20]: np.shares_memory(a, extract_blocks(a, (2,3), keep_as_view=True))
    Out[20]: True
    

    让我们检查一下大型阵列的性能,并验证前面讨论的几乎免费的运行时声明 -

    In [42]: a = np.random.rand(2000,3000)
    
    In [43]: %timeit extract_blocks(a, (2,3), keep_as_view=True)
    1000000 loops, best of 3: 801 ns per loop
    
    In [44]: %timeit extract_blocks(a, (2,3), keep_as_view=False)
    10 loops, best of 3: 29.1 ms per loop
    

    【讨论】:

      【解决方案3】:

      这是一个相当神秘的 numpy one-liner 来生成你的 3-d 数组,在这里称为 result1

      In [60]: x
      Out[60]: 
      array([[2, 1, 2, 2, 0, 2, 2, 1, 3, 2],
             [3, 1, 2, 1, 0, 1, 2, 3, 1, 0],
             [2, 0, 3, 1, 3, 2, 1, 0, 0, 0],
             [0, 1, 3, 3, 2, 0, 3, 2, 0, 3],
             [0, 1, 0, 3, 1, 3, 0, 0, 0, 2],
             [1, 1, 2, 2, 3, 2, 1, 0, 0, 3],
             [2, 1, 0, 3, 2, 2, 2, 2, 1, 2],
             [0, 3, 3, 3, 1, 0, 2, 0, 2, 1]])
      
      In [61]: result1 = x.reshape(x.shape[0]//2, 2, x.shape[1]//2, 2).swapaxes(1, 2).reshape(-1, 2, 2)
      

      result1 就像一个二维数组的一维数组:

      In [68]: result1.shape
      Out[68]: (20, 2, 2)
      
      In [69]: result1[0]
      Out[69]: 
      array([[2, 1],
             [3, 1]])
      
      In [70]: result1[1]
      Out[70]: 
      array([[2, 2],
             [2, 1]])
      
      In [71]: result1[5]
      Out[71]: 
      array([[2, 0],
             [0, 1]])
      
      In [72]: result1[-1]
      Out[72]: 
      array([[1, 2],
             [2, 1]])
      

      (抱歉,我目前没有时间详细说明它的工作原理。也许稍后......)

      这是一个使用嵌套列表推导的不那么神秘的版本。在这种情况下,result2 是一个二维 numpy 数组的 python 列表:

      In [73]: result2 = [x[2*j:2*j+2, 2*k:2*k+2] for j in range(x.shape[0]//2) for k in range(x.shape[1]//2)]
      
      In [74]: result2[5]
      Out[74]: 
      array([[2, 0],
             [0, 1]])
      
      In [75]: result2[-1]
      Out[75]: 
      array([[1, 2],
             [2, 1]])
      

      【讨论】:

      • 谢谢,这就是我要找的东西!
      • @Warren,你值得喝一杯
      • 你会如何逆转这个操作?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-20
      • 1970-01-01
      • 2012-06-05
      • 2019-06-17
      • 1970-01-01
      相关资源
      最近更新 更多