在 data.table R 中以编程方式将不同的函数应用于不同的列
Apply different functions to different columns programmatically in data.table R
我需要使用 data.table
以编程方式将不同的函数应用于不同的列和分组依据。
如果已知列和函数,我会这样做:
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3))
DT
#> id v1 v2
#> 1: a 2 5
#> 2: a 2 5
#> 3: a 2 5
#> 4: b 3 10
#> 5: b 3 10
#> 6: b 3 10
#> 7: c 4 15
#> 8: c 4 15
#> 9: c 4 15
DT[, .(v1=mean(v1), v2=sum(v2)), keyby=.(id)]
#> id v1 v2
#> 1: a 2 15
#> 2: b 3 30
#> 3: c 4 45
但我想通过传递列名及其特定功能来实现:
aggregate_functions = list(v1=mean, v2=sum)
col_selection = c('v1', 'v2')
我写了这样的东西,因为我想不出将列名传递给 lapply
:
的方法
DT[, lapply(.SD,
aggregate_functions[[col_name]] # some way of selecting the right function from aggregate_functions
),
.SDcols = col_selection,
by=id]
我也尝试过 melt
和 dcast
,但后者将所有函数应用于所有列:
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3))
DTm = melt(DT, meaure.vars=col_selection, id.vars='id')
DTm
#> id variable value
#> 1: a v1 2
#> 2: a v1 2
#> 3: a v1 2
#> 4: b v1 3
#> 5: b v1 3
#> 6: b v1 3
#> 7: c v1 4
#> 8: c v1 4
#> 9: c v1 4
#> 10: a v2 5
#> 11: a v2 5
#> 12: a v2 5
#> 13: b v2 10
#> 14: b v2 10
#> 15: b v2 10
#> 16: c v2 15
#> 17: c v2 15
#> 18: c v2 15
DTc = dcast(DTm, id~variable, fun.aggregate=list(sum, mean))
DTc
#> id value_sum_v1 value_sum_v2 value_mean_v1 value_mean_v2
#> 1: a 6 15 2 5
#> 2: b 9 30 3 10
#> 3: c 12 45 4 15
我可以通过编程方式 select 并重命名相关列(在本例中为 3 和 4),但这看起来不是一种有效的方法。
当然我可以有一个循环来完成这项工作并合并结果,但我正在寻找一种 data.table
方式。
感谢您的回答并感谢 data.table
的团队。
由 reprex package (v0.3.0)
于 2019-11-26 创建
在我发布问题后,link 到 answer by @Uwe 出现在包含我要查找的结果的右侧框中。我对其进行了调整以匹配我的示例:
library(magrittr)
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3))
aggregate_functions = list(v1='mean', v2='sum')
col_selection = c('v1', 'v2')
aggregate_functions %>%
names() %>%
lapply(
function(col_selection) lapply(
aggregate_functions[[col_selection]],
function(.fct) sprintf("%s = %s(%s)", col_selection, .fct, col_selection))) %>%
unlist() %>%
paste(collapse = ", ") %>%
sprintf("DT[, .(%s), by = id]", .) %>%
parse(text = .) %>%
eval()
#> id v1 v2
#> 1: a 2 15
#> 2: b 3 30
#> 3: c 4 45
我仍然对 'all in data.table
' 解决方案感兴趣。
由 reprex package (v0.3.0)
于 2019-11-26 创建
一个选项是使用 mapply
:
DT[, mapply(function(f,x) as.list(f(x)), aggregate_functions, .SD), id,
.SDcols=col_selection]
需要注意 col_selection
和 aggregate_functions
的顺序,以便将正确的函数应用于正确的列。
输出:
id v1 v2
1: a 2 15
2: b 3 30
3: c 4 45
从 OP 编辑:
只是为了完成这个绝妙的解决方案。
此解决方案非常有效,如果我们将 col_selection
替换为 names(aggregate_functions)
,则排序没有问题。另外它会自动丢弃所有不在列表中的列:
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3),
id2 = c(rep(c('cc', 'dd'), 4), 'dd')
)
aggregate_functions = list(v1=mean, v2=sum)
DT[, mapply(function(f,x) as.list(f(x)), aggregate_functions, .SD), id,
.SDcols=names(aggregate_functions)]
#> id v1 v2
#> 1: a 2 15
#> 2: b 3 30
#> 3: c 4 45
也可以通过传递列表来使用多个变量进行聚合:
DT[, mapply(function(f,x) as.list(f(x)), aggregate_functions, .SD), list(id, id2),
.SDcols=names(aggregate_functions)]
#> id id2 v1 v2
#> 1: a cc 2 10
#> 2: a dd 2 5
#> 3: b dd 3 20
#> 4: b cc 3 10
#> 5: c cc 4 15
#> 6: c dd 4 30
由 reprex package (v0.3.0)
于 2019-11-27 创建
我需要使用 data.table
以编程方式将不同的函数应用于不同的列和分组依据。
如果已知列和函数,我会这样做:
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3))
DT
#> id v1 v2
#> 1: a 2 5
#> 2: a 2 5
#> 3: a 2 5
#> 4: b 3 10
#> 5: b 3 10
#> 6: b 3 10
#> 7: c 4 15
#> 8: c 4 15
#> 9: c 4 15
DT[, .(v1=mean(v1), v2=sum(v2)), keyby=.(id)]
#> id v1 v2
#> 1: a 2 15
#> 2: b 3 30
#> 3: c 4 45
但我想通过传递列名及其特定功能来实现:
aggregate_functions = list(v1=mean, v2=sum)
col_selection = c('v1', 'v2')
我写了这样的东西,因为我想不出将列名传递给 lapply
:
DT[, lapply(.SD,
aggregate_functions[[col_name]] # some way of selecting the right function from aggregate_functions
),
.SDcols = col_selection,
by=id]
我也尝试过 melt
和 dcast
,但后者将所有函数应用于所有列:
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3))
DTm = melt(DT, meaure.vars=col_selection, id.vars='id')
DTm
#> id variable value
#> 1: a v1 2
#> 2: a v1 2
#> 3: a v1 2
#> 4: b v1 3
#> 5: b v1 3
#> 6: b v1 3
#> 7: c v1 4
#> 8: c v1 4
#> 9: c v1 4
#> 10: a v2 5
#> 11: a v2 5
#> 12: a v2 5
#> 13: b v2 10
#> 14: b v2 10
#> 15: b v2 10
#> 16: c v2 15
#> 17: c v2 15
#> 18: c v2 15
DTc = dcast(DTm, id~variable, fun.aggregate=list(sum, mean))
DTc
#> id value_sum_v1 value_sum_v2 value_mean_v1 value_mean_v2
#> 1: a 6 15 2 5
#> 2: b 9 30 3 10
#> 3: c 12 45 4 15
我可以通过编程方式 select 并重命名相关列(在本例中为 3 和 4),但这看起来不是一种有效的方法。
当然我可以有一个循环来完成这项工作并合并结果,但我正在寻找一种 data.table
方式。
感谢您的回答并感谢 data.table
的团队。
由 reprex package (v0.3.0)
于 2019-11-26 创建在我发布问题后,link 到
library(magrittr)
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3))
aggregate_functions = list(v1='mean', v2='sum')
col_selection = c('v1', 'v2')
aggregate_functions %>%
names() %>%
lapply(
function(col_selection) lapply(
aggregate_functions[[col_selection]],
function(.fct) sprintf("%s = %s(%s)", col_selection, .fct, col_selection))) %>%
unlist() %>%
paste(collapse = ", ") %>%
sprintf("DT[, .(%s), by = id]", .) %>%
parse(text = .) %>%
eval()
#> id v1 v2
#> 1: a 2 15
#> 2: b 3 30
#> 3: c 4 45
我仍然对 'all in data.table
' 解决方案感兴趣。
由 reprex package (v0.3.0)
于 2019-11-26 创建一个选项是使用 mapply
:
DT[, mapply(function(f,x) as.list(f(x)), aggregate_functions, .SD), id,
.SDcols=col_selection]
需要注意 col_selection
和 aggregate_functions
的顺序,以便将正确的函数应用于正确的列。
输出:
id v1 v2
1: a 2 15
2: b 3 30
3: c 4 45
从 OP 编辑:
只是为了完成这个绝妙的解决方案。
此解决方案非常有效,如果我们将 col_selection
替换为 names(aggregate_functions)
,则排序没有问题。另外它会自动丢弃所有不在列表中的列:
library(data.table)
DT = data.table(id = rep(letters[1:3], each=3),
v1 = rep(c(2, 3, 4), each=3),
v2 = rep(c(5, 10, 15), each=3),
id2 = c(rep(c('cc', 'dd'), 4), 'dd')
)
aggregate_functions = list(v1=mean, v2=sum)
DT[, mapply(function(f,x) as.list(f(x)), aggregate_functions, .SD), id,
.SDcols=names(aggregate_functions)]
#> id v1 v2
#> 1: a 2 15
#> 2: b 3 30
#> 3: c 4 45
也可以通过传递列表来使用多个变量进行聚合:
DT[, mapply(function(f,x) as.list(f(x)), aggregate_functions, .SD), list(id, id2),
.SDcols=names(aggregate_functions)]
#> id id2 v1 v2
#> 1: a cc 2 10
#> 2: a dd 2 5
#> 3: b dd 3 20
#> 4: b cc 3 10
#> 5: c cc 4 15
#> 6: c dd 4 30
由 reprex package (v0.3.0)
于 2019-11-27 创建