STL

This function applies STL (Seasonal-Trend decomposition using LOESS) to a univariate time series and returns observed, trend, seasonal, and residual components.

STL models a series as:

y_t = T_t + S_t + R_t

where T_t is a smooth trend, S_t is a seasonal component with known period, and R_t is the remainder. The robust option can reduce the influence of outliers.

Excel Usage

=STL(data, period, seasonal, robust)
  • data (list[list], required): 2D range of time-series values (numeric).
  • period (int, required): Seasonal period in samples (positive integer).
  • seasonal (int, optional, default: 7): Length of seasonal smoother (odd integer).
  • robust (bool, optional, default: false): Use robust fitting to reduce outlier influence.

Returns (list[list]): 2D array with columns [observed, trend, seasonal, residual].

Example 1: STL decomposition of seasonal series

Inputs:

data period seasonal robust
10 12 14 12 11 13 15 13 12 14 16 14 13 15 17 15 4 7 false

Excel formula:

=STL({10,12,14,12,11,13,15,13,12,14,16,14,13,15,17,15}, 4, 7, FALSE)

Expected output:

Result
10 11.625 -1.625 0
12 11.875 0.125 1.77636e-15
14 12.125 1.875 0
12 12.375 -0.375 1.77636e-15
11 12.625 -1.625 0
13 12.875 0.125 -1.77636e-15
15 13.125 1.875 1.77636e-15
13 13.375 -0.375 1.77636e-15
12 13.625 -1.625 1.77636e-15
14 13.875 0.125 3.55271e-15
16 14.125 1.875 -5.32907e-15
14 14.375 -0.375 0
13 14.625 -1.625 7.10543e-15
15 14.875 0.125 3.55271e-15
17 15.125 1.875 8.88178e-15
15 15.375 -0.375 7.10543e-15
Example 2: Robust STL decomposition

Inputs:

data period seasonal robust
10 12 14 12 11 13 15 13 12 14 16 14 13 15 17 15 4 7 true

Excel formula:

=STL({10,12,14,12,11,13,15,13,12,14,16,14,13,15,17,15}, 4, 7, TRUE)

Expected output:

Result
10 11.625 -1.625 -7.10543e-15
12 11.875 0.125 0
14 12.125 1.875 0
12 12.375 -0.375 1.77636e-15
11 12.625 -1.625 3.55271e-15
13 12.875 0.125 1.77636e-15
15 13.125 1.875 0
13 13.375 -0.375 -5.32907e-15
12 13.625 -1.625 8.88178e-15
14 13.875 0.125 1.77636e-15
16 14.125 1.875 -1.77636e-15
14 14.375 -0.375 -1.77636e-15
13 14.625 -1.625 -1.06581e-14
15 14.875 0.125 -1.95399e-14
17 15.125 1.875 4.44089e-14
15 15.375 -0.375 -8.34888e-14
Example 3: STL with single-column range input

Inputs:

data period seasonal robust
10 4 7 false
12
14
12
11
13
15
13
12
14
16
14
13
15
17
15

Excel formula:

=STL({10;12;14;12;11;13;15;13;12;14;16;14;13;15;17;15}, 4, 7, FALSE)

Expected output:

Result
10 11.625 -1.625 0
12 11.875 0.125 1.77636e-15
14 12.125 1.875 0
12 12.375 -0.375 1.77636e-15
11 12.625 -1.625 0
13 12.875 0.125 -1.77636e-15
15 13.125 1.875 1.77636e-15
13 13.375 -0.375 1.77636e-15
12 13.625 -1.625 1.77636e-15
14 13.875 0.125 3.55271e-15
16 14.125 1.875 -5.32907e-15
14 14.375 -0.375 0
13 14.625 -1.625 7.10543e-15
15 14.875 0.125 3.55271e-15
17 15.125 1.875 8.88178e-15
15 15.375 -0.375 7.10543e-15
Example 4: STL with longer period and data length

Inputs:

data period seasonal robust
20 21 23 25 24 22 21 22 24 26 25 23 22 23 25 27 26 24 23 24 26 28 27 25 6 7 false

Excel formula:

=STL({20,21,23,25,24,22,21,22,24,26,25,23,22,23,25,27,26,24,23,24,26,28,27,25}, 6, 7, FALSE)

Expected output:

Result
20 22.0833 -2.08333 0
21 22.25 -1.25 7.10543e-15
23 22.4167 0.583333 3.55271e-15
25 22.5833 2.41667 3.55271e-15
24 22.75 1.25 3.55271e-15
22 22.9167 -0.916667 -3.55271e-15
21 23.0833 -2.08333 3.55271e-15
22 23.25 -1.25 -7.10543e-15
24 23.4167 0.583333 -3.55271e-15
26 23.5833 2.41667 -3.55271e-15
25 23.75 1.25 -3.55271e-15
23 23.9167 -0.916667 3.55271e-15
22 24.0833 -2.08333 -3.55271e-15
23 24.25 -1.25 0
25 24.4167 0.583333 3.55271e-15
27 24.5833 2.41667 3.55271e-15
26 24.75 1.25 -7.10543e-15
24 24.9167 -0.916667 3.55271e-15
23 25.0833 -2.08333 -3.55271e-15
24 25.25 -1.25 0
26 25.4167 0.583333 -1.06581e-14
28 25.5833 2.41667 -1.06581e-14
27 25.75 1.25 -3.55271e-15
25 25.9167 -0.916667 -1.06581e-14

Python Code

import numpy as np
from statsmodels.tsa.seasonal import STL as sm_STL

def stl(data, period, seasonal=7, robust=False):
    """
    Perform STL decomposition of a univariate time series.

    See: https://www.statsmodels.org/stable/generated/statsmodels.tsa.seasonal.STL.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        data (list[list]): 2D range of time-series values (numeric).
        period (int): Seasonal period in samples (positive integer).
        seasonal (int, optional): Length of seasonal smoother (odd integer). Default is 7.
        robust (bool, optional): Use robust fitting to reduce outlier influence. Default is False.

    Returns:
        list[list]: 2D array with columns [observed, trend, seasonal, residual].
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        data = to2d(data)

        if not isinstance(period, int) or period < 2:
            return "Error: period must be an integer greater than or equal to 2"
        if not isinstance(seasonal, int) or seasonal < 3 or seasonal % 2 == 0:
            return "Error: seasonal must be an odd integer greater than or equal to 3"
        if not isinstance(data, list) or not all(isinstance(row, list) for row in data):
            return "Error: data must be a 2D list"

        values = []
        for row in data:
            for item in row:
                try:
                    values.append(float(item))
                except (TypeError, ValueError):
                    continue

        if len(values) < 2 * period:
            return "Error: data must contain at least two complete seasonal cycles"

        result = sm_STL(values, period=period, seasonal=seasonal, robust=robust).fit()

        observed = np.asarray(values)
        trend = np.asarray(result.trend)
        seasonal_comp = np.asarray(result.seasonal)
        resid = np.asarray(result.resid)

        output = []
        for i in range(len(observed)):
            row = []
            for arr in (observed, trend, seasonal_comp, resid):
                val = arr[i]
                row.append(float(val) if np.isfinite(val) else "")
            output.append(row)

        return output
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D range of time-series values (numeric).
Seasonal period in samples (positive integer).
Length of seasonal smoother (odd integer).
Use robust fitting to reduce outlier influence.