检查 R igraph 中节点之间的连接时的时间复杂度问题
time complexity issue when checking the connectivity between nodes in R igraph
我想查看给定图中每个节点的哪些一级节点连接到哪些二级节点。假设我生成一个有 1000 个节点的图。
library(igraph)
g <- erdos.renyi.game(1000, 0.2)
当我为图中的每个节点计算相邻节点和二度节点的集合时,没有问题。
代码运行速度非常快,不受网络规模的影响。一旦我添加了一个 if
语句来检查两个节点是否连接为:
for(j in adjacent){
for(k in secondDegreNodes){
if( are.connected(g, j, k) ){
}
}
}
我的代码需要永远。我面临的确切复杂性问题是什么?有没有更好的方法来进行这个操作?
确实发生了一些奇怪的事情。即使是下面的代码块也不会收敛,尽管它是最简单的操作。
g <- erdos.renyi.game(1000, 0.3)
A <- as_adjacency_matrix(g)
from<- 1
to <- nrow(A)
for(i in from:to){
for(j in i:to){
if(A[i,j] == 1){
#do nothing
}
}
}
编辑:我相信 igraph 包可能存在一些问题。我在 R igraph 中生成了图表,并用 Java 语言对所有内容进行了编码,并且成功了。如我所料,该算法没有复杂性问题。但是,我不知道 igraph 有什么问题。
在您给出的示例中,在 for 循环中重复索引矩阵 A
是相当低效的。在这个特定的例子中,这是由于 A
属于包 Matrix 的 class dgCMatrix
。
当您比较将 A
转换为另一个 class 前后的性能时,您会注意到差异。对于 N = 300
个节点,一旦我转换为标准矩阵 class,for 循环的持续时间在我的机器上从 23.5 秒减少到 0.1 秒。此外还有 (N^2 + N) / 2 次比较。平方项意味着从 300 个节点增加到 3 x 300 = 900 个节点将使计算时间大致增加九倍(至少)。
如果您进一步 Rprof
归档代码,您将看到在对 class dgCMatrix
(即 A[i, j]
)的对象进行子集化时,还有许多其他 R 函数被调用,而函数 [
直接在 C 中为基本矩阵 class 实现。另外,dgCMatrix
来自S4对象系统。这意味着 i.a。找到用于 [
的正确方法比平时要贵一些。
最后,如果您依赖 R,那么(通常)使用 向量化操作 会更好。这些通常会避免进一步(低效的)R 函数的深层调用堆栈,并且通常会在 C 中实现。使用邻接矩阵,您可以通过检查 A_2 = A %*% A
快速找到二阶节点,这也非常快(或我怀疑尤其如此)对于 class dgCMatrix
.
的对象
时间:
library(igraph)
N <- 300
g <- erdos.renyi.game(N, 0.3)
A <- as_adjacency_matrix(g)
from<- 1
to <- nrow(A)
class(A)
# [1] "dgCMatrix"
# attr(,"package")
# [1] "Matrix"
# run through matrix via for loop
# 23.5 seconds
system.time({
for(i in from:to){
for(j in i:to){
if(A[i,j] == 1) {}
}
}
})
# change class
A <- as.matrix(A)
class(A)
# [1] "matrix"
# run for loop again
# 0.097 seconds
system.time({
for(i in from:to){
for(j in i:to){
if(A[i,j] == 1) {}
}
}
})
我想查看给定图中每个节点的哪些一级节点连接到哪些二级节点。假设我生成一个有 1000 个节点的图。
library(igraph)
g <- erdos.renyi.game(1000, 0.2)
当我为图中的每个节点计算相邻节点和二度节点的集合时,没有问题。
代码运行速度非常快,不受网络规模的影响。一旦我添加了一个 if
语句来检查两个节点是否连接为:
for(j in adjacent){
for(k in secondDegreNodes){
if( are.connected(g, j, k) ){
}
}
}
我的代码需要永远。我面临的确切复杂性问题是什么?有没有更好的方法来进行这个操作?
确实发生了一些奇怪的事情。即使是下面的代码块也不会收敛,尽管它是最简单的操作。
g <- erdos.renyi.game(1000, 0.3)
A <- as_adjacency_matrix(g)
from<- 1
to <- nrow(A)
for(i in from:to){
for(j in i:to){
if(A[i,j] == 1){
#do nothing
}
}
}
编辑:我相信 igraph 包可能存在一些问题。我在 R igraph 中生成了图表,并用 Java 语言对所有内容进行了编码,并且成功了。如我所料,该算法没有复杂性问题。但是,我不知道 igraph 有什么问题。
在您给出的示例中,在 for 循环中重复索引矩阵 A
是相当低效的。在这个特定的例子中,这是由于 A
属于包 Matrix 的 class dgCMatrix
。
当您比较将 A
转换为另一个 class 前后的性能时,您会注意到差异。对于 N = 300
个节点,一旦我转换为标准矩阵 class,for 循环的持续时间在我的机器上从 23.5 秒减少到 0.1 秒。此外还有 (N^2 + N) / 2 次比较。平方项意味着从 300 个节点增加到 3 x 300 = 900 个节点将使计算时间大致增加九倍(至少)。
如果您进一步 Rprof
归档代码,您将看到在对 class dgCMatrix
(即 A[i, j]
)的对象进行子集化时,还有许多其他 R 函数被调用,而函数 [
直接在 C 中为基本矩阵 class 实现。另外,dgCMatrix
来自S4对象系统。这意味着 i.a。找到用于 [
的正确方法比平时要贵一些。
最后,如果您依赖 R,那么(通常)使用 向量化操作 会更好。这些通常会避免进一步(低效的)R 函数的深层调用堆栈,并且通常会在 C 中实现。使用邻接矩阵,您可以通过检查 A_2 = A %*% A
快速找到二阶节点,这也非常快(或我怀疑尤其如此)对于 class dgCMatrix
.
时间:
library(igraph)
N <- 300
g <- erdos.renyi.game(N, 0.3)
A <- as_adjacency_matrix(g)
from<- 1
to <- nrow(A)
class(A)
# [1] "dgCMatrix"
# attr(,"package")
# [1] "Matrix"
# run through matrix via for loop
# 23.5 seconds
system.time({
for(i in from:to){
for(j in i:to){
if(A[i,j] == 1) {}
}
}
})
# change class
A <- as.matrix(A)
class(A)
# [1] "matrix"
# run for loop again
# 0.097 seconds
system.time({
for(i in from:to){
for(j in i:to){
if(A[i,j] == 1) {}
}
}
})