代码之家  ›  专栏  ›  技术社区  ›  Panos Kalatzantonakis

将元素插入numy数组并获得所有滚动排列

  •  7
  • Panos Kalatzantonakis  · 技术社区  · 7 年前

    有没有更好的方法在数组中逐个插入元素
    所有可能的位置 (n+1个位置) .

    例如插入 [1] [6 7 8 9] 应产生:

    [1 6 7 8 9]
    [9 1 6 7 8]
    [8 9 1 6 7]
    [7 8 9 1 6]
    [6 7 8 9 1]
    

    如果我插入 A = [1 2 3] 一个接一个到B= [6 7 8 9] 它应该产生:

    [1 6 7 8 9]
    [9 1 6 7 8]
    [8 9 1 6 7]
    [7 8 9 1 6]
    [6 7 8 9 1]
    --------------------
    [2 6 7 8 9]
    [9 2 6 7 8]
    [8 9 2 6 7]
    [7 8 9 2 6]
    [6 7 8 9 2]
    --------------------
    [3 6 7 8 9]
    [9 3 6 7 8]
    [8 9 3 6 7]
    [7 8 9 3 6]
    [6 7 8 9 3]
    --------------------
    

    numpy.roll 这样地:

    import numpy as np
    import timeit
    
    A = np.array([1, 2, 3, 4, 5])
    B = np.array([6, 7, 8, 9])
    
    def inject_one(Ad, Bd):
        for i, _ in enumerate(Ad):
            C = np.append(Ad[i], Bd)
            for _ in range(len(C) - 1):
                C = np.roll(C, 1)
    
    t = timeit.Timer(lambda: inject_one(A, B))
    print("{:.3f}secs for 1000 iterations".format(t.timeit(number=1000))) 
    # > 0.160 secs
    
    3 回复  |  直到 7 年前
        1
  •  3
  •   user3483203    7 年前

    你在这里要求的是 Toeplitz Matrix ,即:

    一种矩阵,其中从左到右的每个降序对角线都是常数

    scipy 具有易于使用的实现:

    from scipy.linalg import toeplitz
    
    def magic_toeplitz(arr, to_add):
        return toeplitz(np.hstack([to_add, arr[::-1]]), np.hstack([to_add, arr]))
    
    a = [6,7,8,9]
    add = [1]
    magic_toeplitz(a, add)
    

    array([[1, 6, 7, 8, 9],
           [9, 1, 6, 7, 8],
           [8, 9, 1, 6, 7],
           [7, 8, 9, 1, 6],
           [6, 7, 8, 9, 1]])
    

    A = np.array([1, 2, 3, 4, 5])
    B = np.array([6, 7, 8, 9])
    
    out = toeplitz(np.hstack([[np.nan], B[::-1]]), np.hstack([np.nan, B]))
    out = np.tile(out, (len(A), 1, 1))
    m = np.ma.array(out, mask=np.isnan(out))
    vals = np.repeat(A, (B.shape[0] + 1)**2).reshape(out.shape)
    print(m.filled(vals))
    

    array([[[1, 6, 7, 8, 9],
            [9, 1, 6, 7, 8],
            [8, 9, 1, 6, 7],
            [7, 8, 9, 1, 6],
            [6, 7, 8, 9, 1]],
    
           [[2, 6, 7, 8, 9],
            [9, 2, 6, 7, 8],
            [8, 9, 2, 6, 7],
            [7, 8, 9, 2, 6],
            [6, 7, 8, 9, 2]],
    
           [[3, 6, 7, 8, 9],
            [9, 3, 6, 7, 8],
            [8, 9, 3, 6, 7],
            [7, 8, 9, 3, 6],
            [6, 7, 8, 9, 3]],
    
           [[4, 6, 7, 8, 9],
            [9, 4, 6, 7, 8],
            [8, 9, 4, 6, 7],
            [7, 8, 9, 4, 6],
            [6, 7, 8, 9, 4]],
    
           [[5, 6, 7, 8, 9],
            [9, 5, 6, 7, 8],
            [8, 9, 5, 6, 7],
            [7, 8, 9, 5, 6],
            [6, 7, 8, 9, 5]]])
    
        2
  •  3
  •   Divakar    7 年前

    2D

    我们可以利用 np.lib.stride_tricks.as_strided 基于 scikit-image's view_as_windows 去拿推拉窗。 More info on use of as_strided based view_as_windows .

    1D 数组以及要添加的新值( 1 在这种情况下)然后 仔细观察。作为一个视图,它将是非常有效的,看起来像这样-

    from skimage.util.shape import view_as_windows
    
    def rolling_add(a,val=1):
        a_ext = np.r_[a,val,a]
        return view_as_windows(a_ext,len(a)+1,1)[::-1]
    

    np.lib.u技巧。当你大步走的时候 要避免翻转部分: [::-1] ,但读者可能很难理解这种设置。

    样品运行-

    In [254]: a = np.array([6, 7, 8, 9])
    
    In [255]: rolling_add(a)
    Out[255]: 
    array([[1, 6, 7, 8, 9],
           [9, 1, 6, 7, 8],
           [8, 9, 1, 6, 7],
           [7, 8, 9, 1, 6],
           [6, 7, 8, 9, 1]])
    

    In [263]: a = np.random.randint(0,10,10000)
    
    In [264]: %timeit rolling_add(a)
    10000 loops, best of 3: 58 µs per loop
    

    3D 案例

    三维

    def rolling_add3D(a,add_ar):
        a_ext = np.r_[a,0,a]
        a_ext2 = np.repeat(a_ext[None],len(add_ar),0)
        a_ext2[:,len(a)] = add_ar
        return view_as_windows(a_ext2,(1,len(a)+1))[...,0,:][:,::-1]
    

    样品运行-

    In [292]: a
    Out[292]: array([6, 7, 8, 9])
    
    In [293]: rolling_add3D(a,[1,2,3])
    Out[293]: 
    array([[[1, 6, 7, 8, 9],
            [9, 1, 6, 7, 8],
            [8, 9, 1, 6, 7],
            [7, 8, 9, 1, 6],
            [6, 7, 8, 9, 1]],
    
           [[2, 6, 7, 8, 9],
            [9, 2, 6, 7, 8],
            [8, 9, 2, 6, 7],
            [7, 8, 9, 2, 6],
            [6, 7, 8, 9, 2]],
    
           [[3, 6, 7, 8, 9],
            [9, 3, 6, 7, 8],
            [8, 9, 3, 6, 7],
            [7, 8, 9, 3, 6],
            [6, 7, 8, 9, 3]]])
    

    非常大的数组上的计时-

    In [294]: a = np.random.randint(0,10,10000)
    
    In [295]: %timeit rolling_add3D(a,[1,2,3])
    10000 loops, best of 3: 83.7 µs per loop
    

    性能将与要添加的阵列长度成正比。所以,添加一个 1000 元素排列成 10000 输入数组的长度为-

    In [301]: a = np.random.randint(0,10,10000)
    
    In [302]: add_array = np.random.randint(0,10,1000)
    
    In [303]: %timeit rolling_add3D(a,add_array)
    100 loops, best of 3: 16.9 ms per loop
    
        3
  •  2
  •   Jonas Wolff    7 年前
    for i in A:
       new_list = B[:]
       new_list.append(i)
       print(new_list)
       for q in B:
            new_list = [new_list[-1]]+new_list[:-1]
            print(new_list)
       print("-"*15)