%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%22optuna%22%2C%0A%23%20%20%20%20%20%22polars%22%2C%0A%23%20%20%20%20%20%22scikit-learn%22%2C%0A%23%20%20%20%20%20%22yohou%22%2C%0A%23%20%20%20%20%20%22yohou-optuna%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.5%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%20Tune%20Composed%20Forecasters%0A%0A%20%20%20%20Tune%20nested%20parameters%20across%20a%20%60PointReductionForecaster%60%20%2B%20%60LagTransformer%60%20pipeline%20using%20%60__%60%20parameter%20routing.%0A%0A%20%20%20%20**Prerequisites**%3A%20familiarity%20with%20%5B%60OptunaSearchCV%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou_optuna.search.OptunaSearchCV%2F)%20(see%20%5BOptunaSearchCV%20Quickstart%5D(%2Fexamples%2Foptuna_search%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%20optuna%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20from%20optuna.distributions%20import%20FloatDistribution%2C%20IntDistribution%0A%20%20%20%20from%20sklearn.linear_model%20import%20Ridge%0A%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_sunspot%0A%20%20%20%20from%20yohou.metrics%20import%20MeanAbsoluteError%0A%20%20%20%20from%20yohou.model_selection%20import%20ExpandingWindowSplitter%0A%20%20%20%20from%20yohou.plotting%20import%20(%0A%20%20%20%20%20%20%20%20plot_autocorrelation%2C%0A%20%20%20%20%20%20%20%20plot_cv_results_scatter%2C%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_residuals%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%20from%20yohou_optuna%20import%20OptunaSearchCV%2C%20Sampler%0A%0A%20%20%20%20optuna.logging.set_verbosity(optuna.logging.WARNING)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20ExpandingWindowSplitter%2C%0A%20%20%20%20%20%20%20%20FloatDistribution%2C%0A%20%20%20%20%20%20%20%20IntDistribution%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%20OptunaSearchCV%2C%0A%20%20%20%20%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20%20%20%20%20Ridge%2C%0A%20%20%20%20%20%20%20%20Sampler%2C%0A%20%20%20%20%20%20%20%20fetch_sunspot%2C%0A%20%20%20%20%20%20%20%20optuna%2C%0A%20%20%20%20%20%20%20%20pl%2C%0A%20%20%20%20%20%20%20%20plot_autocorrelation%2C%0A%20%20%20%20%20%20%20%20plot_cv_results_scatter%2C%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_residuals%2C%0A%20%20%20%20%20%20%20%20plot_time_series%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.%20Load%20the%20Sunspots%20Data%0A%0A%20%20%20%20Load%20a%20subset%20of%20the%20Sunspots%20dataset%20(2820%20monthly%20observations)%20and%20split%20into%20train%2Ftest.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_sunspot%2C%20plot_time_series)%3A%0A%20%20%20%20y_full%20%3D%20fetch_sunspot().frame%0A%20%20%20%20y%20%3D%20y_full.tail(500)%0A%20%20%20%20plot_time_series(y%2C%20title%3D%22Sunspot%20Activity%20(Last%20500%20Months)%22)%0A%20%20%20%20return%20(y%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%202.%20Check%20the%20Autocorrelation%0A%0A%20%20%20%20Plot%20the%20autocorrelation%20to%20identify%20which%20lags%20to%20include%20in%20the%20search%20range.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_autocorrelation%2C%20y)%3A%0A%20%20%20%20plot_autocorrelation(y%2C%20max_lags%3D40%2C%20title%3D%22Autocorrelation%20of%20Sunspot%20Activity%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%203.%20Compose%20the%20Forecaster%20and%20Define%20the%20Search%20Space%0A%0A%20%20%20%20Add%20a%20%60LagTransformer%60%20as%20the%20%60feature_transformer%60%20and%20define%20distributions%0A%20%20%20%20for%20both%20%60estimator__alpha%60%20and%20%60feature_transformer__lag%60.%20The%20%60__%60%20routing%0A%20%20%20%20addresses%20parameters%20inside%20the%20composed%20pipeline.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(y)%3A%0A%20%20%20%20y_train%20%3D%20y.head(400)%0A%20%20%20%20y_test%20%3D%20y.tail(24)%0A%20%20%20%20return%20y_test%2C%20y_train%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20ExpandingWindowSplitter%2C%0A%20%20%20%20FloatDistribution%2C%0A%20%20%20%20IntDistribution%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20OptunaSearchCV%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20Sampler%2C%0A%20%20%20%20optuna%2C%0A)%3A%0A%20%20%20%20forecaster%20%3D%20PointReductionForecaster(%0A%20%20%20%20%20%20%20%20estimator%3DRidge()%2C%0A%20%20%20%20%20%20%20%20feature_transformer%3DLagTransformer(lag%3D6)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20search%20%3D%20OptunaSearchCV(%0A%20%20%20%20%20%20%20%20forecaster%3Dforecaster%2C%0A%20%20%20%20%20%20%20%20param_distributions%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22estimator__alpha%22%3A%20FloatDistribution(0.001%2C%20100.0%2C%20log%3DTrue)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22feature_transformer__lag%22%3A%20IntDistribution(3%2C%2024)%2C%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20scoring%3DMeanAbsoluteError()%2C%0A%20%20%20%20%20%20%20%20sampler%3DSampler(sampler%3Doptuna.samplers.TPESampler%2C%20seed%3D42)%2C%0A%20%20%20%20%20%20%20%20n_trials%3D20%2C%0A%20%20%20%20%20%20%20%20cv%3DExpandingWindowSplitter(n_splits%3D3%2C%20test_size%3D24)%2C%0A%20%20%20%20%20%20%20%20refit%3DTrue%2C%0A%20%20%20%20%20%20%20%20verbose%3D0%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(search%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%204.%20Run%20the%20Search%20and%20Inspect%20Results%0A%0A%20%20%20%20Fit%20the%20search%20and%20review%20per-trial%20scores.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(search%2C%20y_train)%3A%0A%20%20%20%20search.fit(y_train%2C%20forecasting_horizon%3D24)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20search)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%20%20%20%20**Best%20parameters%3A**%20%60%7Bsearch.best_params_%7D%60%0A%0A%20%20%20%20%20%20%20%20**Best%20MAE%3A**%20%60%7Bsearch.best_score_%3A.4f%7D%60%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pl%2C%20search)%3A%0A%20%20%20%20results_df%20%3D%20pl.DataFrame(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22trial%22%3A%20list(range(len(search.cv_results_%5B%22params%22%5D)))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22alpha%22%3A%20%5Bp.get(%22estimator__alpha%22%2C%20None)%20for%20p%20in%20search.cv_results_%5B%22params%22%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22lag%22%3A%20%5Bp.get(%22feature_transformer__lag%22%2C%20None)%20for%20p%20in%20search.cv_results_%5B%22params%22%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mean_test_score%22%3A%20search.cv_results_%5B%22mean_test_score%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22rank%22%3A%20search.cv_results_%5B%22rank_test_score%22%5D%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20).sort(%22rank%22)%0A%20%20%20%20results_df%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_cv_results_scatter%2C%20search)%3A%0A%20%20%20%20plot_cv_results_scatter(%0A%20%20%20%20%20%20%20%20search.cv_results_%2C%0A%20%20%20%20%20%20%20%20param_name%3D%22estimator__alpha%22%2C%0A%20%20%20%20%20%20%20%20higher_is_better%3DFalse%2C%0A%20%20%20%20%20%20%20%20title%3D%22CV%20Score%20vs%20Regularization%20Strength%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_cv_results_scatter%2C%20search)%3A%0A%20%20%20%20plot_cv_results_scatter(%0A%20%20%20%20%20%20%20%20search.cv_results_%2C%0A%20%20%20%20%20%20%20%20param_name%3D%22feature_transformer__lag%22%2C%0A%20%20%20%20%20%20%20%20higher_is_better%3DFalse%2C%0A%20%20%20%20%20%20%20%20title%3D%22CV%20Score%20vs%20Number%20of%20Lags%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%205.%20Forecast%20and%20Check%20Residuals%0A%0A%20%20%20%20Generate%20predictions%20with%20the%20best%20forecaster%20and%20check%20the%20residuals.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(search)%3A%0A%20%20%20%20y_pred%20%3D%20search.predict(forecasting_horizon%3D24)%0A%20%20%20%20y_pred%0A%20%20%20%20return%20(y_pred%2C)%0A%0A%0A%40app.cell%0Adef%20_(plot_forecast%2C%20y_pred%2C%20y_test%2C%20y_train)%3A%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%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20n_history%3D60%2C%0A%20%20%20%20%20%20%20%20title%3D%22Sunspot%20Forecast%3A%20Best%20Composed%20Model%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_residuals%2C%20y_pred%2C%20y_test)%3A%0A%20%20%20%20plot_residuals(%0A%20%20%20%20%20%20%20%20y_pred%2C%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20title%3D%22Forecast%20Residuals%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%20Key%20Takeaways%0A%0A%20%20%20%20-%20**Nested%20parameter%20routing**%20uses%20%60__%60%20to%20address%20parameters%20inside%20composed%20pipelines%20(e.g.%2C%20%60estimator__alpha%60%2C%20%60feature_transformer__lag%60)%0A%20%20%20%20-%20**%60LagTransformer%60**%20creates%20lag-based%20features%20automatically%2C%20turning%20time%20series%20forecasting%20into%20tabular%20regression%0A%20%20%20%20-%20**Autocorrelation%20analysis**%20helps%20motivate%20the%20range%20of%20lags%20to%20search%20over%0A%20%20%20%20-%20**%60ExpandingWindowSplitter%60**%20provides%20time-respecting%20cross-validation%20that%20avoids%20data%20leakage%0A%20%20%20%20-%20**Residual%20diagnostics**%20with%20%60plot_residuals%60%20reveal%20systematic%20prediction%20errors%0A%0A%20%20%20%20%23%23%20Next%20Steps%0A%0A%20%20%20%20-%20%5BHow%20to%20Run%20a%20Multi-Metric%20Search%5D(%2Fexamples%2Fmulti_metric_search%2F)%3A%20evaluate%20multiple%20metrics%20simultaneously%0A%20%20%20%20-%20%5BHow%20to%20Visualize%20Search%20Results%5D(%2Fexamples%2Fsearch_visualization%2F)%20-%20Optuna's%20optimization%20history%20and%20parameter%20importance%20plots%0A%20%20%20%20-%20%5BHow%20to%20Tune%20on%20Panel%20Data%5D(%2Fexamples%2Fpanel_tuning%2F)%3A%20tune%20forecasters%20on%20grouped%20time%20series%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
1ac8c13de617b60cb0bf30c5138bfcb4