计算igraph中连接平均值的有效方法?

时间:2014-04-03 10:31:40

标签: r parallel-processing plyr igraph

我正在使用igraph R.中的一个相当大的图形(约500万个顶点,4000万个边缘)。

我想为每个顶点创建一个新属性,它是每个连接的属性的平均值。

例如:

人A的X值为10,他们与人物B,C和D相连,他们的x值分别为20,50和65。我想为Person A分配一个新值45(平均值为20,50和65)。

我目前正在使用以下方法(来自另一个stackoverflow答案)(我正在使用10个核心)

adjcency_list <- get.adjlist(g)

avg_contact_val <- ldply(adjcency_list, function(neis){ mean(V(g)[neis]$X, na.rm = T)}, 
                      .parallel = TRUE
                      )

V(g)$avg_contact_val  <- avg_contact_val 

这完全符合我的需要,但它不能很好地扩展,并且需要花费很长时间才能完成整个图形。

  • 有更有效的方法吗?
  • 这可能属于使用x值而非度数
  • 的页面排名类型算法
  • 是否有可能以某种方式使用GPU?
  • igraph Python会更快吗?

编辑:

以下是一些示例数据和对建议方法的尝试:

set.seed(12345)
g <- erdos.renyi.game(10000, .0005)
V(g)$NAME <- c(1:10000)
V(g)$X <- round(runif(10000,0,30))

adjcency_list <- get.adjlist(g)

sub_ages <- data.frame(NAME = V(g)$NAME, X = V(g)$X)
dta.table <- data.table(sub_ages, key = "NAME")

数据表方法

system.time(
avg_contact_ages <- ldply(adjcency_list, 
                          function(neis){ 
                                  mean(dta.table[neis,mean(X)], na.rm = T)
                                  }, .progress = "tk"
                          )
)

user  system elapsed 
38.87    1.50   40.37 

数据框架方法

sub_ages2 <- data.frame(row.names = V(g)$NAME, X = V(g)$X)

system.time(
avg_contact_ages <- ldply(adjcency_list, 
                        function(neis){ 
                          mean(sub_ages2[neis, "X"], na.rm = T)
                        }, .progress = "tk"
  )
)

user  system elapsed 
8.69    1.28    9.99 

ORIGINAL APPROACH

system.time(
avg_contact_ages <- ldply(adjcency_list, 
                          function(neis){ 
                            mean(V(g)[neis]$X, na.rm = T)
                          } , .progress = "tk"
                      )
)

user  system elapsed 
16.74    2.35   19.14 

暗影的方法

system.time(
  avg_nei <- ldply(V(g), function(vert){
    mean(get.vertex.attribute(g, "X", index=neighbors(g,vert)), na.rm=TRUE)
  }, .progress = "tk")
)

user  system elapsed 
8.80    1.42   10.23 

2 个答案:

答案 0 :(得分:2)

函数get.vertex.attribute增加了一些速度。但是对于图表的大小,这可能还不够。无论如何,这是我的稍微快一点的版本(在我的基准测试中,对于更小的图形,它比你的版本快2.5倍):

avg_nei <- ldply(V(g), function(vert){
  mean(get.vertex.attribute(g, "X", index=neighbors(g,vert)), na.rm=TRUE)
}, .parallel = TRUE)
V(g)$avg_contact_val <- avg_nei

答案 1 :(得分:2)

  
      
  • 有更有效的方法吗?
  •   

我是这么认为的。不要一直调用V(g),而是将属性放在向量中,并将其编入索引。如果你包含一些示例数据,那么我还会包含一些代码。

  
      
  • 这可能属于使用x值而非度数
  • 的页面排名类型算法   

不,PageRank是递归的,你的等级取决于整个网络,而不仅仅取决于你邻居的得分。

  
      
  • 是否有可能以某种方式使用GPU?
  •   

不是igraph。你可以在没有GPU的情况下让它足够快,所以我不会这样做。

  
      
  • igraph Python会更快吗?
  •   

取决于你如何写它。如果你在R中用正确的方式写它,那么它在Python中也不会更快,imo。

编辑:

我遗漏了进度条,因为那是最慢的,实际上。

上面最快的数据框

解决方案
system.time({
  sub_ages2 <- data.frame(row.names = V(g)$NAME, X = V(g)$X);
  avg_contact_ages <- ldply(adjcency_list, function(neis) {
    mean(sub_ages2[neis, "X"], na.rm = T)
  })
})
#    user  system elapsed 
#   0.368   0.020   0.386 

使用sapply

稍快一些
system.time({
  sub_ages2 <- data.frame(row.names = V(g)$NAME, X = V(g)$X);
  avg_contact_ages <- sapply(adjcency_list, function(neis) {
    mean(sub_ages2[neis, "X"], na.rm = TRUE)
  })
})
#    user  system elapsed 
#   0.340   0.017   0.356 

使用因素

system.time({
  adj_vec <- unlist(adjcency_list)
  adj_fac <- factor(rep(seq_along(adjcency_list),
                 sapply(adjcency_list, length)),levels=seq_len(vcount(g)))
  avg_contact_ages <- tapply(V(g)$X[adj_vec], adj_fac, mean, na.rm=TRUE)
})
#    user  system elapsed 
#   0.131   0.008   0.138 

如果你需要更多的加速,你可能需要转到C / C ++,Rcpp将是一个相对简单的解决方案。