Skip to main content

CUSUM Tests for Structural Change in Dynamic Models

Project description

dyncusum

Python 3.8+ License: MIT

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:

  1. Dynamic CUSUM Test: The straightforward CUSUM test applied to dynamic models
  2. Dufour Test: Modified procedure from Dufour (1982) that first eliminates dynamics
  3. Critical Values: Both tabulated values from BDE (1975) and Monte Carlo simulation
  4. Power Analysis: Tools to analyze test power under various structural change scenarios
  5. Visualization: Publication-quality plots for CUSUM processes
  6. 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 vector
  • X: Exogenous regressors matrix
  • y_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

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dyncusum-1.0.0.tar.gz (32.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dyncusum-1.0.0-py3-none-any.whl (30.9 kB view details)

Uploaded Python 3

File details

Details for the file dyncusum-1.0.0.tar.gz.

File metadata

  • Download URL: dyncusum-1.0.0.tar.gz
  • Upload date:
  • Size: 32.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for dyncusum-1.0.0.tar.gz
Algorithm Hash digest
SHA256 84feb0c0fb540f6ec17fc25318e299039b9bfb2d11c13a468b6b2ed992d42d32
MD5 c3a9b5d80cc13d5b87983c5680d23d1c
BLAKE2b-256 2a33f64295a35e7995d995d4f44502c2ca5b1e00b930dd3f9f160d73bd4e9e6b

See more details on using hashes here.

File details

Details for the file dyncusum-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: dyncusum-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 30.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for dyncusum-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4a25555823c62e35ed6a2387da052fbf575cb5303ed9e254e4c4ec62f8878ed9
MD5 4d6389c611229ee6c921d4e3e568e359
BLAKE2b-256 f767101bfce58d9a3d97524c357445623fbc78060a750eaba97504a829b2c914

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page