R语言中如何高效实现依赖前一行的逐行mutate操作?
高效实现逐行依赖变量计算的方案
针对你需要计算依赖前一行结果的case、case_cum、population_1三个变量的场景,以下几种方案比原生for循环更高效简洁,尤其适合大数据量:
1. 使用data.table优化循环
data.table的内存操作效率远高于普通data.frame,即使保留循环结构,速度也会大幅提升:
library(data.table) set.seed(123) dat <- data.table(month = 1:12, population = rep(1000, 12), rate = runif(12, 0.01, 0.05)) # 批量初始化变量 dat[, `:=`(case = NA_real_, case_cum = NA_real_, population_1 = NA_real_)] # 处理第一行 dat[1, `:=`( case = population * rate, case_cum = case, population_1 = population - case_cum )] # 滚动计算后续行 for (i in 2:nrow(dat)) { dat[i, `:=`( case = dat[i-1, population_1] * rate, case_cum = case + dat[i-1, case_cum], population_1 = population - case_cum )] }
2. 用purrr的累积函数实现函数式计算
利用purrr::accumulate封装状态流转逻辑,代码更简洁,可读性强:
library(purrr) library(dplyr) set.seed(123) dat <- data.frame(month = 1:12, population = rep(1000, 12), rate = runif(12, 0.01, 0.05)) # 定义单步计算逻辑:输入前一步状态,输出当前步状态 calc_next <- function(prev, curr) { curr_case <- prev$pop1 * curr$rate curr_cum <- curr_case + prev$cum curr_pop1 <- curr$population - curr_cum list(case = curr_case, cum = curr_cum, pop1 = curr_pop1) } # 初始化第一行状态 init_state <- list( case = dat$population[1] * dat$rate[1], cum = dat$population[1] * dat$rate[1], pop1 = dat$population[1] - (dat$population[1] * dat$rate[1]) ) # 从第二行开始累积计算 result_list <- accumulate(dat[-1, ], calc_next, .init = init_state) # 将结果合并回原数据框 result_df <- bind_rows(result_list) dat <- dat %>% mutate( case = result_df$case, case_cum = result_df$cum, population_1 = result_df$pop1 )
3. 数学推导简化计算(最高效)
观察计算逻辑可推导递推公式,减少变量跟踪:
case_cum[i] = case_cum[i-1]*(1 - rate[i]) + population[i-1]*rate[i]- 得到
case_cum后,case可通过差分计算,population_1直接用population - case_cum
set.seed(123) dat <- data.frame(month = 1:12, population = rep(1000, 12), rate = runif(12, 0.01, 0.05)) # 计算累积病例数 dat$case_cum <- numeric(nrow(dat)) dat$case_cum[1] <- dat$population[1] * dat$rate[1] for (i in 2:nrow(dat)) { dat$case_cum[i] <- dat$case_cum[i-1] * (1 - dat$rate[i]) + dat$population[i-1] * dat$rate[i] } # 推导其余变量 dat$case <- c(dat$case_cum[1], diff(dat$case_cum)) dat$population_1 <- dat$population - dat$case_cum
这种方式只需要维护一个变量的循环,计算量最小,速度最快。
内容的提问来源于stack exchange,提问作者MooMooU
相关产品推荐
相关产品推荐

