如何在R中高效填充需依赖不同列前序行的数据框?
高效填充依赖前序行数据的计算表方法
我需要一种高效的方法来填充计算表,该表需借助不同列的前序行数据计算当前值。此前我曾提出类似问题但表述不清,现提供新的示例代码及当前使用的(速度较慢的)实现方式:
df = data.frame(elevation = seq(1,10), inflow = c(3,4,6,4,3,5,6,7,8,9), outflow = NA, storage = NA, stat = NA) for(i in 1:nrow(df)) { if (i == 1) { df$outflow[i] = 0 df$storage[i] = 0 df$stat[i] = 0 } else { df$outflow[i] = df$inflow[i-1]/2 + df$stat[i-1] + df$storage[i-1] df$storage[i] = df$inflow[i] - df$outflow[i] + df$stat[i-1] df$stat[i] = df$inflow[i-1] + df$stat[i-1] - df$storage[i-1] } } df
运行结果:
elevation inflow outflow storage stat 1 1 3 0.0 0.0 0.0 2 2 4 1.5 2.5 3.0 3 3 6 7.5 1.5 4.5 4 4 4 9.0 -0.5 9.0 5 5 3 10.5 1.5 13.5 6 6 5 16.5 2.0 15.0 7 7 6 19.5 1.5 18.0 8 8 7 22.5 2.5 22.5 9 9 8 28.5 2.0 27.0 10 10 9 33.0 3.0 33.0
优化方案
方案1:使用data.table快速迭代
data.table在处理逐行依赖计算时性能远优于基础R循环,尤其适合大数据集:
library(data.table) dt = as.data.table(df) dt[1, `:=`(outflow = 0, storage = 0, stat = 0)] for(i in 2:nrow(dt)) { dt[i, outflow := dt[i-1, inflow]/2 + dt[i-1, stat] + dt[i-1, storage]] dt[i, storage := dt[i, inflow] - dt[i, outflow] + dt[i-1, stat]] dt[i, stat := dt[i-1, inflow] + dt[i-1, stat] - dt[i-1, storage]] } dt
方案2:数学简化+向量化运算
通过对递推公式推导,可以将循环转化为效率更高的向量化运算:
分析原始递推关系后,可简化得到以下表达式:
- 第1行:
outflow[1] = 0,storage[1] = 0,stat[1] = 0 - 第i行(i≥2):
stat[i] = 2*stat[i-1] + inflow[i-1]/2outflow[i] = stat[i]storage[i] = inflow[i] + stat[i-1] - stat[i]
基于简化后的关系,用向量化方式实现:
# 初始化向量 n = nrow(df) outflow = numeric(n) storage = numeric(n) stat = numeric(n) outflow[1] = 0 storage[1] = 0 stat[1] = 0 # 简化循环计算 for(i in 2:n) { stat[i] = 2*stat[i-1] + df$inflow[i-1]/2 outflow[i] = stat[i] storage[i] = df$inflow[i] + stat[i-1] - stat[i] } # 赋值回原数据框 df$outflow = outflow df$storage = storage df$stat = stat df
也可以用purrr::accumulate实现无循环计算:
library(purrr) # 用accumulate计算stat向量 stat_vec = accumulate( .x = df$inflow[-1], .f = function(prev_stat, inflow_prev) { 2*prev_stat + inflow_prev/2 }, .init = 0 ) # 生成outflow和storage向量 outflow_vec = stat_vec storage_vec = c(0, df$inflow[-1] + stat_vec[-length(stat_vec)] - stat_vec[-1]) # 赋值回数据框 df$outflow = outflow_vec df$storage = storage_vec df$stat = stat_vec df
以上几种方式都能显著提升计算速度,其中数学简化后的向量化/累积运算效率最高,适合超大规模数据集;data.table方案则兼顾可读性和性能,代码改动成本低。
内容的提问来源于stack exchange,提问作者Vinicius B. de S. Moreira
相关产品推荐
相关产品推荐

