Augmented Dynamic Adaptive Model

Ivan Svetunkov

2021-09-22

This vignette explains briefly how to use the function adam() and the related auto.adam() in smooth package. It does not aim at covering all aspects of the function, but focuses on the main ones.

ADAM is Augmented Dynamic Adaptive Model. It is a model that underlies ETS, ARIMA and regression, connecting them in a unified framework. The underlying model for ADAM is a Single Source of Error state space model, which is explained in detail separately in an online textbook.

The main philosophy of adam() function is to be agnostic of the provided data. This means that it will work with ts, msts, zoo, xts, data.frame, numeric and other classes of data. The specification of seasonality in the model is done using a separate parameter lags, so you are not obliged to transform the existing data to something specific, and can use it as is. If you provide a matrix, or a data.frame, or a data.table, or any other multivariate structure, then the function will use the first column for the response variable and the others for the explanatory ones. One thing that is currently assumed in the function is that the data is measured at a regular frequency. If this is not the case, you will need to introduce missing values manually.

In order to run the experiments in this vignette, we need to load the following packages:

require(greybox)
require(smooth)
require(Mcomp)

ADAM ETS

First and foremost, ADAM implements ETS model, although in a more flexible way than (Hyndman et al. 2008): it supports different distributions for the error term, which are regulated via distribution parameter. By default, the additive error model relies on Normal distribution, while the multiplicative error one assumes Inverse Gaussian. If you want to reproduce the classical ETS, you would need to specify distribution="dnorm". Here is an example of ADAM ETS(MMM) with Normal distribution on a N2568 data from M3 competition (if you provide an Mcomp object, adam() will automatically set the train and test sets, the forecast horizon and even the needed lags):

testModel <- adam(M3[[2568]], "MMM", lags=c(1,12), distribution="dnorm")
summary(testModel)
#> 
#> Model estimated using adam() function: ETS(MMM)
#> Response variable: M3..2568..
#> Distribution used in the estimation: Normal
#> Loss function type: likelihood; Loss function value: 868.0131
#> Coefficients:
#>              Estimate Std. Error Lower 2.5% Upper 97.5%  
#> alpha          0.1443     0.0587     0.0278      0.2604 *
#> beta           0.0117     0.0122     0.0000      0.0358  
#> gamma          0.0000     0.0511     0.0000      0.1010  
#> level       4402.2393   159.8073  4085.1469   4718.3319 *
#> trend          1.0067     0.0030     1.0007      1.0126 *
#> seasonal_1     1.1793     0.0201     1.1540      1.2312 *
#> seasonal_2     0.8202     0.0141     0.7949      0.8721 *
#> seasonal_3     0.8261     0.0141     0.8008      0.8780 *
#> seasonal_4     1.5648     0.0263     1.5395      1.6168 *
#> seasonal_5     0.7420     0.0128     0.7167      0.7940 *
#> seasonal_6     1.2714     0.0218     1.2461      1.3233 *
#> seasonal_7     0.8925     0.0151     0.8672      0.9445 *
#> seasonal_8     0.9142     0.0158     0.8889      0.9662 *
#> seasonal_9     1.2289     0.0220     1.2036      1.2809 *
#> seasonal_10    0.8835     0.0160     0.8581      0.9354 *
#> seasonal_11    0.8383     0.0152     0.8130      0.8902 *
#> 
#> Sample size: 116
#> Number of estimated parameters: 17
#> Number of degrees of freedom: 99
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 1770.026 1776.271 1816.837 1831.680
plot(forecast(testModel,h=18,interval="prediction"))

You might notice that the summary contains more than what is reported by other smooth functions. This one also produces standard errors for the estimated parameters based on Fisher Information calculation. Note that this is computationally expensive, so if you have a model with more than 30 variables, the calculation of standard errors might take plenty of time. As for the default print() method, it will produce a shorter summary from the model, without the standard errors (similar to what es() does):

testModel
#> Time elapsed: 0.12 seconds
#> Model estimated using adam() function: ETS(MMM)
#> Distribution assumed in the model: Normal
#> Loss function type: likelihood; Loss function value: 868.0131
#> Persistence vector g:
#>  alpha   beta  gamma 
#> 0.1443 0.0117 0.0000 
#> 
#> Sample size: 116
#> Number of estimated parameters: 17
#> Number of degrees of freedom: 99
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 1770.026 1776.271 1816.837 1831.680 
#> 
#> Forecast errors:
#> ME: 640.429; MAE: 824.738; RMSE: 1045.357
#> sCE: 158.358%; Asymmetry: 73.7%; sMAE: 11.33%; sMSE: 2.062%
#> MASE: 0.336; RMSSE: 0.33; rMAE: 0.364; rRMSE: 0.344

Also, note that the prediction interval in case of multiplicative error models are approximate. It is advisable to use simulations instead (which is slower, but more accurate):

plot(forecast(testModel,h=18,interval="simulated"))

If you want to do the residuals diagnostics, then it is recommended to use plot function, something like this (you can select, which of the plots to produce):

par(mfcol=c(3,4))
plot(testModel,which=c(1:11))
par(mfcol=c(1,1))
plot(testModel,which=12)

By default ADAM will estimate models via maximising likelihood function. But there is also a parameter loss, which allows selecting from a list of already implemented loss functions (again, see documentation for adam() for the full list) or using a function written by a user. Here is how to do the latter on the example of another M3 series:

lossFunction <- function(actual, fitted, B){
  return(sum(abs(actual-fitted)^3))
}
testModel <- adam(M3[[1234]], "AAN", silent=FALSE, loss=lossFunction)
testModel
#> Time elapsed: 0.02 seconds
#> Model estimated using adam() function: ETS(AAN)
#> Distribution assumed in the model: Normal
#> Loss function type: custom; Loss function value: 23995002
#> Persistence vector g:
#>  alpha   beta 
#> 0.6285 0.2467 
#> 
#> Sample size: 45
#> Number of estimated parameters: 4
#> Number of degrees of freedom: 41
#> Information criteria are unavailable for the chosen loss & distribution.
#> 
#> Forecast errors:
#> ME: -346.531; MAE: 346.531; RMSE: 394.992
#> sCE: -34.049%; Asymmetry: -100%; sMAE: 4.256%; sMSE: 0.235%
#> MASE: 4.795; RMSSE: 4.411; rMAE: 3.938; rRMSE: 3.563

Note that you need to have parameters actual, fitted and B in the function, which correspond to the vector of actual values, vector of fitted values on each iteration and a vector of the optimised parameters.

loss and distribution parameters are independent, so in the example above, we have assumed that the error term follows Normal distribution, but we have estimated its parameters using a non-conventional loss because we can. Some of distributions assume that there is an additional parameter, which can either be estimated or provided by user. These include Asymmetric Laplace (distribution="dalaplace") with alpha, Generalised Normal and Log Generalised normal (distribution=c("gnorm","dlgnorm")) with shape and Student’s T (distribution="dt") with nu:

testModel <- adam(M3[[1234]], "MMN", silent=FALSE, distribution="dgnorm", shape=3)

The model selection in ADAM ETS relies on information criteria and works correctly only for the loss="likelihood". There are several options, how to select the model, see them in the description of the function: ?adam(). The default one uses branch-and-bound algorithm, similar to the one used in es(), but only considers additive trend models (the multiplicative trend ones are less stable and need more attention from a forecaster):

testModel <- adam(M3[[2568]], "ZXZ", lags=c(1,12), silent=FALSE)
#> Forming the pool of models based on... ANN , ANA , MNM , MAM , Estimation progress:    71 %86 %100 %... Done!
testModel
#> Time elapsed: 0.52 seconds
#> Model estimated using adam() function: ETS(MAM)
#> Distribution assumed in the model: Gamma
#> Loss function type: likelihood; Loss function value: 865.0333
#> Persistence vector g:
#>  alpha   beta  gamma 
#> 0.0926 0.0000 0.0000 
#> 
#> Sample size: 116
#> Number of estimated parameters: 17
#> Number of degrees of freedom: 99
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 1764.066 1770.311 1810.878 1825.720 
#> 
#> Forecast errors:
#> ME: 144.73; MAE: 643.485; RMSE: 758.298
#> sCE: 35.787%; Asymmetry: 26%; sMAE: 8.84%; sMSE: 1.085%
#> MASE: 0.262; RMSSE: 0.239; rMAE: 0.284; rRMSE: 0.25

Note that the function produces point forecasts if h>0, but it won’t generate prediction interval. This is why you need to use forecast() method (as shown in the first example in this vignette).

Similarly to es(), function supports combination of models, but it saves all the tested models in the output for a potential reuse. Here how it works:

testModel <- adam(M3[[2568]], "CXC", lags=c(1,12))
testForecast <- forecast(testModel,h=18,interval="semiparametric", level=c(0.9,0.95))
testForecast
#>          Point forecast Lower bound (5%) Lower bound (2.5%) Upper bound (95%)
#> Sep 1992      11148.352        10051.459           9852.399         12292.611
#> Oct 1992       8043.222         7239.286           7093.523          8882.447
#> Nov 1992       7677.836         6919.307           6781.684          8469.258
#> Dec 1992      10491.816         9451.178           9262.414         11577.771
#> Jan 1993      10962.405         9907.600           9715.936         12061.708
#> Feb 1993       7567.024         6835.991           6703.187          8329.024
#> Mar 1993       7703.665         6946.885           6809.535          8493.067
#> Apr 1993      14538.393        13127.451          12871.200         16009.399
#> May 1993       6945.409         6270.109           6147.474          7649.507
#> Jun 1993      11954.270        10790.270          10578.907         13167.993
#> Jul 1993       8423.623         7630.540           7486.259          9249.412
#> Aug 1993       8637.314         7811.957           7661.928          9497.240
#> Sep 1993      11724.187        10524.574          10307.374         12977.776
#> Oct 1993       8456.908         7586.741           7429.242          9366.454
#> Nov 1993       8071.048         7242.661           7092.702          8936.825
#> Dec 1993      11026.836         9877.993           9670.213         12228.361
#> Jan 1994      11519.057        10338.273          10124.506         12753.076
#> Feb 1994       7949.669         7118.877           6968.647          8818.681
#>          Upper bound (97.5%)
#> Sep 1992           12523.212
#> Oct 1992            9051.709
#> Nov 1992            8628.784
#> Dec 1992           11796.711
#> Jan 1993           12283.004
#> Feb 1993            8482.448
#> Mar 1993            8652.141
#> Apr 1993           16305.648
#> May 1993            7791.318
#> Jun 1993           13412.467
#> Jul 1993            9415.472
#> Aug 1993            9670.290
#> Sep 1993           13230.918
#> Oct 1993            9550.175
#> Nov 1993            9111.683
#> Dec 1993           12471.222
#> Jan 1994           13002.292
#> Feb 1994            8994.360
plot(testForecast)

Yes, now we support vectors for the levels in case you want to produce several. In fact, we also support side for prediction interval, so you can extract specific quantiles without a hustle:

forecast(testModel,h=18,interval="semiparametric", level=c(0.9,0.95,0.99), side="upper")
#>          Point forecast Upper bound (90%) Upper bound (95%) Upper bound (99%)
#> Sep 1992      11148.352         12030.248         12292.611         12794.905
#> Oct 1992       8043.222          8689.912          8882.447          9251.173
#> Nov 1992       7677.836          8287.769          8469.258          8816.747
#> Dec 1992      10491.816         11328.703         11577.771         12054.691
#> Jan 1993      10962.405         11809.860         12061.708         12543.660
#> Feb 1993       7567.024          8154.426          8329.024          8663.169
#> Mar 1993       7703.665          8312.080          8493.067          8839.557
#> Apr 1993      14538.393         15672.288         16009.399         16654.625
#> May 1993       6945.409          7488.139          7649.507          7958.374
#> Jun 1993      11954.270         12889.810         13167.993         13700.466
#> Jul 1993       8423.623          9060.373          9249.412          9611.015
#> Aug 1993       8637.314          9300.282          9497.240          9874.100
#> Sep 1993      11724.187         12689.918         12977.776         13529.323
#> Oct 1993       8456.908          9157.552          9366.454          9766.762
#> Nov 1993       8071.048          8737.996          8936.825          9317.814
#> Dec 1993      11026.836         11952.263         12228.361         12757.577
#> Jan 1994      11519.057         12469.691         12753.076         13296.075
#> Feb 1994       7949.669          8618.967          8818.681          9201.510

A brand new thing in the function is the possibility to use several frequencies (double / triple / quadruple / … seasonal models). In order to show how it works, we will generate an artificial time series, inspired by half-hourly electricity demand using sim.gum() function:

ordersGUM <- c(1,1,1)
lagsGUM <- c(1,48,336)
initialGUM1 <- -25381.7
initialGUM2 <- c(23955.09, 24248.75, 24848.54, 25012.63, 24634.14, 24548.22, 24544.63, 24572.77,
                 24498.33, 24250.94, 24545.44, 25005.92, 26164.65, 27038.55, 28262.16, 28619.83,
                 28892.19, 28575.07, 28837.87, 28695.12, 28623.02, 28679.42, 28682.16, 28683.40,
                 28647.97, 28374.42, 28261.56, 28199.69, 28341.69, 28314.12, 28252.46, 28491.20,
                 28647.98, 28761.28, 28560.11, 28059.95, 27719.22, 27530.23, 27315.47, 27028.83,
                 26933.75, 26961.91, 27372.44, 27362.18, 27271.31, 26365.97, 25570.88, 25058.01)
initialGUM3 <- c(23920.16, 23026.43, 22812.23, 23169.52, 23332.56, 23129.27, 22941.20, 22692.40,
                 22607.53, 22427.79, 22227.64, 22580.72, 23871.99, 25758.34, 28092.21, 30220.46,
                 31786.51, 32699.80, 33225.72, 33788.82, 33892.25, 34112.97, 34231.06, 34449.53,
                 34423.61, 34333.93, 34085.28, 33948.46, 33791.81, 33736.17, 33536.61, 33633.48,
                 33798.09, 33918.13, 33871.41, 33403.75, 32706.46, 31929.96, 31400.48, 30798.24,
                 29958.04, 30020.36, 29822.62, 30414.88, 30100.74, 29833.49, 28302.29, 26906.72,
                 26378.64, 25382.11, 25108.30, 25407.07, 25469.06, 25291.89, 25054.11, 24802.21,
                 24681.89, 24366.97, 24134.74, 24304.08, 25253.99, 26950.23, 29080.48, 31076.33,
                 32453.20, 33232.81, 33661.61, 33991.21, 34017.02, 34164.47, 34398.01, 34655.21,
                 34746.83, 34596.60, 34396.54, 34236.31, 34153.32, 34102.62, 33970.92, 34016.13,
                 34237.27, 34430.08, 34379.39, 33944.06, 33154.67, 32418.62, 31781.90, 31208.69,
                 30662.59, 30230.67, 30062.80, 30421.11, 30710.54, 30239.27, 28949.56, 27506.96,
                 26891.75, 25946.24, 25599.88, 25921.47, 26023.51, 25826.29, 25548.72, 25405.78,
                 25210.45, 25046.38, 24759.76, 24957.54, 25815.10, 27568.98, 29765.24, 31728.25,
                 32987.51, 33633.74, 34021.09, 34407.19, 34464.65, 34540.67, 34644.56, 34756.59,
                 34743.81, 34630.05, 34506.39, 34319.61, 34110.96, 33961.19, 33876.04, 33969.95,
                 34220.96, 34444.66, 34474.57, 34018.83, 33307.40, 32718.90, 32115.27, 31663.53,
                 30903.82, 31013.83, 31025.04, 31106.81, 30681.74, 30245.70, 29055.49, 27582.68,
                 26974.67, 25993.83, 25701.93, 25940.87, 26098.63, 25771.85, 25468.41, 25315.74,
                 25131.87, 24913.15, 24641.53, 24807.15, 25760.85, 27386.39, 29570.03, 31634.00,
                 32911.26, 33603.94, 34020.90, 34297.65, 34308.37, 34504.71, 34586.78, 34725.81,
                 34765.47, 34619.92, 34478.54, 34285.00, 34071.90, 33986.48, 33756.85, 33799.37,
                 33987.95, 34047.32, 33924.48, 33580.82, 32905.87, 32293.86, 31670.02, 31092.57,
                 30639.73, 30245.42, 30281.61, 30484.33, 30349.51, 29889.23, 28570.31, 27185.55,
                 26521.85, 25543.84, 25187.82, 25371.59, 25410.07, 25077.67, 24741.93, 24554.62,
                 24427.19, 24127.21, 23887.55, 24028.40, 24981.34, 26652.32, 28808.00, 30847.09,
                 32304.13, 33059.02, 33562.51, 33878.96, 33976.68, 34172.61, 34274.50, 34328.71,
                 34370.12, 34095.69, 33797.46, 33522.96, 33169.94, 32883.32, 32586.24, 32380.84,
                 32425.30, 32532.69, 32444.24, 32132.49, 31582.39, 30926.58, 30347.73, 29518.04,
                 29070.95, 28586.20, 28416.94, 28598.76, 28529.75, 28424.68, 27588.76, 26604.13,
                 26101.63, 25003.82, 24576.66, 24634.66, 24586.21, 24224.92, 23858.42, 23577.32,
                 23272.28, 22772.00, 22215.13, 21987.29, 21948.95, 22310.79, 22853.79, 24226.06,
                 25772.55, 27266.27, 28045.65, 28606.14, 28793.51, 28755.83, 28613.74, 28376.47,
                 27900.76, 27682.75, 27089.10, 26481.80, 26062.94, 25717.46, 25500.27, 25171.05,
                 25223.12, 25634.63, 26306.31, 26822.46, 26787.57, 26571.18, 26405.21, 26148.41,
                 25704.47, 25473.10, 25265.97, 26006.94, 26408.68, 26592.04, 26224.64, 25407.27,
                 25090.35, 23930.21, 23534.13, 23585.75, 23556.93, 23230.25, 22880.24, 22525.52,
                 22236.71, 21715.08, 21051.17, 20689.40, 20099.18, 19939.71, 19722.69, 20421.58,
                 21542.03, 22962.69, 23848.69, 24958.84, 25938.72, 26316.56, 26742.61, 26990.79,
                 27116.94, 27168.78, 26464.41, 25703.23, 25103.56, 24891.27, 24715.27, 24436.51,
                 24327.31, 24473.02, 24893.89, 25304.13, 25591.77, 25653.00, 25897.55, 25859.32,
                 25918.32, 25984.63, 26232.01, 26810.86, 27209.70, 26863.50, 25734.54, 24456.96)
y <- sim.gum(orders=ordersGUM, lags=lagsGUM, nsim=1, frequency=336, obs=3360,
             measurement=rep(1,3), transition=diag(3), persistence=c(0.045,0.162,0.375),
             initial=cbind(initialGUM1,initialGUM2,initialGUM3))$data

We can then apply ADAM to this data:

testModel <- adam(y, "MMdM", lags=c(1,48,336), initial="backcasting",
                  silent=FALSE, h=336, holdout=TRUE)
testModel
#> Time elapsed: 0.53 seconds
#> Model estimated using adam() function: ETS(MMdM)[48, 336]
#> Distribution assumed in the model: Gamma
#> Loss function type: likelihood; Loss function value: 22090.37
#> Persistence vector g:
#>  alpha   beta gamma1 gamma2 
#> 0.9813 0.0000 0.0187 0.0186 
#> Damping parameter: 0.9872
#> Sample size: 3024
#> Number of estimated parameters: 6
#> Number of degrees of freedom: 3018
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 44192.74 44192.77 44228.83 44228.94 
#> 
#> Forecast errors:
#> ME: 74.728; MAE: 745.664; RMSE: 965.984
#> sCE: 82.81%; Asymmetry: 12.8%; sMAE: 2.459%; sMSE: 0.101%
#> MASE: 1.001; RMSSE: 0.941; rMAE: 0.111; rRMSE: 0.117

Note that the more lags you have, the more initial seasonal components the function will need to estimate, which is a difficult task. This is why we used initial="backcasting" in the example above - this speeds up the estimation by reducing the number of parameters to estimate. Still, the optimiser might not get close to the optimal value, so we can help it. First, we can give more time for the calculation, increasing the number of iterations via maxeval (the default value is 40 iterations for each estimated parameter, e.g. \(40 \times 5 = 200\) in our case):

testModel <- adam(y, "MMdM", lags=c(1,48,336), initial="backcasting",
                  silent=FALSE, h=336, holdout=TRUE, maxeval=10000)
testModel
#> Time elapsed: 4.03 seconds
#> Model estimated using adam() function: ETS(MMdM)[48, 336]
#> Distribution assumed in the model: Gamma
#> Loss function type: likelihood; Loss function value: 19613.18
#> Persistence vector g:
#>  alpha   beta gamma1 gamma2 
#> 0.0287 0.0000 0.1607 0.2461 
#> Damping parameter: 0.9996
#> Sample size: 3024
#> Number of estimated parameters: 6
#> Number of degrees of freedom: 3018
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 39238.37 39238.40 39274.45 39274.57 
#> 
#> Forecast errors:
#> ME: 164.419; MAE: 204.501; RMSE: 245.136
#> sCE: 182.202%; Asymmetry: 80.8%; sMAE: 0.674%; sMSE: 0.007%
#> MASE: 0.274; RMSSE: 0.239; rMAE: 0.03; rRMSE: 0.03

This will take more time, but will typically lead to more refined parameters. You can control other parameters of the optimiser as well, such as algorithm, xtol_rel, print_level and others, which are explained in the documentation for nloptr function from nloptr package (run nloptr.print.options() for details). Second, we can give a different set of initial parameters for the optimiser, have a look at what the function saves:

testModel$B

and use this as a starting point for the reestimation (e.g. with a different algorithm):

testModel <- adam(y, "MMdM", lags=c(1,48,336), initial="backcasting",
                  silent=FALSE, h=336, holdout=TRUE, B=testModel$B)
testModel
#> Time elapsed: 0.38 seconds
#> Model estimated using adam() function: ETS(MMdM)[48, 336]
#> Distribution assumed in the model: Gamma
#> Loss function type: likelihood; Loss function value: 19613.18
#> Persistence vector g:
#>  alpha   beta gamma1 gamma2 
#> 0.0287 0.0000 0.1607 0.2461 
#> Damping parameter: 0.9996
#> Sample size: 3024
#> Number of estimated parameters: 6
#> Number of degrees of freedom: 3018
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 39238.37 39238.40 39274.45 39274.57 
#> 
#> Forecast errors:
#> ME: 164.419; MAE: 204.501; RMSE: 245.136
#> sCE: 182.202%; Asymmetry: 80.8%; sMAE: 0.674%; sMSE: 0.007%
#> MASE: 0.274; RMSSE: 0.239; rMAE: 0.03; rRMSE: 0.03

If you are ready to wait, you can change the initialisation to the initial="optimal", which in our case will take much more time because of the number of estimated parameters - 389 for the chosen model. The estimation process in this case might take 20 - 30 times more than in the example above.

In addition, you can specify some parts of the initial state vector or some parts of the persistence vector, here is an example:

testModel <- adam(y, "MMdM", lags=c(1,48,336), initial="backcasting",
                  silent=TRUE, h=336, holdout=TRUE, persistence=list(beta=0.1))
testModel
#> Time elapsed: 0.48 seconds
#> Model estimated using adam() function: ETS(MMdM)[48, 336]
#> Distribution assumed in the model: Gamma
#> Loss function type: likelihood; Loss function value: 21892.15
#> Persistence vector g:
#>  alpha   beta gamma1 gamma2 
#> 0.9671 0.1000 0.0318 0.0329 
#> Damping parameter: 0.6289
#> Sample size: 3024
#> Number of estimated parameters: 5
#> Number of degrees of freedom: 3019
#> Number of provided parameters: 1
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 43794.31 43794.33 43824.38 43824.46 
#> 
#> Forecast errors:
#> ME: 181.969; MAE: 764.319; RMSE: 982.44
#> sCE: 201.65%; Asymmetry: 26.9%; sMAE: 2.521%; sMSE: 0.105%
#> MASE: 1.026; RMSSE: 0.957; rMAE: 0.113; rRMSE: 0.119

The function also handles intermittent data (the data with zeroes) and the data with missing values. This is partially covered in the vignette on the oes() function. Here is a simple example:

testModel <- adam(rpois(120,0.5), "MNN", silent=FALSE, h=12, holdout=TRUE,
                  occurrence="odds-ratio")
testModel
#> Time elapsed: 0.04 seconds
#> Model estimated using adam() function: iETS(MNN)[O]
#> Occurrence model type: Odds ratio
#> Distribution assumed in the model: Mixture of Bernoulli and Gamma
#> Loss function type: likelihood; Loss function value: 27.4311
#> Persistence vector g:
#> alpha 
#>     0 
#> 
#> Sample size: 108
#> Number of estimated parameters: 5
#> Number of degrees of freedom: 103
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 211.5729 211.8037 224.9836 216.1596 
#> 
#> Forecast errors:
#> Asymmetry: -20.667%; sMSE: 39.845%; rRMSE: 0.881; sPIS: 1921.526%; sCE: -72.808%

Finally, adam() is faster than es() function, because its code is more efficient and it uses a different optimisation algorithm with more finely tuned parameters by default. Let’s compare:

adamModel <- adam(M3[[2568]], "CCC")
esModel <- es(M3[[2568]], "CCC")
"adam:"
#> [1] "adam:"
adamModel
#> Time elapsed: 2.04 seconds
#> Model estimated: ETS(CCC)
#> Loss function type: likelihood
#> 
#> Number of models combined: 30
#> Sample size: 116
#> Average number of estimated parameters: 28.0813
#> Average number of degrees of freedom: 87.9187
#> 
#> Forecast errors:
#> ME: 484.288; MAE: 750.839; RMSE: 925.585
#> sCE: 119.749%; sMAE: 10.314%; sMSE: 1.617%
#> MASE: 0.306; RMSSE: 0.292; rMAE: 0.332; rRMSE: 0.305
"es():"
#> [1] "es():"
esModel
#> Time elapsed: 3.87 seconds
#> Model estimated: ETS(CCC)
#> Initial values were optimised.
#> 
#> Loss function type: likelihood
#> Error standard deviation: 414.1228
#> Sample size: 116
#> Information criteria:
#> (combined values)
#>      AIC     AICc      BIC     BICc 
#> 1763.821 1769.594 1807.909 1820.587 
#> 
#> Forecast errors:
#> MPE: 2.9%; sCE: 91.1%; Asymmetry: 49.3%; MAPE: 6.7%
#> MASE: 0.285; sMAE: 9.6%; sMSE: 1.4%; rMAE: 0.31; rRMSE: 0.281

ADAM ARIMA

As mentioned above, ADAM does not only contain ETS, it also contains ARIMA model, which is regulated via orders parameter. If you want to have a pure ARIMA, you need to switch off ETS, which is done via model="NNN":

testModel <- adam(M3[[1234]], "NNN", silent=FALSE, orders=c(0,2,2))
testModel
#> Time elapsed: 0.05 seconds
#> Model estimated using adam() function: ARIMA(0,2,2)
#> Distribution assumed in the model: Normal
#> Loss function type: likelihood; Loss function value: 255.2931
#> ARMA parameters of the model:
#> MA:
#> theta1[1] theta2[1] 
#>   -1.0912    0.3217 
#> 
#> Sample size: 45
#> Number of estimated parameters: 5
#> Number of degrees of freedom: 40
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 520.5863 522.1247 529.6196 532.5478 
#> 
#> Forecast errors:
#> ME: -348.365; MAE: 348.365; RMSE: 396.598
#> sCE: -34.23%; Asymmetry: -100%; sMAE: 4.279%; sMSE: 0.237%
#> MASE: 4.82; RMSSE: 4.429; rMAE: 3.959; rRMSE: 3.578

Given that both models are implemented in the same framework, they can be compared using information criteria.

The functionality of ADAM ARIMA is similar to the one of msarima function in smooth package, although there are several differences.

First, changing the distribution parameter will allow switching between additive / multiplicative models. For example, distribution="dlnorm" will create an ARIMA, equivalent to the one on logarithms of the data:

testModel <- adam(M3[[2568]], "NNN", silent=FALSE, lags=c(1,12),
                  orders=list(ar=c(1,1),i=c(1,1),ma=c(2,2)), distribution="dlnorm")
testModel
#> Time elapsed: 0.75 seconds
#> Model estimated using adam() function: SARIMA(1,1,2)[1](1,1,2)[12]
#> Distribution assumed in the model: Log Normal
#> Loss function type: likelihood; Loss function value: 871.1066
#> ARMA parameters of the model:
#> AR:
#>  phi1[1] phi1[12] 
#>  -0.5397   0.0428 
#> MA:
#>  theta1[1]  theta2[1] theta1[12] theta2[12] 
#>    -0.3543    -0.4905    -0.4019    -0.2538 
#> 
#> Sample size: 116
#> Number of estimated parameters: 33
#> Number of degrees of freedom: 83
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 1808.213 1835.579 1899.082 1964.125 
#> 
#> Forecast errors:
#> ME: 235.386; MAE: 559.775; RMSE: 677.465
#> sCE: 58.203%; Asymmetry: 42.4%; sMAE: 7.69%; sMSE: 0.866%
#> MASE: 0.228; RMSSE: 0.214; rMAE: 0.247; rRMSE: 0.223

Second, if you want the model with intercept / drift, you can do it using constant parameter:

testModel <- adam(M3[[2568]], "NNN", silent=FALSE, lags=c(1,12), constant=TRUE,
                  orders=list(ar=c(1,1),i=c(1,1),ma=c(2,2)), distribution="dnorm")
testModel
#> Time elapsed: 0.77 seconds
#> Model estimated using adam() function: SARIMA(1,1,2)[1](1,1,2)[12] with drift
#> Distribution assumed in the model: Normal
#> Loss function type: likelihood; Loss function value: 894.215
#> ARMA parameters of the model:
#> AR:
#>  phi1[1] phi1[12] 
#>  -0.5503   0.0421 
#> MA:
#>  theta1[1]  theta2[1] theta1[12] theta2[12] 
#>    -0.5118    -0.3392    -0.2967     0.0475 
#> 
#> Sample size: 116
#> Number of estimated parameters: 34
#> Number of degrees of freedom: 82
#> Information criteria:
#>      AIC     AICc      BIC     BICc 
#> 1856.430 1885.813 1950.052 2019.889 
#> 
#> Forecast errors:
#> ME: 363.528; MAE: 658.679; RMSE: 771.884
#> sCE: 89.889%; Asymmetry: 54.9%; sMAE: 9.048%; sMSE: 1.124%
#> MASE: 0.268; RMSSE: 0.244; rMAE: 0.291; rRMSE: 0.254