重新排序data.table记录的子集

时间:2013-05-11 20:45:03

标签: r data.table

假设我有以下数据。表:

set.seed(123)
dt <- data.table (id=1:10,
                  group=sample(LETTERS[1:3], 10, replace=TRUE),
                  val=sample(1:100, 10, replace=TRUE),
                  ltr=sample(letters, 10),
                  col5=sample(100:200, 10)
                  )
setkey(dt, id)
(dt)
#     id group  val  ltr col5
#  1:  1     A   96    x  197
#  2:  2     C   46    r  190
#  3:  3     B   68    p  168
#  4:  4     C   58    w  177
#  5:  5     C   11    o  102
#  6:  6     A   90    v  145
#  7:  7     B   25    k  172
#  8:  8     C    5    l  120
#  9:  9     B   33    f  129
# 10: 10     B   96    c  121

现在我想通过group进行分组来处理它,并且在每个组中我需要按val列排序记录,然后在每个有序组中进行一些操作(例如,添加一个值为ltr的列按顺序合并):

#     id group val ltr letters
#  1   6     A  90   v     v_x
#  2   1     A  96   x     v_x
#  3   7     B  25   k k_f_p_c
#  4   9     B  33   f k_f_p_c
#  5   3     B  68   p k_f_p_c
#  6  10     B  96   c k_f_p_c
#  7   8     C   5   l l_o_r_w
#  8   5     C  11   o l_o_r_w
#  9   2     C  46   r l_o_r_w
#  10  4     C  58   w l_o_r_w

(在本例中,整个表是有序的,但这不是必需的)

这就是我想象的代码:

dt1 <- dt[,
          {
            # processing here, reorder somehow
            # ???
            # ...
            list(id=id, ltr=ltr, letters=paste0(ltr,collapse="_"))
          },
          by=group]

提前感谢任何想法!

UPD。如答案中所述,对于我的示例,我只需按group排序,然后按val排序。如果我需要做几个不同的排序?例如,我想按col5排序并添加col5diff列,这将显示col5值的差异:

#    id group val ltr col5 letters col5diff
# 1:  6     A  90   v  145     v_x        
# 2:  1     A  96   x  197     v_x       52
# 3: 10     B  96   c  121 k_f_p_c        
# 4:  9     B  33   f  129 k_f_p_c        8
# 5:  3     B  68   p  168 k_f_p_c       47
# 6:  7     B  25   k  172 k_f_p_c       51
# 7:  5     C  11   o  102 l_o_r_w        
# 8:  8     C   5   l  120 l_o_r_w       18
# 9:  4     C  58   w  177 l_o_r_w       75
#10:  2     C  46   r  190 l_o_r_w       88

好的,对于此示例,letterscol5diff的计算是独立的,因此我可以简单地连续执行:

setkey(dt, "group", "val")
dt[, letters := paste(ltr, collapse="_"), by = group]

setkey(dt, "group", "col5")
dt<-dt[, col5diff:={
  diff <- NA;
  for (i in 2:length(col5)) {diff <- c(diff, col5[i]-col5[1]);}
  diff; # updated to use := instead of list - thanks to comment of @Frank
}, by = group]

但如果我需要同时使用这两个排序(单{}块),我也很高兴知道该怎么办。

2 个答案:

答案 0 :(得分:2)

我认为你只是在寻找order

dt[, letters:=paste(ltr[order(val)], collapse="_"), by=group]
dt[order(group, val)]
#    id group val ltr col5 letters
# 1:  6     A  90   v  145     v_x
# 2:  1     A  96   x  197     v_x
# 3:  7     B  25   k  172 k_f_p_c
# 4:  9     B  33   f  129 k_f_p_c
# 5:  3     B  68   p  168 k_f_p_c
# 6: 10     B  96   c  121 k_f_p_c
# 7:  8     C   5   l  120 l_o_r_w
# 8:  5     C  11   o  102 l_o_r_w
# 9:  2     C  46   r  190 l_o_r_w
#10:  4     C  58   w  177 l_o_r_w

或者,如果您不想通过引用添加列:

dt[, list(id, val, ltr, letters=paste(ltr[order(val)], collapse="_")), 
     by=group][order(group, val)]
#    group id val ltr letters
# 1:     A  6  90   v     v_x
# 2:     A  1  96   x     v_x
# 3:     B  7  25   k k_f_p_c
# 4:     B  9  33   f k_f_p_c
# 5:     B  3  68   p k_f_p_c
# 6:     B 10  96   c k_f_p_c
# 7:     C  8   5   l l_o_r_w
# 8:     C  5  11   o l_o_r_w
# 9:     C  2  46   r l_o_r_w
#10:     C  4  58   w l_o_r_w

答案 1 :(得分:1)

除非我遗漏了某些内容,否则只需将key的{​​{1}}设置为data.tablegroup

val

您会看到值已自动排序。现在,您可以按setkey(dt, "group", "val") # id group val ltr col5 # 1: 6 A 90 v 145 # 2: 1 A 96 x 197 # 3: 7 B 25 k 172 # 4: 9 B 33 f 129 # 5: 3 B 68 p 168 # 6: 10 B 96 c 121 # 7: 8 C 5 l 120 # 8: 5 C 11 o 102 # 9: 2 C 46 r 190 # 10: 4 C 58 w 177

进行子集化
group