You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在data.table/R中用函数实现递归计算以提升运行效率?

递归计算优化:替代for循环提升R代码效率

问题背景

处理全年每小时温度变化计算,涉及60列、8760行数据,部分变量需按小时递归更新。原for循环可得到正确结果,但完整运行耗时15分钟,尝试用dplyr函数替换时因无法调用计算后的值导致结果错误,需实现依赖上一行计算结果的递归逻辑。

可复现示例

初始data.table

library(data.table)
table <- data.table("A" = c(1), "B" = c(1:5), "C" = c(10))
table

输出:

A B  C
1: 1 1 10
2: 1 2 10
3: 1 3 10
4: 1 4 10
5: 1 5 10

原for循环实现(正确结果)

for (j in (2: nrow(table))) {
  table$A[j] = (table$A[j-1] + table$B[j-1]) * table$B[j]
  table$C[j] = table$B[j] * table$A[j] 
 }
table

预期输出:

A B    C
1:   1 1   10
2:   4 2    8
3:  18 3   54
4:  84 4  336
5: 440 5 2200

失败的dplyr尝试

library(dplyr)
table <- data.table("A" = c(1), "B" = c(1:5), "C" = c(10))

myfun <- function(df){
  df = df %>% mutate(A = (lag(A) + lag(B)) * B, 
                     C = B * A)
  return(df)
}

myfun(table)

错误输出:

A B   C
1 NA 1  NA
2  4 2   8
3  9 3  27
4 16 4  64
5 25 5 125

问题原因:mutate基于列的原始值计算,lag(A)调用的是初始A列的上一行值,而非计算过程中更新后的A值,无法实现递归依赖。

解决方案

方案1:用purrr::accumulate实现向量递归计算

利用accumulate函数生成递归的A序列,再更新C列,避免循环的同时保证递归逻辑:

library(data.table)
library(purrr)

table <- data.table("A" = c(1), "B" = c(1:5), "C" = c(10))

# 生成递归的A值序列
A_vals <- accumulate(2:nrow(table), .init = table$A[1],
                     ~ (.x + table$B[..y - 1]) * table$B[..y])
table$A <- A_vals
# 更新C列(第一行保留原始值,后续行按规则计算)
table$C[-1] <- table$B[-1] * table$A[-1]

table

方案2:优化for循环(data.table原生高效写法)

原循环慢的核心原因是用$赋值会频繁复制data.table,改用set函数直接修改内存中的值,大幅提升速度:

library(data.table)
table <- data.table("A" = c(1), "B" = c(1:5), "C" = c(10))

for (j in 2:nrow(table)) {
  # 用set直接修改指定位置的值,避免数据复制
  set(table, j, "A", (table$A[j-1] + table$B[j-1]) * table$B[j])
  set(table, j, "C", table$B[j] * table$A[j])
}

table

两种方案都能得到预期结果,其中方案2对于大行数(如8760行)的性能提升非常明显,远快于原始for循环;方案1更偏向函数式编程风格,代码更简洁。

内容的提问来源于stack exchange,提问作者Jnz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 08:05:25