逻辑不在 scipy 稀疏矩阵上
Logical not on a scipy sparse matrix
我有一个存储在 D 中的语料库的词袋表示 W 稀疏矩阵 word_freqs
.每行是一个文档,每列是一个词。给定元素 word_freqs[d,w]
表示文档 d.
中单词 w 的出现次数
我正在尝试通过 W 矩阵 not_word_occs
获得另一个 D 其中,对于 [=14 的每个元素=]:
- 如果
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()
生成的。如果有涉及将其转换为另一种矩阵的解决方案,我当然愿意接受。)
制作一个小的稀疏矩阵:
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
有效,也无法解决内存问题。
稀疏矩阵的非零位置的补集是稠密的。因此,如果您想使用标准 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 填充的 same-shape 矩阵,A 是原始稀疏矩阵的邻接矩阵。例如,矩阵乘积 XC 可以写成 XB1 - XA,所以你有一个与稀疏 A 的乘法和一个与 B1 的乘法,这实际上很便宜,因为它归结为计算行总和。这里的要点是您可以在不先计算 C 的情况下计算它。
一个特别简单的例子是与 one-hot 向量相乘。这样的乘法只是选择另一个矩阵的列(如果从右边相乘)或行(如果从左边相乘)。这意味着您只需要找到稀疏矩阵的列或行并取补码(对于单个切片没问题),如果您对 one-hot 矩阵执行此操作,则无需显式计算补码.
这里是一个使用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(因为内存限制),你可以使用一个
我有一个存储在 D 中的语料库的词袋表示 W 稀疏矩阵 word_freqs
.每行是一个文档,每列是一个词。给定元素 word_freqs[d,w]
表示文档 d.
我正在尝试通过 W 矩阵 not_word_occs
获得另一个 D 其中,对于 [=14 的每个元素=]:
- 如果
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()
生成的。如果有涉及将其转换为另一种矩阵的解决方案,我当然愿意接受。)
制作一个小的稀疏矩阵:
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
有效,也无法解决内存问题。
稀疏矩阵的非零位置的补集是稠密的。因此,如果您想使用标准 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 填充的 same-shape 矩阵,A 是原始稀疏矩阵的邻接矩阵。例如,矩阵乘积 XC 可以写成 XB1 - XA,所以你有一个与稀疏 A 的乘法和一个与 B1 的乘法,这实际上很便宜,因为它归结为计算行总和。这里的要点是您可以在不先计算 C 的情况下计算它。
一个特别简单的例子是与 one-hot 向量相乘。这样的乘法只是选择另一个矩阵的列(如果从右边相乘)或行(如果从左边相乘)。这意味着您只需要找到稀疏矩阵的列或行并取补码(对于单个切片没问题),如果您对 one-hot 矩阵执行此操作,则无需显式计算补码.
这里是一个使用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(因为内存限制),你可以使用一个