R data.table如何快速计算各树木对应指定物种更大个体的size总和
实现思路
你需要的跨物种计算本质是对任意给定的尺寸X,提前预计算好每个物种中大于X的尺寸总和,再把预计算结果匹配回原数据集即可,完全不需要逐行循环:
- 提前为每个物种生成「尺寸-对应更大尺寸总和」的查找表
- 用data.table的滚动联接能力,把查找表的结果批量匹配回原数据集的每一行
因为你只有4个物种,不管总数据量多大,整个过程都是向量化运算,性能极高。
完整实现代码
library(data.table) # 构造原始示例数据 DT <- data.table(id=c("a","b","c","d","e","f","g","h","i"), species=c(1,1,1,2,2,2,3,3,3), size=(1:9)) # 步骤1:获取所有唯一物种 all_sp <- unique(DT$species) # 步骤2:为每个物种生成查找表 sp_lookup <- lapply(all_sp, function(sp) { # 提取当前物种数据,按尺寸分组聚合(处理重复尺寸场景),按尺寸升序排列 sp_dt <- DT[species == sp, .(sum_size = sum(size)), by = size][order(size)] # 计算大于当前尺寸的总大小:物种总尺寸减去累积到当前的尺寸和 sp_dt[, larger_sum := sum(sum_size) - cumsum(sum_size)] return(sp_dt[, .(size, larger_sum)]) }) names(sp_lookup) <- paste0("sp", all_sp) # 步骤3:将查找表结果匹配回原数据集 for (sp_name in names(sp_lookup)) { lookup_dt <- sp_lookup[[sp_name]] col_name <- paste0("size_larger_", sp_name) # 滚动联接匹配最近的小于等于当前尺寸的记录,提取对应总和 DT[, (col_name) := lookup_dt[DT, on = .(size), roll = TRUE, x.larger_sum]] # 处理所有该物种尺寸都大于当前行的场景,替换为该物种总尺寸 total_sp_size <- sum(DT[species == as.integer(gsub("sp", "", sp_name))]$size) DT[is.na(get(col_name)), (col_name) := total_sp_size] }
结果验证
运行后输出DT,你可以看到和你手动计算的size_larger_sp2完全一致:
> DT id species size size_larger_sp1 size_larger_sp2 size_larger_sp3 1: a 1 1 5 15 24 2: b 1 2 3 15 24 3: c 1 3 0 15 24 4: d 2 4 0 11 24 5: e 2 5 0 6 24 6: f 2 6 0 0 24 7: g 3 7 0 0 17 8: h 3 8 0 0 9 9: i 3 9 0 0 0
性能说明
该方案时间复杂度为O(N + K*M log M),其中N是总数据量,K是物种数量(你的场景是4),M是每个物种的唯一尺寸数量。10万行规模的数据运行时间不会超过1秒,完全满足业务需求。
内容的提问来源于stack exchange,提问作者Simone Bianchi
相关产品推荐
相关产品推荐

