如何根据带有关系的多个列在R中订购data.table?

时间:2017-01-06 16:18:50

标签: r data.table

我对data.table相当新,并且有一个基本问题。我正在尝试根据两列重新排序以下数据表。

library(data.table)
DT <- data.table(letter=c('a','a','a','a','b','b','c','d','d','d','d'),  
                 value =c(1,2,4,8,2,5,1,1,2,3,9))

        letter value
 1:      a     1
 2:      a     2
 3:      a     4
 4:      a     8
 5:      b     2
 6:      b     5
 7:      c     1
 8:      d     1
 9:      d     2
10:      d     3
11:      d     9

我希望根据最低相关值对字母进行排序,如果它们相等则应比较下一个值(如果可用),依此类推。

这应该产生以下结果:

    letter value
 1:      c     1
 2:      d     1
 3:      d     2
 4:      d     3
 5:      d     9
 6:      a     1
 7:      a     2
 8:      a     4
 9:      a     8
10:      b     2
11:      b     5

我已尝试DT[order(value), .SD, letter]对值进行排序,但在最低关联值的情况下不考虑后续值。我觉得应该有一个简单的方法来做到这一点,但我找不到答案。感谢。

1 个答案:

答案 0 :(得分:1)

  

我想根据最低的相关值对字母进行排序,如果它们相等则应该比较下一个值(如果可用),等等。

这不是那么简单。首先,我们需要填充数据,以便c的“第二”值再次为1;第三;第四个:

n = max(DT[, .N, by=letter]$N)
oDT = DT[, .(rid = 1:n, v = c(value, rep(value[.N], n-.N))), by=letter]

然后,我认为我们需要一个递归函数来检查关系:

chk_ties = function(L, r, maxr = n){
    if (r == maxr) 
        L
    else
        oDT[letter %in% L & rid == r, {
            if (.N > 1L)
                chk_ties(letter, r + 1L)
            else
                letter
        }, keyby=v]$V1
}

chk_ties(unique(DT$letter), 1L)
# [1] "c" "d" "a" "b"

或者,我没有使用递归函数,而是意识到我们可以制作这个hack:

setorderv(dcast(oDT, letter ~ rid), as.character(1:n))$letter
# [1] "c" "d" "a" "b"

最后,我们需要加入,就像在@ lmo的回答中一样:

DT[setorderv(dcast(oDT, letter ~ rid), as.character(1:n))$letter, on="letter"]
# or
DT[chk_ties(unique(DT$letter), 1L), on=.(letter)]

可以在这里写on=.(letter)on="letter"