Mean dari jendela geser di R


19

Saya memiliki vektor nilai yang ingin saya laporkan rata-rata di jendela sepanjang slide yang lebih kecil.

Misalnya, untuk vektor dengan nilai berikut:

4, 5, 7, 3, 9, 8

Ukuran jendela 3 dan slide 2 akan melakukan hal berikut:

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

Dan kembalikan vektor nilai-nilai ini:

5.33, 6.33, 5.67

Apakah ada fungsi sederhana yang akan melakukan ini untuk saya? Jika itu juga mengembalikan indeks mulai jendela yang akan menjadi bonus tambahan. Dalam contoh ini akan menjadi 1,3,5


4
Pernahkah Anda melihat ini ?
JM bukan ahli statistik

Bisakah Anda memberikan latar belakang ide "slide" ini?
Shane

@ JK - Saya belum! Terima kasih! Saya akan melihat cara kerjanya.
T-Burns

@Shane - Ya! Maaf itu tidak jelas. Slide adalah jumlah posisi / indeks yang Anda gerakkan untuk mulai menghitung jendela rata-rata berikutnya. Jadi, daripada jendela berikutnya dimulai setelah akhir yang terakhir ada beberapa tumpang tindih ketika slide lebih kecil dari ukuran jendela Anda. Idenya adalah untuk memuluskan poin data sedikit.
T-Burns

Terima kasih, saya punya pertanyaan yang sama. Sekarang, saya merasa berguna fungsi "rollapply".
angelous

Jawaban:


24

Fungsi rollapplydalam paket kebun binatang membuat Anda dekat:

> 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

Itu tidak akan menghitung nilai terakhir untuk Anda karena tidak mengandung 3 pengamatan. Mungkin ini akan cukup untuk masalah Anda yang sebenarnya? Juga, perhatikan bahwa objek yang dikembalikan memiliki indeks yang Anda inginkan sebagai namesvektor yang dikembalikan.

Contoh Anda membuat asumsi bahwa ada 0 yang tidak teramati di jendela terakhir. Mungkin lebih bermanfaat atau realistis untuk NAmengisi dengan yang mewakili informasi yang hilang dan memberitahu meanuntuk menangani nilai yang hilang. Dalam hal ini kita akan memiliki (8 + 9) / 2 sebagai nilai windowed terakhir kita.

> 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

BTW, saya pernah menulis tentang penggunaan fungsi ini untuk menerapkan gagasan "quantile loess": r-statistics.com/2010/04/…
Tal Galili

Anda dapat menambahkan 0 pada akhir x ( x<-c(x,0)) untuk mendapatkan elemen jawaban terakhir.

1
@ mbq; yaitu membuat asumsi kuat bahwa pengamatannya adalah 0. Saya telah mempertimbangkan hal ini dan T-Burns membuat asumsi yang sama (sebuah 0 yang tidak teramati). Saya lebih suka untuk menggunakan NA dan memberikan na.rm = TRUEargumen mean. Jawabannya tidak akan sama dengan apa yang diminta OP, tetapi tampaknya lebih bermanfaat. Saya akan mengedit jawaban saya untuk memasukkan ini.
Reinstate Monica - G. Simpson

@ucfagls Namun ini mudah diubah dan seperti yang Anda katakan, asumsi ini dibuat oleh OP. Di sisi lain, saya akan lebih membatasi dan menghapus rata-rata terakhir.

Terima kasih! Terutama untuk mencatat nilai terakhir sebagai asumsi nol, saya tidak menganggap itu. Saya sangat peduli dengan jendela terakhir itu !!
T-Burns

12

Rollapply berfungsi baik dengan dataset kecil. Namun, jika Anda bekerja dengan beberapa juta baris (genomik) itu cukup lambat.

Fungsi berikut ini sangat cepat.

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


Cukup membantu. Tetapi berhati-hatilah, jendela itu = 3 akan mengembalikan rata-rata 4 (!) Nilai, kecuali jika Anda menambahkan -1(ke kisaran) dan a +1(ke loop).
BurninLeo

5

Baris kode sederhana ini berfungsi:

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

jika xvektor yang dimaksud.


Ini tidak mengembalikan apa yang diinginkan si penanya, tetapi 5.33 5.00 6.33. Namun, tampilannya cukup menarik. Bisakah Anda menjelaskan ide Anda, karena saya tidak mengerti.
Henrik

1
@ Henric Saya sering menggunakan trik ini, namun kode user1414 mengembalikan gulungan ini dengan slide 1, bukan 2, sebagaimana dimaksud oleh OP. Lihat (c(0,0,x)+c(0,x,0)+c(x,0,0))/3untuk melihat apa yang saya maksud (dan bagaimana cara kerjanya). Rumus yang tepat adalah: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(kita harus memotong 0-padding di awal dan memilih elemen genap kemudian.

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

atau

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

Apakah ini berfungsi untuk matriks 2D? Seperti bagaimana? Jika ukuran jendela adalah 3 * 3 sebagai contoh
Mona Jalal

itu hanya satu arah
RockScience

3

Jawaban shabbychef dalam 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);
}

Sunting: Indeks yang Anda cari hanyalah idx1... fungsi ini dapat dengan mudah dimodifikasi untuk mengembalikannya juga, tetapi hampir sama cepatnya untuk membuatnya kembali dengan panggilan lain seq(1,length(x),by=slide).


terima kasih telah menerjemahkan. Saya pikir itu akan menjadi latihan yang mudah, dan saya belajar beberapa R darinya
shabbychef

Jawaban saya yang diperbarui adalah digunakan fromo::running_meandari versi tepi pendarahan dari paket fromo saya .
shabbychef

3

Saya dapat melakukan ini dengan mudah di Matlab dan bebek saat Anda menurunkan saya:

%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!

sebagai efek samping, idx1adalah indeks elemen dalam penjumlahan. Saya yakin ini dapat dengan mudah diterjemahkan ke dalam R. Idiom first:skip:lastdi Matlab memberikan array pertama, pertama + lompati, pertama + 2 lompati, ..., pertama + n lompati, di mana elemen terakhir dalam array tidak lebih besar dari last.

sunting : Saya telah menghilangkan bagian rata-rata (bagi dengan windowsize).


+1 Tidak tada, rv / windowsize ;-)

1
Kotak komentar ... marg ini terlalu sempit untuk kode ini, jadi saya sudah mengirim jawaban baru.

1
Terima kasih, tetapi MATLAB tidak gratis !!
T-Burns

@ T-Burns: oktaf gratis, namun; juga R cukup dekat dengan Matlab sehingga kode ini dapat dengan mudah diterjemahkan. Faktanya, @mbq melakukan itu ..
shabbychef

1

Ini akan memberi Anda sarana jendela dan indeks nilai pertama dari jendela:

#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
    }

Berbagai peringatan berlaku: belum diuji terhadap apa pun selain data sampel Anda; Saya percaya bahwa menambahkan frame data seperti ini bisa sangat lambat jika Anda memiliki banyak nilai (karena itu akan menyalin data.frame setiap kali); dll. Tapi itu menghasilkan apa yang Anda minta.


Tolong jangan downvote tanpa memberikan komentar. Bagaimana saya bisa tahu apa yang salah?
Matt Parker

Bukan saya, tapi ini lambat (tapi tidak lebih lambat dari rollapply).

2
Bukan saya juga, tetapi seperti yang Anda sebutkan, pra-alokasi objek hasil akan membantu dengan masalah kecepatan. Satu trik, jika Anda tidak tahu, atau membosankan / sulit untuk menentukan, ukuran objek hasil yang Anda butuhkan. Alokasikan sesuatu yang masuk akal, mungkin pra-isi dengan NA. Kemudian isi dengan loop Anda, tetapi tambahkan tanda centang bahwa jika Anda mendekati batas objek yang telah dialokasikan sebelumnya, alokasikan potongan besar lainnya, dan lanjutkan mengisi.
Pasang kembali Monica - G. Simpson

1
@ mbq; Kecepatan hasil, meskipun penting, bukan satu-satunya pertimbangan. Alih-alih harus menemukan kembali sementara dan menangani semua indeks dll dalam solusi kustom, satu-linier yang rollapplyjauh lebih mudah dipahami dan dipahami maksudnya. Juga, rollapplykemungkinan memiliki lebih banyak bola mata memeriksa kodenya daripada sesuatu yang mungkin saya masak suatu sore. Kuda untuk kursus.
Pasang kembali Monica - G. Simpson

1
Mengubah [i:(i+2)]ke [i:(i+win.size-1)]akan membuat kode lebih umum, saya pikir.
Jota
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.