【问题标题】:Quick way to upsample numpy array by nearest neighbor tiling [duplicate]通过最近邻平铺对numpy数组进行上采样的快速方法[重复]
【发布时间】:2023-03-24 06:55:02
【问题描述】:

我有一个整数的二维数组 MxN,我想将数组扩展为 (BM)x(BN) 其中 B 是方块边的长度,因此输入数组的每个元素在最终数组中作为 BxB 块重复。下面是一个带有嵌套 for 循环的示例。有更快/内置的方式吗?

import numpy as np

a = np.arange(9).reshape([3,3])            # input array - 3x3
B=2.                                       # block size - 2  
A = np.zeros([a.shape[0]*B,a.shape[1]*B])  # output array - 6x6

# Loop, filling A with tiled values of a at each index
for i,l in enumerate(a):                   # lines in a
    for j,aij in enumerate(l):             # a[i,j]
        A[B*i:B*(i+1),B*j:B*(j+1)] = aij

结果...

a=      [[0 1 2]
         [3 4 5]
         [6 7 8]]

A =     [[ 0.  0.  1.  1.  2.  2.]
         [ 0.  0.  1.  1.  2.  2.]
         [ 3.  3.  4.  4.  5.  5.]
         [ 3.  3.  4.  4.  5.  5.]
         [ 6.  6.  7.  7.  8.  8.]
         [ 6.  6.  7.  7.  8.  8.]]

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    一个选项是

    >>> a.repeat(2, axis=0).repeat(2, axis=1)
    array([[0, 0, 1, 1, 2, 2],
           [0, 0, 1, 1, 2, 2],
           [3, 3, 4, 4, 5, 5],
           [3, 3, 4, 4, 5, 5],
           [6, 6, 7, 7, 8, 8],
           [6, 6, 7, 7, 8, 8]])
    

    由于中间数组,这有点浪费,但至少简洁。

    【讨论】:

      【解决方案2】:

      可能不是最快的,但是..

      np.kron(a, np.ones((B,B), a.dtype))
      

      它执行Kronecker product,因此它涉及输出中每个元素的乘法。

      【讨论】:

        【解决方案3】:

        这是一种使用步幅技巧和重塑的潜在快速方法:

        from numpy.lib.stride_tricks import as_strided
        
        def tile_array(a, b0, b1):
            r, c = a.shape                                    # number of rows/columns
            rs, cs = a.strides                                # row/column strides 
            x = as_strided(a, (r, b0, c, b1), (rs, 0, cs, 0)) # view a as larger 4D array
            return x.reshape(r*b0, c*b1)                      # create new 2D array
        

        a 中的底层数据是在调用reshape 时复制的,因此该函数不返回视图。但是,与沿多个轴使用repeat 相比,需要的复制操作更少。

        然后可以按如下方式使用该函数:

        >>> a = np.arange(9).reshape(3, 3)
        >>> a
        array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]])
        
        >>> tile_array(a, 2, 2)
        array([[0, 0, 1, 1, 2, 2],
               [0, 0, 1, 1, 2, 2],
               [3, 3, 4, 4, 5, 5],
               [3, 3, 4, 4, 5, 5],
               [6, 6, 7, 7, 8, 8],
               [6, 6, 7, 7, 8, 8]])
        
        >>> tile_array(a, 3, 4)
        array([[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2],
               [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2],
               [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2],
               [3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5],
               [3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5],
               [3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5],
               [6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8],
               [6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8],
               [6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8]])
        

        现在,对于 small 块,此方法比使用 repeat 慢一点,但比 kron 快。

        但是,对于稍大的块,它会比其他替代方案更快。例如,使用(20, 20) 的块形状:

        >>> %timeit tile_array(a, 20, 20)
        100000 loops, best of 3: 18.7 µs per loop
        
        >>> %timeit a.repeat(20, axis=0).repeat(20, axis=1)
        10000 loops, best of 3: 26 µs per loop
        
        >>> %timeit np.kron(a, np.ones((20,20), a.dtype))
        10000 loops, best of 3: 106 µs per loop
        

        方法之间的差距随着块大小的增加而增加。

        另外,如果a 是一个大数组,它可能比其他方法更快:

        >>> a2 = np.arange(1000000).reshape(1000, 1000)
        >>> %timeit tile_array(a2, 2, 2)
        100 loops, best of 3: 11.4 ms per loop
        
        >>> %timeit a2.repeat(2, axis=0).repeat(2, axis=1)
        1 loops, best of 3: 30.9 ms per loop
        

        【讨论】:

        • a.repeat(20,1).repeat(20,0) 比 a.repeat(20,0).repeat(20,1) 快 5 倍。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-06
        • 1970-01-01
        • 2019-01-30
        • 1970-01-01
        • 2015-03-06
        相关资源
        最近更新 更多