たとえば、著者と本をマップする SQL テーブルがあります。リンクされた著者と本 (同じ著者が書いた本、および本を共同執筆した著者) をグループ化し、これらのグループがどのくらい大きくなるかを確認したいと思います。たとえば、JK ローリングがジュノット ディアスと共同執筆し、ジュノット ディアスがザディ スミスと共同で本を執筆した場合、3 人の著者全員が同じグループに属することを望みます。
ここに、私が話している関係のいくつかを含むおもちゃのデータセット (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 がブック 2 を共同執筆したことがわかります。したがって、彼らは同じグループに属しているはずです。3 の著者 63 と 100 についても同じです。4 の場合は D、F、L などです。
(ご想像のとおり) 遅い 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]
}
#})
編集: @Josh O'Brien と @thelatemail で述べたように、私の問題は、すべてのエッジが行であり、2 つの列が接続されたノードである 2 列のリストからグラフの接続されたコンポーネントを探すこととして表現することもできます。 .