Мне нужно рассчитать скользящую медиану. И есть следующий код

i <- 0
median_roll<-c("")
x<-c(1:10)
n<-2
y<-as.data.frame(x)
  while(i < length(x)-n){
    median_roll[i] <- median(y[i:i+n,])
    i <- i + 1  
  }

Которые производят следующие релуты в median_roll

[1] "3" "4" "5" "6" "7" "8" "9"

Мне нужно

[1] "2" "3" "4" "5" "6" "7" "8" "9"
3
Iftikhar 10 Окт 2021 в 00:23

2 ответа

Лучший ответ

Вот три варианта.
Сначала данные.

x <- 1:10
y <- data.frame(x)
n <- 2L

1 База R, for петля.

median_roll <- numeric(length(x) - n)
for(i in seq_along(median_roll)){
  median_roll[i] <- median(y[i:(i+n), ])
}

median_roll
#[1] 2 3 4 5 6 7 8 9

2 База R, sapply петля.

sapply(seq_along(median_roll), \(i, n) median(y[i:(i+n), ]), n = 2L)
#[1] 2 3 4 5 6 7 8 9

3 Пакет zoo.

zoo::rollapplyr(y$x, width = 3L, FUN = median)
#[1] 2 3 4 5 6 7 8 9
5
Rui Barradas 9 Окт 2021 в 21:47

В R индексирование начинается с 1, которым должен соответственно инициализироваться i.

i <- 1; x <- 1:10; r <- NULL; n <- 2
while (i - 1 + n < length(x)) {
  r[i] <- median(x[i:(i + n)])
  i <- i + 1
}
r
# [1] 2 3 4 5 6 7 8 9

Вы также можете использовать цикл repeat, который может быть более читабельным.

i <- 1; x <- 1:10; r <- NULL; n <- 2
repeat {
  r[i] <- median(x[i:(i + n)])
  i <- i + 1
  if (i - 1 + n == length(x))
    break
}
r
# [1] 2 3 4 5 6 7 8 9

Решение sapply(Map()).

x <- 1:10; n <- 2
sapply(Map(`+`, list(1:(n + 1L)), seq(0, length(x) - n - 1L, n - 1L)), 
       \(s) median(x[s]))
# [1] 2 3 4 5 6 7 8 9
1
jay.sf 9 Окт 2021 в 22:05