我在igraph中有一个大图(实际上是几个) - 大约100,000个顶点 - 每个顶点都有一个属性true
或false
。对于每个顶点,我想计算直接连接到它的顶点有多少具有该属性。我目前的解决方案是以下函数,它以图形为参数。
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))
答案 0 :(得分:2)
使用get.adjlist
查询所有相邻顶点,然后在此列表中sapply
(或tapply
可能更快)获取计数。将属性存储在向量中也是值得的,因为这样您就不需要一直提取它。
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
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.adjlist
和sapply
:
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