C8H*_*4O2 6 r difference data.table
如何使用data.table语法生成data.table,其中每列包含原始data.table列与下一列之间的差异?
示例:我有一个data.table,其中每一行都是一个组,每一列都是在第0年之后,第1年,第2年之后存活的人口等.例如:
pop <- data.table(group_id = c(1, 2, 3),
N = c(4588L, 4589L, 4589L),
N_surv_1 = c(4213, 4243, 4264),
N_surv_2 = c(3703, 3766, 3820),
N_surv_3 = c(2953, 3054, 3159) )
# group_id N N_surv_1 N_surv_2 N_surv_3
# 1 4588 4213 3703 2953
# 2 4589 4243 3766 3054
# 3 4589 4264 3820 3159
Run Code Online (Sandbox Code Playgroud)
(数据类型不同,因为N是一个真正的整数计数,N_surv_1等是可能是小数的投影.)
我做了什么:使用基数diff和矩阵换位,我们可以:
diff <- data.table(t(diff(t(as.matrix(pop[,-1,with=FALSE])))))
setnames(diff, paste0("deaths_",1:ncol(diff)))
cbind(group_id = pop[,group_id],diff)
# produces desired output:
# group_id deaths_1 deaths_2 deaths_3
# 1 -375 -510 -750
# 2 -346 -477 -712
# 3 -325 -444 -661
Run Code Online (Sandbox Code Playgroud)
我知道我可以diff在由单个列生成的基础上逐个使用melt.data.table,所以这可行但不漂亮:
melt(pop,
id.vars = "group_id"
)[order(group_id)][, setNames(as.list(diff(value)),
paste0("deaths_",1:(ncol(pop)-2)) ),
keyby = group_id]
Run Code Online (Sandbox Code Playgroud)
这是最实现这一目标的data.table-riffic方法,还是有办法将其作为data.table中的多列操作?
好吧,你可以减去子集:
ncols = grep("^N(_surv_[0-9]+)?", names(pop), value=TRUE)
pop[, Map(
`-`,
utils:::tail.default(.SD, -1),
utils:::head.default(.SD, -1)
), .SDcols=ncols]
# N_surv_1 N_surv_2 N_surv_3
# 1: -375 -510 -750
# 2: -346 -477 -712
# 3: -325 -444 -661
Run Code Online (Sandbox Code Playgroud)
您可以使用以下方法将这些值分配给新列:=.我不知道为什么tail并且head没有更容易获得......正如@akrun所指出的,你可以使用with=FALSE,比如pop[, .SD[, -1, with=FALSE] - .SD[, -ncol(.SD), with=FALSE], .SDcols=ncols].
无论如何,与简单重塑相比,这是非常复杂的:
melt(pop, id="group_id")[, tail(value, -1) - head(value, -1), by=group_id]
# group_id V1
# 1: 1 -375
# 2: 1 -510
# 3: 1 -750
# 4: 2 -346
# 5: 2 -477
# 6: 2 -712
# 7: 3 -325
# 8: 3 -444
# 9: 3 -661
Run Code Online (Sandbox Code Playgroud)