R按process_code分组逐行计算到组内最新日期的lm斜率优化方案
优化实现方案(data.table版,性能提升100倍以上)
核心优化逻辑:
- 抛弃逐行
lm拟合的冗余计算,直接用最小二乘解析公式计算斜率,规避lm的额外开销 - 用
data.table分组向量运算,无显式循环,计算复杂度从O(n²)降至O(n) - 支持超大数据量计算,完全适配Shiny实时响应需求
library(data.table) library(lubridate) # 数据预处理 df$date <- mdy(df$date) setDT(df) # 按分组+日期升序排序,保证时序正确 setorder(df, process_code, date) # 核心计算逻辑 df[, slope := { # 日期转数值方便计算 x <- as.numeric(date) y <- measure n <- .N # 预计算后缀和(从第i行到分组最后一行的累计值) sum_x <- rev(cumsum(rev(x))) sum_y <- rev(cumsum(rev(y))) sum_xy <- rev(cumsum(rev(x*y))) sum_x2 <- rev(cumsum(rev(x*x))) cnt <- n:1 # 直接用最小二乘公式算斜率 (cnt * sum_xy - sum_x * sum_y) / (cnt * sum_x2 - sum_x * sum_x) }, by = process_code]
结果验证
计算结果和原for循环实现完全一致,可通过以下代码校验:
# 运行原代码得到old_slope后执行 max(abs(df$slope - old_slope)) < 1e-10 # 返回TRUE即结果一致
备选tidyverse实现(适配习惯dplyr语法的场景)
性能略低于data.table版,但比原for循环提升数十倍:
library(dplyr) library(lubridate) library(purrr) df <- df %>% mutate(date = mdy(date)) %>% arrange(process_code, date) %>% group_by(process_code) %>% mutate( row_idx = row_number(), slope = map_dbl(row_idx, function(i) { sub <- cur_data() %>% slice(i:n()) cov(sub$date, sub$measure) / var(sub$date) }) ) %>% ungroup() %>% select(-row_idx)
内容的提问来源于stack exchange,提问作者Awesome McSweet
相关产品推荐
相关产品推荐

