如何高效计算需依赖前置行数据的数值?
高效填充依赖前置行数据的计算表
我需要一种高效的方法来填充计算表,该表需借助前置行的数据来获取当前行的数值。以下是我当前使用的低效实现代码示例:
df = data.frame(elevation = seq(1,10), inflow = c(3,4,6,4,3,5,6,7,8,9), outflow = NA, storage = NA) for(i in 1:nrow(df)) { if (i == 1) { df$outflow[i] = 0 df$storage[i] = 0 } else { df$outflow[i] = df$inflow[i-1]/2 - df$storage[i-1] df$storage[i] = df$inflow[i] - df$outflow[i] + df$storage[i-1] } } df # elevation inflow outflow storage # 1 1 3 0.0 0.0 # 2 2 4 1.5 2.5 # 3 3 6 -0.5 9.0 # 4 4 4 -6.0 19.0 # 5 5 3 -17.0 39.0 # 6 6 5 -37.5 81.5 # 7 7 6 -79.0 166.5 # 8 8 7 -163.5 337.0 # 9 9 8 -333.5 678.5 # 10 10 9 -674.5 1362.0
优化方案:推导递推公式 + 向量化/累积计算
原循环里的两个变量存在依赖关系,可以先推导storage的独立递推公式,避免嵌套计算:
将outflow[i] = inflow[i-1]/2 - storage[i-1]代入storage[i]的表达式:
storage[i] = inflow[i] - (inflow[i-1]/2 - storage[i-1]) + storage[i-1] = inflow[i] - inflow[i-1]/2 + 2*storage[i-1]
基于这个公式,我们可以用两种高效方式实现:
方法1:基础R简化循环
只针对storage做循环,再批量计算outflow,减少数据框的修改次数:
df = data.frame(elevation = seq(1,10), inflow = c(3,4,6,4,3,5,6,7,8,9), outflow = NA, storage = NA) # 初始化第一行 df$outflow[1] <- 0 df$storage[1] <- 0 # 用推导后的公式计算storage for(i in 2:nrow(df)){ df$storage[i] <- df$inflow[i] - df$inflow[i-1]/2 + 2*df$storage[i-1] } # 批量计算outflow df$outflow[-1] <- df$inflow[-nrow(df)]/2 - df$storage[-nrow(df)] df
方法2:用purrr::accumulate实现无循环计算
accumulate是底层优化的累积计算函数,比R原生for循环效率高很多,尤其适合大数据量场景:
library(purrr) library(dplyr) df = data.frame(elevation = seq(1,10), inflow = c(3,4,6,4,3,5,6,7,8,9)) df <- df %>% mutate( # 累积计算storage序列 storage = accumulate( .x = 2:n(), .f = function(prev_storage, i) inflow[i] - inflow[i-1]/2 + 2*prev_storage, .init = 0 ), # 批量计算outflow outflow = c(0, inflow[-n()]/2 - storage[-length(storage)]) ) df
两种方法都能得到和原循环完全一致的结果,但效率提升明显——尤其是accumulate实现,避免了R循环的逐行开销,数据量越大优势越显著。
内容的提问来源于stack exchange,提问作者Vinicius B. de S. Moreira
相关产品推荐
相关产品推荐

