%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%20Composition%20Patterns%20for%20Panel%20Data%0A%0A%20%20%20%20Yohou's%20composition%20meta-estimators%20automatically%20handle%20panel%20data%20by%0A%20%20%20%20decomposing%20the%20panel%20into%20groups%2C%20applying%20per-group%20transformations%0A%20%20%20%20and%20models%2C%20and%20reassembling%20the%20results.%20This%20notebook%20demonstrates%0A%20%20%20%20all%20major%20composition%20patterns%20with%20panel%20data.%0A%0A%20%20%20%20This%20notebook%20shows%20how%20to%20combine%20ColumnForecaster%2C%20FeaturePipeline%2C%20FeatureUnion%2C%20and%20DecompositionPipeline%20on%20panel%20data%20with%20per-group%20scoring%20on%20KDD%20Cup%20air%20quality.%0A%0A%20%20%20%20**Prerequisites%3A**%20Panel%20data%20conventions%20(%60__%60%20separator)%20and%20basic%20forecasting%0A%20%20%20%20(see%20%60examples%2Fquickstart.py%60).%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%20(%0A%20%20%20%20%20%20%20%20ColumnForecaster%2C%0A%20%20%20%20%20%20%20%20DecompositionPipeline%2C%0A%20%20%20%20%20%20%20%20FeaturePipeline%2C%0A%20%20%20%20%20%20%20%20FeatureUnion%2C%0A%20%20%20%20)%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_kdd_cup%0A%20%20%20%20from%20yohou.metrics%20import%20MeanAbsoluteError%0A%20%20%20%20from%20yohou.model_selection%20import%20train_test_split%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%2C%20RollingStatisticsTransformer%2C%20StandardScaler%0A%20%20%20%20from%20yohou.stationarity%20import%20PatternSeasonalityForecaster%2C%20PolynomialTrendForecaster%0A%20%20%20%20from%20yohou.utils.panel%20import%20inspect_panel%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%20DecompositionPipeline%2C%0A%20%20%20%20%20%20%20%20FeatureUnion%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%20PolynomialTrendForecaster%2C%0A%20%20%20%20%20%20%20%20Ridge%2C%0A%20%20%20%20%20%20%20%20RollingStatisticsTransformer%2C%0A%20%20%20%20%20%20%20%20SeasonalNaive%2C%0A%20%20%20%20%20%20%20%20fetch_kdd_cup%2C%0A%20%20%20%20%20%20%20%20inspect_panel%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%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.%20Panel%20Data%20Recap%0A%0A%20%20%20%20We%20load%20the%20KDD%20Cup%202018%20air%20quality%20dataset%20with%203%20Beijing%20stations%2C%0A%20%20%20%20each%20monitoring%206%20pollutants.%20The%20%60station__measurement%60%20naming%0A%20%20%20%20convention%20is%20automatically%20detected%20as%20panel%20groups.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_kdd_cup%2C%20inspect_panel%2C%20mo%2C%20train_test_split)%3A%0A%20%20%20%20_bunch%20%3D%20fetch_kdd_cup(n_groups%3D3)%0A%20%20%20%20store%20%3D%20_bunch.frame.drop_nulls().tail(300)%0A%20%20%20%20_globals%2C%20groups%20%3D%20inspect_panel(store)%0A%20%20%20%20target_cols%20%3D%20%5Bc%20for%20c%20in%20store.columns%20if%20c%20!%3D%20%22time%22%5D%0A%0A%20%20%20%20y_train%2C%20y_test%20%3D%20train_test_split(store%2C%20test_size%3D0.15)%0A%20%20%20%20horizon%20%3D%20len(y_test)%0A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22**Groups**%3A%20%7Blist(groups.keys())%7D%5Cn%5Cn%22%0A%20%20%20%20%20%20%20%20f%22**Train**%3A%20%7Blen(y_train)%7D%20rows%2C%20**Test**%3A%20%7Blen(y_test)%7D%20rows%5Cn%5Cn%22%0A%20%20%20%20%20%20%20%20f%223%20stations%20%C3%97%206%20measurements%20from%20KDD%20Cup%202018%22%0A%20%20%20%20)%0A%20%20%20%20return%20groups%2C%20horizon%2C%20store%2C%20target_cols%2C%20y_test%2C%20y_train%0A%0A%0A%40app.cell%0Adef%20_(plot_time_series%2C%20store)%3A%0A%20%20%20%20plot_time_series(store%2C%20title%3D%22KDD%20Cup%202018%3A%20Air%20Quality%20Panel%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.%20Global%20Model%0A%0A%20%20%20%20A%20single%20%5B%60PointReductionForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.reduction.PointReductionForecaster%2F)%20fits%20one%20model%20per%20group%0A%20%20%20%20automatically%20when%20it%20detects%20panel%20data.%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%2C%20horizon%2C%20y_train)%3A%0A%20%20%20%20fc_global%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%2024%5D)%2C%0A%20%20%20%20)%0A%20%20%20%20fc_global.fit(y_train%2C%20forecasting_horizon%3Dhorizon)%0A%20%20%20%20y_pred_global%20%3D%20fc_global.predict(forecasting_horizon%3Dhorizon)%0A%20%20%20%20return%20(y_pred_global%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)%20shows%20the%20global%20model%20predictions%20for%20the%20first%0A%20%20%20%20two%20panel%20groups.%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_global%2C%20y_test%2C%20y_train)%3A%0A%20%20%20%20_groups%20%3D%20sorted(%7Bc.split(%22__%22)%5B0%5D%20for%20c%20in%20y_train.columns%20if%20%22__%22%20in%20c%7D)%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_global%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%20groups%3D_groups%5B%3A2%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22Global%20Model%3A%20First%202%20Stations%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.%20ColumnForecaster%3A%20Per-Group%20Models%0A%0A%20%20%20%20%5B%60ColumnForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.column_forecaster.ColumnForecaster%2F)%20assigns%20different%20forecasters%20to%20different%20column%0A%20%20%20%20subsets.%20With%20panel%20data%2C%20group%20each%20station's%20measurements%20with%20its%0A%20%20%20%20own%20specialised%20model.%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%20groups%2C%0A%20%20%20%20horizon%2C%0A%20%20%20%20target_cols%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20%23%20Assign%20a%20different%20forecaster%20to%20each%20station%0A%20%20%20%20_group_names%20%3D%20sorted(groups.keys())%0A%20%20%20%20_g1_cols%20%3D%20%5Bc%20for%20c%20in%20target_cols%20if%20c.startswith(f%22%7B_group_names%5B0%5D%7D__%22)%5D%0A%20%20%20%20_g2_cols%20%3D%20%5Bc%20for%20c%20in%20target_cols%20if%20c.startswith(f%22%7B_group_names%5B1%5D%7D__%22)%5D%0A%20%20%20%20_g3_cols%20%3D%20%5Bc%20for%20c%20in%20target_cols%20if%20c.startswith(f%22%7B_group_names%5B2%5D%7D__%22)%5D%0A%0A%20%20%20%20fc_column%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%22station_1_ridge%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(alpha%3D1.0)%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%2024%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_g1_cols%2C%0A%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(%22station_2_naive%22%2C%20SeasonalNaive(seasonality%3D24)%2C%20_g2_cols)%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%22station_3_ridge%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(alpha%3D10.0)%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%2024%2C%2048%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_g3_cols%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%20%20%20%20fc_column.fit(y_train%2C%20forecasting_horizon%3Dhorizon)%0A%20%20%20%20y_pred_column%20%3D%20fc_column.predict(forecasting_horizon%3Dhorizon)%0A%20%20%20%20return%20(y_pred_column%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)%20shows%20the%20%5B%60ColumnForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.column_forecaster.ColumnForecaster%2F)%20predictions%2C%20where%20each%0A%20%20%20%20station%20is%20handled%20by%20a%20different%20forecaster.%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_column%2C%20y_test%2C%20y_train)%3A%0A%20%20%20%20_groups%20%3D%20sorted(%7Bc.split(%22__%22)%5B0%5D%20for%20c%20in%20y_train.columns%20if%20%22__%22%20in%20c%7D)%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_column%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%20groups%3D_groups%5B%3A2%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22ColumnForecaster%3A%20Different%20Model%20Per%20Station%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%204.%20FeaturePipeline%20%2B%20FeatureUnion%0A%0A%20%20%20%20Build%20rich%20feature%20sets%20by%20combining%20lag%20features%20and%20rolling%20statistics%0A%20%20%20%20in%20parallel%20via%20%5B%60FeatureUnion%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.feature_union.FeatureUnion%2F)%2C%20then%20use%20as%20%60feature_transformer%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%20FeatureUnion%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20RollingStatisticsTransformer%2C%0A%20%20%20%20horizon%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_union%20%3D%20FeatureUnion(%0A%20%20%20%20%20%20%20%20transformer_list%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22lags%22%2C%20LagTransformer(lag%3D%5B1%2C%2024%5D))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22rolling%22%2C%20RollingStatisticsTransformer(window_size%3D24%2C%20statistics%3D%5B%22mean%22%2C%20%22std%22%5D))%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20fc_union%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%3D_union%2C%0A%20%20%20%20)%0A%20%20%20%20fc_union.fit(y_train%2C%20forecasting_horizon%3Dhorizon)%0A%20%20%20%20_y_pred_union%20%3D%20fc_union.predict(forecasting_horizon%3Dhorizon)%0A%0A%20%20%20%20_groups%20%3D%20sorted(%7Bc.split(%22__%22)%5B0%5D%20for%20c%20in%20y_train.columns%20if%20%22__%22%20in%20c%7D)%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_union%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%20groups%3D_groups%5B%3A2%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22FeatureUnion%20(Lags%20%2B%20Rolling)%20on%20Panel%20Data%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.%20DecompositionPipeline%0A%0A%20%20%20%20Decompose%20each%20panel%20group%20into%20trend%20%2B%20residual%20automatically.%0A%20%20%20%20The%20pipeline%20fits%20a%20separate%20trend%20model%20per%20group.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20DecompositionPipeline%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20PolynomialTrendForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20horizon%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_decomp%20%3D%20DecompositionPipeline(%0A%20%20%20%20%20%20%20%20forecasters%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22trend%22%2C%20PolynomialTrendForecaster(degree%3D1))%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%22residual%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(alpha%3D1.0)%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%2024%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)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20store_residuals%3DTrue%2C%0A%20%20%20%20)%0A%20%20%20%20fc_decomp.fit(y_train%2C%20forecasting_horizon%3Dhorizon)%0A%20%20%20%20_y_pred_decomp%20%3D%20fc_decomp.predict(forecasting_horizon%3Dhorizon)%0A%0A%20%20%20%20_groups%20%3D%20sorted(%7Bc.split(%22__%22)%5B0%5D%20for%20c%20in%20y_train.columns%20if%20%22__%22%20in%20c%7D)%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_decomp%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%20groups%3D_groups%5B%3A2%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22DecompositionPipeline%20(Trend%20%2B%20Residual)%20on%20Panel%20Data%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%206.%20Nested%20Pipeline%0A%0A%20%20%20%20Combine%20decomposition%20with%20feature%20engineering%3A%20remove%20trend%20first%2C%0A%20%20%20%20then%20use%20%5B%60FeatureUnion%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.feature_union.FeatureUnion%2F)%20for%20lag%20%2B%20rolling%20features%20on%20the%20residual.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20DecompositionPipeline%2C%0A%20%20%20%20FeatureUnion%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20PolynomialTrendForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20RollingStatisticsTransformer%2C%0A%20%20%20%20horizon%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_union_nested%20%3D%20FeatureUnion(%0A%20%20%20%20%20%20%20%20transformer_list%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22lags%22%2C%20LagTransformer(lag%3D%5B1%2C%2024%5D))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22rolling%22%2C%20RollingStatisticsTransformer(window_size%3D24%2C%20statistics%3D%22mean%22))%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20fc_nested%20%3D%20DecompositionPipeline(%0A%20%20%20%20%20%20%20%20forecasters%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22trend%22%2C%20PolynomialTrendForecaster(degree%3D1))%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%22residual%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(alpha%3D1.0)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20feature_transformer%3D_union_nested%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)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%20%20%20%20fc_nested.fit(y_train%2C%20forecasting_horizon%3Dhorizon)%0A%20%20%20%20_y_pred_nested%20%3D%20fc_nested.predict(forecasting_horizon%3Dhorizon)%0A%0A%20%20%20%20_groups%20%3D%20sorted(%7Bc.split(%22__%22)%5B0%5D%20for%20c%20in%20y_train.columns%20if%20%22__%22%20in%20c%7D)%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_nested%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%20groups%3D%5B_groups%5B0%5D%2C%20_groups%5B-1%5D%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22Nested%20Pipeline%20on%20Panel%20Data%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%207.%20Compare%20Global%20vs%20Local%0A%0A%20%20%20%20Score%20each%20approach%20with%20groupwise%20aggregation%20to%20see%20which%20groups%0A%20%20%20%20benefit%20from%20specialised%20models.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20groups%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20pl%2C%0A%20%20%20%20y_pred_column%2C%0A%20%20%20%20y_pred_global%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20_scorer%20%3D%20MeanAbsoluteError()%0A%20%20%20%20_scorer.fit(y_train)%0A%0A%20%20%20%20_rows%20%3D%20%5B%5D%0A%20%20%20%20for%20_group%20in%20sorted(groups.keys())%3A%0A%20%20%20%20%20%20%20%20_s_global%20%3D%20_scorer.score(y_test%2C%20y_pred_global%2C%20groups%3D%5B_group%5D)%0A%20%20%20%20%20%20%20%20_s_column%20%3D%20_scorer.score(y_test%2C%20y_pred_column%2C%20groups%3D%5B_group%5D)%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%22Group%22%3A%20_group%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Global%20MAE%22%3A%20round(float(_s_global)%2C%201)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22ColumnForecaster%20MAE%22%3A%20round(float(_s_column)%2C%201)%2C%0A%20%20%20%20%20%20%20%20%7D)%0A%0A%20%20%20%20comparison%20%3D%20pl.DataFrame(_rows)%0A%20%20%20%20mo.ui.table(comparison)%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%5BCompose%20Feature%20Pipelines%5D(%2Fpages%2Fhow-to%2Fcompose-feature-pipelines%2F)%20for%20the%20full%20guide%0A%20%20%20%20-%20%5BPanel%20Data%20Forecasting%20Tutorial%5D(%2Fpages%2Ftutorials%2Fpanel-data%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
e469219a243c3042d4ac240127314684