greeny
greeny

Reputation: 445

Exponential smoothing method

I am trying to create a function in r for exponential smoothing.

I have been able to create what I need in excel using a formula:

=(alpha*observed+(alpha - 1)*previous)

This can easily be dragged down and achieves the desired result. Here is an example of this with alpha = 0.1.

Score <- c(4,7,3,5,7,2,3)

Score   Exp Smooth      Calculation
4       #N/A            #N/A
7       4               4
3       4.3             0.1*7+0.9*4
5       4.17            0.1*3+0.9*4.3
7       4.253           0.1*5+0.9*4.17
2       4.5277          0.1*7+0.9*4.253
3       4.27493         0.1*2+0.9*4.5277

I'm sure there must be a way to recreate this as a function in r. Furthermore, I need this function to be able to be grouped over multiple fields. Here is another example with more fields and the desired exponential smoothing figures.

Player <- c('Y','Z','Z','Z','Z','Y','Y','Y','Y','Z','Y','Y','Z','Y','Z','Y','Z','Z','Y','Y','Z','Y','Z','Y','Z','Z','Y')
Team <- c('A','B','A','A','B','A','B','B','A','A','B','B','A','A','A','A','A','A','A','B','B','B','B','A','A','A','A')
Score <- c(5,2,7,3,9,6,3,7,1,7,3,8,3,4,1,9,4,6,3,8,3,4,1,9,4,6,6)
data.frame(Player, Team, Score)

Desired result:

Player  Team    Score   Exp Smooth
Y       A       5       #N/A            
Z       B       2       #N/A
Z       A       7       #N/A            
Z       A       3       7                
Z       B       9       2
Y       A       6       5
Y       B       3       #N/A
Y       B       7       3
Y       A       1       5.1
Z       A       7       6.6
Y       B       3       3.4
Y       B       8       3.36
Z       A       3       6.64
Y       A       4       4.69
Z       A       1       6.276
Y       A       9       4.621
Z       A       4       5.7484
Z       A       6       5.57356
Y       A       3       5.05890
Y       B       8       3.82400
Z       B       3       2.70000
Y       B       4       4.24160
Z       B       1       2.73000
Y       A       9       4.85301
Z       A       4       5.616204
Z       A       6       5.454584
Y       A       6       5.267709

I'm sure there must be a way to achieve this in r. Any help would be much appreciated!

Upvotes: 3

Views: 1921

Answers (1)

Roland
Roland

Reputation: 132706

You can use the filter function. However, we have to be a bit creative since its recursive filter implies a coefficient of 1 for lag 0.

fun <- function(x) {
  res <- stats::filter(x * c(1, rep(0.1, length(x) - 1)), 0.9, method = "recursive")
  c(NA, res[-length(res)])
}

Score <- c(4,7,3,5,7,2,3)
fun(Score)
#[1]      NA 4.00000 4.30000 4.17000 4.25300 4.52770 4.27493

There is an enormous number of answers on Stack Overflow showing how to apply a function by groups ("split-apply-combine").

Upvotes: 3

Related Questions