问题
在原有图基础上,来了新的节点及边关系后如何能快速的得到新的邻接矩阵,并进行后续处理是比较重要的。如果说直接在原有图上进行边的添加,再基于图去生成邻接矩阵的话,这个耗时会是相当费时的。
import networkx as nx
origin_G = nx.read_gpickle('graph.pkl') # 获得原始图
nodes = origin_G.nodes # 图的所有节点
new_node = max(nodes) + 1 # 对于最新的节点而言,对其编码为原始节点中最大id节点+1
new_edges = [(new_node, 1), (new_node, 10), ...]
origin_G.add_edges_from(new_edges) # 向图中添加新的边
new_adjacency = nx.adjacency_matrix(origin_G) # 得到新的邻接矩阵
上述耗时根据图的大小不同,本人实验的图的话上述大概耗时10秒左右;
解决办法
有了原始图之后,我们可以直接从原始图得到原始的邻接矩阵,对于新的节点而言,我们可以直接对原始矩阵进行扩增列和行来表示新的邻接矩阵,基于边关系更改邻接矩阵中的值即可,不用进行复杂的往图中添加边,从图中获取邻接矩阵。
from scipy import sparse
origin_adjacency = nx.adjacency_matrix(origin_G).toarray() # 转化为ndarray进行处理,否则是scipy sparse格式
m, n = origin_adjacency.shape
row_pad = np.array([[0] * m]) # 增加空行
col_pad = np.array([[0] * (n+1)]) # 增加空列
tmp_adjacency = np.insert(origin_adjacency, m, values=row_pad, axis=0) # 原始邻接矩阵末尾加一行全零值
new_adjacency = np.insert(tmp_adjacency, n, values=col_pad, axis=1) # 在添加行的矩阵上最后一列多加一列全零值
for edge in new_edges:
i, j = edge
new_adjacency[i][j] = 1
new_adjacency[j][i] = 1 # 无向图
new_adj = sparse.csr_matrix(new_adjacency) # 转化为scipy sparse 格式
上述耗时大约为 8 ∗ 1 0 − 7 8*10^{-7} 8∗10−7秒左右,从10秒加速了好几个量级,且二者得到的结果一样,保证了准确性提高了速度。
总结
虽然封装的方法使用起来非常方便快捷,但如果能够理解一些基础性的原理和操作的话,通过简单的加减乘除等操作处理能够在保证结果准确的前提下,大大提升速度。
参考
- https://stackoverflow.com/questions/7922487/how-to-transform-numpy-matrix-or-array-to-scipy-sparse-matrix
- https://stackoverflow.com/questions/26576524/how-do-i-transform-a-scipy-sparse-matrix-to-a-numpy-matrix
- https://blog.csdn.net/tintinetmilou/article/details/78119320
- https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.toarray.html