The Box-Jenkins methodology remains the dominant framework for univariate time series modelling. Its classical identification step relies on the Autocorrelation Function (ACF) and Partial Autocorrelation Function (PACF) plots. However, these plots often present conflicting or ambiguous pictures, particularly for mixed ARIMA(p,d,q) models, making reliable identification difficult in practice.
The arimasel package proposes an alternative algorithm
grounded in the mathematical theory of Cartesian products of
sets. Rather than examining ACF/PACF plots or using stepwise
search (as in auto.arima), the algorithm:
cp_sets()cp_sets(p_set = 0:2, d_set = 0:1, q_set = 0:2)
#> Cartesian Product P x D x Q
#> P = {0, 1, 2}
#> D = {0, 1}
#> Q = {0, 1, 2}
#> |P| x |D| x |Q| = 3 x 2 x 3 = 18 candidate model(s)
#>
#> Candidate ARIMA models:
#> ARIMA(0,0,0) ARIMA(0,0,1) ARIMA(0,0,2) ARIMA(1,0,0) ARIMA(1,0,1) ARIMA(1,0,2) ARIMA(2,0,0) ARIMA(2,0,1) ARIMA(2,0,2) ARIMA(0,1,0) ARIMA(0,1,1) ARIMA(0,1,2) ARIMA(1,1,0) ARIMA(1,1,1) ARIMA(1,1,2) ARIMA(2,1,0) ARIMA(2,1,1) ARIMA(2,1,2)The function confirms \(|P| \times |D| \times |Q| = 3 \times 2 \times 3 = 18\) candidate models.
The package ships with three Nigerian macroeconomic time series.
data(gdp_ng)
data(exchange_ng)
data(inflation_ng)
par(mfrow = c(1, 3), mar = c(4, 4, 3, 1))
plot(gdp_ng, main = "GDP Growth (%)", ylab = "%")
plot(exchange_ng, main = "USD/NGN Rate", ylab = "NGN")
plot(inflation_ng,main = "CPI Inflation (%)", ylab = "%")stationarity_test(gdp_ng)
#> Registered S3 method overwritten by 'quantmod':
#> method from
#> as.zoo.data.frame zoo
#> Warning in tseries::kpss.test(x_vec): p-value greater than printed p-value
#>
#> Stationarity Test Battery (alpha = 0.05)
#> n = 34 observations
#>
#> Test Statistic p_value Conclusion
#> ADF (H0: unit root) -1.8808 0.1795 Non-stationary
#> PP (H0: unit root) -15.0002 0.1639 Non-stationary
#> KPSS (H0: stationary) 0.1995 0.1000 Stationary
#>
#> Consensus : Non-stationary | Suggested d : 1
#> Test Statistic p_value Conclusion
#> 1 ADF (H0: unit root) -1.8808 0.1795 Non-stationary
#> 2 PP (H0: unit root) -15.0002 0.1639 Non-stationary
#> 3 KPSS (H0: stationary) 0.1995 0.1000 Stationary
d_rec <- suggest_d(gdp_ng)
cat("Recommended d:", d_rec, "\n")
#> Recommended d: 2result <- cart_arima(gdp_ng,
p_set = 0:3,
d_set = 0:1,
q_set = 0:3,
criterion = "AIC",
top_n = 10L)
print(result)
#>
#> Cartesian Product ARIMA Model Selection
#> =========================================
#> Call : cart_arima(x = gdp_ng, p_set = 0:3, d_set = 0:1, q_set = 0:3,
#> Call : criterion = "AIC", top_n = 10L)
#> Obs (n) : 34
#> Candidates: 32 | Converged: 32 | Failed: 0
#> Criterion : AIC
#> Best model: ARIMA(0,1,0)
#>
#> Top 10 models (ranked by AIC):
#> Rank Model AIC AICc BIC HQIC Delta Weight
#> 1 ARIMA(0,1,0) 155 155 156 155 0.000 0.1381
#> 2 ARIMA(1,1,1) 155 156 159 156 0.053 0.1345
#> 3 ARIMA(0,1,1) 155 156 158 156 0.576 0.1036
#> 4 ARIMA(0,1,2) 156 156 160 157 1.012 0.0833
#> 5 ARIMA(1,1,0) 156 156 159 157 1.267 0.0733
#> 6 ARIMA(2,1,0) 156 157 161 158 1.381 0.0692
#> 7 ARIMA(1,0,0) 157 157 161 158 1.899 0.0534
#> 8 ARIMA(2,1,1) 157 158 163 159 2.052 0.0495
#> 9 ARIMA(1,1,2) 157 158 163 159 2.052 0.0495
#> 10 ARIMA(0,1,3) 158 159 164 160 2.998 0.0309summary(result)
#>
#> === arimasel: Cartesian Product ARIMA Summary ===
#>
#> Call: cart_arima(x = gdp_ng, p_set = 0:3, d_set = 0:1, q_set = 0:3,
#>
#> Call: criterion = "AIC", top_n = 10L)
#>
#> Search space:
#> P = {0,1,2,3}, D = {0,1}, Q = {0,1,2,3}
#> Total candidates: 32 | Converged: 32
#>
#> Best model by primary criterion:
#> ARIMA(0,1,0) (criterion: AIC)
#>
#> Criterion vote table:
#> Model Votes Criteria
#> ARIMA(0,1,0) 4 AIC/AICc/BIC/HQIC
#>
#> Top 10 model comparison:
#> Model p d q LogLik AIC AICc BIC HQIC Rank Delta Weight
#> ARIMA(0,1,0) 0 1 0 -76.3 155 155 156 155 1 0.000 0.1381
#> ARIMA(1,1,1) 1 1 1 -74.4 155 156 159 156 2 0.053 0.1345
#> ARIMA(0,1,1) 0 1 1 -75.6 155 156 158 156 3 0.576 0.1036
#> ARIMA(0,1,2) 0 1 2 -74.8 156 156 160 157 4 1.012 0.0833
#> ARIMA(1,1,0) 1 1 0 -76.0 156 156 159 157 5 1.267 0.0733
#> ARIMA(2,1,0) 2 1 0 -75.0 156 157 161 158 6 1.381 0.0692
#> ARIMA(1,0,0) 1 0 0 -75.3 157 157 161 158 7 1.899 0.0534
#> ARIMA(2,1,1) 2 1 1 -74.4 157 158 163 159 8 2.052 0.0495
#> ARIMA(1,1,2) 1 1 2 -74.4 157 158 163 159 9 2.052 0.0495
#> ARIMA(0,1,3) 0 1 3 -74.8 158 159 164 160 10 2.998 0.0309
#>
#> Best model coefficients:
#> numeric(0)
#>
#> sigma^2: 5.9821 | Log-likelihood: -76.340arima_table(result, criterion = "BIC", top_n = 5)
#> Model p d q LogLik AIC AICc BIC HQIC Rank Delta Weight
#> 1 ARIMA(0,1,0) 0 1 0 -76.340 154.680 154.805 156.206 155.200 1 0.000 0.4281
#> 2 ARIMA(0,1,1) 0 1 1 -75.628 155.256 155.643 158.309 156.297 2 2.103 0.1496
#> 3 ARIMA(1,1,0) 1 1 0 -75.974 155.947 156.334 159.000 156.988 3 2.794 0.1059
#> 4 ARIMA(1,1,1) 1 1 1 -74.366 154.733 155.533 159.312 156.294 4 3.106 0.0906
#> 5 ARIMA(0,1,2) 0 1 2 -74.846 155.692 156.492 160.271 157.253 5 4.065 0.0561ic_vals <- setNames(result$full_table$AIC,
result$full_table$Model)
arima_weights(ic_vals[1:6])
#> Model IC_value Delta Weight EvidenceRatio
#> 1 ARIMA(0,1,0) 154.680 0.000 0.2294 1.00
#> 2 ARIMA(1,1,1) 154.733 0.053 0.2234 1.03
#> 3 ARIMA(0,1,1) 155.256 0.576 0.1720 1.33
#> 4 ARIMA(0,1,2) 155.692 1.012 0.1383 1.66
#> 5 ARIMA(1,1,0) 155.947 1.267 0.1218 1.88
#> 6 ARIMA(2,1,0) 156.061 1.381 0.1150 1.99arima_diagnose(result, lags = 15)
#>
#> Residual diagnostics for ARIMA(0,1,0)
#> n (residuals) = 34
#> sigma^2 = 5.9821
#> Shapiro-Wilk: W = 0.9839, p-value = 0.8859 [Cannot reject normality]
#> Ljung-Box: No significant autocorrelation detected (alpha = 0.05).res_ex <- cart_arima(exchange_ng,
p_set = 0:2, d_set = 1L, q_set = 0:2,
criterion = "BIC")
print(res_ex)
#>
#> Cartesian Product ARIMA Model Selection
#> =========================================
#> Call : cart_arima(x = exchange_ng, p_set = 0:2, d_set = 1L, q_set = 0:2,
#> Call : criterion = "BIC")
#> Obs (n) : 168
#> Candidates: 9 | Converged: 9 | Failed: 0
#> Criterion : BIC
#> Best model: ARIMA(0,1,0)
#>
#> Top 9 models (ranked by BIC):
#> Rank Model AIC AICc BIC HQIC Delta Weight
#> 1 ARIMA(0,1,0) 1624 1624 1627 1625 0.00 0.8478
#> 2 ARIMA(0,1,1) 1626 1626 1632 1628 5.10 0.0661
#> 3 ARIMA(1,1,0) 1626 1626 1632 1628 5.11 0.0660
#> 4 ARIMA(0,1,2) 1627 1627 1637 1631 9.67 0.0068
#> 5 ARIMA(2,1,0) 1627 1627 1637 1631 9.68 0.0067
#> 6 ARIMA(1,1,1) 1628 1628 1637 1631 10.03 0.0056
#> 7 ARIMA(1,1,2) 1629 1629 1642 1634 14.79 0.0005
#> 8 ARIMA(2,1,1) 1629 1629 1642 1634 14.80 0.0005
#> 9 ARIMA(2,1,2) 1631 1632 1647 1638 19.91 0.0000
arima_forecast(res_ex, h = 12, plot = TRUE)compare_arima(gdp_ng, p_set = 0:3, d_set = 0:1, q_set = 0:3,
holdout = 5L)
#> Fitting cart_arima...
#> Fitting auto.arima...
#>
#> --- Model Comparison ---
#> Method Model AIC AICc BIC HQIC OOS_RMSE OOS_MAE
#> cart_arima ARIMA(0,1,0) 129 129 131 130 2.07 1.84
#> auto.arima ARIMA(1,0,0) 133 134 137 134 2.24 1.53
#>
#> Winner (most metric wins): cart_arimaThe arimasel package provides a transparent, exhaustive,
multi-criteria approach to ARIMA model identification. Key advantages
over stepwise methods:
Awe, O. O. (2026). arimasel: Cartesian Product-Based ARIMA Model Identification and Selection. R package version 0.1.0.
Akaike, H. (1974). A new look at the statistical model identification. IEEE Transactions on Automatic Control, 19(6), 716–723.
Box, G. E. P., Jenkins, G. M., Reinsel, G. C., and Ljung, G. M. (2015). Time Series Analysis: Forecasting and Control (5th ed.). John Wiley & Sons.
Burnham, K. P. and Anderson, D. R. (2002). Model Selection and Multimodel Inference: A Practical Information-Theoretic Approach (2nd ed.). Springer.
Hannan, E. J. and Quinn, B. G. (1979). The determination of the order of an autoregression. Journal of the Royal Statistical Society, Series B, 41(2), 190–195.
cp_sets()