通过另一列的总和对级别进行嵌套排序

时间:2017-09-11 07:26:31

标签: r data.table

我正在寻找一种更好的方法,通过另一列的总和来对组内的级别进行排序。

在每个密钥(例如样本数据中的K1)中,级别(例如,样本数据中的x, y)应按数字列的总和降序排序({{1在示例数据中)。更一般地说,我可能有N个键(即从K_1到K_N)。

除了首先执行聚合然后查找每个键的排名然后使用连接键对整个表进行排序之外,我想不出任何其他方式。

有没有更好的方法来使用base + data.table语法的一些组合,即更快或更短的方法来解决这个问题?

示例数据

size

期望的输出

library(data.table)

dat <- data.table(K1=c("x","x","y","y","y"), 
    K2=c("K","R","R","G","G"), 
    K3=1:5,
    size=c(1, 2.5, 4, 3.5, 1),
    key=c("K1","K2","K3"))

#   K1 K2 K3 size
#1:  x  K  1  1.0
#2:  x  R  2  2.5
#3:  y  G  4  3.5
#4:  y  G  5  1.0
#5:  y  R  3  4.0

使用示例数据的示例演练

对于K1,y的 K1 K2 K3 size y G 4 3.5 y G 5 1.0 y R 3 4.0 x R 2 2.5 x K 1 1.0 之和为8.5,大于x的size之和,因此y应该高于等级中的x。

在K1 = y内,G的size之和为4.5,大于R的size之和,即4.0,因此G应该在K1的等级中高于R = Y。

在K1 = y&amp; K2 = G,K3 = 4的size为3.5,大于K3 = 5的size 1.0,因此K3 = 4应高于K3 = 5。

到目前为止我尝试了什么(看起来很复杂)

size

测试案例2

dat[, rank:=""]
for (n in seq_along(key(dat))) {
    x <- key(dat)[seq_len(n)]

    #name of dummy column
    col <- last(paste0(x, "_rank"))

    #aggregate by desired key
    rankDT <- dat[, list(size=sum(as.numeric(size), na.rm=TRUE)), by=x]

    #rank the size column in descending order then left pad this rank to equal number of digits
    rankDT[,(col) := formatC(
        frank(-size, ties.method="first"), 
        width=ceiling(.N/10), 
        format="d", 
        flag="0")]

    #concatenate this rank to the existing list of rank
    dat[rankDT,
        rank := paste0(rank, get(col)),
        on=x]
}
dat[order(rank)]

测试用例2的所需输出

dat <- data.table(K1=c("x","x","y","y","y"), 
    K2=c("K","R","R","G","G"), 
    K3=1:5,
    size=c(1, 16, 4, 3.5, 10),
    key=c("K1","K2","K3"))

#   K1 K2 K3 size
#1:  x  K  1  1.0
#2:  x  R  2 16.0
#3:  y  G  4  3.5
#4:  y  G  5 10.0
#5:  y  R  3  4.0

尝试搜索&#34;递归排序&#34;,&#34;嵌套排序&#34;,&#34;组+汇总+排名&#34;。但是这些按字母顺序排序和/或按特定列排序,而不是基于另一列排序。

谢谢!

编辑:@Jaap启发的另一个较短的解决方案

   K1 K2 K3 size rank
    y  G  5 10.0  122
    y  G  4  3.5  124
    y  R  3  4.0  133
    x  R  2 16.0  211
    x  K  1  1.0  245

1 个答案:

答案 0 :(得分:1)

使用:

cols <- setdiff(key(dat), 'K3')

dat[, Ksum := sum(size), by = cols][]
setorderv(dat, c('Ksum', cols), order = -1)

你得到:

   K1 K2 K3 size Ksum
1:  y  G  4  3.5  4.5
2:  y  G  5  1.0  4.5
3:  y  R  3  4.0  4.0
4:  x  R  2  2.5  2.5
5:  x  K  1  1.0  1.0

这是做什么的:

  • cols <- key(dat)创建一个列名称向量。
  • dat[, Ksum := sum(size), by = cols]按分组列对值进行求和,并将其作为新变量Ksum添加到 data.table
  • setorderv(dat, c('Ksum', cols), order = -1)按降序(c('Ksum', cols))按一组列(包括总和列:order = -1)的引用重新排序 data.table

如果您不想保留Ksum - 列,可以使用dat[, Ksum := NULL]将其删除:

> dat[, Ksum := NULL][]
   K1 K2 K3 size
1:  y  G  4  3.5
2:  y  G  5  1.0
3:  y  R  3  4.0
4:  x  R  2  2.5
5:  x  K  1  1.0