【问题标题】:Get norm of numpy sparse matrix rows获取 numpy 稀疏矩阵行的范数
【发布时间】:2013-12-08 18:01:41
【问题描述】:

我有一个使用 Sklearn 的 TfidfVectorizer 对象获得的稀疏矩阵:

vect = TfidfVectorizer(sublinear_tf=True, max_df=0.5, analyzer='word', vocabulary=my_vocab, stop_words='english')
tfidf = vect.fit_transform([my_docs])

稀疏矩阵为(为了概括,去掉了数字):

<sparse matrix of type '<type 'numpy.float64'>'
with stored elements in Compressed Sparse Row format>]

我正在尝试为每一行获取一个数值,以告诉我文档包含我要查找的术语的高度。我真的不在乎它包含哪些单词,我只想知道它包含了多少。所以我想得到每个或 row*row.T 的规范。但是,我很难使用 numpy 来获得这个。

我的第一个方法是简单地做:

tfidf[i] * numpy.transpose(tfidf[i])

但是,numpy 显然不会转置小于一维的数组,因此只会对向量进行平方。所以我试着做:

tfidf[i] * numpy.transpose(numpy.atleast_2d(tfidf[0]))

但是 numpy.transpose(numpy.atleast_2d(tfidf[0])) 仍然不会转置该行。

我继续尝试获得该行的规范(无论如何,这种方法可能更好)。我最初的方法是使用 numpy.linalg。

numpy.linalg.norm(tfidf[0])

但这给了我一个“尺寸不匹配”的错误。所以我尝试手动计算标准。我首先设置一个等于稀疏矩阵的 numpy 数组版本的变量并打印出第一行的 len:

my_array = numpy.array(tfidf)
print my_array
print len(my_array[0])

它正确打印出 my_array,但是当我尝试访问 len 时它告诉我:

IndexError: 0-d arrays can't be indexed

我只是想获取 fit_transform 返回的稀疏矩阵中每一行的数值。获得规范将是最好的。非常感谢这里的任何帮助。

【问题讨论】:

  • 它是什么类型的稀疏矩阵?
  • 您好,感谢您的回复。我编辑了答案以显示类型。
  • 我可以解释最后一个错误:调用 np.array(tfidf) 将整个矩阵的 1 元素和 0 维数组作为对象。要使其成为普通数组,请使用tfidf.toarray() 或要获取矩阵,请使用tfidf.todense()
  • 太棒了!那行得通,我可以在行上使用 linalg.norm() 。现在我只需要弄清楚如何不使每一行的范数等于 1。我认为整个 tfidf 矩阵正在被归一化,而不是每一行......
  • 我想出了一种方法来使用tfidf.multiply(tfidf).sum(1) 获得稀疏形式的规范。有关详细信息,请参阅我的答案。

标签: python arrays numpy matrix norm


【解决方案1】:

一些简单的假数据:

a = np.arange(9.).reshape(3,3)
s = sparse.csr_matrix(a)

要从稀疏中获取每一行的范数,可以使用:

np.sqrt(s.multiply(s).sum(1))

而重新规范化的s 将是

s.multiply(1/np.sqrt(s.multiply(s).sum(1)))

或在重新规范化之前保持稀疏:

s.multiply(sparse.csr_matrix(1/np.sqrt(s.multiply(s).sum(1))))

要从中获取普通矩阵或数组,请使用:

m = s.todense()
a = s.toarray()

如果你有足够的内存用于密集版本,你可以得到每一行的范数:

n = np.sqrt(np.einsum('ij,ij->i',a,a))

n = np.apply_along_axis(np.linalg.norm, 1, a)

要正常化,你可以这样做

an = a / n[:, None]

或者,将原始数组归一化:

a /= n[:, None]

[:, None] 基本上将n 转置为垂直数组。

【讨论】:

    【解决方案2】:

    scipy.sparse 是一个很棒的包,它在每个版本中都在不断改进,但是很多东西仍然只完成了一半,如果你自己实现一些算法,你可以获得很大的性能提升。例如,使用 scipy 函数比 @askewchan 的实现提高了 7 倍:

    In [18]: a = sps.rand(1000, 1000, format='csr')
    
    In [19]: a
    Out[19]: 
    <1000x1000 sparse matrix of type '<type 'numpy.float64'>'
        with 10000 stored elements in Compressed Sparse Row format>
    
    In [20]: %timeit a.multiply(a).sum(1)
    1000 loops, best of 3: 288 us per loop
    
    In [21]: %timeit np.add.reduceat(a.data * a.data, a.indptr[:-1])
    10000 loops, best of 3: 36.8 us per loop
    
    In [24]: np.allclose(a.multiply(a).sum(1).ravel(),
        ...:             np.add.reduceat(a.data * a.data, a.indptr[:-1]))
    Out[24]: True
    

    您可以通过以下方式对数组进行类似的规范化:

    norm_rows = np.sqrt(np.add.reduceat(a.data * a.data, a.indptr[:-1]))
    nnz_per_row = np.diff(a.indptr)
    a.data /= np.repeat(norm_rows, nnz_per_row)
    

    如果您要经常使用稀疏矩阵,请阅读the wikipedia page on compressed sparse formats,您通常会找到比默认方法更好的方法。

    【讨论】:

      【解决方案3】:

      使用原生 scipy API scipy.sparse.linalg.norm 怎么样?

      阅读更多https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.norm.html

      【讨论】:

        猜你喜欢
        • 2017-07-20
        • 2021-11-25
        • 1970-01-01
        • 2023-04-06
        • 1970-01-01
        • 2012-01-10
        • 2016-08-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多