# xtbreak Quickstart > For installation and a first example, see the [README](https://github.com/gorgeousfish/xtbreak-py#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: 1. **Select** how many breaks the data supports 2. **Inspect** regime-specific statistics 3. **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): ```python 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: ```python 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: ```python 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: ```python 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: ```python 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: | `vce` value | Estimator | Availability | |-------------|-----------|--------------| | `"ssr"` | Classical SSR-based | Time series + panel | | `"hc"` | Heteroskedasticity-consistent (HC0) | Time series + panel | | `"hac"` | Newey–West HAC (Bartlett kernel) | Time series + panel | | `"np"` | Nonparametric panel | Panel only | | `"wpn"` | Weighted prewhitened nonparametric | Panel only | ```python 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: ```python 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: ```python 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: ```python 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 | `N=80`, `trimming=0.15`, 40 deterministic holdout replications, true break `40`, `ci_level=0.95`, empirical coverage `36/40 = 0.90`, exact break recovery `20/40`, mean absolute break error `1.1`, and mean CI width `7.9`. | ## Next Steps - **Full API reference**: see [api-reference.md](api-reference.md) - **Worked examples**: see [examples/](../examples/) (runnable .py scripts) - **Validation details**: see `validation.md` (internal, not published)