@@ -843,31 +843,99 @@ def splitter(X, y, index_generator):
843843# .to_dict()
844844# )
845845
846+ # %% [markdown]
847+ #
848+ # ### Exercise: non-linear feature engineering coupled with linear predictive model
849+ #
850+ # Now, it is your turn to make a predictive model. Towards this end, we request you
851+ # to preprocess the input features with non-linear feature engineering:
852+ #
853+ # - the first step is to impute the missing values using a `SimpleImputer`. Make sure
854+ # to include the indicator of missing values in the feature set (i.e. look at the
855+ # `add_indicator` parameter);
856+ # - use a `SplineTransformer` to create non-linear features. Use the default parameters
857+ # but make sure to set `sparse_output=True` since it subsequent processing will be
858+ # faster and more memory efficient with such data structure;
859+ # - use a `VarianceThreshold` to remove features with potential constant features;
860+ # - use a `SelectKBest` to select the most informative features. Set `k` to be chosen
861+ # from a log-uniform distribution between 100 and 1,000 (i.e. use `skrub.choose_int`);
862+ # - use a `Nystroem` to approximate an RBF kernel. Set `n_components` to be chosen
863+ # from a log-uniform distribution between 10 and 200 (i.e. use `skrub.choose_int`).
864+ # - finally, use a `Ridge` as the final predictive model. Set `alpha` to be
865+ # chosen from a log-uniform distribution between 1e-6 and 1e3 (i.e. use
866+ # `skrub.choose_float`).
867+ #
868+ # Use a scikit-learn `Pipeline` using `make_pipeline` to chain the steps together.
869+ #
870+ # Once the predictive model is defined, apply it on the `feature_with_dropped_cols`
871+ # expression. Do not forget to define that `target` is the `y` variable.
872+
873+
846874# %%
847- # TODO: Exercise applying a linear model with some additional feature engineering
875+ # Here we provide all the imports for creating the predictive model.
848876from sklearn .feature_selection import SelectKBest , VarianceThreshold
849877from sklearn .impute import SimpleImputer
850878from sklearn .linear_model import Ridge
851879from sklearn .kernel_approximation import Nystroem
852880from sklearn .pipeline import make_pipeline
853881from sklearn .preprocessing import SplineTransformer
854882
855- model = make_pipeline (
856- SimpleImputer (add_indicator = True ),
857- SplineTransformer (sparse_output = True ),
858- VarianceThreshold (threshold = 1e-6 ),
859- SelectKBest (k = skrub .choose_int (100 , 1_000 , log = True , name = "n_selected_splines" )),
860- Nystroem (
861- n_components = skrub .choose_int (
862- 10 , 200 , log = True , name = "n_components" , default = 150
863- )
883+ # %%
884+ # Write your code here.
885+ #
886+ #
887+ #
888+ #
889+ #
890+ #
891+ #
892+ #
893+ #
894+ #
895+ #
896+
897+ # %%
898+ predictions_ridge = features_with_dropped_cols .skb .apply (
899+ make_pipeline (
900+ SimpleImputer (add_indicator = True ),
901+ SplineTransformer (sparse_output = True ),
902+ VarianceThreshold (threshold = 1e-6 ),
903+ SelectKBest (
904+ k = skrub .choose_int (100 , 1_000 , log = True , name = "n_selected_splines" )
905+ ),
906+ Nystroem (
907+ n_components = skrub .choose_int (
908+ 10 , 200 , log = True , name = "n_components" , default = 150
909+ )
910+ ),
911+ Ridge (
912+ alpha = skrub .choose_float (1e-6 , 1e3 , log = True , name = "alpha" , default = 1e-2 )
913+ ),
864914 ),
865- Ridge ( alpha = skrub . choose_float ( 1e-6 , 1e3 , log = True , name = "alpha" , default = 1e-2 )) ,
915+ y = target ,
866916)
867-
868- predictions_ridge = features_with_dropped_cols .skb .apply (model , y = target )
869917predictions_ridge
870918
919+ # %% [markdown]
920+ #
921+ # Now that you defined the predictive model, let's make a similar analysis than earlier.
922+ # First, let's make a sanity check that plot forecast of our model on a subset of the
923+ # training data to make a sanity check.
924+
925+ # %%
926+ # Write your code here.
927+ #
928+ #
929+ #
930+ #
931+ #
932+ #
933+ #
934+ #
935+ #
936+ #
937+ #
938+
871939# %%
872940altair .Chart (
873941 pl .concat (
@@ -887,6 +955,31 @@ def splitter(X, y, index_generator):
887955 x = "prediction_time:T" , y = "value:Q" , color = "key:N"
888956).interactive ()
889957
958+
959+ # %% [markdown]
960+ #
961+ # Now, let's evaluate the performance of the model using cross-validation. Use the
962+ # time-based cross-validation splitter `ts_cv_5` defined earlier. Make sure to compute
963+ # the R2 score and the mean absolute percentage error. Return the training scores as
964+ # well as the fitted pipeline such that we can make additional analysis.
965+ #
966+ # Does this model perform better or worse than the previous model?
967+ # Is it underfitting or overfitting?
968+
969+ # %%
970+ # Write your code here.
971+ #
972+ #
973+ #
974+ #
975+ #
976+ #
977+ #
978+ #
979+ #
980+ #
981+ #
982+
890983# %%
891984cv_results_ridge = predictions_ridge .skb .cross_validate (
892985 cv = ts_cv_5 ,
@@ -900,6 +993,26 @@ def splitter(X, y, index_generator):
900993 n_jobs = - 1 ,
901994)
902995
996+ # %% [markdown]
997+ #
998+ # Call all cross-validated predictions to plot the Lorenz curve and the reliability
999+ # diagram. Call the function `collect_cv_predictions` to collect the predictions and
1000+ # then call the `plot_lorenz_curve` and `plot_reliability_diagram` functions to plot
1001+ # the results.
1002+
1003+ # %%
1004+ # Write your code here.
1005+ #
1006+ #
1007+ #
1008+ #
1009+ #
1010+ #
1011+ #
1012+ #
1013+ #
1014+ #
1015+ #
9031016
9041017# %%
9051018cv_predictions_ridge = collect_cv_predictions (
@@ -914,6 +1027,28 @@ def splitter(X, y, index_generator):
9141027 title = "Reliability diagram from cross-validation predictions"
9151028)
9161029
1030+ # %% [markdown]
1031+ #
1032+ # Now, you can perform a randomized search on the hyper-parameters of the model.
1033+ # Use the `ts_cv_2` splitter defined earlier. This search is quite computationally
1034+ # expensive, so feel free to reduce the number of iterations but doing at least 100
1035+ # iterations is nice to have an overview of the impact of the hyper-parameters.
1036+ # Use `plot_results` to show the parallel coordinates plot of the results.
1037+
1038+ # %%
1039+ # Write your code here.
1040+ #
1041+ #
1042+ #
1043+ #
1044+ #
1045+ #
1046+ #
1047+ #
1048+ #
1049+ #
1050+ #
1051+
9171052# %%
9181053randomized_search_ridge = predictions_ridge .skb .get_randomized_search (
9191054 cv = ts_cv_2 ,
@@ -955,6 +1090,10 @@ def splitter(X, y, index_generator):
9551090# %%
9561091# nested_cv_results_ridge.round(3)
9571092
1093+ # %% [markdown]
1094+ #
1095+ # ## Predicting multiple horizons with a multi-output model
1096+
9581097# %%
9591098from sklearn .multioutput import MultiOutputRegressor
9601099
@@ -1202,19 +1341,19 @@ def scoring(regressor, X, y):
12021341)
12031342
12041343# %%
1205- cv_results_hgbr_05 [[ col for col in cv_results_hgbr_05 . columns if col . startswith ( "test_" )]]. mean (
1206- axis = 0
1207- ).round (3 )
1344+ cv_results_hgbr_05 [
1345+ [ col for col in cv_results_hgbr_05 . columns if col . startswith ( "test_" )]
1346+ ]. mean ( axis = 0 ).round (3 )
12081347
12091348# %%
1210- cv_results_hgbr_50 [[ col for col in cv_results_hgbr_50 . columns if col . startswith ( "test_" )]]. mean (
1211- axis = 0
1212- ).round (3 )
1349+ cv_results_hgbr_50 [
1350+ [ col for col in cv_results_hgbr_50 . columns if col . startswith ( "test_" )]
1351+ ]. mean ( axis = 0 ).round (3 )
12131352
12141353# %%
1215- cv_results_hgbr_95 [[ col for col in cv_results_hgbr_95 . columns if col . startswith ( "test_" )]]. mean (
1216- axis = 0
1217- ).round (3 )
1354+ cv_results_hgbr_95 [
1355+ [ col for col in cv_results_hgbr_95 . columns if col . startswith ( "test_" )]
1356+ ]. mean ( axis = 0 ).round (3 )
12181357
12191358# %%
12201359results = pl .concat (
0 commit comments