xtbreak Quickstart
For installation and a first example, see the README. This guide extends the README with deeper usage patterns.
Beyond the Basics
After running your first test() → estimate() cycle (shown in the README),
the next step is to explore the full workflow:
Select how many breaks the data supports
Inspect regime-specific statistics
Export results programmatically
Break-Count Selection
When you don’t know how many breaks exist, use select() with caller-supplied
critical values (from Bai–Perron tables or your simulation):
import numpy as np
from xtbreak import select
np.random.seed(42)
y = np.concatenate([
np.random.normal(0, 1, 40),
np.random.normal(3, 1, 40),
np.random.normal(1, 1, 40),
])
x = np.ones((120, 1))
result = select(
y, x,
trimming=0.15,
max_breaks=3,
critical_values={1: 8.58, 2: 7.22, 3: 5.96},
)
print(f"Selected breaks: {result.selected_breaks}")
print(f"Break locations: {result.selected_breakpoints}")
# Access the promoted estimate (when breaks > 0)
if result.estimate is not None:
for be in result.estimate.break_estimates:
print(f" Break {be.break_number} at index {be.index}, "
f"CI: {be.ci_index}")
Pandas DataFrame Input
All three entry points accept a data= keyword for DataFrame input:
import numpy as np
import pandas as pd
from xtbreak import estimate
np.random.seed(42)
T = 100
x_vals = np.random.randn(T)
y_vals = np.where(np.arange(T) < 60, 2.0 * x_vals, 5.0 * x_vals) + np.random.randn(T) * 0.5
df = pd.DataFrame({'y': y_vals, 'x1': x_vals})
result = estimate(data=df, y='y', x=['x1'], breaks=1, trimming=0.15)
print(f"Break at index: {result.break_table()[0]['index']}")
When data is provided, y, x, entity, and time should be column name
strings (or a list of strings for x). Numerical paths are identical to direct
array input.
Regime Statistics and Chow Tests
After estimation, inspect per-regime OLS fits:
import numpy as np
from xtbreak import estimate
np.random.seed(2024)
y = np.concatenate([np.random.normal(0, 1, 50), np.random.normal(3, 1, 50)])
x = np.ones((100, 1))
result = estimate(y, x, breaks=1, trimming=0.15)
# Per-regime statistics
for rs in result.regime_statistics:
print(f"Regime {rs.regime_index}: coef={rs.coefficients[0]:.4f}, "
f"SE={rs.standard_errors[0]:.4f}, n={rs.n_observations}, "
f"R²={rs.r_squared:.4f}")
# Chow test for structural change between adjacent regimes
for ct in result.chow_tests:
p_str = f"{ct.p_value:.6f}" if ct.p_value else "N/A (install scipy)"
print(f"Chow F({ct.degrees_of_freedom[0]},{ct.degrees_of_freedom[1]})"
f" = {ct.f_statistic:.4f}, p = {p_str}")
# Export to pandas DataFrame
df_stats = result.to_dataframe()
print(df_stats)
Panel Data
Specify entity= and time= arrays for panel data with common break dates:
import numpy as np
from xtbreak import test, estimate
np.random.seed(42)
N, T, break_t = 5, 40, 25
entity = np.repeat(np.arange(N), T)
time = np.tile(np.arange(1, T + 1), N)
# State effects + regime shift
y = np.zeros(N * T)
for i in range(N):
s, e = i * T, (i + 1) * T
y[s:s + break_t] = 10 + i + np.random.randn(break_t)
y[s + break_t:e] = 15 + i + np.random.randn(T - break_t)
x = np.ones((N * T, 1))
# Test
test_r = test(y, x, breaks=1, trimming=0.15, entity=entity, time=time)
print(f"Panel SupF: {test_r.statistic:.2f}")
# Estimate
est_r = estimate(y, x, breaks=1, trimming=0.15, entity=entity, time=time)
print(f"Break at common time: {est_r.break_estimates[0].time_value}")
print(f"CI: {est_r.break_estimates[0].ci_time_value}")
Trend Parameters
Use trend=True for a fixed linear trend (non-breaking) and
breaktrend=True for a trend that shifts at break dates:
from xtbreak import estimate
# Fixed trend across regimes
result = estimate(y, x, breaks=1, trimming=0.15, trend=True)
# Trend allowed to shift at breakpoints
result = estimate(y, x, breaks=1, trimming=0.15, breaktrend=True)
Robust Covariance
vce= controls the variance–covariance estimator:
|
Estimator |
Availability |
|---|---|---|
|
Classical SSR-based |
Time series + panel |
|
Heteroskedasticity-consistent (HC0) |
Time series + panel |
|
Newey–West HAC (Bartlett kernel) |
Time series + panel |
|
Nonparametric panel |
Panel only |
|
Weighted prewhitened nonparametric |
Panel only |
from xtbreak import estimate
# Robust to heteroskedasticity
result = estimate(y, x, breaks=1, trimming=0.15, vce="hc")
print(result.metadata["covariance_estimator"]) # "hc"
# HAC for autocorrelation
result = estimate(y, x, breaks=1, trimming=0.15, vce="hac")
print(result.metadata["bandwidth"]) # automatic bandwidth selection
Time-series vce="np" or vce="wpn" raises XTBreakValidationError
(these require panel arrays).
Information Criteria
select() supports BIC/AIC-based model selection alongside sequential F:
from xtbreak import select
result = select(
y, x,
max_breaks=5,
trimming=0.15,
critical_values={1: 8.58, 2: 7.22, 3: 5.96, 4: 4.99, 5: 3.91},
information_criterion='bic',
)
ic_count = result.metadata.get('ic_selected_breaks')
print(f"BIC recommends {ic_count} break(s)")
Performance Options
For large-T samples or many breaks:
from xtbreak import estimate
# Parallel dynamic programming
result = estimate(y, x, breaks=3, trimming=0.15, n_jobs=4)
# Memory optimization for large T (>5000)
result = estimate(y, x, breaks=1, trimming=0.15, lazy_ssr=True)
Serialization
Every result object is JSON-safe:
import json
from xtbreak import estimate
result = estimate(y, x, breaks=1, trimming=0.15)
# Full JSON-safe snapshot
payload = result.to_dict()
json.dumps(payload) # works directly
# Human-readable summary
print(result.summary())
# Break date labels
labels = result.break_date_labels()
Quantitative Smoke Anchors
The Monte Carlo rows are low-budget smoke and calibration anchors only; they are not publication-strength size, power, coverage, or benchmark claims.
Surface |
Anchor |
|---|---|
CI coverage smoke |
|
Next Steps
Full API reference: see api-reference.md
Worked examples: see examples/ (runnable .py scripts)
Validation details: see
validation.md(internal, not published)