在scipy.sparse矩阵上的布尔运算
我有一组稀疏矩阵,里面填满了布尔值(就是只有真和假),我需要对它们进行逻辑运算(主要是逐元素的“或”运算)。
就像在numpy中,两个布尔类型的矩阵相加时,会得到逐元素的“或”结果,但有一个麻烦的副作用:
>>> from scipy import sparse
>>> [a,b] = [sparse.rand(5,5,density=0.1,format='lil').astype('bool')
... for x in range(2)]
>>> b
<5x5 sparse matrix of type '<class 'numpy.bool_'>'
with 2 stored elements in LInked List format>
>>> a+b
<5x5 sparse matrix of type '<class 'numpy.int8'>'
with 4 stored elements in Compressed Sparse Row format>
结果的数据类型会变成'int8',这会导致后续操作出现问题。虽然可以通过下面的方法来解决:
(a+b).astype('bool')
但我感觉这种类型的变化会影响性能。
为什么结果的数据类型和操作数的数据类型不一样呢?
有没有更好的方法在python中对稀疏矩阵进行逻辑运算?
2 个回答
7
你可以很简单地用以下方法来表示布尔运算。这样它就可以和稀疏矩阵一起使用。
a.multiply(b) #AND
a+b #OR
(a>b)+(a<b) #XOR
a>b #NOT
所以,布尔运算是被支持的。
6
稀疏矩阵不支持逻辑运算,但把它转换回布尔值其实并不太费事。实际上,如果你使用的是LIL格式的矩阵,转换的时间可能会因为性能波动而看起来是负的:
a = scipy.sparse.rand(10000, 10000, density=0.001, format='lil').astype('bool')
b = scipy.sparse.rand(10000, 10000, density=0.001, format='lil').astype('bool')
In [2]: %timeit a+b
10 loops, best of 3: 61.2 ms per loop
In [3]: %timeit (a+b).astype('bool')
10 loops, best of 3: 60.4 ms per loop
你可能注意到,在把LIL矩阵相加之前,它们被转换成了CSR格式,看看返回的格式。如果你一开始就使用CSR格式,那么转换的额外开销就会更明显:
In [14]: %timeit a+b
100 loops, best of 3: 2.28 ms per loop
In [15]: %timeit (a+b).astype(bool)
100 loops, best of 3: 2.96 ms per loop
CSR(和CSC)矩阵有一个叫做data
的属性,它是一个一维数组,里面存放着稀疏矩阵中实际的非零元素。因此,重新转换你的稀疏矩阵的成本将取决于矩阵中非零元素的数量,而不是它的大小:
a = scipy.sparse.rand(10000, 10000, density=0.0005, format='csr').astype('int8')
b = scipy.sparse.rand(1000, 1000, density=0.5, format='csr').astype('int8')
In [4]: %timeit a.astype('bool') # a is 10,000x10,000 with 50,000 non-zero entries
10000 loops, best of 3: 93.3 us per loop
In [5]: %timeit b.astype('bool') # b is 1,000x1,000 with 500,000 non-zero entries
1000 loops, best of 3: 1.7 ms per loop