Середнє значення розсувного вікна в 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


4
Ви бачили це ?
JM не є статистиком

Чи можете ви дати деяку інформацію про цю ідею "слайда"?
Шейн

@JM - я ні! Дякую! Я збираюся побачити, як це працює.
T-Burns

@Shane - Так! Вибачте, що було не ясно. Слайд - це кількість позицій / індексів, які ви переміщуєте, щоб почати обчислювати наступне вікно середніх значень. Тож замість наступного вікна, що починається після закінчення останнього, є деяке перекриття, коли слайд менший за розмір вікна. Ідея полягає в тому, щоб трохи згладити точки даних.
T-Burns

Дякую, у мене було те саме питання. Тепер я знайшов корисною функцію "rollapply".
ангел

Відповіді:


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/…
Тал Галілі

Ви можете додати 0 в кінці x ( x<-c(x,0)), щоб отримати останній елемент відповіді.

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

@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


Дуже корисно. Але майте на увазі, що вікно = 3 поверне середнє значення 4 (!), Якщо ви не додасте -1(до діапазону) та а +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 Я часто використовую цей трюк, але код користувача1414 повертає цей рулон із слайдом 1, а не 2, як це було призначено ОП. Перевірте, (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-padding на початку і потім вибрати рівні елементи.

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

відповідь shabbychef на 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);
}

EDIT: Індекси, які ви шукаєте, просто idx1... цю функцію можна легко змінити, щоб також повернути їх, але майже однаково швидко їх відтворити за допомогою іншого дзвінка seq(1,length(x),by=slide).


дякую за переклад Я подумав, що це буде легка вправа, і я навчився з неї кілька R
shabbychef

Моєю оновленою відповіддю є використання fromo::running_meanв крайовій версії мого пакету fromo .
shabbychef

3

Я можу це легко зробити в Матлабі та качку, поки ти мене зневажаєш:

%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 дає масив спочатку, перший + пропуск, перший + 2скіп, ..., перший + n пропуск, де останній елемент масиву не більший за last.

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


+1 Не тада, rv /

1
Цей поле… коментар занадто вузький для цього коду, тому я опублікував нову відповідь.

1
Дякую, але MATLAB не безкоштовний !!
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
не я був, але як зазначав сам, попереднє виділення результату об'єкта допоможе у питанні швидкості. Один трюк, якщо ви не знаєте, або це важко / важко визначити, розмір потрібного вам об'єкта. Виділіть щось розумне, можливо, попередньо заповнивши НС. Потім заповніть свою петлю, але додайте чек, що якщо ви наближаєтесь до межі попередньо виділеного об’єкта, виділіть ще один великий фрагмент і продовжуйте заповнювати.
Відновіть Моніку - Г. Сімпсон,

1
@mbq; Швидкість результатів, хоча це важливо, не є єдиною увагою. Замість того, щоб винаходити час і обробляти всі індекси тощо в користувацьких рішеннях, однолінійне, що rollapplyнабагато простіше зрозуміти і зрозуміти намір. Також, rollapplyшвидше за все, було б набагато більше очних яблук, які перевіряли його код, ніж щось, що я можу приготувати одного дня. Коні на курси.
Відновіть Моніку - Г. Сімпсон,

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