Skip to content

Commit 9f59565

Browse files
Morten Taborclaude
andcommitted
Add GETS indicator saturation (SIS/IIS/MIS/TIS) with example notebook
Implements the Autometrics/GETS algorithm for detecting structural breaks via general-to-specific model selection with indicator saturation. New features: - gets_search(): bounded iterative GETS reduction with multi-path search - isat(): indicator saturation with SIS (level shifts), IIS (outliers), MIS (coefficient shifts), TIS (broken trends), and user indicators - Split-half block procedure for large indicator sets - Dual representation: shifts <-> regime levels with SE propagation via the delta method - 3 visualization functions: plot_sis_coefficients, plot_mis_coefficients, plot_regime_levels - .isat() convenience methods on OLS, AR, ADL models - Example notebook 05 demonstrating all features including comparison with Bai-Perron and Markov switching 166 new tests (1069 total), lint clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 71e658f commit 9f59565

24 files changed

+5233
-9
lines changed

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- **GETS indicator saturation** (Autometrics algorithm, Doornik 2009; Castle, Doornik & Hendry 2012)
13+
- `gets_search()`: General-to-specific model selection with bounded iterative search, multi-path exploration (up to 5 paths), encompassing tests, and diagnostic checks
14+
- `isat()`: Indicator saturation entry point supporting four indicator types:
15+
- **SIS** (Step Indicator Saturation) — detect level shifts in the intercept
16+
- **IIS** (Impulse Indicator Saturation) — detect one-time outliers
17+
- **MIS** (Multiplicative Indicator Saturation) — detect coefficient shifts (interact steps with regressors)
18+
- **TIS** (Trend Indicator Saturation) — detect broken linear trends
19+
- User-supplied custom indicators via `user_indicators` parameter
20+
- Split-half block procedure for large indicator sets exceeding n/2 candidates
21+
- **Dual representation**: shifts (initial level + step changes) ↔ regime levels (cumulated per-parameter schedules) with standard error propagation via the delta method
22+
- `SaturationResults` dataclass with `.summary()`, `.break_dates`, `.n_regimes`, `.retained_indicators`, `.shifts`, `.regime_levels`
23+
- `GETSResults` and `TerminalModel` dataclasses for detailed GETS search inspection
24+
- `ShiftsRepresentation`, `RegimeLevelsRepresentation`, `ParameterRegime` dataclasses
25+
- `shifts_to_levels()` / `levels_to_shifts()` conversion functions
26+
- Indicator generators: `step_indicators()`, `impulse_indicators()`, `multiplicative_indicators()`, `trend_indicators()`
27+
- **GETS visualization functions**
28+
- `plot_sis_coefficients()`: Intercept regime levels as step function with confidence bands
29+
- `plot_mis_coefficients()`: Per-parameter coefficient regime levels
30+
- `plot_regime_levels()`: Combined SIS + MIS regime levels (multi-panel)
31+
- `.plot_sis()`, `.plot_mis()`, `.plot_regime_levels()` convenience methods on `SaturationResults`
32+
- **`.isat()` convenience methods** on OLS, AR, and ADL models for one-step indicator saturation
33+
- **Example notebook** `05_gets_indicator_saturation.ipynb` demonstrating all features including AR(1) with dual structural breaks, method comparison (GETS vs Bai-Perron vs Markov switching), and end-to-end workflow
34+
- 166 new tests (1069 total)
35+
1036
## [0.3.2] - 2026-02-20
1137

1238
### Fixed

README.md

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ A Python package for structural break detection and estimation in time-series ec
1313
- **Chow Test**: Test for structural breaks at known break points with standard and predictive variants
1414
- **CUSUM Tests**: CUSUM and CUSUM-SQ tests for parameter and variance instability (Brown, Durbin, Evans, 1975)
1515
- **Andrews-Ploberger Test**: SupF, ExpF, and AveF tests for a structural break at unknown date (Andrews, 1993; Andrews & Ploberger, 1994)
16+
- **GETS Indicator Saturation**: Autometrics algorithm (Doornik 2009) with SIS (level shifts), IIS (outliers), MIS (coefficient shifts), TIS (broken trends), dual representation (shifts ↔ regime levels), and split-half block procedure
1617
- **Markov Regime-Switching**: Markov switching regression, AR, and ADL models with regime number selection and restricted transitions
1718
- **Time-Series Models**: AR, ADL, OLS with HAC standard errors and known break support
1819
- **ADL Models**: Autoregressive Distributed Lag models with flexible lag specification and distributed lag diagnostics
1920
- **Rolling & Recursive Estimation**: Track parameter evolution with fixed or expanding windows
20-
- **Model Selection**: BIC, LWZ criteria for selecting the number of breaks; AIC/BIC lag selection for ADL
21+
- **Model Selection**: GETS general-to-specific search; BIC, LWZ criteria for selecting the number of breaks; AIC/BIC lag selection for ADL
2122
- **Visualization**: Plot time series with break lines, regime means, rolling coefficients, and confidence intervals
2223
- **statsmodels Integration**: Familiar `Model.fit() -> Results` API pattern
2324

@@ -250,6 +251,47 @@ restricted_results = restricted.fit()
250251
results.plot_transition_matrix()
251252
```
252253

254+
### Indicator Saturation (GETS)
255+
256+
Detect structural breaks automatically using the Autometrics algorithm with indicator saturation:
257+
258+
```python
259+
import numpy as np
260+
import regimes as rg
261+
262+
# Simulate data with two level shifts
263+
rng = np.random.default_rng(42)
264+
y = np.concatenate([
265+
rng.normal(0, 1, 100),
266+
rng.normal(3, 1, 100),
267+
rng.normal(1, 1, 100),
268+
])
269+
270+
# Step indicator saturation: detect level shifts
271+
result = rg.isat(y, sis=True, alpha=0.01)
272+
print(result.summary())
273+
print(f"Break dates: {result.break_dates}")
274+
result.plot_sis()
275+
276+
# Inspect regime levels
277+
for param, regimes in result.regime_levels.param_regimes.items():
278+
for r in regimes:
279+
print(f" {param} [{r.start}-{r.end}]: level={r.level:.3f}")
280+
```
281+
282+
Use `.isat()` convenience methods on any model:
283+
284+
```python
285+
# AR(1) with SIS + MIS: detect intercept and coefficient shifts
286+
ar_model = rg.AR(y, lags=1)
287+
result = ar_model.isat(sis=True, mis=True, alpha=0.01)
288+
result.plot_regime_levels()
289+
290+
# ADL with indicator saturation
291+
adl_model = rg.ADL(y, x, lags=1, exog_lags=0)
292+
result = adl_model.isat(sis=True, alpha=0.01)
293+
```
294+
253295
### OLS with HAC Standard Errors
254296

255297
```python
@@ -460,6 +502,7 @@ fig, axes = rg.plot_residual_acf(results, nlags=15)
460502
| `RestrictedMarkovAR` | Markov AR with restricted transition probabilities |
461503

462504
All models (`OLS`, `AR`, `ADL`) have:
505+
- `.isat(sis, iis, mis, tis, alpha)` method for indicator saturation (GETS)
463506
- `.bai_perron()` method for integrated break detection
464507
- `.chow_test(break_points)` method for testing breaks at known dates
465508
- `.cusum_test()` method for CUSUM parameter instability test
@@ -501,6 +544,18 @@ All models (`OLS`, `AR`, `ADL`) have:
501544
| `SequentialRestrictionTest` | GETS-style sequential restriction of transition probabilities |
502545
| `RegimeNumberSelection` | Select number of regimes by IC (AIC/BIC/HQIC) or sequential LRT |
503546

547+
### GETS / Indicator Saturation
548+
549+
| Class / Function | Description |
550+
|------------------|-------------|
551+
| `isat` | Main entry point for indicator saturation (SIS, IIS, MIS, TIS) |
552+
| `gets_search` | Low-level general-to-specific model selection algorithm |
553+
| `SaturationResults` | Results from `isat()` with dual representation, break dates, regime levels |
554+
| `GETSResults` | Detailed GETS search results with terminal models |
555+
| `ShiftsRepresentation` | Shifts form: initial level + step changes |
556+
| `RegimeLevelsRepresentation` | Regime levels form: per-parameter level schedules |
557+
| `shifts_to_levels` / `levels_to_shifts` | Convert between representations |
558+
504559
**Key methods:**
505560
- `BaiPerronTest.from_model(model)` - Create test from OLS or AR model
506561
- `BaiPerronResults.to_ols()` - Convert results to OLS with detected breaks
@@ -532,6 +587,9 @@ All models (`OLS`, `AR`, `ADL`) have:
532587
| `plot_transition_matrix` | Heatmap of transition probability matrix |
533588
| `plot_parameter_time_series` | Regime-dependent parameter as step function over time |
534589
| `plot_ic` | Information criteria vs number of regimes |
590+
| `plot_sis_coefficients` | Intercept regime levels as step function with confidence bands |
591+
| `plot_mis_coefficients` | Per-parameter coefficient regime levels |
592+
| `plot_regime_levels` | Combined SIS + MIS regime levels (multi-panel) |
535593

536594
### Style Utilities
537595

@@ -557,7 +615,7 @@ All regression models support multiple covariance estimators:
557615

558616
## Testing
559617

560-
The package includes a comprehensive test suite with 903 tests:
618+
The package includes a comprehensive test suite with 1069 tests:
561619

562620
```bash
563621
# Run all tests
@@ -592,6 +650,8 @@ regimes uses [Hypothesis](https://hypothesis.readthedocs.io/) for property-based
592650
- Hamilton, J. D. (1989). A new approach to the economic analysis of nonstationary time series and the business cycle. *Econometrica*, 57(2), 357-384.
593651
- Chib, S. (1998). Estimation and comparison of multiple change-point models. *Journal of Econometrics*, 86(2), 221-241.
594652
- Andrews, D. W. K. (2001). Testing when a parameter is on the boundary of the maintained hypothesis. *Econometrica*, 69(3), 683-734.
653+
- Doornik, J. A. (2009). Autometrics. In J. L. Castle & N. Shephard (Eds.), *The Methodology and Practice of Econometrics*. Oxford University Press.
654+
- Castle, J. L., Doornik, J. A., & Hendry, D. F. (2012). Model selection when there are multiple breaks. *Journal of Econometrics*, 169(2), 239-246.
595655

596656
## License
597657

ROADMAP.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Current Status
44

5-
**Phase 3: v0.3.0 - Structural Break Tests & Markov-Switching** Complete[github.com/knightianuncertainty/regimes](https://github.com/knightianuncertainty/regimes)
5+
**Phase 4: v0.4.0 - Model Selection & Indicator Saturation** In progress[github.com/knightianuncertainty/regimes](https://github.com/knightianuncertainty/regimes)
66

77
## Completed Phases
88

@@ -76,10 +76,23 @@ Core package structure, OLS/AR models, Bai-Perron test, basic visualization, CI/
7676

7777
### Phase 4: v0.4.0 - Model Selection & Indicator Saturation
7878

79-
- [ ] Autometrics-inspired general-to-specific model-selection algorithm
80-
- [ ] Step-indicator saturation (SIS)
81-
- [ ] Multiplicative step-indicator saturation
82-
- [ ] Target: 88%+ test coverage
79+
- [x] Autometrics-inspired general-to-specific model-selection algorithm (`gets_search()`)
80+
- [x] Bounded iterative search with multi-path exploration (up to 5 paths)
81+
- [x] Encompassing tests and diagnostic checks
82+
- [x] `GETSResults` and `TerminalModel` dataclasses
83+
- [x] Indicator saturation (`isat()`) with split-half block procedure
84+
- [x] Step indicator saturation (SIS) — level shifts in the intercept
85+
- [x] Impulse indicator saturation (IIS) — one-time outliers
86+
- [x] Multiplicative indicator saturation (MIS) — coefficient shifts
87+
- [x] Trend indicator saturation (TIS) — broken linear trends
88+
- [x] User-supplied custom indicators
89+
- [x] Dual representation: shifts ↔ regime levels with SE propagation via delta method
90+
- [x] `ShiftsRepresentation`, `RegimeLevelsRepresentation`, `ParameterRegime` dataclasses
91+
- [x] `shifts_to_levels()` / `levels_to_shifts()` conversion functions
92+
- [x] GETS visualization: `plot_sis_coefficients()`, `plot_mis_coefficients()`, `plot_regime_levels()`
93+
- [x] `.isat()` convenience methods on OLS, AR, and ADL models
94+
- [x] Example notebook: `05_gets_indicator_saturation.ipynb`
95+
- [x] 166 new tests (1069 total, 86% coverage)
8396

8497
### Phase 5: v0.5.0 - Documentation & Release
8598

@@ -119,7 +132,7 @@ These features are deferred and may be added in future versions based on need:
119132
| 0.3.0 | Complete | Structural break tests (Chow, CUSUM, Andrews-Ploberger), Markov-switching, 880 tests (86% coverage), 4 example notebooks |
120133
| 0.3.1 | Complete | Fix smoothed probability leakage in restricted Markov models, 880 tests |
121134
| 0.3.2 | Complete | Fix Bai-Perron partial structural change & multicollinearity (PR #4), R cross-validation, 903 tests |
122-
| 0.4.0 | Planned | Autometrics-inspired model selection, step-indicator saturation |
135+
| 0.4.0 | In progress | GETS indicator saturation (SIS/IIS/MIS/TIS), Autometrics model selection, dual representation, 1069 tests |
123136
| 0.5.0 | Planned | Real data examples, example notebooks, Sphinx docs, PyPI stable release |
124137
| 0.6.0 | Planned | Advanced models: VAR, cointegration, panel data, bootstrap |
125138
| 0.7.0+ | Future | End-to-end forecasting workflow with structural change |

0 commit comments

Comments
 (0)