<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Archives smooth - Open Forecasting</title>
	<atom:link href="https://openforecast.org/tag/smooth/feed/" rel="self" type="application/rss+xml" />
	<link>https://openforecast.org/tag/smooth/</link>
	<description>How to look into the future</description>
	<lastBuildDate>Wed, 15 Apr 2026 09:32:22 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2015/08/cropped-usd-05-32x32.png&amp;nocache=1</url>
	<title>Archives smooth - Open Forecasting</title>
	<link>https://openforecast.org/tag/smooth/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>smooth forecasting with the smooth package in Python</title>
		<link>https://openforecast.org/2026/04/09/smooth-forecasting-with-the-smooth-package-in-python/</link>
					<comments>https://openforecast.org/2026/04/09/smooth-forecasting-with-the-smooth-package-in-python/#respond</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Thu, 09 Apr 2026 09:15:02 +0000</pubDate>
				<category><![CDATA[ETS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Univariate models]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3961</guid>

					<description><![CDATA[<p>Here is another piece of news I have been hoping to deliver for quite some time now (since January 2026 actually). We have finally created the first release of the smooth package for Python and it is available on PyPI! Anyone interested? Read more! On this page: Why does &#8220;smooth&#8221; exist? A bit of history [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2026/04/09/smooth-forecasting-with-the-smooth-package-in-python/">smooth forecasting with the smooth package in Python</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Here is another piece of news I have been hoping to deliver for quite some time now (since January 2026 actually). We have finally created the first release of the smooth package for Python and it is available on PyPI! Anyone interested? Read more!</p>
<p>On this page:</p>
<ul>
<li><a href="#whySmooth">Why does &#8220;smooth&#8221; exist?</a></li>
<li><a href="#history">A bit of history</a></li>
<li><a href="#install">How to install</a></li>
<li><a href="#whatWorks">What works</a></li>
<li><a href="#example">An example</a></li>
<li><a href="#evaluation">Evaluation</a></li>
<ul>
<li><a href="#evaluationSetup">Setup</a></li>
<li><a href="https://github.com/config-i1/smooth/blob/master/python/tests/notebooks/benchmark_exponential_smoothing.ipynb">Jupiter notebook</a></li>
<li><a href="#sktime">sktime non-collaborative stance</a></li>
<li><a href="#evaluationResults">Results</a></li>
</ul>
<li><a href="#whatsNext">What&#8217;s next?</a></li>
<li><a href="#summary">Summary</a></li>
</ul>
<h2 id="whySmooth">Why does &#8220;smooth&#8221; exist?</h2>
<p>There are lots of implementations of ETS and ARIMA (dynamic models) out there, both in Python and in R (and also in Julia now, <a href="https://github.com/taf-society/Durbyn.jl">see Durbyn</a>). So, why bother creating yet another one?</p>
<p>The main philosophy of the smooth package in R is flexibility. It is not just an implementation of ETS or ARIMA &#8211; it is there to give you more control over what you can do with these models in different situations. The main function in the package is called <a href="https://openforecast.org/adam/">&#8220;ADAM&#8221; &#8211; the Augmented Dynamic Adaptive Model</a>. It is the single source of error state space model that unites ETS, ARIMA, and regression, and supports the following list of features (taken from the Introduction in <a href="https://openforecast.org/adam/">the book</a>):</p>
<ol>
<li>ETS;</li>
<li>ARIMA;</li>
<li>Regression;</li>
<li>TVP regression;</li>
<li>Combination of (1), (2), and either (3) or (4). i.e. ARIMAX/ETSX;</li>
<li>Automatic selection/combination of states for ETS;</li>
<li>Automatic orders selection for ARIMA;</li>
<li>Variables selection for regression;</li>
<li>Normal and non-normal distributions;</li>
<li>Automatic selection of most suitable distributions;</li>
<li>Multiple seasonality;</li>
<li>Occurrence part of the model to handle zeroes in data (intermittent demand);</li>
<li>Modelling scale of distribution (GARCH and beyond);</li>
<li>A variety of ways to produce forecasts for different situation;</li>
<li>Advanced loss functions for model estimation;</li>
<li>&#8230;</li>
</ol>
<p>All of these features come with the ability to fine tune the optimiser (e.g. how the parameters are estimated) and to manually adjust any model parameters you want. This allows, for example, fitting iETSX(M,N,M) with multiple frequencies with Gamma distribution to better model <a href="/2023/05/10/story-of-probabilistic-forecasting-of-hourly-emergency-department-arrivals/">hourly emergency department arrivals (intermittent demand) and thus producing more accurate forecasts of it</a>. There is no other package either in R or Python that could give such flexibility with the dynamic models to users.</p>
<p>And at the same time, over the years, I have managed to iron out the R functions so much that they handle almost any real life situation and do not break. And at the same time, they work quite fast and produce accurate forecasts, <a href="/2026/02/09/smooth-v4-4-0/#evaluationResults">sometimes outperforming the other existing R implementations</a>.</p>
<p>So, here we are. We want to bring this flexibility, robustness, and speed to <strong>Python</strong>.</p>
<h2 id="history">A bit of history</h2>
<p>The smooth package for R was first released on CRAN in 2016, when I finished my PhD. It went from v1.4.3 to v4.4.0 over the last 10 years. It saw a rise in popularity, but then an inevitable decline due to the decreasing number of R users in business. So, back in 2021, Rebecca Killick and I applied for an EPSRC grant to develop Python packages for forecasting and time series analysis. The idea was to translate what we have in R (including greybox, smooth, forecast, and changepoint detection packages) to Python with the help of professional programmers. Unfortunately, we did not receive the funding (it went to sktime for a good reason &#8211; they already had an existing codebase in Python).</p>
<p>In the beginning of 2023, Leonidas Tsaprounis got in touch with me, suggesting some help with the development and translation of the smooth package to Python. The idea was to use the existing C++ core and simply create a wrapper in Python. &#8220;Simply&#8221; is actually an oversimplification here, because I am not a programmer, so my functions are messy and hard to read. Nonetheless, we started cooking. Leo helped in setting up pybind11 and carma, and creating the necessary files for the compilation of the C++ code. Just to test whether that worked, we managed to create a basic function for the simple moving average based on the <code>sma()</code> from the R version. Our progress was a bit slow, because we were both busy with other projects. All of that changed when in July 2023 Filotas Theodosiou joined our small team and started working on the translation. We decided to implement the hardest thing first &#8211; <a href="/adam/">ADAM</a>.</p>
<p>What Fil did was use LLMs to translate the code from R to Python. Fil will write about this work at some point; the only thing I can say here is that it was not an easy process, because thousands of lines of R code needed to be translated to Python and then refactored. I only helped with suggestions and explanations of what is happening inside, and Leo provided guidance regarding the coding philosophy. It was Fil and his AI tools that did the main heavy lifting. By Summer 2025, we had a basic working ADAM() function, but it worked slightly differently from the one in R due to differences in initialisation and optimisation. He presented his work at the <a href="/2025/06/30/iif-open-source-forecasting-software-workshop-and-smooth/">IIF Open Source Forecasting Software Workshop</a>, explaining his experience with LLMs and code translation. Because everyone was pretty busy, it took a bit more time to reach the first proper release of smooth in Python.</p>
<p>In December 2025, I bought a Claude AI subscription and started vibe coding my way through the existing Python code. Between the three of us, we managed to progress the project, and finally in January 2026 we reached v1.0.0 of smooth in Python. Now ADAM works in exactly the same way in both R and Python: if you give it the same time series, it will select the same model and produce the same parameter estimates across languages. It took us time and effort to reach this, but we feel it is a critically important step &#8211; ensuring that users working in different languages have the same experience.</p>
<h2 id="install">How to install</h2>
<p>We are entirely grateful to Gustavo Niemeyer, who gave us the name <code>smooth</code> on PyPI. It belonged to him since 2020, but the project was abandoned, and he agreed to transfer it to us. So, now you can install smooth simply by running:</p>
<pre class="decode">pip install smooth</pre>
<p>There is also a development version of the package, which you can install by following the instructions in our <a href="https://github.com/config-i1/smooth/wiki/Installation#python">Installation wiki</a> on GitHub.</p>
<h2 id="whatWorks">What works</h2>
<p>The package currently does not have the full functionality, but there are already some things:</p>
<ol>
<li><code>ADAM()</code> &#8211; the main function that supports ETS with:
<ul>
<li>components selection via <code>model="ZXZ"</code> or other pools (see <a href="https://github.com/config-i1/smooth/wiki/ADAM">wiki on GitHub for details</a>);</li>
<li>forecast combination using AIC weights via <code>model="CCC"</code> or other pools (again, explained in the wiki);</li>
<li>multiple seasonalities via <code>lags=[24,168]</code>;</li>
<li>ability to provide some smoothing parameters or initial values (e.g. only alpha), letting the function estimate the rest;</li>
<li>different distributions;</li>
<li>advanced <a href="https://github.com/config-i1/smooth/wiki/Loss-Functions">loss functions</a>;</li>
<li>several options for <a href="https://github.com/config-i1/smooth/wiki/Initialisation">model initialisation</a>;</li>
<li>fine-tuning of the optimiser via <code>nlopt_kargs</code> (<a href="https://github.com/config-i1/smooth/wiki/Model-Estimation">read more in the wiki</a>);</li>
</ul>
</li>
<li><code>ES()</code> &#8211; the wrapper of <code>ADAM()</code> with the normal distribution. Supports the same functionality, but is a simplification of ADAM.</li>
</ol>
<p>We also have the standard methods for fitting and forecasting, and many attributes that allow extracting information from the model, all of which are <a href="https://github.com/config-i1/smooth/wiki/Fitted-Values-and-Forecasts">explained in the wiki of the project</a>.</p>
<h2 id="example">An example</h2>
<p>Here is an example of how to work with ADAM in Python. For this example to work, you will need to install the <code>fcompdata</code> package from pip:<br />
<code>pip install fcompdata</code></p>
<p>The example:</p>
<pre class="decode">from smooth import ADAM
from fcompdata import M3

model = ADAM(model="ZXZ", lags=12)
model.fit(M3[2568].x)

print(model)</pre>
<p>This is what you should see as the result of print:</p>
<pre>Time elapsed: 0.21 seconds
Model estimated using ADAM() function: ETS(MAM)
With backcasting initialisation
Distribution assumed in the model: Gamma
Loss function type: likelihood; Loss function value: 868.7085
Persistence vector g:
 alpha   beta  gamma
0.0205 0.0203 0.1568
Damping parameter: 1.0000
Sample size: 116
Number of estimated parameters: 4
Number of degrees of freedom: 112
Information criteria:
      AIC      AICc       BIC      BICc
1745.4170 1745.7774 1756.4314 1757.2879</pre>
<p>which is exactly the same output as in R (see, for example, some explanations <a href="https://openforecast.org/adam/ADAMETSPureAdditiveExamples.html">here</a>). We can then produce a forecast from this model:</p>
<pre class="decode">predict(model, h=18, interval="prediction", level=[0.9,0.95])</pre>
<p>The predict method currently supports analytical (aka &#8220;parametric&#8221;/&#8221;approximate&#8221;) and simulated prediction intervals. The <code>interval="prediction"</code> will tell the function to choose between the two depending on the type of model (multiplicative ETS models do not have analytical formulae for the multistep conditional variance and, as a result, do not have proper analytical prediction intervals). The <code>level</code> parameter can accept either a vector (which will produce several quantiles) or a scalar. What I get after running this is:</p>
<pre>             mean    lower_0.05   lower_0.025    upper_0.95   upper_0.975
116  11234.592643  10061.150811   9853.119370  12443.904763  12686.143870
117   8050.810544   7228.709864   7064.356429   8896.078713   9080.867866
118   7658.608163   6886.165498   6746.881596   8475.545469   8633.149796
119  10552.382933   9452.306261   9236.493206  11679.816814  11892.381046
120  10889.816551   9768.665327   9559.580233  12066.628218  12313.872205
121   7409.545388   6643.378080   6495.237349   8232.558913   8363.550598
122   7591.183726   6800.878319   6650.514904   8425.167556   8576.257297
123  14648.452226  13089.346824  12793.226771  16263.206997  16582.786939
124   6953.045603   6206.829418   6079.126523   7730.260301   7892.917098
125  11938.941882  10650.759513  10427.172989  13307.563498  13579.662925
126   8299.626845   7379.550080   7200.075336   9280.095498   9468.327654
127   8508.558884   7530.987557   7367.541698   9534.117611   9734.218257
128  11552.654541  10162.615284   9907.770755  13039.710057  13313.534412
129   8286.727505   7273.279560   7100.450038   9401.374461   9627.922116
130   7889.999721   6879.771040   6710.494741   8948.052817   9186.279622
131  10860.671447   9438.536335   9174.365147  12353.444279  12664.983138
132  11218.330395   9690.780430   9453.114931  12849.545829  13201.679610
133   7620.922782   6564.497975   6391.080974   8748.561119   8977.120673</pre>
<p>The separate wiki on <a href="https://github.com/config-i1/smooth/wiki/Fitted-Values-and-Forecasts#level-parameter">Fitted Values and Forecasts</a> explains all the parameters accepted by the predict method and what is returned by it.</p>
<h2 id="evaluation">Evaluation</h2>
<p>To see how the developed function works, I decided to conduct exactly the same evaluation that <a href="/2026/02/09/smooth-v4-4-0/">I did for the recent R release of the smooth package</a>, running the functions on the M1, M3, and Tourism competition data (5,315 time series) using the <a href="/2026/01/26/forecasting-competitions-datasets-in-python/">fcompdata</a> package.</p>
<h3 id="evaluationSetup">Setup</h3>
<p>I have selected the same set of models for Python as I did in R. Here are several options for the ADAM <code>model</code> parameter to see how the specific pools impact accuracy (this is discussed in detail in <a href="https://openforecast.org/adam/ETSSelection.html">Section 15.1 of ADAM</a>):</p>
<ol>
<li>XXX &#8211; select between pure additive ETS models only;</li>
<li>ZZZ &#8211; select from the pool of all 30 models, but use branch-and-bound to remove the less suitable models;</li>
<li>ZXZ &#8211; same as (2), but without the multiplicative trend models. This is used in the <code>smooth</code> functions <strong>by default</strong>;</li>
<li>FFF &#8211; select from the pool of all 30 models (exhaustive search);</li>
<li>SXS &#8211; the pool of models used by default in <code>ets()</code> from the <code>forecast</code> package in R.</li>
</ol>
<p>I also tested three types of ETS initialisation (read more about them <a href="https://github.com/config-i1/smooth/wiki/Initialisation">here</a>):</p>
<ol>
<li>Back &#8211; <code>initial="backcasting"</code> &#8211; this is the default initialisation method;</li>
<li>Opt &#8211; <code>initial="optimal"</code>;</li>
<li>Two &#8211; <code>initial="two-stage"</code>.</li>
</ol>
<p>I have also found the following implementations of ETS in Python and included them in my evaluation:</p>
<ol>
<li><a href="https://www.sktime.net/en/stable/api_reference/auto_generated/sktime.forecasting.ets.AutoETS.html">sktime AutoETS</a></li>
<li><a href="https://skforecast.org/0.20.0/api/stats#skforecast.stats._ets.Ets">skforecast AutoETS</a></li>
<li><a href="https://nixtlaverse.nixtla.io/statsforecast/docs/models/autoets.html">statsforecast AutoETS</a></li>
</ol>
<p>There is also a <a href="https://unit8co.github.io/darts/generated_api/darts.models.forecasting.sf_auto_ets.html">darts implementation of AutoETS</a>, which is actually a wrapper of the statsforecast one. So I ran it just to check how it works, and found that it failed in 1,518 cases. <a href="https://github.com/unit8co/darts/issues/3001">I filed the issue</a>, and it turned out that their implementation does not deal with short time series (10 observations or fewer), which is their design decision. They are now considering what to do about that, if anything.</p>
<p>I used RMSSE (<a href="https://www.doi.org/10.1016/j.ijforecast.2021.11.013">M5 competition</a>, motivated by <a href="https://www.doi.org/10.1016/j.ijforecast.2022.08.003">Athanasopoulos &#038; Kourentzes (2023)</a>) and SAME error measure together with the computational time for each time series:<br />
\begin{equation*}<br />
\mathrm{RMSSE} = \frac{1}{\sqrt{\frac{1}{T-1} \sum_{t=1}^{T-1} \Delta_t^2}} \mathrm{RMSE},<br />
\end{equation*}<br />
where \(\mathrm{RMSE} = \sqrt{\frac{1}{h} \sum_{j=1}^h e^2_{t+j}}\) is the Root Mean Squared Error of the point forecasts, and \(\Delta_t\) is the first differences of the in-sample actual values.</p>
<p>\begin{equation*}<br />
\mathrm{SAME} = \frac{1}{\frac{1}{T-1} \sum_{t=1}^{T-1} |\Delta_t|} \mathrm{AME},<br />
\end{equation*}<br />
where \(\mathrm{AME}= \left| \frac{1}{h} \sum_{j=1}^h e_{t+j} \right|\).</p>
<p>All of this was implemented in a Jupyter notebook, which is <a href="https://github.com/config-i1/smooth/blob/master/python/tests/notebooks/benchmark_exponential_smoothing.ipynb">available here</a> in case you want to reproduce the results.</p>
<h3 id="sktime">sktime non-collaborative stance</h3>
<p>In the first run of this (on 28th January 2026), I encountered several errors in AutoETS in sktime: it took an extremely long time to compute (see the table below &#8211; on average around 30 seconds per time series) and produced ridiculous forecasts (mean RMSSE was 106,951). I <a href="https://github.com/sktime/sktime/issues/9291">filed an issue</a> in their repo and sent a courtesy message to Franz Kiraly on LinkedIn the same day, saying that I would be happy to rerun the results if this was fixed. I then received an insulting email from him, blaming me for not collaborating and trying to diminish sktime. They then closed the issue, claiming that it was fixed. I reran the experiment with their development version from GitHub on 21st March (two months later!), only to get exactly the same results. I do not think their fix is working, but given Franz&#8217;s toxic behaviour, I am not going to rerun this any further or help him in any way. The Jupyter notebook with the experiment is <a href="https://github.com/config-i1/smooth/blob/master/python/tests/notebooks/benchmark_exponential_smoothing.ipynb">here</a>, so he can investigate on his own.</p>
<h3 id="evaluationResults">Results</h3>
<p>So, here are the summary results for the tested models:</p>
<pre>====================================================================================
EVALUATION RESULTS for RMSSE (All Series)
====================================================================================
               Method       Min        Q1       Med        Q3       Max      Mean
        ADAM ETS Back  0.018252  <strong>0.663358</strong>  <strong>1.161473</strong>  <strong>2.301861</strong>  <strong>50.25854</strong>  1.928086
         ADAM ETS Opt  0.024155  0.670682  1.185932  2.365498  51.61599  1.943729
         ADAM ETS Two  0.024599  0.669522  1.182516  2.342385  51.61599  1.947715
              ES Back  0.018252  0.667225  1.160971  2.313932  <strong>50.25854</strong>  1.927436
               ES Opt  0.024155  0.673575  1.185756  2.364915  51.61599  1.947180
               ES Two  0.024467  0.671771  1.187368  2.346343  51.61599  1.955076
               ES XXX  0.018252  0.677717  1.170823  2.306197  <strong>50.25854</strong>  1.961318
               ES ZZZ  <strong>0.011386</strong>  0.670211  1.179916  2.353334  115.5442  2.053459
               ES FFF  <strong>0.011386</strong>  0.680956  1.211736  2.449626  115.5442  2.100899
               ES SXS  0.018252  0.674537  1.169187  2.353334  <strong>50.25854</strong>  1.939847
statsforecast AutoETS  0.024468  0.673157  1.189209  2.326650  51.61597  <strong>1.923925</strong>
   skforecast AutoETS  0.074744  0.747200  1.344916  2.721083  50.54339  2.273724
       sktime AutoETS  0.024467  0.676191  1.190093  2.456184 565753200  106951.7</pre>
<p>Things to note:</p>
<ol>
<li>The best performing ETS on average is from Nixtla&#8217;s statsforecast package. The second best is our implementation (ADAM/ES) with backcasting;</li>
<li>Given that I <a href="/2026/02/09/smooth-v4-4-0/">ran exactly the same experiment for the R packages</a>, we can conclude that Nixtla&#8217;s implementation is even better than the one in the forecast package in R;</li>
<li>In terms of median RMSSE, ES with backcasting outperforms all other implementations;</li>
<li>ADAM ETS is the best in terms of the first and third quartiles of RMSSE;</li>
<li>ADAM ETS and ES perform quite similarly. This is expected, because ES is a wrapper of ADAM ETS, which assumes normality for the error term. ADAM ETS switches between Normal and Gamma distributions based on the type of error term;</li>
<li>Backcasting leads to the most accurate forecasts on these datasets. This does not mean it is a universal rule, and I am sure the situation will change for other datasets;</li>
<li>ES XXX gives exactly the same results as the one implemented in <a href="/2026/02/09/smooth-v4-4-0/#evaluationResults">the R version of the package</a>. This is important because we were aiming to reproduce results between R and Python with 100% precision, and we did. The reason why other ETS flavours differ between R and Python is that since smooth 4.4.0 for R, we changed how point forecasts are calculated for multiplicative component models: previously, they relied on simulations; now we simply use point forecasts. While this is not entirely statistically accurate, it is pragmatic because it avoids explosive trajectories.</li>
</ol>
<p>The results for SAME are qualitatively similar to those for RMSSE:</p>
<pre>===================================================================================
EVALUATION RESULTS for SAME (All Series)
===================================================================================
               Method       Min        Q1       Med        Q3       Max      Mean
        ADAM ETS Back  0.001142  0.374466  0.995272  <strong>2.402342</strong>  52.34177  1.951070
         ADAM ETS Opt  0.000106  0.373551  1.021661  2.485596  55.10179  1.962040
         ADAM ETS Two  0.000782  0.380398  1.029629  2.451008  55.10186  1.970422
              ES Back  0.001142  0.372777  <strong>0.994547</strong>  2.412503  53.45041  1.946517
               ES Opt  0.000217  <strong>0.372725</strong>  1.024666  2.478435  54.68603  1.967217
               ES Two  0.000095  0.384795  1.028561  2.454543  54.68558  1.982261
               ES XXX  0.000094  0.373315  1.005006  2.425682  <strong>53.16973</strong>  1.992656
               ES ZZZ  0.000760  0.386673  1.017732  2.467912  145.7604  2.107522
               ES FFF  0.000597  0.401426  1.048395  2.566151  145.7604  2.173559
               ES SXS  0.000597  0.375438  1.005603  2.450490  53.45041  1.964322
statsforecast AutoETS  0.000228  0.374821  1.015205  2.434952  53.61359  <strong>1.938682</strong>
   skforecast AutoETS  0.000993  0.457066  1.217751  2.954003  59.84443  2.409900
       sktime AutoETS  0.000433  0.392802  1.029433  2.571555 385286900  72931.90</pre>
<p>Finally, I also measured the computational time and got the following summary. Note that I moved ES flavours below because they are not directly comparable with the others (they have special pools of models):</p>
<pre>================================================================================
EVALUATION RESULTS for Computational Time in seconds (All Series)
================================================================================
               Method       Min        Q1       Med        Q3        Max      Mean
        ADAM ETS Back  0.008679  0.086219  0.140929  0.241768   <strong>0.923601</strong>  0.181546
         ADAM ETS Opt  0.051302  0.229400  0.315379  0.792827   2.638193  0.550378
         ADAM ETS Two  0.051314  0.287382  0.455149  1.080276   3.535120  0.715090
              ES Back  0.009274  0.085299  0.139511  0.247114   0.958868  0.182547
               ES Opt  0.053176  0.224293  0.312200  0.772161   2.888662  0.541243
               ES Two  0.048539  0.279598  0.446404  1.058847   3.553156  0.703183
statsforecast AutoETS  <strong>0.001770</strong>  <strong>0.007702</strong>  <strong>0.081189</strong>  <strong>0.167040</strong>   1.271202  <strong>0.102575</strong>
   skforecast AutoETS  0.021553  0.243102  0.302078  1.478667   7.482101  0.820576
       sktime AutoETS  0.128021  6.227344 19.170921 41.494513 229.793067 30.712191

================================================================================
               ES XXX  0.008793  0.054139  0.093792  0.144012   0.480976  0.104800
               ES ZZZ  0.010502  0.127297  0.184561  0.447649   1.794031  0.313157
               ES FFF  0.046921  0.215119  1.110657  1.557724   3.489375  1.071004
               ES SXS  0.024909  0.116427  0.434594  0.564973   1.251257  0.403988</pre>
<p>Things to note:</p>
<ol>
<li>Nixtla&#8217;s implementation is actually the fastest and very hard to beat. As far as I understand, they did great work implementing some code in C++ and then using numba (I do not know what that means yet);</li>
<li>Our implementation does not use numba, but our ETS with backcasting is still faster than the skforecast and sktime implementations;</li>
<li>ADAM ETS with backcasting also has the lowest maximum time, implying that in difficult situations it finds a solution relatively quickly compared with the others;</li>
</ol>
<p>So, overall, I would argue that the smooth implementation of ETS is competitive with other implementations. But it has one important benefit: it supports more features. And we plan to expand it further to make it even more useful across a wider variety of cases.</p>
<h2 id="whatsNext">What&#8217;s next</h2>
<p>There are still a lot of features that we have not managed to implement yet. Here is a non-exhaustive list:</p>
<ol>
<li><a href="/adam/ADAMX.html">Explanatory variables to have ETSX/ARIMAX</a>;</li>
<li><a href="/adam/ADAMARIMA.html">ARIMA</a>;</li>
<li><a href="/adam/ADAMIntermittent.html">Occurrence model</a> for intermittent demand forecasting;</li>
<li><a href="/adam/ADAMscaleModel.html">Scale model</a> for ADAM;</li>
<li><a href="/adam/ADAMUncertaintySimulation.html">Simulation functions</a>;</li>
<li><a href="/adam/diagnostics.html">Model diagnostics</a>;</li>
<li>CES, MSARIMA, SSARIMA, GUM, and SMA &#8211; functions that are available in R and not yet ported to Python.</li>
</ol>
<p>So, lots of work to do. I am sure we will be quite busy well into 2026.</p>
<h2 id="summary">Summary</h2>
<p>It has been a long and winding road, but Filotas and Leo did an amazing job to make this happen. The existing ETS implementation in <code>smooth</code> already works quite well and quite fast. It does not fail as some other implementations do, and it is quite reliable. I have actually spent many years testing the R version on different time series to make sure that it produces something sensible no matter what. The code was translated to Python one-to-one, so I am fairly confident that the function will work as expected in 99.9% of cases (there is always a non-zero probability that something will go wrong). Both ADAM and ES already support a variety of features that you might find useful.</p>
<p>One thing I will kindly ask of you is that if you find a bug or an issue when running experiments on your datasets, please file it in our GitHub repo <a href="https://github.com/config-i1/smooth/issues">here</a> &#8211; we will try to find the time to fix it. Also, if you would like to contribute by translating some features from R to Python or implementing something additional, please get in touch with me.</p>
<p>Finally, I am always glad to hear success stories. If you find the <code>smooth</code> package useful in your work, please let us know. One way of doing that is via the <a href="https://github.com/config-i1/smooth/discussions">Discussions</a> on GitHub, or you can simply send me an email.</p>
<p>Message <a href="https://openforecast.org/2026/04/09/smooth-forecasting-with-the-smooth-package-in-python/">smooth forecasting with the smooth package in Python</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2026/04/09/smooth-forecasting-with-the-smooth-package-in-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>smooth v4.4.0</title>
		<link>https://openforecast.org/2026/02/09/smooth-v4-4-0/</link>
					<comments>https://openforecast.org/2026/02/09/smooth-v4-4-0/#respond</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Mon, 09 Feb 2026 09:02:21 +0000</pubDate>
				<category><![CDATA[Package smooth for R]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[ARIMA]]></category>
		<category><![CDATA[CES]]></category>
		<category><![CDATA[ETS]]></category>
		<category><![CDATA[GUM]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3959</guid>

					<description><![CDATA[<p>Great news, everyone! smooth package for R version 4.4.0 is now on CRAN. Why is this a great news? Let me explain! On this page: What&#8217;s new? Evaluation Setup Results What&#8217;s next? Here is what&#8217;s new since 4.3.0: First, I have worked on tuning the initialisation in adam() in case of backcasting, and improved the [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2026/02/09/smooth-v4-4-0/">smooth v4.4.0</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Great news, everyone! smooth package for R version 4.4.0 is now on CRAN. Why is this a great news? Let me explain!</p>
<p>On this page:</p>
<ul>
<li><a href="#whatsNew">What&#8217;s new?</a></li>
<li><a href="#evaluation">Evaluation</a></li>
<ul>
<li><a href="#evaluationSetup">Setup</a></li>
<li><a href="#evaluationResults">Results</a></li>
</ul>
<li><a href="#whatsNext">What&#8217;s next?</a></li>
</ul>
<h3 id="whatsNew">Here is what&#8217;s new since 4.3.0:</h3>
<p>First, I have worked on tuning the initialisation in <code>adam()</code> in case of backcasting, and improved the <code>msdecompose()</code> function a bit to get more robust results. This was necessary to make sure that when the smoothing parameters are close to zero, initial values would still make sense. This is already in <code>adam</code> (use <code>smoother="global"</code> to test), but will become the default behaviour in the next version of the package, when we iron everything out. This is all a part of a larger work with Kandrika Pritularga on a paper about the initialisation of dynamic models.</p>
<p>Second, I have fixed a long standing issue of the eigenvalues calculation inside the dynamic models, which is applicable only in case of <code>bounds="admissible"</code> and might impact ARIMA, CES and GUM. The parameter restriction are now done consistently across all functions, guaranteeing that they will not fail and will produce stable/invertible estimates of parameters.</p>
<p>Third, I have added the Sparse ARMA function, which constructs ARMA(p,q) of the specific orders, dropping all the elements from 1 to those. e.g. SpARMA(2,3) would have the following form:<br />
\begin{equation*}<br />
y_t = \phi_2 y_{t-2} + \theta_3 \epsilon_{t-3} + \epsilon_{t}<br />
\end{equation*}<br />
This weird model is needed for a project I am working on together with Devon Barrow, Nikos Kourentzes and Yves Sagaert. I&#8217;ll explain more when we get the final draft of the paper.</p>
<p>And something very important, which you will not notice: I refactored the C++ code in the package so that it is available not only for R, but also for Python&#8230; Why? I&#8217;ll explain in the next post :). But this also means that the old functions that relied on the previous generation of the C++ code are now discontinued, and all the smooth functions use the new core. This applies to <code>es()</code>, <code>ssarima()</code>, <code>msarima()</code>, <code>ces()</code>, <code>gum()</code> and <code>sma()</code>. You will not notice any change, except that some of them should become a bit faster and probably more robust. And this also means that all of them will now be able to use methods for the <code>adam()</code> function. For example, the <code>summary()</code> will produce the proper output with standard errors and confidence intervals for all estimated parameters.</p>
<h2 id="evaluation">Evaluation</h2>
<p><strong>DISCLAIMER</strong>: The previous evaluation was for smooth v4.3.0, you can find it <a href="/2025/07/04/smooth-v4-3-0-in-r-what-s-new-and-what-s-next/">here</a>. I have changed one of error measures (sCE to SAME), but the rest is the same, so the results are widely comparable between the versions.</p>
<h3 id="evaluationSetup">The setup</h3>
<p>As usual, in situations like this, I have run the evaluation on the M1, M3 and Tourism competition data. This time, I have added more flavours of the ETS model selection so that you can see how the models pool impacts the forecasting accuracy. Short description:</p>
<ol>
<li>XXX &#8211; select between pure additive ETS models only;</li>
<li>ZZZ &#8211; select from the pool of all 30 models, but use branch-and-bound to kick out the less suitable models;</li>
<li>ZXZ &#8211; same as (2), but without the multiplicative trend models. This is used in the <code>smooth</code> functions <strong>by default</strong>;</li>
<li>FFF &#8211; select from the pool of all 30 models (exhaustive search);</li>
<li>SXS &#8211; the pool of models that is used by default in <code>ets()</code> from the <code>forecast</code> package in R.</li>
</ol>
<p>I also tested three types of the ETS initialisation:</p>
<ol>
<li>Back &#8211; <code>initial="backcasting"</code></li>
<li>Opt &#8211; <code>initial="optimal"</code></li>
<li>Two &#8211; <code>initial="two-stage"</code></li>
</ol>
<p>Backcasting is now the default method of initialisation, and does well in many cases, but I found that optimal initials (if done correctly) help in some difficult situations, as long a you have enough of computational time.</p>
<p>I used two error measures and computational time to check how functions work. The first error measure is called RMSSE (Root Mean Squared Scaled Error) from <a href="http://dx.doi.org/10.1016/j.ijforecast.2021.11.013">M5 competition</a>, motivated by <a href="http://dx.doi.org/10.1016/j.ijforecast.2022.08.003">Athanasopoulos &#038; Kourentzes (2023)</a>:</p>
<p>\begin{equation*}<br />
\mathrm{RMSSE} = \frac{1}{\sqrt{\frac{1}{T-1} \sum_{t=1}^{T-1} \Delta_t^2}} \mathrm{RMSE},<br />
\end{equation*}<br />
where \(\mathrm{RMSE} = \sqrt{\frac{1}{h} \sum_{j=1}^h e^2_{t+j}}\) is the Root Mean Squared Error of the point forecasts, and \(\Delta_t\) is the first differences of the in-sample actual values.</p>
<p>The second measure does not have a standard name in the literature, but the idea of it is to the measure the bias of forecasts and to get rid of the sign to make sure that positively biased forecasts on some time series are not cancelled out by the negative ones on the other ones. I call this measure &#8220;Scaled Absolute Mean Error&#8221; (SAME):</p>
<p>\begin{equation*}<br />
\mathrm{SAME} = \frac{1}{\frac{1}{T-1} \sum_{t=1}^{T-1} |\Delta_t|} \mathrm{AME},<br />
\end{equation*}<br />
where \(\mathrm{AME}= \left| \frac{1}{h} \sum_{j=1}^h e_{t+j} \right|\).</p>
<p>For both of these measures, the lower value is better than the higher one. As for the computational time, I have measured it for each model and each series, and this time I provided distribution of times to better see how methods perform.</p>
<div class="su-spoiler su-spoiler-style-fancy su-spoiler-icon-plus su-spoiler-closed" data-scroll-offset="0" data-anchor-in-url="no"><div class="su-spoiler-title" tabindex="0" role="button"><span class="su-spoiler-icon"></span>Boring code in R</div><div class="su-spoiler-content su-u-clearfix su-u-trim">
<pre class="decode">library(Mcomp)
library(Tcomp)
library(forecast)
library(smooth)

library(doMC)
registerDoMC(detectCores())

# Create a small but neat function that will return a vector of error measures
errorMeasuresFunction <- function(object, holdout, insample){
        holdout <- as.vector(holdout);
        insample <- as.vector(insample);
	# RMSSE and SAME are defined in greybox v2.0.7
        return(c(RMSSE(holdout, object$mean, mean(diff(insample^2)),
                 SAME(holdout, object$mean, mean(abs(diff(insample)))),
                 object$timeElapsed))
}

datasets <- c(M1,M3,tourism)
datasetLength <- length(datasets)

# Method configuration list
# Each method specifies: fn (function name), pkg (package), model, initial,
methodsConfig <- list(
	# ETS and Auto ARIMA from the forecast package in R
	"ETS" = list(fn = "ets", pkg = "forecast", use_x_only = TRUE),
	"Auto ARIMA" = list(fn = "auto.arima", pkg = "forecast", use_x_only = TRUE),
	# ADAM with different initialisation schemes
	"ADAM ETS Back" = list(fn = "adam", pkg = "smooth", model = "ZXZ", initial = "back"),
	"ADAM ETS Opt" = list(fn = "adam", pkg = "smooth", model = "ZXZ", initial = "opt"),
	"ADAM ETS Two" = list(fn = "adam", pkg = "smooth", model = "ZXZ", initial = "two"),
	# ES, which is a wrapper of ADAM. Should give very similar results to ADAM on regular data
	"ES Back" = list(fn = "es", pkg = "smooth", model = "ZXZ", initial = "back"),
	"ES Opt" = list(fn = "es", pkg = "smooth", model = "ZXZ", initial = "opt"),
	"ES Two" = list(fn = "es", pkg = "smooth", model = "ZXZ", initial = "two"),
	# Several flavours for model selection in ES
	"ES XXX" = list(fn = "es", pkg = "smooth", model = "XXX", initial = "back"),
	"ES ZZZ" = list(fn = "es", pkg = "smooth", model = "ZZZ", initial = "back"),
	"ES FFF" = list(fn = "es", pkg = "smooth", model = "FFF", initial = "back"),
	"ES SXS" = list(fn = "es", pkg = "smooth", model = "SXS", initial = "back"),
	# ARIMA implementations in smooth
	"MSARIMA" = list(fn = "auto.msarima", pkg = "smooth", initial = "back"),
	"SSARIMA" = list(fn = "auto.ssarima", pkg = "smooth", initial = "back"),
	# Complex Exponential Smoothing
	"CES" = list(fn = "auto.ces", pkg = "smooth", initial = "back"),
	# Generalised Univeriate Model (experimental)
	"GUM" = list(fn = "auto.gum", pkg = "smooth", initial = "back")
)

methodsNames <- names(methodsConfig)
methodsNumber <- length(methodsNames)

measuresNames <- c("RMSSE","SAME","Time")
measuresNumber <- length(measuresNames)

testResults <- array(NA, c(methodsNumber, datasetLength, measuresNumber),
                     dimnames = list(methodsNames, NULL, measuresNames))

# Unified loop over all methods
for(j in seq_along(methodsConfig)){
	cfg <- methodsConfig[[j]]
	cat("Running method:", methodsNames[j], "\n")

	result <- foreach(i = 1:datasetLength, .combine = "cbind",
	                  .packages = c("smooth", "forecast")) %dopar% {
		startTime <- Sys.time()

		# Build model call based on method type
		if(isTRUE(cfg$use_x_only)){
			# forecast package methods: ets, auto.arima
			test <- do.call(cfg$fn, list(datasets[[i]]$x))
		}else if(cfg$fn %in% c("adam", "es")) {
			# adam and es take dataset and model
			test <- do.call(cfg$fn, list(datasets[[i]], model=cfg$model, initial = cfg$initial))
		}else{
			# auto.msarima, auto.ssarima, auto.ces, auto.gum
			test <- do.call(cfg$fn, list(datasets[[i]], initial = cfg$initial))
		}

		# Build forecast call
		forecast_args <- list(test, h = datasets[[i]]$h)
		testForecast <- do.call(forecast, forecast_args)
		testForecast$timeElapsed <- Sys.time() - startTime

		return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x))
	}
	testResults[j,,] <- t(result)
}

</pre>
</div></div>
<h3 id="evaluationResults">Results</h3>
<p>And here are the results for the smooth functions in v4.4.0 for R. First, we summarise the RMSSEs. I produce quartiles of distribution of RMSSE together with the mean.</p>
<pre class="decode">cbind(t(apply(testResults[,,"RMSSE"],1,quantile, na.rm=T)),
      mean=apply(testResults[,,"RMSSE"],1,mean)) |> round(4)</pre>
<pre>                  0%    25%    50%    75%      100%   mean
ETS           0.0245 0.6772 1.1806 2.3765   51.6160 1.9697
Auto ARIMA    0.0246 0.6802 1.1790 2.3583   51.6160 1.9864
ADAM ETS Back 0.0183 <strong>0.6647</strong> <strong>1.1620</strong> <strong>2.3023</strong>   <strong>50.2585</strong> <strong>1.9283</strong>
ADAM ETS Opt  0.0242 0.6714 1.1868 2.3623   51.6160 1.9432
ADAM ETS Two  0.0246 0.6690 1.1875 2.3374   51.6160 1.9480
ES Back       0.0183 0.6674 1.1647 2.3164   <strong>50.2585</strong> 1.9292
ES Opt        0.0242 0.6740 1.1858 2.3644   51.6160 1.9469
ES Two        0.0245 0.6717 1.1874 2.3463   51.6160 1.9538
ES XXX        0.0183 0.6777 1.1708 2.3062   <strong>50.2585</strong> 1.9613
ES ZZZ        <strong>0.0108</strong> 0.6682 1.1816 2.3611  201.4959 2.0841
ES FFF        0.0145 0.6795 1.2170 2.4575 5946.1858 3.3033
ES SXS        0.0183 0.6754 1.1709 2.3539   <strong>50.2585</strong> 1.9448
MSARIMA       0.0278 0.6988 1.1898 2.4208   51.6160 2.0750
SSARIMA       0.0277 0.7371 1.2544 2.4425   51.6160 2.0625
CES Back      0.0450 0.6761 1.1741 2.3205   51.0571 1.9650
GUM Back      0.0333 0.7077 1.2073 2.4533   51.6184 2.0461
</pre>
<p>The worst performing models are the ETS with the multiplicative trend (ES ZZZ and ES FFF). This is because there are outliers in some time series, and the multiplicative trend reacts to them by amending the trend value to something large (e.g. 2, i.e. twice increase in level for each step), and then can never return to a reasonable level (see explanation of this phenomenon in <a href="https://openforecast.org/adam/ADAMETSMultiplicativeAlternative.html">Section 6.6 of ADAM book</a>). As expected, ADAM ETS does very similar to the ES, and we can see that the default initialisation (backcasting) is pretty good in terms of RMSSE values. To be fair, if the models are tested on a different dataset, it might be the case that the optimal initialisation would do better.</p>
<p>Here is a table with the SAME results:</p>
<pre class="decode">cbind(t(apply(testResults[,,"SAME"],1,quantile, na.rm=T)),
      mean=apply(testResults[,,"SAME"],1,mean)) |> round(4)</pre>
<pre>                 0%    25%    50%    75%      100%   mean
ETS           8e-04 0.3757 1.0203 2.5097   54.6872 1.9983
Auto ARIMA    <strong>0e+00</strong> 0.3992 1.0429 2.4565   53.2710 2.0446
ADAM ETS Back 1e-04 0.3752 0.9965 <strong>2.4047</strong>   <strong>52.3418</strong> 1.9518
ADAM ETS Opt  5e-04 0.3733 1.0212 2.4848   55.1018 1.9618
ADAM ETS Two  8e-04 0.3780 1.0316 2.4511   55.1019 1.9712
ES Back       <strong>0e+00</strong> 0.3733 <strong>0.9945</strong> 2.4122   53.4504 <strong>1.9485</strong>
ES Opt        2e-04 <strong>0.3727</strong> 1.0255 2.4756   54.6860 1.9673
ES Two        1e-04 0.3855 1.0323 2.4535   54.6856 1.9799
ES XXX        1e-04 0.3733 1.0050 2.4257   53.1697 1.9927
ES ZZZ        3e-04 0.3824 1.0135 2.4885  229.7626 2.1376
ES FFF        3e-04 0.3972 1.0489 2.6042 3748.4268 2.9501
ES SXS        6e-04 0.3750 1.0125 2.4627   53.4504 1.9725
MSARIMA       1e-04 0.3960 1.0094 2.5409   54.7916 2.1227
SSARIMA       1e-04 0.4401 1.1222 2.5673   52.5023 2.1248
CES Back      6e-04 0.3767 1.0079 2.4085   54.9026 2.0052
GUM Back      0e+00 0.3803 1.0575 2.6259   63.0637 2.0858
</pre>
<p>In terms of bias, smooth implementations of ETS are doing well again, and we can see the same issue with the multiplicative trend here as before. Another thing to note is that MSARIMA and SSARIMA are not as good as the Auto ARIMA from the forecast package on these datasets in terms of RMSSE and SAME (at least, in terms of mean error measures). And actually, GUM and CES are now better than those in terms of both error measures.</p>
<p>Finally, here is a table with the computational time:</p>
<pre class="decode">cbind(t(apply(testResults[,,"Time"],1,quantile, na.rm=T)),
      mean=apply(testResults[,,"Time"],1,mean)) |> round(4)</pre>
<pre>                  0%    25%    50%     75%    100%   mean
ETS           <strong>0.0032</strong> <strong>0.0117</strong> 0.1660  0.6728  1.6400 0.3631
Auto ARIMA    0.0100 0.1184 0.3618  1.0548 54.3652 1.4760
ADAM ETS Back 0.0162 0.1062 0.1854  0.4022  2.5109 0.2950
ADAM ETS Opt  0.0319 0.1920 0.3103  0.6792  3.8933 0.5368
ADAM ETS Two  0.0427 0.2548 0.4035  0.8567  3.7178 0.6331
ES Back       0.0153 0.0896 <strong>0.1521</strong>  0.3335  2.1128 0.2476
ES Opt        0.0303 0.1667 0.2565  0.5910  3.5887 0.4522
ES Two        0.0483 0.2561 0.4016  0.8626  3.5892 0.6309
MSARIMA Back  0.0614 0.3418 0.6947  0.9868  3.9677 0.7534
SSARIMA Back  0.0292 0.2963 0.8988  2.1729 13.7635 1.6581
CES Back      0.0146 0.0400 0.1834  <strong>0.2298</strong>  <strong>1.2099</strong> <strong>0.1713</strong>
GUM Back      0.0165 0.2101 1.5221  3.0543  9.5380 1.9506

# Separate table for special pools of ETS.
# The time is proportional to the number of models here
=========================================================
                  0%    25%    50%     75%    100%   mean
ES XXX        0.0114 0.0539 0.0782  0.1110  0.8163 0.0859
ES ZZZ        0.0147 0.1371 0.2690  0.4947  2.2049 0.3780
ES FFF        0.0529 0.2775 1.1539  1.5926  3.8552 1.1231
ES SXS        0.0323 0.1303 0.4491  0.6013  2.2170 0.4581
</pre>
<p><em><br />
I have manually moved the specific ES model pools flavours below because there is no point in comparing their computational time with the time of the others (they have different pools of models and thus are not really comparable with the rest).</em></p>
<p>What we can see from this, is that the ES with backcasting is faster in comparison with the other models in this setting (in terms of mean and median computational time). CES is very fast in terms of mean computational time, which is probably because of the very short pool of models to choose from (only four). SSARIMA is pretty slow, which is due to the nature of its order selection algorithm (I don't plan to update it any time soon, but if someone wants to contribute - let me know). But the interesting thing is that Auto ARIMA, while being relatively fine in terms of median time, has the highest maximum one, meaning that for some time series, it failed for some unknown reason. The series that caused the biggest issue for Auto ARIMA is N389 from the M1 competition. I'm not sure what the issue was, and I don't have time to investigate this.</p>
<div id="attachment_4002" style="width: 310px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2026/02/smoot-4-4-0-time-vs-RMSSE.png&amp;nocache=1"><img fetchpriority="high" decoding="async" aria-describedby="caption-attachment-4002" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2026/02/smoot-4-4-0-time-vs-RMSSE-300x180.png&amp;nocache=1" alt="Mean computational time vs mean RMSSE" width="300" height="180" class="size-medium wp-image-4002" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2026/02/smoot-4-4-0-time-vs-RMSSE-300x180.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2026/02/smoot-4-4-0-time-vs-RMSSE-768x461.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2026/02/smoot-4-4-0-time-vs-RMSSE.png&amp;nocache=1 1000w" sizes="(max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-4002" class="wp-caption-text">Mean computational time vs mean RMSSE</p></div>
<p>Comparing the mean computational time with mean RMSSE value (image above), it looks like the overall tendency in the <code>smooth</code> + <code>forecast</code> functions for the M1, M3 and Tourism datasets is that additional computational time does not improve the accuracy. But it also looks like a simpler pool of pure additive models (ETS(X,X,X)) harms the accuracy in comparison with the branch-and-bound based one of the default <code>model="ZXZ"</code>. There seems to be a sweet spot in terms of the pool of models to choose from (no multiplicative trend, allow mixed models). This aligns well with the papers of <a href="https://doi.org/10.1080/01605682.2024.2421339">Petropoulos et al. (2025)</a>, who investigated the accuracy of arbitrary short pools of models and <a href="https://doi.org/10.1016/j.ijpe.2018.05.019">Kourentzes et al. (2019)</a>, who showed how pooling (if done correctly) can improve the accuracy on average.</p>
<h3 id="whatsNext">What's next?</h3>
<p>For R, the main task now is to rewrite the <code>oes()</code> function and substitute it with the <code>om()</code> one - "Occurrence Model". This should be equivalent to <code>adam()</code> in functionality, allowing to introduce ETS, ARIMA and explanatory variables for the occurrence part of the model. This is a huge work, which I hope to progress slowly throughout the 2026 and finish by the end of the year. Doing that will also allow me removing the last bits of the old C++ code and switch to the ADAM core completely, introducing more functionality for capturing patterns on intermittent demand. The minor task, is to test the <code>smoother="global"</code> more for the ETS initialisation and roll it out as the default in the next release for both R and Python.</p>
<p>For Python,... What Python? Ah! You'll see soon :)</p>
<p>Message <a href="https://openforecast.org/2026/02/09/smooth-v4-4-0/">smooth v4.4.0</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2026/02/09/smooth-v4-4-0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>smooth v4.3.0 in R: what&#8217;s new and what&#8217;s next?</title>
		<link>https://openforecast.org/2025/07/04/smooth-v4-3-0-in-r-what-s-new-and-what-s-next/</link>
					<comments>https://openforecast.org/2025/07/04/smooth-v4-3-0-in-r-what-s-new-and-what-s-next/#respond</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Fri, 04 Jul 2025 10:02:17 +0000</pubDate>
				<category><![CDATA[Package smooth for R]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[ARIMA]]></category>
		<category><![CDATA[CES]]></category>
		<category><![CDATA[ETS]]></category>
		<category><![CDATA[GUM]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3898</guid>

					<description><![CDATA[<p>Good news! The smooth package v4.3.0 is now on CRAN. And there are several things worth mentioning, so I have written this post. New default initialisation mechanism Since the beginning of the package, the smooth functions supported three ways for initialising the state vector (the vector that includes level, trend, seasonal indices): optimisation, backcasting and [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2025/07/04/smooth-v4-3-0-in-r-what-s-new-and-what-s-next/">smooth v4.3.0 in R: what&#8217;s new and what&#8217;s next?</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Good news! The smooth package v4.3.0 is now on CRAN. And there are several things worth mentioning, so I have written this post.</p>
<h3>New default initialisation mechanism</h3>
<p>Since the beginning of the package, the <code>smooth</code> functions supported three ways for initialising the state vector (the vector that includes level, trend, seasonal indices): optimisation, backcasting and values provided by user. The former has been considered the standard way of estimating ETS, while the backcasting was originally proposed by Box &#038; Jenkins (1970) and was only implemented in the <code>smooth</code> (at least, I haven&#8217;t seen it anywhere else). The main advantage of the latter is in computational time, because you do not need to estimate every single value of the state vector. The new ADAM core that I developed during COVID lockdown, had some improvements for the backcasting, and I noticed that <code>adam()</code> produced more accurate forecasts with it than with the optimisation. But I needed more testing, so I have not changed anything back then.</p>
<p>However, my recent work with Kandrika Pritularga on capturing uncertainty in ETS, have demonstrated that backcasting solves some fundamental problems with the variance of states &#8211; the optimisation cannot handle so many parameters, and asymptotic properties of ETS do not make sense in that case (we&#8217;ll release the paper as soon as we finish the experiments). So, with this evidence on hands and additional tests, I have made a decision to switch from the optimisation to backcasting as the default initialisation mechanism for all the <strong>smooth</strong> functions.</p>
<p>The final users should not feel much difference, but it should work faster now and (hopefully) more accurately. If this is not the case, please get in touch or <a href="https://github.com/config-i1/smooth/issues">file an issue on github</a>.</p>
<p>Also, rest assured the <code>initial="optimal"</code> is available and will stay available as an option in all the <code>smooth</code> functions, so, you can always switch back to it if you don&#8217;t like backcasting.</p>
<p>Finally, I have introduce a new initialisation mechanism called &#8220;two-stage&#8221;, the idea of which is to apply backcasting first and then to optimise the obtained state values. It is slower, but is supposed to be better than the standard optimisation.</p>
<h3>ADAM core</h3>
<p>Every single function in the <code>smooth</code> package now uses ADAM C++ core, and the old core will be discontinued starting from v4.5.0 of the package. This applies to the functions: <code>es()</code>, <code>ssarima()</code>, <code>msarima()</code>, <code>ces()</code>, <code>gum()</code>, <code>sma()</code>. There are now the legacy versions of these functions in the package with the prefix &#8220;_old&#8221; (e.g. <code>es_old()</code>), which will be removed in the smooth v4.5.0. The new engine also helped <code>ssarima()</code>, which now became slightly more accurate than before. Unfortunately, there are still some issues with the initialisation of the seasonal <code>ssarima()</code>, which I have failed to solve completely. But I hope that over time this will be resolved as well.</p>
<h3>smooth performance update</h3>
<p>I have applied all the smooth functions together with the <code>ets()</code> and <code>auto.arima()</code> from the <code>forecast</code> package to the M1, M3 and Tourism competition data and have measured their performances in terms of RMSSE, scaled Cumulative Error (sCE) and computational time. I used the following R code for that:</p>
<div class="su-spoiler su-spoiler-style-fancy su-spoiler-icon-plus su-spoiler-closed" data-scroll-offset="0" data-anchor-in-url="no"><div class="su-spoiler-title" tabindex="0" role="button"><span class="su-spoiler-icon"></span>Long and boring code in R</div><div class="su-spoiler-content su-u-clearfix su-u-trim">
<pre class="decode">library(Mcomp)
library(Tcomp)

library(forecast)
library(smooth)

# I work on Linux and use doMC. Substitute this with doParallel if you use Windows
library(doMC)
registerDoMC(detectCores())

# Create a small but neat function that will return a vector of error measures
errorMeasuresFunction <- function(object, holdout, insample){
	holdout <- as.vector(holdout);
	insample <- as.vector(insample);
	return(c(measures(holdout, object$mean, insample),
			 mean(holdout < object$upper &#038; holdout > object$lower),
			 mean(object$upper-object$lower)/mean(insample),
			 pinball(holdout, object$upper, 0.975)/mean(insample),
			 pinball(holdout, object$lower, 0.025)/mean(insample),
			 sMIS(holdout, object$lower, object$upper, mean(insample),0.95),
			 object$timeElapsed))
}

# Datasets to use
datasets <- c(M1,M3,tourism)
datasetLength <- length(datasets)
# Types of models to try
methodsNames <- c("ETS", "Auto ARIMA",
				  "ADAM ETS Back", "ADAM ETS Opt", "ADAM ETS Two",
				  "ES Back", "ES Opt", "ES Two",
				  "ADAM ARIMA Back", "ADAM ARIMA Opt", "ADAM ARIMA Two",
				  "MSARIMA Back", "MSARIMA Opt", "MSARIMA Two",
				  "SSARIMA Back", "SSARIMA Opt", "SSARIMA Two",
				  "CES Back", "CES Opt", "CES Two",
				  "GUM Back", "GUM Opt", "GUM Two");
methodsNumber <- length(methodsNames);
test <- adam(datasets[[125]]);

testResults20250603 <- array(NA,c(methodsNumber,datasetLength,length(test$accuracy)+6),
                             dimnames=list(methodsNames, NULL,
                                           c(names(test$accuracy),
                                             "Coverage","Range",
                                             "pinballUpper","pinballLower","sMIS",
                                             "Time")));

#### ETS from forecast package ####
j <- 1;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="forecast") %dopar% {
  startTime <- Sys.time()
  test <- ets(datasets[[i]]$x);
  testForecast <- forecast(test, h=datasets[[i]]$h, level=95);
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### AUTOARIMA ####
j <- 2;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="forecast") %dopar% {
    startTime <- Sys.time()
    test <- auto.arima(datasets[[i]]$x);
    testForecast <- forecast(test, h=datasets[[i]]$h, level=95);
    testForecast$timeElapsed <- Sys.time() - startTime;
    return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ADAM ETS Backcasting ####
j <- 3;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- adam(datasets[[i]],"ZXZ", initial="back");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="pred");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ADAM ETS Optimal ####
j <- 4;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- adam(datasets[[i]],"ZXZ", initial="opt");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="pred");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ADAM ETS Two-stage ####
j <- 5;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- adam(datasets[[i]],"ZXZ", initial="two");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="pred");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ES Backcasting ####
j <- 6;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- es(datasets[[i]],"ZXZ", initial="back");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ES Optimal ####
j <- 7;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- es(datasets[[i]],"ZXZ", initial="opt");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ES Two-stage ####
j <- 8;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- es(datasets[[i]],"ZXZ", initial="two");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ADAM ARIMA Backcasting ####
j <- 9;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.adam(datasets[[i]], "NNN", initial="back", distribution=c("dnorm"));
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="pred");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ADAM ARIMA Optimal ####
j <- 10;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.adam(datasets[[i]], "NNN", initial="opt", distribution=c("dnorm"));
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="pred");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### ADAM ARIMA Two-stage ####
j <- 11;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.adam(datasets[[i]], "NNN", initial="two", distribution=c("dnorm"));
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="pred");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### MSARIMA Backcasting ####
j <- 12;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.msarima(datasets[[i]], initial="back");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### MSARIMA Optimal ####
j <- 13;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.msarima(datasets[[i]], initial="opt");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### MSARIMA Two-stage ####
j <- 14;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.msarima(datasets[[i]], initial="two");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### SSARIMA Backcasting ####
j <- 15;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.ssarima(datasets[[i]], initial="back");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### SSARIMA Optimal ####
j <- 16;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="forecast") %dopar% {
    startTime <- Sys.time()
    test <- auto.ssarima(datasets[[i]], initial="opt");
    testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
    testForecast$timeElapsed <- Sys.time() - startTime;
    return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### SSARIMA Two-stage ####
j <- 17;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="forecast") %dopar% {
    startTime <- Sys.time()
    test <- auto.ssarima(datasets[[i]], initial="two");
    testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
    testForecast$timeElapsed <- Sys.time() - startTime;
    return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### CES Backcasting ####
j <- 18;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.ces(datasets[[i]], initial="back");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### CES Optimal ####
j <- 19;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.ces(datasets[[i]], initial="opt");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### CES Two-stage ####
j <- 20;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.ces(datasets[[i]], initial="two");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### GUM Backcasting ####
j <- 21;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.gum(datasets[[i]], initial="back");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### GUM Optimal ####
j <- 22;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.gum(datasets[[i]], initial="opt");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);

#### GUM Two-stage ####
j <- 23;
result <- foreach(i=1:datasetLength, .combine="cbind", .packages="smooth") %dopar% {
  startTime <- Sys.time()
  test <- auto.gum(datasets[[i]], initial="two");
  testForecast <- forecast(test, h=datasets[[i]]$h, interval="parametric");
  testForecast$timeElapsed <- Sys.time() - startTime;
  return(errorMeasuresFunction(testForecast, datasets[[i]]$xx, datasets[[i]]$x));
}
testResults20250603[j,,] <- t(result);</pre>
<p># Summary of results<br />
cbind(t(apply(testResults20250603[c(1:8,12:23),,"RMSSE"],1,quantile)),<br />
	  mean=apply(testResults20250603[c(1:8,12:23),,"RMSSE"],1,mean),<br />
	  sCE=apply(testResults20250603[c(1:8,12:23),,"sCE"],1,mean),<br />
	  Time=apply(testResults20250603[c(1:8,12:23),,"Time"],1,mean)) |> round(3)<br />
</div></div>
<p>The table below shows the distribution of RMSSE, the mean sCE and mean Time. The boldface shows the best performing model.</p>
<pre>                    min   Q1  median   Q3     max  mean    sCE  Time
ETS                0.024 0.677 1.181 2.376  51.616 1.970  0.299 0.385
Auto ARIMA         0.025 0.680 1.179 2.358  51.616 1.986  0.124 1.467

ADAM ETS Back      <strong>0.015</strong> <strong>0.666</strong> 1.175 <strong>2.276</strong>  51.616 <strong>1.921</strong>  0.470 0.218
ADAM ETS Opt       0.020 <strong>0.666</strong> 1.190 2.311  51.616 1.937  0.299 0.432
ADAM ETS Two       0.025 <strong>0.666</strong> 1.179 2.330  51.616 1.951  0.330 0.579

ES Back            <strong>0.015</strong> 0.672 <strong>1.174</strong> 2.284  51.616 <strong>1.921</strong>  0.464 0.219
ES Opt             0.020 0.672 1.186 2.316  51.616 1.943  0.302 0.497
ES Two             0.024 0.668 1.181 2.346  51.616 1.952  0.346 0.562

MSARIMA Back       0.025 0.710 1.188 2.383  51.616 2.028  <strong>0.067</strong> 0.780
MSARIMA Opt        0.025 0.724 1.242 2.489  51.616 2.083  0.088 1.905
MSARIMA Two        0.025 0.718 1.250 2.485  51.906 2.075  0.083 2.431

SSARIMA Back       0.045 0.738 1.248 2.383  51.616 2.063  0.167 1.747
SSARIMA Opt        0.025 0.774 1.292 2.413  51.616 2.040  0.178 7.324
SSARIMA Two        0.025 0.742 1.241 2.414  51.616 2.027  0.183 8.096

CES Back           0.046 0.695 1.189 2.355  51.342 1.981  0.125 <strong>0.185</strong>
CES Opt            0.030 0.698 1.218 2.327  <strong>49.480</strong> 2.001 -0.135 0.834
CES Two            0.025 0.696 1.207 2.343  51.242 1.993 -0.078 1.006

GUM Back           0.046 0.707 1.215 2.399  51.134 2.049 -0.285 3.575
GUM Opt            0.026 0.795 1.381 2.717 240.143 2.932 -0.549 4.668
GUM Two            0.026 0.803 1.406 2.826 240.143 3.041 -0.593 4.703</pre>
<p>Several notes:</p>
<ul>
<li>ES is a wrapper of ADAM ETS. The main difference between them is that the latter uses the Gamma distribution for the multiplicative error models, while the former relies on the Normal one.</li>
<li>MSARIMA is a wrapper for ADAM ARIMA, which is why I don't report the latter in the results.</li>
</ul>
<p>One thing you can notice from the output above, is that the models with backcasting consistently produce more accurate forecasts across all measures. I explain this with the idea that they tend not to overfit the data as much as the optimal initialisation does.</p>
<p>To see the stochastic dominance of the forecasting models, I conducted the modification of the MCB/Nemenyi test, explained in <a href="/2020/08/17/accuracy-of-forecasting-methods-can-you-tell-the-difference/">this post</a>:</p>
<pre class="decode">par(mar=c(10,3,4,1))
greybox::rmcb(t(testResults20250603[c(1:8,12:23),,"RMSSE"]), outplot="mcb")</pre>
<div id="attachment_3908" style="width: 310px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2025/07/2025-07-04-smooth-v4-3-0.png&amp;nocache=1"><img decoding="async" aria-describedby="caption-attachment-3908" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2025/07/2025-07-04-smooth-v4-3-0-300x175.png&amp;nocache=1" alt="Nemenyi test for the smooth functions" width="300" height="175" class="size-medium wp-image-3908" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2025/07/2025-07-04-smooth-v4-3-0-300x175.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2025/07/2025-07-04-smooth-v4-3-0-1024x597.png&amp;nocache=1 1024w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2025/07/2025-07-04-smooth-v4-3-0-768x448.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2025/07/2025-07-04-smooth-v4-3-0.png&amp;nocache=1 1200w" sizes="(max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-3908" class="wp-caption-text">Nemenyi test for the smooth functions</p></div>
<p>The image shows mean ranks for each of the models and whether the performance of those is significant on the 5% level or not. It is apparent that ADAM ETS has the lowest rank, no matter what the initialisation is used, but its performance does not differ significantly from the <code>es()</code>, <code>ets()</code> and <code>auto.arima()</code>. Also, <code>auto.arima()</code> significantly outperforms <code>msarima()</code> and <code>ssarima()</code> on this data, which could be due to their initialisation. Still, backcasting seems to help all the functions in terms of accuracy in comparison with the "optimal" and "two-stage" initials.</p>
<h3>What's next?</h3>
<p>I am now working on a modified formulation for ETS, which should fix some issues with the multiplicative trend and make the ETS safer. This is based on <a href="https://openforecast.org/adam/ADAMETSMultiplicativeAlternative.html">Section 6.6</a> of the online version of the ADAM monograph (it is not in the printed version). I am not sure whether this will improve the accuracy further, but I hope that it will make some of the ETS models more resilient than they are right now. I specifically need the multiplicative trend model, which sometimes behave like crazy due to its formulation.</p>
<p>I also plan to translate all the simulation functions to the ADAM core. This applies to <code>sim.es()</code>, <code>sim.ssarima()</code>, <code>sim.gum()</code> and <code>sim.ces()</code>. Currently they rely on the older one, and I want to get rid of it. Having said that, the method <code>simulate()</code> applied to the new <code>smooth</code> functions already uses the new core. It just lacks the flexibility that the other functions have.</p>
<p>Furthermore, I want to rewrite the <code>oes()</code> function and substitute it with <code>oadam()</code>, which would use a better engine, supporting more features, such as multiple frequencies and ARIMA for the occurrence. This is a lot of work, and I probably will need help with that.</p>
<p>Finally, Filotas Theodosiou, Leonidas Tsaprounis, and I are working on the translation of the R code of the <code>smooth</code> to Python. You can read a bit more about this project <a href="/2025/06/30/iif-open-source-forecasting-software-workshop-and-smooth/">here</a>. There are several other people who decided to help us, but the progress so far has been a bit slow, because of the code translation. If you want to help, please get in touch.</p>
<p>Message <a href="https://openforecast.org/2025/07/04/smooth-v4-3-0-in-r-what-s-new-and-what-s-next/">smooth v4.3.0 in R: what&#8217;s new and what&#8217;s next?</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2025/07/04/smooth-v4-3-0-in-r-what-s-new-and-what-s-next/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>IIF Open Source Forecasting software workshop and smooth</title>
		<link>https://openforecast.org/2025/06/30/iif-open-source-forecasting-software-workshop-and-smooth/</link>
					<comments>https://openforecast.org/2025/06/30/iif-open-source-forecasting-software-workshop-and-smooth/#respond</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Mon, 30 Jun 2025 09:00:40 +0000</pubDate>
				<category><![CDATA[Conferences]]></category>
		<category><![CDATA[Social media]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3892</guid>

					<description><![CDATA[<p>Here is one thing you have probably not heard of: a workshop on Open Source Forecasting software, held in Beijing on 26th &#8211; 27th June 2025. This was a closed event, with speakers attending by invitation only. It focused on recent advancements and potential avenues in open-source forecasting software. But why am I writing about [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2025/06/30/iif-open-source-forecasting-software-workshop-and-smooth/">IIF Open Source Forecasting software workshop and smooth</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Here is one thing you have probably not heard of: a workshop on Open Source Forecasting software, held in Beijing on 26th &#8211; 27th June 2025. This was a closed event, with speakers attending by invitation only. It focused on recent advancements and potential avenues in open-source forecasting software. But why am I writing about it if it has already passed and was closed?</p>
<p>First things first, the event was organised by Mitchell O’Hara, Xiaoqian Wang, Bahman Rostami-Tabar, Azul Garza, Resul Akay, Shanika Wickramasuriya and me. My contribution was acting as the programme chair of the workshop and helping invite some speakers. The event was sponsored by the <a href="https://forecasters.org/">International Institute of Forecasters</a>, and you can find some information about it on the following <a href="https://event.nectric.com.au/iif-osf/">website</a>. The workshop lasted for two days, and there were several great talks delivered by excellent speakers (see the <a href="https://event.nectric.com.au/iif-osf/program/schedule/">full programme here</a>).</p>
<p>But among those, there were two talks especially important to me personally, because they were related to the smooth package:</p>
<p>1. by Kandrika Pritularga, explaining the core of the package, the maths behind it, and how it works,<br />
2. by Filotas Theodosiou, who explained his excellent work on translating the smooth R code to Python.</p>
<p>Yes, you&#8217;ve heard correctly! We have finally had some progress translating the smooth package from R to Python (done between Filotas, Leonidas Tsaprounis and me. I&#8217;m a vibe coder now! :D). The Python code is available in <a href="https://github.com/config-i1/smooth/tree/Python/python">this GitHub branch</a>, and we now even have a <a href="https://github.com/config-i1/smooth/blob/Python/python/smooth_package_structure.md">description of the package structure and function flow</a> (thanks to Fil and his AI friends).</p>
<p>It’s still a work in progress, and there&#8217;s lots to do, but it’s an important step for us. We plan to continue working on it, and there are already several people who have started helping us with the translation. So, stay tuned &#8211; great times are coming!</p>
<p>Message <a href="https://openforecast.org/2025/06/30/iif-open-source-forecasting-software-workshop-and-smooth/">IIF Open Source Forecasting software workshop and smooth</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2025/06/30/iif-open-source-forecasting-software-workshop-and-smooth/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Methods for the smooth functions in R</title>
		<link>https://openforecast.org/2024/10/10/methods-for-the-smooth-functions-in-r/</link>
					<comments>https://openforecast.org/2024/10/10/methods-for-the-smooth-functions-in-r/#respond</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Thu, 10 Oct 2024 13:46:22 +0000</pubDate>
				<category><![CDATA[adam()]]></category>
		<category><![CDATA[Applied forecasting]]></category>
		<category><![CDATA[Package smooth for R]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3685</guid>

					<description><![CDATA[<p>I have been asked recently by a colleague of mine how to extract the variance from a model estimated using adam() function from the smooth package in R. The problem was that that person started reading the source code of the forecast.adam() and got lost between the lines (this happens to me as well sometimes). [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2024/10/10/methods-for-the-smooth-functions-in-r/">Methods for the smooth functions in R</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I have been asked recently by a colleague of mine how to extract the variance from a model estimated using <code>adam()</code> function from the <code>smooth</code> package in R. The problem was that that person started reading the source code of the <code>forecast.adam()</code> and got lost between the lines (this happens to me as well sometimes). Well, there is an easier solution, and in this post I want to summarise several methods that I have implemented in the <code>smooth</code> package for forecasting functions. In this post I will focus on the <code>adam()</code> function, although all of them work for <code>es()</code> and <code>msarima()</code> as well, and some of them work for other functions (at least as for now, for smooth v4.1.0). Also, some of them are mentioned in the <a href="https://openforecast.org/adam/cheatSheet.html">Cheat sheet for adam() function</a> of my monograph (available <a href="https://openforecast.org/adam/">online</a>).</p>
<p><!-- Before I start, I have a <strong>short announcement</strong>. Kandrika Pritularga and I are planning to host the first online course on "Demand Forecasting with R" in November 2024. There are still some places left, so you can register via <a href="https://online-payments.lancaster-university.co.uk/product-catalogue/courses/lancaster-university-management-school-lums/centre-for-marketing-analytics-forecasting-cmaf/demand-forecasting-with-r">the Lancaster University shop</a>. You can read about the course <a href="https://www.lancaster.ac.uk/centre-for-marketing-analytics-and-forecasting/grow-with-us/demand-forecasting-with-r/">here</a>. --></p>
<h3>The main methods</h3>
<p>The <code>adam</code> class supports several methods that are used in other packages in R (for example, for the <code>lm</code> class). Here are they:</p>
<ul>
<li><code>forecast()</code> and <code>predict()</code> &#8211; produce forecasts from the model. The former is preferred, the latter has a bit of limited functionality. See documentation to see what forecasts can be generated. This was also discussed in <a href="https://openforecast.org/adam/ADAMForecasting.html">Chapter 18</a> of my monograph.</li>
<li><code>fitted()</code> &#8211; extracts the fitted values from the estimated object;</li>
<li><code>residuals()</code> &#8211; extracts the residuals of the model. These are values of \(e_t\), which differ depending on the error type of the model (see <a href="https://openforecast.org/adam/non-mle-based-loss-functions.html">discussion here</a>);</li>
<li><code>rstandard()</code> &#8211; returns standardised residuals, i.e. residuals divided by their standard deviation;</li>
<li><code>rstudent()</code> &#8211; studentised residuals, i.e. residuals that are divided by their standard deviation, dropping the impact of each specific observation on it. This helps in case of influential outliers.</li>
</ul>
<p>An additional method was introduced in the <code>greybox</code> package, called <code>actuals()</code>, which allows extracting the actual values of the response variable. Another useful method is <code>accuracy()</code>, which returns a set of error measures using the <code>measures()</code> function of the <code>greybox</code> package for the provided model and the holdout values.</p>
<p>All the methods above can be used for model diagnostics and for forecasting (the main purpose of the package). Furthermore, the <code>adam</code> class supports several functions for working with coefficients of models, similar to how it is done in case of <code>lm</code>:</p>
<ul>
<li><code>coef()</code> or <code>coefficient()</code> &#8211; extracts all the estimated coefficients in the model;</li>
<li><code>vcov()</code> &#8211; extracts the covariance matrix of parameters. This can be done either using Fisher Information or via a bootstrap (<code>bootstrap=TRUE</code>).  In the latter case, the <code>coefbootstrap()</code> method is used to create bootstrapped time series, reapply the model and extract estimates of parameters;</li>
<li><code>confint()</code> &#8211; returns the confidence intervals for the estimated parameter. Relies on <code>vcov()</code> and the assumption of normality (<a href="https://openforecast.org/adam/ADAMUncertaintyConfidenceInterval.html">CLT</a>);</li>
<li><code>summary()</code> &#8211; returns the output of the model, containing the table with estimated parameters, their standard errors and confidence intervals.</li>
</ul>
<p>Here is an example of an output from an ADAM ETS estimated using <code>adam()</code>:</p>
<pre class="decode">adamETSBJ <- adam(BJsales, h=10, holdout=TRUE)
summary(adamETSBJ, level=0.99)</pre>
<p>The first line above estimates and selects the most appropriate ETS for the data, while the second one will create a summary with 99% confidence intervals, which should look like this:</p>
<pre>Model estimated using adam() function: ETS(AAdN)
Response variable: BJsales
Distribution used in the estimation: Normal
Loss function type: likelihood; Loss function value: 241.1634
Coefficients:
      Estimate Std. Error Lower 0.5% Upper 99.5%  
alpha   0.8251     0.1975     0.3089      1.0000 *
beta    0.4780     0.3979     0.0000      0.8251  
phi     0.7823     0.2388     0.1584      1.0000 *
level 199.9314     3.6753   190.3279    209.5236 *
trend   0.2178     2.8416    -7.2073      7.6340  

Error standard deviation: 1.3848
Sample size: 140
Number of estimated parameters: 6
Number of degrees of freedom: 134
Information criteria:
     AIC     AICc      BIC     BICc 
494.3268 494.9584 511.9767 513.5372</pre>
<p>How to read this output, is discussed in <a href="https://openforecast.org/adam/ADAMUncertaintyConfidenceInterval.html">Section 16.3</a>.</p>
<h3>Multistep forecast errors</h3>
<p>There are two methods that can be used as additional analytical tools for the estimated model. Their generics are implemented in the <code>smooth</code> package itself:</p>
<ol>
<li><code>rmultistep()</code> - extracts the multiple steps ahead in-sample forecast errors for the specified horizon. This means that the model produces the forecast of length <code>h</code> for every observation starting from the very first one, till the last one and then calculates forecast errors based on it. This is used in case of semiparametric and nonparametric prediction intervals, but can also be used for diagnostics (see, for example, <a href="https://openforecast.org/adam/diagnosticsResidualsIIDExpectation.html#diagnosticsResidualsIIDExpectationMultiple">Subsection 14.7.3</a>);</li>
<li><code>multicov()</code> - returns the covariance matrix of the h steps ahead forecast error. The diagonal of this matrix corresponds to the h steps ahead variance conditional on the in-sample information.</li>
</ol>
<p>For the same model that we used in the previous section, we can extract and plot the multistep errors:</p>
<pre class="decode">rmultistep(adamETSBJ, h=10) |> boxplot()
abline(h=0, col="red2", lwd=2)</pre>
<p>which will result in:<br />
<div id="attachment_3689" style="width: 310px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamBJETSMulti.png&amp;nocache=1"><img decoding="async" aria-describedby="caption-attachment-3689" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamBJETSMulti-300x210.png&amp;nocache=1" alt="Distributions of the multistep forecast errors" width="300" height="210" class="size-medium wp-image-3689" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamBJETSMulti-300x210.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamBJETSMulti-768x538.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamBJETSMulti.png&amp;nocache=1 1000w" sizes="(max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-3689" class="wp-caption-text">Distributions of the multistep forecast errors</p></div>
<p>The image above shows that the model tend to under shoot the actual values in-sample (because the boxplots tend to lie slightly above the zero line). This might cause a bias in the final forecasts.</p>
<p>The covariance matrix of the multistep forecast error looks like this in our case:</p>
<pre class="decode">multicov(adamETSBJ, h=10) |> round(3)</pre>
<pre>       h1    h2     h3     h4     h5     h6     h7     h8     h9    h10
h1  1.918 2.299  2.860  3.299  3.643  3.911  4.121  4.286  4.414  4.515
h2  2.299 4.675  5.729  6.817  7.667  8.333  8.853  9.260  9.579  9.828
h3  2.860 5.729  8.942 10.651 12.250 13.501 14.480 15.246 15.845 16.314
h4  3.299 6.817 10.651 14.618 16.918 18.979 20.592 21.854 22.841 23.613
h5  3.643 7.667 12.250 16.918 21.538 24.348 26.808 28.733 30.239 31.417
h6  3.911 8.333 13.501 18.979 24.348 29.515 32.753 35.549 37.737 39.448
h7  4.121 8.853 14.480 20.592 26.808 32.753 38.372 41.964 45.036 47.440
h8  4.286 9.260 15.246 21.854 28.733 35.549 41.964 47.950 51.830 55.127
h9  4.414 9.579 15.845 22.841 30.239 37.737 45.036 51.830 58.112 62.223
h10 4.515 9.828 16.314 23.613 31.417 39.448 47.440 55.127 62.223 68.742</pre>
<p>This is not useful on its own, but can be used for some further derivations.</p>
<p>Note that the returned values by both <code>rmultistep()</code> and <code>multicov()</code> depend on the model's error type (see <a href="https://openforecast.org/adam/non-mle-based-loss-functions.html">Section 11.2</a> for clarification).</p>
<h3>Model diagnostics</h3>
<p>The conventional <code>plot()</code> method applied to a model estimated using <code>adam()</code> can produce a variety of images for the visual model diagnostics. This is controlled by the <code>which</code> parameter (overall, 16 options). The documentation of the <code>plot.smooth()</code> contains the exhaustive list of options and Chapter 14 of the monograph shows how they can be used for model diagnostics. Here I only list several main ones:</p>
<ul>
<li><code>plot(ourModel, which=1)</code> - actuals vs fitted values. Can be used for general diagnostics of the model. Ideally, all points should lie around the diagonal line;</li>
<li><code>plot(ourModel, which=2)</code> - standardised residuals vs fitted values. Useful for detecting potential outliers. Also accepts the <code>level</code> parameter, which regulates the width of the confidence bounds.</li>
<li><code>plot(ourModel, which=4)</code> - absolute residuals vs fitted, which can be used for detecting heteroscedasticity of the residuals;</li>
<li><code>plot(ourModel, which=6)</code> - QQ plot for the analysis of the distribution of the residuals. The specific figure changes for different distribution assumed in the model (see <a href="https://openforecast.org/adam/ADAMETSEstimationLikelihood.html">Section 11.1</a> for the supported ones);</li>
<li><code>plot(ourModel, which=7)</code> - actuals, fitted values and point forecasts over time. Useful for understanding how the model fits the data and what point forecast it produces;</li>
<li><code>plot(ourModel, which=c(10,11))</code> - ACF and PACF of the residuals of the model to detect potentially missing AR/MA elements;</li>
<li><code>plot(ourModel, which=12)</code> - plot of the components of the model. In case of ETS, will show the time series decomposition based on it.</li>
</ul>
<p>And here are four default plots for the model that we estimated earlier:</p>
<pre class="decode">par(mfcol=c(2,2))
plot(adamETSBJ)</pre>
<div id="attachment_3695" style="width: 310px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJPlots.png&amp;nocache=1"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3695" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJPlots-300x210.png&amp;nocache=1" alt="Diagnostic plots for the estimated model" width="300" height="210" class="size-medium wp-image-3695" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJPlots-300x210.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJPlots-768x538.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJPlots.png&amp;nocache=1 1000w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-3695" class="wp-caption-text">Diagnostic plots for the estimated model</p></div>
<p>Based on the plot above, we can conclude that the model fits the data fine, does not have apparent heteroscedasticity, but has several potential outliers, which can be explored to improve it. The outliers detection is done via the <code>outlierdummy()</code> method, the generic of which is implemented in the <code>greybox</code> package.</p>
<h3>Other useful methods</h3>
<p>There are many methods that are used by functions to extract some information about the model. I sometimes use them to simplify my coding routine. Here they are:</p>
<ul>
<li><code>lags()</code> - returns lags of the model. Especially useful if you fit a multiple seasonal model;</li>
<li><code>orders()</code> - the vector of orders of the model. Mainly useful in case of ARIMA, which can have multiple seasonalities and p,d,q,P,D,Q orders;</li>
<li><code>modelType()</code> - the type of the model. In case with the one fitted above will return "AAdN". Can be useful to easily refit the similar model on the new data;</li>
<li><code>modelName()</code> - the name of the model. In case of the one we fitted above will return "ETS(AAdN)";</li>
<li><code>nobs()</code>, <code>nparam()</code>, <code>nvariate()</code> - number of in-sample observations, number of all estimated parameters and number of time series used in the model respectively. The latter one is developed mainly for the multivariate models, such as VAR and VETS (e.g. <code>legion</code> package in R);</li>
<li><code>logLik()</code> - extracts log-Likelihood of the model;</li>
<li><code>AIC()</code>, <code>AICc()</code>, <code>BIC()</code>, <code>BICc()</code> - extract respective information criteria;</li>
<li><code>sigma()</code> - returns the standard error of the residuals.</li>
</ul>
<h3>More specialised methods</h3>
<p>One of the methods that can be useful for scenarios and artificial data generation is <code>simulate()</code>. It will take the structure and parameters of the estimated model and use them to generate time series, similar to the original one. This is discussed in <a href="https://openforecast.org/adam/ADAMUncertaintySimulation.html">Section 16.1</a> of the ADAM monograph.</p>
<p>Furthermore, <code>smooth</code> implements the scale model, discussed in <a href="https://openforecast.org/adam/ADAMscaleModel.html">Chapter 17</a>, which allows modelling time varying scale of distribution. This is done via the <code>sm()</code> method (generic introduced in the <code>greybox</code> package), the output of which can then be merged with the original model via the <code>implant()</code> method.</p>
<p>For the same model that we used earlier, the scale model can be estimated this way:</p>
<pre class="decode">adamETSBJSM <- sm(adamETSBJ)</pre>
<p>This is how it looks:</p>
<pre class="decode">plot(adamETSBJSM, 7)</pre>
<div id="attachment_3707" style="width: 310px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJSM.png&amp;nocache=1"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3707" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJSM-300x210.png&amp;nocache=1" alt="Scale model for the ADAM ETS" width="300" height="210" class="size-medium wp-image-3707" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJSM-300x210.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJSM-768x538.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJSM.png&amp;nocache=1 1000w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-3707" class="wp-caption-text">Scale model for the ADAM ETS</p></div>
<p>In the plot above, the y-axis contains the squared residuals. The fact that the holdout sample contains a large increase in the error is expected, because that part corresponds to the forecast errors rather than residuals. It is added to the plot for completeness.</p>
<p>To use the scale model in forecasting, we should implant it in the location one, which can be done using the following command:</p>
<pre class="decode">adamETSBJFull <- implant(location=adamETSBJ, scale=adamETSBJSM)</pre>
<p>The resulting model will have fewer degrees of freedom (because the scale model estimated two parameters), but its prediction interval will now take the scale model into account, and will differ from the original. We will now take into account the time varying variance based on the more recent information instead of the averaged one across the whole time series. In our case, the forecasted variance is lower than the one we would obtain in case of the adamETSBJ model. This leads to the narrower prediction interval (you can produce them for both models and compare):</p>
<pre class="decode">forecast(adamETSBJFull, h=10, interval="prediction") |> plot()</pre>
<div id="attachment_3708" style="width: 310px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJFull.png&amp;nocache=1"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3708" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJFull-300x210.png&amp;nocache=1" alt="Forecast from the full ADAM, containing both location and scale parts" width="300" height="210" class="size-medium wp-image-3708" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJFull-300x210.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJFull-768x538.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2024/10/adamETSBJFull.png&amp;nocache=1 1000w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-3708" class="wp-caption-text">Forecast from the full ADAM, containing both location and scale parts</p></div>
<h3>Conclusions</h3>
<p>The methods discussed above give a bit of flexibility of how to model things and what tools to use. I hope this makes your life easier and that you won't need to spend time reading the source code, but instead can focus on <a href="https://openforecast.org/adam/">forecasting and analytics with ADAM</a>.</p>
<p>Message <a href="https://openforecast.org/2024/10/10/methods-for-the-smooth-functions-in-r/">Methods for the smooth functions in R</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2024/10/10/methods-for-the-smooth-functions-in-r/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Detecting patterns in white noise</title>
		<link>https://openforecast.org/2024/04/10/detecting-patterns-in-white-noise/</link>
					<comments>https://openforecast.org/2024/04/10/detecting-patterns-in-white-noise/#respond</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Wed, 10 Apr 2024 08:16:58 +0000</pubDate>
				<category><![CDATA[ARIMA]]></category>
		<category><![CDATA[ETS]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[Social media]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3413</guid>

					<description><![CDATA[<p>Back in 2015, when I was working on my paper on Complex Exponential Smoothing, I conducted a simple simulation experiment to check how ARIMA and ETS select components/orders in time series. And I found something interesting&#8230; One of the important steps in forecasting with statistical models is identifying the existing structure. In the case of [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2024/04/10/detecting-patterns-in-white-noise/">Detecting patterns in white noise</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Back in 2015, when I was working on my paper on <a href="/2022/08/02/complex-exponential-smoothing/">Complex Exponential Smoothing</a>, I conducted a simple simulation experiment to check how ARIMA and ETS select components/orders in time series. And I found something interesting&#8230;</p>
<p>One of the important steps in forecasting with statistical models is identifying the existing structure. In the case of ETS, it comes to selecting trend/seasonal components, while for ARIMA, it&#8217;s about order selection. In R, several functions automatically handle this based on information criteria (<a href="https://doi.org/10.18637/jss.v027.i03">Hyndman &#038; Khandakar, 2006</a>; <a href="https://doi.org/10.1080/00207543.2019.1600764">Svetunkov &#038; Boylan (2017)</a>; <a href="https://openforecast.org/adam/ADAMSelection.html">Chapter 15 of ADAM</a>). I decided to investigate how this mechanism works.</p>
<p>I generated data from the Normal distribution with a fixed mean of 5000 and a standard deviation of 50. Then, I asked ETS and ARIMA (from the forecast package in R) to automatically select the appropriate model for each of 1000 time series. Here is the R code for this simple experiment:</p>
<div class="su-accordion su-u-trim"><div class="su-spoiler su-spoiler-style-default su-spoiler-icon-plus su-spoiler-closed" data-scroll-offset="0" data-anchor-in-url="no"><div class="su-spoiler-title" tabindex="0" role="button"><span class="su-spoiler-icon"></span>Some R code</div><div class="su-spoiler-content su-u-clearfix su-u-trim">
<pre class="decode"># Set random seed for reproducibility
set.seed(41, kind="L'Ecuyer-CMRG")
# Number of iterations
nsim <- 1000
# Number of observations
obsAll <- 120
# Generate data from N(5000, 50)
rnorm(nsim*obsAll, 5000, 50) |>
  matrix(obsAll, nsim) |>
  ts(frequency=12) -> x

# Load forecast package
library(forecast)
# Load doMC for parallel calculations
# doMC is only available on Linux and Max
# Use library(doParallel) on Windows
library(doMC)
registerDoMC(detectCores())

# A loop for ARIMA, recording the orders
matArima <- foreach(i=1:nsim, .combine=cbind, .packages=c("forecast")) %dopar% {
    testModel <- auto.arima(x&#091;,i&#093;)
    # The element number 5 is just m, period of seasonality
    return(c(testModel$arma&#091;-5&#093;,(!is.na(testModel$coef&#091;"drift"&#093;))*1))
}
rownames(matArima) <- c("AR","MA","SAR","SMA","I","SI","Drift")

# A loop for ETS, recording the model types
matEts <- foreach(i=1:nsim, .combine=cbind, .packages=c("forecast")) %dopar% {
    testModel <- ets(x&#091;,i&#093;, allow.multiplicative.trend=TRUE)
    return(testModel&#091;13&#093;$method)
}
</pre>
</div></div></div>
<p>The findings of this experiment are summarised using the following chunk of the R code:</p>
<div class="su-accordion su-u-trim"><div class="su-spoiler su-spoiler-style-default su-spoiler-icon-plus su-spoiler-closed" data-scroll-offset="0" data-anchor-in-url="no"><div class="su-spoiler-title" tabindex="0" role="button"><span class="su-spoiler-icon"></span>R code for the analysis of the results</div><div class="su-spoiler-content su-u-clearfix su-u-trim">
<pre class="decode">
#### Auto ARIMA ####
# Non-seasonal ARIMA elements
mean(apply(matArima[c("AR","MA","I","Drift"),]!=0, 2, any))
# Seasonal ARIMA elements
mean(apply(matArima[c("SAR","SMA","SI"),]!=0, 2, any))

#### ETS ####
# Trend in ETS
mean(substr(matEts,7,7)!="N")
# Seasonality in ETS
mean(substr(matEts,nchar(matEts)-1,nchar(matEts)-1)!="N")</pre>
</div></div></div>
<p>I summarised them in the following table:</p>
<table>
<thead>
<tr>
<td></td>
<td><strong>ARIMA</strong></td>
<td><strong>ETS</strong></td>
</tr>
</thead>
<tr>
<td>Non-seasonal elements</td>
<td>24.8%</td>
<td>2.3%</td>
</tr>
<tr>
<td>Seasonal elements</td>
<td>18.0%</td>
<td>0.2%</td>
</tr>
<tr>
<td>Any type of structure</td>
<td>37.9%</td>
<td>2.4%</td>
</tr>
</table>
<p>So, ARIMA detected some structure (had non-zero orders) in almost 40% of all time series, even though the data was designed to have no structure (just white noise). It also captured non-seasonal orders in a quarter of the series and identified seasonality in 18% of them. ETS performed better (only 0.2% of seasonal models identified on the white noise), but still captured trends in 2.3% of cases.</p>
<p>Does this simple experiment suggest that ARIMA is a bad model and ETS is a good one? No, it does not. It simply demonstrates that ARIMA tends to overfit the data if allowed to select whatever it wants. How can we fix that?</p>
<p>My solution: restrict the pool of ARIMA models to check, preventing it from going crazy. My personal pool includes ARIMA(0,1,1), (1,1,2), (0,2,2), along with the seasonal orders of (0,1,1), (1,1,2), and (0,2,2), and combinations between them. This approach is motivated by the connection between <a href="https://openforecast.org/adam/ARIMAandETS.html">ARIMA and ETS</a>. Additionally, we can check whether the addition of AR/MA orders detected by ACF/PACF analysis of the best model reduces the AICc. If not, they shouldn't be included.</p>
<p>This algorithm can be written in the following simple function that uses <code>msarima()</code> function from the smooth package in R (note that the reason why this function is used is because all ARIMA models implemented in the function are directly comparable via information criteria):</p>
<div class="su-accordion su-u-trim"><div class="su-spoiler su-spoiler-style-default su-spoiler-icon-plus su-spoiler-closed" data-scroll-offset="0" data-anchor-in-url="no"><div class="su-spoiler-title" tabindex="0" role="button"><span class="su-spoiler-icon"></span>R code for the compact ARIMA function</div><div class="su-spoiler-content su-u-clearfix su-u-trim">
<pre class="decode">arimaCompact <- function(y, lags=c(1,frequency(y)), ic=c("AICc","AIC","BIC","BICc"), ...){

    # Start measuring the time of calculations
    startTime <- Sys.time();

    # If there are no lags for the basic components, correct this.
    if(sum(lags==1)==0){
        lags <- c(1,lags);
    }

    orderLength <- length(lags);
    ic <- match.arg(ic);
    IC <- switch(ic,
                 "AIC"=AIC,
                 "AICc"=AICc,
                 "BIC"=BIC,
                 "BICc"=BICc);

    # We consider the following list of models:
    # ARIMA(0,1,1), (1,1,2), (0,2,2),
    # ARIMA(0,0,0)+c, ARIMA(0,1,1)+c,
    # seasonal orders (0,1,1), (1,1,2), (0,2,2)
    # And all combinations between seasonal and non-seasonal parts
    # 
    # Encode all non-seasonal parts
    nNonSeasonal <- 5
    arimaNonSeasonal <- matrix(c(0,1,1,0, 1,1,2,0, 0,2,2,0, 0,0,0,1, 0,1,1,1), nNonSeasonal,4,
                               dimnames=list(NULL, c("ar","i","ma","const")), byrow=TRUE)
    # Encode all seasonal parts ()
    nSeasonal <- 4
    arimaSeasonal <- matrix(c(0,0,0, 0,1,1, 1,1,2, 0,2,2), nSeasonal,3,
                               dimnames=list(NULL, c("sar","si","sma")), byrow=TRUE)

    # Check all the models in the pool
    testModels <- vector("list", nSeasonal*nNonSeasonal);
    m <- 1;
    for(i in 1:nSeasonal){
        for(j in 1:nNonSeasonal){
            testModels&#091;&#091;m&#093;&#093; <- msarima(y, orders=list(ar=c(arimaNonSeasonal&#091;j,1&#093;,arimaSeasonal&#091;i,1&#093;),
                                                      i=c(arimaNonSeasonal&#091;j,2&#093;,arimaSeasonal&#091;i,2&#093;),
                                                      ma=c(arimaNonSeasonal&#091;j,3&#093;,arimaSeasonal&#091;i,3&#093;)),
                                       constant=arimaNonSeasonal&#091;j,4&#093;==1, lags=lags, ...);
            m&#091;&#093; <- m+1;
        }
    }

    # Find the best one
    m <- which.min(sapply(testModels, IC));
    # Amend computational time
    testModels&#091;&#091;m&#093;&#093;$timeElapsed <- Sys.time()-startTime;

    return(testModels&#091;&#091;m&#093;&#093;);
}</pre>
</div></div></div>
<p>Additionally, we can check whether the addition of AR/MA orders detected by ACF/PACF analysis of the best model reduces the AICc. If not, they shouldn't be included. I have not added that part in the code above. Still, this algorithm brings some improvements:</p>
<div class="su-accordion su-u-trim"><div class="su-spoiler su-spoiler-style-default su-spoiler-icon-plus su-spoiler-closed" data-scroll-offset="0" data-anchor-in-url="no"><div class="su-spoiler-title" tabindex="0" role="button"><span class="su-spoiler-icon"></span>R code for the application of compact ARIMA to the data</div><div class="su-spoiler-content su-u-clearfix su-u-trim">
<pre class="decode">#### Load the smooth package
library(smooth)

# A loop for the compact ARIMA, recording the orders
matArimaCompact <- foreach(i=1:nsim, .packages=c("smooth")) %dopar% {
    testModel <- arimaCompact(x&#091;,i&#093;)
    return(orders(testModel))
}

#### Auto MSARIMA from smooth ####
# Non-seasonal ARIMA elements
mean(sapply(sapply(matArimaCompact, "&#091;&#091;", "ar"), function(x){x&#091;1&#093;!=0}) |
  sapply(sapply(matArimaCompact, "&#091;&#091;", "i"), function(x){x&#091;1&#093;!=0}) |
  sapply(sapply(matArimaCompact, "&#091;&#091;", "ma"), function(x){x&#091;1&#093;!=0}))

# Seasonal ARIMA elements
mean(sapply(sapply(matArimaSmooth, "&#091;&#091;", "ar"), function(x){length(x)==2 &#038;&#038; (x&#091;2&#093;!=0)}) |
  sapply(sapply(matArimaSmooth, "&#091;&#091;", "i"), function(x){length(x)==2 &#038;&#038; (x&#091;2&#093;!=0)}) |
  sapply(sapply(matArimaSmooth, "&#091;&#091;", "ma"), function(x){length(x)==2 &#038;&#038; (x&#091;2&#093;!=0)}))
</pre>
</div></div></div>
<p>In my case, it resulted in the following:</p>
<table>
<thead>
<tr>
<td></td>
<td><strong>ARIMA</strong></td>
<td><strong>ETS</strong></td>
<td style="text-align: center"><strong>Compact ARIMA</strong></td>
</tr>
</thead>
<tr>
<td>Non-seasonal elements</td>
<td>24.8%</td>
<td>2.3%</td>
<td style="text-align: center">2.4%</td>
</tr>
<tr>
<td>Seasonal elements</td>
<td>18.0%</td>
<td>0.2%</td>
<td style="text-align: center">0.0%</td>
</tr>
<tr>
<td>Any type of structure</td>
<td>37.9%</td>
<td>2.4%</td>
<td style="text-align: center">2.4%</td>
</tr>
</table>
<p>As we see, when we impose restrictions on order selection in ARIMA, it avoids fitting seasonal models to non-seasonal data. While it still makes minor mistakes in terms of non-seasonal structure, it's nothing compared to the conventional approach. What about accuracy? I don't know. I'll have to write another post on this :).</p>
<p>Note that the models were applied to samples of 120 observations, which is considered "small" in statistics, while in real life is sometimes a luxury to have...</p>
<p>Message <a href="https://openforecast.org/2024/04/10/detecting-patterns-in-white-noise/">Detecting patterns in white noise</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2024/04/10/detecting-patterns-in-white-noise/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>smooth &#038; greybox under LGPLv2.1</title>
		<link>https://openforecast.org/2023/09/19/smooth-greybox-under-lgplv2-1/</link>
					<comments>https://openforecast.org/2023/09/19/smooth-greybox-under-lgplv2-1/#comments</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Tue, 19 Sep 2023 09:32:56 +0000</pubDate>
				<category><![CDATA[Package greybox for R]]></category>
		<category><![CDATA[Package smooth for R]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[greybox]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3286</guid>

					<description><![CDATA[<p>Good news, everyone! I&#8217;ve recently released major versions of my packages smooth and greybox, v4.0.0 and v2.0.0 respectively, on CRAN. Has something big happened? Yes and no. Let me explain. Starting from these versions, the packages will be licensed under LGPLv2.1 instead of the very restrictive GPLv2. This does not change anything to the everyday [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2023/09/19/smooth-greybox-under-lgplv2-1/">smooth &#038; greybox under LGPLv2.1</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Good news, everyone! I&#8217;ve recently released major versions of my packages <a href="https://cran.r-project.org/package=smooth">smooth</a> and <a href="https://cran.r-project.org/web/packages/greybox/index.html">greybox</a>, v4.0.0 and v2.0.0 respectively, on CRAN. Has something big happened? Yes and no. Let me explain.</p>
<div id="attachment_3308" style="width: 510px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/09/greybox-smooth.png&amp;nocache=1"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3308" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/09/greybox-smooth.png&amp;nocache=1" alt="Stickers of the greybox and smooth packages for R" width="500" height="289" class="size-full wp-image-3308" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/09/greybox-smooth.png&amp;nocache=1 500w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/09/greybox-smooth-300x173.png&amp;nocache=1 300w" sizes="auto, (max-width: 500px) 100vw, 500px" /></a><p id="caption-attachment-3308" class="wp-caption-text">Stickers of the greybox and smooth packages for R</p></div>
<p>Starting from these versions, the packages will be licensed under <a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html">LGPLv2.1</a> instead of the very restrictive <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPLv2</a>. This does not change anything to the everyday users of the packages, but is a potential game changer to software developers and those who might want to modify the source code of the packages for commercial purposes. This is because any change of the code under GPLv2 implies that these changes need to be released and made available to everyone, while the LGPLv2.1 allows modifications without releasing the source code. At the same time, both licenses imply that the attribution to the author is necessary, so if someone modifies the code and uses it for their purposes, they still need to say that the original package was developed by this and that author (Ivan Svetunkov in this case). The reason I decided to change the license is that one of software vendors that I sometimes work with pointed out that they cannot touch anything under GPL because of the restrictions above. Moving to the LGPL will now allow them using my packages in their own developments. This applies to such functions as <a href="https://openforecast.org/adam/">adam()</a>, <a href="/en/category/r-en/smooth/es-function/">es()</a>, <a href="https://cran.r-project.org/web/packages/smooth/vignettes/ssarima.html">msarima()</a>, <a href="/en/2022/08/02/complex-exponential-smoothing/">ces()</a>, <a href="https://cran.r-project.org/web/packages/greybox/vignettes/alm.html">alm()</a> and others. I don&#8217;t mind, as long as they say who developed the original thing.</p>
<p>What happens now? The versions of the <code>smooth</code> and <code>greybox</code> packages under GPLv2 are available on github <a href="https://github.com/config-i1/smooth/releases/tag/v3.2.2">here</a> and <a href="https://github.com/config-i1/greybox/releases/tag/v1.0.9">here</a> respectively, so if you are a radical open source adept, you can download those releases, install them and use them instead of the new versions. But from now on, I plan to support the packages under the LGPLv2.1 license.</p>
<p>Finally, a small teaser: colleagues of mine have agreed to help me in translating the R code into Python (actually, I am quite useless in this endeavor, they do everything), so at some point in future, we might see the <code>smooth</code> and <code>greybox</code> packages in Python. And they will also be licensed under LGPLv2.1.</p>
<p>Message <a href="https://openforecast.org/2023/09/19/smooth-greybox-under-lgplv2-1/">smooth &#038; greybox under LGPLv2.1</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2023/09/19/smooth-greybox-under-lgplv2-1/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>smooth v3.2.0: what&#8217;s new?</title>
		<link>https://openforecast.org/2023/01/30/smooth-v3-2-0-what-s-new/</link>
					<comments>https://openforecast.org/2023/01/30/smooth-v3-2-0-what-s-new/#comments</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Mon, 30 Jan 2023 13:06:47 +0000</pubDate>
				<category><![CDATA[About es() function]]></category>
		<category><![CDATA[adam()]]></category>
		<category><![CDATA[ARIMA]]></category>
		<category><![CDATA[ETS]]></category>
		<category><![CDATA[Package smooth for R]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[Regression]]></category>
		<category><![CDATA[Univariate models]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3063</guid>

					<description><![CDATA[<p>smooth package has reached version 3.2.0 and is now on CRAN. While the version change from 3.1.7 to 3.2.0 looks small, this has introduced several substantial changes and represents a first step in moving to the new C++ code in the core of the functions. In this short post, I will outline the main new [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2023/01/30/smooth-v3-2-0-what-s-new/">smooth v3.2.0: what&#8217;s new?</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>smooth package has reached version 3.2.0 and is now <a href="https://cran.r-project.org/package=smooth">on CRAN</a>. While the version change from 3.1.7 to 3.2.0 looks small, this has introduced several substantial changes and represents a first step in moving to the new C++ code in the core of the functions. In this short post, I will outline the main new features of smooth 3.2.0.</p>
<p><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/smooth2.png&amp;nocache=1"><img loading="lazy" decoding="async" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/smooth2-300x218.png&amp;nocache=1" alt="" width="300" height="218" class="aligncenter size-medium wp-image-3065" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/smooth2-300x218.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/smooth2-1024x745.png&amp;nocache=1 1024w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/smooth2-768x559.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/smooth2-1536x1117.png&amp;nocache=1 1536w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/smooth2.png&amp;nocache=1 1650w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<h3>New engines for ETS, MSARIMA and SMA</h3>
<p>The first and one of the most important changes is the new engine for the ETS (Error-Trend-Seasonal exponential smoothing model), MSARIMA (Multiple Seasonal ARIMA) and SMA (Simple Moving Average), implemented respectively in <code>es()</code>, <code>msarima()</code> and <code>sma()</code> functions. The new engine was developed for <code>adam()</code> and the three models above can be considered as special cases of it. You can read more about ETS in ADAM monograph, starting from<a href="https://openforecast.org/adam/ETSConventional.html"> Chapter 4</a>; MSARIMA is discussed in <a href="https://openforecast.org/adam/ADAMARIMA.html">Chapter 9</a>, while SMA is briefly discussed in <a href="https://openforecast.org/adam/simpleForecastingMethods.html#SMA">Subsection 3.3.3</a>.</p>
<p>The <code>es()</code> function now implements the ETS close to the conventional one, assuming that the error term follows normal distribution. It still supports explanatory variables (discussed in <a href="https://openforecast.org/adam/ADAMX.html">Chapter 10 of ADAM monograph</a>) and advanced estimators (<a href="https://openforecast.org/adam/ADAMETSEstimation.html">Chapter 11</a>), and it has the same syntax as the previous version of the function had, but now acts as a wrapper for <code>adam()</code>. This means that it is now faster, more accurate and requires less memory than it used to. <code>msarima()</code> being a wrapper of <code>adam()</code> as well, is now also faster and more accurate than it used to be. But in addition to that both functions now support the methods that were developed for <code>adam()</code>, including <code>vcov()</code>, <code>confint()</code>, <code>summary()</code>, <code>rmultistep()</code>, <code>reapply()</code>, <code>plot()</code> and others. So, now you can do more thorough analysis and improve the models using all these advanced instruments (see, for example, <a href="https://openforecast.org/adam/diagnostics.html">Chapter 14 of ADAM</a>).</p>
<p>The main reason why I moved the functions to the new engine was to clean up the code and remove the old chunks that were developed when I only started learning C++. A side effect, as you see, is that the functions have now been improved in a variety of ways.</p>
<p>And to be on the safe side, the old versions of the functions are still available in <code>smooth</code> under the names <code>es_old()</code>, <code>msarima_old()</code> and <code>sma_old()</code>. They will be removed from the package if it ever reaches the v.4.0.0.</p>
<h3>New methods for ADAM</h3>
<p>There are two new methods for <code>adam()</code> that can be used in a variety of cases. The first one is <code>simulate()</code>, which will generate data based on the estimated ADAM, whatever the original model is (e.g. mixture of ETS, ARIMA and regression on the data with multiple frequencies). Here is how it can be used:</p>
<pre class="decode">adam(BJsales, "AAdN") |>
     simulate() |>
     plot()</pre>
<p>which will produce a plot similar to the following:</p>
<div id="attachment_3077" style="width: 650px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamSimulate.png&amp;nocache=1"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3077" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamSimulate-1024x597.png&amp;nocache=1" alt="Simulated data based on adam() applied to Box-Jenkins sales data" width="640" height="373" class="size-large wp-image-3077" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamSimulate-1024x597.png&amp;nocache=1 1024w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamSimulate-300x175.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamSimulate-768x448.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamSimulate.png&amp;nocache=1 1200w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a><p id="caption-attachment-3077" class="wp-caption-text">Simulated data based on adam() applied to Box-Jenkins sales data</p></div>
<p>This can be used for research, when a more controlled environment is needed. If you want to fine tune the parameters of ADAM before simulating the data, you can save the output in an object and amend its parameters. For example:</p>
<pre class="decode">testModel <- adam(BJsales, "AAdN")
testModel$persistence <- c(0.5, 0.2)
simulate(testModel)</pre>
<p>The second new method is the <code>xtable()</code> from the respective <code>xtable</code> package. It produces LaTeX version of the table from the summary of ADAM. Here is an example of a summary from ADAM ETS:</p>
<pre class="decode">adam(BJsales, "AAdN") |>
     summary()</pre>
<pre>Model estimated using adam() function: ETS(AAdN)
Response variable: BJsales
Distribution used in the estimation: Normal
Loss function type: likelihood; Loss function value: 256.1516
Coefficients:
      Estimate Std. Error Lower 2.5% Upper 97.5%  
alpha   0.9514     0.1292     0.6960      1.0000 *
beta    0.3328     0.2040     0.0000      0.7358  
phi     0.8560     0.1671     0.5258      1.0000 *
level 203.2835     5.9968   191.4304    215.1289 *
trend  -2.6793     4.7705   -12.1084      6.7437  

Error standard deviation: 1.3623
Sample size: 150
Number of estimated parameters: 6
Number of degrees of freedom: 144
Information criteria:
     AIC     AICc      BIC     BICc 
524.3032 524.8907 542.3670 543.8387</pre>
<p>As you can see in the output above, the function generates the confidence intervals for the parameters of the model, including the smoothing parameters, dampening parameter and the initial states. This summary can then be used to generate the LaTeX code for the main part of the table:</p>
<pre class="decode">adam(BJsales, "AAdN") |>
     xtable()</pre>
<p>which will looks something like this:</p>
<div id="attachment_3073" style="width: 650px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamXtable.png&amp;nocache=1"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-3073" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamXtable-1024x303.png&amp;nocache=1" alt="Summary of adam()" width="512" height="152" class="size-large wp-image-3073" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamXtable-1024x303.png&amp;nocache=1 1024w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamXtable-300x89.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamXtable-768x227.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2023/01/adamXtable.png&amp;nocache=1 1207w" sizes="auto, (max-width: 512px) 100vw, 512px" /></a><p id="caption-attachment-3073" class="wp-caption-text">Summary of adam()</p></div>
<h3>Other improvements</h3>
<p>First, one of the major changes in <code>smooth</code> functions is the new backcasting mechanism for <code>adam()</code>, <code>es()</code> and <code>msarima()</code> (this is discussed in <a href="https://openforecast.org/adam/ADAMInitialisation.html">Section 11.4 of ADAM monograph</a>). The main difference with the old one is that now it does not backcast the parameters for the explanatory variables and estimates them separately via optimisation. This feature appeared to be important for some of users who wanted to try MSARIMAX/ETSX (a model with explanatory variables) but wanted to use backcasting as the initialisation. These users then wanted to get a summary, analysing the uncertainty around the estimates of parameters for exogenous variables, but could not because the previous implementation would not estimate them explicitly. This is now available. Here is an example:</p>
<pre class="decode">cbind(BJsales, BJsales.lead) |>
    adam(model="AAdN", initial="backcasting") |>
    summary()</pre>
<pre>Model estimated using adam() function: ETSX(AAdN)
Response variable: BJsales
Distribution used in the estimation: Normal
Loss function type: likelihood; Loss function value: 255.1935
Coefficients:
             Estimate Std. Error Lower 2.5% Upper 97.5%  
alpha          0.9724     0.1108     0.7534      1.0000 *
beta           0.2904     0.1368     0.0199      0.5607 *
phi            0.8798     0.0925     0.6970      1.0000 *
BJsales.lead   0.1662     0.2336    -0.2955      0.6276  

Error standard deviation: 1.3489
Sample size: 150
Number of estimated parameters: 5
Number of degrees of freedom: 145
Information criteria:
     AIC     AICc      BIC     BICc 
520.3870 520.8037 535.4402 536.4841</pre>
<p>As you can see in the output above, the initial level and trend of the model are not reported, because they were estimated via backcasting. However, we get the value of the parameter <code>BJsales.lead</code> and the uncertainty around it. The old backcasting approach is now called "complete", implying that all values of the state vector are produce via backcasting.</p>
<p>Second, <code>forecast.adam()</code> now has a parameter <code>scenarios</code>, which when TRUE will return the simulated paths from the model. This only works when <code>interval="simulated"</code> and can be used for the analysis of possible forecast trajectories.</p>
<p>Third, the <code>plot()</code> method now can also produce ACF/PACF for the squared residuals for all <code>smooth</code> functions. This becomes useful if you suspect that your data has ARCH elements and want to see if they need to be modelled separately. This can also be done using <code>adam()</code> and <code>sm()</code> and is discussed in <a href="https://openforecast.org/adam/ADAMscaleModel.html">Chapter 17 of the monograph</a>.</p>
<p>Finally, the <code>sma()</code> function now has the <code>fast</code> parameter, which when true will use a modified Ternary search for the best order based on information criteria. It might not give the global minimum, but it works much faster than the exhaustive search.</p>
<h3>Conclusions</h3>
<p>These are the main new features in the package. I feel that the main job in <code>smooth</code> is already done, and all I can do now is just tune the functions and improve the existing code. I want to move all the functions to the new engine and ditch the old one, but this requires much more time than I have. So, I don't expect to finish this any time soon, but I hope I'll get there someday. On the other hand, I'm not sure that spending much time on developing an R package is a wise idea, given that nowadays people tend to use Python. I would develop Python analogue of the <code>smooth</code> package, but currently I don't have the necessary expertise and time to do that. Besides, there already exist great libraries, such as <a href="https://github.com/Nixtla/nixtla/tree/main/tsforecast">tsforecast</a> from <a href="https://github.com/Nixtla/nixtla">nixtla</a> and <a href="https://www.sktime.org/">sktime</a>. I am not sure that another library, implementing ETS and ARIMA is needed in Python. What do you think?</p>
<p>Message <a href="https://openforecast.org/2023/01/30/smooth-v3-2-0-what-s-new/">smooth v3.2.0: what&#8217;s new?</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2023/01/30/smooth-v3-2-0-what-s-new/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Smooth forecasting with the smooth package in R</title>
		<link>https://openforecast.org/2023/01/04/smooth-forecasting-with-the-smooth-package-in-r/</link>
					<comments>https://openforecast.org/2023/01/04/smooth-forecasting-with-the-smooth-package-in-r/#comments</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Wed, 04 Jan 2023 09:59:45 +0000</pubDate>
				<category><![CDATA[Package smooth for R]]></category>
		<category><![CDATA[Papers]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[papers]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=3052</guid>

					<description><![CDATA[<p>Authors: Ivan Svetunkov Abstract: There are many forecasting related packages in R with varied popularity, the most famous of all being forecast, which implements several important forecasting approaches, such as ARIMA, ETS, TBATS and others. However, the main issue with the existing functionality is the lack of flexibility for research purposes, when it comes to [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2023/01/04/smooth-forecasting-with-the-smooth-package-in-r/">Smooth forecasting with the smooth package in R</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><strong>Authors</strong>: Ivan Svetunkov</p>
<p><strong>Abstract</strong>: There are many forecasting related packages in R with varied popularity, the most famous of all being forecast, which implements several important forecasting approaches, such as ARIMA, ETS, TBATS and others. However, the main issue with the existing functionality is the lack of flexibility for research purposes, when it comes to modifying the implemented models. The R package smooth introduces a new approach to univariate forecasting, implementing ETS and ARIMA models in Single Source of Error (SSOE) state space form and implementing an advanced functionality for experiments and time series analysis. It builds upon the SSOE model and extends it by including explanatory variables, multiple frequencies, and introducing advanced forecasting instruments. In this paper, we explain the philosophy behind the package and show how the main functions work.</p>
<p><strong>DOI</strong>: <a href="https://doi.org/10.48550/arXiv.2301.01790">10.48550/arXiv.2301.01790</a></p>
<p><strong>How to cite</strong>: Svetunkov (2023). Smooth forecasting with the smooth package in R. OpenForecast.org</p>
<p><strong>The story of the paper</strong>: This paper was rejected from the Journal of Statistical Software by a reviewer maintaining the package competing with the <code>smooth</code>. Given that the paper was written specifically for that journal, and I have nowhere else to submit it, I&#8217;ve decided to upload it online and make it freely available.</p>
<p>And here is the smooth hex sticker for completeness. If you need one, get in touch with me.<br />
<a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2018/01/smooth.png&amp;nocache=1"><img loading="lazy" decoding="async" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2018/01/smooth-249x300.png&amp;nocache=1" alt="" width="249" height="300" class="aligncenter size-medium wp-image-1534" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2018/01/smooth-249x300.png&amp;nocache=1 249w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2018/01/smooth-768x925.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2018/01/smooth-850x1024.png&amp;nocache=1 850w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2018/01/smooth.png&amp;nocache=1 965w" sizes="auto, (max-width: 249px) 100vw, 249px" /></a></p>
<p>Message <a href="https://openforecast.org/2023/01/04/smooth-forecasting-with-the-smooth-package-in-r/">Smooth forecasting with the smooth package in R</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2023/01/04/smooth-forecasting-with-the-smooth-package-in-r/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>The first draft of &#8220;Forecasting and Analytics with ADAM&#8221;</title>
		<link>https://openforecast.org/2022/04/11/the-first-draft-of-forecasting-and-analytics-with-adam/</link>
					<comments>https://openforecast.org/2022/04/11/the-first-draft-of-forecasting-and-analytics-with-adam/#respond</comments>
		
		<dc:creator><![CDATA[Ivan Svetunkov]]></dc:creator>
		<pubDate>Mon, 11 Apr 2022 15:30:26 +0000</pubDate>
				<category><![CDATA[adam()]]></category>
		<category><![CDATA[ARIMA]]></category>
		<category><![CDATA[ETS]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[Regression]]></category>
		<category><![CDATA[Theory of forecasting]]></category>
		<category><![CDATA[ADAM]]></category>
		<category><![CDATA[regression]]></category>
		<category><![CDATA[smooth]]></category>
		<guid isPermaLink="false">https://openforecast.org/?p=2817</guid>

					<description><![CDATA[<p>After working on this for more than a year, I have finally prepared the first draft of my online monograph &#8220;Forecasting and Analytics with ADAM&#8220;. This is a monograph on the model that unites ETS, ARIMA and regression and introduces advanced features in univariate modelling, including: ETS in a new State Space form; ARIMA in [&#8230;]</p>
<p>Message <a href="https://openforecast.org/2022/04/11/the-first-draft-of-forecasting-and-analytics-with-adam/">The first draft of &#8220;Forecasting and Analytics with ADAM&#8221;</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div id="attachment_2819" style="width: 222px" class="wp-caption aligncenter"><a href="/wp-content/uploads/2022/03/Adam-Title-web.jpg"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-2819" src="/wp-content/uploads/2022/03/Adam-Title-web-212x300.jpg" alt="Forecasting and Analytics with ADAM" width="212" height="300" class="size-medium wp-image-2819" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/Adam-Title-web-212x300.jpg&amp;nocache=1 212w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/Adam-Title-web-724x1024.jpg&amp;nocache=1 724w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/Adam-Title-web-768x1087.jpg&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/Adam-Title-web.jpg&amp;nocache=1 1000w" sizes="auto, (max-width: 212px) 100vw, 212px" /></a><p id="caption-attachment-2819" class="wp-caption-text">Forecasting and Analytics with ADAM</p></div>
<p>After working on this for <a href="/en/2021/01/13/the-creation-of-adam-next-step-in-statistical-forecasting/" rel="noopener">more than</a> <a href="/en/2021/02/28/after-the-creation-of-adam-smooth-v3-1-0/">a year</a>, I have finally prepared the first draft of my online monograph &#8220;<a href="https://openforecast.org/adam/" rel="noopener" target="_blank">Forecasting and Analytics with ADAM</a>&#8220;. This is a monograph on the model that unites ETS, ARIMA and regression and introduces advanced features in univariate modelling, including:</p>
<ol>
<li>ETS in a new State Space form;</li>
<li>ARIMA in a new State Space form;</li>
<li>Regression;</li>
<li>TVP regression;</li>
<li>Combinations of (1), (2) and either (3), or (4);</li>
<li>Automatic selection/combination for ETS;</li>
<li>Automatic orders selection for ARIMA;</li>
<li>Variables selection for regression part;</li>
<li>Normal and non-normal distributions;</li>
<li>Automatic selection of most suitable distribution;</li>
<li>Multiple seasonality;</li>
<li>Occurrence part of the model to handle zeroes in data (intermittent demand);</li>
<li>Modelling scale of distribution (GARCH and beyond);</li>
<li>Handling uncertainty of estimates of parameters.</li>
</ol>
<p>The model and all its features are already implemented in <code>adam()</code> function from <code>smooth</code> package for R (you need v3.1.6 from CRAN for all the features listed above). The function supports many options that allow one experimenting with univariate forecasting, allowing to build complex models, combining elements from the list above. The monograph explaining how models underlying ADAM and how to work with them is <a href="https://openforecast.org/adam/" rel="noopener" target="_blank">available online</a>, and I plan to produce several physical copies of it after refining the text. Furthermore, I have already asked two well-known academics to act as reviewers of the monograph to collect the feedback and improve the monograph, and if you want to act as a reviewer as well, please let me know.</p>
<h3>Examples in R</h3>
<p>Just to give you a flavour of ADAM, I decided to provide a couple of examples on time series <code>AirPassengers</code> (included in <code>datasets</code> package in R). The first one is the ADAM ETS.</p>
<p>Building and selecting the most appropriate ADAM ETS comes to running the following line of code:</p>
<pre class="decode">adamETSAir <- adam(AirPassengers, h=12, holdout=TRUE)</pre>
<p>In this case, ADAM will select the most appropriate ETS model for the data, creating a holdout of the last 12 observations. We can see the details of the model by printing the output:</p>
<pre class="decode">adamETSAir</pre>
<pre>Time elapsed: 0.75 seconds
Model estimated using adam() function: ETS(MAM)
Distribution assumed in the model: Gamma
Loss function type: likelihood; Loss function value: 467.2981
Persistence vector g:
 alpha   beta  gamma 
0.7691 0.0053 0.0000 

Sample size: 132
Number of estimated parameters: 17
Number of degrees of freedom: 115
Information criteria:
      AIC      AICc       BIC      BICc 
 968.5961  973.9646 1017.6038 1030.7102 

Forecast errors:
ME: 9.537; MAE: 20.784; RMSE: 26.106
sCE: 43.598%; Asymmetry: 64.8%; sMAE: 7.918%; sMSE: 0.989%
MASE: 0.863; RMSSE: 0.833; rMAE: 0.273; rRMSE: 0.254</pre>
<p>The output above provides plenty of detail on what was estimated and how. Some of these elements have been discussed in <a href="/en/2016/11/02/smooth-package-for-r-es-function-part-ii-pure-additive-models/">one of my previous posts</a> on <code>es()</code> function. The new thing is the information about the assumed distribution for the response variable. By default, ADAM works with Gamma distribution in case of multiplicative error model. This is done to make model more robust in cases of low volume data, where the Normal distribution might produce negative numbers (see <a href="/en/2021/06/30/isf2021-how-to-make-multiplicative-ets-work-for-you/">my presentation</a> on this issues). In case of high volume data, the Gamma distribution will perform similar to the Normal one. The pure multiplicative ADAM ETS is discussed in <a href="https://openforecast.org/adam/ADAMETSPureMultiplicativeChapter.html" rel="noopener" target="_blank">Chapter 6 of ADAM monograph</a>. If Gamma is not suitable, then the other distribution can be selected via the <code>distribution</code> parameter. There is also an automated distribution selection approach in the function <code>auto.adam()</code>:</p>
<pre class="decode">adamETSAutoAir <- auto.adam(AirPassengers, h=12, holdout=TRUE)
adamETSAutoAir</pre>
<pre>Time elapsed: 3.86 seconds
Model estimated using auto.adam() function: ETS(MAM)
Distribution assumed in the model: Normal
Loss function type: likelihood; Loss function value: 466.0744
Persistence vector g:
 alpha   beta  gamma 
0.8054 0.0000 0.0000 

Sample size: 132
Number of estimated parameters: 17
Number of degrees of freedom: 115
Information criteria:
      AIC      AICc       BIC      BICc 
 966.1487  971.5172 1015.1564 1028.2628 

Forecast errors:
ME: 9.922; MAE: 21.128; RMSE: 26.246
sCE: 45.36%; Asymmetry: 65.4%; sMAE: 8.049%; sMSE: 1%
MASE: 0.877; RMSSE: 0.838; rMAE: 0.278; rRMSE: 0.255</pre>
<p>As we see from the output above, the Normal distribution is more appropriate for the data in terms of AICc than the other ones tried out by the function (by default the list includes Normal, Laplace, S, Generalised Normal, Gamma, Inverse Gaussian and Log Normal distributions, but this can be amended by providing a vector of names via <code>distribution</code> parameter). The selection of ADAM ETS and distributions is discussed in <a href="https://openforecast.org/adam/ADAMSelection.html" rel="noopener" target="_blank">Chapter 15 of the monograph</a>.</p>
<p>Having obtained the model, we can diagnose it using <code>plot.adam()</code> function:</p>
<pre class="decode">par(mfcol=c(3,3))
plot(adamETSAutoAir,which=c(1,4,2,6,7,8,10,11,13))</pre>
<p>The <code>which</code> parameter specifies what type of plots to produce, you can find the list of plots in the documentation for <code>plot.adam()</code>. The code above will result in:<br />
<div id="attachment_2824" style="width: 310px" class="wp-caption aligncenter"><a href="/wp-content/uploads/2022/03/adamETSAirDiagnostics.png"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-2824" src="/wp-content/uploads/2022/03/adamETSAirDiagnostics-300x175.png" alt="Diagnostics plots for ADAM ETS on AirPassengers data" width="300" height="175" class="size-medium wp-image-2824" /></a><p id="caption-attachment-2824" class="wp-caption-text">Diagnostics plots for ADAM ETS on AirPassengers data</p></div>
The diagnostic plots are discussed in the <a href="https://openforecast.org/adam/diagnostics.html" rel="noopener" target="_blank">Chapter 14 of ADAM monograph</a>. The plot above does not show any serious issues with the model.</p>
<p>Just for the comparison, we could also try fitting the most appropriate ADAM ARIMA to the data (this model is discussed in <a href="https://openforecast.org/adam/ADAMARIMA.html" rel="noopener" target="_blank">Chapter 9</a>). The code in this case is slightly more complicated, because we need to switch off ETS part of the model and define the maximum orders of ARIMA to try:</p>
<pre class="decode">adamARIMAAir <- adam(AirPassengers, model="NNN", h=12, holdout=TRUE,
                     orders=list(ar=c(3,2),i=c(2,1),ma=c(3,2),select=TRUE))</pre>
<p>This results in the following <a href="https://openforecast.org/adam/ARIMASelection.html" rel="noopener" target="_blank">automatically selected</a> ARIMA model:</p>
<pre>Time elapsed: 3.54 seconds
Model estimated using auto.adam() function: SARIMA(0,1,1)[1](0,1,1)[12]
Distribution assumed in the model: Normal
Loss function type: likelihood; Loss function value: 491.7117
ARMA parameters of the model:
MA:
 theta1[1] theta1[12] 
   -0.1952    -0.0720 

Sample size: 132
Number of estimated parameters: 16
Number of degrees of freedom: 116
Information criteria:
     AIC     AICc      BIC     BICc 
1015.423 1020.154 1061.548 1073.097 

Forecast errors:
ME: -13.795; MAE: 16.65; RMSE: 21.644
sCE: -63.064%; Asymmetry: -79.4%; sMAE: 6.343%; sMSE: 0.68%
MASE: 0.691; RMSSE: 0.691; rMAE: 0.219; rRMSE: 0.21</pre>
<p>Given that ADAM ETS and ADAM ARIMA are formulated in the same framework, they are directly comparable using information critirea. Comparing AICc of the models <code>adamETSAutoAir</code> and <code>adamARIMAAir</code>, we can conclude that the former is more appropriate to the data than the latter. However, the default ARIMA works with the Normal distribution, which might not be appropriate for the data, so we can revert to the <code>auto.adam()</code> to select the better one:</p>
<pre class="decode">adamAutoARIMAAir <- auto.adam(AirPassengers, model="NNN", h=12, holdout=TRUE,
                              orders=list(ar=c(3,2),i=c(2,1),ma=c(3,2),select=TRUE))</pre>
<p>This will take more computational time, but will result in a different model with a lower AICc (which is still higher than the one in ADAM ETS):</p>
<pre>Time elapsed: 25.46 seconds
Model estimated using auto.adam() function: SARIMA(0,1,1)[1](0,1,1)[12]
Distribution assumed in the model: Log-Normal
Loss function type: likelihood; Loss function value: 472.923
ARMA parameters of the model:
MA:
 theta1[1] theta1[12] 
   -0.2785    -0.5530 

Sample size: 132
Number of estimated parameters: 16
Number of degrees of freedom: 116
Information criteria:
      AIC      AICc       BIC      BICc 
 977.8460  982.5764 1023.9708 1035.5197 

Forecast errors:
ME: -12.968; MAE: 13.971; RMSE: 19.143
sCE: -59.285%; Asymmetry: -91.7%; sMAE: 5.322%; sMSE: 0.532%
MASE: 0.58; RMSSE: 0.611; rMAE: 0.184; rRMSE: 0.186</pre>
<p>Note that although the AICc is higher for ARIMA than for ETS, the former has lower error measures than the latter. So, the higher AICc does not necessarily mean that the model is not good. But if we rely on the information criteria, then we should stick with ADAM ETS and we can then produce the forecasts for the next 12 observations (see <a href="https://openforecast.org/adam/ADAMForecasting.html" rel="noopener" target="_blank">Chapter 18</a>):</p>
<pre class="decode">adamETSAutoAirForecast <- forecast(adamETSAutoAir, h=12, interval="prediction",
                                   level=c(0.9,0.95,0.99))
par(mfcol=c(1,1))
plot(adamETSAutoAirForecast)</pre>
<div id="attachment_2839" style="width: 310px" class="wp-caption aligncenter"><a href="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/adamETSAirForecast.png&amp;nocache=1"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-2839" src="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/adamETSAirForecast-300x175.png&amp;nocache=1" alt="Forecast from ADAM ETS" width="300" height="175" class="size-medium wp-image-2839" srcset="https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/adamETSAirForecast-300x175.png&amp;nocache=1 300w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/adamETSAirForecast-1024x597.png&amp;nocache=1 1024w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/adamETSAirForecast-768x448.png&amp;nocache=1 768w, https://openforecast.org/wp-content/webpc-passthru.php?src=https://openforecast.org/wp-content/uploads/2022/03/adamETSAirForecast.png&amp;nocache=1 1200w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-2839" class="wp-caption-text">Forecast from ADAM ETS</p></div>
Finally, if we want to do a more in-depth analysis of parameters of ADAM, we can also produce the summary, which will create the confidence intervals for the parameters of the model:</p>
<pre class="decode">summary(adamETSAutoAir)</pre>
<pre>Model estimated using auto.adam() function: ETS(MAM)
Response variable: data
Distribution used in the estimation: Normal
Loss function type: likelihood; Loss function value: 466.0744
Coefficients:
            Estimate Std. Error Lower 2.5% Upper 97.5%  
alpha         0.8054     0.0864     0.6343      0.9761 *
beta          0.0000     0.0203     0.0000      0.0401  
gamma         0.0000     0.0382     0.0000      0.0755  
level        96.2372     6.8596    82.6496    109.7919 *
trend         2.0901     0.3955     1.3068      2.8716 *
seasonal_1    0.9145     0.0077     0.9003      0.9372 *
seasonal_2    0.8999     0.0081     0.8857      0.9227 *
seasonal_3    1.0308     0.0094     1.0165      1.0535 *
seasonal_4    0.9885     0.0077     0.9743      1.0112 *
seasonal_5    0.9856     0.0072     0.9713      1.0083 *
seasonal_6    1.1165     0.0093     1.1023      1.1392 *
seasonal_7    1.2340     0.0115     1.2198      1.2568 *
seasonal_8    1.2254     0.0105     1.2112      1.2481 *
seasonal_9    1.0668     0.0094     1.0526      1.0896 *
seasonal_10   0.9256     0.0087     0.9113      0.9483 *
seasonal_11   0.8040     0.0075     0.7898      0.8268 *

Error standard deviation: 0.0367
Sample size: 132
Number of estimated parameters: 17
Number of degrees of freedom: 115
Information criteria:
      AIC      AICc       BIC      BICc 
 966.1487  971.5172 1015.1564 1028.2628 </pre>
<p>Note that the <code>summary()</code> function might complain about the Observed Fisher Information. This is because the covariance matrix of parameters is calculated numerically and sometimes the likelihood is not maximised properly. I have not been able to fully resolve this issue yet, but hopefully will do at some point. The summary above shows, for example, that the smoothing parameters \(\beta\) and \(\gamma\) are not significantly different from zero (on 5% level), while \(\alpha\) is expected to vary between 0.6343 and 0.9761 in 95% of the cases. You can read more about the uncertainty of parameters in ADAM in <a href="https://openforecast.org/adam/ADAMUncertainty.html" rel="noopener" target="_blank">Chapter 16</a> of the monograph.</p>
<p>As for the other features of ADAM, here is a brief guide:</p>
<ul>
<li>If you work with multiple seasonal data, then you might need to specify the seasonality via the <code>lags</code> parameter, for example as <code>lags=c(24,7*24)</code> in case of hourly data. This is discussed in <a href="https://openforecast.org/adam/multiple-frequencies-in-adam.html" rel="noopener" target="_blank">Chapter 12</a>;</li>
<li>If you have intermittent data, then you should read <a href="https://openforecast.org/adam/ADAMIntermittent.html" rel="noopener" target="_blank">Chapter 13</a>, which explains how to work with the <code>occurrence</code> parameter of the function;</li>
<li>Explanatory variables are discussed in <a href="https://openforecast.org/adam/ADAMX.html" rel="noopener" target="_blank">Chapter 10</a> and are handled in the <code>adam()</code> function via the <code>formula</code> parameter;</li>
<li>In the cases of heteroscedasticity (time varying or induced by some explanatory variables), there a scale model (which is discussed in <a href="https://openforecast.org/adam/ADAMscaleModel.html" rel="noopener" target="_blank">Chapter 17</a> and implemented as <code>sm()</code> method for the <code>adam</code> class).</li>
</ul>
<p>You can also experiment with advanced estimators (<a href="https://openforecast.org/adam/ADAMETSEstimation.html" rel="noopener" target="_blank">Chapter 11</a>, including custom loss functions) via the <code>loss</code> parameter and forecast combinations (<a href="https://openforecast.org/adam/ADAMCombinations.html" rel="noopener" target="_blank">Section 15.4</a>).</p>
<p>Long story short, if you are interested in univariate forecasting, then do give ADAM a try - it might have the flexibility you needed for your experiments. If you are worried about its accuracy, check out <a href="/en/2021/02/28/after-the-creation-of-adam-smooth-v3-1-0/">this post</a>, where I compared ADAM with other models.</p>
<p>And, as a friend of mine says, "Happy forecasting!"</p>
<p>Message <a href="https://openforecast.org/2022/04/11/the-first-draft-of-forecasting-and-analytics-with-adam/">The first draft of &#8220;Forecasting and Analytics with ADAM&#8221;</a> first appeared on <a href="https://openforecast.org">Open Forecasting</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://openforecast.org/2022/04/11/the-first-draft-of-forecasting-and-analytics-with-adam/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
