%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%20Multi-Column%20Forecasting%20with%20ColumnForecaster%0A%0A%20%20%20%20When%20a%20dataset%20contains%20multiple%20target%20columns%2C%20you%20may%20want%20to%20apply%0A%20%20%20%20**different%20forecasters**%20to%20each%20column%20(or%20column%20group).%20%5B%60ColumnForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.column_forecaster.ColumnForecaster%2F)%0A%20%20%20%20is%20yohou's%20answer%20to%20sklearn's%20%5B%60ColumnTransformer%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.column_transformer.ColumnTransformer%2F)%2C%20but%20for%20forecasters.%0A%0A%20%20%20%20**Prerequisites%3A**%20Familiarity%20with%20%5B%60SeasonalNaive%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.naive.SeasonalNaive%2F)%20and%20%5B%60PointReductionForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.reduction.PointReductionForecaster%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.linear_model%20import%20Ridge%0A%0A%20%20%20%20from%20yohou.compose%20import%20ColumnForecaster%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_electricity_demand%2C%20fetch_hospital%0A%20%20%20%20from%20yohou.metrics%20import%20MeanAbsoluteError%0A%20%20%20%20from%20yohou.plotting%20import%20plot_forecast%2C%20plot_time_series%0A%20%20%20%20from%20yohou.point%20import%20PointReductionForecaster%2C%20SeasonalNaive%0A%20%20%20%20from%20yohou.preprocessing%20import%20LagTransformer%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20ColumnForecaster%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%20Ridge%2C%0A%20%20%20%20%20%20%20%20SeasonalNaive%2C%0A%20%20%20%20%20%20%20%20fetch_electricity_demand%2C%0A%20%20%20%20%20%20%20%20fetch_hospital%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_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%20Multivariate%20Data%0A%0A%20%20%20%20The%20Electricity%20Demand%20dataset%20has%20demand%20columns%20for%20several%20Australian%20states.%0A%20%20%20%20We'll%20select%20Victoria%20and%20NSW%20demand%20as%20targets.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_electricity_demand%2C%20pl%2C%20plot_time_series)%3A%0A%20%20%20%20raw%20%3D%20fetch_electricity_demand().frame%0A%0A%20%20%20%20%23%20Resample%20to%20daily%20to%20keep%20the%20example%20fast%20(drop%20trailing%20all-null%20days)%0A%20%20%20%20y_full%20%3D%20(%0A%20%20%20%20%20%20%20%20raw%0A%20%20%20%20%20%20%20%20.group_by_dynamic(%22time%22%2C%20every%3D%221d%22)%0A%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22vic__demand%22).mean().alias(%22vic_demand%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22nsw__demand%22).mean().alias(%22nsw_demand%22)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.sort(%22time%22)%0A%20%20%20%20%20%20%20%20.drop_nulls()%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Use%20last%20365%20days%0A%20%20%20%20y_full%20%3D%20y_full.tail(365)%0A%0A%20%20%20%20from%20yohou.model_selection%20import%20train_test_split%0A%0A%20%20%20%20y_train%2C%20y_test%20%3D%20train_test_split(y_full%2C%20test_size%3D30)%0A%20%20%20%20forecasting_horizon%20%3D%20len(y_test)%0A%0A%20%20%20%20plot_time_series(y_full%2C%20title%3D%22Daily%20Electricity%20Demand%20(VIC%20%2B%20NSW)%22)%0A%20%20%20%20return%20forecasting_horizon%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.%20ColumnForecaster%20Basics%0A%0A%20%20%20%20Each%20entry%20is%20a%20%60(name%2C%20forecaster%2C%20columns)%60%20tuple.%0A%20%20%20%20Here%20we%20use%20%5B%60SeasonalNaive%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.naive.SeasonalNaive%2F)%20for%20vic_demand%20and%20a%20%5B%60PointReductionForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.reduction.PointReductionForecaster%2F)%20for%20nsw_demand.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20ColumnForecaster%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20SeasonalNaive%2C%0A%20%20%20%20forecasting_horizon%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20col_fc%20%3D%20ColumnForecaster(%0A%20%20%20%20%20%20%20%20forecasters%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22vic_demand%22%2C%20SeasonalNaive(seasonality%3D7)%2C%20%22vic_demand%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22nsw_demand%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PointReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DRidge()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20feature_transformer%3DLagTransformer(lag%3Dlist(range(1%2C%208)))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22nsw_demand%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20col_fc.fit(y_train%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20y_pred%20%3D%20col_fc.predict(forecasting_horizon%3Dforecasting_horizon)%0A%0A%20%20%20%20print(f%22Prediction%20columns%3A%20%7By_pred.columns%7D%22)%0A%20%20%20%20y_pred.head()%0A%20%20%20%20return%20col_fc%2C%20y_pred%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%5B%60plot_forecast%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.plotting.forecasting.plot_forecast%2F)%20displays%20each%20predicted%20column%20against%20its%20test%20actuals.%0A%20%20%20%20When%20multiple%20target%20columns%20are%20present%2C%20the%20plot%20overlays%20them%20in%20a%0A%20%20%20%20single%20figure.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%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%20title%3D%22ColumnForecaster%3A%20VIC%20Demand%20%2B%20NSW%20Demand%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%203.%20Accessing%20Sub-Forecasters%0A%0A%20%20%20%20After%20fitting%2C%20access%20individual%20forecasters%20by%20name%20via%20%60named_forecasters_%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(col_fc)%3A%0A%20%20%20%20for%20name%2C%20fc%2C%20cols%20in%20col_fc.forecasters_%3A%0A%20%20%20%20%20%20%20%20print(f%22%7Bname%7D%3A%20%7Btype(fc).__name__%7D%20%E2%86%92%20%7Bcols%7D%22)%0A%0A%20%20%20%20vic_demand_fc%20%3D%20col_fc.named_forecasters_%5B%22vic_demand%22%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%204.%20Remainder%20Handling%0A%0A%20%20%20%20By%20default%20%60remainder%3D%22drop%22%60%2C%20columns%20not%20assigned%20to%20any%20forecaster%20are%0A%20%20%20%20excluded%20from%20predictions.%20Pass%20a%20forecaster%20to%20handle%20them%20automatically.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20ColumnForecaster%2C%0A%20%20%20%20SeasonalNaive%2C%0A%20%20%20%20forecasting_horizon%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%20col_fc_rem%20%3D%20ColumnForecaster(%0A%20%20%20%20%20%20%20%20forecasters%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22vic_demand%22%2C%20SeasonalNaive(seasonality%3D7)%2C%20%22vic_demand%22)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20remainder%3DSeasonalNaive(seasonality%3D7)%2C%20%20%23%20fallback%20for%20nsw_demand%0A%20%20%20%20)%0A%0A%20%20%20%20col_fc_rem.fit(y_train%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20y_pred_rem%20%3D%20col_fc_rem.predict(forecasting_horizon%3Dforecasting_horizon)%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_rem%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20title%3D%22ColumnForecaster%20with%20Remainder%20(SeasonalNaive%20fallback)%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.%20Scaling%20to%20Many%20Columns%3A%20Hospital%20Dataset%0A%0A%20%20%20%20The%20**Hospital**%20dataset%20has%20767%20monthly%20patient%20count%20series.%0A%20%20%20%20We%20select%207%20to%20demonstrate%20%5B%60ColumnForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.column_forecaster.ColumnForecaster%2F)%20at%20scale%2C%20assigning%20a%0A%20%20%20%20dedicated%20forecaster%20to%20the%20primary%20series%20and%20using%20%60remainder%60%20for%20the%20rest.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_hospital%2C%20plot_time_series)%3A%0A%20%20%20%20hosp%20%3D%20fetch_hospital().frame%0A%0A%20%20%20%20%23%20Select%20first%207%20series%20and%20rename%20to%20remove%20__%20prefix%20for%20multivariate%20use%0A%20%20%20%20_selected%20%3D%20%5Bf%22T%7Bi%7D__patients%22%20for%20i%20in%20range(1%2C%208)%5D%0A%20%20%20%20_renamed%20%3D%20%7Bf%22T%7Bi%7D__patients%22%3A%20f%22T%7Bi%7D_patients%22%20for%20i%20in%20range(1%2C%208)%7D%0A%20%20%20%20hosp_sub%20%3D%20hosp.select(%22time%22%2C%20*_selected).rename(_renamed).drop_nulls()%0A%0A%20%20%20%20hosp_split%20%3D%20len(hosp_sub)%20-%2012%20%20%23%2012%20months%20test%0A%20%20%20%20hosp_train%20%3D%20hosp_sub.head(hosp_split)%0A%20%20%20%20hosp_test%20%3D%20hosp_sub.tail(len(hosp_sub)%20-%20hosp_split)%0A%20%20%20%20hosp_horizon%20%3D%20len(hosp_test)%0A%0A%20%20%20%20print(f%22Hospital%20columns%3A%20%7Bhosp_sub.columns%7D%22)%0A%20%20%20%20print(f%22Train%3A%20%7Blen(hosp_train)%7D%2C%20Test%3A%20%7Blen(hosp_test)%7D%22)%0A%20%20%20%20plot_time_series(hosp_sub%2C%20title%3D%22Hospital%20Patient%20Counts%20(7%20Series)%22)%0A%20%20%20%20return%20hosp_horizon%2C%20hosp_test%2C%20hosp_train%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20ColumnForecaster%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20SeasonalNaive%2C%0A%20%20%20%20hosp_horizon%2C%0A%20%20%20%20hosp_test%2C%0A%20%20%20%20hosp_train%2C%0A)%3A%0A%20%20%20%20%23%20Dedicated%20Ridge%20forecaster%20for%20T1_patients%20(primary%20target)%0A%20%20%20%20%23%20SeasonalNaive(12mo)%20as%20remainder%20for%20T2..T7_patients%0A%20%20%20%20col_fc_hosp%20%3D%20ColumnForecaster(%0A%20%20%20%20%20%20%20%20forecasters%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22primary%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PointReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DRidge()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20feature_transformer%3DLagTransformer(lag%3D%5B1%2C%202%2C%203%2C%2012%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22T1_patients%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20remainder%3DSeasonalNaive(seasonality%3D12)%2C%20%20%23%20yearly%20cycle%20for%20remaining%20columns%0A%20%20%20%20)%0A%0A%20%20%20%20col_fc_hosp.fit(hosp_train%2C%20forecasting_horizon%3Dhosp_horizon)%0A%20%20%20%20hosp_pred%20%3D%20col_fc_hosp.predict(forecasting_horizon%3Dhosp_horizon)%0A%0A%20%20%20%20print(f%22Hospital%20prediction%20columns%3A%20%7Bhosp_pred.columns%7D%22)%0A%20%20%20%20print(f%22Remainder%20columns%3A%20%7Bcol_fc_hosp.remainder_cols_%7D%22)%0A%0A%20%20%20%20%23%20Score%0A%20%20%20%20hosp_mae%20%3D%20MeanAbsoluteError()%0A%20%20%20%20hosp_mae.fit(hosp_test)%0A%20%20%20%20hosp_score%20%3D%20hosp_mae.score(hosp_test%2C%20hosp_pred)%0A%20%20%20%20print(f%22%5CnHospital%20Multi-column%20MAE%3A%20%7Bhosp_score%3A.2f%7D%22)%0A%20%20%20%20return%20(hosp_pred%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%5B%60plot_forecast%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.plotting.forecasting.plot_forecast%2F)%20with%20%60columns%3D%5B%22T1_patients%22%5D%60%20shows%20just%20the%20primary%20series%0A%20%20%20%20predicted%20by%20the%20dedicated%20Ridge%20forecaster%2C%20while%20the%20remaining%20columns%0A%20%20%20%20use%20%5B%60SeasonalNaive%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.naive.SeasonalNaive%2F)%20via%20the%20%60remainder%60%20parameter.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(hosp_pred%2C%20hosp_test%2C%20hosp_train%2C%20plot_forecast)%3A%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20hosp_test%2C%0A%20%20%20%20%20%20%20%20hosp_pred%2C%0A%20%20%20%20%20%20%20%20y_train%3Dhosp_train%2C%0A%20%20%20%20%20%20%20%20title%3D%22Hospital%3A%20ColumnForecaster%20(Ridge%20for%20T1%2C%20SeasonalNaive%20for%20rest)%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**Feature%20forecasting**%3A%20See%20%5B%60feature_forecasting.py%60%5D(%2Fexamples%2Fforecasting-models%2Ffeature_forecasting%2F)%20for%20%5B%60ForecastedFeatureForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.forecasted_feature_forecaster.ForecastedFeatureForecaster%2F)%0A%20%20%20%20-%20**Decomposition**%3A%20See%20%5BStationarity%5D(%2Fexamples%2F%23stationarity)%20for%20%5B%60DecompositionPipeline%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.decomposition_pipeline.DecompositionPipeline%2F)%0A%20%20%20%20-%20**Panel%20data**%3A%20See%20%60examples%2Fpanel_reduction.py%60%20for%20panel%20forecasting%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
29d22b85fbea7d5579e7d10dacb5ff04