{"id":1264,"date":"2017-02-10T04:30:42","date_gmt":"2017-02-10T04:30:42","guid":{"rendered":"http:\/\/kourentzes.com\/forecasting\/?p=1264"},"modified":"2017-02-11T02:01:48","modified_gmt":"2017-02-11T02:01:48","slug":"forecasting-time-series-with-neural-networks-in-r","status":"publish","type":"post","link":"https:\/\/kourentzes.com\/forecasting\/2017\/02\/10\/forecasting-time-series-with-neural-networks-in-r\/","title":{"rendered":"Forecasting time series with neural networks in R"},"content":{"rendered":"<p style=\"text-align: justify;\">I have been looking for a package to do time series modelling in R with neural networks for quite some time with limited success. The only implementation I am aware of that takes care of autoregressive lags in a user-friendly way is the <code>nnetar<\/code> function in the <code>forecast<\/code> package, written by <a href=\"http:\/\/robjhyndman.com\/hyndsight\/\" target=\"_blank\">Rob Hyndman<\/a>. In my view there is space for a more flexible implementation, so I decided to write a few functions for that purpose. For now these are included in the <a href=\"http:\/\/kourentzes.com\/forecasting\/2014\/04\/19\/tstools-for-r\/\" target=\"_blank\">TStools<\/a> package that is available in <a href=\"https:\/\/github.com\/trnnick\/TStools\" target=\"_blank\">GitHub<\/a>, but when I am happy with their performance and flexibility I will put them in a package of their own.<\/p>\n<p style=\"text-align: justify;\">Here I will provide a quick overview of what these is available right now. I plan to write a more detailed post about these functions when I get the time.<\/p>\n<p style=\"text-align: justify;\">For this example I will model the <code>AirPassengers<\/code> time series available in R. I have kept the last 24 observations as a test set and will use the rest to fit the neural networks. Currently there are two types of neural network available, both feed-forward: (i) multilayer perceptrons (use function <code>mlp<\/code>); and extreme learning machines (use function <code>elm<\/code>).<\/p>\n<pre><span style=\"color: #008000;\"># Fit MLP<\/span>\r\nmlp.fit &lt;- mlp(y.in)\r\nplot(mlp.fit)\r\nprint(mlp.fit)\r\n<\/pre>\n<p style=\"text-align: justify;\">This is the basic command to fit an MLP network to a time series. This will attempt to automatically specify autoregressive inputs and any necessary pre-processing of the time series. With the pre-specified arguments it trains 20 networks which are used to produce an ensemble forecast and a single hidden layer with 5 nodes. You can override any of these settings. The output of <code>print<\/code> is a summary of the fitted network:<\/p>\n<pre>MLP fit with 5 hidden nodes and 20 repetitions.\r\nSeries modelled in differences: D1.\r\nUnivariate lags: (1,3,4,6,7,8,9,10,12)\r\nDeterministic seasonal dummies included.\r\nForecast combined using the median operator.\r\nMSE: 6.2011.\r\n<\/pre>\n<p style=\"text-align: justify;\">As you can see the function determined that level differences are needed to <a href=\"http:\/\/kourentzes.com\/forecasting\/2016\/12\/28\/can-neural-networks-predict-trended-time-series\/\" target=\"_blank\">capture the trend<\/a>. It also selected some autoregressive lags and decided to also use dummy variables for the seasonality. Using <code>plot<\/code> displays the architecture of the network (Fig. 1).<\/p>\n<div id=\"attachment_1265\" style=\"width: 410px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_mlp.png\"><img aria-describedby=\"caption-attachment-1265\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-1265\" src=\"http:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_mlp.png\" width=\"400\" height=\"308\" srcset=\"https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_mlp.png 650w, https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_mlp-150x115.png 150w, https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_mlp-300x231.png 300w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><p id=\"caption-attachment-1265\" class=\"wp-caption-text\">Fig. 1. Output of <code>plot(mlp.fit).<\/code><\/p><\/div>\n<p style=\"text-align: justify;\">The light red inputs represent the binary dummies used to code seasonality, while the grey ones are autoregressive lags. To produce forecasts you can type:<\/p>\n<pre>mlp.frc &lt;- forecast(mlp.fit,h=tst.n)\r\nplot(mlp.frc)\r\n<\/pre>\n<p style=\"text-align: justify;\">Fig. 2 shows the ensemble forecast, together with the forecasts of the individual neural networks. You can control the way that forecasts are combined (I recommend using the <a href=\"http:\/\/kourentzes.com\/forecasting\/2014\/04\/19\/neural-network-ensemble-operators-for-time-series-forecasting\/\" target=\"_blank\">median or mode operators<\/a>), as well as the size of the ensemble.<\/p>\n<div id=\"attachment_1267\" style=\"width: 410px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/forecast_mlp.png\"><img aria-describedby=\"caption-attachment-1267\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-1267\" src=\"http:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/forecast_mlp.png\" width=\"400\" height=\"308\" srcset=\"https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/forecast_mlp.png 650w, https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/forecast_mlp-150x115.png 150w, https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/forecast_mlp-300x231.png 300w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><p id=\"caption-attachment-1267\" class=\"wp-caption-text\">Fig. 2. Output of the <code>plot<\/code> function for the MLP forecasts.<\/p><\/div>\n<p style=\"text-align: justify;\">You can also let it choose the number of hidden nodes. There are various options for that, but all are computationally expensive (I plan to move the base code to CUDA at some point, so that computational cost stops being an issue).<\/p>\n<pre><span style=\"color: #008000;\"># Fit MLP with automatic hidden layer specification<\/span>\r\nmlp2.fit &lt;- mlp(y.in,hd.auto.type=\"valid\",hd.max=10)\r\nprint(round(mlp2.fit$MSEH,4))\r\n<\/pre>\n<p style=\"text-align: justify;\">This will evaluate from 1 up to 10 hidden nodes and pick the best on validation set MSE. You can also use cross-validation (if you have patience&#8230;). You can ask it to output the errors for each size:<\/p>\n<pre>        MSE\r\nH.1  0.0083\r\nH.2  0.0066\r\nH.3  0.0065\r\nH.4  0.0066\r\nH.5  0.0071\r\nH.6  0.0074\r\nH.7  0.0061\r\nH.8  0.0076\r\nH.9  0.0083\r\nH.10 0.0076\r\n<\/pre>\n<p style=\"text-align: justify;\">There are a few experimental options in specifying various aspects of the neural networks, which are not fully documented and is probably best if you stay away from them for now!<\/p>\n<p style=\"text-align: justify;\">ELMs work pretty much in the same way, although for these I have made default the automatic specification of the hidden layer.<\/p>\n<pre><span style=\"color: #008000;\"># Fit ELM<\/span>\r\nelm.fit &lt;- elm(y.in)\r\nprint(elm.fit)\r\nplot(elm.fit)\r\n<\/pre>\n<p style=\"text-align: justify;\">This gives the following network summary:<\/p>\n<pre>ELM fit with 100 hidden nodes and 20 repetitions.\r\nSeries modelled in differences: D1.\r\nUnivariate lags: (1,3,4,6,7,8,9,10,12)\r\nDeterministic seasonal dummies included.\r\nForecast combined using the median operator.\r\nOutput weight estimation using: lasso.\r\nMSE: 83.0044.\r\n<\/pre>\n<p style=\"text-align: justify;\">I appreciate that using 100 hidden nodes on such a short time series can make some people uneasy, but I am using a shrinkage estimator instead of conventional least squares to estimate the weights, which in fact eliminates most of the connections. This is apparent in the network architecture in Fig. 3. Only the nodes connected with the black lines to the output layer contribute to the forecasts. The remaining connection weights have been shrunk to zero.<\/p>\n<div id=\"attachment_1268\" style=\"width: 410px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_elm.png\"><img aria-describedby=\"caption-attachment-1268\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-1268\" src=\"http:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_elm.png\" width=\"400\" height=\"308\" srcset=\"https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_elm.png 650w, https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_elm-150x115.png 150w, https:\/\/kourentzes.com\/forecasting\/wp-content\/uploads\/2017\/02\/plot_elm-300x231.png 300w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><p id=\"caption-attachment-1268\" class=\"wp-caption-text\">Fig. 3. ELM network architecture.<\/p><\/div>\n<p>Another nice thing about these functions is that you can call them from the <a href=\"http:\/\/robjhyndman.com\/software\/thief\/\" target=\"_blank\">thief<\/a> package, which implements <a href=\"http:\/\/kourentzes.com\/forecasting\/2015\/08\/28\/forecasting-with-temporal-hierarchies-2\/\">Temporal Hierarchies<\/a> forecasting in R. You can do that in the following way:<\/p>\n<pre><span style=\"color: #008000;\"># Use THieF<\/span>\r\nlibrary(thief)\r\nmlp.thief &lt;- thief(y.in,h=tst.n,forecastfunction=mlp.thief)\r\n<\/pre>\n<p style=\"text-align: justify;\">There is a similar function for using ELM networks: <code>elm.thief<\/code>.<\/p>\n<p style=\"text-align: justify;\">Since for this simple example I kept some test set, I benchmark the forecasts against exponential smoothing:<\/p>\n<div class=\"table-responsive\"><table  style=\"width:220px;  margin-left:auto;margin-right:auto\"  class=\"easy-table easy-table-default \" >\n<thead>\r\n<tr><th  style=\"width:100px;text-align:left\" >Method<\/th>\n<th  style=\"width:60px;text-align:center\" >MAE<\/th>\n<\/tr>\n<\/thead>\n<tbody>\r\n<tr><td  style=\"text-align:left\" >MLP (5 nodes)<\/td>\n<td  style=\"text-align:center\" > 62.471<\/td>\n<\/tr>\n\r\n<tr><td  style=\"text-align:left\" >MLP (auto)<\/td>\n<td  style=\"text-align:center\" > 48.234<\/td>\n<\/tr>\n\r\n<tr><td  style=\"text-align:left\" >ELM<\/td>\n<td  style=\"text-align:center\" > 48.253<\/td>\n<\/tr>\n\r\n<tr><td  style=\"text-align:left\" >THieF-MLP<\/td>\n<td  style=\"text-align:center\" > 45.906<\/td>\n<\/tr>\n\r\n<tr><td  style=\"text-align:left\" >ETS<\/td>\n<td  style=\"text-align:center\" > 64.528<\/td>\n<\/tr>\n<\/tbody><\/table><\/div>\n<p style=\"text-align: justify;\">Temporal hierarchies, like <a href=\"http:\/\/kourentzes.com\/forecasting\/2014\/04\/19\/improving-forecasting-by-estimating-time-series-structural-components-across-multiple-frequencies\/\">MAPA<\/a>, are great for making your forecasts more robust and often more accurate. However, with neural networks the additional computational cost is evident!<\/p>\n<p style=\"text-align: justify;\">These functions are still in development, so the default values may change and there are a few experimental options that may give you good results or not!<\/p>\n<div class=\"SPOSTARBUST-Related-Posts\"><H3>Related Posts<\/H3><ul class=\"entry-meta\"><li class=\"SPOSTARBUST-Related-Post\"><a title=\"Stochastic Coherency in Forecast Reconciliation\" href=\"https:\/\/kourentzes.com\/forecasting\/2021\/07\/09\/stochastic-coherency-in-forecast-reconciliation\/\" rel=\"bookmark\">Stochastic Coherency in Forecast Reconciliation<\/a><\/li>\n<li class=\"SPOSTARBUST-Related-Post\"><a title=\"Visitor Arrivals Forecasts amid COVID-19: A Perspective from the Africa Team\" href=\"https:\/\/kourentzes.com\/forecasting\/2021\/07\/09\/visitor-arrivals-forecasts-amid-covid-19-a-perspective-from-the-africa-team\/\" rel=\"bookmark\">Visitor Arrivals Forecasts amid COVID-19: A Perspective from the Africa Team<\/a><\/li>\n<li class=\"SPOSTARBUST-Related-Post\"><a title=\"Discussion panel on &#8216;AI in research&#8217; at Sk\u00f6vde\" href=\"https:\/\/kourentzes.com\/forecasting\/2020\/11\/06\/discussion-panel-on-ai-in-research-at-skovde\/\" rel=\"bookmark\">Discussion panel on &#8216;AI in research&#8217; at Sk\u00f6vde<\/a><\/li>\n<\/ul><\/div><!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>I have been looking for a package to do time series modelling in R with neural networks for quite some time with limited success. The only implementation I am aware of that takes care of autoregressive lags in a user-friendly way is the nnetar function in the forecast package, written by Rob Hyndman. In my\u2026 <span class=\"read-more\"><a href=\"https:\/\/kourentzes.com\/forecasting\/2017\/02\/10\/forecasting-time-series-with-neural-networks-in-r\/\">Read More &raquo;<\/a><\/span><!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[41],"tags":[12,39,68],"_links":{"self":[{"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/posts\/1264"}],"collection":[{"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/comments?post=1264"}],"version-history":[{"count":8,"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/posts\/1264\/revisions"}],"predecessor-version":[{"id":1275,"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/posts\/1264\/revisions\/1275"}],"wp:attachment":[{"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/media?parent=1264"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/categories?post=1264"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kourentzes.com\/forecasting\/wp-json\/wp\/v2\/tags?post=1264"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}<!-- WP Super Cache is installed but broken. The constant WPCACHEHOME must be set in the file wp-config.php and point at the WP Super Cache plugin directory. -->