在data.table中使用dplyr/across速度慢,求兼顾速度与便捷的方案
问题:兼顾dplyr便捷性与data.table性能的分组汇总方法
使用dplyr的across()函数按字符型变量分组、汇总数值型变量时,无需手动指定变量名,非常便捷。但如果把这套逻辑用在data.table对象上,运行速度会明显变慢,和操作普通data.frame差不多。有没有办法既能保留这种自动识别变量的便捷性,又不损失data.table的高性能?
原代码示例:
library(data.table) library(dplyr) test_data <- data.table(x=c('a','b','c','a','b','c'),y=c('d','e','f','d','e','f'),a=c(1:6),b=c(1,7,NA,3,5,6),c=c(NA,3,NA,4,7,8)) test_data %>% group_by(across(where(is.character))) %>% summarise(across(where(is.number),function(x) sum(x,na.rm=TRUE)))
方案1:data.table原生语法+自动变量筛选
先自动识别并提取分组变量(字符型)和汇总变量(数值型),再用data.table原生语法执行,既不用手动写变量名,又能发挥data.table的性能优势。
代码示例:
library(data.table) test_data <- data.table(x=c('a','b','c','a','b','c'),y=c('d','e','f','d','e','f'),a=c(1:6),b=c(1,7,NA,3,5,6),c=c(NA,3,NA,4,7,8)) # 自动筛选分组变量和汇总变量 group_vars <- names(test_data)[sapply(test_data, is.character)] sum_vars <- names(test_data)[sapply(test_data, is.numeric)] # data.table原生分组汇总 test_data[, lapply(.SD, sum, na.rm = TRUE), by = group_vars, .SDcols = sum_vars]
方案2:用dtplyr适配dplyr语法到data.table
dtplyr是dplyr的data.table适配器,允许你写熟悉的dplyr风格代码,底层会自动转换成data.table原生语法执行,兼顾便捷性和性能。
代码示例:
library(data.table) library(dtplyr) library(dplyr, warn.conflicts = FALSE) test_data <- data.table(x=c('a','b','c','a','b','c'),y=c('d','e','f','d','e','f'),a=c(1:6),b=c(1,7,NA,3,5,6),c=c(NA,3,NA,4,7,8)) # 用lazy_dt包装后使用dplyr语法 test_data %>% lazy_dt() %>% group_by(across(where(is.character))) %>% summarise(across(where(is.numeric), ~sum(.x, na.rm = TRUE))) %>% as.data.table()
方案3:封装自定义函数简化重复操作
如果需要频繁执行这类分组汇总,可以把变量筛选和data.table操作封装成函数,调用时一步到位:
代码示例:
library(data.table) # 自定义分组汇总函数 sum_by_char_groups <- function(dt) { group_vars <- names(dt)[sapply(dt, is.character)] sum_vars <- names(dt)[sapply(dt, is.numeric)] return(dt[, lapply(.SD, sum, na.rm = TRUE), by = group_vars, .SDcols = sum_vars]) } # 调用函数 test_data <- data.table(x=c('a','b','c','a','b','c'),y=c('d','e','f','d','e','f'),a=c(1:6),b=c(1,7,NA,3,5,6),c=c(NA,3,NA,4,7,8)) sum_by_char_groups(test_data)
内容的提问来源于stack exchange,提问作者anderwyang
相关产品推荐
相关产品推荐

