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

如何在R中按组实现递减权重的累积求和(Grouped diminishing weighted cumsum)

问题描述

给定如下R语言tibble数据:

df <- tibble(
  id = c(rep("ID100", 3), 
             rep("ID200", 3), 
             rep("ID450", 3)), 
  year = 2021, 
  month = c(rep(c(5, 6, 7), 3)), 
  value = 5 
)

数据预览:

# A tibble: 9 × 4
  id     year month value
  <chr> <dbl> <dbl> <dbl>
1 ID100  2021     5     5
2 ID100  2021     6     5
3 ID100  2021     7     5
4 ID200  2021     5     5
5 ID200  2021     6     5
6 ID200  2021     7     5
7 ID450  2021     5     5
8 ID450  2021     6     5
9 ID450  2021     7     5

需求:按id和year分组,对value列计算带递减权重的累积求和(命名为acc_sum)。权重规则为:组内最新的月份(最大month值)对应权重1,上一个月份对应0.5,再上一个对应0.25,以此类推(每次减半)。期望输出如下:

# A tibble: 9 × 5
  id     year month value acc_sum
  <chr> <dbl> <dbl> <dbl>   <dbl>
1 ID100  2021     5     5    1.25 # 5 * 0.25
2 ID100  2021     6     5    4    # 5 * 0.5 + 1.25
3 ID100  2021     7     5    9    # 5 * 1 + 4
4 ID200  2021     5     5    1.25
5 ID200  2021     6     5    4   
6 ID200  2021     7     5    9   
7 ID450  2021     5     5    1.25
8 ID450  2021     6     5    4   
9 ID450  2021     7     5    9 

当前已尝试硬编码权重的实现方式,但扩展性差(组内元素数量变化时需手动修改):

df %>%
  group_by(id, year) %>%
  arrange(id, year, month) %>%
  mutate(weights = last(value) +
           lag(value) * 0.5 +
           lag(value, 2) * 0.25)

需要实现无需硬编码权重的通用方案,可借助cumsum或accumulate函数。


解决方案

方法1:用cumsum结合组内位置自动计算权重

这是最简洁的方案,利用组内元素总数和当前行的位置,自动生成对应权重,再通过cumsum计算累积和:

library(dplyr)

df %>%
  group_by(id, year) %>%
  arrange(month) %>% # 确保按月份升序排列
  mutate(
    # 生成对应权重:组内第i行的权重为0.5^(组内总数 - 当前行号)
    weight = 0.5^(n() - row_number()),
    acc_sum = cumsum(value * weight)
  ) %>%
  select(-weight) # 移除中间变量

逻辑说明:

  • n()获取当前组的元素总数
  • row_number()获取当前行在组内的位置(从1开始)
  • 权重公式0.5^(n() - row_number())自动适配组内元素数量,比如3个元素的组会生成0.25, 0.5, 1的权重序列,完全匹配需求
  • cumsum(value * weight)直接计算出期望的累积求和结果

方法2:用purrr::accumulate实现递推累加

如果偏好递推逻辑,可以用accumulate函数,先生成对应权重序列再累加:

library(dplyr)
library(purrr)

df %>%
  group_by(id, year) %>%
  arrange(month) %>%
  mutate(
    # 生成反转的权重序列:2^-(0:(n()-1))生成1,0.5,0.25,反转后得到0.25,0.5,1
    weights = rev(2^-(0:(n()-1))),
    acc_sum = accumulate(value * weights, ~ .x + .y)
  ) %>%
  select(-weights)

逻辑说明:

  • 2^-(0:(n()-1))生成从1开始依次减半的权重序列,反转后适配按月份升序的行顺序
  • accumulate函数依次累加每个value*weight的值,得到累积求和结果

两种方法都无需硬编码权重,可自动适配任意数量的组内元素,完全满足需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:18:25