高效合并多个共享相同键的数据表的dcast结果

3

我要解决的问题很简单:我有一个像下面这个表格的数据表,我试图使用dcast.data.table函数来计算每个组的晋升人数,并且我还想计算每个组成绩的中位数:

set.seed(10);
DT = data.table(GROUP = sample(c("a","b","c"),100,replace = T), 
                ADVANCED = sample(c("ADVANCED","DROP"),100,replace = T),
                GRADE = sample(1:10,100, replace=T))

     GROUP ADVANCED GRADE
  1:     b ADVANCED     3
  2:     a ADVANCED     6
  3:     b ADVANCED     7
  4:     c ADVANCED     9

 95:     b     DROP     6
 96:     c ADVANCED     5
 97:     a     DROP    10
 98:     b ADVANCED     1
 99:     c     DROP     6
100:     a     DROP     2
     GROUP ADVANCED GRADE

我需要的结果基本上是这样的:

result = merge(
  dcast.data.table(DT,.Primitive("~")(GROUP,ADVANCED)),
  dcast.data.table(DT,.Primitive("~")(GROUP,.),
                   value.var="GRADE", 
                   fun.aggregate=median));

setnames(result,".","MEDIAN_GRADE")

   GROUP ADVANCED DROP MEDIAN_GRADE
1:     a       17   19            6
2:     b       20   21            7
3:     c       13   10            6

现在我想知道如何在不制作两张单独的dcast表并在最后合并它们的情况下完成。我的表格中有许多行和列,按键分组是一个瓶颈。我想知道是否有更好的方法来计算这个问题?

**由于我的第一个问题比较模糊,我已经完全修改了它(感谢Frank和Akrun的反馈)。


在生成随机示例之前,您应该使用 set.seed - Frank
reshape2::dcast(DT, GROUP ~ ADVANCED, margins="ADVANCED"),但你将无法使用data.table::dcast中的改进。看起来margins从未被实现:https://github.com/Rdatatable/data.table/issues/1214 - Frank
我同意你的观点,请接受我的道歉。 - Mahdi Jadaliha
~rhs 在两个 dcast 中是不同的,因此无法在单个 dcast 中完成。我发布了一个带有 on 的选项。 - akrun
谢谢你的回答,使用 on 而不是 merge 让我的代码快了30%。 :) - Mahdi Jadaliha
显示剩余2条评论
2个回答

4

关于更新的问题

setnames(dcast(DT, GROUP~ADVANCED, length)[dcast(DT, GROUP~., median),
            on = "GROUP"], ".", "MEDIAN_GRADE")[]
#   GROUP ADVANCED DROP MEDIAN_GRADE
#1:     a       17   19            6
#2:     b       20   21            7
#3:     c       13   10            6

或者更快的方法是按'GROUP'分组,获取'GRADE'的中位数,然后将其与dcast输出的结果进行join

DT[,.(MEDIAN_GRADE = median(GRADE)) , .(GROUP)][
              dcast(DT, GROUP ~ ADVANCED, length), on = 'GROUP']

2
更一般地说,dcast(DT, GROUP ~ ADVANCED)[, SIZE := Reduce(\+`, .SD), .SDcols = unique(DT$ADVANCED)][]` - Frank
抱歉,我会在一分钟内修复它,并提供更详细的示例。 - Mahdi Jadaliha
1
是的,我认为使用on这种最终方法是最好的选择。 - Frank
1
谢谢@akrun,这个答案显著提高了我的代码性能。如果您删除第一个问题的答案以避免混淆,那就太好了。 :) - Mahdi Jadaliha
@MahdiJadaliha 好的,我已经将其删除。 - akrun
显示剩余5条评论

3

你可以先进行长形式计算,然后再进行重塑:

dcast(DT[, rbind(
  .SD[, .(v = .N), by=.(stat = paste0("n.",ADVANCED))],
  .(stat = "med", v = as.numeric(median(GRADE)))
), by=GROUP], GROUP ~ stat)

   GROUP med n.ADVANCED n.DROP
1:     a   6         17     19
2:     b   7         20     21
3:     c   6         13     10

显然,这仍然涉及大量手动调整。它还要求你的所有统计数据都是数字(因为它们在dcast之前堆叠在stat列中)。我认为@akrun答案中的方法 - 像DT[, f(...), by=GROUP][dcast(DT, GROUP ~ x), on=GROUP] - 更好,只将dcast限制在需要的调用中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接