有效地组合多个 dcast data.table(共享相同的密钥)
Combine several dcast data.table (which share same key) efficiently
这是我要解决的简单问题:我有一个 data.table,就像下面的 table,我正在尝试使用 dcast.data.table
函数来计算每个组的进步,但我也有兴趣计算每个组的 median
成绩:
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 table 并在最后合并的情况下做到这一点。我在 table 中处理许多行和列,按键分组是一个瓶颈。我想知道有没有更好的方法来计算这个?
** 因为我的第一个问题含糊不清,所以我完全编辑了(感谢 Frank 和 Akrun 的反馈)。
更新后的问题
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' 的 median
,然后加入 on
和 dcast
输出
DT[,.(MEDIAN_GRADE = median(GRADE)) , .(GROUP)][
dcast(DT, GROUP ~ ADVANCED, length), on = 'GROUP']
好吧,你可以用长格式计算然后重塑:
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
限制为仅那些需要它的调用。
这是我要解决的简单问题:我有一个 data.table,就像下面的 table,我正在尝试使用 dcast.data.table
函数来计算每个组的进步,但我也有兴趣计算每个组的 median
成绩:
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 table 并在最后合并的情况下做到这一点。我在 table 中处理许多行和列,按键分组是一个瓶颈。我想知道有没有更好的方法来计算这个?
** 因为我的第一个问题含糊不清,所以我完全编辑了(感谢 Frank 和 Akrun 的反馈)。
更新后的问题
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' 的 median
,然后加入 on
和 dcast
输出
DT[,.(MEDIAN_GRADE = median(GRADE)) , .(GROUP)][
dcast(DT, GROUP ~ ADVANCED, length), on = 'GROUP']
好吧,你可以用长格式计算然后重塑:
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
限制为仅那些需要它的调用。