重新排序并将附加列附加到.SD输出

时间:2017-03-02 03:51:29

标签: r data.table

我想将标量函数(如mean)应用于主要组,并对次要组中的值进行排名。这是我尝试做的示例代码:

library(data.table)
mytestdata <- data.table(name=c("tom","john","tom","john","jim","jim","jack"),
                         len=c(10,15,12,23,3,12,3),
                         group=c("a","b","a","a","a","b","b"))
mytestdata[, .SD[, .(mean(len), .N), by="name"][order(V1)], by = "group"]  # I need the .N to log

这里的输出是我想要的。但是,当我尝试对每个组中的名称进行排名时,我无法获得所需的输出。

mytestdata[, .SD[, .(mean(len), .N), by="name"][order(V1), myrank := seq(1:.N)], by = "group"]

上面的代码正确地分配了排名,但是将列重新排序为默认排序(忽略order(V1),这在前一行中有效)。我认为这与:=不显示输出有关。有办法解决这个问题吗?

我试过像

这样的东西
mytestdata[, .(.SD[, .(mean(len), .N), by="name"][order(V1)], seq(1:.N), by = "group"]

但它在list()中使用j方法的错误使用会引发错误。

编辑:我想要的输出是(排名应该在组内)(A)

   group name V1 N myrank
1:     a  jim  3 1    1
2:     a  tom 11 2    2
3:     a john 23 1    3
4:     b jack  3 1    1
5:     b  jim 12 1    2
6:     b john 15 1    3

编辑:为了澄清我的观点,我的原始代码

mytestdata[, .SD[, .(mean(len), .N), by="name"][order(V1)], by = "group"]

返回按照我喜欢的方式排序的数据表,即(1)

   group name V1 N
1:     a  jim  3 1
2:     a  tom 11 2
3:     a john 23 1
4:     b jack  3 1
5:     b  jim 12 1
6:     b john 15 1

现在,我想保持这种排序,并为每个组中的名称分配排名。由于i在data.table中的j之前进行了评估,因此我可以在与上面order()相同的语句中分配排名,即

mytestdata[, .SD[, .(mean(len), .N), by="name"][order(V1), myrank := 1:.N], by = "group"]

这正确地指定等级,即(2)

   group name V1 N myrank
1:     a  tom 11 2      2
2:     a john 23 1      3
3:     a  jim  3 1      1
4:     b john 15 1      3
5:     b  jim 12 1      2
6:     b jack  3 1      1

然而,行的排序不再与(1)中的顺序相同,因为我的猜测是,赋值运算符抑制输出并以无序格式存储数据表。现在,为了以(A)的形式获得输出,我必须通过再次分组来重新排序行在链接方法中分配排名列,即,

mytestdata[, .SD[, .(mean(len), .N), by="name"][order(V1), myrank := 1:.N], by = "group"][order(rank), .SD, by = "group"]

(OR)

mytestdata[, .SD[, .(mean(len), .N), by="name"][order(V1)], by = "group"][, myrank := 1:.N, by = "group"]

这会得到所需的输出(A)。虽然这两个都解决了我的问题,但我很好奇是否有一个解决方案可以消除额外的链接,因为在(2)中正确分配了排名,并且在(1)

1 个答案:

答案 0 :(得分:1)

我认为您遇到处理[.data.table的i和j参数的顺序问题;

这就是我认为你想要的,尽管你实际上只提供了你不想要的细节:

mytestdata[, .SD[, .(mean(len), .N), by="name"]][order(V1),][,rank := rank(V1)][]
   name   V1 N rank
1: jack  3.0 1    1
2:  jim  7.5 2    2
3:  tom 11.0 2    3
4: john 19.0 2    4

当问题出现时,我搜索了:

> ?rank   # Turns out there is a data.table function for that as well, `frank`

> mytestdata[, .SD[, .(mean(len), .N), by="name"]][order(V1),][,rank := frank(V1)][]
   name   V1 N rank
1: jack  3.0 1    1
2:  jim  7.5 2    2
3:  tom 11.0 2    3
4: john 19.0 2    4

单独应用排序(第一)和计算排名(后来)似乎是需要的。如果你想要一种不同的计算排名的方法,那么坦率的函数有:ties.method=c("average", "first", "random", "max", "min", "dense"),终端[]的使用是我刚刚从@thelatemail学到的东西。最后评论。我会使列名更“特别”。使用像“rank”这样的列的名称会混淆习惯于将其视为函数名称的用户。最好把它变成“myrank”或“testrank”。

回应下面的评论:我仍然难以理解究竟想要什么(特别是不想要“最后额外分组”是什么意思)但如果希望根据“新”排名重新排序那么为什么不:

 mytestdata[, .SD[, .(mean(len), .N), by=name][order(V1)], by=group][ #
                       , myrank := frank(V1), by=group][order(myrank), ]
   group name V1 N myrank
1:     a  jim  3 1      1
2:     b jack  3 1      1
3:     a  tom 11 2      2
4:     b  jim 12 1      2
5:     a john 23 1      3
6:     b john 15 1      3