【问题标题】:Logical not on a scipy sparse matrix逻辑不在 scipy 稀疏矩阵上
【发布时间】:2017-06-22 19:37:54
【问题描述】:

我有一个由 W 稀疏矩阵 word_freqs 存储在 D 中的语料库的词袋表示。每一行是一个文档,每一列是一个单词。给定元素word_freqs[d,w] 表示文档d 中单词w 的出现次数。

我正在尝试通过 W 矩阵 not_word_occs 获得另一个 D,其中,对于 word_freqs 的每个元素:

  • 如果word_freqs[d,w] 为零,则not_word_occs[d,w] 应为一。
  • 否则,not_word_occs[d,w] 应为零。

最终,这个矩阵需要与其他可能密集或稀疏的矩阵相乘。


我尝试了很多方法,包括:

not_word_occs = (word_freqs == 0).astype(int)

这个词是玩具示例,但我的实际数据(大约为 18,000x16,000)导致 MemoryError

我也试过np.logical_not():

word_occs = sklearn.preprocessing.binarize(word_freqs)
not_word_occs = np.logical_not(word_freqs).astype(int)

这看起来很有希望,但 np.logical_not() 不适用于稀疏矩阵,并出现以下错误:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().

任何想法或指导将不胜感激。

(顺便说一句,word_freqs 是由 sklearn 的preprocessing.CountVectorizer() 生成的。如果有解决方案将其转换为另一种矩阵,我当然愿意。)

【问题讨论】:

  • 如果 word_freqs 是一个 scipy 稀疏矩阵,它应该具有显示形状、非零值数量、dtype 和稀疏格式的打印表示。
  • <18144x14511 sparse matrix of type '<class 'numpy.int64'>' with 619900 stored elements in Compressed Sparse Row format>
  • 所以它是 .002 稀疏的。 not 然后将是所有 99.8% 的。
  • @err1100,你会考虑使用 Pandas.SparseDataFrame 代替 scipy 稀疏矩阵吗?
  • 我不会反对,但请参阅下面的评论。我最终需要将它与其他矩阵相乘。我可以用 pandas 做到这一点吗?

标签: python-3.x numpy scipy scikit-learn sparse-matrix


【解决方案1】:

这里是一个使用Pandas.SparseDataFrame的例子:

In [42]: X = (sparse.rand(10, 10, .1) != 0).astype(np.int64)

In [43]: X = (sparse.rand(10, 10, .1) != 0).astype(np.int64)

In [44]: d1 = pd.SparseDataFrame(X.toarray(), default_fill_value=0, dtype=np.int64)

In [45]: d2 = pd.SparseDataFrame(np.ones((10,10)), default_fill_value=1, dtype=np.int64)

In [46]: d1.memory_usage()
Out[46]:
Index    80
0        16
1         0
2         8
3        16
4         0
5         0
6        16
7        16
8         8
9         0
dtype: int64

In [47]: d2.memory_usage()
Out[47]:
Index    80
0         0
1         0
2         0
3         0
4         0
5         0
6         0
7         0
8         0
9         0
dtype: int64

数学:

In [48]: d2 - d1
Out[48]:
   0  1  2  3  4  5  6  7  8  9
0  1  1  0  0  1  1  0  1  1  1
1  1  1  1  1  1  1  1  1  0  1
2  1  1  1  1  1  1  1  1  1  1
3  1  1  1  1  1  1  1  0  1  1
4  1  1  1  1  1  1  1  1  1  1
5  0  1  1  1  1  1  1  1  1  1
6  1  1  1  1  1  1  1  1  1  1
7  0  1  1  0  1  1  1  0  1  1
8  1  1  1  1  1  1  0  1  1  1
9  1  1  1  1  1  1  1  1  1  1

源稀疏矩阵:

In [49]: d1
Out[49]:
   0  1  2  3  4  5  6  7  8  9
0  0  0  1  1  0  0  1  0  0  0
1  0  0  0  0  0  0  0  0  1  0
2  0  0  0  0  0  0  0  0  0  0
3  0  0  0  0  0  0  0  1  0  0
4  0  0  0  0  0  0  0  0  0  0
5  1  0  0  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0  0  0
7  1  0  0  1  0  0  0  1  0  0
8  0  0  0  0  0  0  1  0  0  0
9  0  0  0  0  0  0  0  0  0  0

内存使用情况:

In [50]: (d2 - d1).memory_usage()
Out[50]:
Index    80
0        16
1         0
2         8
3        16
4         0
5         0
6        16
7        16
8         8
9         0
dtype: int64

PS 如果你不能一次构建整个 SparseDataFrame(因为内存限制),你可以使用approach similar to one used in this answer

【讨论】:

    【解决方案2】:

    稀疏矩阵的非零位置的补是密集的。因此,如果您想使用标准的 numpy 数组实现既定目标,您将需要相当多的 RAM。这是一个快速且完全不科学的技巧,可以让您了解您的计算机可以处理多少个此类数组:

    >>> import numpy as np
    >>> a = []
    >>> for j in range(100):
    ...     print(j)
    ...     a.append(np.ones((16000, 18000), dtype=int))
    

    我的笔记本电脑在 j=1 时窒息。所以除非你有一台非常好的电脑,即使你能得到补充(你可以做到

    >>> compl = np.ones(S.shape,int)
    >>> compl[S.nonzero()] = 0
    

    ) 内存将是一个问题。

    一种方法可能是不显式计算补码,我们称其为 C = B1 - A,其中 B1 是完全用 1 填充的形状相同的矩阵,而 A 是原始稀疏矩阵的邻接矩阵。例如,矩阵乘积 XC 可以写成 XB1 - XA,所以你有一个与稀疏 A 的乘法和一个与 B1 的乘法,这实际上很便宜,因为它归结为计算行和。这里的重点是你可以在不先计算 C 的情况下计算它。

    一个特别简单的例子是与 one-hot 向量相乘。这样的乘法只是选择另一个矩阵的一列(如果从右边相乘)或行(如果从左边相乘)。这意味着您只需要找到稀疏矩阵的该列或行并取补(对于单个切片没问题),如果您对单热矩阵执行此操作,如上所述,您无需显式计算补码。

    【讨论】:

    • 我想我跟着你,但什么是“[我的]原始稀疏矩阵的邻接矩阵”?
    • @err1100 哦,行话,抱歉。它是同一个矩阵,所有非零条目都设置为 1。顺便提一句。我很确定我在上一段中描述的方案将适用于单热矩阵。让我想一想,我再补充几行。
    • 谢谢,保罗。多亏了你的分解,我才能让事情顺利进行。计算实际矩阵仍然使用过多的 RAM(特别是制作 16K x 18K 的矩阵),但是您的热门段落让我知道如何在不制作矩阵的情况下做到这一点。
    【解决方案3】:

    制作一个小的稀疏矩阵:

    In [743]: freq = sparse.random(10,10,.1)
    In [744]: freq
    Out[744]: 
    <10x10 sparse matrix of type '<class 'numpy.float64'>'
        with 10 stored elements in COOrdinate format>
    

    repr(freq) 显示形状、元素和格式。

    In [745]: freq==0
    /usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:213: SparseEfficiencyWarning: Comparing a sparse matrix with 0 using == is inefficient, try using != instead.
      ", try using != instead.", SparseEfficiencyWarning)
    Out[745]: 
    <10x10 sparse matrix of type '<class 'numpy.bool_'>'
        with 90 stored elements in Compressed Sparse Row format>
    

    如果您执行第一个操作,我会收到一个警告和包含 90 个(共 100 个)非零项的新数组。 not 不再稀疏。

    通常 numpy 函数在应用于稀疏矩阵时不起作用。为了工作,他们必须将任务委托给稀疏方法。但即使logical_not 工作,它也不能解决内存问题。

    【讨论】:

    • 那么,您有什么建议吗?对于上下文,我有一个由 K 矩阵 doc_topics 表示每个文档的主题的单热 D。稍后,我需要通过 K 矩阵得到一个 W 矩阵,该矩阵告诉我主题 k 的文档有多少 not 包含单词 w。在我的玩具示例中,我使用 not_word_occs.T @ doc_topics 来完成此操作,但我现在需要另一种方法来完成此操作。
    • @hpaulj 一旦我尝试不以这种方式使用逻辑,如果我尝试用另一个稀疏矩阵做一个 Hadamard 产品,我会得到一个维度不匹配错误,这很奇怪。
    猜你喜欢
    • 1970-01-01
    • 2016-05-26
    • 1970-01-01
    • 2015-01-30
    • 2017-03-26
    • 2017-03-31
    • 2023-04-10
    • 2017-07-21
    • 2011-11-28
    相关资源
    最近更新 更多