2016-08-16 1 views
-1

Учитывая упорядоченный вектор 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).

UPDATE: Я ясно имею в виду без использования цикла

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

Просьба показать ваше усилие и где он идет не так. –

+0

Возможный дубликат: http://stackoverflow.com/q/743812/903061 - в то время как это не относится к * взвешенному * скользящему средству, многие из методов (например, 'RcppRoll') предоставляют эту функциональность. – Gregor

+0

[Вот еще один] (http://stackoverflow.com/q/8720055/903061), хотя он кажется немного устаревшим. – Gregor

ответ

2

Вот наивная реализация. Создайте функцию, которая делает то, что вы говорите; только «умный» вещь использовать функцию seq_len() вместо 1: я для создания индексов

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

, а затем использовать его в sapply

sapply(seq_along(vec), fun, vec) 

Это достаточно хорошо - NaN как первый элемент, а не NA, но это легко корректируется после факта (или концептуально принятого в качестве правильного ответа). Это также лучше, чем ваше решение, но все же «использование цикла» - управление вектором результата выполняется sapply(), а не в вашем цикле, где вам нужно управлять им самостоятельно. И, в частности, ваш подход «копирование и добавление» очень плохой по производительности, делая копию существующего результата каждый раз через цикл. Лучше предварительно выделить вектор результата соответствующей длины 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(), чтобы получить кумулятивный веса, а не индивидуальных весов, т.е., Возвращает вектор, пока x, где го элемента является взвешенное среднее значение до этого момента

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))) 

Это делает один проход через данных, поэтому масштабируется линейно (по крайней мере теоретически).

Смежные вопросы