问题描述
我有一个非常大的配对列表,我需要将其分解为单个链接社区。到目前为止,我已经能够完全在 R 中做到这一点。但是我需要为整个列表可能太大而无法保存在内存中或 igraph 的 R 实现来处理的可能性做准备。此任务的一个非常简单的版本如下所示:
library(igraph)
df <- data.frame("p1" = c("a","a","d","d"),"p2" = c("b","c","e","f"),"val" = c(0.5,0.75,0.25,0.35))
g <- graph_from_data_frame(d = df,directed = FALSE)
sg <- groups(components(g))
sg <- sapply(sg,function(x) induced_subgraph(graph = g,vids = x),USE.NAMES = FALSE,simplify = FALSE)
如果 df
非常大 - 在数亿到数百亿行的规模上,有没有办法让我提取 sg
的各个位置而无需构建 {{ 1}} 的全部内容?对我来说,将 g
的表示作为压缩的 txt 文件或 sqlite 数据库存储在 R 之外相对容易。
解决方法
为了解决 igraph 的 R 实现的问题(假设数据集仍然可以保存在 RAM 中,否则请参阅@Paul Brodersen 的回答):
以下解决方案的工作原理是指定图形的一个元素,然后遍历所有连接,直到找不到更多边为止。因此,它在不构建整个图的情况下创建子图。与递归函数相比,它看起来有点笨拙,但扩展性更好。
library(igraph)
reduce_graph <- function(df,element) {
stop = F
elements_to_inspect <- element
rows_graph <-0
while(stop ==F) {
graph_parts <- df[df$p1 %in% elements_to_inspect |
df$p2 %in% elements_to_inspect,]
elements_to_inspect <- unique(c(unique(graph_parts$p1),unique(graph_parts$p2)))
if(dim(graph_parts)[1] == rows_graph) {
stop <-TRUE
} else {
rows_graph <- dim(graph_parts)[1]
}
}
return(graph_parts)
}
df <- data.frame("p1" = c("a","a","d","o"),"p2" = c("b","c","e","f","u"),"val" = c(100,0.75,0.25,0.35,1))
small_graph <- reduce_graph(df,"f")
g <- graph_from_data_frame(d = small_graph,directed = FALSE)
sg <- groups(components(g))
sg <- sapply(sg,function(x) induced_subgraph(graph = g,vids = x),USE.NAMES = FALSE,simplify = FALSE)
可以在更大的数据集上测试速度。
##larger dataset with lots of sparse graphs.
set.seed(100)
p1 <- as.character(sample(1:10000000,1000000,replace=T))
p2 <- as.character(sample(1:10000000,replace=T))
val <- rep(1,1000000)
df <- data.frame("p1" = p1,"p2" = p2,"val" = val)
small_graph <- reduce_graph(df,"9420672") #has 3 pairwise connections
g <- graph_from_data_frame(d = small_graph,simplify = FALSE)
构建组和子图需要一秒钟,而在我的机器上构建整个图需要几分钟。这当然取决于图的稀疏连接程度。