LjungBox

An Elixir implementation of the Ljung-Box test for autocorrelation in time series residuals.

Overview

The Ljung-Box test checks whether the residuals of a time series model (or any sequence of values) are independently distributed — i.e., whether they exhibit no autocorrelation up to a chosen number of lags.

Null hypothesis H₀: The data are independently distributed (white noise).
Alternative H₁: The data exhibit serial correlation at one or more lags.

Method

The Q-statistic is:

$$Q = n(n+2)\sum_{k=1}^{h}\frac{\hat{\rho}_k^2}{n-k}$$

Symbol Meaning
$n$ Number of observations
$h$ Number of lags tested
$\hat{\rho}_k$ Sample autocorrelation at lag $k$

Under H₀, $Q$ follows a chi-squared distribution with $h$ degrees of freedom. When testing ARMA(p, q) residuals, use $h - p - q$ degrees of freedom instead and adjust the lags count accordingly.

The p-value is computed using the regularised lower incomplete gamma function (Lanczos + Lentz continued-fraction method, pure Elixir, no FFI).

Interpretation of results

p-value Conclusion
< 0.05 Reject H₀ — significant autocorrelation is present
≥ 0.05 Fail to reject H₀ — series is consistent with white noise

Practical tips:

Installation

Add ljung_box to your list of dependencies in mix.exs:

def deps do
  [
    {:ljung_box, "~> 0.1.0"}
  ]
end

Usage

Full test

# residuals from an ARIMA model
residuals = [0.12, -0.05, 0.03, 0.21, -0.18, 0.07, -0.02, 0.11, ...]

result = LjungBox.test(residuals, 10)
# %{statistic: 8.43, p_value: 0.587, lags: 10, n: 200}

if result.p_value < 0.05 do
  IO.puts("Residuals show significant autocorrelation — revisit the model.")
else
  IO.puts("Residuals are consistent with white noise.")
end

Q-statistic only

LjungBox.statistic([1, 2, 3, 4], 2)
# => 1.58

Autocorrelations

# Individual autocorrelation at a specific lag
LjungBox.autocorrelation([1, 2, 3, 4], 1)
# => 0.25

# All autocorrelations up to max_lag
LjungBox.autocorrelations([1, 2, 3, 4, 5, 6], 4)
# => [rho_1, rho_2, rho_3, rho_4]

API

Function Description
LjungBox.test(series, lags \\ 10) Full test — returns %{statistic, p_value, lags, n}
LjungBox.statistic(series, lags) Q-statistic only
LjungBox.autocorrelation(series, lag) Sample autocorrelation at a single lag
LjungBox.autocorrelations(series, max_lag) Sample autocorrelations at lags 1..max_lag

References