%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%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%20How%20to%20Control%20Step%20Feature%20Alignment%0A%0A%20%20%20%20This%20notebook%20shows%20how%20to%20use%20the%20%60step_feature_alignment%60%20parameter%20of%0A%20%20%20%20%5B%60PointReductionForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.reduction.PointReductionForecaster%2F)%0A%20%20%20%20to%20control%20which%20step-indexed%20columns%20each%20direct-strategy%20estimator%0A%20%20%20%20sees%20during%20training%20and%20prediction.%20The%20synthetic%20data%20is%20generated%20with%0A%20%20%20%20%5B%60make_exogenous_regression%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.datasets._fetchers.make_exogenous_regression%2F).%0A%0A%20%20%20%20**Prerequisites%3A**%20Familiarity%20with%20the%20direct%20reduction%20strategy%20and%0A%20%20%20%20exogenous%20features%0A%20%20%20%20(%5BExogenous%20Tutorial%5D(%2Fexamples%2Fcompose%2Fexogenous_features%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%20import%20polars%20as%20pl%0A%20%20%20%20from%20sklearn.ensemble%20import%20HistGradientBoostingRegressor%0A%0A%20%20%20%20from%20yohou.datasets%20import%20make_exogenous_regression%0A%20%20%20%20from%20yohou.metrics%20import%20MeanAbsoluteError%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%20HistGradientBoostingRegressor%2C%0A%20%20%20%20%20%20%20%20LagTransformer%2C%0A%20%20%20%20%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20%20%20%20%20make_exogenous_regression%2C%0A%20%20%20%20%20%20%20%20pl%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%20Generate%20synthetic%20data%20with%20temperature%20(X_actual)%2C%20holidays%0A%20%20%20%20(X_future)%2C%20and%20weather%20forecasts%20(X_forecast).%20Use%20a%2012-step%0A%20%20%20%20horizon%20to%20make%20step%20column%20differences%20visible.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(make_exogenous_regression)%3A%0A%20%20%20%20H%20%3D%2012%0A%20%20%20%20data%20%3D%20make_exogenous_regression(n_samples%3D300%2C%20forecasting_horizon%3DH)%0A%20%20%20%20y%20%3D%20data.y%0A%20%20%20%20X_actual%20%3D%20data.X_actual%0A%20%20%20%20X_future%20%3D%20data.X_future%0A%20%20%20%20X_forecast%20%3D%20data.X_forecast%0A%0A%20%20%20%20from%20yohou.model_selection%20import%20train_test_split%0A%0A%20%20%20%20y_train%2C%20y_test%2C%20X_actual_train%2C%20_%20%3D%20train_test_split(%0A%20%20%20%20%20%20%20%20y%2C%20X_actual%2C%20test_size%3DH%0A%20%20%20%20)%0A%0A%20%20%20%20print(f%22Horizon%3A%20%7BH%7D%2C%20Train%3A%20%7Blen(y_train)%7D%2C%20Test%3A%20%7Blen(y_test)%7D%22)%0A%20%20%20%20return%20H%2C%20X_actual_train%2C%20X_forecast%2C%20X_future%2C%20y_test%2C%20y_train%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.%20Compare%20Alignment%20Modes%0A%0A%20%20%20%20The%20%60step_feature_alignment%60%20parameter%20only%20affects%20the%20%60%22direct%22%60%0A%20%20%20%20strategy%2C%20where%20H%20independent%20estimators%20are%20fitted%20(one%20per%20step).%0A%0A%20%20%20%20%7C%20Mode%20%7C%20Estimator%20for%20step%20h%20sees%20%7C%0A%20%20%20%20%7C------%7C--------------------------%7C%0A%20%20%20%20%7C%20%60%22all%22%60%20%7C%20All%20step%20columns%20(%60*_step_1%60%20through%20%60*_step_H%60)%20%7C%0A%20%20%20%20%7C%20%60%22matched%22%60%20%7C%20Only%20its%20own%20step%20column%20(%60*_step_h%60)%20%7C%0A%20%20%20%20%7C%20%60%22cumulative%22%60%20%7C%20Step%20columns%201%20through%20h%20(%60*_step_1..h%60)%20%7C%0A%0A%20%20%20%20Fit%20three%20forecasters%20with%20identical%20configurations%20except%20for%0A%20%20%20%20%60step_feature_alignment%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20H%2C%0A%20%20%20%20HistGradientBoostingRegressor%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20X_actual_train%2C%0A%20%20%20%20X_forecast%2C%0A%20%20%20%20X_future%2C%0A%20%20%20%20pl%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20results%20%3D%20%5B%5D%0A%20%20%20%20predictions%20%3D%20%7B%7D%0A%0A%20%20%20%20for%20_mode%20in%20%5B%22all%22%2C%20%22matched%22%2C%20%22cumulative%22%5D%3A%0A%20%20%20%20%20%20%20%20forecaster%20%3D%20PointReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DHistGradientBoostingRegressor(max_iter%3D50%2C%20max_depth%3D3%2C%20random_state%3D42)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20feature_transformer%3DLagTransformer(%5B1%2C%202%2C%203%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20reduction_strategy%3D%22direct%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20step_feature_alignment%3D_mode%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20forecaster.fit(%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dy_train%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20X_actual%3DX_actual_train%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20forecasting_horizon%3DH%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20X_future%3DX_future%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20X_forecast%3DX_forecast%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20pred%20%3D%20forecaster.predict()%0A%20%20%20%20%20%20%20%20predictions%5B_mode%5D%20%3D%20pred%0A%0A%20%20%20%20%20%20%20%20scorer%20%3D%20MeanAbsoluteError()%0A%20%20%20%20%20%20%20%20scorer.fit(y_train)%0A%20%20%20%20%20%20%20%20mae%20%3D%20scorer.score(y_test%2C%20pred)%0A%20%20%20%20%20%20%20%20results.append(%7B%22mode%22%3A%20_mode%2C%20%22mae%22%3A%20f%22%7Bmae%3A.4f%7D%22%7D)%0A%20%20%20%20%20%20%20%20print(f%22step_feature_alignment%3D%7B_mode%3A%3E12s%7D%20%20MAE%3A%20%7Bmae%3A.4f%7D%22)%0A%0A%20%20%20%20pl.DataFrame(results)%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%203.%20When%20to%20Use%20Each%20Mode%0A%0A%20%20%20%20-%20**%22all%22**%20(default)%3A%20each%20estimator%20can%20learn%20cross-step%0A%20%20%20%20%20%20patterns%20(e.g.%2C%20step%203%20weather%20forecast%20differs%20systematically%0A%20%20%20%20%20%20from%20step%201).%20Works%20well%20when%20step%20columns%20carry%20complementary%0A%20%20%20%20%20%20signal%20across%20the%20horizon.%0A%0A%20%20%20%20-%20**%22matched%22**%3A%20reduces%20feature%20dimensionality%20by%20giving%20each%0A%20%20%20%20%20%20estimator%20only%20its%20corresponding%20step%20column.%20Useful%20when%20step%0A%20%20%20%20%20%20columns%20are%20noisy%20and%20including%20irrelevant%20steps%20hurts%0A%20%20%20%20%20%20generalization.%0A%0A%20%20%20%20-%20**%22cumulative%22**%3A%20a%20middle%20ground.%20Early-step%20estimators%20see%0A%20%20%20%20%20%20fewer%20features%20(less%20noise)%2C%20later-step%20estimators%20accumulate%0A%20%20%20%20%20%20context.%20Useful%20when%20earlier%20steps%20provide%20reliable%20information%0A%20%20%20%20%20%20that%20later%20steps%20can%20build%20upon.%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%204.%20Inspect%20Feature%20Matrices%0A%0A%20%20%20%20Verify%20the%20difference%20by%20checking%20how%20many%20features%20each%20step%0A%20%20%20%20estimator%20receives.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20H%2C%0A%20%20%20%20HistGradientBoostingRegressor%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20X_actual_train%2C%0A%20%20%20%20X_forecast%2C%0A%20%20%20%20X_future%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20feature_counts%20%3D%20%7B%7D%0A%0A%20%20%20%20for%20_mode%20in%20%5B%22all%22%2C%20%22matched%22%2C%20%22cumulative%22%5D%3A%0A%20%20%20%20%20%20%20%20fc%20%3D%20PointReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DHistGradientBoostingRegressor(max_iter%3D50%2C%20max_depth%3D3%2C%20random_state%3D42)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20feature_transformer%3DLagTransformer(%5B1%2C%202%2C%203%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20reduction_strategy%3D%22direct%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20step_feature_alignment%3D_mode%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fc.fit(%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dy_train%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20X_actual%3DX_actual_train%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20forecasting_horizon%3DH%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20X_future%3DX_future%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20X_forecast%3DX_forecast%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%23%20Check%20feature%20count%20for%20first%20and%20last%20step%20estimators%0A%20%20%20%20%20%20%20%20n_features_first%20%3D%20fc.estimator_%5B0%5D.n_features_in_%0A%20%20%20%20%20%20%20%20n_features_last%20%3D%20fc.estimator_%5B-1%5D.n_features_in_%0A%20%20%20%20%20%20%20%20feature_counts%5B_mode%5D%20%3D%20(n_features_first%2C%20n_features_last)%0A%20%20%20%20%20%20%20%20print(f%22%7B_mode%3A%3E12s%7D%3A%20step%201%20has%20%7Bn_features_first%7D%20features%2C%20step%20%7BH%7D%20has%20%7Bn_features_last%7D%20features%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%20Next%20Steps%0A%0A%20%20%20%20-%20%5BUse%20Exogenous%20Features%5D(%2Fpages%2Fhow-to%2Fexogenous-features%2F)%20for%20the%20full%20guide%0A%20%20%20%20-%20%5BCompose%20Feature%20Pipelines%5D(%2Fpages%2Fhow-to%2Fcompose-feature-pipelines%2F)%20for%20related%20techniques%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
02727787a18bece68fe0f032b0452237