%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22scikit-learn%22%2C%0A%23%20%20%20%20%20%22yohou%5Bplotting%5D%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.8%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Conformity%20Scorers%20for%20Conformal%20Prediction%0A%0A%20%20%20%20Conformal%20prediction%20builds%20prediction%20intervals%20by%20measuring%20how%0A%20%20%20%20%22non-conforming%22%20each%20calibration%20point%20is.%20The%20**conformity%20scorer**%0A%20%20%20%20determines%20that%20measurement.%20Different%20scorers%20produce%20intervals%20with%0A%20%20%20%20different%20shapes%20and%20properties%3A%0A%0A%20%20%20%20%7C%20Scorer%20%7C%20Formula%20%7C%20Interval%20%7C%20Best%20For%20%7C%0A%20%20%20%20%7C--------%7C---------%7C----------%7C----------%7C%0A%20%20%20%20%7C%20%5B%60Residual%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.conformity.Residual%2F)%20%7C%20%24y%20-%20%5Chat%7By%7D%24%20%7C%20Asymmetric%20%7C%20General%20use%20%7C%0A%20%20%20%20%7C%20%5B%60AbsoluteResidual%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.conformity.AbsoluteResidual%2F)%20%7C%20%24%5C%7Cy%20-%20%5Chat%7By%7D%5C%7C%24%20%7C%20Symmetric%20%7C%20Balanced%20errors%20%7C%0A%20%20%20%20%7C%20%5B%60GammaResidual%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.conformity.GammaResidual%2F)%20%7C%20%24(y%20-%20%5Chat%7By%7D)%20%2F%20(%5Chat%7By%7D%20%2B%20%5Cvarepsilon)%24%20%7C%20Asymmetric%2C%20adaptive%20%7C%20Proportional%20errors%20%7C%0A%20%20%20%20%7C%20%5B%60AbsoluteGammaResidual%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.conformity.AbsoluteGammaResidual%2F)%20%7C%20%24%5C%7C(y%20-%20%5Chat%7By%7D)%20%2F%20(%5Chat%7By%7D%20%2B%20%5Cvarepsilon)%5C%7C%24%20%7C%20Symmetric%2C%20adaptive%20%7C%20Proportional%20%2B%20balanced%20%7C%0A%0A%20%20%20%20**Prerequisites%3A**%20Familiarity%20with%20%5B%60SplitConformalForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.interval.split_conformal.SplitConformalForecaster%2F).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20from%20copy%20import%20deepcopy%0A%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20from%20sklearn.linear_model%20import%20Ridge%0A%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_tourism_monthly%0A%20%20%20%20from%20yohou.interval%20import%20DistanceSimilarity%2C%20SplitConformalForecaster%0A%20%20%20%20from%20yohou.metrics%20import%20EmpiricalCoverage%2C%20IntervalScore%2C%20MeanIntervalWidth%0A%20%20%20%20from%20yohou.metrics.conformity%20import%20(%0A%20%20%20%20%20%20%20%20AbsoluteGammaResidual%2C%0A%20%20%20%20%20%20%20%20AbsoluteResidual%2C%0A%20%20%20%20%20%20%20%20GammaResidual%2C%0A%20%20%20%20%20%20%20%20Residual%2C%0A%20%20%20%20)%0A%20%20%20%20from%20yohou.model_selection%20import%20train_test_split%0A%20%20%20%20from%20yohou.plotting%20import%20(%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_score_per_step%2C%0A%20%20%20%20%20%20%20%20plot_score_time_series%2C%0A%20%20%20%20%20%20%20%20plot_time_series%2C%0A%20%20%20%20)%0A%20%20%20%20from%20yohou.point%20import%20PointReductionForecaster%0A%20%20%20%20from%20yohou.preprocessing%20import%20LagTransformer%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20AbsoluteGammaResidual%2C%0A%20%20%20%20%20%20%20%20AbsoluteResidual%2C%0A%20%20%20%20%20%20%20%20DistanceSimilarity%2C%0A%20%20%20%20%20%20%20%20EmpiricalCoverage%2C%0A%20%20%20%20%20%20%20%20GammaResidual%2C%0A%20%20%20%20%20%20%20%20IntervalScore%2C%0A%20%20%20%20%20%20%20%20LagTransformer%2C%0A%20%20%20%20%20%20%20%20MeanIntervalWidth%2C%0A%20%20%20%20%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20%20%20%20%20Residual%2C%0A%20%20%20%20%20%20%20%20Ridge%2C%0A%20%20%20%20%20%20%20%20SplitConformalForecaster%2C%0A%20%20%20%20%20%20%20%20deepcopy%2C%0A%20%20%20%20%20%20%20%20fetch_tourism_monthly%2C%0A%20%20%20%20%20%20%20%20pl%2C%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_score_per_step%2C%0A%20%20%20%20%20%20%20%20plot_score_time_series%2C%0A%20%20%20%20%20%20%20%20plot_time_series%2C%0A%20%20%20%20%20%20%20%20train_test_split%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%201.%20Prepare%20Data%0A%0A%20%20%20%20We%20load%20the%20Tourism%20Monthly%20dataset%20and%20split%20it%20into%20training%2C%20calibration%2C%0A%20%20%20%20and%20test%20sets.%20All%20four%20conformity%20scorers%20will%20share%20the%20same%20underlying%0A%20%20%20%20%5B%60PointReductionForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.reduction.PointReductionForecaster%2F)%20so%20that%20differences%20in%20interval%20shape%20come%0A%20%20%20%20solely%20from%20the%20choice%20of%20scorer.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_tourism_monthly%2C%20train_test_split)%3A%0A%20%20%20%20df%20%3D%20fetch_tourism_monthly().frame.select(%22time%22%2C%20%22T1__tourists%22).drop_nulls().rename(%7B%22T1__tourists%22%3A%20%22tourists%22%7D)%0A%20%20%20%20y_train%2C%20_y_rest%20%3D%20train_test_split(df%2C%20test_size%3D0.15)%0A%20%20%20%20%23%20Cap%20test%20size%20at%2024%20so%20it%20fits%20within%20calibration_size%0A%20%20%20%20y_test%20%3D%20_y_rest.head(24)%0A%20%20%20%20return%20df%2C%20y_test%2C%20y_train%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20plot_time_series)%3A%0A%20%20%20%20plot_time_series(df%2C%20title%3D%22Tourism%20Monthly%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%202.%20Build%20a%20Shared%20Point%20Forecaster%0A%0A%20%20%20%20All%20conformal%20forecasters%20share%20the%20same%20underlying%20point%20forecaster.%0A%20%20%20%20This%20isolates%20the%20effect%20of%20the%20conformity%20scorer%20on%20interval%20quality.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(LagTransformer%2C%20PointReductionForecaster%2C%20Ridge)%3A%0A%20%20%20%20base_forecaster%20%3D%20PointReductionForecaster(%0A%20%20%20%20%20%20%20%20estimator%3DRidge(alpha%3D1.0)%2C%0A%20%20%20%20%20%20%20%20feature_transformer%3DLagTransformer(lag%3D%5B1%2C%206%2C%2012%5D)%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(base_forecaster%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%203.%20Residual%3A%20%60y%20-%20y_hat%60%0A%0A%20%20%20%20The%20simplest%20scorer.%20Computes%20raw%20signed%20residuals%2C%20producing%0A%20%20%20%20**asymmetric**%20intervals%20(lower%20and%20upper%20bounds%20can%20differ%20in%20distance%0A%20%20%20%20from%20the%20point%20prediction).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Residual%2C%0A%20%20%20%20SplitConformalForecaster%2C%0A%20%20%20%20base_forecaster%2C%0A%20%20%20%20plot_forecast%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20fc_residual%20%3D%20SplitConformalForecaster(%0A%20%20%20%20%20%20%20%20point_forecaster%3Dbase_forecaster%2C%0A%20%20%20%20%20%20%20%20calibration_size%3D24%2C%0A%20%20%20%20%20%20%20%20conformity_scorer%3DResidual()%2C%0A%20%20%20%20)%0A%20%20%20%20_horizon%20%3D%20len(y_test)%0A%20%20%20%20fc_residual.fit(y_train%2C%20forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_residual%20%3D%20fc_residual.predict_interval(forecasting_horizon%3D_horizon%2C%20coverage_rates%3D%5B0.9%5D)%0A%20%20%20%20_y_point%20%3D%20fc_residual.predict(forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_residual%20%3D%20y_pred_residual.hstack(_y_point.drop(%22time%22%2C%20%22vintage_time%22))%0A%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_pred_residual%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20n_history%3D36%2C%0A%20%20%20%20%20%20%20%20coverage_rates%3D%5B0.9%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22Residual%3A%20Asymmetric%20Intervals%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20fc_residual%2C%20y_pred_residual%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%204.%20AbsoluteResidual%3A%20%60%7Cy%20-%20y_hat%7C%60%0A%0A%20%20%20%20Takes%20the%20absolute%20value%2C%20producing%20**symmetric**%20intervals%20centred%20on%20the%0A%20%20%20%20point%20prediction.%20This%20is%20the%20most%20common%20choice%20when%20you%20have%20no%20reason%0A%20%20%20%20to%20expect%20directional%20bias.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20AbsoluteResidual%2C%0A%20%20%20%20SplitConformalForecaster%2C%0A%20%20%20%20base_forecaster%2C%0A%20%20%20%20plot_forecast%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20fc_abs%20%3D%20SplitConformalForecaster(%0A%20%20%20%20%20%20%20%20point_forecaster%3Dbase_forecaster%2C%0A%20%20%20%20%20%20%20%20calibration_size%3D24%2C%0A%20%20%20%20%20%20%20%20conformity_scorer%3DAbsoluteResidual()%2C%0A%20%20%20%20)%0A%20%20%20%20_horizon%20%3D%20len(y_test)%0A%20%20%20%20fc_abs.fit(y_train%2C%20forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_abs%20%3D%20fc_abs.predict_interval(forecasting_horizon%3D_horizon%2C%20coverage_rates%3D%5B0.9%5D)%0A%20%20%20%20_y_point%20%3D%20fc_abs.predict(forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_abs%20%3D%20y_pred_abs.hstack(_y_point.drop(%22time%22%2C%20%22vintage_time%22))%0A%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_pred_abs%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20n_history%3D36%2C%0A%20%20%20%20%20%20%20%20coverage_rates%3D%5B0.9%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22AbsoluteResidual%3A%20Symmetric%20Intervals%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(y_pred_abs%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%205.%20GammaResidual%3A%20%60(y%20-%20y_hat)%20%2F%20(y_hat%20%2B%20epsilon)%60%0A%0A%20%20%20%20Normalises%20residuals%20by%20the%20prediction%20magnitude%2C%20making%20intervals%0A%20%20%20%20**adaptive**%20(wider%20when%20predictions%20are%20large%2C%20narrower%20when%20small).%0A%20%20%20%20This%20is%20especially%20useful%20for%20data%20with%20**multiplicative**%20noise%20patterns%0A%20%20%20%20like%20the%20Tourism%20Monthly%20series.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20GammaResidual%2C%0A%20%20%20%20SplitConformalForecaster%2C%0A%20%20%20%20base_forecaster%2C%0A%20%20%20%20plot_forecast%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20fc_gamma%20%3D%20SplitConformalForecaster(%0A%20%20%20%20%20%20%20%20point_forecaster%3Dbase_forecaster%2C%0A%20%20%20%20%20%20%20%20calibration_size%3D24%2C%0A%20%20%20%20%20%20%20%20conformity_scorer%3DGammaResidual(epsilon%3D1e-8)%2C%0A%20%20%20%20)%0A%20%20%20%20_horizon%20%3D%20len(y_test)%0A%20%20%20%20fc_gamma.fit(y_train%2C%20forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_gamma%20%3D%20fc_gamma.predict_interval(forecasting_horizon%3D_horizon%2C%20coverage_rates%3D%5B0.9%5D)%0A%20%20%20%20_y_point%20%3D%20fc_gamma.predict(forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_gamma%20%3D%20y_pred_gamma.hstack(_y_point.drop(%22time%22%2C%20%22vintage_time%22))%0A%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_pred_gamma%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20n_history%3D36%2C%0A%20%20%20%20%20%20%20%20coverage_rates%3D%5B0.9%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22GammaResidual%3A%20Adaptive%20Asymmetric%20Intervals%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(y_pred_gamma%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%206.%20AbsoluteGammaResidual%3A%20%60%7C(y%20-%20y_hat)%20%2F%20(y_hat%20%2B%20epsilon)%7C%60%0A%0A%20%20%20%20Combines%20magnitude-adaptive%20scaling%20with%20symmetric%20intervals.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20AbsoluteGammaResidual%2C%0A%20%20%20%20SplitConformalForecaster%2C%0A%20%20%20%20base_forecaster%2C%0A%20%20%20%20plot_forecast%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20fc_abs_gamma%20%3D%20SplitConformalForecaster(%0A%20%20%20%20%20%20%20%20point_forecaster%3Dbase_forecaster%2C%0A%20%20%20%20%20%20%20%20calibration_size%3D24%2C%0A%20%20%20%20%20%20%20%20conformity_scorer%3DAbsoluteGammaResidual(epsilon%3D1e-8)%2C%0A%20%20%20%20)%0A%20%20%20%20_horizon%20%3D%20len(y_test)%0A%20%20%20%20fc_abs_gamma.fit(y_train%2C%20forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_abs_gamma%20%3D%20fc_abs_gamma.predict_interval(forecasting_horizon%3D_horizon%2C%20coverage_rates%3D%5B0.9%5D)%0A%20%20%20%20_y_point%20%3D%20fc_abs_gamma.predict(forecasting_horizon%3D_horizon)%0A%20%20%20%20y_pred_abs_gamma%20%3D%20y_pred_abs_gamma.hstack(_y_point.drop(%22time%22%2C%20%22vintage_time%22))%0A%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_pred_abs_gamma%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20n_history%3D36%2C%0A%20%20%20%20%20%20%20%20coverage_rates%3D%5B0.9%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22AbsoluteGammaResidual%3A%20Adaptive%20Symmetric%20Intervals%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(y_pred_abs_gamma%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%207.%20Quantitative%20Comparison%0A%0A%20%20%20%20Compare%20all%20four%20scorers%20visually%20with%20%5B%60plot_score_time_series%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.plotting.evaluation.plot_score_time_series%2F).%0A%20%20%20%20Each%20line%20shows%20the%20per-timestep%20interval%20score%20for%20one%20conformity%0A%20%20%20%20scorer%2C%20making%20it%20easy%20to%20spot%20where%20specific%20scorers%20struggle.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20IntervalScore%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20plot_score_time_series%2C%0A%20%20%20%20y_pred_abs%2C%0A%20%20%20%20y_pred_abs_gamma%2C%0A%20%20%20%20y_pred_gamma%2C%0A%20%20%20%20y_pred_residual%2C%0A%20%20%20%20y_test%2C%0A)%3A%0A%20%20%20%20_preds%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22Residual%22%3A%20y_pred_residual%2C%0A%20%20%20%20%20%20%20%20%22AbsoluteResidual%22%3A%20y_pred_abs%2C%0A%20%20%20%20%20%20%20%20%22GammaResidual%22%3A%20y_pred_gamma%2C%0A%20%20%20%20%20%20%20%20%22AbsoluteGammaResidual%22%3A%20y_pred_abs_gamma%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20mo.vstack(%5B%0A%20%20%20%20%20%20%20%20plot_score_time_series(%0A%20%20%20%20%20%20%20%20%20%20%20%20IntervalScore(coverage_rates%3D%5B0.9%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20_preds%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Interval%20Score%20per%20Timestep%22%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%208.%20When%20to%20Use%20Which%20Scorer%0A%0A%20%20%20%20-%20**Residual**%3A%20Choose%20when%20errors%20may%20be%20directionally%20biased%20(under-%20vs.%20over-prediction)%20and%20you%20want%20intervals%20that%20reflect%20that%20asymmetry%0A%20%20%20%20-%20**AbsoluteResidual**%3A%20Default%20choice%20for%20symmetric%20errors%3B%20simplest%20and%20most%20interpretable%0A%20%20%20%20-%20**GammaResidual**%3A%20Choose%20for%20multiplicative%20data%20(e.g.%2C%20sales%2C%20passenger%20counts)%20where%20absolute%20error%20scales%20with%20the%20level%0A%20%20%20%20-%20**AbsoluteGammaResidual**%3A%20Combines%20adaptiveness%20with%20symmetry%3B%20good%20default%20for%20multiplicative%20data%20with%20balanced%20errors%0A%0A%20%20%20%20For%20this%20Tourism%20Monthly%20series%20(strong%20multiplicative%20trend)%2C%20the%0A%20%20%20%20**Gamma**%20variants%20should%20produce%20better-calibrated%20intervals%20because%0A%20%20%20%20interval%20width%20adapts%20to%20the%20prediction%20magnitude.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%209.%20Coverage%20and%20Width%20Comparison%0A%0A%20%20%20%20%5B%60EmpiricalCoverage%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.interval.EmpiricalCoverage%2F)%20checks%20whether%20intervals%20contain%20the%0A%20%20%20%20true%20value%20at%20the%20target%20rate.%20%5B%60MeanIntervalWidth%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.interval.MeanIntervalWidth%2F)%20measures%20the%0A%20%20%20%20average%20band%20width.%20Narrower%20intervals%20are%20better%2C%20provided%20coverage%0A%20%20%20%20is%20maintained.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20EmpiricalCoverage%2C%0A%20%20%20%20MeanIntervalWidth%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20pl%2C%0A%20%20%20%20y_pred_abs%2C%0A%20%20%20%20y_pred_abs_gamma%2C%0A%20%20%20%20y_pred_gamma%2C%0A%20%20%20%20y_pred_residual%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20_cov%20%3D%20EmpiricalCoverage()%0A%20%20%20%20_width%20%3D%20MeanIntervalWidth()%0A%20%20%20%20_cov.fit(y_train)%0A%20%20%20%20_width.fit(y_train)%0A%0A%20%20%20%20_scorers_map%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22Residual%22%3A%20y_pred_residual%2C%0A%20%20%20%20%20%20%20%20%22AbsoluteResidual%22%3A%20y_pred_abs%2C%0A%20%20%20%20%20%20%20%20%22GammaResidual%22%3A%20y_pred_gamma%2C%0A%20%20%20%20%20%20%20%20%22AbsoluteGammaResidual%22%3A%20y_pred_abs_gamma%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20_rows%20%3D%20%5B%5D%0A%20%20%20%20for%20_name%2C%20_pred%20in%20_scorers_map.items()%3A%0A%20%20%20%20%20%20%20%20_c%20%3D%20float(_cov.score(y_test%2C%20_pred))%0A%20%20%20%20%20%20%20%20_w%20%3D%20float(_width.score(y_test%2C%20_pred))%0A%20%20%20%20%20%20%20%20_rows.append(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Scorer%22%3A%20_name%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Empirical%20Coverage%22%3A%20round(_c%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Mean%20Interval%20Width%22%3A%20round(_w%2C%201)%2C%0A%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20mo.ui.table(pl.DataFrame(_rows))%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%2010.%20With%20DistanceSimilarity%0A%0A%20%20%20%20%5B%60DistanceSimilarity%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.interval.similarity.DistanceSimilarity%2F)%20reweights%20calibration%20residuals%20based%20on%0A%20%20%20%20similarity%20to%20the%20current%20observation.%20Combined%20with%20different%0A%20%20%20%20conformity%20scorers%2C%20this%20produces%20**adaptive**%20intervals%20that%20are%0A%20%20%20%20narrower%20in%20well-understood%20regions%20and%20wider%20in%20unusual%20ones.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20AbsoluteResidual%2C%0A%20%20%20%20DistanceSimilarity%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20SplitConformalForecaster%2C%0A%20%20%20%20plot_forecast%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20_base_sim%20%3D%20PointReductionForecaster(%0A%20%20%20%20%20%20%20%20estimator%3DRidge(alpha%3D1.0)%2C%0A%20%20%20%20%20%20%20%20feature_transformer%3DLagTransformer(lag%3D%5B1%2C%206%2C%2012%5D)%2C%0A%20%20%20%20)%0A%20%20%20%20fc_sim%20%3D%20SplitConformalForecaster(%0A%20%20%20%20%20%20%20%20point_forecaster%3D_base_sim%2C%0A%20%20%20%20%20%20%20%20calibration_size%3D24%2C%0A%20%20%20%20%20%20%20%20conformity_scorer%3DAbsoluteResidual()%2C%0A%20%20%20%20%20%20%20%20similarity%3DDistanceSimilarity(metric%3D%22euclidean%22)%2C%0A%20%20%20%20)%0A%20%20%20%20_horizon%20%3D%20len(y_test)%0A%20%20%20%20fc_sim.fit(y_train%2C%20forecasting_horizon%3D_horizon)%0A%20%20%20%20_y_pred_sim%20%3D%20fc_sim.predict_interval(forecasting_horizon%3D_horizon%2C%20coverage_rates%3D%5B0.9%5D)%0A%20%20%20%20_y_point%20%3D%20fc_sim.predict(forecasting_horizon%3D_horizon)%0A%20%20%20%20_y_pred_sim%20%3D%20_y_pred_sim.hstack(_y_point.drop(%22time%22%2C%20%22vintage_time%22))%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20_y_pred_sim%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20n_history%3D36%2C%0A%20%20%20%20%20%20%20%20coverage_rates%3D%5B0.9%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22AbsoluteResidual%20%2B%20DistanceSimilarity%20(Adaptive)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Multi-vintage%20Scoring%0A%0A%20%20%20%20The%20%60observe_predict_interval%60%20method%20with%20%60stride%3D1%60%20produces%20one%0A%20%20%20%20interval%20forecast%20per%20observation%20point%2C%20creating%20multiple%20*vintages*.%0A%20%20%20%20Each%20vintage%20represents%20a%20different%20forecast%20origin%2C%20so%20you%20can%20analyse%0A%20%20%20%20how%20interval%20quality%20evolves%20as%20the%20model%20absorbs%20more%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(deepcopy%2C%20fc_residual%2C%20y_test)%3A%0A%20%20%20%20_vintage_model%20%3D%20deepcopy(fc_residual)%0A%20%20%20%20y_pred_vintages%20%3D%20_vintage_model.observe_predict_interval(%0A%20%20%20%20%20%20%20%20y%3Dy_test%2C%0A%20%20%20%20%20%20%20%20stride%3D1%2C%0A%20%20%20%20%20%20%20%20forecasting_horizon%3Dlen(y_test)%2C%0A%20%20%20%20%20%20%20%20coverage_rates%3D%5B0.9%5D%2C%0A%20%20%20%20)%0A%20%20%20%20print(f%22Vintages%3A%20%7By_pred_vintages%5B'vintage_time'%5D.n_unique()%7D%22)%0A%20%20%20%20y_pred_vintages.head(10)%0A%20%20%20%20return%20(y_pred_vintages%2C)%0A%0A%0A%40app.cell%0Adef%20_(IntervalScore%2C%20y_train)%3A%0A%20%20%20%20vintage_scorer%20%3D%20IntervalScore()%0A%20%20%20%20vintage_scorer.fit(y_train)%0A%20%20%20%20return%20(vintage_scorer%2C)%0A%0A%0A%40app.cell%0Adef%20_(plot_score_per_step%2C%20vintage_scorer%2C%20y_pred_vintages%2C%20y_test)%3A%0A%20%20%20%20plot_score_per_step(%0A%20%20%20%20%20%20%20%20vintage_scorer%2C%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_pred_vintages%2C%0A%20%20%20%20%20%20%20%20title%3D%22Interval%20Score%20per%20Step%22%2C%0A%20%20%20%20%20%20%20%20y_label%3D%22Interval%20Score%22%2C%0A%20%20%20%20%20%20%20%20height%3D380%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Next%20Steps%0A%0A%20%20%20%20-%20**Distance%20similarity**%3A%20See%20%5B%60distance_similarity.py%60%5D(%2Fexamples%2Fforecasting-models%2Fdistance_similarity%2F)%20for%20full%20adaptive%20conformal%20intervals%20deep-dive%0A%20%20%20%20-%20**Interval%20metrics**%3A%20See%20%5B%60interval_metrics.py%60%5D(%2Fexamples%2Fevaluation-search%2Finterval_metrics%2F)%20for%20deep-dive%20into%20interval%20evaluation%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
f91240c291f65573a613e14d405d0b8f