使用Numpy沿对角线复制给定数组高效创建矩阵的方法
生成滑动窗口式矩阵的解决方案
嗨,这个问题我之前处理过!确实,常规的numpy.kron或者块对角方法(比如scipy.linalg.block_diag)完全没法生成这种每行向右滑动一位的矩阵,因为它们的逻辑是重复或块填充,和我们要的滑动窗口式移位结构不匹配。
下面给你两种实用的解决方案,从直观到高效都有:
方法一:直观循环填充(适合小矩阵)
这种方法逻辑简单,容易理解,对于小规模的矩阵完全够用:
import numpy as np a = np.array([1,2,3]) n = 4 rows = n + 1 # 结果矩阵的行数 cols = len(a) + n # 结果矩阵的列数 # 初始化全零矩阵 result = np.zeros((rows, cols), dtype=a.dtype) # 逐行填充:第i行把a放到从第i列开始的位置 for i in range(rows): result[i, i:i+len(a)] = a print(result)
运行后会输出你期望的矩阵:
array([[1., 2., 3., 0., 0., 0., 0.], [0., 1., 2., 3., 0., 0., 0.], [0., 0., 1., 2., 3., 0., 0.], [0., 0., 0., 1., 2., 3., 0.], [0., 0., 0., 0., 1., 2., 3.]])
方法二:利用Stride Tricks高效生成(适合大矩阵)
如果你的n很大,循环会影响效率,这时候可以用numpy的stride_tricks,它通过直接操作数组的内存步长来生成滑动窗口,不需要复制数据,效率极高:
import numpy as np from numpy.lib.stride_tricks import as_strided a = np.array([1,2,3]) n = 4 cols = len(a) + n rows = n + 1 # 构造一个足够长的填充数组:前后各补n个0 pad_a = np.concatenate([np.zeros(n, dtype=a.dtype), a, np.zeros(n, dtype=a.dtype)]) # 利用步长生成滑动窗口:行方向步长为负(向左滑动),列方向步长为正 stride = pad_a.itemsize result = as_strided( pad_a, shape=(rows, cols), strides=(-stride, stride), writeable=False # 设为False避免意外修改原数组 ) print(result)
这个方法和循环得到的结果完全一致,但运行速度快很多,尤其当n是几百上千的时候。
为什么常规方法不行?
简单说:
numpy.kron是克罗内克积,会把a和另一个矩阵的每个元素做乘法扩展,生成的是重复块结构,不是滑动移位。- 块对角方法(比如
block_diag)只会把a放在对角线的块里,其他位置全0,无法实现每行向右移位的效果。
内容的提问来源于stack exchange,提问作者Alex Hu
相关产品推荐
相关产品推荐

