使用dplyr与lag函数按分组逐行递推计算金额
用dplyr实现分组递推计算amt字段
原始数据
首先定义并查看原始数据:
df = data.frame(name=c(rep("Group1",5),rep("Group2",5)), mon=c(1,2,3,4,5,1,2,3,4,5), amt=c(10,NA,NA,NA,NA,15,NA,NA,NA,NA), inc=c(.1,.1,.2,.2,.3,.1,.1,.2,.2,.3)) df
输出:
name mon amt inc 1 Group1 1 10 0.1 2 Group1 2 NA 0.1 3 Group1 3 NA 0.2 4 Group1 4 NA 0.2 5 Group1 5 NA 0.3 6 Group2 1 15 0.1 7 Group2 2 NA 0.1 8 Group2 3 NA 0.2 9 Group2 4 NA 0.2 10 Group2 5 NA 0.3
需求说明
按name字段分组,每组首行amt有有效值,其余行为NA;需要递推计算后续行的amt,公式为:
后一行amt = 前一行amt(1+当前行inc)*
分组切换时重新开始计算。
dplyr解决方案
结合dplyr的分组功能和purrr的accumulate函数,可以优雅实现递推计算,替代循环写法:
library(dplyr) library(purrr) df_result <- df %>% group_by(name) %>% mutate(amt = accumulate(1 + inc, ~ .x * .y, .init = first(amt))[-1]) %>% ungroup() df_result
代码解释
group_by(name):按分组字段name划分数据集,确保每组独立计算accumulate(1 + inc, ~ .x * .y, .init = first(amt)):1 + inc将增长率转换为增长系数(比如0.1的增长率对应1.1的系数).x代表上一步的计算结果,.y代表当前行的增长系数,~ .x * .y定义每一步的计算逻辑.init = first(amt)指定每组的初始值为该组第一个非NA的amt值[-1]移除accumulate返回结果中的初始值,保证结果长度与原数据一致
ungroup():取消分组,将结果转换为普通数据框
计算结果
# A tibble: 10 × 4 name mon amt inc <chr> <dbl> <dbl> <dbl> 1 Group1 1 10 0.1 2 Group1 2 11 0.1 3 Group1 3 13.2 0.2 4 Group1 4 15.8 0.2 5 Group1 5 20.6 0.3 6 Group2 1 15 0.1 7 Group2 2 16.5 0.1 8 Group2 3 19.8 0.2 9 Group2 4 23.8 0.2 10 Group2 5 30.9 0.3
内容的提问来源于stack exchange,提问作者user1723699
相关产品推荐
相关产品推荐

