%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%22numpy%22%2C%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%20Run%20a%20Multi-Metric%20Search%0A%0A%20%20%20%20Pass%20multiple%20scorers%20to%20%60OptunaSearchCV%60%20and%20choose%20which%20metric%20drives%20model%20selection%20with%20the%20%60refit%60%20parameter.%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%20numpy%20as%20np%0A%20%20%20%20import%20optuna%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20from%20optuna.distributions%20import%20CategoricalDistribution%2C%20FloatDistribution%0A%20%20%20%20from%20sklearn.linear_model%20import%20Ridge%0A%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_electricity_demand%0A%20%20%20%20from%20yohou.metrics%20import%20MeanAbsoluteError%2C%20MeanSquaredError%2C%20RootMeanSquaredError%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_correlation_heatmap%2C%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_model_comparison_bar%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%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%20CategoricalDistribution%2C%0A%20%20%20%20%20%20%20%20FloatDistribution%2C%0A%20%20%20%20%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20%20%20%20%20MeanSquaredError%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%20RootMeanSquaredError%2C%0A%20%20%20%20%20%20%20%20Sampler%2C%0A%20%20%20%20%20%20%20%20fetch_electricity_demand%2C%0A%20%20%20%20%20%20%20%20np%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_correlation_heatmap%2C%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_model_comparison_bar%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%20Data%0A%0A%20%20%20%20The%20Electricity%20Demand%20dataset%20contains%2030-minute%20measurements%20of%0A%20%20%20%20electricity%20demand%20across%20Australian%20states.%20We%20select%20three%20state%20columns%0A%20%20%20%20and%20rename%20them%20for%20multivariate%20forecasting%2C%20then%20use%20a%20subset%20to%20keep%0A%20%20%20%20the%20search%20fast.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_electricity_demand)%3A%0A%20%20%20%20y_full%20%3D%20fetch_electricity_demand().frame%0A%20%20%20%20y_all%20%3D%20(%0A%20%20%20%20%20%20%20%20y_full.select(%5B%22time%22%2C%20%22nsw__demand%22%2C%20%22vic__demand%22%2C%20%22qun__demand%22%5D)%0A%20%20%20%20%20%20%20%20.rename(%7B%22nsw__demand%22%3A%20%22nsw_demand%22%2C%20%22vic__demand%22%3A%20%22vic_demand%22%2C%20%22qun__demand%22%3A%20%22qun_demand%22%7D)%0A%20%20%20%20%20%20%20%20.head(1000)%0A%20%20%20%20)%0A%20%20%20%20y_all.head()%0A%20%20%20%20return%20(y_all%2C)%0A%0A%0A%40app.cell%0Adef%20_(plot_time_series%2C%20y_all)%3A%0A%20%20%20%20plot_time_series(y_all%2C%20title%3D%22Electricity%20Demand%3A%20NSW%2C%20VIC%2C%20QUN%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_correlation_heatmap%2C%20y_all)%3A%0A%20%20%20%20plot_correlation_heatmap(y_all%2C%20title%3D%22Feature%20Correlation%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.%20Define%20Multi-Metric%20Scoring%0A%0A%20%20%20%20Pass%20a%20dictionary%20of%20scorers%20to%20%60scoring%60%20and%20set%20%60refit%60%20to%20the%20metric%0A%20%20%20%20that%20should%20drive%20model%20selection.%20Set%20%60return_train_score%3DTrue%60%20if%20you%0A%20%20%20%20need%20overfitting%20diagnostics.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(y_all)%3A%0A%20%20%20%20y_train%20%3D%20y_all.head(800)%0A%20%20%20%20y_test%20%3D%20y_all.tail(200)%0A%20%20%20%20return%20y_test%2C%20y_train%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20CategoricalDistribution%2C%0A%20%20%20%20FloatDistribution%2C%0A%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20MeanSquaredError%2C%0A%20%20%20%20OptunaSearchCV%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20RootMeanSquaredError%2C%0A%20%20%20%20Sampler%2C%0A%20%20%20%20optuna%2C%0A)%3A%0A%20%20%20%20search%20%3D%20OptunaSearchCV(%0A%20%20%20%20%20%20%20%20forecaster%3DPointReductionForecaster(estimator%3DRidge())%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%22estimator__fit_intercept%22%3A%20CategoricalDistribution(%5BTrue%2C%20False%5D)%2C%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20scoring%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mae%22%3A%20MeanAbsoluteError()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22rmse%22%3A%20RootMeanSquaredError()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mse%22%3A%20MeanSquaredError()%2C%0A%20%20%20%20%20%20%20%20%7D%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%3D15%2C%0A%20%20%20%20%20%20%20%20refit%3D%22mae%22%2C%0A%20%20%20%20%20%20%20%20cv%3D3%2C%0A%20%20%20%20%20%20%20%20return_train_score%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%203.%20Run%20the%20Search%0A%0A%20%20%20%20Fit%20the%20search.%20All%20three%20metrics%20are%20evaluated%20per%20trial%3B%20%60refit%3D%22mae%22%60%0A%20%20%20%20determines%20which%20one%20selects%20the%20best%20model.%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%20(by%20MAE)%3A**%20%60%7Bsearch.best_params_%7D%60%0A%0A%20%20%20%20%20%20%20%20**Best%20MAE%3A**%20%60%7Bsearch.cv_results_%5B'mean_test_mae'%5D%5Bsearch.best_index_%5D%3A.4f%7D%60%0A%0A%20%20%20%20%20%20%20%20**Best%20RMSE%3A**%20%60%7Bsearch.cv_results_%5B'mean_test_rmse'%5D%5Bsearch.best_index_%5D%3A.4f%7D%60%0A%0A%20%20%20%20%20%20%20%20**Best%20MSE%3A**%20%60%7Bsearch.cv_results_%5B'mean_test_mse'%5D%5Bsearch.best_index_%5D%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(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.%20Compare%20Metrics%0A%0A%20%20%20%20Review%20per-trial%20scores%20and%20independent%20rankings%20for%20each%20metric.%0A%20%20%20%20%22%22%22)%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%22mean_test_mae%22%3A%20search.cv_results_%5B%22mean_test_mae%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mean_test_rmse%22%3A%20search.cv_results_%5B%22mean_test_rmse%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mean_test_mse%22%3A%20search.cv_results_%5B%22mean_test_mse%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22rank_mae%22%3A%20search.cv_results_%5B%22rank_test_mae%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22rank_rmse%22%3A%20search.cv_results_%5B%22rank_test_rmse%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mean_train_mae%22%3A%20search.cv_results_%5B%22mean_train_mae%22%5D%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20).sort(%22rank_mae%22)%0A%20%20%20%20results_df%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%20Compare%20the%20best%20model's%20test%20scores%20across%20all%20three%20metrics%20with%20a%20bar%20chart.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plot_model_comparison_bar%2C%20search)%3A%0A%20%20%20%20best_by_mae_idx%20%3D%20search.best_index_%0A%20%20%20%20best_by_rmse_idx%20%3D%20int(np.argmin(search.cv_results_%5B%22rank_test_rmse%22%5D))%0A%0A%20%20%20%20comparison%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22Best%20by%20MAE%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22MAE%22%3A%20abs(search.cv_results_%5B%22mean_test_mae%22%5D%5Bbest_by_mae_idx%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22RMSE%22%3A%20abs(search.cv_results_%5B%22mean_test_rmse%22%5D%5Bbest_by_mae_idx%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22MSE%22%3A%20abs(search.cv_results_%5B%22mean_test_mse%22%5D%5Bbest_by_mae_idx%5D)%2C%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22Best%20by%20RMSE%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22MAE%22%3A%20abs(search.cv_results_%5B%22mean_test_mae%22%5D%5Bbest_by_rmse_idx%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22RMSE%22%3A%20abs(search.cv_results_%5B%22mean_test_rmse%22%5D%5Bbest_by_rmse_idx%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22MSE%22%3A%20abs(search.cv_results_%5B%22mean_test_mse%22%5D%5Bbest_by_rmse_idx%5D)%2C%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%7D%0A%20%20%20%20plot_model_comparison_bar(%0A%20%20%20%20%20%20%20%20comparison%2C%0A%20%20%20%20%20%20%20%20group_by%3D%22model%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Best%20by%20MAE%20vs%20Best%20by%20RMSE%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%20with%20the%20Best%20Model%0A%0A%20%20%20%20Generate%20predictions%20and%20compare%20visually%20against%20the%20held-out%20test%20set.%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%3D48%2C%0A%20%20%20%20%20%20%20%20title%3D%22Multi-Metric%20Best%20Forecast%20(refit%3DMAE)%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%20Next%20Steps%0A%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-%20%5BHow%20to%20Tune%20Composed%20Forecasters%5D(%2Fexamples%2Fcomposed_tuning%2F)%3A%20tune%20nested%20pipelines%20with%20feature%20transformers%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
4f0292e789236c7987cc46e3acdf56d1