7

问题

在R 包中,是否有可以处理多个源顶点igraph的有效实现和/或 BFS?subcomponent()

动机

drakeR 包将用户的工作流建模为相互依赖的对象和文件的 DAG。DAG 应该只包含用户的目标及其上游依赖项,因此drake用于igraph::subcomponent()消除多余的顶点。这种方法效率低下,因为v参数必须是单个顶点,因此drake最终会为用户想要构建的每个目标执行新的 BFS。

编辑:2019-01-10

drake现在使用一种不同的方法,最终依赖于对adjacent_vertices(). 该方法很笨拙,但速度提升实际上相当不错。仍然坚持更优雅和精致的东西。

4

1 回答 1

2

我认为您可以使用distances()生成节点之间的距离矩阵(没有边)的函数来做到这一点。这似乎只进行一次搜索,并且比遍历每个顶点要快得多。

示例代码:

library(igraph)
library(microbenchmark)

# generate some random testing data
set.seed(1234)
g <- erdos.renyi.game(50, .01)

# Here we make a function that iterates 
# across the vector of IDs applying the function
# and returns a list where each element is the
# ids of the subcomponents
sc_apply <- function(g) {
  vs <- V(g)
  res <- sapply(vs, function(v){as.numeric( # to facilitate comparison
    subcomponent(g, v, mode = "in")
    )})
  res
}

# Try it for testing
t1 <- sc_apply(g)

# Here we get the matrix of node distances. Infinite distance
# implies a seperate component. We iterate through rows of
# matrix to extract the set of nodes that are connected 
sc_distmat <- function(g) {
  dmat <- distances(g, mode = "in")
  res <- apply(dmat, 1, function(row){which(is.finite(row))})
  res
}

# extract for testing
t2 <- sc_distmat(g)

# check that equal (we need to sort the 
# subcomponent list elements first to facilitate comparison)
all.equal(lapply(t1, sort), t2)
#> [1] TRUE

结果是相同的——尽管值得注意的是,如果您的图表是一个巨大的组件,那么 apply 将向您返回一个矩阵而不是一个列表,因此您需要以稍微不同的方式进行比较。

好的,现在让我们看看这更快/是否更快:

# generate graphs of different sizes (not too big because my
# laptop is borderline antique!)
set.seed(42)
small_g <- erdos.renyi.game(10, .2)
mid_g <- erdos.renyi.game(50, .1)
big_g <- erdos.renyi.game(100, .1)

# check speed improvement
microbenchmark(sc_apply(small_g), sc_distmat(small_g))
#> Unit: microseconds
#>                 expr      min        lq      mean   median        uq
#>    sc_apply(small_g) 2181.465 2243.4895 2734.7132 2313.005 2777.7135
#>  sc_distmat(small_g)  451.333  471.8565  840.4742  521.865  598.0845
#>        max neval cld
#>   9152.262   100   b
#>  27139.262   100  a
microbenchmark(sc_apply(mid_g), sc_distmat(mid_g))
#> Unit: microseconds
#>               expr       min        lq       mean    median         uq
#>    sc_apply(mid_g) 11006.113 11327.794 13590.9536 12919.492 15397.2510
#>  sc_distmat(mid_g)   757.752   795.308   949.2551   841.834   965.4545
#>        max neval cld
#>  27068.296   100   b
#>   2061.824   100  a
microbenchmark(sc_apply(big_g), sc_distmat(big_g))
#> Unit: milliseconds
#>               expr      min        lq      mean    median        uq
#>    sc_apply(big_g) 23.11678 26.696373 29.940675 29.191045 33.012796
#>  sc_distmat(big_g)  1.67531  1.727873  2.156307  1.855994  2.244872
#>        max neval cld
#>  47.081647   100   b
#>   7.576123   100  a

如您所见,该distances()方法速度更快,并且随着图形大小的增长越来越快。

reprex 包(v0.2.1)于 2019 年 1 月 10 日创建

于 2019-01-10T14:43:39.820 回答