%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%20How%20to%20Combine%20Classification%20Forecasters%20with%20VotingClassProbaForecaster%0A%0A%20%20%20%20This%20notebook%20shows%20how%20to%20combine%20multiple%20classification%20forecasters%0A%20%20%20%20into%20a%20single%20ensemble%20using%20%5B%60VotingClassProbaForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.ensemble.VotingClassProbaForecaster%2F).%0A%0A%20%20%20%20**Prerequisites%3A**%20Familiarity%20with%20class-probability%20forecasting.%20See%20the%0A%20%20%20%20%5BClass-Probability%20Forecasting%20Quickstart%5D(%2Fexamples%2Fforecasting-models%2Fclass_proba_forecaster%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%20from%20copy%20import%20deepcopy%0A%0A%20%20%20%20from%20sklearn.ensemble%20import%20GradientBoostingClassifier%2C%20RandomForestClassifier%0A%20%20%20%20from%20sklearn.linear_model%20import%20LogisticRegression%0A%20%20%20%20from%20sklearn.model_selection%20import%20train_test_split%0A%20%20%20%20from%20sklearn.multioutput%20import%20MultiOutputClassifier%0A%20%20%20%20from%20sklearn.tree%20import%20DecisionTreeClassifier%0A%0A%20%20%20%20from%20yohou.class_proba%20import%20ClassProbaReductionForecaster%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_air_quality_classification%0A%20%20%20%20from%20yohou.ensemble%20import%20VotingClassProbaForecaster%0A%20%20%20%20from%20yohou.metrics%20import%20Accuracy%2C%20BrierScore%2C%20LogLoss%0A%20%20%20%20from%20yohou.plotting%20import%20plot_forecast%0A%20%20%20%20from%20yohou.preprocessing%20import%20LagTransformer%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20Accuracy%2C%0A%20%20%20%20%20%20%20%20BrierScore%2C%0A%20%20%20%20%20%20%20%20ClassProbaReductionForecaster%2C%0A%20%20%20%20%20%20%20%20DecisionTreeClassifier%2C%0A%20%20%20%20%20%20%20%20GradientBoostingClassifier%2C%0A%20%20%20%20%20%20%20%20LagTransformer%2C%0A%20%20%20%20%20%20%20%20LogLoss%2C%0A%20%20%20%20%20%20%20%20LogisticRegression%2C%0A%20%20%20%20%20%20%20%20MultiOutputClassifier%2C%0A%20%20%20%20%20%20%20%20RandomForestClassifier%2C%0A%20%20%20%20%20%20%20%20VotingClassProbaForecaster%2C%0A%20%20%20%20%20%20%20%20deepcopy%2C%0A%20%20%20%20%20%20%20%20fetch_air_quality_classification%2C%0A%20%20%20%20%20%20%20%20plot_forecast%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%20Prepare%20Data%0A%0A%20%20%20%20Air%20quality%20classification%20with%204%20categories%20(good%20%2F%20moderate%20%2F%20unhealthy%20%2F%20hazardous).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_air_quality_classification%2C%20train_test_split)%3A%0A%20%20%20%20y%20%3D%20fetch_air_quality_classification().y%0A%20%20%20%20forecasting_horizon%20%3D%2014%0A%20%20%20%20y_train%2C%20y_test%20%3D%20train_test_split(y%2C%20test_size%3Dforecasting_horizon%2C%20shuffle%3DFalse)%0A%0A%20%20%20%20print(f%22Training%3A%20%7Blen(y_train)%7D%20obs%2C%20Test%3A%20%7Blen(y_test)%7D%20obs%22)%0A%20%20%20%20print(f%22Target%20column%3A%20%7B%5Bc%20for%20c%20in%20y.columns%20if%20c%20!%3D%20'time'%5D%7D%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.%20Define%20Base%20Forecasters%0A%0A%20%20%20%20Create%20diverse%20classifiers%20wrapped%20in%20%5B%60ClassProbaReductionForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.class_proba.reduction.ClassProbaReductionForecaster%2F).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20ClassProbaReductionForecaster%2C%0A%20%20%20%20DecisionTreeClassifier%2C%0A%20%20%20%20GradientBoostingClassifier%2C%0A%20%20%20%20LagTransformer%2C%0A%20%20%20%20LogisticRegression%2C%0A%20%20%20%20MultiOutputClassifier%2C%0A%20%20%20%20RandomForestClassifier%2C%0A)%3A%0A%20%20%20%20base_forecasters%20%3D%20%5B%0A%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22logistic%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20ClassProbaReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DMultiOutputClassifier(LogisticRegression(max_iter%3D500))%2C%0A%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%207%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22tree%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20ClassProbaReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DDecisionTreeClassifier(max_depth%3D5%2C%20random_state%3D42)%2C%0A%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%207%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22rf%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20ClassProbaReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DRandomForestClassifier(n_estimators%3D50%2C%20random_state%3D42)%2C%0A%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%207%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22gbm%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20ClassProbaReductionForecaster(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20estimator%3DMultiOutputClassifier(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20GradientBoostingClassifier(n_estimators%3D50%2C%20random_state%3D42)%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%20feature_transformer%3DLagTransformer(lag%3D%5B1%2C%202%2C%203%2C%207%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%5D%0A%20%20%20%20return%20(base_forecasters%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.%20Soft%20Voting%20Ensemble%0A%0A%20%20%20%20Pass%20the%20named%20forecasters%20to%20%5B%60VotingClassProbaForecaster%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.ensemble.voting_class_proba.VotingClassProbaForecaster%2F)%20with%20%60method%3D%22soft%22%60.%0A%20%20%20%20Soft%20voting%20averages%20the%20predicted%20class%20probabilities.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20VotingClassProbaForecaster%2C%0A%20%20%20%20base_forecasters%2C%0A%20%20%20%20forecasting_horizon%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20ensemble_soft%20%3D%20VotingClassProbaForecaster(%0A%20%20%20%20%20%20%20%20forecasters%3Dbase_forecasters%2C%0A%20%20%20%20%20%20%20%20method%3D%22soft%22%2C%0A%20%20%20%20)%0A%20%20%20%20ensemble_soft.fit(y_train%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20return%20(ensemble_soft%2C)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20deepcopy%2C%0A%20%20%20%20ensemble_soft%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%20y_pred_soft%20%3D%20deepcopy(ensemble_soft).observe_predict(y_test%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20plot_forecast(y_test%2C%20y_pred_soft%2C%20y_train%3Dy_train%2C%20n_history%3D60%2C%20title%3D%22Soft%20Voting%20Ensemble%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.%20Hard%20Voting%20Ensemble%0A%0A%20%20%20%20Hard%20voting%20takes%20the%20majority%20class%20from%20each%20forecaster's%20argmax%20prediction.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20VotingClassProbaForecaster%2C%0A%20%20%20%20base_forecasters%2C%0A%20%20%20%20forecasting_horizon%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20ensemble_hard%20%3D%20VotingClassProbaForecaster(%0A%20%20%20%20%20%20%20%20forecasters%3Dbase_forecasters%2C%0A%20%20%20%20%20%20%20%20method%3D%22hard%22%2C%0A%20%20%20%20)%0A%20%20%20%20ensemble_hard.fit(y_train%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20return%20(ensemble_hard%2C)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20deepcopy%2C%0A%20%20%20%20ensemble_hard%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%20y_pred_hard%20%3D%20deepcopy(ensemble_hard).observe_predict(y_test%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20plot_forecast(y_test%2C%20y_pred_hard%2C%20y_train%3Dy_train%2C%20n_history%3D60%2C%20title%3D%22Hard%20Voting%20Ensemble%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.%20Weighted%20Soft%20Voting%0A%0A%20%20%20%20Assign%20higher%20weight%20to%20models%20you%20expect%20to%20be%20better%20calibrated.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20VotingClassProbaForecaster%2C%0A%20%20%20%20base_forecasters%2C%0A%20%20%20%20forecasting_horizon%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20ensemble_weighted%20%3D%20VotingClassProbaForecaster(%0A%20%20%20%20%20%20%20%20forecasters%3Dbase_forecasters%2C%0A%20%20%20%20%20%20%20%20method%3D%22soft%22%2C%0A%20%20%20%20%20%20%20%20weights%3D%5B0.5%2C%200.5%2C%202.0%2C%202.0%5D%2C%0A%20%20%20%20)%0A%20%20%20%20ensemble_weighted.fit(y_train%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20return%20(ensemble_weighted%2C)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20deepcopy%2C%0A%20%20%20%20ensemble_weighted%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%20y_pred_weighted%20%3D%20deepcopy(ensemble_weighted).observe_predict(y_test%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20plot_forecast(y_test%2C%20y_pred_weighted%2C%20y_train%3Dy_train%2C%20n_history%3D60%2C%20title%3D%22Weighted%20Soft%20Voting%20Ensemble%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%206.%20Compare%20Ensemble%20Strategies%0A%0A%20%20%20%20Evaluate%20all%20three%20strategies%20with%20%5B%60LogLoss%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.class_proba.LogLoss%2F)%2C%20%5B%60BrierScore%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.class_proba.BrierScore%2F)%2C%20and%20%5B%60Accuracy%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.metrics.classification.Accuracy%2F).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Accuracy%2C%0A%20%20%20%20BrierScore%2C%0A%20%20%20%20LogLoss%2C%0A%20%20%20%20deepcopy%2C%0A%20%20%20%20ensemble_hard%2C%0A%20%20%20%20ensemble_soft%2C%0A%20%20%20%20ensemble_weighted%2C%0A%20%20%20%20forecasting_horizon%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20log_loss%20%3D%20LogLoss()%0A%20%20%20%20brier%20%3D%20BrierScore()%0A%20%20%20%20accuracy%20%3D%20Accuracy()%0A%0A%20%20%20%20for%20_scorer%20in%20%5Blog_loss%2C%20brier%2C%20accuracy%5D%3A%0A%20%20%20%20%20%20%20%20_scorer.fit(y_train)%0A%0A%20%20%20%20ensembles%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22Soft%22%3A%20ensemble_soft%2C%0A%20%20%20%20%20%20%20%20%22Hard%22%3A%20ensemble_hard%2C%0A%20%20%20%20%20%20%20%20%22Weighted%20Soft%22%3A%20ensemble_weighted%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20rows%20%3D%20%5B%5D%0A%20%20%20%20for%20name%2C%20model%20in%20ensembles.items()%3A%0A%20%20%20%20%20%20%20%20y_pred%20%3D%20deepcopy(model).observe_predict_class_proba(y_test%2C%20forecasting_horizon%3Dforecasting_horizon)%0A%20%20%20%20%20%20%20%20rows.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Strategy%22%3A%20name%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22LogLoss%22%3A%20f%22%7Blog_loss.score(y_test%2C%20y_pred)%3A.4f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22BrierScore%22%3A%20f%22%7Bbrier.score(y_test%2C%20y_pred)%3A.4f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Accuracy%22%3A%20f%22%7Baccuracy.score(y_test%2C%20y_pred)%3A.4f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20mo.ui.table(rows%2C%20selection%3DNone)%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%5BEnsemble%20Forecasting%5D(%2Fpages%2Fhow-to%2Fensemble-forecasting%2F)%20for%20the%20full%20guide%0A%20%20%20%20-%20%5BClass-Probability%20Forecasting%20Tutorial%5D(%2Fpages%2Ftutorials%2Fclass-proba-forecasting%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
be60f48bf937625cce76de87da915ed1