Среднее скользящего окна в 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.