## Measures of forecast accuracy
## Forecasts in f. This may be a numerical vector or the output from arima or ets or derivatives.
## Actual values in x
## test enables a subset of x and f to be tested.
forecasterrors <- function(f,x,test=1:length(x))
{
data.x <- dx <- NULL
if(is.list(f))
{
if(is.element("x",names(f)))
data.x <- f$x
if(is.element("mean",names(f)))
f = f$mean
else
stop("Unknown list structure")
}
n <- length(x)
ff <- f
xx <- x
dx <- data.x
error <- (xx-ff[1:n])[test]
me <- mean(error)
mse <- mean(error^2)
mae <- mean(abs(error))
mape <- mean(100*abs(error/xx[test]))
mpe <- mean(100*error/xx[test])
junk <- c(me,sqrt(mse),mae,mpe,mape)
names(junk) <- c("ME","RMSE","MAE","MPE","MAPE")
if(!is.null(tsp(data.x)))
{
if(!is.null(dx))
{
scale <- mean(abs(diff(dx)),na.rm=TRUE)
mase <- mean(abs(error/scale))
junk <- c(junk,mase)
names(junk)[6] <- "MASE"
}
if(n>1)
{
fpe <- (c(ff[2:n])/c(xx[1:(n-1)]) - 1)[test-1]
ape <- (c(xx[2:n])/c(xx[1:(n-1)]) - 1)[test-1]
theil <- sqrt(sum((fpe - ape)^2)/sum(ape^2))
r1 <- acf(error,plot=FALSE,lag.max=2)$acf[2,1,1]
nj <- length(junk)
junk <- c(junk,r1,theil)
names(junk)[nj+(1:2)] <- c("ACF1","Theil's U")
}
}
return(junk)
}
accuracy <- function(f,x,test=1:length(x))
{
if(!missing(x))
return(forecasterrors(f,x,test))
if(class(f)=="Arima" & !is.element("x", names(f)))
f$x <- eval(parse(text = f$series))
ff <- f$x
fits <- fitted(f) # Don't use f$resid as this may contain multiplicative errors.
res <- ff-fits
pe <- res/ff * 100 # Percentage error
out <- c(mean(res,na.rm=TRUE), sqrt(mean(res^2,na.rm=TRUE)), mean(abs(res),na.rm=TRUE), mean(pe,na.rm=TRUE), mean(abs(pe),na.rm=TRUE))
names(out) <- c("ME","RMSE","MAE","MPE","MAPE")
if(!is.null(tsp(f$x)))
{
scale <- mean(abs(diff(ff)),na.rm=TRUE)
out <- c(out, mean(abs(res/scale),na.rm=TRUE))
names(out)[6] <- "MASE"
}
return(out)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.