如何在R中用purrr::accumulate实现带双条件的累加计算?
累加和计算问题的解决思路
需求说明
需要实现带约束的累加逻辑:
- 每次迭代累加固定常量,累加和总值不得超过400
- 当累加和达到400后:
- 夜间(22:00-次日6:00)保持400不变
- 白天(6:00-22:00)重置为0,重新开始累加
原代码问题分析
你当前代码的核心问题是:accumulate()中引用的time2是整个列向量,而非当前迭代对应的时间值。accumulate()的回调函数默认仅能获取上一次累加结果(.x)和当前待累加值(.y),无法直接调用当前行的时间变量,导致时间判断逻辑完全失效,出现要么持续保持400、要么无视昼夜直接重置的问题。
解决方案
方法1:使用accumulate2()传递时间变量
purrr::accumulate2()支持同时传入两个输入序列,刚好可以将时间变量同步传递到回调函数中,实现逐行的时间判断:
library(tidyverse) k_in = 2 # 每次迭代的累加常量 tmax = 24*2*60 # 两天的分钟数 x <- tibble(time = c(1:tmax), # 时间(分钟) time_h = time/60, # 时间(小时) time2 = (time_h %% 24), # 归一化到0-24小时 value = rep(k_in, tmax)) # 待累加值 # 使用accumulate2同时传递value和time2 x <- x %>% mutate(Sum = accumulate2(value, time2, function(prev_sum, curr_val, curr_time) { if (prev_sum + curr_val <= 400) { prev_sum + curr_val } else { # 判断当前时间是否处于夜间 if (curr_time >= 22 | curr_time < 6) { prev_sum # 夜间保持400 } else { curr_val # 白天重置后累加当前值(即从2开始) } } }, .init = 0) %>% # 初始值设为0,去掉最后多余的初始值 head(-1))
方法2:使用显式循环(更直观易调试)
如果函数式写法的逻辑不够清晰,可以用普通循环逐行处理,更便于调试多变量条件:
library(tibble) k_in = 2 tmax = 24*2*60 x <- tibble(time = c(1:tmax), time_h = time/60, time2 = (time_h %% 24), value = rep(k_in, tmax)) # 初始化Sum列 x$Sum <- 0 for (i in 2:nrow(x)) { prev_sum <- x$Sum[i-1] curr_val <- x$value[i] curr_time <- x$time2[i] if (prev_sum + curr_val <= 400) { x$Sum[i] <- prev_sum + curr_val } else { if (curr_time >=22 | curr_time <6) { x$Sum[i] <- prev_sum } else { x$Sum[i] <- curr_val # 重置为0后加当前值,即从2开始 } } }
逻辑验证
- 累加和未到400时,正常执行累加操作
- 累加和达到400后,夜间时段持续保持400
- 进入白天时段后,立即重置为0并启动新的累加周期
内容的提问来源于stack exchange,提问作者Tatiana
相关产品推荐
相关产品推荐

