Среднее скользящего окна в R


19

У меня есть вектор значений, который я хотел бы сообщить о среднем в окнах вдоль меньшего слайда.

Например, для вектора следующих значений:

4, 5, 7, 3, 9, 8

Размер окна 3 и слайд 2 будут делать следующее:

(4+5+7)/3 = 5.33
(7+3+9)/3 = 6.33
(9+8)/3 = 5.67

И вернуть вектор этих значений:

5.33, 6.33, 5.67

Есть ли простая функция, которая сделает это для меня? Если бы это также возвратило индексы начала окна, это было бы добавленным бонусом. В этом примере это будет 1,3,5



Можете ли вы дать некоторое представление об этой идее «слайд»?
— Шейн

@JM - я не имел! Спасибо! Я собираюсь посмотреть, как это работает.
— T-Burns

@ Шейн - Да! Извините, это не было ясно. Слайд - это число позиций / индексов, которые вы перемещаете, чтобы начать вычисление следующего окна средних значений. Таким образом, вместо следующего окна, начинающегося после конца последнего, есть некоторое перекрытие, когда слайд меньше размера вашего окна. Идея состоит в том, чтобы немного сгладить точки данных.
— T-Burns

Спасибо, у меня был тот же вопрос. Теперь мне показалась полезной функция «раскатать».
— ангел

Ответы:


24

Функция rollapplyв пакете зоопарка приближает вас:

> require(zoo)
> TS <- zoo(c(4, 5, 7, 3, 9, 8))
> rollapply(TS, width = 3, by = 2, FUN = mean, align = "left")
       1        3 
5.333333 6.333333

Он просто не будет вычислять последнее значение для вас, поскольку он не содержит 3 наблюдения. Может быть, этого будет достаточно для вашей реальной проблемы? Также обратите внимание, что возвращаемый объект имеет нужные вам индексы в namesкачестве возвращаемого вектора.

Ваш пример предполагает, что в последнем окне есть ненаблюдаемый 0. Возможно, было бы более полезным или реалистичным дополнить NAего представлением недостающей информации и сказать, что meanнужно обрабатывать пропущенные значения. В этом случае мы будем иметь (8 + 9) / 2 как наше окончательное оконное значение.

> TS <- zoo(c(4, 5, 7, 3, 9, 8, NA))
> rollapply(TS, width = 3, by = 2, FUN = mean, na.rm = TRUE, align = "left")
       1        3        5 
5.333333 6.333333 8.500000

Кстати, я однажды писал об использовании этой функции для реализации понятия «квантильный лёсс»: r-statistics.com/2010/04/…
— Tal

Вы можете добавить 0 в конце x ( x<-c(x,0)), чтобы получить последний элемент ответа.

1
@mbq; это делает сильное предположение, что наблюдение равно 0. Я обдумывал эту точку, и Т-Бернс делает то же самое предположение (ненаблюдаемый 0). Я предпочел бы, возможно, дополнить NA и передать na.rm = TRUEаргумент mean. Ответ не будет таким же, как запрос OP, но он кажется более полезным. Я отредактирую свой ответ, чтобы включить это.
— Восстановить Монику - Г. Симпсон

@ucfagls Но это легко изменить, и, как вы сказали, это предположение было сделано ОП. С другой стороны, я был бы еще более ограничительным и убрал бы последнее среднее значение.

Благодарность! Специально для того, чтобы отметить последнее значение как нулевое предположение, я не учел это. Я определенно забочусь об этом последнем окне !!
— T-Burns

12

Rollapply прекрасно работает с небольшим набором данных. Однако, если вы работаете с несколькими миллионами строк (геномика), это довольно медленно.

Следующая функция супер быстрая.

data <- c(runif(100000, min=0, max=.1),runif(100000, min=.05, max=.1),runif(10000, min=.05, max=1), runif(100000, min=0, max=.2))

slideFunct <- function(data, window, step){
  total <- length(data)
  spots <- seq(from=1, to=(total-window), by=step)
  result <- vector(length = length(spots))
  for(i in 1:length(spots)){
    result[i] <- mean(data[spots[i]:(spots[i]+window)])
  }
  return(result)
}

http://coleoguy.blogspot.com/2014/04/sliding-window-analysis.html


Довольно полезно Но имейте в виду, что window = 3 вернет среднее значение из 4 (!) Значений, если вы не добавите a -1(в диапазон) и a +1(в цикл).
— BurninLeo

5

Эта простая строка кода делает вещь:

((c(x,0,0) + c(0,x,0) + c(0,0,x))/3)[3:(length(x)-1)]

если xэто вектор в вопросе.


Это не возвращает того, что хотел аскер, но 5.33 5.00 6.33. Тем не менее, это выглядит довольно интересно. Можете ли вы объяснить свою идею, потому что я не понимаю.
— Хенрик,

1
@Henric Я часто использую этот трюк, но код user1414 возвращает этот ролик со слайдом 1, а не 2, как и предполагалось OP. Проверьте, (c(0,0,x)+c(0,x,0)+c(x,0,0))/3что я имею в виду (и как это работает). Правильная формула будет: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(мы должны сократить 0-отступ в начале и затем выбрать четные элементы.

4
library(zoo)
x=c(4, 5, 7, 3, 9, 8)
rollmean(x,3)

или

library(TTR)
x=c(4, 5, 7, 3, 9, 8)
SMA(x,3)

Это работает для 2D матриц? Например как? Если размер окна 3 * 3 в качестве примера
— Мона Джалал

это только одно направление
— RockScience

3

Ответ Шеббычефа в R:

slideMean<-function(x,windowsize=3,slide=2){
 idx1<-seq(1,length(x),by=slide);
 idx1+windowsize->idx2;
 idx2[idx2>(length(x)+1)]<-length(x)+1;
 c(0,cumsum(x))->cx;
 return((cx[idx2]-cx[idx1])/windowsize);
}

РЕДАКТИРОВАТЬ: Индексы, которые вы ищете, просто idx1... эта функция может быть легко изменена, чтобы возвращать их, но почти одинаково быстро воссоздать их с другим вызовом seq(1,length(x),by=slide).


спасибо за перевод. Я подумал, что это будет легкое упражнение, и я узнал кое-что из R
— shabbychef

Мой обновленный ответ - использование fromo::running_meanновейшей версии моего пакета fromo .
— Шаббычеф

3

Я легко могу сделать это в Matlab и утке, пока ты меня опускаешь:

%given vector x, windowsize, slide 
idx1 = 1:slide:numel(x);
idx2 = min(numel(x) + 1,idx1 + windowsize);  %sic on +1 here and no -1;
cx = [0;cumsum(x(:))];  %pad out a zero, perform a cumulative sum;
rv = (cx(idx2) - cx(idx1)) / windowsize; %tada! the answer!

как побочный эффект, idx1является индексом элемента в сумме. Я уверен, что это можно легко перевести на R. Идиома first:skip:lastв Matlab дает массив first, first + skip, first + 2skip, ..., first + n skip, где последний элемент в массиве не больше чем last.

редактировать : я опустил часть усреднения (делить на windowsize).


+1 Не тада, rv /

1
Это поле для комментариев ... слишком узкое для этого кода, поэтому я отправил новый ответ.

1
Спасибо, но MATLAB не бесплатен!
— T-Burns

@ T-Burns: октава свободна, однако; также R достаточно близок к Matlab, чтобы этот код можно было легко перевести. Фактически, @mbq сделал это ..
— shabbychef

1

Это даст вам средство окна и индекс первого значения окна:

#The data
x <- c(4, 5, 7, 3, 9, 8)

#Set window size and slide
win.size <- 3
slide <- 2

#Set up the table of results
results <- data.frame(index = numeric(), win.mean = numeric())

#i indexes the first value of the window (the sill?)
i <- 1
#j indexes the row of the results to be added next
j <- 1
while(i < length(x)) {
    #This mean preserves the denominator of 3
    win.mean <- sum(x[i:(i+2)], na.rm = TRUE)/win.size
    #Insert the results
    results[j, ] <- c(i, win.mean)
    #Increment the indices for the next pass
    i <- i + slide
    j <- j + 1
    }

Применяются различные предостережения: не проверял это ни против чего, кроме ваших данных выборки; Я считаю, что добавление к таким фреймам данных может быть очень медленным, если у вас много значений (потому что каждый раз будет копироваться data.frame); и т.д. Но он производит то, что вы просили.


Пожалуйста, не отрицайте, не предоставив комментарий. Откуда мне знать, что не так?
— Мэтт Паркер

Это был не я, но это медленно (но не намного медленнее, чем rollapply).

2
это был не я, но, как вы сами отметили, предварительное выделение объекта результата поможет решить проблему скорости. Один трюк, если вы не знаете, или это утомительно / трудно определить, размер нужного вам объекта результата. Выделите что-то разумное, возможно, предварительно заполнив NA. Затем заполните свой цикл, но добавьте проверку, что, если вы приближаетесь к пределу предварительно выделенного объекта, выделите еще один большой кусок и продолжите заполнение.
— Восстановить Монику - Г. Симпсон

1
@mbq; Скорость результатов, хотя и важна, не единственное соображение. Вместо того, чтобы заново изобретать while и обрабатывать все индексы и т. Д. В пользовательских решениях, однолинейный, который rollapplyгораздо проще понять и понять замысел. Кроме того, rollapplyвероятно, было гораздо больше глазных яблок, проверяющих его код, чем то, что я мог бы приготовить однажды днем. Лошади на курсы.
— Восстановить Монику - Г. Симпсон

1
Изменение [i:(i+2)]в [i:(i+win.size-1)]бы сделать код более общим, я думаю.
— Jota
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.