寻找比ddply按分组聚合变量更高效的实现方案
解决方案
原代码性能极差的核心原因是ddply属于plyr包的旧版分组函数,处理大数据时会产生大量临时数据副本,内存开销极高。你已经将数据转为data.table对象,直接使用data.table原生的分组赋值语法即可实现相同逻辑,全程原地操作无额外拷贝,性能提升至少百倍。
最优实现(data.table版本)
# 不需要修改原数据可先复制,不需要保留原数据可直接操作t对象 t2 <- copy(t) # 生成aj1.consecutive字段,.N对应原逻辑的n(),代表分组内行数 t2[, aj1.consecutive := (sum(j2.consecutive) - j2.consecutive)/(.N - 1), by = .(oid, aid)] # 生成apj1.consecutive字段 t2[, apj1.consecutive := (sum(j2.consecutive) - j2.consecutive)/(.N - 1), by = .(oid, pid)] # 按要求排序 setorder(t2, aid, o4.in)
如果存在分组内只有1条记录的场景,计算时会出现除零得到NaN的情况,可根据业务需要加判断逻辑替换默认值,示例:
t2[, aj1.consecutive := fifelse(.N == 1, 0, (sum(j2.consecutive) - j2.consecutive)/(.N - 1)), by = .(oid, aid)]
该方案处理400万条数据仅需几秒,不会出现内存不足导致Rstudio崩溃的问题,运行结果和原有ddply实现完全一致。
备选实现(dplyr版本)
如果更习惯tidyverse语法,用dplyr的原生分组语法也远快于ddply:
library(dplyr) t2 <- t %>% group_by(oid, aid) %>% mutate(aj1.consecutive = (sum(j2.consecutive) - j2.consecutive)/(n()-1)) %>% ungroup() %>% group_by(oid, pid) %>% mutate(apj1.consecutive = (sum(j2.consecutive) - j2.consecutive)/(n()-1)) %>% ungroup() %>% arrange(aid, o4.in)
内容的提问来源于stack exchange,提问作者J.K.
相关产品推荐
相关产品推荐

