# Time Series ARIMA Forecasting Using R

**Time Series Forecasting Using R: A Starter Pack**

**Some basic theoretical ideas needed before we proceed:-**

**Time Series Data-** A time series is a set of observations on the values that a variable takes at different times. Such data may be collected at regular time intervals, such as daily (e.g., stock prices, weather reports), weekly (e.g., money supply), monthly [e.g., the unemployment rate, the Consumer Price Index (CPI)], quarterly (e.g., GDP), annually (e.g., government budgets), quinquennially, that is, every 5 years (e.g., the census of manufactures), or decennially (e.g., the census of population).

**Stochastic Process-** A random or stochastic process is a collection of random variables ordered in time.

**Stationary Stochastic Processes-** A stochastic process is said to be stationary if its mean and variance are constant over time and the value of the covariance between two time periods depends only on the distance or gap or lag between the two time periods and not the actual time point at which the covariance is computed.

**Nonstationary Stochastic Processes-** A stochastic process is said to be nonstationary if at least one of the characteristics of it from among its mean or variance or the value of the covariance between two time periods depends on the actual time point at which it is being computed.

**Why are stationary time series so important-** This is because if a time series is nonstationary, we can study its behaviour only for the time period under consideration. Each set of time series data will, therefore, be for a particular episode. As a consequence, it is not possible to generalize it to other time periods. Therefore, for the purpose of forecasting, such (nonstationary) time series may be of little practical value.

**Autocorrelation Function (ACF)-** One simple test of stationarity is based on the so-called autocorrelation function (ACF). The ACF at lag k is given as = (Covariance at lag k/Variance).

**Augmented Dickey-Fuller Test (ADF Test)-** Augmented Dickey-Fuller test (ADF) tests the null hypothesis that a time series sample suffers from Non-Stationarity vs. the alternative hypothesis of Stationarity or Trend-Stationarity.

**Exponential Smoothing Methods-** These are essentially methods of getting a suitable curve to historical data of a given time series. There are a variety of these methods, such as single exponential smoothing, Holt’s linear method, and Holt-Winters’ method and their variations.

**Auto Regressive Model (AR Model)-** The autoregressive model specifies that a time series variable depends linearly on its own previous period values and on a stochastic term. Thus the model is in the form of a stochastic difference equation. The autoregressive model is not always stationary.

**Moving Average Model (MA Model)-** The Moving Average Model is a common approach for modeling univariate time series. The moving-average model specifies that the output variable depends linearly on the current and various past values of a stochastic term. Contrary to the AR model, the finite MA model is always stationary.

**Auto Regressive Integrated Moving Average Model (ARIMA Model)-** Auto Regressive Integrated Mmoving Average (ARIMA) Model is a generalization of an ARMA Model. Both of these models are fitted to time series data either to better understand the data or to predict future points in the series (forecasting). ARIMA models are applied in some cases where data show evidence of non-stationarity, where an initial differencing step (corresponding to the “integrated” part of the model) can be applied one or more times to eliminate the non-stationarity.

**In the next portion, we discuss the hands-on techniques required to perform a Time Series Analysis in R.**

At first, we need to Call up the library named “forecast” required later to perform predictions.

1 2 |
library(forecast) |

1 2 |
## Warning: package 'forecast' was built under R version 3.3.3 |

The next step is setting the working directory of the data set under consideration.

The required path for my system is:-

1 2 |
## "F:StepUpAnalytics.comBlog FilesTime SeriesSales.csv" |

So, we use the function “setwd( )” along with the above relevant path, to set the working directory.

1 2 |
setwd("F:\StepUpAnalytics.com\Blog Files\Time Series") |

The name of the required data set in my analysis is “Sales.csv”, i.e. a CSV file. If anyone needs to get access to this data set, get it from the link below link for dataset – Sales.csv.

So we create a space in R to read and store the entire data from the “Sales.csv” file. Thus we require R to read the required CSV file using the ccommand: read.csv(“sales.csv”). After reading the data, we want R to store it in a space named “data”. So, “data” is the name of the data set in R, henceforth.

1 2 |
data <- read.csv("Sales.csv") |

Now we will be using the data set named “data” for our analysis. By default “data” has been created by R as a Data Frame. Just to verify we check for the class of “data” using the following command.

1 2 |
class(data) |

1 2 |
## [1] "data.frame" |

On execution of the above command, it shows “data.frame”. Next, we need to look at the contents of the data frame named “data”. Since it is not necessary at all to go through all the rows of records in “data”.

So we just want to get an idea by looking at the first few rows of “data”. So we use the function “head( )”, which returns the 1st 6 rows of records from “data”.

1 2 |
head(data) |

1 2 3 4 5 6 7 8 |
## Month.Year Sales ## 1 Jan-03 25400 ## 2 Feb-03 25440 ## 3 Mar-03 25370 ## 4 Apr-03 25400 ## 5 May-03 25490 ## 6 Jun-03 25240 |

On execution, we see that “data” contains 2 columns/variables. The 1st one is “Month.Year” having values like “Jan-03”, “Feb-03”, etc. So it is the time variable of our data frame. The 2nd variable is “Sales”, having records like “141”, “157”, etc.

So this is the variable/series varying over time which we need to analyse. This series viz. “Sales” is a continuous variable, as evident from its data records. Next, we plan to rename the column heads of “data” as per our own convenience.

So, we choose to rename the original time variable “Month.Year” as “Date”. And the variable “Sales” is to be renamed as it is. We use the “names( )” function to rename both the columns of “data”.

So we specify as an option while renaming, that we want to start with the 1st column head. And then proceed on renaming till the 2nd column head. So, we use “names(data)[c(1:2)]” .

1 2 |
names(data)[c(1:2)] <- c("Date", "Sales") |

Again to verify whether the renaming is done successfully we check the content of “data” again.

1 2 |
head(data) |

1 2 3 4 5 6 7 8 |
## Date Sales ## 1 Jan-03 25400 ## 2 Feb-03 25440 ## 3 Mar-03 25370 ## 4 Apr-03 25400 ## 5 May-03 25490 ## 6 Jun-03 25240 |

On execution, we see the renaming has been successfully done. Now our next task is to instruct R to convert this data frame into a time series structure. So, we use the **“ts( )”** function with its relevant arguments on the data frame “data”. The conversion of the original data frame “data” into Time Series mode is done as follows.

1 2 |
data <- ts(data[,2], start = c(2003,1), frequency = 12) |

We see in the above process, while using the function **“ts( )”,** we specify the 2nd column of “data”, i.e. “Sales” as the series under consideration and also indicate to R, that the starting point of the series should be “(2003,1)”, i.e. the 1st month of the year 2003. Also, the frequency was set to be equal to 12, indicating that all the 12 months of each year are to be considered.

Now just for the sake of knowing the class of “data” after this conversion we do the following.

1 2 |
class(data) |

1 2 |
## [1] "ts" |

We see that the class has changed to “ts”, indicating a Time Series structure. To understand the differences newly created in the Time Series structure “data”, after it has been tabulated in Time Series mode, we return the entire data frame.

1 2 |
data</code><code> |

On execution, we see that the earlier representation of “data” has now been changed. Now, it has a more structured and bi-variety tabulated look. Next, we go for an initial visual analysis of the series “Sales” from “data”. Actually, this will help us to get a crude idea about the nature of the series “Sales”.

So, we plot the “Sales” data points against the corresponding values of the time variable.

1 2 |
plot(data, xlab = "Years", ylab = "Sales") |

Here we re-label the X-axis as “Years” and the Y-axis as “Sales”. We see from the plot that the values of the series “Sales” are gradually increasing over time. Moreover, there are some ups and downs in the path of the series “Sales” over time.

Again, these ups and downs gradually increase in magnitude over time, specifically from 2011. This is quite evident from the heights of the spikes created starting from the year 2011 and on. So, we can apparently say that this series has an upward rising trend.

Also, it shows that some kind of seasonality from the year 2011 until the very end. During some months of each year starting from 2011, the “Sales” go up drastically, as compared to its values during the other months of that year.

The magnitude of this seasonal change in “Sales” taking place each year also increases over the years.

This is evident from the fact that the heights of the spikes go on increasing from one year to the next and so on.

So, it may be apparent that the series “Sales” taken up here suffers from non-stationarity as well. But we need to conduct the stationarity test of the series “Sales”, in order to get certified. So we conduct the **Augmented Dickey-Fuller (ADF)** Test to check for stationarity.

For this, we specifically require to call up the R library “**tseries**” and then conduct the test.

1 2 |
library(tseries)</code><code> |

1 2 |
adf.test(data, alternative = "stationary") |

1 2 3 4 5 6 7 |
## ## Augmented Dickey-Fuller Test ## ## data: data ## Dickey-Fuller = -1.024, Lag order = 5, p-value = 0.9318 ## alternative hypothesis: stationary |

Here while conducting the ADF Test on the series “Sales” of “data”, we pre-specify the alternative hypothesis of the test to be renamed as “stationary”.

So, our ADF Test validates for, Ho: The series is Non-Stationary. vs. H1: The series is stationary. On execution of this test, we see from the results that ADF has automatically considered 5 to be the appropriate order of lag for the series “Sales” at level.

However, the results of this test show that the p-value = 0.9318 (i.e. > 0.05). So at a default level of significance of 5 %, this test indicates that the observed p-value is much higher than the critical p-value here.

This indicates that here we have to reject the Alternative Hypothesis, but fail to reject the Null Hypothesis.

Thus it is clear that the series “Sales” suffers from Non-Stationarity at level. Proceeding with this Non-Stationary series for further analysis is not viable.

Had this series been found to be stationary at the level only, then we could have proceeded with it. So, now we need to go for differencing the series “Sales” and then conducting the ADF Test to check if the differenced series is Stationary or not.

If after taking the 1st difference of the series “Sales”, we still find that the ADF Test indicates this 1st differenced series to be Non-Stationary also, then we need to consider the 2nd order difference of the series “Sales” and again check for its Stationarity using ADF Test.

This process should be continued until we obtain stationarity at some higher level of difference. So, this time we go for a Time Series plot of the 1st difference of “Sales” from “data”. This will again help us in getting a visual idea.

1 2 |
plot(diff(data), ylab = "1st Order Difference of Sales") |

Here, we use “diff(data)” to indicate the 1st order difference of “Sales” from “data”, to be considered as the variable for plotting against time. We re-label the Y-Axis as “1st Order Difference of Sales”, just for our convenience.

The graph indicates that the 1st order difference of “Sales” when plotted against time, shows no trend in the Long Run. However, it exhibits some up and down movement in its path over the years.

Thus some steep spikes are created over time.

Again, the magnitude of fluctuation represented by these spikes increases gradually over the years. This implies although the mean behaviour of this series is time-invariant, the variation shown by it over the years is certainly time dependent.

So again, it is suspected that this 1st differenced series too may be Non-Stationary. But, still, we conduct the ADF Test to get a strong verification. So, we first store the 1st order differenced series of “Sales” in a different TS structure.

We have a look at the get up of this new TS structure named as “data1”. Then we conduct the ADF Test on the differenced series of “Sales”, which has been separately stored in this new TS structure named “data1”.

1 2 3 |
data1 <- diff(data) data1 |

1 2 |
adf.test(data1, alternative = "stationary") |

1 2 3 4 5 6 7 |
## ## Augmented Dickey-Fuller Test ## ## data: data1 ## Dickey-Fuller = -2.9945, Lag order = 5, p-value = 0.1612 ## alternative hypothesis: stationary |

On execution, we again see that the appropraite lag length has been automatically chosen as 5.

The p-value here is 0.1612 (i.e. > 0.05). This indicates that at 5 % level of significance, we need to reject the Alternative Hypothesis again.

Thus it is evident that this 1st order differenced series of “Sales” is Non-Stationary too. We cannot proceed with this series even. So, we go for 2nd order differencing of “Sales” and conduct ADF Test on it, We use the same process as above.

First, we plot the 2nd order differenced series of “Sales” and then try to get a visual idea.

1 2 |
plot(diff(data1), ylab = "2nd Order Difference of Sales") |

On execution, from the graph, we again find that there is no presence of Long Run trend. However, the spikes/fluctuations are still there showing an increase in their magnitude over time. So, we suspect presence of time component in the variance, if not in trend. Again, there is a chance of Non-Stationarity. So we test it.

1 2 3 |
data2 <- diff(data1) data2 |

1 2 |
adf.test(data2, alternative = "stationary") |

1 2 3 |
## Warning in adf.test(data2, alternative = "stationary"): p-value smaller ## than printed p-value |

1 2 3 4 5 6 7 |
## ## Augmented Dickey-Fuller Test ## ## data: data2 ## Dickey-Fuller = -4.9091, Lag order = 5, p-value = 0.01 ## alternative hypothesis: stationary |

On execution, we see that the appropriate lag order is 5 again. But this time the p-value = 0.01 (i.e. < 0.05).

So, at 5 % level of significance, we need to reject the Null Hypothesis. Thus we fail to reject the Alternative Hypothesis in this case.So, the 2nd order differenced series of “Sales” is Stationary. This goes against the usual visual inference that we had made earlier from the graph.

So, this is where testing proves to be necessary for verification. Thus we can proceed further with this stationary series for further analysis. But there is another factor we need to take care of.

We have seen from all the previous graphs that there were some unevenness in the fluctuations shown by the different ordered differenced series of “Sales” as well as the series “Sales” at level. This uneven fluctuation/variance if corrected for could improve our results further. So we try out with a logarithmic transformation of the series of “Sales” at level. We plot it first and then try to carry out the further steps as before.

1 2 |
plot(log10(data), ylab = "Log(Sales)") |

On execution, we see from the graph that there is a Long term upward trend. However, the fluctuations/spikes have significantly smoothened up as compared to the graph of the orginal series “Sales” at level. Next we go for the test of stationarity.

1 2 3 |
data10 <- log10(data) data10</code><code> |

1 2 |
adf.test(data10, alternative = "stationary") |

1 2 3 4 5 6 7 |
## ## Augmented Dickey-Fuller Test ## ## data: data10 ## Dickey-Fuller = -0.50572, Lag order = 5, p-value = 0.9805 ## alternative hypothesis: stationary |

On execution, we see from the test results that the p-value = 0.9805 (i.e. > 0.05). So at 5 % level of significance, we have to reject the Alternative Hypothesis. Thus this series is Non-Stationary and we cannot proceed with this series futher. We now take differences as before and proceed thereafter.

1 2 |
plot(diff(data10), ylab = "1st Order Difference of Log(Sales)") |

The graph shows that apparently there is very little downward trend over time. The fluctuations/spikes are still there and very haphazard in nature. We conduct the ADF Test as before, to check for Non-Stationarity.

1 2 3 |
data11 <- diff(data10) data11 |

1 2 |
adf.test(data11, alternative = "stationary") |

1 2 3 4 5 6 7 |
## ## Augmented Dickey-Fuller Test ## ## data: data11 ## Dickey-Fuller = -2.7906, Lag order = 5, p-value = 0.2463 ## alternative hypothesis: stationary |

On execution, we see from the results that the p-value = 0.2463 (i.e. > 0.05). Thus at 5 % level of significance, we reject the Alternative Hypothesis. We infer that this series is again Non-Stationary.

And we cannot proceed further with this. Next, we consider the 2nd order difference of the series “**Log(Sales)**” and proceed further.

1 2 |
plot(diff(data11), ylab = "2nd Order Difference of Log(Sales)") |

From the graph, it is apparent that there is no Long Run trend. And above all the fluctuations have eased down a lot, reducing the unevenness. We check for Stationarity of this.

1 2 3 |
data12 <- diff(data11) data12</code><code> |

1 2 |
adf.test(data12, alternative = "stationary") |

1 2 3 |
## Warning in adf.test(data12, alternative = "stationary"): p-value smaller ## than printed p-value |

1 2 3 4 5 6 7 |
## ## Augmented Dickey-Fuller Test ## ## data: data12 ## Dickey-Fuller = -5.2646, Lag order = 5, p-value = 0.01 ## alternative hypothesis: stationary |

On execution, we see that the test results give us a p-value = 0.01 (i.e. < 0.05). So, at 5 % level of significance, we fail to reject the Alternative Hypothesis. This implies that the 2nd Order Difference of the series “Log(Sales)” is Stationary. Thus we can proceed further with this series. Till now we have finalised two different statioanry series for further analysis.

They are:- 2nd Order Difference of the series “Sales” and 2nd Order Difference of the series “Log(Sales)”

Now we will consider further analysis with these two series separately. Ultimately we will keep that one only which shows a better fit at the final stage.

Our next task is to find out the most appropraite Model for the above two series. For that we at first need to create the ACF and PACF plots for both separately.

1 2 |
acf(ts(diff(diff(data))), main = "ACF Sales") |

We see from the ACF Plot, that the order of Moving Average is expected to be 0. This is because the last spike which is significantly outside the limits is at lag 0.

1 2 |
pacf(ts(diff(diff(data))), main = "PACF Sales") |

We see from the PACF Plot, that the order of Auto Regression is expected to be 2. This is because the last spike which is significantly outside the limits is at lag 2. So we expect the model to be ARIMA(2,2,0)

The order of integration was previously determined as 2. We now fit the ARIMA model as per our expectations.

Here we fit the ARIMA(2,2,0) model on the 1st order difference of the series “Sales”. This is because though the order of integration is 2, i.e. we need to work with the 2nd order difference of the series “Sales”, the ARMA process requires one lag lower order of integration while operating. Thus we effectively need to model the 1st order differenced values of the series “Sales”.

**Fitting appropraite models**

1 2 |
ARIMAfit <- arima(diff(data), c(2,2,0)) |

Next, we look at the summary of the fit stored under the name “ARIMAfit”.

1 2 |
summary(ARIMAfit) |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
## ## Call: ## arima(x = diff(data), order = c(2, 2, 0)) ## ## Coefficients: ## ar1 ar2 ## -0.8322 -0.5793 ## s.e. 0.0634 0.0633 ## ## sigma^2 estimated as 865420: log likelihood = -1362.55, aic = 2731.1 ## ## Training set error measures: ## ME RMSE MAE MPE MAPE MASE ACF1 ## Training set -20.51933 924.6924 648.394 Inf Inf 1.148089 -0.2322592 |

From the summary results, we get the various coefficients of the model equation fitted. We just take a note of the values of the different “Training set error measures” given. These Error Measures help us to compare between two or more fitted models. The model with the lowest error values is considered to be the best fit.

However, the above ARIMA(2,2,0) model was fit on the basis of rough observations done from the ACF and PACF plots.

They may not be accurate always. So we fit an auto arima model for better accuracy. Auto Arima model helps in finding the optimum values of orders of AR and MA and fits the best model possible.

So for running the auto arima, we need to call up the library “forecast” at first. Then we go on to fit the auto arima model.

1 2 |
require(forecast) |

1 2 |
ARIMAautofit <- auto.arima(diff(data), approximation = TRUE, trace = TRUE)</code><code> |

On running this, we see the most accurate ARIMA model that could be fitted is automatically detected.

The best model fit here is ARIMA(1,0,1)(0,0,1)[12]. So the best fit model indicates AR(1) and MA(1).

The seasonality component is automatically best fitted with the order (0,0,1).

Now to get a summary of this best fit model we do the following.

1 2 |
summary(ARIMAautofit) |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
## Series: diff(data) ## ARIMA(1,0,1)(0,0,1)[12] with non-zero mean ## ## Coefficients: ## ar1 ma1 sma1 mean ## 0.7663 -0.2481 -0.1114 412.3128 ## s.e. 0.0980 0.1420 0.0795 166.9744 ## ## sigma^2 estimated as 575753: log likelihood=-1342.77 ## AIC=2695.54 AICc=2695.91 BIC=2711.13 ## ## Training set error measures: ## ME RMSE MAE MPE MAPE MASE ACF1 ## Training set 1.876461 749.6416 504.2896 NaN Inf 0.5500694 0.02094562 |

The summary gives us the various coefficients of the best fit equation. Again we note the values of the different “Training set error measures” given. These error values are supposed to be the lowest among all possible fits.

To check this claim, we compare the values of RMSE obtained in case of ARIMAfit with that of ARIMAautofit. ARIMAfit had a RMSE value of 924, while ARIMAautofit has a RMSE value of 749.

Thus it is evident that ARIMAautofit gives us the model with the best fit possible. So, till now we have been able to fit the best model for 2nd Order Difference of the series “Sales”. Now the same needs to be done with the 2nd Order Difference of the series “Log(Sales)”. Then we will be comparing between the two Best Fit models in terms of lower RMSE values. We carry out the ACF and PACF plots to have a visual idea of the best fit possible.

1 2 |
acf(ts(diff(diff(log10(data)))), main = "ACF Log(Sales)") |

1 2 |
pacf(ts(diff(diff(log10(data)))), main = "PACF Log(Sales)") |

Next we auto fit the arima model on 2nd Order Difference of the series “Log(Sales)”. So we effectively use the 1st Order Difference of the series “Log(Sales)” as the variable.

1 2 |
ARIMAautofit2 <- auto.arima(diff(log10(data)), approximation = TRUE, trace = TRUE)</code><code> |

This fitting is given a name of “ARIMAautofit2”. The best model that can be fitted in this case is determined automatically to be ARIMA(0,1,1). ARIMA(0,1,1) model implies this is a purely Moving Average Series.

Note: We have intentionally not performed the manual fitting as it has already been explained in the previous case. Now we need to get a summary of the latest best fit model named as “ARIMAautofit2”.

1 2 |
summary(ARIMAautofit2) |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
## Series: diff(log10(data)) ## ARIMA(0,1,1) ## ## Coefficients: ## ma1 ## -0.5347 ## s.e. 0.0731 ## ## sigma^2 estimated as 2.338e-05: log likelihood=649.86 ## AIC=-1295.71 AICc=-1295.64 BIC=-1289.49 ## ## Training set error measures: ## ME RMSE MAE MPE MAPE MASE ## Training set -0.0001096626 0.004806686 0.003329635 Inf Inf 0.5568284 ## ACF1 ## Training set 0.02903617 |

The summary gives us the coefficients of the best fit model equation. We take a note of the values of the different “Training set error measures”. Here we see that the value of RMSE for this fit is 0.0048 (approx.).

However we cannot compare the 2 best fits represented by ARIMAautofit ~ ARIMA(1,0,1)(0,0,1)[12] and ARIMAautofit2 ~ ARIMA(0,1,1). This is because ARIMAautofit is a perfect Auto Regressive Moving Average process. While ARIMAautofit2 is a purely Moving Average Process.

We need to check which one is a better fit graphically after making predictions using them. Getting the most accurate Predicted Results using a fitted model is always our target. A fitted model which does not predict accurately is useless.

So, we will use both the models viz. “ARIMAautofit” and “ARIMAautofit2” to make separate predictions.

As ARIMAautofit ~ ARIMA(1,0,1)(0,0,1)[12] , it is expected to give us the better predictive results.

But as ARIMAautofit2 ~ ARIMA(0,1,1) i.e. actually an MA(1) process, it is expected that using the Exponential Smoothing Method would increase the predictive power of this model.

**Prediction using ARIMAautofit ~ ARIMA(1,0,1)(0,0,1)[12]**

1 2 3 |
pred <- predict(ARIMAautofit, n.ahead = 36) pred |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
## $pred ## Jan Feb Mar Apr May ## 2017 -1821.998536 -1521.463105 -1127.913509 -691.513134 -499.836912 ## 2018 577.705657 539.053828 509.434819 486.737685 469.344806 ## 2019 419.094244 417.509439 416.294998 415.364368 414.651224 ## Jun Jul Aug Sep Oct ## 2017 -358.187199 -161.766874 -66.984202 6.921324 386.274926 ## 2018 456.016591 445.803141 437.976545 431.979001 427.383066 ## 2019 414.104740 413.685967 413.365061 413.119149 412.930706 ## Nov Dec ## 2017 562.325349 704.691036 ## 2018 423.861188 421.162362 ## 2019 412.786302 412.675645 ## ## $se ## Jan Feb Mar Apr May Jun Jul ## 2017 758.7839 854.5981 906.1530 935.1034 951.6934 961.3019 966.8997 ## 2018 976.3260 976.7186 976.9491 977.0844 977.1639 977.2106 977.2380 ## 2019 977.2753 977.2760 977.2764 977.2766 977.2767 977.2768 977.2769 ## Aug Sep Oct Nov Dec ## 2017 970.1718 972.0881 973.2117 973.8708 974.2577 ## 2018 977.2540 977.2635 977.2690 977.2723 977.2742 ## 2019 977.2769 977.2769 977.2769 977.2769 977.2769 |

Here we make predictions for the next 36 months, i.e. for a stretch of 3 years in the future. For this, we use the option “n.ahead = 36”. We store the results of this under the name “pred”. To see the Predicted Values we use the following.

1 2 |
pred$pred |

1 2 3 4 5 6 7 8 9 10 11 12 13 |
## Jan Feb Mar Apr May ## 2017 -1821.998536 -1521.463105 -1127.913509 -691.513134 -499.836912 ## 2018 577.705657 539.053828 509.434819 486.737685 469.344806 ## 2019 419.094244 417.509439 416.294998 415.364368 414.651224 ## Jun Jul Aug Sep Oct ## 2017 -358.187199 -161.766874 -66.984202 6.921324 386.274926 ## 2018 456.016591 445.803141 437.976545 431.979001 427.383066 ## 2019 414.104740 413.685967 413.365061 413.119149 412.930706 ## Nov Dec ## 2017 562.325349 704.691036 ## 2018 423.861188 421.162362 ## 2019 412.786302 412.675645 |

To see the Standard Errors of the Predicted Values we use the following.

1 2 |
pred$se |

1 2 3 4 5 6 7 8 9 |
## Jan Feb Mar Apr May Jun Jul ## 2017 758.7839 854.5981 906.1530 935.1034 951.6934 961.3019 966.8997 ## 2018 976.3260 976.7186 976.9491 977.0844 977.1639 977.2106 977.2380 ## 2019 977.2753 977.2760 977.2764 977.2766 977.2767 977.2768 977.2769 ## Aug Sep Oct Nov Dec ## 2017 970.1718 972.0881 973.2117 973.8708 974.2577 ## 2018 977.2540 977.2635 977.2690 977.2723 977.2742 ## 2019 977.2769 977.2769 977.2769 977.2769 977.2769 |

Next, we go for plotting the observed and the predicted data together, using “ARIMAautofit”

This will help us to get a visual idea about the accuracy of the fit.

1 2 |
plot(forecast(ARIMAautofit, h = 36)) |

We extend the plot by forecasting the values for the next 36 months i.e. the next 3 years. The predictions, in this case, have been done starting from Jan-2017 to Dec-2019. The plot shows the predicted values of the series with a blue line.

The predicted line shows an upward trend starting from Jan-2017 till Dec-2017, after which its falls for a while and then flattens out. The inner purple zone shows the 80 % Confidence Interval of our prediction.

The inner Purple zone added with the outer Grey zone together shows the 95 % Confidence Interval of our prediction.

It can be seen that the Confidence Intervals become wider gradually over the prediction range. They keep on widening from the Jan-2017 till Dec-2017, after which they become constant through out. So, it is apparent that the forecast done here is not that accurate after 1 year.

**Residual Analysis**

Next we go for a mandatory Residual Analysis of ARIMAautofit. We look at the ACF and the PACF plots of ARIMAautofit.

1 2 |
acf(ts(ARIMAautofit$residuals), main = "ACF Residual Of Sales") |

The ACF graph shows that the spikes are within the acceptable limits at all lags. So, there is no Moving Average pattern prevalent in the Residuals.

1 2 |
pacf(ts(ARIMAautofit$residuals), main = "PACF Residual Of Sales") |

The PACF graph shows that the spikes are within the acceptable limits at all lags. So, there is no Auto Regressive pattern prevalent in the Residuals. Thus due to the absence of both AR and MA patterns in the Residuals, we can say that the Residuals, in this case, are random in nature, which is actually desired.

**Prediction using ARIMAautofit2 ~ ARIMA(0,1,1).**

Here it is evident that ARIMAautofit2 actually ~ MA(1). Thus it is a pure Moving Average process. Thus instead of fitting it with an ARIMA model, it is desirable to re-fit it into an MA structure.

For this, we will be using Exponential Smoothing. For our convenience and to save time, we refrain from carrying out the step by step process of Simple Exponential Smoothing, Double Exponential Smoothing and Triple Exponential Smoothing. Instead, we go for an Automatic Exponential Smoothing using the State Space Model approach.

1 2 |
autoexp_fit <- ets(data10) |

Here we perform an Exponential Smoothing by using the “ets( )” function. We store the newly fitted model by the name “autoexp_fit”. Next we go look into the summary of this fit to make some decisions.

1 2 |
summary(autoexp_fit) |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
## ETS(M,Ad,N) ## ## Call: ## ets(y = data10) ## ## Smoothing parameters: ## alpha = 0.9999 ## beta = 0.4286 ## phi = 0.9275 ## ## Initial states: ## l = 4.4076 ## b = -0.002 ## ## sigma: 0.001 ## ## AIC AICc BIC ## -926.7532 -926.2315 -908.0095 ## ## Training set error measures: ## ME RMSE MAE MPE MAPE ## Training set 0.0004934518 0.004729652 0.003297052 0.01088269 0.0691976 ## MASE ACF1 ## Training set 0.06786506 0.05123158 |

From the results, we get an idea about the values of the different “Training set error measures”.

We see that this fit has an RMSE of 0.0047. We note down this RMSE value for “autoexp_fit” and compare it with the RMSE values obtained from several other model fits which also have undergone Exponential Smoothing.

The model fit with the lowest RMSE value, obtained after Exponential Smoothing, will be considered as the best fit. We see that earlier in case of “ARIMAautofit2” which was not fitted after Exponential Smoothing, the RMSE was obtained as to be equal to 0.0048.

But now, under Exponential Smoothing, we find the RMSE value for “autoexp_fit” to be 0.0047. So, there has been no significant increase in the accuracy of the model in this case. We go for predicting using this “autoexp_fit”, for the next 36 months. Thus we would be forecasting the values for the next 3 years, i.e. from Jan-2017 till Dec-2019.

1 2 |
pred_ets <- predict(autoexp_fit, h = 36) |

Next we go for plotting the observed and the forecasted data together, using “autoexp_fit”

This will help us to get a visual idea about the accuracy of the fit.

1 2 |
plot(forecast(autoexp_fit)) |

From the graph, we see that the predicted value of “Sales”, given by the deep Blue line, declines gradually from Jan-2017 to Dec-2019. The inner purple zone shows the 80 % Confidence Interval of our prediction.

The inner Purple zone added with the outer Grey zone together shows the 95 % Confidence Interval of our prediction.

It can be seen that the Confidence Intervals become wider gradually over the prediction range. So, it is apparent that the accuracy of the forecast declines gradually with time. Next, we go for a mandatory Residual Analysis of “autoexp_fit”. We look at the ACF plot of “autoexp_fit”.

Here as this is a purely MA process, no PACF plot is required.

1 2 |
acf(autoexp_fit$residuals, lag.max = 20, main = "ACF Residual Of Sales") |

The ACF graph shows that the spikes are within the acceptable limits at all lags. So, there is no Moving Average pattern prevalent in the Residuals. It can be said that the Residuals are random in nature, which is actually desired.

**Thus we show how an analysis of Time Series Data can be done accurately. ****At last, just to recapitulate we again recall that a proper ARIMA series is better fitted using the “auto.arima( )” process, while in most cases a purely MA series is better fitted using the Exponential Smoothing Method of “ets( )”.**