如何在R中的特定条件下对向量的元素进行求和?

How to cumsum the elements of a vector under certain condition in R?

我的objective是对向量的元素进行累加和,并将结果分配给每个元素。但当达到一定条件时,则重置累计和。

例如:

vector_A <- c(1, 1, -1, -1, -1, 1, -1, -1, 1, -1)

现在,假设重置累计和的条件是下一个元素有不同的符号

那么期望的输出是:

vector_B <- c(1, 2, -1, -2, -3, 1, -1, -2, 1, -1)

我怎样才能做到这一点?

想到的方法是找到由定义的 运行s (rle()) 数据中的条件 (sign()),分别对每个 运行 应用 cumsum() (tapply()),然后连接回向量 (unlist())。某物 像这样:

vector_A <- c(1, 1, -1, -1, -1, 1, -1, -1, 1, -1)

run_length <- rle(sign(vector_A))$lengths
run_id <- rep(seq_along(run_length), run_length)

unlist(tapply(vector_A, run_id, cumsum), use.names = FALSE)
#>  [1]  1  2 -1 -2 -3  1 -1 -2  1 -1

稍微总结一下这个过程,我可能会找到分组因子(运行 索引)在函数中?然后分组摘要将需要使用 现有工具,如上面的 tapply(),或创意 ave(),或在 数据帧的上下文,group_by()summarise() with dplyr.

run_index <- function(x) {
  with(rle(x), rep(seq_along(lengths), lengths))
}

ave(vector_A, run_index(sign(vector_A)), FUN = cumsum)
#>  [1]  1  2 -1 -2 -3  1 -1 -2  1 -1

您可以使用自定义函数代替 cumsum 并使用例如purrr::accumulate:

library(purrr)
vector_A <- c(1, 1, -1, -1, -1, 1, -1, -1, 1, -1)

purrr::accumulate(vector_A, function(a,b) {
  if (sign(a) == sign(b))
    a+b
  else
    b
  })

[1]  1  2 -1 -2 -3  1 -1 -2  1 -1

或者如果您想避免任何分支:

purrr::accumulate(vector_A, function(a,b) { b + a*(sign(a) == sign(b))})

[1]  1  2 -1 -2 -3  1 -1 -2  1 -1

具有 Reduce

的基础 R 选项
> Reduce(function(x, y) ifelse(x * y > 0, x + y, y), vector_A, accumulate = TRUE)
 [1]  1  2 -1 -2 -3  1 -1 -2  1 -1

或使用 ave + cumsum

> ave(vector_A, cumsum(c(1, diff(sign(vector_A)) != 0)), FUN = cumsum)
 [1]  1  2 -1 -2 -3  1 -1 -2  1 -1

使用ave:

ave(vector_A, data.table::rleid(sign(A)), FUN = cumsum)
#  [1]  1  2 -1 -2 -3  1 -1 -2  1 -1

accumulate的公式版本:

purrr::accumulate(vector_A, ~ ifelse(sign(.x) == sign(.y), .x + .y, .y))
#  [1]  1  2 -1 -2 -3  1 -1 -2  1 -1