%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%20Naive%20Forecasters%20as%20Baselines%0A%0A%20%20%20%20Every%20forecasting%20project%20needs%20a%20**baseline**%20to%20judge%20model%20quality.%0A%20%20%20%20Naive%20methods%20repeat%20past%20patterns%20with%20no%20learning%2C%20yet%20they%20are%20surprisingly%0A%20%20%20%20hard%20to%20beat%20on%20many%20datasets.%0A%0A%20%20%20%20%23%23%20Prerequisites%0A%0A%20%20%20%20Basic%20understanding%20of%20seasonality%20in%20time%20series.%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%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_forecast%2C%0A%20%20%20%20%20%20%20%20plot_score_heatmap%2C%0A%20%20%20%20%20%20%20%20plot_score_per_step%2C%0A%20%20%20%20%20%20%20%20plot_score_time_series%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%20SeasonalNaive%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20MeanAbsoluteError%2C%0A%20%20%20%20%20%20%20%20SeasonalNaive%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_forecast%2C%0A%20%20%20%20%20%20%20%20plot_score_heatmap%2C%0A%20%20%20%20%20%20%20%20plot_score_per_step%2C%0A%20%20%20%20%20%20%20%20plot_score_time_series%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.%20Load%20and%20Split%20Data%0A%0A%20%20%20%20We%20begin%20by%20loading%20the%20Monthly%20Tourism%20dataset%20and%20splitting%20it%20into%20training%20and%20test%20sets%20for%20evaluating%20the%20forecasters.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_tourism_monthly%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%3D36)%0A%20%20%20%20forecasting_horizon%20%3D%2012%0A%0A%20%20%20%20print(f%22Train%3A%20%7Blen(y_train)%7D%20obs%2C%20Test%3A%20%7Blen(y_test)%7D%20obs%22)%0A%20%20%20%20return%20forecasting_horizon%2C%20y%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%5B%60plot_time_series%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.plotting.exploration.plot_time_series%2F)%20renders%20the%20full%20dataset%20to%20reveal%20the%20yearly%20seasonal%0A%20%20%20%20pattern%20and%20upward%20trend%20that%20the%20naive%20forecaster%20will%20attempt%20to%20capture.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_time_series%2C%20y)%3A%0A%20%20%20%20plot_time_series(y%2C%20title%3D%22Monthly%20Tourism%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.%20SeasonalNaive%20Forecaster%0A%0A%20%20%20%20%5B%60SeasonalNaive%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.point.naive.SeasonalNaive%2F)%20repeats%20the%20last%20%60seasonality%60%20observations%20cyclically.%0A%20%20%20%20With%20%60seasonality%3D12%60%20on%20monthly%20data%2C%20it%20predicts%20each%20month%0A%20%20%20%20using%20the%20same%20month%20from%20the%20previous%20year.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(SeasonalNaive%2C%20forecasting_horizon%2C%20y_train)%3A%0A%20%20%20%20naive%20%3D%20SeasonalNaive(seasonality%3D12)%0A%20%20%20%20naive.fit(y_train%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%0A%20%20%20%20y_pred_naive%20%3D%20naive.predict(forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20print(f%22Predicted%20%7Blen(y_pred_naive)%7D%20steps%20ahead%22)%0A%20%20%20%20y_pred_naive.head()%0A%20%20%20%20return%20naive%2C%20y_pred_naive%0A%0A%0A%40app.cell%0Adef%20_(MeanAbsoluteError%2C%20plot_forecast%2C%20y_pred_naive%2C%20y_test%2C%20y_train)%3A%0A%20%20%20%20mae%20%3D%20MeanAbsoluteError()%0A%20%20%20%20y_test_h%20%3D%20y_test.head(len(y_pred_naive))%0A%20%20%20%20mae.fit(y_train)%0A%20%20%20%20score%20%3D%20mae.score(y_test_h%2C%20y_pred_naive)%0A%20%20%20%20print(f%22Seasonal%20Naive%20MAE%3A%20%7Bscore%3A.2f%7D%22)%0A%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20y_test_h%2C%0A%20%20%20%20%20%20%20%20y_pred_naive%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20title%3D%22Seasonal%20Naive%20Forecast%20(seasonality%3D12)%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.%20Comparing%20Seasonality%20Periods%0A%0A%20%20%20%20The%20%60seasonality%60%20parameter%20controls%20how%20far%20back%20the%20forecaster%20looks.%0A%20%20%20%20Let's%20compare%20%60seasonality%3D1%60%20(repeat%20last%20value)%2C%20%606%60%2C%20and%20%6012%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(MeanAbsoluteError%2C%20SeasonalNaive%2C%20forecasting_horizon%2C%20y_test%2C%20y_train)%3A%0A%20%20%20%20results%20%3D%20%7B%7D%0A%20%20%20%20for%20period%20in%20%5B1%2C%206%2C%2012%5D%3A%0A%20%20%20%20%20%20%20%20model%20%3D%20SeasonalNaive(seasonality%3Dperiod)%0A%20%20%20%20%20%20%20%20model.fit(y_train%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20%20%20%20%20_pred%20%3D%20model.predict(forecasting_horizon%3Dforecasting_horizon)%0A%0A%20%20%20%20%20%20%20%20scorer%20%3D%20MeanAbsoluteError()%0A%20%20%20%20%20%20%20%20y_t%20%3D%20y_test.head(len(_pred))%0A%20%20%20%20%20%20%20%20scorer.fit(y_train)%0A%20%20%20%20%20%20%20%20results%5Bf%22seasonality%3D%7Bperiod%7D%22%5D%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mae%22%3A%20scorer.score(y_t%2C%20_pred)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22pred%22%3A%20_pred%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20print(f%22seasonality%3D%7Bperiod%3A%3E2d%7D%20%20MAE%3A%20%7Bresults%5Bf'seasonality%3D%7Bperiod%7D'%5D%5B'mae'%5D%3A.2f%7D%22)%0A%20%20%20%20return%20(results%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)%20overlays%20predictions%20from%20all%20three%20seasonality%20settings%0A%20%20%20%20against%20the%20test%20actuals%2C%20making%20it%20easy%20to%20see%20which%20period%20best%20captures%0A%20%20%20%20the%20seasonal%20pattern.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_forecast%2C%20results%2C%20y_test%2C%20y_train)%3A%0A%20%20%20%20preds_dict%20%3D%20%7Bname%3A%20r%5B%22pred%22%5D%20for%20name%2C%20r%20in%20results.items()%7D%0A%20%20%20%20plot_forecast(%0A%20%20%20%20%20%20%20%20y_test.head(12)%2C%0A%20%20%20%20%20%20%20%20preds_dict%2C%0A%20%20%20%20%20%20%20%20y_train%3Dy_train%2C%0A%20%20%20%20%20%20%20%20title%3D%22Comparing%20Seasonality%20Periods%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.%20predict%20vs%20observe_predict%0A%0A%20%20%20%20%60predict%60%20generates%20forecasts%20from%20the%20last%20fitted%20state.%0A%20%20%20%20%60observe_predict%60%20first%20ingests%20new%20observations%2C%20then%20predicts%2C%0A%20%20%20%20giving%20the%20model%20fresh%20data%20to%20work%20with.%20Comparing%20both%20on%20the%0A%20%20%20%20same%20test%20set%20reveals%20the%20benefit%20of%20incremental%20observation.%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%20SeasonalNaive%2C%0A%20%20%20%20plot_score_time_series%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20fc%20%3D%20SeasonalNaive(seasonality%3D12)%0A%20%20%20%20fc.fit(y_train%2C%20forecasting_horizon%3D12)%0A%0A%20%20%20%20%23%20predict%3A%20forecast%20from%20the%20last%20fitted%20state%0A%20%20%20%20_y_pred%20%3D%20fc.predict(forecasting_horizon%3Dlen(y_test))%0A%0A%20%20%20%20%23%20observe_predict%3A%20observe%20test%20data%20first%2C%20then%20predict%0A%20%20%20%20_y_obs_pred%20%3D%20fc.observe_predict(y_test%2C%20forecasting_horizon%3D12)%0A%0A%20%20%20%20_scorer%20%3D%20MeanAbsoluteError()%0A%20%20%20%20_scorer.fit(y_train)%0A%20%20%20%20plot_score_time_series(%0A%20%20%20%20%20%20%20%20_scorer%2C%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20%7B%22predict%22%3A%20_y_pred%2C%20%22observe_predict%22%3A%20_y_obs_pred%7D%2C%0A%20%20%20%20%20%20%20%20title%3D%22MAE%20Over%20Time%3A%20predict%20vs%20observe_predict%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%20forecasting_horizon%2C%20naive%2C%20y_test)%3A%0A%20%20%20%20_vintage_model%20%3D%20deepcopy(naive)%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%3Dforecasting_horizon%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%0Adef%20_(plot_score_heatmap%2C%20vintage_scorer%2C%20y_pred_vintages%2C%20y_test)%3A%0A%20%20%20%20plot_score_heatmap(%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%22Score%20Heatmap%20(Step%20x%20Vintage)%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**Reduction%20forecasting**%3A%20See%20%5B%60reduction_forecaster.py%60%5D(%2Fexamples%2Fgetting-started%2Freduction_forecaster%2F)%20for%20ML-based%20approach%0A%20%20%20%20-%20**Scoring**%3A%20See%20%5BMetrics%5D(%2Fexamples%2F%23metrics)%20for%20comprehensive%20evaluation%20metrics%0A%20%20%20%20-%20**Cross-validation**%3A%20See%20%5BModel%20Selection%5D(%2Fexamples%2F%23model-selection)%20for%20temporal%20CV%20strategies%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
2cc77c8b5aa06e0eb1164464185e2646