ค่าเฉลี่ยของหน้าต่างเลื่อนใน 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"
angelous

คำตอบ:


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 ที่ไม่ได้สังเกตในหน้าต่างสุดท้าย มันอาจจะมีประโยชน์มากกว่าหรือเป็นจริงในการใช้ pad 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

BTW ฉันเคยเขียนเกี่ยวกับการใช้งานฟังก์ชั่นนี้เพื่อใช้แนวคิด "quantile loess": r-statistics.com/2010/04/…
Tal Galili

คุณสามารถเพิ่ม 0 ที่ท้าย x (x<-c(x,0) ) เพื่อรับองค์ประกอบคำตอบสุดท้าย

1
@mbq; นั่นทำให้สมมติฐานที่ว่าการสังเกตคือ 0 ฉันได้ครุ่นคิดถึงจุดนี้และ T-Burns ก็ทำสมมติฐานเดียวกัน (0 ที่ไม่ได้สังเกต) ฉันชอบบางทีอาจจะมีแผ่น NA และผ่านในอาร์กิวเมนต์na.rm = TRUE meanคำตอบจะไม่เหมือนกับที่ OP ร้องขอ แต่ดูเหมือนจะมีประโยชน์มากกว่า ฉันจะแก้ไขคำตอบของฉันเพื่อรวมสิ่งนี้
Reinstate Monica - G. Simpson

@ucfagls แต่นี่เป็นเรื่องง่ายที่จะเปลี่ยนและตามที่คุณพูดว่าข้อสันนิษฐานนี้ทำโดย OP ในทางตรงกันข้ามฉันจะเข้มงวดมากขึ้นและลบค่าเฉลี่ยล่าสุด

ขอบคุณ! โดยเฉพาะอย่างยิ่งสำหรับการสังเกตค่าสุดท้ายว่าเป็นศูนย์สมมุติฉันไม่ได้คิดอย่างนั้น ฉันสนใจหน้าต่างสุดท้ายนั้นแน่นอน !!
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 อย่างไรก็ตามมันดูน่าสนใจทีเดียว คุณช่วยอธิบายความคิดของคุณเพราะฉันไม่เข้าใจ
Henrik

1
@Henric ฉันใช้เคล็ดลับนี้บ่อยครั้ง แต่รหัสของผู้ใช้ 1414 จะส่งคืนม้วนนี้ด้วยสไลด์ 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-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 เป็นตัวอย่าง
Mona Jalal

มันเป็นเพียงทิศทางเดียว
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);
}

แก้ไข: ดัชนีที่คุณกำลังมองหาเป็นเพียงidx1... ฟังก์ชั่นนี้สามารถแก้ไขได้อย่างง่ายดายเพื่อส่งคืนพวกเขา แต่ก็เกือบจะเร็วพอ ๆ กันที่จะสร้างพวกเขาใหม่ด้วยการโทรอีกseq(1,length(x),by=slide)ครั้ง


ขอบคุณสำหรับการแปล ฉันคิดว่ามันจะเป็นการออกกำลังกายที่ง่ายและฉันได้เรียนรู้ R จากมัน
shabbychef

คำตอบของฉันคือการปรับปรุงการใช้งานfromo::running_meanจากรุ่นขอบเลือดของฉันแพคเกจ fromo
shabbychef

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คือดัชนีขององค์ประกอบในผลรวม ผมมั่นใจว่านี้สามารถแปลได้อย่างง่ายดายในอาร์สำนวนfirst:skip:lastใน Matlab ให้อาร์เรย์แรกแรก + ข้ามแรก + 2skip ... + n lastแรกข้ามไปที่องค์ประกอบสุดท้ายในอาร์เรย์คือไม่เกิน

แก้ไข : ฉันได้ละเว้นส่วนค่าเฉลี่ย (หารด้วยwindowsize)


+1 ไม่ใช่ tada, rv / windowsize ;-)

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 ในแต่ละครั้ง); เป็นต้น แต่มันจะผลิตสิ่งที่คุณขอ


กรุณาอย่า downvote โดยไม่ต้องแสดงความคิดเห็น ฉันจะรู้ได้อย่างไรว่ามีอะไรผิดปกติ?
Matt Parker

ไม่ใช่ฉัน แต่มันช้า (แต่ไม่ช้ากว่าrollapplyนี้มาก)

2
ไม่ใช่ฉันเหมือนกัน แต่ตามที่กล่าวไว้ด้วยตัวคุณเองการจัดสรรวัตถุผลลัพธ์ล่วงหน้าจะช่วยเรื่องความเร็ว เคล็ดลับอย่างหนึ่งถ้าคุณไม่รู้หรือมันยาก / ยากที่จะกำหนดขนาดของวัตถุผลลัพธ์ที่คุณต้องการ จัดสรรบางสิ่งบางอย่างที่สมเหตุสมผล จากนั้นกรอกข้อมูลด้วยลูปของคุณ แต่เพิ่มการตรวจสอบว่าถ้าคุณใกล้ถึงขีด จำกัด ของวัตถุที่จัดสรรล่วงหน้าให้จัดสรรก้อนใหญ่อีกก้อนหนึ่งแล้วเติมต่อ
Reinstate Monica - G. Simpson

1
@mbq; ความเร็วของผลลัพธ์ในขณะที่สำคัญไม่ใช่ข้อพิจารณาเพียงอย่างเดียว แทนที่จะต้องบูรณาการในขณะที่และจัดการดัชนี ฯลฯ ทั้งหมดในโซลูชันที่กำหนดเองหนึ่งเชิงเส้นที่rollapplyง่ายต่อการเข้าใจและ grep เจตนาของ นอกจากนี้rollapplyมีแนวโน้มที่จะมีลูกตามากขึ้นตรวจสอบรหัสของมันมากกว่าสิ่งที่ฉันอาจทำอาหารในบ่ายวันหนึ่ง ม้าสำหรับหลักสูตร
Reinstate Monica - G. Simpson

1
เปลี่ยน[i:(i+2)]ไป[i:(i+win.size-1)]จะทำให้รหัสทั่วไปมากขึ้นผมคิดว่า
Jota
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.