如何修改data.table列对分组计算代码以支持任意自定义函数
解决方案:用自定义函数替代sum并支持任意函数
首先,咱们得先理清原始数据处理后的结构:经过之前的merge操作,d里每个time+i分组对应两行数据——分别是一对列(比如a-b)的两个值。而你的自定义函数fun1需要接收两个独立的参数x和y,不是对一组值求和,所以直接在dcast里替换sum是行不通的,得先把每组的两个值拆分开,再传递给自定义函数。
步骤1:拆分每组的两个值为x和y
先在d中按time和i分组,把每组的第一个value设为x,第二个设为y:
library(data.table) # 你的原始数据处理代码 d = data.table(time = c(1,1,2,2), a = c(1,2,3,4), b =c(4,3,2,1), c = c(1,1,1,1)) pairs = d[, data.table(t(combn(names(.SD), 2))), by = time] pairs$i = 1:nrow(pairs) pairs = melt(pairs, id.vars = c('time', 'i'), value.name = 'firm') d = melt(d, id.vars = 'time', variable.name = 'firm') d = merge(pairs, d) # 拆分每组的value为x和y d[, c("x", "y") := .(value[1], value[2]), by = .(time, i)]
步骤2:应用自定义函数并整理结果
接下来就可以分组计算自定义函数的结果,同时保留配对列的名称:
# 自定义函数 fun1<- function(x,y, na.rm = FALSE) 1 - 0.5*sum(abs(x-y)) # 计算结果 result = d[, .( pair = paste(unique(firm), collapse = "_"), # 保留列对名称 fun_result = fun1(x, y) # 应用自定义函数 ), by = .(time, i)]
运行后你会得到这样的结果:
time i pair fun_result 1: 1 1 a_b -0.5 2: 1 2 a_c 0.0 3: 1 3 b_c -1.5 4: 2 4 a_b -0.5 5: 2 5 a_c 0.0 6: 2 6 b_c 0.5
扩展:支持任意自定义函数
如果想快速切换不同的自定义函数,可以封装成一个通用函数,还能支持传递额外参数:
apply_pair_fun = function(data, custom_fun, ...) { # 拆分x和y data[, c("x", "y") := .(value[1], value[2]), by = .(time, i)] # 应用自定义函数,支持额外参数(比如na.rm) result = data[, .( pair = paste(unique(firm), collapse = "_"), fun_result = custom_fun(x, y, ...) ), by = .(time, i)] return(result) } # 示例:用fun1并传入na.rm参数 result = apply_pair_fun(d, fun1, na.rm = TRUE) # 再比如用另一个自定义函数测试 fun2 <- function(x, y) x^2 + y^2 result2 = apply_pair_fun(d, fun2)
为什么不用dcast?
原来的dcast写法里,sum是对分组内所有value值求和,但你的自定义函数需要两个独立的输入(一对列的两个值),所以必须先把每组的两个值拆成x和y,再传递给函数,这种分组处理的方式比dcast更灵活,能适配任意需要双参数的自定义函数。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

