给定一个有序向量vec <- c(1, 4, 6, 3, 2, 7)
,我想为i
的每个元素vec
计算前一个元素的加权平均值,其中权重是距元素的距离的倒数i
。
该功能应如下进行。
1
,应返回NA
(没有前一个元素)。4
,应返回1
。 6
,应返回weighted.mean(x = c(1,4), w
= c(1,2))
。3
,应返回weighted.mean(x =
c(1,4,6), w = c(1,2,3))
生成的向量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)))
}
}
答案 0 :(得分:2)
这是一个天真的实施。创建一个完成你所说的功能;唯一聪明的&#39;事情是使用函数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,但事实之后很容易纠正(或者在概念上被接受为正确的答案)。它也比你的解决方案更好,但仍然使用循环&#39; - 结果向量的管理由sapply()
完成,而不是在您必须自己管理的循环中完成。特别是你的复制和追加&#39;方法在性能方面非常差,每次通过循环复制现有结果。最好预先分配适当长度result = numeric(length(vec))
的结果向量,然后填充result[[i]] = ...
,最好让sapply()
为你做正确的事!
问题在于,天真的实现以二次方式进行缩放 - 您沿着vec
传递以处理每个元素,然后为每个元素进行第二次传递以计算加权平均值,因此存在{{ 1}}计算。所以......
查看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()
返回一个向量,其中第i个元素是加权意味着到那时为止
x
你想要一些不同的东西
cumweighted.mean <- function(x, w) {
## handle NA values?
w <- as.numeric(w) # to avoid integer overflow
cumsum(x * w)[w != 0] / cumsum(w)
}
这使得单次通过数据,因此线性扩展(至少在理论上)。