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
........

したがって、この場合、11/09/01より前の50エントリのaの平均は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)

これを行う1つの方法は

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 に答える