【问题标题】:Write vector into matrix starting from the diagonal从对角线开始将向量写入矩阵
【发布时间】:2019-01-23 03:10:39
【问题描述】:

我有一个向量长度n 和一个mxm 矩阵。通常m >> nmn 大得多)。我需要从对角线开始反复将向量写入矩阵。例如:

带有4x4 零矩阵的向量v = [v_1, v_2, v_3] 会导致:

v_1,  v_2,  v_3,  0
0,    v_1,  v_2,  v_3
0,    0,    v_1,  v_2
0,    0,    0,    v_1

因为我必须经常这样做,所以它必须相当快。现在我在原始 python 中遍历矩阵的每一行并将向量写入所需的位置,但这很慢。

【问题讨论】:

  • 发布的解决方案是否对您有用?
  • 我明天试试然后回来!抱歉,因为工作中的另一个项目而分心了……

标签: python numpy


【解决方案1】:

检查numpy.eye。这对你有用吗?

v = [1,2,3]
N = 5
M = 10
arr = np.sum(np.eye(N, k=i, M=10) * j for i, j in enumerate(v))
arr
>>array([[1., 2., 3., 0., 0., 0., 0., 0., 0., 0.],
   [0., 1., 2., 3., 0., 0., 0., 0., 0., 0.],
   [0., 0., 1., 2., 3., 0., 0., 0., 0., 0.],
   [0., 0., 0., 1., 2., 3., 0., 0., 0., 0.],
   [0., 0., 0., 0., 1., 2., 3., 0., 0., 0.]])

编辑(感谢 hpaulj 的建议):如果你的矩阵很大并且有很多 0,你可以使用稀疏矩阵

from scipy.sparse import diags
arr = diags(v,offsets=[0,1,2],shape=(N,M))
print(arr.A)
>>array([[1., 2., 3., 0., 0., 0., 0., 0., 0., 0.],
   [0., 1., 2., 3., 0., 0., 0., 0., 0., 0.],
   [0., 0., 1., 2., 3., 0., 0., 0., 0., 0.],
   [0., 0., 0., 1., 2., 3., 0., 0., 0., 0.],
   [0., 0., 0., 0., 1., 2., 3., 0., 0., 0.]])

【讨论】:

  • 既然你提到scipy.sparse,试试sparse.diags([1,2,3],offsets=[0,1,2],shape=(4,4),dtype=int).A
  • numpy.eye 对于我的用例来说工作得足​​够快!谢谢!
【解决方案2】:

这是与Divakar's 类似的答案,但仅适用于 NumPy。它用零填充给定的向量,然后从该缓冲区创建一个视图:

import numpy as np

def view_into_diagonals(v, m):
    # Add zeros before and after the vector
    v_pad = np.pad(v, [(m - 1, m - len(v))], mode='constant')
    # Current stride
    s, = v_pad.strides
    # Offset from which the first row starts
    offset = s * (m - 1)
    # Make ndarray
    view = np.ndarray(shape=(m, m),
                      dtype=v_pad.dtype,
                      buffer=v_pad.data,
                      offset=offset,
                      # Each column moves one forward, each row moves one backwards
                      strides=(-s, s))
    # Probably better not write to it
    view.flags.writeable = False
    return view

print(view_into_diagonals([1, 2, 3], 6))
# [[1 2 3 0 0 0]
#  [0 1 2 3 0 0]
#  [0 0 1 2 3 0]
#  [0 0 0 1 2 3]
#  [0 0 0 0 1 2]
#  [0 0 0 0 0 1]]

【讨论】:

    【解决方案3】:

    解决它的一个想法是在两边填充适当数量的零,并沿着它获得长度为m 的滑动窗口。我们可以利用基于scikit-image's view_as_windowsnp.lib.stride_tricks.as_strided 来获得滑动窗口。 More info on use of as_strided based view_as_windows.

    from skimage.util.shape import view_as_windows
    
    def extend2D(a, m):
        # Create zeros padded version
        p1 = np.zeros(m-1,dtype=a.dtype)
        p2 = np.zeros(m-len(a),dtype=a.dtype)    
        b = np.concatenate((p1,a,p2))
    
        # Get sliding windows along it of lengths `m` and finally flip rows
        return view_as_windows(b,m)[::-1]
    

    输出将只是将窗口视图滑动到输入的零填充版本中。因此,如果您需要输出有自己的内存空间,请将.copy() 附加到输出。

    示例运行 -

    In [45]: a
    Out[45]: array([5, 8, 6])
    
    In [46]: extend2D(a, m=4)
    Out[46]: 
    array([[5, 8, 6, 0],
           [0, 5, 8, 6],
           [0, 0, 5, 8],
           [0, 0, 0, 5]])
    
    In [47]: extend2D(a, m=5)
    Out[47]: 
    array([[5, 8, 6, 0, 0],
           [0, 5, 8, 6, 0],
           [0, 0, 5, 8, 6],
           [0, 0, 0, 5, 8],
           [0, 0, 0, 0, 5]])
    

    优化-I

    如果您想通过使用np.lib.stride_tricks.as_strided 坚持使用 NumPy 来弄脏strided-indexing 并在此过程中避免在前一种方法的最后一步中翻转 -

    def extend2D_v2(a, m):
        p1 = np.zeros(m-1,dtype=a.dtype)
        p2 = np.zeros(m-len(a),dtype=a.dtype)    
        b = np.concatenate((p1,a,p2))
        s = b.strides[0]
        return np.lib.stride_tricks.as_strided(b[m-1:],shape=(m,m),strides=(-s,s))
    

    优化-II

    进一步优化,我们可以初始化一个 zeros 数组,然后将输入赋值给它 -

    def extend2D_v3(a, m):
        b = np.zeros(2*m-1,dtype=a.dtype)
        b[m-1:m-1+len(a)] = a
        s = b.strides[0]
        return np.lib.stride_tricks.as_strided(b[m-1:],shape=(m,m),strides=(-s,s))
    

    n=100m=10000 随机数据数组的时序 -

    In [97]: np.random.seed(0)
        ...: a = np.random.randint(1,9,(100))
    
    In [98]: %timeit extend2D(a, m=10000)
        ...: %timeit extend2D_v2(a, m=10000)
        ...: %timeit extend2D_v3(a, m=10000)
    10000 loops, best of 3: 51.3 µs per loop
    10000 loops, best of 3: 19.6 µs per loop
    100000 loops, best of 3: 12.6 µs per loop
    

    【讨论】:

    • 您也可以使用np.pad 代替串联或零+赋值。
    • @jdehesa 根据我的经验,np.pad 似乎更慢。所以,避免这种情况。
    猜你喜欢
    • 2021-03-28
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    相关资源
    最近更新 更多