Skip to main content

Bootstrap tests for autocorrelation in regression models

Project description

boot_dw: Bootstrap Tests for Autocorrelation

Python 3.8+ License: MIT

A Python implementation of bootstrap-based tests for autocorrelation in regression models, based on:

Jeong, J. and Chung, S. (2001). "Bootstrap tests for autocorrelation". Computational Statistics & Data Analysis 38: 49-69.

Overview

The classical Durbin-Watson (DW) test for autocorrelation suffers from an important limitation: the test is inconclusive when the test statistic falls into the "indeterminate range" (dL, dU). This package implements bootstrap alternatives that eliminate this problem and provide superior finite-sample properties.

Implemented Tests

  1. Classical DW Test - Traditional Durbin-Watson test (with indeterminate range)
  2. BDW Test - Bootstrapped Durbin-Watson test (eliminates indeterminate range)
  3. B-ρ Test - Bootstrapped AR(1) coefficient test (percentile method)
  4. BCa-ρ Test - Bias-corrected accelerated ρ test (recommended, most powerful)

Installation

pip install boot_dw

Or install from source:

git clone https://github.com/merwanroudane/bootdw.git
cd bootdw
pip install -e .

Quick Start

import numpy as np
from boot_dw import autocorrelation_test

# Generate sample data
np.random.seed(42)
n = 50
X = np.random.randn(n, 2)
y = X @ np.array([2, -1]) + np.random.randn(n)

# Run BCa-ρ test (recommended)
result = autocorrelation_test(y, X, method='bca_rho', random_state=42)
print(result)

Output:

======================================================================
  Bias-corrected accelerated ρ (BCa-ρ) test
======================================================================
H₀: ρ = 0  vs  H₁: ρ > 0

Test statistic:  -0.045123
P-value:         0.685000

Conclusion: Fail to reject H₀

Estimated ρ̂:    -0.045123
DW statistic:    2.087456
95% BCa CI:      (-0.312456, 0.198234)

Sample size:     n = 50, k = 2
Bootstrap reps:  B = 200
======================================================================

Features

Publication-Ready Output

The package provides publication-quality formatted output:

from boot_dw import bca_rho_test

result = bca_rho_test(y, X, n_bootstrap=200, random_state=42)

# Detailed summary
print(result.summary())

# LaTeX table for multiple tests
from boot_dw.utils import format_latex_table

results = {
    'Classical DW': dw_test(y, X),
    'BDW': bdw_test(y, X, random_state=42),
    'BCa-ρ': bca_rho_test(y, X, random_state=42)
}

print(format_latex_table(results))

Monte Carlo Simulations

Replicate the simulations from Jeong & Chung (2001):

import numpy as np
from boot_dw import autocorrelation_test

# Simulation parameters
n = 50
k = 3
rho_values = np.arange(0, 1.0, 0.1)
n_simulations = 1000
n_bootstrap = 200

rejection_rates = []

for rho in rho_values:
    rejections = 0
    
    for _ in range(n_simulations):
        # Generate data with AR(1) errors
        X = np.random.randn(n, k)
        u = np.zeros(n)
        u[0] = np.random.randn()
        
        for t in range(1, n):
            u[t] = rho * u[t-1] + np.random.randn()
        
        y = X @ np.ones(k) + u
        
        # Test for autocorrelation
        result = autocorrelation_test(y, X, method='bca_rho', 
                                     n_bootstrap=n_bootstrap, alpha=0.05)
        
        if result.pvalue < 0.05:
            rejections += 1
    
    rejection_rates.append(rejections / n_simulations)

print(f"Empirical size (ρ=0): {rejection_rates[0]:.3f}")
print(f"Power at ρ=0.5: {rejection_rates[5]:.3f}")

API Reference

Main Test Function

autocorrelation_test(y, X, method='bca_rho', alternative='greater', 
                    n_bootstrap=200, alpha=0.05, add_constant=True, 
                    random_state=None)

Parameters:

  • y: Dependent variable (n,)
  • X: Independent variables (n, k)
  • method: Test method - 'dw', 'bdw', 'b_rho', or 'bca_rho' (recommended)
  • alternative: 'greater' (default), 'less', or 'two-sided'
  • n_bootstrap: Number of bootstrap replications (default: 200)
  • alpha: Significance level (default: 0.05)
  • add_constant: Add intercept to regression (default: True)
  • random_state: Random seed for reproducibility

Returns: TestResult object with attributes:

  • statistic: Test statistic value
  • pvalue: P-value
  • method: Test name
  • alternative: Alternative hypothesis
  • additional_info: Dict with details (CI, critical values, etc.)

Individual Test Functions

from boot_dw import dw_test, bdw_test, b_rho_test, bca_rho_test

# Classical Durbin-Watson test
result_dw = dw_test(y, X)

# Bootstrapped Durbin-Watson test
result_bdw = bdw_test(y, X, n_bootstrap=200, random_state=42)

# Bootstrapped ρ test (percentile method)
result_brho = b_rho_test(y, X, n_bootstrap=200, random_state=42)

# BCa-ρ test (most powerful)
result_bca = bca_rho_test(y, X, n_bootstrap=200, random_state=42)

Core Functions

from boot_dw.core import durbin_watson, ols_regression, estimate_rho

# Calculate DW statistic
dw_stat = durbin_watson(residuals)

# OLS regression
beta, residuals, fitted = ols_regression(y, X, add_constant=True)

# Estimate AR(1) coefficient
rho_hat = estimate_rho(residuals)

Bootstrap Functions

from boot_dw.bootstrap import (
    recursive_bootstrap_dw,
    recursive_bootstrap_rho,
    bca_confidence_interval
)

# Bootstrap DW distribution
dw_bootstrap = recursive_bootstrap_dw(y, X, residuals, rho_est, n_bootstrap=200)

# Bootstrap ρ distribution
rho_bootstrap = recursive_bootstrap_rho(y, X, residuals, rho_est, n_bootstrap=200)

# BCa confidence interval
lower, upper, z0, a0 = bca_confidence_interval(rho_bootstrap, rho_obs, y, X)

Theoretical Background

The Durbin-Watson Statistic

For regression model y = Xβ + u with AR(1) errors:

$$u_t = \rho u_{t-1} + e_t, \quad |ρ| < 1$$

The Durbin-Watson statistic is:

$$d = \frac{\sum_{t=2}^T (e_t - e_{t-1})^2}{\sum_{t=1}^T e_t^2} \approx 2(1 - \hat{\rho})$$

where:

  • d ≈ 2: No autocorrelation (ρ ≈ 0)
  • d < 2: Positive autocorrelation (ρ > 0)
  • d > 2: Negative autocorrelation (ρ < 0)

Bootstrap Procedures

BDW Test (Bootstrapped Durbin-Watson)

  1. Estimate β̂, ρ̂ from original data
  2. Resample innovations ê with replacement
  3. Construct u* = e* (imposing H₀: ρ = 0)
  4. Create bootstrap data y* = Xβ̂ + u*
  5. Compute DW* and build empirical distribution F*_d
  6. Compare observed DW to F*_d for p-value

B-ρ Test (Bootstrapped ρ)

  1. Estimate β̂, ρ̂ and compute innovations
  2. Resample innovations ê with replacement
  3. Recursively construct u*t = ρ̂u*{t-1} + e*_t
  4. Estimate ρ* from bootstrap errors
  5. Build empirical distribution F*_ρ
  6. Test if 0 is in the confidence interval

BCa-ρ Test (Bias-Corrected Accelerated ρ)

  1. Perform B-ρ bootstrap
  2. Calculate bias correction: z₀ = Φ⁻¹(Ĝ(ρ̂))
  3. Calculate acceleration: a₀ from jackknife influence function
  4. Compute adjusted confidence interval
  5. Test if 0 is outside BCa interval

Performance (from Jeong & Chung 2001)

Monte Carlo results show:

  1. Classical DW test:

    • Has indeterminate range
    • Poor size and power in small samples
  2. BDW test:

    • Eliminates indeterminate range
    • Better power than classical DW and (a+bdU) approximation
  3. B-ρ test:

    • More powerful than BDW
    • May have size distortions in small samples
  4. BCa-ρ test (BEST):

    • Most accurate empirical size
    • Highest power, especially in small samples (n=10-50)
    • Robust across different sample sizes
    • Strongly recommended for practical applications

Examples

Example 1: Testing with Simulated AR(1) Data

import numpy as np
from boot_dw import autocorrelation_test

# Set parameters
np.random.seed(123)
n = 100
k = 3
rho_true = 0.6

# Generate regressors
X = np.random.randn(n, k)
beta_true = np.array([2.0, -1.5, 0.8])

# Generate AR(1) errors
u = np.zeros(n)
u[0] = np.random.randn()
for t in range(1, n):
    u[t] = rho_true * u[t-1] + np.random.randn()

# Generate dependent variable
y = X @ beta_true + u

# Test for autocorrelation
result = autocorrelation_test(y, X, method='bca_rho', random_state=123)
print(result.summary())

Example 2: Comparing All Tests

import numpy as np
from boot_dw import dw_test, bdw_test, b_rho_test, bca_rho_test
from boot_dw.utils import format_latex_table

# Generate data
np.random.seed(42)
n = 50
X = np.random.randn(n, 2)
y = X @ np.array([2, -1]) + np.random.randn(n) * 0.5

# Run all tests
results = {
    'Classical DW': dw_test(y, X),
    'BDW': bdw_test(y, X, n_bootstrap=200, random_state=42),
    'B-ρ (Percentile)': b_rho_test(y, X, n_bootstrap=200, random_state=42),
    'BCa-ρ': bca_rho_test(y, X, n_bootstrap=200, random_state=42)
}

# Print comparison
for name, result in results.items():
    print(f"\n{name}:")
    if result.pvalue is not None:
        print(f"  Statistic: {result.statistic:.4f}")
        print(f"  P-value: {result.pvalue:.4f}")
    else:
        print(f"  DW statistic: {result.statistic:.4f}")
        print(f"  P-value: Not available (use DW tables)")

# Generate LaTeX table
print("\nLaTeX Table:")
print(format_latex_table(results))

Example 3: Power Simulation Study

import numpy as np
import matplotlib.pyplot as plt
from boot_dw import autocorrelation_test

def simulate_power(n=50, k=3, rho_values=None, n_sim=100, n_bootstrap=200):
    """Simulate power function for BCa-ρ test."""
    if rho_values is None:
        rho_values = np.arange(0, 1.0, 0.1)
    
    power = np.zeros(len(rho_values))
    
    for i, rho in enumerate(rho_values):
        rejections = 0
        
        for _ in range(n_sim):
            # Generate data
            X = np.random.randn(n, k)
            u = np.zeros(n)
            u[0] = np.random.randn() / np.sqrt(1 - rho**2)
            
            for t in range(1, n):
                u[t] = rho * u[t-1] + np.random.randn()
            
            y = X @ np.ones(k) + u
            
            # Test
            result = autocorrelation_test(y, X, method='bca_rho', 
                                        n_bootstrap=n_bootstrap, alpha=0.05)
            
            if result.pvalue < 0.05:
                rejections += 1
        
        power[i] = rejections / n_sim
        print(f"ρ = {rho:.1f}: power = {power[i]:.3f}")
    
    return rho_values, power

# Run simulation
rho_vals, power_vals = simulate_power(n=50, k=3, n_sim=100, n_bootstrap=200)

# Plot
plt.figure(figsize=(10, 6))
plt.plot(rho_vals, power_vals, 'o-', linewidth=2, markersize=8)
plt.axhline(y=0.05, color='r', linestyle='--', label='Nominal size (5%)')
plt.xlabel('True ρ', fontsize=12)
plt.ylabel('Rejection Rate', fontsize=12)
plt.title('Power Function of BCa-ρ Test (n=50, k=3)', fontsize=14)
plt.grid(True, alpha=0.3)
plt.legend(fontsize=10)
plt.tight_layout()
plt.savefig('power_function.png', dpi=300)
plt.show()

Citation

If you use this package in your research, please cite both the package and the original paper:

Package:

@software{boot_dw2024,
  author = {Roudane, Merwan},
  title = {boot\_dw: Bootstrap Tests for Autocorrelation},
  year = {2024},
  url = {https://github.com/merwanroudane/bootdw},
  version = {0.0.1}
}

Original paper:

@article{jeong2001bootstrap,
  title={Bootstrap tests for autocorrelation},
  author={Jeong, Jinook and Chung, Seoung},
  journal={Computational Statistics \& Data Analysis},
  volume={38},
  number={1},
  pages={49--69},
  year={2001},
  publisher={Elsevier}
}

References

  1. Jeong, J. and Chung, S. (2001). "Bootstrap tests for autocorrelation". Computational Statistics & Data Analysis 38: 49-69.

  2. Durbin, J. and Watson, G.S. (1950). "Testing for Serial Correlation in Least Squares Regression I". Biometrika 37: 409-428.

  3. Durbin, J. and Watson, G.S. (1951). "Testing for Serial Correlation in Least Squares Regression II". Biometrika 38: 159-178.

  4. Efron, B. (1987). "Better Bootstrap Confidence Intervals". Journal of the American Statistical Association 82: 171-200.

License

MIT License - see LICENSE file for details.

Author

Dr. Merwan Roudane
Email: merwanroudane920@gmail.com
GitHub: https://github.com/merwanroudane

Contributing

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

Acknowledgments

This implementation is based on the seminal work of Jeong & Chung (2001). Special thanks to the authors for their rigorous theoretical and empirical analysis of bootstrap methods for autocorrelation testing.

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

boot_dw-0.0.1.tar.gz (33.1 kB view details)

Uploaded Source

Built Distribution

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

boot_dw-0.0.1-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

Details for the file boot_dw-0.0.1.tar.gz.

File metadata

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

File hashes

Hashes for boot_dw-0.0.1.tar.gz
Algorithm Hash digest
SHA256 5bec36b79b1bc0bc287b580ce6940e4039c896e5d93e55a9abda408a33825c02
MD5 ccd7d230a45c523ca5e091af9e2dc932
BLAKE2b-256 a08a79ae84a788795f4749e081bb9b257b3b2f5d43fa137bf224bf34603fbbfc

See more details on using hashes here.

File details

Details for the file boot_dw-0.0.1-py3-none-any.whl.

File metadata

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

File hashes

Hashes for boot_dw-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4438ad5ea1e9d88d84d2dd223710c3eb3ab17794277ec73794aa23e5df2f947c
MD5 fffa936bcd0e366dd752b634d3e6703f
BLAKE2b-256 6fe955f140028511723d9fe5a45eae9ae5754e618d42c7146a209d416a998dcf

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