Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 查找稀疏矩阵中的所有零列_Python_Numpy_Scipy_Sparse Matrix - Fatal编程技术网

Python 查找稀疏矩阵中的所有零列

Python 查找稀疏矩阵中的所有零列,python,numpy,scipy,sparse-matrix,Python,Numpy,Scipy,Sparse Matrix,例如,我有一个coo_矩阵a: import scipy.sparse as sp A = sp.coo_matrix([3,0,3,0], [0,0,2,0], [2,5,1,0], [0,0,0,0]) 如何获得结果[0,0,0,1],它指示前3列包含非零值,只有第4列是全零 PS:无法将A转换为其他类型。 PS2:我尝试使用了np.nonzero,但我的实现似乎不是很优雅。方法#1

例如,我有一个coo_矩阵a:

import scipy.sparse as sp
A = sp.coo_matrix([3,0,3,0],
                  [0,0,2,0],
                  [2,5,1,0],
                  [0,0,0,0])
如何获得结果[0,0,0,1],它指示前3列包含非零值,只有第4列是全零

PS:无法将A转换为其他类型。
PS2:我尝试使用了
np.nonzero
,但我的实现似乎不是很优雅。

方法#1我们可以这样做-

# Get the columns indices of the input sparse matrix
C = sp.find(A)[1]

# Use np.in1d to create a mask of non-zero columns. 
# So, we invert it and convert to int dtype for desired output.
out = (~np.in1d(np.arange(A.shape[1]),C)).astype(int)
或者,为了缩短代码,我们可以使用减法-

out = 1-np.in1d(np.arange(A.shape[1]),C)
循序渐进-

1) 从中输入数组和稀疏矩阵:

In [137]: arr             # Regular dense array
Out[137]: 
array([[3, 0, 3, 0],
       [0, 0, 2, 0],
       [2, 5, 1, 0],
       [0, 0, 0, 0]])

In [138]: A = sp.coo_matrix(arr) # Convert to sparse matrix as input here on
2) 获取非零列索引:

In [139]: C = sp.find(A)[1]

In [140]: C
Out[140]: array([0, 2, 2, 0, 1, 2], dtype=int32)
3) 使用
np.inad
获取非零列的掩码:

In [141]: np.in1d(np.arange(A.shape[1]),C)
Out[141]: array([ True,  True,  True, False], dtype=bool)
4) 反转它:

In [142]: ~np.in1d(np.arange(A.shape[1]),C)
Out[142]: array([False, False, False,  True], dtype=bool)
5) 最后转换为int-dtype:

In [143]: (~np.in1d(np.arange(A.shape[1]),C)).astype(int)
Out[143]: array([0, 0, 0, 1])
备选减法:

In [145]: 1-np.in1d(np.arange(A.shape[1]),C)
Out[145]: array([0, 0, 0, 1])
方法#2这里有另一种方法,可能是一种更快的方法,使用
矩阵乘法
-

out = 1-np.ones(A.shape[0],dtype=bool)*A.astype(bool)

运行时测试

让我们在一个非常稀疏的大矩阵上测试所有发布的方法-

In [29]: A = sp.coo_matrix((np.random.rand(4000,4000)>0.998).astype(int))

In [30]: %timeit 1-np.in1d(np.arange(A.shape[1]),sp.find(A)[1])
100 loops, best of 3: 4.12 ms per loop # Approach1

In [31]: %timeit 1-np.ones(A.shape[0],dtype=bool)*A.astype(bool)
1000 loops, best of 3: 771 µs per loop # Approach2

In [32]: %timeit 1 - (A.col==np.arange(A.shape[1])[:,None]).any(axis=1)
1 loops, best of 3: 236 ms per loop # @hpaulj's soln

In [33]: %timeit (A!=0).sum(axis=0)==0
1000 loops, best of 3: 1.03 ms per loop  # @jez's soln

In [34]: %timeit (np.sum(np.absolute(A.toarray()), 0) == 0) * 1
10 loops, best of 3: 86.4 ms per loop  # @wwii's soln 

实际的逻辑操作可以这样执行:

b = (A!=0).sum(axis=0)==0
# matrix([[False, False, False,  True]], dtype=bool)
现在,为了确保我准确地回答了您的问题,我最好告诉您如何将布尔值转换为整数(尽管实际上,对于我能想到的大多数应用程序,如果您坚持使用
bool
s数组,您可以在
numpy
和朋友中做更多工作):

无论哪种方式,要从
矩阵
转换为
列表
,都可以执行以下操作:

c = list(b.flat)
# [0, 0, 0, 1]
…虽然我也不确定这是否是最好的做法:对于我能想象到的大多数应用程序,我可能只是将其转换为一维
numpy.array
,使用
c=b.a.flant()

类似,只是它想用1填充这些列并对它们进行规范化

我立即建议转置的
lil
格式。所有-0列都将是此格式的空列表。但是坚持我建议的
coo
格式

np.nonzero(~(Mo.col==np.arange(Mo.shape[1])[:,None]).any(axis=1))[0]
或用于此1/0格式

1 - (Mo.col==np.arange(Mo.shape[1])[:,None]).any(axis=1)
其功能与:

1 - np.in1d(np.arange(Mo.shape[1]),Mo.col)
sparse.find
将矩阵转换为
csr
以求和重复项并消除重复项,然后返回到
coo
以获取
数据
属性(返回)

Mo.nonzero
使用
A.data!=0
在返回
属性之前消除0

np.one(A.shape[0],dtype=bool)*A.astype(bool)
解决方案需要将
A
转换为
csr
格式进行乘法

(A!=0)。sum(axis=0)
也会转换为
csr
,因为列(或行)和是通过矩阵乘法完成的

因此,不转换要求是不现实的,至少在稀疏格式的范围内是如此

===============

对于Divakar的测试用例,我的
=
版本相当慢;小的测试可以,但创建的测试数组太大,有1000列

在一个矩阵上进行测试,该矩阵足够稀疏,可以有多个0列:

In [183]: Arr=sparse.random(1000,1000,.001)
In [184]: (1-np.in1d(np.arange(Arr.shape[1]),Arr.col)).any()
Out[184]: True
In [185]: (1-np.in1d(np.arange(Arr.shape[1]),Arr.col)).sum()
Out[185]: 367

In [186]: timeit 1-np.ones(Arr.shape[0],dtype=bool)*Arr.astype(bool)
1000 loops, best of 3: 334 µs per loop
In [187]: timeit 1-np.in1d(np.arange(Arr.shape[1]),Arr.col)
1000 loops, best of 3: 323 µs per loop
In [188]: timeit 1-(Arr.col==np.arange(Arr.shape[1])[:,None]).any(axis=1)
100 loops, best of 3: 3.9 ms per loop
In [189]: timeit (Arr!=0).sum(axis=0)==0
1000 loops, best of 3: 820 µs per loop

转换为数组或密集矩阵,沿第一个轴求绝对值之和,根据零测试结果,转换为int

>>> import numpy as np
>>> (np.sum(np.absolute(a.toarray()), 0) == 0) * 1
array([0, 0, 0, 1])
>>> (np.sum(np.absolute(a.todense()), 0) == 0) * 1
matrix([[0, 0, 0, 1]])
>>> 
>>> np.asarray((np.sum(np.absolute(a.todense()), 0) == 0), dtype = np.int32)
array([[0, 0, 0, 1]])
>>>

第一个是最快的-24我们为您在我的机器上的例子


对于由
np.random.randint(0,3,(10001000))
构成的矩阵,在我的机器上25毫秒时一切正常。

其他类型
你是指其他稀疏格式,还是像
numpy
array这样的类型?@hpaulj我的意思是说只是coo_矩阵正如我在回答中指出的,解决方案可能涉及到封面下的格式转换。稀疏函数可以自由转换格式以满足计算需要。对于这样的测试数组,不太可能有任何全0列。它不是稀疏的,只有1/3是零<代码>稀疏。random(10001000)更稀疏,但可能仍然没有这样的列。但这似乎并没有改变时间排名。因此,我们可以使用:
sp.coo_矩阵((np.random.rand(10001000)>0.998).astype(int))
,但据推测,加速不会有太大的变化。感谢您的基准测试,这真的很有帮助。
>>> import numpy as np
>>> (np.sum(np.absolute(a.toarray()), 0) == 0) * 1
array([0, 0, 0, 1])
>>> (np.sum(np.absolute(a.todense()), 0) == 0) * 1
matrix([[0, 0, 0, 1]])
>>> 
>>> np.asarray((np.sum(np.absolute(a.todense()), 0) == 0), dtype = np.int32)
array([[0, 0, 0, 1]])
>>>