从多个变量中按比例减去

Proportional substraction from multiple variables

我有两个随时间变化的变量。加法是已知的,但是对于减法,我只知道需要减去的和,而我想从两个变量中按比例减去它。

这是一个数据集示例

df = data.frame(id = c(rep(1,5), rep(2,3)),
                ord = c(1:5, 1:3),
                a = c(10, NA, 20, 0, NA, 0, 15, NA),
                b = c(0, NA, 0, 15, NA, 10, 0, NA),
                substract = c(NA, -5, NA, NA, -10, NA, NA, -15)) %>% 
  rowwise() %>% 
  mutate(all = sum(c(a, b, substract), na.rm = TRUE)) %>% 
  arrange(id, ord) %>% 
  group_by(id) %>% 
  mutate(all = cumsum(all)) %>% 
  ungroup()

所以,我想用 substract 中的值替换 ab 中的 NA,乘以 ab 分别除以 allNA 之前的值。问题是,在每次替换之后,下一次替换应该考虑到所有之前的替换,因为 ab 的累加和会在之后发生变化。

我有一个带有 while 循环的解决方案,该解决方案有效,但效率极低。原始数据集很大,所以它不是我的选择,但它可能会让我对我想要实现的目标有一些额外的了解。

test = df %>% 
  group_by(id)
while(any(is.na(test$a))){
  test = test %>% 
    mutate(across(c("a", "b"), ~ ifelse(is.na(.x), lag(cumsum(.x)) / lag(all) * substract, .x)))
}

谁能提出更有效的解决方案?就像,如果有任何方法可以让 mutate 函数在每次突变后保存更改(因此不需要将其放入 while 循环)或其他什么?

编辑:user63230 suggested using 。这似乎确实是我想要的,但我仍然很难将它们应用到我的案例中。 accumulate2() 只接受 3 个参数函数并且似乎不适用于 lag() (因为我不仅需要当前变量的先前值),所以它似乎还不够。也许有办法让它工作,但我还没有发现它。任何帮助将不胜感激。

使用与 类似的方法,我认为这会奏效,虽然不是很漂亮:

library(dplyr)
sp <- split(df, df$id)
list_of_dfs <- lapply(sp, function(x){
  for(i in which(is.na(x$a))){
    tmp <- x[seq_len(i), ]
    x$a[i] <- tail(cumsum(tmp$a)[!is.na(cumsum(tmp$a))], 1)/tail(dplyr::lag(tmp$all), 1)*tail((tmp$substract), 1)
  }
  x
})
bind_rows(list_of_dfs)
#      id   ord     a     b substract   all
#   <dbl> <int> <dbl> <dbl>     <dbl> <dbl>
# 1     1     1 10        0        NA    10
# 2     1     2 -5       NA        -5     5
# 3     1     3 20        0        NA    25
# 4     1     4  0       15        NA    40
# 5     1     5 -6.25    NA       -10    30
# 6     2     1  0       10        NA    10
# 7     2     2 15        0        NA    25
# 8     2     3 -9       NA       -15    10

如果合适可以repeated/automated给b吗?