Python 计算scipy稀疏矩阵的稀疏传递闭包
我想用Python计算稀疏矩阵的。目前我正在使用scipy稀疏矩阵 矩阵幂(Python 计算scipy稀疏矩阵的稀疏传递闭包,python,numpy,scipy,sparse-matrix,floyd-warshall,Python,Numpy,Scipy,Sparse Matrix,Floyd Warshall,我想用Python计算稀疏矩阵的。目前我正在使用scipy稀疏矩阵 矩阵幂(**12在我的例子中)适用于非常稀疏的矩阵,无论它们有多大,但对于定向不太稀疏的情况,我希望使用更智能的算法 我在中发现了(德语页面有更好的伪代码),这比它应该做的要多一些:只有Warshall的算法没有函数——这是一回事 主要问题是我可以将稀疏矩阵传递给函数,但这完全没有意义,因为函数总是返回密集矩阵,因为传递闭包中应该为0的现在是inf长度的路径,有人认为需要显式存储 所以我的问题是:是否有任何python模块允许计
**12
在我的例子中)适用于非常稀疏的矩阵,无论它们有多大,但对于定向不太稀疏的情况,我希望使用更智能的算法
我在中发现了(德语页面有更好的伪代码),这比它应该做的要多一些:只有Warshall的算法没有函数——这是一回事
主要问题是我可以将稀疏矩阵传递给函数,但这完全没有意义,因为函数总是返回密集矩阵,因为传递闭包中应该为0的现在是inf
长度的路径,有人认为需要显式存储
所以我的问题是:是否有任何python模块允许计算稀疏矩阵的传递闭包,并使其保持稀疏
我不是100%确定他是否使用相同的矩阵,但杰拉尔德·佩恩(Gerald Penn)在这方面表现出了令人印象深刻的加速,这表明有可能解决这个问题
编辑:由于存在许多困惑,我将指出理论背景: 我正在寻找传递闭包(非自反或对称) 我将确保在布尔矩阵中编码的关系具有所需的属性,即对称性或自反性 我有两个关系的案例:
(source, dictionary of reachable targets)
转换成SciPy稀疏矩阵(csr格式在这里很自然)需要一些工作。一个完整的例子:
import numpy as np
import networkx as nx
import scipy.stats as stats
import scipy.sparse as sparse
A = sparse.random(6, 6, density=0.2, format='csr', data_rvs=stats.randint(1, 2).rvs).astype(np.uint8)
G = nx.DiGraph(A) # directed because A need not be symmetric
paths = nx.all_pairs_shortest_path_length(G)
indices = []
indptr = [0]
for row in paths:
reachable = [v for v in row[1] if row[1][v] > 0]
indices.extend(reachable)
indptr.append(len(indices))
data = np.ones((len(indices),), dtype=np.uint8)
A_trans = A + sparse.csr_matrix((data, indices, indptr), shape=A.shape)
print(A, "\n\n", A_trans)
添加back的原因如下所示。Networkx输出包括长度为0的路径,这将立即填充对角线。我们不希望发生这种情况(您希望传递闭包,而不是自反和传递闭包)。因此,如果行[1][v]>0],则行reachable=[v代表行[1]中的v]。但是我们根本没有得到任何对角线条目,即使在A有对角线条目的地方(0长度的空路径比自循环形成的1长度路径好)。所以我给结果加了一个back。它现在有条目1或条目2,但只有它们不是零这一事实才有意义
运行上述操作的一个示例(为了输出的可读性,我选择了6×6的大小)。原始矩阵:
(0, 3) 1
(3, 2) 1
(4, 3) 1
(5, 1) 1
(5, 3) 1
(5, 4) 1
(5, 5) 1
传递闭包:
(0, 2) 1
(0, 3) 2
(3, 2) 2
(4, 2) 1
(4, 3) 2
(5, 1) 2
(5, 2) 1
(5, 3) 2
(5, 4) 2
(5, 5) 1
您可以看到这是正确的:添加的条目是(0,2)、(4,2)和(5,2),所有条目都是通过路径(3,2)获取的
顺便说一句,networkx也有方法,但它的文档中说
该算法最适合于稠密图。运行时间是O(n^3),运行空间是O(n^2),其中n是G中的节点数
输出再次密集。我得到的印象是,这个算法本质上被认为是稠密的。似乎所有对的最短路径长度是一种
及物与反身
如果您想要传递闭包(包含给定路径的最小传递关系)和自反闭包(包含给定路径的最小传递和自反关系),而不是传递闭包,那么代码将简化,因为我们不再担心0长度路径
for row in paths:
indices.extend(row[1])
indptr.append(len(indices))
data = np.ones((len(indices),), dtype=np.uint8)
A_trans = sparse.csr_matrix((data, indices, indptr), shape=A.shape)
传递的、自反的和对称的
这意味着找到包含给定等价关系的最小等价关系。等效地,将顶点划分为连接的组件。为此,您不需要转到networkx,这里有一种SciPy方法。在此处设置directed=False
。例如:
import numpy as np
import scipy.stats as stats
import scipy.sparse as sparse
import itertools
A = sparse.random(20, 20, density=0.02, format='csr', data_rvs=stats.randint(1, 2).rvs).astype(np.uint8)
components = sparse.csgraph.connected_components(A, directed=False)
nonzeros = []
for k in range(components[0]):
idx = np.where(components[1] == k)[0]
nonzeros.extend(itertools.product(idx, idx))
row = tuple(r for r, c in nonzeros)
col = tuple(c for r, c in nonzeros)
data = np.ones_like(row)
B = sparse.coo_matrix((data, (row, col)), shape=A.shape)
这是一个随机示例的输出print(B.toarray())
的样子,20 x 20:
[[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]]
关于PS,我想看一些例子(另一个问题?)。稀疏矩阵与密集数组相乘返回密集数组。为了提高效率,sparse.csr
不会在每次更改值时更改稀疏索引。有时您必须运行消除_零
来清除它。过去的示例:,如果乘法返回密集矩阵,请尝试先将其他
数组转换为稀疏矩阵sparse*sparse
生成sparse
floyd_warshall
在sparse.csgraph.shortest_path中。所以
,一个编译模块。你说得对,我刚刚在“关于scipy的失望”下面收集了这个。。。我要问一个新问题。我有点担心创建python字典作为输出的开销,但可能真的没有基于C的实现返回稀疏的scipy矩阵……也许我误解了传递闭包的含义。我实际上想要你们所说的“自反和传递闭包”。这也是一个选项,但我希望有一个解决方案能够与通常的依赖项一起工作。numy或scipyConnected组件也执行对称闭包,因为关系“a和b在同一个组件中”是对称的。请向自己和他人明确说明,您是寻求传递闭包、传递闭包和自反闭包、传递闭包和自反闭包、对称闭包(因此,由给定闭包生成的等价关系)还是其他什么。添加了完整的示例f
[[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
[1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]]