Author: J.L. Gallego
Date: 2025-11-03

# Quick Introduction to the tfarima Package

#### J.L. Gallego

#### 2025-11-03

# Introduction

The tfarima package provides a comprehensive framework for specifying, estimating, and analyzing Transfer Function and ARIMA models in a unified and transparent way.
It introduces several S3 classes such as `lagpol`, `um`, `tfm`, and `ucarima` that allow users to work directly with lag polynomials, univariate models, transfer function models, and UCARIMA decompositions, respectively.

This vignette offers a quick overview of the main features of the package, demonstrating how to define models, simulate data, estimate parameters, and perform diagnostic and forecasting analyses.

# First-Order Autoregressive (Markov) Process

We begin with a simple AR(1) model to illustrate basic functionality.

    # Creating an AR(1) process with mean 0.5 and innovation variance 1.5
    ar1p <- um(ar = "1 - 0.8B", mu = 0.5, sig2 = 1.5)

    # Displaying model properties
    phi(ar1p)
    #> 1 - 0.8B
    roots(ar1p)
    #> $ar1
    #>      Real Imaginary Modulus Frequency Period Mult.
    #> [1,] 1.25         0    1.25         0    Inf     1
    psi.weights(ar1p, 10)
    #>      psi0      psi1      psi2      psi3      psi4      psi5      psi6
    #> 1.0000000 0.8000000 0.6400000 0.5120000 0.4096000 0.3276800 0.2621440
    #>      psi7      psi8      psi9     psi10
    #> 0.2097152 0.1677722 0.1342177 0.1073742
    autocorr(ar1p, 10)
    #>      rho0      rho1      rho2      rho3      rho4      rho5      rho6
    #> 1.0000000 0.8000000 0.6400000 0.5120000 0.4096000 0.3276800 0.2621440
    #>      rho7      rho8      rho9     rho10
    #> 0.2097152 0.1677722 0.1342177 0.1073742
    spec(ar1p)[1:5, ]
    #>          w       fw
    #> [1,] 0.000 5.968310
    #> [2,] 0.001 5.963602
    #> [3,] 0.002 5.949520
    #> [4,] 0.003 5.926199
    #> [5,] 0.004 5.893857
    display(ar1p)

Now we can simulate a realization and fit the same model back to the data.

    set.seed(1234)
    z <- sim(ar1p, n = 100)
    ide(z)

    ar1p.fit <- fit(ar1p, z)
    diagchk(ar1p.fit)

    p <- predict(ar1p.fit, n.ahead = 5)
    plot(p, n.back = 20)

# Lag Polynomial Objects (`lagpol` Class)

The `lagpol` class provides a convenient symbolic representation of lag polynomials, including seasonal and multiplicative structures.

    lp1 <- lagpol(param = c(theta = 0.5), p = 2)
    lp2 <- lagpol(param = c(Theta1 = 1.2, Theta2 = -0.9), s = 12)
    lp3 <- lagpol(param = c(theta = 0.8, Theta = 0.9),
                  coef = c("theta", "Theta", "-theta*Theta"),
                  lags = c(1, 12, 13))
    lp3
    #> 1 - 0.8B - 0.9B^12 + 0.72B^13

It also supports compact symbolic specifications through `lagpol0()`:

    i  <- lagpol0(list(1, c(1, 3), c(1, 12)), "i")
    ma <- lagpol0("(1 - 0.8B)(1 - 0.7B3)(1 - 0.6B12)", "ma")
    printLagpolList(i)
    #> [1] 1 - B   [2] 1 - B^3   [3] 1 - B^12
    printLagpolList(ma)
    #> [1] 1 - 0.8B   [2] 1 - 0.7B^3   [3] 1 - 0.6B^12

# Univariate Models (`um` Class)

The `um` class represents univariate ARIMA-type models, combining lag polynomials and parameters in a structured way.

    ar1p <- um(ar = "(1 - 0.9B)")
    ar1n <- um(ar = "(1 + 0.9B)")
    ma1p <- um(ma = "(1 - 0.9B)")
    ma1n <- um(ma = "(1 + 0.9B)")
    ar2c <- um(ar = "(1 - 1.52B + 0.8B^2)")

    display(list(ar1p, ar1n, ma1p, ma1n, ar2c),
            lag.max = 20, graphs = c("acf", "pacf", "spec"))

# Example: Building Material Series

Here we identify and estimate a seasonal ARIMA model for the `BuildingMat` dataset.

    Z <- BuildingMat
    ide(Z, transf = list(
      list(bc = TRUE),
      list(bc = TRUE, S = 1),
      list(bc = TRUE, d = 1, D = 1),
      list(bc = TRUE, d = 1, D = 1, i = lagpol(s = 3, coef = "1"))
    ))

    um1 <- um(Z, bc = TRUE,
              i  = list(1, c(1, 3), c(1, 12)),
              ma = list(theta = 1, Theta = c(1, 3), THETA = c(1, 12)))
    diagchk(um1)

    p <- predict(um1, n.ahead = 12, i = c(1, 12))
    plot(p, n.back = 72)

A UCARIMA decomposition can be obtained for the fitted model:

    uca1 <- as.ucarima(um1, i = 3)
    uc1 <- wkfilter(uca1)
    plot(uc1, main = "")

# Transfer Function Models (`tfm` Class)

Transfer function models allow us to model dynamic relationships between input and output time series.

    Y <- seriesJ$Y - mean(seriesJ$Y)
    X <- seriesJ$X - mean(seriesJ$X)

    umx <- um(X, ar = 3)
    umy <- fit(umx, Y)
    pccf(X, Y, um.x = umx, lag.max = 16)

    tfx  <- tfest(Y, X, delay = 3, p = 2, q = 2, um.x = umx, um.y = umy)
    tfmy <- tfm(Y, inputs = tfx, noise = um(ar = 2))
    tfmy
    #>         Estimate Std. Error
    #> X    -0.53141158 0.07356736
    #> X.d1  0.56456814 0.20463368
    #> X.d2 -0.01122093 0.14146574
    #> X.w1 -0.69926401 0.33925408
    #> X.w2 -0.96083268 0.31367491
    #> ar1   1.52875879 0.04617066
    #> ar2  -0.63046844 0.04857962
    #>
    #> log likelihood:  4.288532
    #> Residual standard error:  0.2375415
    #> aic: 0.01832073

Another example with BJsales data:

    Y <- window(BJsales, end = 140)
    X <- window(BJsales.lead, end = 140)
    umy <- um(Y, i = 1, ma = "1-0.620B", mu = 0.033, fit = FALSE)
    umx <- um(X, i = 1, ma = "1 - 0.4483B", fit = FALSE)
    tfx <- tf(X, delay = 3, w0 = 4.716, ar = "1-0.725B", um = umx)
    tfmy <- tfm(output = Y, inputs = tfx, noise = umy, fit = FALSE)
    plot(predict(tfmy, n.ahead = 10, ori = 89), n.back = 15, ylab = expression(Y[t]))

# Outliers and Calendar Effects

The `outliers()` function can automatically detect additive outliers, level shifts, and calendar-related effects.

    tfm1 <- outliers(um1, calendar = TRUE, easter = TRUE,
                     form = "wd", c = 4, p.value = 0.05, n.ahead = 24)
    tfm1
    #>                 Estimate   Std. Error
    #> wkdays_wknd  0.007332737 0.0002480437
    #> leapyear     0.037447165 0.0058897925
    #> Easter4     -0.013014259 0.0038389251
    #> LS20.05      0.128985025 0.0204090465
    #> TC21.03      0.116594564 0.0196686907
    #> theta        0.208174283 0.0505459903
    #> Theta        0.999513134 0.0161521838
    #> THETA        0.666107661 0.0417386475
    #>
    #> log likelihood:  878.6611
    #> Residual standard error:  0.02266491
    #> aic: -4.582427

# UCARIMA Decompositions

Finally, the `ucarima` class provides a unified structure for unobserved components models.

    trend <- um(i = 2, ma = c(theta = 1), sig2 = c(s2t = 0.1))
    seas  <- um(i = "12",
                 ma = lagpol(coef = c("0.7944","0.6185","0.4699",
                                      "0.3465","0.2458","0.1658",
                                      "0.1041","0.0587","0.0275","0.0086")),
                 sig2 = c(s2s = 0.01))
    irreg <- um(sig2 = c(s2i = 1))

    uca1 <- ucarima(Z, bc = TRUE,
                    ucm = list(trend = trend, seas = seas, irreg = irreg))
    rf1  <- as.um(uca1)
    uca3 <- as.ucarima(rf1, i = 2, canonical = FALSE)
    uca3
    #> signal1
    #> (1 - B)^2z_t = (1 - 0.94B)a_t, s2a = 0.0002011
    #> signal2
    #> (1 + B + B^2 + B^3 + B^4 + B^5 + B^6 + B^7 + B^8 + B^9 + B^10 +
    #> B^11)z_t = (1 + 0.11B + 0.07B^2 + 0.037B^3 + 0.013B^4 - 0.0017B^5 -
    #> 0.01B^6 - 0.013B^7 - 0.012B^8 - 0.0082B^9 - 0.0036B^10)a_t, s2a =
    #> 1.169e-05
    #> noise
    #> z_t = a_t, s2a = 0.0008268

# Summary

This vignette has illustrated how tfarima supports the entire workflow for ARIMA and transfer function modeling:
from model specification (`lagpol`, `um`) and simulation, to estimation (`fit`), diagnostics (`diagchk`), forecasting (`predict`), and structural decomposition (`ucarima`).

For more formal details, theoretical background, and advanced examples, see the accompanying article and package documentation.