Расчет скользящей средней

163

Я пытаюсь использовать R для вычисления скользящей средней по ряду значений в матрице. Обычный поиск в списке рассылки R не очень помог. Кажется, что встроенная функция в R позволит мне рассчитать скользящие средние. Предоставляются ли какие-либо пакеты? Или мне нужно написать свой собственный?

Теги:
moving-average
r-faq

10 ответов

121
Лучший ответ
  • Rolling Means/Maximums/Medians в пакете zoo (rollmean)
  • MovingAverages в TTR
  • ma in forecast
  • 0
    Что такое скользящее среднее в R, не содержащее будущих значений данной временной метки? Я проверил forecast::ma и он содержит все окрестности, не верно.
196

Или вы можете просто рассчитать его с помощью фильтра, здесь функция, которую я использую:

ma <- function(x, n = 5){filter(x, rep(1 / n, n), sides = 2)}

Если вы используете dplyr, будьте осторожны, dplyr stats::filter в функции выше.

  • 42
    Я должен отметить, что "сторон = 2" может быть важным вариантом в случаях использования многих людей, которые они не хотят упускать из виду. Если вы хотите, чтобы в скользящем среднем значении была только конечная информация, вы должны использовать сторон = 1.
  • 32
    Несколько лет спустя, но dplyr теперь имеет функцию фильтра, если у вас загружен этот пакет, используйте stats::filter
Показать ещё 1 комментарий
25

Использование cumsum должно быть достаточным и эффективным. Предполагая, что у вас есть вектор x, и вы хотите получить текущую сумму из n чисел

cx <- c(0,cumsum(x))
rsum <- (cx[(n+1):length(cx)] - cx[1:(length(cx) - n)]) / n

Как указано в комментариях @mzuther, это предполагает, что в данных нет NA. чтобы справиться с этим, потребуется разделить каждое окно на количество значений, отличных от NA. Вот один из способов сделать это, включив комментарий @Ricardo Cruz:

cx <- c(0, cumsum(ifelse(is.na(x), 0, x)))
cn <- c(0, cumsum(ifelse(is.na(x), 0, 1)))
rx <- cx[(n+1):length(cx)] - cx[1:(length(cx) - n)]
rn <- cn[(n+1):length(cx)] - cn[1:(length(cx) - n)]
rsum <- rx / rn

Это все еще имеет проблему, что, если все значения в окне являются NA, тогда будет ошибка деления на ноль.

  • 8
    Недостатком этого решения является то, что оно не может обрабатывать cumsum(c(1:3,NA,1:3)) : cumsum(c(1:3,NA,1:3))
  • 0
    Вы можете легко заставить его обрабатывать NA, выполнив cx <- c(0, cumsum(ifelse(is.na(x), 0, x))) .
Показать ещё 3 комментария
8

В data.table 1.12.0 была добавлена новая функция frollmean для вычисления быстрого и точного скользящего среднего, тщательно обрабатывая значения NA, NaN и +Inf, -Inf.

Так как в этом вопросе нет воспроизводимого примера, здесь не так много вопросов.

Вы можете найти более подробную информацию о ?frollmean в руководстве, также доступном онлайн по адресу ?frollmean.

Примеры из руководства ниже:

library(data.table)
d = as.data.table(list(1:6/2, 3:8/4))

# rollmean of single vector and single window
frollmean(d[, V1], 3)

# multiple columns at once
frollmean(d, 3)

# multiple windows at once
frollmean(d[, .(V1)], c(3, 4))

# multiple columns and multiple windows at once
frollmean(d, c(3, 4))

## three above are embarrassingly parallel using openmp
8

Вы можете использовать RcppRoll для очень быстрых скользящих средних, написанных в C++. Просто вызовите функцию roll_mean. Документы можно найти здесь.

В противном случае этот (более медленный) цикл for должен сработать:

ma <- function(arr, n=15){
  res = arr
  for(i in n:length(arr)){
    res[i] = mean(arr[(i-n):i])
  }
  res
}
  • 3
    Не могли бы вы объяснить мне подробнее, как работает этот алгоритм? Потому что я не могу понять идею
  • 0
    Сначала он инициализирует вектор такой же длины с помощью res = arr . Затем есть цикл, который повторяется, начиная с n или, 15-го элемента, до конца массива. это означает, что самое первое подмножество, которое он принимает в качестве среднего, это arr[1:15] которое заполняет spot res[15] . Теперь я предпочитаю устанавливать res = rep(NA, length(arr)) вместо res = arr поэтому каждый элемент res[1:14] равен NA, а не числу, где мы не можем получить полное среднее из 15 элементов ,
8

Пакет caTools имеет очень быстрое скользящее среднее/мин/макс/сд и несколько других функций. Я работал только с runmean и runsd, и они являются самыми быстрыми из любых других пакетов, упомянутых на сегодняшний день.

  • 1
    Это круто! Это единственная функция, которая делает это простым и приятным способом. И сейчас 2018 год ...
7

На самом деле RcppRoll очень хорошо.

Код, отправленный cantdutchthis, должен быть исправлен в четвертой строке, чтобы окно было исправлено:

ma <- function(arr, n=15){
  res = arr
  for(i in n:length(arr)){
    res[i] = mean(arr[(i-n+1):i])
  }
  res
}

Другой способ, который обрабатывает пропуски, дается здесь.

Третий способ, улучшающий cantdutchthis код для вычисления частичных средних или нет, следует:

  ma <- function(x, n=2,parcial=TRUE){
  res = x #set the first values

  if (parcial==TRUE){
    for(i in 1:length(x)){
      t<-max(i-n+1,1)
      res[i] = mean(x[t:i])
    }
    res

  }else{
    for(i in 1:length(x)){
      t<-max(i-n+1,1)
      res[i] = mean(x[t:i])
    }
    res[-c(seq(1,n-1,1))] #remove the n-1 first,i.e., res[c(-3,-4,...)]
  }
}
4

Чтобы дополнить ответ cantdutchthis и Родриго Ремедио,

moving_fun <- function(x, w, FUN, ...) {
  # x: a double vector
  # w: the length of the window, i.e., the section of the vector selected to apply FUN
  # FUN: a function that takes a vector and return a summarize value, e.g., mean, sum, etc.
  # Given a double type vector apply a FUN over a moving window from left to the right, 
  #    when a window boundary is not a legal section, i.e. lower_bound and i (upper bound) 
  #    are not contained in the length of the vector, return a NA_real_
  if (w < 1) {
    stop("The length of the window 'w' must be greater than 0")
  }
  output <- x
  for (i in 1:length(x)) {
     # plus 1 because the index is inclusive with the upper_bound 'i'
    lower_bound <- i - w + 1
    if (lower_bound < 1) {
      output[i] <- NA_real_
    } else {
      output[i] <- FUN(x[lower_bound:i, ...])
    }
  }
  output
}

# example
v <- seq(1:10)

# compute a MA(2)
moving_fun(v, 2, mean)

# compute moving sum of two periods
moving_fun(v, 2, sum)
1

все параметры, перечисленные здесь, являются каузальными скользящими средними. если требуется не причинная версия, тогда пакет сигнал имеет некоторые параметры.

0

Хотя и немного медленно, но вы также можете использовать zoo :: rollapply для выполнения вычислений на матрицах.

reqd_ma <- rollapply(x, FUN = mean, width = n)

где x - набор данных, FUN = mean - функция; Вы также можете изменить его на min, max, sd и т.д., а width - это скользящее окно.

  • 0
    Это не медленно; Сравнивая это с базой R, это намного быстрее. set.seed(123); x <- rnorm(1000); system.time(apply(embed(x, 5), 1, mean)); library(zoo); system.time(rollapply(x, 5, mean)) На моей машине это так быстро, что возвращает время 0 секунд.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню