Giá trị trung bình của cửa sổ trượt trong R


19

Tôi có một vectơ các giá trị mà tôi muốn báo cáo trung bình trong các cửa sổ dọc theo một slide nhỏ hơn.

Ví dụ: đối với một vectơ của các giá trị sau:

4, 5, 7, 3, 9, 8

Kích thước cửa sổ là 3 và slide 2 sẽ làm như sau:

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

Và trả về một vectơ của các giá trị này:

5.33, 6.33, 5.67

Có một chức năng đơn giản sẽ làm điều này cho tôi? Nếu nó cũng trả về các chỉ số của cửa sổ bắt đầu thì đó sẽ là phần thưởng bổ sung. Trong ví dụ này sẽ là 1,3,5



Bạn có thể cho một số nền tảng về ý tưởng "trượt" này?
Shane

@JM - Tôi đã không! Cảm ơn bạn! Tôi sắp xem nó hoạt động như thế nào.
T-Burns

@Shane - Vâng! Tôi xin lỗi đã không rõ ràng. Slide là số lượng vị trí / chỉ số bạn di chuyển để bắt đầu tính toán cửa sổ trung bình tiếp theo. Vì vậy, thay vì cửa sổ tiếp theo bắt đầu sau khi kết thúc cuối cùng, có một số trùng lặp khi slide nhỏ hơn kích thước cửa sổ của bạn. Ý tưởng là để làm mịn các điểm dữ liệu một chút.
T-Burns

Cảm ơn, tôi đã có cùng một câu hỏi. Bây giờ, tôi thấy nó hữu ích với chức năng "rollapply".
thiên thần

Câu trả lời:


24

Chức năng rollapplytrong gói sở thú giúp bạn gần gũi:

> 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

Nó sẽ không tính giá trị cuối cùng cho bạn vì nó không chứa 3 quan sát. Có lẽ điều này sẽ đủ cho vấn đề thực sự của bạn? Ngoài ra, lưu ý rằng đối tượng được trả về có các chỉ số bạn muốn lànames vectơ được trả về.

Ví dụ của bạn đang đưa ra một giả định rằng có 0 không quan sát được trong cửa sổ cuối cùng. Nó có thể hữu ích hoặc thực tế hơn để đệm với một NAđại diện cho thông tin bị thiếu và nói meanđể xử lý các giá trị bị thiếu. Trong trường hợp này, chúng tôi sẽ có (8 + 9) / 2 làm giá trị cửa sổ cuối cùng của chúng tôi.

> 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, tôi đã từng viết về việc sử dụng chức năng này để thực hiện khái niệm "hoàng thổ lượng tử": r-statistic.com/2010/04/ Thẻ
Tal Galili

Bạn có thể thêm 0 vào cuối x ( x<-c(x,0)) để lấy phần tử trả lời cuối cùng.

1
@mbq; điều đó đang đưa ra một giả định mạnh mẽ rằng quan sát là 0. Tôi đã nghiên cứu kỹ điểm này và T-Burns cũng đưa ra giả định tương tự (một số 0 không quan sát được). Tôi có lẽ muốn đệm với NA và chuyển vào na.rm = TRUEđối số để mean. Câu trả lời sẽ không giống như những gì OP yêu cầu, nhưng có vẻ hữu ích hơn. Tôi sẽ chỉnh sửa câu trả lời của tôi để bao gồm điều này.
Phục hồi Monica - G. Simpson

@ucfagls Tuy nhiên, điều này rất dễ thay đổi và như bạn đã nói giả định này được thực hiện bởi OP. Mặt khác, tôi thậm chí sẽ hạn chế hơn và loại bỏ mức trung bình cuối cùng.

Cảm ơn! Đặc biệt là để lưu ý giá trị cuối cùng là giả định bằng không, tôi đã không xem xét điều đó. Tôi chắc chắn quan tâm đến cửa sổ cuối cùng đó !!
T-Burns

12

Rollapply hoạt động tuyệt vời với một tập dữ liệu nhỏ. Tuy nhiên, nếu bạn đang làm việc với vài triệu hàng (genomics) thì khá chậm.

Các chức năng sau là siêu nhanh.

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


Khá hữu ich. Nhưng hãy lưu ý, cửa sổ đó = 3 sẽ trả về trung bình 4 giá trị (!), Trừ khi bạn thêm một -1(vào phạm vi) và một +1(vào vòng lặp).
BurninLeo

5

Dòng mã đơn giản này thực hiện điều:

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

nếu xlà vectơ trong câu hỏi.


Điều này không trả về những gì người hỏi muốn, nhưng 5,33 5,00 6,33. Tuy nhiên, nó trông khá thú vị. Bạn có thể giải thích ý tưởng của bạn, bởi vì tôi không hiểu nó.
Henrik

1
@Henric Tôi sử dụng thủ thuật này thường xuyên, nhưng mã của user1414 trả lại cuộn này với slide 1, không phải 2, như dự định của OP. Kiểm tra (c(0,0,x)+c(0,x,0)+c(x,0,0))/3để xem những gì tôi có ý nghĩa (và làm thế nào nó hoạt động). Công thức thích hợp sẽ là: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(chúng ta phải cắt 0 phần đệm ngay từ đầu và sau đó chọn các phần tử chẵn.

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

hoặc là

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

Điều này có làm việc cho ma trận 2D không? Như thế nào? Nếu kích thước cửa sổ là 3 * 3 làm ví dụ
Mona Jalal

nó chỉ là một hướng
RockScience

3

câu trả lời của shabbychef trong 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: Các chỉ số bạn đang tìm kiếm chỉ là idx1... chức năng này có thể dễ dàng được sửa đổi để trả lại chúng, nhưng nó cũng nhanh như nhau để tạo lại chúng bằng một cuộc gọi khác seq(1,length(x),by=slide).


cảm ơn vì đã dịch Tôi nghĩ rằng nó sẽ là một bài tập dễ dàng và tôi đã học được một số R từ nó
shabbychef

Câu trả lời cập nhật của tôi là sử dụng fromo::running_meantừ phiên bản xuất sắc của gói fromo của tôi .
shabbychef

3

Tôi có thể làm điều này một cách dễ dàng trong Matlab và vịt trong khi bạn đánh giá thấp tôi:

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

như một tác dụng phụ, idx1 là chỉ số của phần tử trong tổng. Tôi chắc chắn điều này có thể dễ dàng dịch sang R. Thành ngữ first:skip:lasttrong Matlab đưa ra mảng đầu tiên, đầu tiên + bỏ qua, đầu tiên + 2skip, ..., bỏ qua đầu tiên + n, trong đó phần tử cuối cùng trong mảng không lớn hơn last.

chỉnh sửa : Tôi đã bỏ qua phần trung bình (chia cho windowsize).


+1 Không phải tada, rv / windowsize ;-)

1
Hộp bình luận này ... quá hẹp đối với mã này, vì vậy tôi đã đăng một câu trả lời mới.

1
Cảm ơn, nhưng MATLAB không miễn phí !!
T-Burns

@ T-Burns: quãng tám là miễn phí, tuy nhiên; R cũng đủ gần với Matlab để mã này có thể dễ dàng được dịch. Trên thực tế, @mbq đã làm điều đó ..
shabbychef

1

Điều này sẽ giúp bạn có nghĩa là cửa sổ và chỉ mục của giá trị đầu tiên của cửa sổ:

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

Nhiều cảnh báo khác nhau được áp dụng: chưa thử nghiệm điều này với bất kỳ thứ gì trừ dữ liệu mẫu của bạn; Tôi tin rằng việc thêm vào các khung dữ liệu như thế này có thể trở nên rất chậm nếu bạn có nhiều giá trị (vì nó sẽ sao chép data.frame mỗi lần); vv Nhưng nó không sản xuất những gì bạn yêu cầu.


Xin đừng downvote mà không cung cấp một nhận xét. Làm thế nào tôi có thể biết những gì sai?
Matt Parker

Đó không phải là tôi, nhưng điều này chậm (nhưng không chậm hơn nhiều rollapply).

2
cũng không phải tôi, nhưng như bạn đã đề cập, việc phân bổ trước đối tượng kết quả sẽ giúp giải quyết vấn đề tốc độ. Một mẹo, nếu bạn không biết, hoặc rất tẻ nhạt / khó xác định, kích thước của đối tượng kết quả bạn cần. Phân bổ một cái gì đó hợp lý, có lẽ điền trước với NA. Sau đó điền vào vòng lặp của bạn, nhưng thêm một kiểm tra xem nếu bạn đang tiến gần đến giới hạn của đối tượng preallocated, hãy phân bổ một đoạn lớn khác và tiếp tục điền.
Phục hồi Monica - G. Simpson

1
@mbq; Tốc độ của kết quả, trong khi quan trọng, không phải là sự cân nhắc duy nhất. Thay vì phải phát minh lại trong khi xử lý tất cả các chỉ mục, v.v. trong các giải pháp tùy chỉnh, thì một tuyến tính rollapplydễ hiểu hơn nhiều và hiểu được ý định của nó. Ngoài ra, rollapplycó khả năng đã có nhiều nhãn cầu kiểm tra mã của nó hơn là thứ tôi có thể nấu vào một buổi chiều. Ngựa cho các khóa học.
Phục hồi Monica - G. Simpson

1
Thay đổi [i:(i+2)]để [i:(i+win.size-1)]làm cho mã chung hơn, tôi nghĩ.
Jota
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.