代码之家  ›  专栏  ›  技术社区  ›  Sheldore

生成NumPy矩阵的矢量化解法

  •  1
  • Sheldore  · 技术社区  · 5 年前

    n 通过 矩阵 n>1

    n = 2
    # array([[1, 2], 
    #        [2, 3]])
    
    n = 3
    # array([[1, 2, 3], 
    #        [3, 4, 5], 
    #        [5, 6, 7]])
    
    n = 4
    # array([[1, 2, 3, 4], 
    #        [4, 5, 6, 7], 
    #        [7, 8, 9, 10], 
    #        [10, 11, 12, 13]])
    

    我的尝试 使用列表理解。同样可以用扩展for循环语法编写。

    import numpy as np
    n = 4
    arr = np.array([[(n-1)*j+i for i in range(1, n+1)] for j in range(n)])
    # array([[ 1,  2,  3,  4],
    #        [ 4,  5,  6,  7],
    #        [ 7,  8,  9, 10],
    #        [10, 11, 12, 13]])
    
    1 回复  |  直到 5 年前
        1
  •  3
  •   Dion    5 年前

    如果您想让事情保持简单(并且有点可读性),应该这样做:

    def ranged_mat(n):
        out = np.arange(1, n ** 2 + 1).reshape(n, n)
        out -= np.arange(n).reshape(n, 1)
        return out
    

    只需构建从1到n的所有数字,将其重塑为所需的块形状,然后从每行中减去行号。

    ranged_mat_v2 ,但我喜欢显式地使用中间数组形状。并非所有人都是NumPy广播规则的专家。

        2
  •  2
  •   Divakar    5 年前

    方法#1

    我们可以利用 np.lib.stride_tricks.as_strided 基于 scikit-image's view_as_windows 要得到滑动窗口。 More info on use of as_strided based view_as_windows .

    step

    from skimage.util.shape import view_as_windows
    
    def ranged_mat(n):
        r  = np.arange(1,n*(n-1)+2)
        return view_as_windows(r,n,step=n-1)
    

    样本运行-

    In [270]: ranged_mat(2)
    Out[270]: 
    array([[1, 2],
           [2, 3]])
    
    In [271]: ranged_mat(3)
    Out[271]: 
    array([[1, 2, 3],
           [3, 4, 5],
           [5, 6, 7]])
    
    In [272]: ranged_mat(4)
    Out[272]: 
    array([[ 1,  2,  3,  4],
           [ 4,  5,  6,  7],
           [ 7,  8,  9, 10],
           [10, 11, 12, 13]])
    

    进近#2

    另一个 outer-broadcasted-addition

    def ranged_mat_v2(n):
        r = np.arange(n)
        return (n-1)*r[:,None]+r+1
    

    方法#3

    我们也可以使用 numexpr module 它支持多核处理,从而在大型计算机上实现更好的效率 n's -

    import numexpr as ne
    
    def ranged_mat_v3(n):
        r = np.arange(n)
        r2d = (n-1)*r[:,None]
        return ne.evaluate('r2d+r+1')
    

    使用切片可以使我们的内存效率更高-

    def ranged_mat_v4(n):
        r  = np.arange(n+1)
        r0 = r[1:]
        r1 = r[:-1,None]*(n-1)
        return ne.evaluate('r0+r1')
    

    In [423]: %timeit ranged_mat(10000)
    273 ms ± 3.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    In [424]: %timeit ranged_mat_v2(10000)
    316 ms ± 2.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    In [425]: %timeit ranged_mat_v3(10000)
    176 ms ± 85.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    In [426]: %timeit ranged_mat_v4(10000)
    154 ms ± 82.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
        3
  •  1
  •   Tls Chris    5 年前

    下面还有一个np.from函数。 docs here

    def func(n):
        return np.fromfunction(lambda r,c: (n-1)*r+1+c, shape=(n,n))
    

        4
  •  1
  •   yatu Sayali Sonawane    5 年前

    我们可以使用 NumPy strides 为此:

    def as_strides(n):
        m = n**2 - (n-1)
        a = np.arange(1, m+1)
        s = a.strides[0]
        return np.lib.stride_tricks.as_strided(a, shape=(n,n), strides=((n-1)*s,s))
    

    as_strides(2)
    rray([[1, 2],
           [2, 3]])
    
    as_strides(3)
    array([[1, 2, 3],
           [3, 4, 5],
           [5, 6, 7]])
    
    as_strides(4)
    array([[ 1,  2,  3,  4],
           [ 4,  5,  6,  7],
           [ 7,  8,  9, 10],
           [10, 11, 12, 13]])