5

我有一个通过使用 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 返回的稀疏矩阵中每一行的数值。获得规范将是最好的。非常感谢这里的任何帮助。

4

3 回答 3

10

一些简单的假数据:

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成一个垂直数组。

于 2013-11-23T23:11:29.290 回答
6

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)

如果您要经常使用稀疏矩阵,请阅读有关压缩稀疏格式的维基百科页面,您通常会找到比默认方法更好的方法来做事。

于 2013-11-23T23:42:29.540 回答
2

使用本机 scipy APIscipy.sparse.linalg.norm怎么样?

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

于 2020-02-07T11:06:34.807 回答