我有两组由id1和&表示的节点。 ID2。 我有一个data.table包含对节点对的惩罚 - 键(id1,id2),值是惩罚。
如何有效地将data.table范围扩展到节点对,并且每个节点(id1和id2)出现一次?
简单示例:
输入data.table:
dtIn <- data.table(
id1 = rep(letters[1:3], each=3)
, id2 = rep(1:3, 3)
, penalty = 1:9
)
setkey(dtIn, id1, id2)
print(dtIn)
id1 id2 penalty
1: a 1 1
2: a 2 2
3: a 3 3
4: b 1 4
5: b 2 5
6: b 3 6
7: c 1 7
8: c 2 8
9: c 3 9
所需的输出数据。表:
id1 id2 penalty
1: a 1 1
2: b 2 5
3: c 3 9
我知道如何实现编写循环的算法:按惩罚排序,循环记录并按顺序选择每一对,如果之前没有节点匹配的话。请参阅下面的代码。
但是当然这样的循环对我的真实大小的数据来说运行得非常慢。
手动循环功能在逻辑上正确但执行方式太差:
manualIter <- function(dtIn) {
setkey(dtIn, penalty, id1, id2) # Enusred ordered by penalty.
id1Match <- NULL; id2Match <- NULL; pen <- NULL;
for (i in seq_len(nrow(dtIn))) {
if (!(dtIn$id1[i] %in% id1Match) && !(dtIn$id2[i] %in% id2Match)) {
id1Match <- c(id1Match, dtIn$id1[i])
id2Match <- c(id2Match, dtIn$id2[i])
pen <- c(pen, dtIn$penalty[i])
}
}
# Build the return data.table for the matching ids.
dtf <- data.table(id1 = id1Match, id2 = id2Match, penalty = pen)
setkey(dtf, id1, id2)
return(dtf)
}
所以问题是如何有效地矢量化这个算法?
答案 0 :(得分:0)
更新了答案。我不确定你能否实现这一目标。我认为它本质上是一个递归问题。我的回答是直截了当的(给定数据按惩罚排序):
dtOut <- list()
dtOut[[1]] <- dtIn[1]
i <- 2
while(dtIn[, .N] > 0) {
dtIn <- dtIn[!(id1 == dtOut[[i - 1]][, id1] | id2 == dtOut[[i - 1]][, id2])]
if(dtIn[, .N] < 1) break
dtOut[[i]] <- dtIn[1]
i <- i + 1
}
dtOut <- rbindlist(dtOut)