KPSS Test (Kwiatkowski-Phillips-Schmidt-Shin Test)
Introduction
The KPSS Test (Kwiatkowski-Phillips-Schmidt-Shin Test) is a statistical test for stationarity in a time series: it puts stationarity in the null hypothesis and a unit root in the alternative-the reverse of the Augmented Dickey-Fuller (ADF) Test, which treats a unit root as the null.
A time series is stationary when its mean, variance, and autocorrelation structure don't change over time. Most classical time series models (ARIMA, exponential smoothing, standard regression on time-ordered data) assume this implicitly. When it doesn't hold, forecasts drift, regressions between unrelated series produce spurious correlations, and confidence intervals understate the true uncertainty. The KPSS Test exists to catch this before it corrupts downstream modeling.
What Is the KPSS Test?
The KPSS Test, introduced by Kwiatkowski, Phillips, Schmidt, and Shin in 1992, assumes the series is stationary and checks whether the data provides enough evidence to reject that assumption in favor of a unit root. This is the inverse of most unit root tests- ADF, Phillips-Perron-which assume the series has a unit root and check whether the data provides enough evidence to reject that assumption in favor of stationarity.
This inversion matters because unit-root-null tests like ADF have limited statistical power in small samples: a genuinely stationary series can easily fail to reject a unit root simply because there isn't enough data to disprove it. The KPSS Test corrects for this by putting the burden of proof on the opposite side. When a series fails to reject stationarity under KPSS and rejects the unit-root null under ADF, that agreement is substantially stronger evidence than either test alone.
When to Use It
The KPSS Test applies to a single, time-ordered series where the goal is direct evidence for stationarity, not merely an absence of evidence against a unit root. In practice it is run alongside the ADF Test-before fitting an ARIMA/SARIMA model, before running a regression where the series appears as a dependent or independent variable, or as a precondition check for cointegration testing.
| Scenario | Series | What's Being Checked |
|---|---|---|
| Confirming an ADF result | Any series where ADF failed to reject the unit-root null | Whether stationarity can be directly supported, not just "not disproven" |
| ARIMA model building | Monthly sales, website traffic, demand | Whether the series is already stationary before differencing |
| Macroeconomic analysis | GDP, inflation rate, unemployment rate | Whether the series reverts to a trend or drifts like a random walk |
| Financial time series | Stock prices, exchange rates, index levels | Whether raw price levels show any stationary behavior at all |
| Cointegration analysis | Residuals from a regression between two price series | Direct confirmation that the residual spread is stationary |
| Pre-check before Granger causality testing | Two related economic or financial series | Whether both series are stationary before running the Granger Causality Test |
Key Assumptions
- The series is a single, time-ordered sequence: the test is built for one series at a time, observed in its correct chronological order-shuffled or unordered data makes the test meaningless.
- The correct regression variant matches the series' behavior: the level-stationary variant assumes the series should hover around a fixed mean, while the trend-stationary variant assumes it should hover around a deterministic trend line-picking the wrong one can flip the conclusion, see Critical Values and Test Variants.
- The long-run variance is estimated with an appropriate lag truncation: the correction for autocorrelation in the residuals depends on a bandwidth (lag truncation) parameter-too small a value under-corrects and inflates false rejections, too large a value costs power.
- The underlying errors are well-behaved enough for the correction to work: the non-parametric long-run variance estimator assumes the residual autocorrelation and heteroskedasticity follow reasonably standard patterns, not extreme structural anomalies.
- No missing observations within the sequence: gaps in an otherwise time-ordered series distort both the cumulative partial sums and the long-run variance estimate the test relies on.
Hypotheses
The KPSS Test formally tests whether a time series can be described as stationary around a deterministic component (a constant mean or a linear trend), against the alternative that it instead contains a random walk component:
- Null Hypothesis (\( H_0 \)): the series is stationary-either around a constant mean (level-stationary) or a deterministic trend (trend-stationary), depending on the variant fit.
- Alternative Hypothesis (\( H_1 \)): the series has a unit root and is non-stationary.
(Notice this is the exact mirror image of the ADF Test: here, failing to reject \( H_0 \) is the "good news" outcome that supports stationarity, while rejecting \( H_0 \) is direct evidence of a unit root. Whichever test you run, always check which hypothesis is playing which role before interpreting a p-value.)
The Formula, Explained
Let \( y_1, y_2, \ldots, y_n \) be the observed time series in its natural order. The KPSS Test starts by regressing \( y_t \) on a deterministic component-either just a constant (for the level-stationary variant) or a constant plus a linear time trend (for the trend-stationary variant)-and collecting the residuals \( e_t \):
\[ y_t = \mu + \delta t + e_t \](Set \( \delta = 0 \) for the level-stationary variant, so the "regression" is simply \( e_t = y_t - \bar{y} \).) Next, build the cumulative partial sum of these residuals-this is the heart of the test, since a stationary series should keep this running sum bounded, while a unit-root series will let it wander:
\[ S_t = \sum_{i=1}^{t} e_i, \qquad t = 1, 2, \ldots, n \]The KPSS test statistic (often called the Lagrange Multiplier, or LM, statistic) is then:
\[ \text{KPSS} = \frac{1}{n^2} \sum_{t=1}^{n} \frac{S_t^2}{\hat{\sigma}^2} \]Here \( \hat{\sigma}^2 \) is a long-run variance estimate of \( e_t \), not just the plain sample variance-it is typically computed with a Newey-West type kernel that adds weighted autocovariance terms up to some lag truncation \( \ell \), to account for autocorrelation in the residuals:
\[ \hat{\sigma}^2 = \frac{1}{n}\sum_{t=1}^{n} e_t^2 \; + \; \frac{2}{n}\sum_{s=1}^{\ell} w(s,\ell) \sum_{t=s+1}^{n} e_t e_{t-s} \]where \( w(s, \ell) = 1 - \frac{s}{\ell+1} \) is the Bartlett kernel weight. When \( \ell = 0 \)-no autocorrelation correction-this collapses to the plain average of \( e_t^2 \), which is exactly what the hand-worked examples below use for a clean, fully manual calculation.
Unlike the ADF Test's t-statistic, the KPSS statistic is always non-negative and its null distribution isn't a standard one either-Kwiatkowski, Phillips, Schmidt, and Shin derived their own asymptotic distribution and published a dedicated set of critical values for it, covered next.
Critical Values and Test Variants
Because the KPSS statistic's distribution under \( H_0 \) is non-standard, it cannot be evaluated with ordinary chi-squared tables. Instead, Kwiatkowski, Phillips, Schmidt, and Shin derived a separate set of critical values that depend on which of two regression variants you fit:
| Variant | Regression | When to Use |
|---|---|---|
Level stationarity (regression='c') | \( y_t = \mu + e_t \) | Series expected to hover around a fixed, non-trending mean |
Trend stationarity (regression='ct') | \( y_t = \mu + \delta t + e_t \) | Series that visibly trends upward or downward but should stay near that trend line |
Asymptotic critical values, as published in the original 1992 paper:
| Significance Level | Level Stationarity (\( \eta_\mu \)) | Trend Stationarity (\( \eta_\tau \)) |
|---|---|---|
| 10% | \( 0.347 \) | \( 0.119 \) |
| 5% | \( 0.463 \) | \( 0.146 \) |
| 2.5% | \( 0.574 \) | \( 0.176 \) |
| 1% | \( 0.739 \) | \( 0.216 \) |
Worked Example 1: A Stable (Stationary) Series
Suppose we observe a series over 8 consecutive periods that hovers around a fixed level with no visible drift or trend:
| Time \( t \) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| \( y_t \) | 2.0 | 2.3 | 1.8 | 2.1 | 1.9 | 2.2 | 1.7 | 2.0 |
We fit the level-stationary variant with no lag correction (\( \ell = 0 \)) for a fully hand-computable walkthrough: \( y_t = \mu + e_t \).
Step 1: Fit the mean and compute residuals
\[ \bar{y} = \frac{2.0+2.3+1.8+2.1+1.9+2.2+1.7+2.0}{8} = 2.0 \] \[ e_t = y_t - \bar{y}:\quad 0.0,\ 0.3,\ -0.2,\ 0.1,\ -0.1,\ 0.2,\ -0.3,\ 0.0 \]Step 2: Build the cumulative partial sums \( S_t \)
\[ S_t = \sum_{i=1}^{t} e_i:\quad 0.0,\ 0.3,\ 0.1,\ 0.2,\ 0.1,\ 0.3,\ 0.0,\ 0.0 \]Notice how \( S_t \) keeps returning close to zero rather than growing-that's the visual signature of stationarity in this statistic.
Step 3: Compute \( \sum S_t^2 \) and the long-run variance \( \hat{\sigma}^2 \)
\[ \sum_{t=1}^{8} S_t^2 = 0^2 + 0.3^2 + 0.1^2 + 0.2^2 + 0.1^2 + 0.3^2 + 0^2 + 0^2 = 0.24 \] \[ \hat{\sigma}^2 = \frac{1}{n}\sum_{t=1}^{n} e_t^2 = \frac{0^2+0.3^2+0.2^2+0.1^2+0.1^2+0.2^2+0.3^2+0^2}{8} = \frac{0.28}{8} = 0.035 \]Step 4: Compute the KPSS statistic
\[ \text{KPSS} = \frac{\sum S_t^2}{n^2 \, \hat{\sigma}^2} = \frac{0.24}{8^2 \times 0.035} = \frac{0.24}{2.24} \approx 0.1071 \]Step 5: Interpret
With a KPSS statistic of \( \approx 0.1071 \), compare against the level-stationary critical values from earlier: it sits well below even the 10% threshold (\( 0.347 \)). We fail to reject \( H_0 \)-this series is consistent with stationarity around a fixed mean, matching the bounded, non-drifting partial sums computed in Step 2.
Worked Example 2: A Trending (Non-Stationary) Series
Now suppose a second series over 8 consecutive periods climbs steadily, with no sign of reverting to any fixed level:
| Time \( t \) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| \( y_t \) | 5.0 | 5.8 | 7.1 | 7.9 | 9.3 | 10.1 | 11.4 | 12.6 |
We again fit the level-stationary variant with \( \ell = 0 \), which is the deliberately "wrong" variant here-exactly the kind of series where checking against a fixed mean, rather than a trend line, should produce a strong signal of non-stationarity.
Step 1: Fit the mean and compute residuals
\[ \bar{y} = \frac{5.0+5.8+7.1+7.9+9.3+10.1+11.4+12.6}{8} = 8.65 \] \[ e_t = y_t - \bar{y}:\quad -3.65,\ -2.85,\ -1.55,\ -0.75,\ 0.65,\ 1.45,\ 2.75,\ 3.95 \]Step 2: Build the cumulative partial sums \( S_t \)
\[ S_t = \sum_{i=1}^{t} e_i:\quad -3.65,\ -6.50,\ -8.05,\ -8.80,\ -8.15,\ -6.70,\ -3.95,\ 0.00 \]Unlike Example 1, \( S_t \) swings far away from zero and stays there for most of the sample instead of oscillating around it-that persistent excursion is exactly what the KPSS statistic is built to detect.
Step 3: Compute \( \sum S_t^2 \) and the long-run variance \( \hat{\sigma}^2 \)
\[ \sum_{t=1}^{8} S_t^2 \approx 13.32 + 42.25 + 64.80 + 77.44 + 66.42 + 44.89 + 15.60 + 0.00 = 324.73 \] \[ \hat{\sigma}^2 = \frac{1}{n}\sum_{t=1}^{n} e_t^2 \approx \frac{13.32+8.12+2.40+0.56+0.42+2.10+7.56+15.60}{8} = \frac{50.10}{8} \approx 6.2625 \]Step 4: Compute the KPSS statistic
\[ \text{KPSS} = \frac{\sum S_t^2}{n^2 \, \hat{\sigma}^2} = \frac{324.73}{8^2 \times 6.2625} = \frac{324.73}{400.8} \approx 0.8102 \]Step 5: Interpret
With a KPSS statistic of \( \approx 0.8102 \), compare again against the level-stationary critical values: it is well past even the 1% threshold (\( 0.739 \)). We reject \( H_0 \) at the 1% level- strong evidence that this series is not stationary around a fixed mean, consistent with the steady upward climb visible in the raw data. (Fitting the trend-stationary variant instead, which allows the series to hover around a rising trend line rather than a flat mean, would likely tell a very different story-see the Python example below.)
Python Example
You can run the full KPSS Test, including automatic lag selection for the long-run variance estimate, in one line using statsmodels.tsa.stattools.kpss:
import numpy as np
from statsmodels.tsa.stattools import kpss
# Worked Example 1 data: a stable, level-stationary series
y = np.array([2.0, 2.3, 1.8, 2.1, 1.9, 2.2, 1.7, 2.0])
stat, p_value, used_lags, crit_values = kpss(y, regression='c', nlags=0)
print(f"KPSS statistic: {stat:.4f}")
print(f"p-value: {p_value}")
print(f"Lags used: {used_lags}")
print("Critical values:", crit_values)
Output (matches the hand-worked \( \ell = 0 \) case exactly):
KPSS statistic: 0.1071
p-value: 0.1
Lags used: 0
Critical values: {'10%': 0.347, '5%': 0.463, '2.5%': 0.574, '1%': 0.739}
Checking the Trending Series with Both Variants
# Worked Example 2 data: a steadily climbing series
y_trend = np.array([5.0, 5.8, 7.1, 7.9, 9.3, 10.1, 11.4, 12.6])
# Level-stationary variant (matches the hand calculation above)
stat_c, p_c, lags_c, crit_c = kpss(y_trend, regression='c', nlags=0)
print(f"Level variant -> KPSS statistic: {stat_c:.4f}")
# KPSS statistic: 0.8102 -> rejects H0 at 1%, non-stationary around a fixed mean
# Trend-stationary variant: allow the series to hover around a trend line instead
stat_ct, p_ct, lags_ct, crit_ct = kpss(y_trend, regression='ct', nlags=0)
print(f"Trend variant -> KPSS statistic: {stat_ct:.4f}")
print("Trend critical values:", crit_ct)
# KPSS statistic: 0.0762 -> fails to reject H0, series is trend-stationary
# First-differencing is the alternative fix if trend-stationarity doesn't apply:
y_diff = np.diff(y_trend)
stat_diff, p_diff, lags_diff, crit_diff = kpss(y_diff, regression='c', nlags=0)
print(f"After differencing -> KPSS statistic: {stat_diff:.4f}")
This is the single most important practical lesson of the KPSS Test: the same series can be "non-stationary" under the level-stationary variant (\( 0.8102 \), rejected at 1%) and simultaneously "stationary" under the trend-stationary variant (\( 0.0762 \), comfortably below even the 10% threshold of \( 0.119 \))-because a steadily climbing series really is stable once you let it hover around a rising trend line instead of a flat one. Choosing the right variant, covered next in How to Interpret Results, is not optional.
How to Interpret Results
Because the KPSS Test is right-tailed and non-negative, interpretation runs in the opposite direction from the ADF Test-large statistics are the "bad news" outcome here, not small or negative ones.
| Result | Interpretation |
|---|---|
| KPSS statistic below the critical value (large p-value) | Fail to reject \( H_0 \)-series is likely stationary |
| KPSS statistic above the critical value (small p-value) | Reject \( H_0 \)-series likely has a unit root, non-stationary |
| Level variant rejects, trend variant does not | Series is trend-stationary-hovers around a trend line, not a flat mean |
| Result borderline across significance levels | Weak or inconclusive evidence-consider a larger sample or the ADF Test |
Checking Assumptions in Practice
- Plot the series first: a simple line plot over time tells you which variant to fit-visible oscillation around a flat level suggests the level-stationary variant, while a steady, predictable climb or decline suggests the trend-stationary variant, matching the contrast in Worked Example 1 and Worked Example 2.
- Always try both variants on a trending series: as shown in the Python example, the same climbing series can reject under the level-stationary variant while comfortably failing to reject under the trend-stationary variant-fitting only one variant risks a misleading conclusion.
- Let the software pick the lag truncation, then sanity-check it: automatic selection via
nlags='auto'is the standard recommendation-too few lags leave autocorrelation uncorrected and inflate false rejections, too many lags waste degrees of freedom and reduce power. The Ljung-Box Test is a useful separate check on whether autocorrelation remains in the residuals. - Cross-check with the ADF Test: because KPSS and ADF have opposite null hypotheses, running both and checking for agreement (see KPSS vs ADF vs Phillips-Perron) gives much stronger evidence than either test alone, especially for series near the boundary.
- Watch for structural breaks: a single sharp level shift or regime change partway through the series can make the KPSS Test falsely reject \( H_0 \), even when each segment is individually stationary-inspect the plot for breaks before trusting a "non-stationary" conclusion.
What to Do If a Unit Root Is Detected
- Check the trend-stationary variant before differencing: if the level variant rejects \( H_0 \) but the series visibly trends smoothly, refit with
regression='ct'first-many series that look non-stationary against a flat mean are perfectly stationary around a trend line, as shown in the Python example. - Take the first difference and re-test: if neither variant supports stationarity, replace \( y_t \) with \( \Delta y_t = y_t - y_{t-1} \) and re-run the KPSS Test; a large share of economic and business series become stationary after exactly one round of differencing.
- Difference again if needed: if the once-differenced series still rejects \( H_0 \), take a second difference, though needing more than two rounds is uncommon and may signal a different underlying issue.
- Consider a log transform first: for series with multiplicative growth (revenue, prices), taking logs before differencing or detrending often produces a cleaner, more stable series.
- Confirm with the ADF Test: before committing to a differencing or detrending strategy, check whether the ADF Test agrees-if it also indicates a unit root, that's strong combined evidence, as covered in KPSS vs ADF vs Phillips-Perron.
Advantages
- Puts stationarity in the null hypothesis, so failing to reject is direct, positive evidence for stationarity-rather than the ADF Test's "absence of evidence against a unit root."
- Provides an independent cross-check against ADF-style tests, and agreement between the two is much stronger evidence than either test alone, especially for borderline series.
- Explicitly supports a trend-stationary variant, letting the test correctly recognize series that are stable around a rising or falling trend line rather than flagging them as non-stationary.
- Non-parametric correction for autocorrelation (via the long-run variance estimate) avoids having to choose an explicit autoregressive lag order the way the ADF Test does.
- Widely implemented and reported automatically by standard software, including one-line support in
statsmodelsand R'stseriespackage.
Limitations
- Known to over-reject the null hypothesis of stationarity in samples with strong positive autocorrelation, even when the lag truncation parameter is chosen reasonably-meaning it can flag a genuinely stationary series as having a unit root more often than the nominal significance level suggests.
- Sensitive to the lag truncation choice: results can shift noticeably depending on how many lags are used in the long-run variance estimate, with no single universally agreed-upon rule.
- Sensitive to structural breaks: a single level shift can cause the test to falsely reject \( H_0 \), even when the series is stationary within each regime.
- Results depend heavily on choosing the correct regression variant (level vs. trend)-as shown in the worked examples, the same series can produce opposite conclusions under the two variants.
- Like the ADF Test, it only addresses a single unit root at a time and assumes standard conditions on the error term that heavy structural anomalies can undermine.
When NOT to Use It
- ADF Test: use instead, or alongside, when you want a unit root as the null hypothesis rather than the alternative-particularly useful as the primary test, with KPSS as the confirming cross-check.
- Phillips-Perron Test: use instead when you want a unit-root-null test with a non-parametric autocorrelation correction similar in spirit to KPSS's long-run variance estimate, but framed the same direction as ADF.
- Series with a known structural break: use a break-aware stationarity test instead of the plain KPSS Test, which can misread a level shift as a unit root.
- Panel data with multiple series: use a panel stationarity test (e.g., Hadri's test, the KPSS-style panel counterpart) instead, which pools information across units for more power than running separate KPSS Tests on each series.
- Cross-sectional data with no time ordering: don't use the KPSS Test at all if your observations have no meaningful sequence-there is no "cumulative partial sum" for the test to work with.
KPSS vs ADF vs Phillips-Perron
17.1 KPSS Test vs ADF Test
| Aspect | KPSS Test | ADF Test |
|---|---|---|
| Null hypothesis | Series is stationary | Series has a unit root (non-stationary) |
| Rejecting \( H_0 \) means | Evidence for a unit root | Evidence for stationarity |
| Test statistic direction | Right-tailed; reject if statistic is large | Left-tailed; reject if statistic is very negative |
| Handles autocorrelation via | Non-parametric long-run variance correction | Lagged difference terms in the regression |
| Best practice | Run alongside ADF; agreement is stronger evidence than either alone | Same-agreement resolves the ambiguity of either test in isolation |
17.2 KPSS Test vs Phillips-Perron Test
| Aspect | KPSS Test | Phillips-Perron Test |
|---|---|---|
| Null hypothesis | Stationarity | Unit root (same framework as ADF) |
| Approach to autocorrelation | Non-parametric long-run variance estimate | Non-parametric correction to the test statistic directly |
| Typical use | Confirming test, run alongside a unit-root-null test | Alternative to ADF as the primary unit-root-null test |
| Sensitivity | Sensitive to lag truncation choice; can over-reject stationarity | Can behave poorly under strong negative moving-average errors |
17.3 Reading the Four Possible Combinations
| ADF Result | KPSS Result | Conclusion |
|---|---|---|
| Rejects unit root | Fails to reject stationarity | Strong, consistent evidence the series is stationary |
| Fails to reject unit root | Rejects stationarity | Strong, consistent evidence the series is non-stationary |
| Fails to reject unit root | Fails to reject stationarity | Inconclusive-often a sign of low power in a small sample; consider more data |
| Rejects unit root | Rejects stationarity | Contradictory-often indicates a series that is stationary around a trend rather than a level (or vice versa); check both regression variants, as in the Python example |
Common Misconceptions
- "A large p-value in KPSS is bad news, like in most tests." Not true-since stationarity is the null hypothesis here, a large p-value means you fail to reject stationarity, which is the outcome analysts usually hope for. This is the exact opposite convention from the ADF Test.
- "Failing to reject \( H_0 \) in KPSS proves the series is stationary." Failing to reject is evidence consistent with stationarity, but the KPSS Test's own null-hypothesis framing means it can also fail to detect a unit root that is genuinely present, especially with a poorly chosen lag truncation-see Limitations.
- "KPSS and ADF should always agree." They test opposite null hypotheses and frequently disagree, particularly for series that are trend-stationary but not level-stationary-this is a feature, not a bug, since the disagreement itself is informative, as shown in KPSS vs ADF vs Phillips-Perron.
- "The level-stationary and trend-stationary variants should give the same answer." No-Worked Example 2 shows a series that is firmly rejected as non-stationary under the level variant but comfortably accepted as stationary under the trend variant, because it is stable around a rising trend line rather than a flat mean.
- "More lags in the long-run variance estimate is always safer." No-adding unnecessary lag terms to the correction reduces the test's power to detect a unit root that is genuinely present, which is why automatic selection via a data-driven rule (
nlags='auto') is generally preferred over arbitrarily maximizing the lag truncation.
Interview Questions
- Explain why the KPSS Test places stationarity in the null hypothesis, and what practical advantage this gives you compared to the ADF Test.
- Derive the intuition for why the cumulative partial sum \( S_t \) of the residuals stays bounded for a stationary series but grows for a series with a unit root.
- Why can't the KPSS test statistic be compared against a standard chi-squared distribution, and what did Kwiatkowski, Phillips, Schmidt, and Shin do instead?
- What is the difference between the level-stationary and trend-stationary variants of the KPSS Test, and when would you choose one over the other?
- Explain the difference in null hypotheses between the KPSS Test and the ADF Test, and why running both together is common practice.
- Why does the KPSS Test use a non-parametric long-run variance estimate rather than adding explicit lagged difference terms the way the ADF Test does?
- Suppose the ADF Test rejects a unit root but the KPSS Test also rejects stationarity for the same series. What would you check next?
- What happens to the KPSS Test's reliability if the series has a structural break partway through, and how would that show up in the cumulative partial sums?
- Why is failing to reject the null hypothesis of the KPSS Test considered directly informative for stationarity, rather than simply "no result"?
- How would the choice of lag truncation parameter in the long-run variance estimate affect the KPSS statistic, and what happens in the limiting case where it is set to zero?
Frequently Asked Questions
- The KPSS Test checks whether a time series is stationary-either around a fixed mean or a deterministic trend-or whether it has a unit root and drifts unpredictably like a random walk. It is a standard companion to the ADF Test, run before fitting ARIMA models, running regressions on time-ordered data, or checking a precondition for a cointegration test.
- The KPSS statistic is LM = S / (n^2 * sigma_hat^2), where S is the sum of squared cumulative partial sums S_t of the regression residuals e_t = y_t - mu_hat (or the detrended residuals for the trend variant), and sigma_hat^2 is a long-run variance estimate of the e_t series that corrects for autocorrelation using a Newey-West type kernel. Large LM values indicate the partial sums are wandering rather than staying bounded.
- The KPSS statistic is always non-negative and is compared against a one-sided, right-tailed critical value. If the statistic exceeds the critical value at your chosen significance level, you reject the null hypothesis of stationarity and conclude the series likely has a unit root. If the statistic is below the critical value, you fail to reject the null, meaning the series is likely stationary.
- The null hypothesis (H0) is that the series is stationary-either level-stationary (constant mean) or trend-stationary (stable around a deterministic trend line), depending on which variant is fit. The alternative hypothesis (H1) is that the series has a unit root and is non-stationary. This framing is the reverse of the ADF Test, so failing to reject H0 here is direct evidence in favor of stationarity, not against it.
- The KPSS Test treats stationarity as the null hypothesis and a unit root as the alternative, so failing to reject H0 points toward stationarity. The ADF Test flips this: a unit root is the null hypothesis and stationarity is the alternative, so failing to reject H0 points toward a unit root. Because the two tests can disagree in the presence of near-unit-root behavior, many analysts run both and only trust a stationarity conclusion when the two agree.
- Most software, including statsmodels, can select the lag truncation parameter automatically-nlags='auto' uses a data-driven rule based on sample size, which is the recommended default. Too few lags leave residual autocorrelation uncorrected, inflating the false-rejection rate; too many lags reduce the test's power to detect a genuine unit root.
Key Takeaways
- The KPSS Test checks for stationarity by putting it in the null hypothesis-the exact mirror image of the ADF Test, which puts a unit root in the null instead.
- It works by fitting a mean or trend to the series, building the cumulative partial sum of the residuals, and testing whether that sum stays bounded (\( H_0 \): stationary) or grows (\( H_1 \): unit root).
- Because the KPSS statistic's distribution under \( H_0 \) is non-standard, it is compared against special KPSS critical values, and the test is right-tailed-large statistics, not negative ones, indicate rejection.
- Unlike the ADF Test, failing to reject \( H_0 \) is the outcome that supports the "nicer" property (stationarity)-a large p-value here is genuinely good news.
- Choosing between the level-stationary and trend-stationary variants matters enormously-the same series can be rejected under one and comfortably accepted under the other, as shown in the worked examples.
- In Python,
statsmodels.tsa.stattools.kpssruns the full test in one line, including automatic lag selection for the long-run variance correction. - Because the KPSS Test and the ADF Test can disagree, pairing them and checking for agreement gives much more reliable evidence than either test used alone.
The KPSS Test complements the ADF Test by testing stationarity from the opposite direction. A test with stationarity as its null hypothesis produces something the ADF Test cannot: direct evidence for a well-behaved series, rather than only a failure to prove otherwise. In small samples, where unit-root tests have limited power, this distinction changes what conclusions the data actually supports.
The two worked examples show both outcomes-a series that stays bounded around a fixed mean and fails to reject stationarity, and a steadily climbing series that is rejected under the level-stationary variant but accepted under the trend-stationary one. Reporting the KPSS statistic alongside the ADF Test, matching the regression variant to the series' visible behavior, and treating disagreement between the two tests as informative rather than inconclusive gives a complete picture of stationarity that neither statistic alone provides.