R data.table中排除当前id的分组均值计算高效方案咨询
更高效的data.table解决方案:计算排除当前id的同condition均值
你的原方法虽然能得到正确结果,但在数据量较大时效率较低——因为每次分组都要全表筛选id!=ID & condition==CONDITION,相当于重复扫描整个数据集,时间复杂度为O(n*k)(k为分组数),内存开销也会随数据量增长而变大。
我们可以用代数推导替代逐组筛选,先计算每个condition的全局总和与样本量,再计算每个id在对应condition下的总和与样本量,最后用「(全局总和 - 当前id总和)/(全局样本量 - 当前id样本量)」得到目标均值。这种方法只需要两次分组聚合,时间复杂度为O(n),效率和内存友好度都远高于原方法。
原数据
DT <- data.table(id=c("A","A","B","B","C","C"),condition=c(1,2,1,2,1,2),value=c(0,1,1,3,2,2))
优化方案1:分步清晰版
# 1. 计算每个condition的全局总和与总样本数 DT[, `:=`(cond_total_sum = sum(value), cond_total_n = .N), by = condition] # 2. 计算每个id在对应condition下的总和与样本数 DT[, `:=`(id_cond_sum = sum(value), id_cond_n = .N), by = .(id, condition)] # 3. 计算目标均值 DT[, meanothers := (cond_total_sum - id_cond_sum)/(cond_total_n - id_cond_n)] # 可选:清理中间变量 DT[, c("cond_total_sum", "cond_total_n", "id_cond_sum", "id_cond_n") := NULL]
优化方案2:简洁嵌套版
如果不想保留中间变量,也可以用嵌套分组一步完成:
DT[, meanothers := { # 先拿到当前condition的全局统计量 cond_stats <- .SD[, .(sum_val = sum(value), n_val = .N), by = condition] # 拿到当前id在该condition下的统计量 id_stats <- .SD[, .(sum_id = sum(value), n_id = .N), by = .(id, condition)] # 合并后计算均值 merge(id_stats, cond_stats, on = "condition")[, (sum_val - sum_id)/(n_val - n_id)] }, by = condition]
结果验证
两种方案得到的meanothers列结果与原方法完全一致:
| id | condition | value | meanothers |
|---|---|---|---|
| A | 1 | 0 | 1.5 |
| A | 2 | 1 | 2.5 |
| B | 1 | 1 | 1.0 |
| B | 2 | 3 | 1.5 |
| C | 1 | 2 | 0.5 |
| C | 2 | 2 | 2.0 |
内容的提问来源于stack exchange,提问作者Jinglestar
相关产品推荐
相关产品推荐

