我想将标量函数(如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)
答案 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