使用data.table

时间:2015-12-16 20:35:25

标签: r data.table

我有两组由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)
}

所以问题是如何有效地矢量化这个算法?

1 个答案:

答案 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)