Python 用numpy生成带状矩阵

Python 用numpy生成带状矩阵,python,numpy,matrix,Python,Numpy,Matrix,我使用以下代码从生成器g创建带状矩阵: def banded(g, N): """Creates a `g` generated banded matrix with 'N' rows""" n=len(g) T = np.zeros((N,N+n-1)) for x in range(N): T[x][x:x+n]=g return T 用法很简单,如下所示: banded([1,2,3], 3) 它回来了 [1, 2, 3, 0,

我使用以下代码从生成器
g
创建带状矩阵:

def banded(g, N):
    """Creates a `g` generated banded matrix with 'N' rows"""
    n=len(g)
    T = np.zeros((N,N+n-1))
    for x in range(N):
        T[x][x:x+n]=g
    return T
用法很简单,如下所示:

banded([1,2,3], 3)
它回来了

[1, 2, 3, 0, 0]
[0, 1, 2, 3, 0]
[0, 0, 1, 2, 3]
它将主要用于求解具有给定模板的有限差分模型,例如
(-1,1)

有更好的方法生成模具吗?我找不到任何好的NumPy函数


我说的更好是指更快,使用更少的内存,从python中删除循环并发送到Numpy堆栈。所有这些都是改进。

您可以使用
scipy.sparse.diags

输入:

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

array([[ 1.,  2.,  3.,  0.,  0.],
      [ 0.,  1.,  2.,  3.,  0.],
      [ 0.,  0.,  1.,  2.,  3.]])
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,1,2]是偏移量列表。它告诉您希望某个元素与对角线的偏移量。

这里有一个,它为我们提供了一个
2D
视图,进入一个零填充
1D
版本的输入,因此内存效率很高,因此性能也很好。这个技巧已经被探索过无数次-

因此,执行工作将是非常重要的-

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))
样本运行-

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]])
同样的理念,但不太混乱的版本,我们也可以利用基于的来获得滑动窗口


您还可以使用scipy的toeplitz函数,它与matlab中的对应函数非常相似。它周围的形状也很灵巧,不用担心它

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)
如果需要可变大小,请使用大小参数(N)将零动态添加到列和行中。下面是我对最小值为3的有限差分的实现

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

array([[ 1.,  2.,  3.,  0.,  0.],
      [ 0.,  1.,  2.,  3.,  0.],
      [ 0.,  0.,  1.,  2.,  3.]])
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.]])

请定义“更好”。更短的代码?更一般(以什么方式)?更快?消耗更少的内存?能够在更高的维度中工作?更快,消耗更少的内存,从python中删除循环并发送到numpy堆栈。任何(或全部)都更好。真实程序中的真实输入是什么?
g
通常有多长,以及
N
有多大?
g
不是很大,从2个元素到32个元素不等(是一个常规的有限差分模板)。但是
N
可以稍大一些。就像
100000
,任何真正决定矩阵大小的
N
。而且大小会变大,
N**2
@Lin是输入数组还是列表?Joe,是的,scipy sparse是一个想法。真是个好主意。事实上,第二个参数可以是
范围
。为了进行比较,我尝试使用稀疏方法和我在示例中使用的方法生成相同的矩阵,稀疏矩阵在矩阵分配(对于100000x1000000)矩阵时稍微快一点。当然,我相信在尝试求逆时,稀疏性是有好处的。只是为了获取信息,我使用了
scipy.sparse.diags(g,range(len(g),shape=(N,N+len(g)-1)).toarray()
,其中
N
g
在问题上是相同的。哇!这种方法最快,速度为4个数量级。