2

我有一个显示日期、项目和值的数据框,我想添加一列显示其先前 50 个条目的平均值(如果没有 50 个则为 NA),例如该表可能是

      data
date     item value  
01/01/01 a    2  
01/01/01 b    1.5  
04/01/01 c    1.7  
05/01/01 a    1.9  
......

它的一部分可能变成

date     item value last_50_mean   
........ 
11/09/01 a    1.2   1.1638
12/09/01 b    1.9   1.5843 
12/09/01 a    1.4   1.1621
13/09/01 c    0.9   NA
........

因此,在这种情况下,a 在 11/09/01 之前的 50 个条目中的平均值是 1.1638,而 c 在 13/09/01 之前没有 50 个条目,因此返回 NA

我目前正在使用以下功能执行此操作

  data[, 'last_50_mean'] <- sapply(1:nrow(data), function(i){
        prevDates <- data[data$date < data$date[i] & data$item == data$item[i], ]
        num       <- nrow(prevGames)
        if(nGames >= 50){
          round(mean(prevDates[(num- 49):num, ]$value), 4)
        }
      }
  )

但是我的数据框很大,而且需要很长时间(事实上,我不能 100% 确定它是否有效,因为它仍在运行……有谁知道最好的方法吗?

4

1 回答 1

4

N 个观测值的平均值可以通过累积总和以及第一个值和最后一个值之间的差值来计算diff(cumsum(x), lag=N - 1)。您的问题想要填充前 N - 1 个值,所以

meanN <- function(x, N=50)
    ## mean of last N observations, padded in front with NA
{
    x0 <- x[seq_len(length(x) - N + 1)]
    x1 <- (x0 + diff(cumsum(x), lag=N-1)) / N
    c(rep(NA, N - 1), x1)
}

您想为多个组执行此操作。对于一个data.frame喜欢

df <- data.frame(item=sample(letters[1:3], 1000, TRUE),
                 value=runif(1000, 1, 3),
                 last_50_mean=NA)

一种方法是

split(df$last_50_mean, df$item) <- lapply(split(df$value, df$item), meanN)

导致例如

> tail(df)
     item    value last_50_mean
995     c 1.191486     2.037707
996     c 2.899214     2.073022
997     c 2.019375     2.054914
998     c 2.737043     2.066389
999     a 1.703752     1.923234
1000    c 1.602442     2.043517

这假设您的数据框是按时间排序的。一个潜在的问题是当长向量溢出时cumsum;可以通过居中来解决这个问题,value因此期望cumsum不会偏离零太远。最近的一个问题解决split<-了最后 N 个观察的替代方案和删除。

于 2012-05-23T16:25:11.917 回答