Generating banded matrices using numpy

前端 未结 3 2057
梦毁少年i
梦毁少年i 2021-01-06 14:17

I\'m using the following piece of code to create a banded matrix from a generator g:

def banded(g, N):
    \"\"\"Creates a `g` generated banded          


        
相关标签:
3条回答
  • 2021-01-06 14:47

    Here's one with np.lib.stride_tricks.as_strided to give us a 2D view into a zeros padded 1D version of the input and as such pretty memory efficient and hence performant too. This trick had been explored numerous times - 1,2.

    Thus, the implementation would be -

    def sliding_windows(a, W):
        a = np.asarray(a)
        p = np.zeros(W-1,dtype=a.dtype)
        b = np.concatenate((p,a,p))
        s = b.strides[0]
        strided = np.lib.stride_tricks.as_strided
        return strided(b[W-1:], shape=(W,len(a)+W-1), strides=(-s,s))
    

    Sample runs -

    In [99]: a = [1,2,3]
    
    In [100]: sliding_windows(a, W=3)
    Out[100]: 
    array([[1, 2, 3, 0, 0],
           [0, 1, 2, 3, 0],
           [0, 0, 1, 2, 3]])
    
    In [101]: a = [1,2,3,4,5]
    
    In [102]: sliding_windows(a, W=3)
    Out[102]: 
    array([[1, 2, 3, 4, 5, 0, 0],
           [0, 1, 2, 3, 4, 5, 0],
           [0, 0, 1, 2, 3, 4, 5]])
    

    With the same philosophy, but less messier version, we can also leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windows. More info on use of as_strided based view_as_windows.

    from skimage.util.shape import view_as_windows
    
    def sliding_windows_vw(a, W):
        a = np.asarray(a)
        p = np.zeros(W-1,dtype=a.dtype)
        b = np.concatenate((p,a,p))
        return view_as_windows(b,len(a)+W-1)[::-1]
    
    0 讨论(0)
  • 2021-01-06 14:58

    You can also use scipy's toeplitz function, which is very similar to its matlab counterpart. It is also smart around the shape, do do not worry about the it.

    import scipy.linalg as scl
    
    # define first column and first line
    column1 = [1,0,0]
    line1 = [1,2,3,0,0]
    
    scl.toeplitz(column1, line1)
    

    If you want variable sizes, use your size parameter (N) to add zeros to the columns and lines dynamically. The following is my implementation for finite differences with a minimum size of 3.

    col = [1,0,0] + [0] * (size -3)
    lin = [1,2,1] + [0] * (size -3)
    m = scl.toeplitz(col, lin)
    

    Output:

    array([[1., 2., 1., 0., 0.],
            [0., 1., 2., 1., 0.],
            [0., 0., 1., 2., 1.],
            [0., 0., 0., 1., 2.],
            [0., 0., 0., 0., 1.]])
    
    0 讨论(0)
  • 2021-01-06 15:00

    You could use scipy.sparse.diags:

    Input:

    diags([1, 2, 3], [0, 1, 2], shape=(3,5)).toarray()
    

    Output:

    array([[ 1.,  2.,  3.,  0.,  0.],
          [ 0.,  1.,  2.,  3.,  0.],
          [ 0.,  0.,  1.,  2.,  3.]])
    

    The second list, [0, 1, 2], is an offset list. It tells how offset from the diagonal you want a certain element to be.

    0 讨论(0)
提交回复
热议问题