是否可以对聚合的 dcast 值进行操作?
Is it possible to operate on the aggregated dcast values?
dcast.data.table 具有聚合多个 value.var 的功能。是否可以以某种方式引用正在创建的聚合值,然后在乐趣中执行操作?
这将创建 4 个变量
DT = data.table(x=sample(5,20,TRUE), y=sample(2,20,TRUE),
z=sample(letters[1:2], 20,TRUE), d1 = runif(20), d2=1L)
> head(DT)
x y z d1 d2
1: 3 2 a 0.6166590 1
2: 3 1 a 0.1891611 1
3: 5 2 a 0.3061658 1
4: 3 1 a 0.7233832 1
5: 2 1 b 0.6799675 1
6: 2 1 b 0.5144392 1
dcast(DT, x + y ~ z, fun=sum, value.var=c("d1", "d2"))
x y d1_a d1_b d2_a d2_b
1: 1 1 1.0400277 0.3835004 2 1
2: 2 1 0.7032111 1.3713884 1 2
3: 3 1 0.9759893 2.0853103 1 3
4: 3 2 0.5210792 0.0000000 1 0
5: 4 1 1.0971931 0.4417819 2 1
6: 4 2 0.5009533 0.0000000 1 0
7: 5 1 0.9372943 0.0000000 4 0
8: 5 2 0.7671728 0.0000000 1 0
并且可以在第二步中对聚合值进行操作
dcast(DT, x + y ~ z, fun=sum, value.var=c("d1", "d2"))[,.(div1 = d1_a/d2_a
,div2 = d1_b/d2_b)]
div1 div2
1: 0.5200139 0.3835004
2: 0.7032111 0.6856942
3: 0.9759893 0.6951034
4: 0.5210792 NaN
5: 0.5485965 0.4417819
6: 0.5009533 NaN
7: 0.2343236 NaN
8: 0.7671728 NaN
这个有点绕,
但对于这个问题,我认为你可以做以下事情:
zs <- unique(DT$z)
sum_div <- function(dt) {
ans <- dt[, .(div = sum(d1) / sum(d2)), by = .(z)]
split(ans$div, factor(ans$z, levels = zs), drop = FALSE)
}
DT[, sum_div(.SD), by = .(x, y), .SDcols = c("z", "d1", "d2")]
发生的事情是 .SD
最终具有 .SDcols
中指定的 3 列,
但对于 x
和 y
值的可能组合具有不同的子集。
然后,sum_div
仅对该子集执行所需的操作,
并且 split
将结果发送到 return 列表,以便 z
的每个可能值在最终的 data.table
.
中都有自己的列
为了每次都获得相同数量的列表元素,执行factor(ans$z, levels = zs)
很重要
(data.table
预计);
通过指定我们期望的 levels
数量,
如果 level
没有值,split
将 return 一个空向量,
但它肯定会 return 每个人都有一些东西。
请注意,您可以通过以下方式实现相同的效果:
dcast(DT[, .(div = sum(d1) / sum(d2)), by = .(x, y, z)], x + y ~ z, value.var = "div")
我不确定一步完成所有操作是否会获得可观的性能。
编辑:你可能没有:
library(data.table)
library(microbenchmark)
n <- 2e5
DT = data.table(x = sample(5L, n, TRUE),
y = sample(3L, n, TRUE),
z = sample(letters[1:2], n, TRUE),
d1 = runif(n),
d2 = 1L)
zs <- sort(unique(DT$z))
sum_div <- function(dt) {
ans <- dt[, .(div = sum(d1) / sum(d2)), by = .(z)]
split(ans$div, factor(ans$z, levels = zs), drop = FALSE)
}
microbenchmark(
one = DT[, sum_div(.SD), keyby = .(x, y), .SDcols = c("z", "d1", "d2")],
two = dcast(DT[, .(div = sum(d1) / sum(d2)), by = .(x, y, z)], x + y ~ z, value.var = "div"),
times = 10L
)
Unit: milliseconds
expr min lq mean median uq max neval
one 24.37323 25.74273 26.72413 25.99279 26.62943 34.40309 10
two 11.31050 11.91650 12.66345 12.51094 13.01364 15.35549 10
dcast.data.table 具有聚合多个 value.var 的功能。是否可以以某种方式引用正在创建的聚合值,然后在乐趣中执行操作?
这将创建 4 个变量
DT = data.table(x=sample(5,20,TRUE), y=sample(2,20,TRUE),
z=sample(letters[1:2], 20,TRUE), d1 = runif(20), d2=1L)
> head(DT)
x y z d1 d2
1: 3 2 a 0.6166590 1
2: 3 1 a 0.1891611 1
3: 5 2 a 0.3061658 1
4: 3 1 a 0.7233832 1
5: 2 1 b 0.6799675 1
6: 2 1 b 0.5144392 1
dcast(DT, x + y ~ z, fun=sum, value.var=c("d1", "d2"))
x y d1_a d1_b d2_a d2_b
1: 1 1 1.0400277 0.3835004 2 1
2: 2 1 0.7032111 1.3713884 1 2
3: 3 1 0.9759893 2.0853103 1 3
4: 3 2 0.5210792 0.0000000 1 0
5: 4 1 1.0971931 0.4417819 2 1
6: 4 2 0.5009533 0.0000000 1 0
7: 5 1 0.9372943 0.0000000 4 0
8: 5 2 0.7671728 0.0000000 1 0
并且可以在第二步中对聚合值进行操作
dcast(DT, x + y ~ z, fun=sum, value.var=c("d1", "d2"))[,.(div1 = d1_a/d2_a
,div2 = d1_b/d2_b)]
div1 div2
1: 0.5200139 0.3835004
2: 0.7032111 0.6856942
3: 0.9759893 0.6951034
4: 0.5210792 NaN
5: 0.5485965 0.4417819
6: 0.5009533 NaN
7: 0.2343236 NaN
8: 0.7671728 NaN
这个有点绕, 但对于这个问题,我认为你可以做以下事情:
zs <- unique(DT$z)
sum_div <- function(dt) {
ans <- dt[, .(div = sum(d1) / sum(d2)), by = .(z)]
split(ans$div, factor(ans$z, levels = zs), drop = FALSE)
}
DT[, sum_div(.SD), by = .(x, y), .SDcols = c("z", "d1", "d2")]
发生的事情是 .SD
最终具有 .SDcols
中指定的 3 列,
但对于 x
和 y
值的可能组合具有不同的子集。
然后,sum_div
仅对该子集执行所需的操作,
并且 split
将结果发送到 return 列表,以便 z
的每个可能值在最终的 data.table
.
为了每次都获得相同数量的列表元素,执行factor(ans$z, levels = zs)
很重要
(data.table
预计);
通过指定我们期望的 levels
数量,
如果 level
没有值,split
将 return 一个空向量,
但它肯定会 return 每个人都有一些东西。
请注意,您可以通过以下方式实现相同的效果:
dcast(DT[, .(div = sum(d1) / sum(d2)), by = .(x, y, z)], x + y ~ z, value.var = "div")
我不确定一步完成所有操作是否会获得可观的性能。
编辑:你可能没有:
library(data.table)
library(microbenchmark)
n <- 2e5
DT = data.table(x = sample(5L, n, TRUE),
y = sample(3L, n, TRUE),
z = sample(letters[1:2], n, TRUE),
d1 = runif(n),
d2 = 1L)
zs <- sort(unique(DT$z))
sum_div <- function(dt) {
ans <- dt[, .(div = sum(d1) / sum(d2)), by = .(z)]
split(ans$div, factor(ans$z, levels = zs), drop = FALSE)
}
microbenchmark(
one = DT[, sum_div(.SD), keyby = .(x, y), .SDcols = c("z", "d1", "d2")],
two = dcast(DT[, .(div = sum(d1) / sum(d2)), by = .(x, y, z)], x + y ~ z, value.var = "div"),
times = 10L
)
Unit: milliseconds
expr min lq mean median uq max neval
one 24.37323 25.74273 26.72413 25.99279 26.62943 34.40309 10
two 11.31050 11.91650 12.66345 12.51094 13.01364 15.35549 10