首页 > 解决方案 > 使用 dplyr 对两个变量进行递归求和

问题描述

我有两列的值,a 和 b。我想添加第三列c,它是(在第i行)b的0到i的总和加上c的0到(i-1)的总和,乘以a,即

c_i = (sum_i (b) + sum_(i-1) (c) ) * a_i

我试过

data %>%
mutate(
 c = a * (cumsum(b) + lag(cumsum(c), default = 0))
)

但是这不起作用,因为我只是根据目前不存在的 c 值创建 c :

Error: Problem with `mutate()` input `c`.
x object 'c' not found

以前我使用 for 循环处理此类问题。但是,我习惯了 dplyr,而且总有办法。但是,我不明白。

我很感激任何帮助!

编辑:在以前的版本中,我不准确,因为 a 也是一个向量,而不是一个常数。我在公式里改了

所需的输出:

row 1: 0.5 * (7  + 0 ) =3.5

row 2: 0.3 * (7+1 + 3.5) = 3.45

row 3: 1.0 * (7+1+9 + 3.5+3.45) = 23.95

| a | b | c |
|---|---|---|
|0.5|7|3.5|
|0.3|1|3.45|
|1|9|23.95|
|0.2|10|...|

标签: rdataframeperformancerecursiondplyr

解决方案


更新

一个超级有效的选择是求解线性矩阵(感谢@Martin Gal 的评论):

transform(
  df,
  C = solve(
    `diag<-`(mat <- matrix(-a, length(a), length(a)), 1) * lower.tri(mat, diag = TRUE),
    a * cumsum(b)
  )
)

这使

    a  b       C
1 0.5  7  3.5000
2 0.3  1  3.4500
3 1.0  9 23.9500
4 0.2 10 11.5800
5 0.4  3 28.9920
6 0.8  2 82.7776

或以某种dplyr方式

df %>%
  mutate(
    C = solve(
      `diag<-`(mat <- matrix(-a, length(a), length(a)), 1) * lower.tri(mat, diag = TRUE),
      a * cumsum(b)
    )
  )

这使

# A tibble: 6 x 3
      a     b     C
  <dbl> <int> <dbl>
1   0.5     7  3.5
2   0.3     1  3.45
3   1       9 24.0
4   0.2    10 11.6
5   0.4     3 29.0
6   0.8     2 82.8

上一个答案(递归方法,无效


通过定义递归函数的基本 R 选项(但效率低下)f

f <- function(k) {
  if (k == 1) {
    return(with(df[k, ], a * b))
  }
  r <- f(k - 1)
  c(r, with(df, a[k] * (sum(b[1:k]) + sum(r))))
}

你会看到

> f(nrow(df))
[1]  3.5000  3.4500 23.9500 11.5800 28.9920 82.7776

> df %>%
+   mutate(C = f(n()))
# A tibble: 6 x 3
      a     b     C
  <dbl> <int> <dbl>
1   0.5     7  3.5
2   0.3     1  3.45
3   1       9 24.0
4   0.2    10 11.6
5   0.4     3 29.0
6   0.8     2 82.8

推荐阅读