我正在使用以下代码从生成器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堆栈。任何(或全部)都是改进。
答案 0 :(得分:2)
您可以使用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.]])
第二个列表[0,1,2]是偏移列表。它告诉您希望某个元素与对角线的偏移量。
答案 1 :(得分:2)
这里有一个np.lib.stride_tricks.as_strided
,可以为我们提供一个2D
视图,可以看到填充了1D
版本的输入的零,并且这样的内存效率很高,因此性能也很高。这个技巧已经探索了无数次-1
,2
。
因此,实现应为-
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]])
采用相同的原理,但版本少一些混乱,我们还可以利用基于np.lib.stride_tricks.as_strided
的scikit-image's view_as_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]
答案 2 :(得分:0)
您还可以使用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)
如果要使用可变大小,请使用size参数(N)向列和行动态添加零。以下是我对最小为3的有限差分的实现。
col = [1,0,0] + [0] * (size -3)
lin = [1,2,1] + [0] * (size -3)
m = scl.toeplitz(col, lin)
输出:
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.]])