计算顶点邻域中有多少个顶点在igraph中有一个属性

时间:2014-04-18 13:39:49

标签: r igraph

我在igraph中有一个大图(实际上是几个) - 大约100,000个顶点 - 每个顶点都有一个属性truefalse。对于每个顶点,我想计算直接连接到它的顶点有多少具有该属性。我目前的解决方案是以下函数,它以图形为参数。

attrcount <- function(g) {
  nb <- neighborhood(g,order=1)
  return(sapply(nb,function(x) {sum(V(g)$attr[x]}))
}

这会返回一个计数向量,对于具有该属性的顶点,它会减1,但我可以轻松地调整它。

问题在于这种速度非常缓慢,似乎应该有一种快速的方法来实现这一点,因为,例如,使用degree(g)计算每个顶点的程度几乎是瞬时的。

我这样做是一种愚蠢的方式吗?

举个例子,假设这是我们的图表。

set.seed(42)
g <- erdos.renyi.game(169081, 178058, type="gnm")
V(g)$att <- as.logical(rbinom(vcount(g), 1, 0.5))

2 个答案:

答案 0 :(得分:2)

使用get.adjlist查询所有相邻顶点,然后在此列表中sapply(或tapply可能更快)获取计数。将属性存储在向量中也是值得的,因为这样您就不需要一直提取它。

与sapply

system.time({
  al <- get.adjlist(g)
  att <- V(g)$att
  res <- sapply(al, function(x) sum(att[x]))
})
#   user  system elapsed 
#  0.571   0.005   0.576 

使用tapply

system.time({
  al <- get.adjlist(g)
  alv <- unlist(al)
  alf <- factor(rep(seq_along(al), sapply(al, length)),
                levels=seq_along(al))
  att <- V(g)$att
  res2 <- tapply(att[alv], alf, sum)
  res2[is.na(res2)] <- 0
})
#   user  system elapsed 
#  1.121   0.020   1.144 

all(res == res2)
# TRUE

对我来说有点意外,但tapply解决方案实际上更慢。

如果这仍然不够,那么我想你仍然可以通过用C / C ++编写来加快速度。

答案 1 :(得分:0)

为了加快计算速度,使用get.adjacency拉出邻接矩阵,然后使用%*%将矩阵乘以属性向量:

library(igraph)
set.seed(42)
g <- erdos.renyi.game(1000, 1000, type = "gnm")
V(g)$att <- as.logical(rbinom(vcount(g), 1, 0.5))

system.time({
  ma   <- get.adjacency(g)
  att  <- V(g)$att
  res1 <- as.numeric(ma %*% att)
})
#  user  system elapsed 
# 0.003   0.000   0.003 

与使用get.adjlistsapply

相比
system.time({
  al   <- get.adjlist(g)
  att  <- V(g)$att
  res2 <- sapply(al, function(x) sum(att[x]))
})
#   user  system elapsed 
#  9.733   0.243  10.107

修改res1的类后,结果向量是相同的:

res1 <- as.numeric(res1)
identical(res1, res2)
# [1] TRUE