Author: Ivan Svetunkov
Date: 2026-02-05

# ces() - Complex Exponential Smoothing

#### Ivan Svetunkov

#### 2026-02-05

This vignette covers `ces()` and `auto.ces()` functions, which are part of smooth package.

Let’s load the necessary packages:

    require(smooth)

`ces()` function allows constructing Complex Exponential Smoothing either with no seasonality, or with simple/partial/full one. A simple call for `ces()` results in estimation of non-seasonal model:

For the same series from M3 dataset `ces()` can be constructed using:

    ces(BJsales, h=12, holdout=TRUE, silent=FALSE)

    ## Time elapsed: 0.02 seconds
    ## Model estimated using ces() function: CES(none)
    ## With backcasting initialisation
    ## Distribution assumed in the model: Normal
    ## Loss function type: likelihood; Loss function value: 249.4688
    ##         a0+ia1
    ## 2.0004+1.0035i
    ##
    ## Sample size: 138
    ## Number of estimated parameters: 3
    ## Number of degrees of freedom: 135
    ## Information criteria:
    ##      AIC     AICc      BIC     BICc
    ## 504.9376 505.1167 513.7194 514.1606
    ##
    ## Forecast errors:
    ## ME: 0.07; MAE: 1.037; RMSE: 1.276
    ## sCE: 0.371%; Asymmetry: -12.6%; sMAE: 0.456%; sMSE: 0.003%
    ## MASE: 0.871; RMSSE: 0.832; rMAE: 0.335; rRMSE: 0.333

This output is very similar to ones printed out by `adam()` function. The only difference is complex smoothing parameter values which are printed out instead of persistence vector in `adam()`.

If we want automatic model selection, then we use `auto.ces()` function:

    auto.ces(AirPassengers, h=12, holdout=TRUE, silent=FALSE)

    ## Estimating CES with seasonality: "none" "simple" "partial" "full"
    ## The best model is with seasonality = "full"

    ## Time elapsed: 0.13 seconds
    ## Model estimated using ces() function: CES(full)
    ## With backcasting initialisation
    ## Distribution assumed in the model: Normal
    ## Loss function type: likelihood; Loss function value: 498.5864
    ##         a0+ia1
    ## 1.3909+1.0079i
    ##         b0+ib1
    ## 1.8505+1.1037i
    ##
    ## Sample size: 132
    ## Number of estimated parameters: 5
    ## Number of degrees of freedom: 127
    ## Information criteria:
    ##      AIC     AICc      BIC     BICc
    ## 1007.173 1007.649 1021.587 1022.749
    ##
    ## Forecast errors:
    ## ME: -3.351; MAE: 9.544; RMSE: 13.747
    ## sCE: -15.317%; Asymmetry: -21.3%; sMAE: 3.636%; sMSE: 0.274%
    ## MASE: 0.396; RMSSE: 0.439; rMAE: 0.126; rRMSE: 0.133

By default, the function optimises the initial values, but other options (“backcasting” and “complete”) are supported as well:

    ces(BJsales, h=12, holdout=TRUE, initial="back")

    ## Time elapsed: 0.02 seconds
    ## Model estimated using ces() function: CES(none)
    ## With backcasting initialisation
    ## Distribution assumed in the model: Normal
    ## Loss function type: likelihood; Loss function value: 249.4688
    ##         a0+ia1
    ## 2.0004+1.0035i
    ##
    ## Sample size: 138
    ## Number of estimated parameters: 3
    ## Number of degrees of freedom: 135
    ## Information criteria:
    ##      AIC     AICc      BIC     BICc
    ## 504.9376 505.1167 513.7194 514.1606
    ##
    ## Forecast errors:
    ## ME: 0.07; MAE: 1.037; RMSE: 1.276
    ## sCE: 0.371%; Asymmetry: -12.6%; sMAE: 0.456%; sMSE: 0.003%
    ## MASE: 0.871; RMSSE: 0.832; rMAE: 0.335; rRMSE: 0.333

The function also works with explanatory variables if the data frame or a matrix is provided instead of the vector of values:

    BJData <- cbind(y=BJsales, x=BJsales.lead)
    cesModel <- ces(BJData, h=12, holdout=TRUE, regressors="use")

Finally, all the main methods for the adam function are supported by `ces()` as well. For example, here how we can produce prediction interval:

    forecast(cesModel, h=12, interval="pred") |> plot()