Historical TV-Radius Calibration¶
calibrate_tv_radius(...) estimates a total-variation stress radius from
observed consecutive-period hidden-composition changes and evaluates it with
rolling one-step backtests. It addresses the practical question:
How large should the TV budget be if it is meant to cover a declared share of the recompositions seen in this historical series?
The result is an empirical calibration, not a universal or forward-looking guarantee. It makes the source of the radius inspectable and backtestable.
Basic Workflow¶
Install the CVXPY extra used by q_tv_budget(...):
pip install "updatesupport[cvxpy]"
Define the reporting claim once, then calibrate it on period-labelled history:
import updatesupport as us
claim = us.claim(
"MQL-to-SQL conversion remains above the review floor",
public=["reported_segment", "region"],
hidden=[
"reported_segment",
"region",
"lead_source",
"industry",
"rep_ramp_band",
],
target="sql_conversion_rate",
weight="mql_count",
ambiguity_limit=0.02,
decision=us.threshold_decision(">=", 0.18),
)
calibration = claim.calibrate_tv(
historical_rows,
period="quarter",
coverage=0.90,
min_train_transitions=4,
)
print(calibration.to_markdown())
print(calibration.calibrated_radius)
The returned report exposes the calibrated preset as calibration.q. It can
also apply the calibrated claim directly:
current_audit = calibration.audit(current_period_rows)
current_design = calibration.design(current_period_rows)
The functional spelling is equivalent:
calibration = us.calibrate_tv_radius(
historical_rows,
claim,
period="quarter",
coverage=0.90,
min_train_transitions=4,
)
Use period_order=[...] when period labels do not have the desired natural
sort order.
What Is Calibrated¶
Let p_t(o) be the public law in reference period t, and let
c_t(d | o) be the hidden-cell composition inside public cell o. The
reference hidden law is:
q_t(d) = p_t(o) c_t(d | o)
The next period is restandardized to the reference public law:
q_{t+1|t}(d) = p_t(o) c_{t+1}(d | o)
The historical transition radius is then:
r_t = 0.5 * ||q_{t+1|t} - q_t||_1
This is the same total-variation geometry used by q_tv_budget(r_t). Changes
in public bucket shares are removed before the distance is calculated, so the
radius measures within-public-cell recomposition rather than general
population drift.
The final radius is the higher empirical quantile of eligible transition
distances. For example, coverage=0.90 selects a radius at least as large as
the empirical 90th percentile under the conservative higher quantile rule.
Rolling Backtests¶
For transition t -> t+1, the rolling backtest calibrates its radius using
eligible transitions ending no later than t. The transition being evaluated
is never included in its own training set.
Each row separates:
Shift coverage: whether the realized restandardized TV distance is no larger than the historically calibrated radius.
Target coverage: whether the recomposed target value falls inside the TV audit interval built from reference-period target values.
Decision preservation: when the claim has a decision rule, whether the realized recomposed value implies the same decision as the reference value.
Predicted ambiguity and decision invariance: whether the calibrated audit itself meets the claim’s ambiguity limit or certifies its decision.
Target backtesting deliberately holds reference-period hidden-cell target values fixed. That isolates composition sensitivity. Using evaluation-period target values would mix target or model drift into the TV calibration.
Support Drift¶
An ordinary TV ball in updatesupport reweights the retained reference support;
it does not invent new hidden cells. A transition is therefore excluded from
radius calibration when:
the evaluation period introduces a positive-mass hidden cell absent from the reference retained support, or
a positive-mass reference public cell disappears, leaving no evaluation composition to restandardize.
These transitions remain visible in the report as unsupported_support. They
are not silently counted as ordinary radius misses. A high unsupported rate is
evidence that support expansion needs its own stress model or that the retained
cell definition is too brittle for historical calibration.
Structured Exports¶
The report supports the standard artifact API:
calibration.to_json()
calibration.to_tables()
calibration.to_dataframes()
The named tables are summary, claim, transitions, backtests, and
limitations.
Interpretation Boundary¶
Historical coverage describes this sequence of retained compositions under the selected period definition, filtering rule, and quantile level. It does not guarantee coverage after a regime change, validate the target estimator, or cover variables absent from the retained refinement.