Setting ARIMA model parameters in R: Grid search vs. auto.arima() | by Emily A. Halford | Towards Data Science

One of the most popular ways of representing and forecasting time series data is through Autoregressive Integrated Moving Average (ARIMA) models. These models are defined by three parameters:
p: the lag order (number of lag observations included)
d: the degree of differencing needed for stationarity (number of times the data is differenced)
q: the order of the moving average
If you’re new to ARIMA modeling, there are lots of great instructional webpages and step-by-step guides such as this one from otexts.com and this one on oracle.com which give more thorough overviews.
However, the vast majority of these guides suggest setting the p, d, and q parameters by using the auto.arima() function or by hand using ACF and PACF plots. As someone who frequently uses ARIMA models, I felt like I still needed a better option. The models suggested to me by auto.arima() frequently had high AIC values (a measure for comparing models — the best model is typically that with the lowest AIC) and significant lags which indicate poor model fit. While I could achieve lower AIC values and eliminate significant lags by changing parameters by hand, this process felt somewhat arbitrary and I was never confident that I was truly selecting the best possible model for my data.
I eventually began using grid searches to aid my selection of parameters (borrowing some code from this guide). While it’s always important to conduct exploratory analyses with your data, test assumptions, and think critically about the ACF and PACF plots, I have found it very useful to have a data-driven place to start with my parameter selection. I will walk through example code and output comparing the auto.arima() and grid search approaches below.
First, you’ll need to load the tidyverse and tseries packages:
library('tidyverse')library('tseries')library('forecast')
A moving average object will also need to be created using your training data:
training_data$hits_ma = ma(training_data$seattle_hits, order = 7)hits_ma = ts(na.omit(training_data$hits_ma), frequency = 52)
Creating and viewing an auto.arima() object is very simple:
auto_1 = auto.arima(hits_ma, seasonal = TRUE)auto_1
The parameters selected using auto.arima() are (0,1,0) and this model has an associated AIC of 234.99. It’s also important to look for significant lags in the ACF and PACF plots:
tsdisplay(residuals(auto_1), lag.max = 45, main = '(0,1,0) Model Residuals')
Significant lags extend beyond the dashed blue lines and indicate poor model fit. Both plots show significant lags at 7, and the ACF plot has an additional significant lag at 14.
First, you have to indicate what parameters you want to test out in your grid search. I decided to consider all parameters between 0 and 7 (for p and d) and 0 and 14 (for q) given the significant lags at these values. The end result is a dataframe called “orderdf” containing all possible parameter combinations:
order_list = list(seq(0, 7),                   seq(0, 7),                   seq(0, 14)) %>%    cross() %>%    map(lift(c))orderdf = tibble("order" = order_list)
Next, map over this dataframe to identify the model with the lowest AIC:
models_df = orderdf %>%    mutate(models = map(order, ~possibly(arima, otherwise = NULL)(x = hits_ma, order = .x))) %>%     filter(models != 'NULL') %>%     mutate(aic = map_dbl(models, "aic"))best_model = models_df %>%    filter(aic == min(models_df$aic, na.rm = TRUE))
I have pulled out the model with the lowest AIC as “best_model” so that I can use that object later on, but you can also sort the data by lowest AIC in order to explore the best few options.
Viewing this “best_model” object shows the parameters selected by the grid search method:
The grid search has identified (7,1,0) as the best parameters, and the AIC of 208.89 associated with this model is much lower than that of 234.99 from the auto.arima() approach.
Additionally, there are no longer any significant lags appearing in the ACF or PACF plots and the residuals are smaller. This model appears to fit my data much better than that produced using auto.arima().
I have consistently gotten better results using grid searches than using either the auto.arima() function or manual selection, and I highly recommend implementing this approach when fitting ARIMA models to your data.