You could use split and rollapply from the zoo package as one of many ways to approach this. Note that in the example below I set the width of the rollapply function to 1 so it just returns each value. For widths greater than one it will take the mean of that number of values.
require(zoo)
sapply( split( df , df$id) , function(x) rollapply( x , width = 1 , align = 'left' , mean) )
#Note that by setting width = 1 we just return the value
$`82`
id score
[1,] 82 0.50000
[2,] 82 0.39286
[3,] 82 0.56250
$`328`
id score
[1,] 328 0.50000
[2,] 328 0.67647
[3,] 328 0.93750
[4,] 328 0.91667
If we were to set width = 3
you would get:
$`82`
id score
[1,] 82 0.48512
$`328`
id score
[1,] 328 0.7046567
[2,] 328 0.8435467
Or you could use aggregate in base
R:
aggregate( score ~ id , data = df , function(x) rollapply( x , width = 1 , align = 'left' , mean) )
id score
1 82 0.50000, 0.39286, 0.56250
2 328 0.50000, 0.67647, 0.93750, 0.91667
There are quite a few ways to do this. I would precisely define your moving average function though, because there are many ways to calculate it (check out for example TTR:::SMA
)
Or more straightforward using ave
:
within(df, { MA_score <- ave(score, id, FUN=function(x)
rollmean(x, k=3, na.pad = TRUE))})