Scipy稀疏矩阵的一种有效归一化方法

hzbexzde  于 2023-02-19  发布在  其他
关注(0)|答案(6)|浏览(242)

我想写一个函数,将一个大型稀疏矩阵的行归一化(使它们的和为1)。

from pylab import *
import scipy.sparse as sp

def normalize(W):
    z = W.sum(0)
    z[z < 1e-6] = 1e-6
    return W / z[None,:]

w = (rand(10,10)<0.1)*rand(10,10)
w = sp.csr_matrix(w)
w = normalize(w)

但是,这给出了以下例外情况:

File "/usr/lib/python2.6/dist-packages/scipy/sparse/base.py", line 325, in __div__
     return self.__truediv__(other)
File "/usr/lib/python2.6/dist-packages/scipy/sparse/compressed.py", line 230, in  __truediv__
   raise NotImplementedError

有没有合理简单的解决方案?我已经看过this,但仍然不清楚如何实际做除法。

xmjla07d

xmjla07d1#

这已经在scikit-learn sklearn. preprocessing. normalize中实现了。

from sklearn.preprocessing import normalize
w_normalized = normalize(w, norm='l1', axis=1)

axis=1应按行规范化,axis=0按列规范化。使用可选参数copy=False就地修改矩阵。

nkkqxpd9

nkkqxpd92#

虽然Aarons的答案是正确的,但当我想根据 absolute 值的最大值进行规范化时,我实现了一个解决方案,sklearn没有提供这个解决方案。我的方法使用非零项,并在csr_matrix.data数组中找到它们,以快速替换那里的值。

def normalize_sparse(csr_matrix):
    nonzero_rows = csr_matrix.nonzero()[0]
    for idx in np.unique(nonzero_rows):
        data_idx = np.where(nonzero_rows==idx)[0]
        abs_max = np.max(np.abs(csr_matrix.data[data_idx]))
        if abs_max != 0:
            csr_matrix.data[data_idx] = 1./abs_max * csr_matrix.data[data_idx]

与sunan的解决方案相比,这种方法不需要将矩阵转换为密集格式(这可能会引起内存问题),也不需要矩阵乘法。我在形状为(35'000,486'000)的稀疏矩阵上测试了这种方法,耗时约18秒。

3z6pesqy

3z6pesqy3#

这是我解决办法。

  • 转座A
  • 计算每列的总和
  • 带和倒数的格式对角矩阵B
  • A*B等于归一化
  • 转座C
import scipy.sparse as sp
import numpy as np
import math

minf = 0.0001

A = sp.lil_matrix((5,5))
b = np.arange(0,5)
A.setdiag(b[:-1], k=1)
A.setdiag(b)
print A.todense()
A = A.T
print A.todense()

sum_of_col = A.sum(0).tolist()
print sum_of_col
c = []
for i in sum_of_col:
    for j in i:
        if math.fabs(j)<minf:
            c.append(0)
        else:
            c.append(1/j)

print c

B = sp.lil_matrix((5,5))
B.setdiag(c)
print B.todense()

C = A*B
print C.todense()
C = C.T
print C.todense()
mwg9r5ms

mwg9r5ms4#

我发现这是一种优雅的方法,不需要使用内置函数。

import scipy.sparse as sp

def normalize(W):
    #Find the row scalars as a Matrix_(n,1)
    rowSumW = sp.csr_matrix(W.sum(axis=1))
    rowSumW.data = 1/rowSumW.data

    #Find the diagonal matrix to scale the rows
    rowSumW = rowSumW.transpose()
    scaling_matrix = sp.diags(rowSumW.toarray()[0])

    return scaling_matrix.dot(W)
vjrehmav

vjrehmav5#

在不导入sklearn的情况下,转换为密集矩阵或乘法矩阵,并且通过利用csr矩阵的数据表示:

from scipy.sparse import isspmatrix_csr

def normalize(W):
    """ row normalize scipy sparse csr matrices inplace.
    """
    if not isspmatrix_csr(W):
        raise ValueError('W must be in CSR format.')
    else:
        for i in range(W.shape[0]):
            row_sum = W.data[W.indptr[i]:W.indptr[i+1]].sum()
            if row_sum != 0:
                W.data[W.indptr[i]:W.indptr[i+1]] /= row_sum

W.indices是列索引的数组,W.data是对应的非零值的数组,并且W.indptr指向索引和数据中的行开始。
如果需要L1范数,可以在求和时添加numpy.abs(),或者使用numpy.max()按每行的最大值进行归一化。

hc2pp10m

hc2pp10m6#

如果只使用csr_array,您可以使用它的multiplysum方法并执行以下操作:

row_sum = w.sum(axis=1)
row_sum[row_sum == 0] = 1  # to avoid divide by zero
w = w.multiply(1. / row_sum)

相关问题