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不是统计学家2010年

您能为这个“幻灯片”概念提供一些背景知识吗?
Shane 2010年

@JM-我没有!谢谢!我将要看看它是如何工作的。
T-Burns,2010年

@Shane-是的!对不起,不清楚。幻灯片是您移动以开始计算下一个均值窗口的位置/指数的数​​量。因此,当幻灯片小于您的窗口大小时,而不是在最后一个窗口结束之后开始的下一个窗口存在重叠。这个想法是使数据点稍微平滑一些。
T-Burns,2010年

谢谢,我有同样的问题。现在,我发现“ rollapply”功能很有用。
2014年

Answers:


24

rollapply软件包zoo中的函数使您接近:

> 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/...
塔尔加利利

您可以在x(x<-c(x,0))的末尾添加0,以获得答案的最后一个元素。

1
@mbq; 这是一个很强的假设,即观测值是0。我一直在考虑这一点,而T-Burns做出了相同的假设(未观察到的0)。我可能更希望使用NA并将na.rm = TRUE参数传递给mean。答案将与OP要求的答案不同,但似乎更有用。我将编辑答案以包括此内容。
恢复莫妮卡-辛普森

@ucfagls然而,这很容易更改,正如您所说的,此假设是由OP做出的。另一方面,我会更加严格,并删除最后的平均值。

谢谢!特别是为了将最后一个值标记为零假设,我没有考虑这一点。我绝对在乎最后一个窗口!
T-Burns,2010年

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


很有帮助。但请注意,除非您将a -1(添加到范围)和a +1(添加到循环),否则window = 3将返回4个(!)值的平均值。
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)返回此滚动。看看(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

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 2010年

我更新的答案是fromo::running_meanfromo软件包的最新版本中使用。
shabbychef

3

当您对我投反对票时,我可以在Matlab和Duck中轻松完成此操作:

%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:lastR。Matlab中的惯用法使数组为first,first + skip,first + 2skip,...,first + n skip,其中数组的最后一个元素不大于last

编辑:我已经省略了平均部分(除以windowsize)。


+1不是tada,rv / windowsize ;-)

1
此marg ...注释框对于此代码而言太狭窄,因此我发布了一个新答案。

1
谢谢,但是MATLAB不是免费的!
T-Burns 2010年

@ T-Burns:但是,八度是免费的;R也足够接近Matlab,因此可以轻松地翻译此代码。实际上,@ mbq就是这样做的。–
shabbychef,2010年

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);等等。但是它确实产生了您所要求的。


请不要在没有提供评论的情况下投票。我怎么知道怎么了?
Matt Parker 2010年

不是我,但这很慢(但速度不比慢rollapply)。

2
也不是我,但是正如您自己提到的那样,预先分配结果对象将有助于解决速度问题。一个诀窍,如果您不知道或难以确定所需结果对象的大小。分配一些合理的东西,也许用NA预先填充。然后填写您的循环,但是添加一个检查,如果您正在接近预分配对象的限制,请分配另一个大块,然后继续填充。
恢复莫妮卡-G.辛普森

1
@mbq; 结果的速度虽然很重要,但不是唯一的考虑因素。不必在定制解决方案中浪费时间并处理所有索引等,rollapply而是更容易理解和理解其意图的单线性。另外,rollapply检查它的代码的目光可能比我一个下午准备的东西多得多。马课程。
恢复莫妮卡-G.辛普森

1
我认为更改[i:(i+2)][i:(i+win.size-1)]将使代码更通用。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.