%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%20Trend%20and%20Seasonality%20Decomposition%0A%0A%20%20%20%20Classical%20decomposition%20splits%20a%20time%20series%20into%20**trend**%2C%20**seasonality**%2C%0A%20%20%20%20and%20**residual**%20components.%20Yohou%20provides%20specialized%20forecasters%20for%20each%0A%20%20%20%20component%20and%20%5B%60DecompositionPipeline%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.compose.decomposition_pipeline.DecompositionPipeline%2F)%20to%20chain%20them.%0A%0A%20%20%20%20%23%23%20Prerequisites%0A%0A%20%20%20%20Understanding%20of%20trend%20and%20seasonality%20concepts.%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%20from%20copy%20import%20deepcopy%0A%0A%20%20%20%20from%20sklearn.linear_model%20import%20LinearRegression%2C%20Ridge%0A%0A%20%20%20%20from%20yohou.compose%20import%20DecompositionPipeline%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_tourism_monthly%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%20(%0A%20%20%20%20%20%20%20%20plot_decomposition%2C%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_score_per_step%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%20%20%20%20from%20yohou.stationarity%20import%20(%0A%20%20%20%20%20%20%20%20FourierSeasonalityForecaster%2C%0A%20%20%20%20%20%20%20%20LogTransformer%2C%0A%20%20%20%20%20%20%20%20PatternSeasonalityForecaster%2C%0A%20%20%20%20%20%20%20%20PolynomialTrendForecaster%2C%0A%20%20%20%20)%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20DecompositionPipeline%2C%0A%20%20%20%20%20%20%20%20FourierSeasonalityForecaster%2C%0A%20%20%20%20%20%20%20%20LagTransformer%2C%0A%20%20%20%20%20%20%20%20LinearRegression%2C%0A%20%20%20%20%20%20%20%20LogTransformer%2C%0A%20%20%20%20%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20%20%20%20%20PatternSeasonalityForecaster%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%20deepcopy%2C%0A%20%20%20%20%20%20%20%20fetch_tourism_monthly%2C%0A%20%20%20%20%20%20%20%20plot_decomposition%2C%0A%20%20%20%20%20%20%20%20plot_forecast%2C%0A%20%20%20%20%20%20%20%20plot_score_per_step%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.%20Prepare%20Data%0A%0A%20%20%20%20We%20load%20a%20time%20series%20dataset%20suitable%20for%20demonstrating%20trend%20and%20seasonality%20decomposition.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_tourism_monthly%2C%20plot_time_series%2C%20train_test_split)%3A%0A%20%20%20%20y%20%3D%20fetch_tourism_monthly().frame.select(%22time%22%2C%20%22T1__tourists%22).drop_nulls().rename(%7B%22T1__tourists%22%3A%20%22tourists%22%7D)%0A%20%20%20%20y_train%2C%20y_test%20%3D%20train_test_split(y%2C%20test_size%3D65)%0A%20%20%20%20fh%20%3D%20len(y_test)%0A%0A%20%20%20%20plot_time_series(y%2C%20title%3D%22Monthly%20Tourism%20(T1)%22)%0A%20%20%20%20return%20fh%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.%20PolynomialTrendForecaster%0A%0A%20%20%20%20Fits%20a%20polynomial%20to%20the%20time%20index.%20%60degree%3D1%60%20is%20linear%2C%20%60degree%3D2%60%20is%20quadratic.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(PolynomialTrendForecaster%2C%20fh%2C%20plot_forecast%2C%20y_test%2C%20y_train)%3A%0A%20%20%20%20trend_fc%20%3D%20PolynomialTrendForecaster(degree%3D1)%0A%20%20%20%20trend_fc.fit(y_train%2C%20forecasting_horizon%3Dfh)%0A%20%20%20%20y_pred_trend%20%3D%20trend_fc.predict(forecasting_horizon%3Dfh)%0A%0A%20%20%20%20print(f%22Trend%20prediction%20(first%205)%3A%20%7By_pred_trend%5B'tourists'%5D.head(5).to_list()%7D%22)%0A%20%20%20%20plot_forecast(y_test%2C%20y_pred_trend%2C%20y_train%3Dy_train%2C%20title%3D%22Linear%20Trend%20Forecast%22)%0A%20%20%20%20return%20(trend_fc%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.%20PatternSeasonalityForecaster%0A%0A%20%20%20%20Captures%20recurring%20patterns%20by%20averaging%20(or%20median%2Fnaive)%20over%20past%20seasons.%0A%0A%20%20%20%20-%20%60method%3D%22naive%22%60%3A%20Repeat%20last%20season's%20exact%20values%0A%20%20%20%20-%20%60method%3D%22average%22%60%3A%20Average%20across%20all%20observed%20seasons%0A%20%20%20%20-%20%60method%3D%22median%22%60%3A%20Median%20across%20seasons%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(PatternSeasonalityForecaster%2C%20fh%2C%20y_train)%3A%0A%20%20%20%20for%20method%20in%20%5B%22naive%22%2C%20%22average%22%2C%20%22median%22%5D%3A%0A%20%20%20%20%20%20%20%20season_fc%20%3D%20PatternSeasonalityForecaster(seasonality%3D12%2C%20method%3Dmethod)%0A%20%20%20%20%20%20%20%20season_fc.fit(y_train%2C%20forecasting_horizon%3Dfh)%0A%20%20%20%20%20%20%20%20pred%20%3D%20season_fc.predict(forecasting_horizon%3Dfh)%0A%20%20%20%20%20%20%20%20print(f%22method%3D%7Bmethod%3A%3E7s%7D%20%20first%20pred%3A%20%7Bpred%5B'tourists'%5D%5B0%5D%3A.1f%7D%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.%20FourierSeasonalityForecaster%0A%0A%20%20%20%20Models%20seasonality%20using%20Fourier%20basis%20functions.%20More%20harmonics%0A%20%20%20%20capture%20more%20complex%20seasonal%20shapes.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20FourierSeasonalityForecaster%2C%0A%20%20%20%20LinearRegression%2C%0A%20%20%20%20fh%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%20fourier_fc%20%3D%20FourierSeasonalityForecaster(%0A%20%20%20%20%20%20%20%20estimator%3DLinearRegression()%2C%0A%20%20%20%20%20%20%20%20seasonality%3D12.0%2C%0A%20%20%20%20%20%20%20%20harmonics%3D%5B1%2C%202%2C%203%5D%2C%0A%20%20%20%20)%0A%20%20%20%20fourier_fc.fit(y_train%2C%20forecasting_horizon%3Dfh)%0A%20%20%20%20y_pred_fourier%20%3D%20fourier_fc.predict(forecasting_horizon%3Dfh)%0A%0A%20%20%20%20plot_forecast(y_test%2C%20y_pred_fourier%2C%20y_train%3Dy_train%2C%20title%3D%22Fourier%20Seasonality%20(3%20harmonics)%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%205.%20DecompositionPipeline%0A%0A%20%20%20%20Chain%20multiple%20component%20forecasters%20sequentially.%20Each%20forecaster%20in%20the%20pipeline%0A%20%20%20%20fits%20on%20the%20**residuals**%20from%20the%20previous%20one.%0A%0A%20%20%20%20%60trend%20%E2%86%92%20seasonality%20%E2%86%92%20residual%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%20DecompositionPipeline%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20LogTransformer%2C%0A%20%20%20%20PatternSeasonalityForecaster%2C%0A%20%20%20%20PointReductionForecaster%2C%0A%20%20%20%20PolynomialTrendForecaster%2C%0A%20%20%20%20Ridge%2C%0A%20%20%20%20fh%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20decomp%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(%22seasonality%22%2C%20PatternSeasonalityForecaster(seasonality%3D12%2C%20method%3D%22average%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%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%3D100)%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%2013)))%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%20target_transformer%3DLogTransformer()%2C%0A%20%20%20%20%20%20%20%20store_residuals%3DTrue%2C%0A%20%20%20%20)%0A%0A%20%20%20%20decomp.fit(y_train%2C%20forecasting_horizon%3Dfh)%0A%20%20%20%20y_pred_decomp%20%3D%20decomp.predict(forecasting_horizon%3Dfh)%0A%20%20%20%20print(f%22DecompositionPipeline%20prediction%3A%20%7Blen(y_pred_decomp)%7D%20steps%22)%0A%20%20%20%20return%20decomp%2C%20y_pred_decomp%0A%0A%0A%40app.cell%0Adef%20_(MeanAbsoluteError%2C%20y_pred_decomp%2C%20y_test%2C%20y_train)%3A%0A%20%20%20%20mae%20%3D%20MeanAbsoluteError()%0A%20%20%20%20mae.fit(y_train)%0A%20%20%20%20score%20%3D%20mae.score(y_test%2C%20y_pred_decomp)%0A%20%20%20%20print(f%22Decomposition%20MAE%3A%20%7Bscore%3A.2f%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_forecast%2C%20y_pred_decomp%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_decomp%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20title%3D%22DecompositionPipeline%3A%20Trend%20%2B%20Season%20%2B%20Residual%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.%20Visualizing%20Components%0A%0A%20%20%20%20With%20%60store_residuals%3DTrue%60%2C%20access%20each%20component's%20contribution%20via%0A%20%20%20%20%60named_forecasters_%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(decomp%2C%20fh%2C%20plot_decomposition%2C%20y_test)%3A%0A%20%20%20%20components%20%3D%20%7B%7D%0A%20%20%20%20for%20name%2C%20fc%2C%20*_%20in%20decomp.forecasters_%3A%0A%20%20%20%20%20%20%20%20comp_pred%20%3D%20fc.predict(forecasting_horizon%3Dfh)%0A%20%20%20%20%20%20%20%20components%5Bname%5D%20%3D%20comp_pred%0A%0A%20%20%20%20plot_decomposition(%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20components%2C%0A%20%20%20%20%20%20%20%20title%3D%22Decomposition%20Components%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%20Multi-vintage%20Scoring%0A%0A%20%20%20%20The%20%60observe_predict%60%20method%20with%20%60stride%3D1%60%20produces%20one%20forecast%20per%0A%20%20%20%20observation%20point%2C%20creating%20multiple%20*vintages*.%20Each%20vintage%20represents%0A%20%20%20%20a%20different%20forecast%20origin%2C%20so%20you%20can%20analyse%20how%20accuracy%20evolves%20as%0A%20%20%20%20the%20model%20absorbs%20more%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(deepcopy%2C%20fh%2C%20trend_fc%2C%20y_test)%3A%0A%20%20%20%20_vintage_model%20%3D%20deepcopy(trend_fc)%0A%20%20%20%20y_pred_vintages%20%3D%20_vintage_model.observe_predict(%0A%20%20%20%20%20%20%20%20y%3Dy_test%2C%0A%20%20%20%20%20%20%20%20stride%3D1%2C%0A%20%20%20%20%20%20%20%20forecasting_horizon%3Dfh%2C%0A%20%20%20%20)%0A%20%20%20%20print(f%22Vintages%3A%20%7By_pred_vintages%5B'vintage_time'%5D.n_unique()%7D%22)%0A%20%20%20%20y_pred_vintages.head(10)%0A%20%20%20%20return%20(y_pred_vintages%2C)%0A%0A%0A%40app.cell%0Adef%20_(MeanAbsoluteError%2C%20y_train)%3A%0A%20%20%20%20vintage_scorer%20%3D%20MeanAbsoluteError()%0A%20%20%20%20vintage_scorer.fit(y_train)%0A%20%20%20%20return%20(vintage_scorer%2C)%0A%0A%0A%40app.cell%0Adef%20_(plot_score_per_step%2C%20vintage_scorer%2C%20y_pred_vintages%2C%20y_test)%3A%0A%20%20%20%20plot_score_per_step(%0A%20%20%20%20%20%20%20%20vintage_scorer%2C%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_pred_vintages%2C%0A%20%20%20%20%20%20%20%20title%3D%22MAE%20per%20Forecast%20Step%22%2C%0A%20%20%20%20%20%20%20%20y_label%3D%22MAE%22%2C%0A%20%20%20%20%20%20%20%20height%3D380%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**Stationarity%20transforms**%3A%20See%20%5B%60stationarity_transforms.py%60%5D(%2Fexamples%2Fdata-features%2Fstationarity_transforms%2F)%20for%20differencing%0A%20%20%20%20-%20**Reduction%20forecasting**%3A%20See%20%5B%60point%2Freduction_forecaster.py%60%5D(%2Fexamples%2Fgetting-started%2Freduction_forecaster%2F)%0A%20%20%20%20-%20**Interval%20forecasting**%3A%20See%20%5BInterval%5D(%2Fexamples%2F%23interval-forecasting)%20for%20prediction%20intervals%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
3c2a7edfa1c46edb859afc629488c7f4