Scipy函数,可以对压缩的稀疏列矩阵执行np.diff()

js81xvg6  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(111)

我想计算单位矩阵的离散差分。下面的代码使用了numpy和scipy。

import numpy as np
from scipy.sparse import identity
from scipy.sparse import csc_matrix

x = identity(4).toarray()
y = csc_matrix(np.diff(x, n=2))
print(y)

我想提高性能或内存使用。由于单位矩阵产生很多零,以压缩稀疏列(csc)格式执行计算会减少内存使用。但是,np.diff()不接受csc格式,所以使用csc_matrix在csc和普通格式之间转换会稍微慢一点。
标准格式

x = identity(4).toarray()
print(x)
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]

csc格式

x = identity(4)
print(x)
  (0, 0)    1.0
  (1, 1)    1.0
  (2, 2)    1.0
  (3, 3)    1.0

谢谢

5jdjgkvh

5jdjgkvh1#

这是我的黑客解决方案,以获得稀疏矩阵,因为你想要的。

  • L-原始单位矩阵的长度,
  • n-np.diff的参数。

在你的问题中,它们是:

L = 4
n = 2

我的代码生成的y与您的代码相同,但没有csc和普通格式之间的转换。
您的代码:

from scipy.sparse import identity, csc_matrix

x = identity(L).toarray()
y = csc_matrix(np.diff(x, n=n))

我的代码:

from scipy.linalg import pascal

def get_data(n, L):
    nums = pascal(n + 1, kind='lower')[-1].astype(float)
    minuses_from = n % 2 + 1
    nums[minuses_from : : 2] *= -1
    return np.tile(nums, L - n)

data = get_data(n, L)
row_ind = (np.arange(n + 1) + np.arange(L - n).reshape(-1, 1)).flatten()
col_ind = np.repeat(np.arange(L - n), n + 1)

y = csc_matrix((data, (row_ind, col_ind)), shape=(L, L - n))

我注意到,在单位矩阵n上应用np.diff多次后,各列的值是符号交替的二项式系数,这就是我的变量data
那么我只是构造csc_matrix。

bfnvny8b

bfnvny8b2#

不幸的是,SciPy似乎没有提供任何工具来处理这种稀疏矩阵,不管怎样,通过巧妙地处理条目的索引和数据,我们可以直接模拟np.diff(x,n)
给定二维NumPy数组(矩阵)维度为MxNnp.diff()将每列相乘(属于列索引y)与-1进行比较,并向其中添加下一列(列索引y+1)。k阶差正好是1阶差的k的迭代应用。0阶的差正好返回输入矩阵。
下面的方法利用了这一点,通过sum_duplicates()的加法迭代地消除重复的条目,将列数减一,并过滤无效的索引。

def csc_diff(x, n):
    '''Emulates np.diff(x,n) for a sparse matrix by iteratively taking difference of order 1'''
    assert isinstance(x, csc_matrix) or (isinstance(x, np.ndarray) & len(x.shape) == 2), "Input matrix must be a 2D np.ndarray or csc_matrix."
    assert isinstance(n, int) & n >= 0, "Integer n must be larger or equal to 0."

    if n >= x.shape[1]:
        return csc_matrix(([], ([], [])), shape=(x.shape[0], 0))

    if isinstance(x, np.ndarray):
        x = csc_matrix(x)

    # set-up of data/indices via column-wise difference
    if(n > 0):
        for k in range(1,n+1):
            # extract data/indices of non-zero entries of (current) sparse matrix
            M, N = x.shape
            idx, idy = x.nonzero()
            dat = x.data

            # difference: this row (y) * (-1) + next row (y+1)
            idx = np.concatenate((idx, idx))
            idy = np.concatenate((idy, idy-1))
            dat = np.concatenate(((-1)*dat, dat))

            # filter valid indices
            validInd = (0<=idy) & (idy<N-1)

            # x_diff: csc_matrix emulating np.diff(x,1)'s output'
            x_diff =  csc_matrix((dat[validInd], (idx[validInd], idy[validInd])), shape=(M, N-1))
            x_diff.sum_duplicates()

            x = x_diff

    return x

此外,当差阶大于或等于输入矩阵的列数时,该方法输出维度为Mx0的空csc_matrix

csc_diff(x, 2).toarray()
> array([[ 1.,  0.],
         [-2.,  1.],
         [ 1., -2.],
         [ 0.,  1.]])

其与

np.diff(x.toarray(), 2)
> array([[ 1.,  0.],
         [-2.,  1.],
         [ 1., -2.],
         [ 0.,  1.]])

这个恒等式也适用于其他差序

(csc_diff(x, 0).toarray() == np.diff(x.toarray(), 0)).all()
>True

(csc_diff(x, 3).toarray() == np.diff(x.toarray(), 3)).all()
>True

(csc_diff(x, 13).toarray() == np.diff(x.toarray(), 13)).all()
>True

相关问题