KPSS
This function applies the Kwiatkowski-Phillips-Schmidt-Shin (KPSS) test for stationarity.
Unlike the ADF test, the KPSS null hypothesis is stationarity (around a level or trend), and the alternative is a unit root.
The output includes the KPSS statistic, p-value, selected lag truncation, and reference critical values.
Excel Usage
=KPSS(x, kpss_regression, nlags, store)
x(list[list], required): Time-series observations as a 2D range.kpss_regression(str, optional, default: “c”): Null hypothesis type, c for level-stationary or ct for trend-stationary.nlags(str, optional, default: “auto”): Lag selection mode (auto or legacy) or an integer provided as text.store(bool, optional, default: false): Return result storage object in addition to scalar outputs.
Returns (list[list]): 2D key-value table summarizing KPSS statistics and critical values.
Example 1: KPSS with automatic lag selection and level stationarity null
Inputs:
| x | kpss_regression | nlags | store | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1.1 | 1.05 | 1.08 | 1.03 | 1.09 | 1.04 | 1.1 | 1.06 | 1.11 | c | auto | false |
Excel formula:
=KPSS({1,1.1,1.05,1.08,1.03,1.09,1.04,1.1,1.06,1.11}, "c", "auto", FALSE)
Expected output:
| Result | |
|---|---|
| kpss_stat | 0.5 |
| p_value | 0.0416667 |
| lags | 9 |
| critical_10% | 0.347 |
| critical_5% | 0.463 |
| critical_2.5% | 0.574 |
| critical_1% | 0.739 |
Example 2: KPSS with legacy lag rule and trend stationarity null
Inputs:
| x | kpss_regression | nlags | store | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2 | 2.2 | 2.35 | 2.5 | 2.65 | 2.8 | 2.95 | 3.1 | 3.25 | 3.4 | ct | legacy | false |
Excel formula:
=KPSS({2,2.2,2.35,2.5,2.65,2.8,2.95,3.1,3.25,3.4}, "ct", "legacy", FALSE)
Expected output:
| Result | |
|---|---|
| kpss_stat | 0.358798 |
| p_value | 0.01 |
| lags | 7 |
| critical_10% | 0.119 |
| critical_5% | 0.146 |
| critical_2.5% | 0.176 |
| critical_1% | 0.216 |
Example 3: KPSS with manually provided lag count
Inputs:
| x | kpss_regression | nlags | store | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3 | 3.1 | 3 | 3.15 | 3.05 | 3.2 | 3.1 | 3.25 | 3.15 | 3.3 | c | 2 | false |
Excel formula:
=KPSS({3,3.1,3,3.15,3.05,3.2,3.1,3.25,3.15,3.3}, "c", 2, FALSE)
Expected output:
| Result | |
|---|---|
| kpss_stat | 0.440047 |
| p_value | 0.0598935 |
| lags | 2 |
| critical_10% | 0.347 |
| critical_5% | 0.463 |
| critical_2.5% | 0.574 |
| critical_1% | 0.739 |
Example 4: KPSS on low-variance stationary-looking series
Inputs:
| x | kpss_regression | nlags | store | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 5 | 5.02 | 4.99 | 5.01 | 5 | 5.03 | 4.98 | 5.01 | 5 | 5.02 | c | auto | false |
Excel formula:
=KPSS({5,5.02,4.99,5.01,5,5.03,4.98,5.01,5,5.02}, "c", "auto", FALSE)
Expected output:
| Result | |
|---|---|
| kpss_stat | 0.326271 |
| p_value | 0.1 |
| lags | 6 |
| critical_10% | 0.347 |
| critical_5% | 0.463 |
| critical_2.5% | 0.574 |
| critical_1% | 0.739 |
Python Code
import numpy as np
from statsmodels.tsa.stattools import kpss as sm_kpss
def kpss(x, kpss_regression='c', nlags='auto', store=False):
"""
Run the KPSS stationarity test under level or trend null hypotheses.
See: https://www.statsmodels.org/stable/generated/statsmodels.tsa.stattools.kpss.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time-series observations as a 2D range.
kpss_regression (str, optional): Null hypothesis type, c for level-stationary or ct for trend-stationary. Valid options: Constant, Constant+Trend. Default is 'c'.
nlags (str, optional): Lag selection mode (auto or legacy) or an integer provided as text. Valid options: Auto, Legacy. Default is 'auto'.
store (bool, optional): Return result storage object in addition to scalar outputs. Default is False.
Returns:
list[list]: 2D key-value table summarizing KPSS statistics and critical values.
"""
try:
def to1d(values):
if isinstance(values, list):
if all(isinstance(row, list) for row in values):
raw = [item for row in values for item in row]
else:
raw = values
else:
raw = [values]
out = []
for item in raw:
try:
out.append(float(item))
except (TypeError, ValueError):
continue
return out
if kpss_regression not in ("c", "ct"):
return "Error: regression must be 'c' or 'ct'"
if nlags in ("auto", "legacy"):
nlags_arg = nlags
else:
try:
parsed = int(float(nlags))
except (TypeError, ValueError):
return "Error: nlags must be 'auto', 'legacy', or an integer"
if parsed < 0:
return "Error: nlags integer must be nonnegative"
nlags_arg = parsed
series = to1d(x)
if len(series) < 4:
return "Error: x must contain at least four numeric values"
result = sm_kpss(
np.asarray(series, dtype=float),
regression=kpss_regression,
nlags=nlags_arg,
store=store,
)
kpss_stat = float(result[0])
p_value = float(result[1])
used_lags = int(result[2])
crit_values = result[3]
rows = [
["kpss_stat", kpss_stat],
["p_value", p_value],
["lags", used_lags],
]
if isinstance(crit_values, dict):
for key in ("10%", "5%", "2.5%", "1%"):
if key in crit_values:
rows.append([f"critical_{key}", float(crit_values[key])])
return rows
except Exception as e:
return f"Error: {str(e)}"Online Calculator
Time-series observations as a 2D range.
Null hypothesis type, c for level-stationary or ct for trend-stationary.
Lag selection mode (auto or legacy) or an integer provided as text.
Return result storage object in addition to scalar outputs.