从矩阵中有效地减去向量(Scipy)

fol*_*oof 6 python numpy scipy sparse-matrix

我有一个大型矩阵存储为scipy.sparse.csc_matrix,并希望从大矩阵中的每一列中减去一个列向量.当你正在进行规范化/标准化这样的事情时,这是一个非常常见的任务,但我似乎找不到有效地做到这一点的正确方法.

这是一个示例:

# mat is a 3x3 matrix
mat = scipy.sparse.csc_matrix([[1, 2, 3],
                               [2, 3, 4],
                               [3, 4, 5]])

#vec is a 3x1 matrix (or a column vector)
vec = scipy.sparse.csc_matrix([1,2,3]).T

""" 
I want to subtract `vec` from each of the columns in `mat` yielding...
    [[0, 1, 2],
     [0, 1, 2],
     [0, 1, 2]]
"""
Run Code Online (Sandbox Code Playgroud)

实现我想要的一种方法是对vec自己进行3次自身,产生一个3x3矩阵,其中每列都是vec,然后从中减去mat.但同样,我正在寻找一种有效地做到这一点的方法,并且hstacked矩阵需要很长时间才能创建.我确信有一些神奇的方法可以用切片和广播来做到这一点,但它让我望而却步.

谢谢!

编辑:删除了"就地"约束,因为稀疏结构将在就地分配方案中不断变化.

hpa*_*ulj 7

首先,我们将如何处理密集阵列?

mat-vec.A # taking advantage of broadcasting
mat-vec.A[:,[0]*3] # explicit broadcasting
mat-vec[:,[0,0,0]] # that also works with csr matrix
Run Code Online (Sandbox Code Playgroud)

在https://codereview.stackexchange.com/questions/32664/numpy-scipy-optimization/33566中, 我们发现as_strided在mat.indptr向量上使用是步进稀疏矩阵行的最有效方法.(本x.rows,x.cols一个lil_matrix是几乎一样好. getrow很慢).该函数实现了迭代等功能.

def sum(X,v):
    rows, cols = X.shape
    row_start_stop = as_strided(X.indptr, shape=(rows, 2),
                            strides=2*X.indptr.strides)
    for row, (start, stop) in enumerate(row_start_stop):
        data = X.data[start:stop]
        data -= v[row]

sum(mat, vec.A)
print mat.A
Run Code Online (Sandbox Code Playgroud)

我是vec.A为了简单而使用.如果我们保持vec稀疏,我们必须添加非零值的测试row.此类迭代也只修改了非零元素mat. 0's没有改变.

我怀疑时间优势将在很大程度上取决于矩阵和向量的稀疏性.如果vec有大量的零,然后是有意义的迭代,只修改那些行mat,其中vec非零.但是vec这个例子几乎是密集的,可能很难被击败mat-vec.A.