R:计算有序向量的先前元素

R: Compute on previous elements of an ordered vector

给定一个有序向量 vec <- c(1, 4, 6, 3, 2, 7),我想为 vec 的每个元素 i 计算前面元素的加权平均值,其中权重是距离的倒数元素 i.

该功能应按以下方式进行。

结果向量 result 应该是 length(result) == length(vec), c(NA, 1, 3, 4.5, 3.9, 3.266667).

更新: 我的意思显然是不使用循环

result <- numeric()

for (i in 1:length(vec)) {
  if (i == 1) {
    result <-
      c(result, NA)
  } else {
    previous_elements <- vec[1:(i-1)]
    result <-
      c(result, 
        weighted.mean(x = previous_elements, w = 1:length(previous_elements)))
  }
}

这是一个天真的实现。创建一个按照你说的做的函数;唯一 'clever' 的事情是使用函数 seq_len() 而不是 1:i 来生成索引

fun = function(i, vec)
    weighted.mean(head(vec, i - 1), w=seq_len(i - 1))

然后在sapply中使用

sapply(seq_along(vec), fun, vec)

这已经足够了 -- NaN 作为第一个元素,而不是 NA,但这很容易在事后更正(或在概念上被接受为正确答案)。它也比您的解决方案更好,但仍然 'using a loop' -- 结果向量的管理由 sapply() 完成,而不是在您必须自己管理的循环中完成。特别是您的 'copy and append' 方法在性能方面非常糟糕,每次通过循环都会复制现有结果。最好预先分配一个适当长度的结果向量result = numeric(length(vec))然后填充它result[[i]] = ...,更好的是让sapply()为你做正确的事情!

问题是天真的实现按二次方缩放——你通过 vec 处理每个元素,然后对每个元素进行第二次处理以计算加权平均值,所以有n (n - 1) / 2 计算。所以...

看看weighted.mean

> stats:::weighted.mean.default
function (x, w, ..., na.rm = FALSE) 
{
    ## SNIP -- edited for brevity
    w <- as.double(w)
    if (na.rm) {
        i <- !is.na(x)
        w <- w[i]
        x <- x[i]
    }
    sum((x * w)[w != 0])/sum(w)
}

并使用 cumsum() 而不是 sum() 来获取累积权重,而不是单个权重,即 return 一个向量,只要 x,其中第 i 个元素是到该点的加权平均值

cumweighted.mean <- function(x, w) {
    ## handle NA values?
    w <- as.numeric(w)  # to avoid integer overflow
    cumsum(x * w)[w != 0] / cumsum(w)
}

你想要一些不同的东西

myweighted.mean <- function(x)
    c(NA, cumweighted.mean(head(x, -1), head(seq_along(x), - 1)))

这会单次传递数据,因此线性缩放(至少在理论上是这样)。