我有一个 SQL 表,可以映射作者和书籍等内容。我想将链接的作者和书籍(同一作者撰写的书籍以及共同撰写一本书的作者)分组在一起,并确定这些组的规模有多大。例如,如果 J.K.罗琳与朱诺·迪亚兹合写,朱诺·迪亚兹与扎迪·史密斯合写了一本书,那么我希望这三位作者都在同一组。
这是一个玩具数据集(h/t Matthew Dowle),其中包含我正在谈论的一些关系:
set.seed(1)
authors <- replicate(100,sample(1:3,1))
book_id <- rep(1:100,times=authors)
author_id <- c(lapply(authors,sample,x=1:100,replace=FALSE),recursive=TRUE)
aubk <- data.table(author_id = author_id,book_id = book_id)
aubk[order(book_id,author_id),]
在这里可以看到作者 27 和 36 共同撰写了第二本书,因此他们应该属于同一组。作者 63 和 3 的作者 100 也是如此; 4 为 D、F 和 L。依此类推。
除了 for 循环之外,我想不出有什么好方法来做到这一点,因为 for 循环(正如你可以猜到的)很慢。我尝试了一点data.table
以避免不必要的复制。有更好的方法吗?
aubk$group <- integer(dim(aubk)[1])
library(data.table)
aubk <- data.table(aubk)
#system.time({
for (x in 1:dim(aubk)[1]) {
if(identical(x,1)) {
value <- 1L
} else {
sb <- aubk[1:(x-1),]
index <- match(aubk[x,author_id],sb[,author_id])
if (identical(index,NA_integer_)) {
index <- match(aubk[x,book_id],sb[,book_id])
if (identical(index,NA_integer_)) {
value <- x
} else {
value <- aubk[index,group]
}
} else {
value <- aubk[index,group]
}
}
aubk[x,group:=value]
}
#})
EDIT:正如 @Josh O'Brien 和 @thelatemail 所提到的,我的问题也可以表述为从两列列表中查找图形的连接组件,其中每条边都是一行,两列是连接的节点。