dyncusum
CUSUM Tests for Structural Change in Dynamic Models
A Python library implementing the CUSUM tests for structural change as described in:
Krämer, W., Ploberger, W., & Alt, R. (1988). "Testing for Structural Change in Dynamic Models." Econometrica, Vol. 56, No. 6, pp. 1355-1369.
Overview
This library provides a complete implementation of the CUSUM (Cumulative Sum) test for detecting structural change in linear regression models with lagged dependent variables. The implementation follows the original paper exactly, including:
- Dynamic CUSUM Test: The straightforward CUSUM test applied to dynamic models
- Dufour Test: Modified procedure from Dufour (1982) that first eliminates dynamics
- Critical Values: Both tabulated values from BDE (1975) and Monte Carlo simulation
- Power Analysis: Tools to analyze test power under various structural change scenarios
- Visualization: Publication-quality plots for CUSUM processes
- Tables: Formatted output for academic publications
Installation
pip install dyncusum
Or install from source:
git clone https://github.com/merwanroudane/cusum.git
cd cusum
pip install -e .
Quick Start
Basic Usage
import numpy as np
from dyncusum import dynamic_cusum_test, plot_cusum, print_test_summary
# Generate sample data
np.random.seed(42)
T = 100
y = np.zeros(T)
u = np.random.normal(0, 1, T)
# AR(1) process: y_t = 0.5 * y_{t-1} + u_t
for t in range(1, T):
y[t] = 0.5 * y[t-1] + u[t]
# Prepare data for test
y_current = y[1:]
y_lagged = y[:-1]
X = np.ones((T-1, 1)) # Constant term
# Perform the Dynamic CUSUM test
result = dynamic_cusum_test(y_current, X, y_lagged, significance_level=0.05)
# Print summary
print_test_summary(result)
# Plot the CUSUM process
fig = plot_cusum(result, save_path='cusum_plot.png')
Comparing Tests
from dyncusum import dynamic_cusum_test, dufour_test, plot_comparison
# Run both tests
result_dc = dynamic_cusum_test(y_current, X, y_lagged)
result_duf = dufour_test(y_current, X, y_lagged)
# Compare results
fig = plot_comparison(result_dc, result_duf, save_path='comparison.png')
Theoretical Background
The Model
The library considers the dynamic linear regression model:
$$y_t = \gamma y_{t-1} + \beta_1 x_{t1} + \cdots + \beta_K x_{tK} + u_t \quad (t = 1, \ldots, T)$$
where:
- $y_t$ is the dependent variable
- $\gamma$ is the coefficient of the lagged dependent variable ($|\gamma| < 1$)
- $x_{t1}, \ldots, x_{tK}$ are exogenous regressors
- $u_t$ are iid$(0, \sigma^2)$ disturbances
The CUSUM Test
The test statistic is based on recursive residuals:
$$w_r = (y_r - z'_r \hat{\delta}^{(r-1)}) / f_r$$
where $f_r = (1 + z'_r(Z^{(r-1)'}Z^{(r-1)})^{-1}z_r)^{1/2}$
The CUSUM process is:
$$W^{(r)} = \frac{1}{\hat{\sigma}} \sum_{t=K+2}^{r} w_t$$
And the test statistic is:
$$S = \max_{K+1 < r \leq T} \left| \frac{W^{(r)}}{\sqrt{T-K-1}} \right| / \left(1 + 2\frac{r-K-1}{T-K-1}\right)$$
Key Theorems
Theorem 1: Both the Dynamic CUSUM test and the Dufour test retain their asymptotic nominal significance levels in dynamic models.
Theorem 2: If the structural change $g(z)$ is orthogonal to the mean regressor $d$ for almost all $z$, the limiting rejection probability equals the nominal significance level (no power).
Critical Values
Critical values are based on Brownian motion theory (BDE, 1975):
| Significance Level | Critical Value |
|---|---|
| 0.01 | 1.143 |
| 0.025 | 1.035 |
| 0.05 | 0.948 |
| 0.10 | 0.850 |
API Reference
Core Functions
dynamic_cusum_test(y, X, y_lagged=None, significance_level=0.05, sigma_method='harvey', n_simulations=10000)
Perform the Dynamic CUSUM test for structural change.
Parameters:
y: Dependent variable vectorX: Exogenous regressors matrixy_lagged: Lagged dependent variable (optional)significance_level: Significance level (default: 0.05)sigma_method: 'harvey' or 'ols' (default: 'harvey')n_simulations: Monte Carlo simulations for p-value
Returns: CUSUMResult object
dufour_test(y, X, y_lagged, significance_level=0.05, sigma_method='harvey', n_simulations=10000)
Perform the Dufour (1982) modified CUSUM test.
Power Analysis
monte_carlo_power(gamma, psi, z_star, b, T=120, n_simulations=1000, ...)
Compute power via Monte Carlo simulation.
replicate_table_1(T=120, n_simulations=1000, ...)
Replicate Table I from the original paper.
Visualization
plot_cusum(result, title=None, figsize=(10, 6), ...)
Plot the CUSUM process with critical boundaries.
create_summary_figure(result, figsize=(14, 10), ...)
Create a comprehensive summary figure with multiple panels.
Examples
Detecting Structural Change
import numpy as np
from dyncusum import dynamic_cusum_test, generate_dynamic_data
# Generate data with a structural break at t = 60
T = 100
gamma = 0.5
beta = np.array([2, 10])
# Break: coefficients change by 20% after observation 60
structural_break = {
'z_star': 0.6, # Break at 60% of sample
'delta_delta': np.array([0, 0.4, 2.0]) # Change in [γ, β_1, β_2]
}
y, X, y_lagged = generate_dynamic_data(T, gamma, beta,
structural_break=structural_break,
seed=42)
# Test for structural change
result = dynamic_cusum_test(y, X, y_lagged)
print(f"Test Statistic: {result.statistic:.4f}")
print(f"P-value: {result.p_value:.4f}")
print(f"Reject H0: {result.reject_null}")
Power Analysis
from dyncusum import analyze_power_vs_angle, plot_power_curve
# Analyze how power varies with the angle ψ
results = analyze_power_vs_angle(gamma=0.0, z_star=0.5, b=12, T=120)
# Plot power curve
fig = plot_power_curve(
np.array(results['angles']),
np.array(results['powers']),
save_path='power_curve.png'
)
Replicating Paper Results
The library can replicate the Monte Carlo results from Table I:
from dyncusum import replicate_table_1, format_power_table
# Note: This takes several hours with default settings
results = replicate_table_1(
T=120,
n_simulations=100, # Use 1000 for publication
gamma_values=[-0.5, 0, 0.5],
psi_values=[0, 30, 60, 90],
z_star_values=[0.3, 0.5, 0.7],
b_values=[3, 6, 12]
)
# Format as table
print(format_power_table(results))
Citation
If you use this library in your research, please cite both the original paper and this implementation:
@article{kramer1988testing,
title={Testing for Structural Change in Dynamic Models},
author={Kr{\"a}mer, Walter and Ploberger, Werner and Alt, Raimund},
journal={Econometrica},
volume={56},
number={6},
pages={1355--1369},
year={1988}
}
@software{roudane2024dyncusum,
author = {Roudane, Merwan},
title = {dyncusum: CUSUM Tests for Structural Change in Dynamic Models},
year = {2024},
url = {https://github.com/merwanroudane/cusum}
}
References
- Brown, R. L., Durbin, J., & Evans, J. M. (1975). Techniques for Testing the Constancy of Regression Relationships over Time. Journal of the Royal Statistical Society, Series B, 37, 149-163.
- Dufour, J. M. (1982). Recursive Stability Analysis of Linear Regression Relationships. Journal of Econometrics, 19, 31-76.
- Harvey, A. (1975). Comment on the Paper by Brown, Durbin and Evans. Journal of the Royal Statistical Society, B, 37, 179-180.
License
MIT License - see LICENSE file for details.
Author
Dr. Merwan Roudane
- Email: merwanroudane920@gmail.com
- GitHub: https://github.com/merwanroudane/cusum
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Metadata
Release files for dyncusum 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| dyncusum-1.0.0.tar.gz | 32.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dyncusum-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.4 kB
Release files / dyncusum-1.0.0.tar.gz
| Download URL | dyncusum-1.0.0.tar.gz |
|---|---|
| Size | 32.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
84feb0c0fb540f6ec17fc25318e299039b9bfb2d11c13a468b6b2ed992d42d32
|
|
BLAKE2b-256 checksum How to use checksums |
2a33f64295a35e7995d995d4f44502c2ca5b1e00b930dd3f9f160d73bd4e9e6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / dyncusum-1.0.0-py3-none-any.whl
| Download URL | dyncusum-1.0.0-py3-none-any.whl |
|---|---|
| Size | 30.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4a25555823c62e35ed6a2387da052fbf575cb5303ed9e254e4c4ec62f8878ed9
|
|
BLAKE2b-256 checksum How to use checksums |
f767101bfce58d9a3d97524c357445623fbc78060a750eaba97504a829b2c914
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Security for dyncusum 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.