%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%22numpy%22%2C%0A%23%20%20%20%20%20%22plotly%22%2C%0A%23%20%20%20%20%20%22scikit-learn%22%2C%0A%23%20%20%20%20%20%22sklearn-wrap%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%22%22%22%0A%23%20Parameter%20Management%0A%0AWe%20explore%20how%20%60get_params()%60%20and%20%60set_params()%60%20work%20in%20wrapped%20estimators%2C%0Aand%20why%20sklearn's%20ecosystem%20depends%20on%20this%20interface.%0A%22%22%22%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.2%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_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20from%20sklearn_wrap%20import%20BaseClassWrapper%0A%0A%20%20%20%20return%20BaseClassWrapper%2C%20np%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20In%20this%20tutorial%20we%20examine%20how%20%60BaseClassWrapper%60%20implements%20sklearn's%20parameter%0A%20%20%20%20interface.%20We%20will%20use%20interactive%20sliders%20to%20see%20parameter%20changes%20in%20real%20time%2C%0A%20%20%20%20inspect%20%60get_params()%60%20output%2C%20and%20experiment%20with%20%60set_params()%60%20-%20including%20what%0A%20%20%20%20happens%20with%20invalid%20parameters.%0A%0A%20%20%20%20**Prerequisites**%20-%20Familiarity%20with%20%5Bfirst_wrapper.py%5D(first_wrapper.py).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.class_definition(hide_code%3DTrue)%0Aclass%20ConfigurableRegressor%3A%0A%20%20%20%20%22%22%22Non-sklearn%20regressor%20with%20different%20method%20names.%22%22%22%0A%0A%20%20%20%20def%20__init__(self%2C%20alpha%3D1.0%2C%20beta%3D0.0)%3A%0A%20%20%20%20%20%20%20%20%23%20Store%20with%20different%20internal%20names%0A%20%20%20%20%20%20%20%20self._slope%20%3D%20alpha%0A%20%20%20%20%20%20%20%20self._offset%20%3D%20beta%0A%0A%20%20%20%20def%20train_model(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Train%20the%20model%20(not%20'fit').%22%22%22%0A%20%20%20%20%20%20%20%20self._coefficient%20%3D%20self._slope%0A%20%20%20%20%20%20%20%20self._intercept_value%20%3D%20self._offset%0A%20%20%20%20%20%20%20%20return%20self%0A%0A%20%20%20%20def%20make_predictions(self%2C%20X)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Make%20predictions%20(not%20'predict').%22%22%22%0A%20%20%20%20%20%20%20%20return%20X.flatten()%20*%20self._coefficient%20%2B%20self._intercept_value%0A%0A%0A%40app.cell%0Adef%20_(BaseClassWrapper)%3A%0A%20%20%20%20class%20ConfigurableWrapper(BaseClassWrapper)%3A%0A%20%20%20%20%20%20%20%20_estimator_name%20%3D%20%22model%22%0A%20%20%20%20%20%20%20%20_estimator_base_class%20%3D%20object%0A%0A%20%20%20%20%20%20%20%20def%20fit(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22sklearn%20fit%20that%20delegates%20to%20train_model().%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instantiate()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instance_.train_model(X%2C%20y)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.fitted_%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self%0A%0A%20%20%20%20%20%20%20%20def%20predict(self%2C%20X)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22sklearn%20predict%20that%20delegates%20to%20make_predictions().%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.instance_.make_predictions(X)%0A%0A%20%20%20%20return%20(ConfigurableWrapper%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%201.%20Why%20Parameters%20Matter%0A%0A%20%20%20%20%60get_params()%60%20and%20%60set_params()%60%20are%20the%20interface%20that%20%60GridSearchCV%60%2C%20%60Pipeline%60%2C%0A%20%20%20%20and%20%60clone()%60%20all%20rely%20on.%20%60BaseClassWrapper%60%20implements%20them%20automatically%20by%0A%20%20%20%20inspecting%20the%20wrapped%20class's%20%60__init__%60%20signature.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%202.%20Interactive%20Parameter%20Control%0A%0A%20%20%20%20Let's%20use%20sliders%20to%20change%20%60alpha%60%20and%20%60beta%60%20and%20watch%20the%20model%20update%20in%20real%20time.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20def%20create_slider(start%2C%20stop%2C%20value%2C%20label%2C%20step%3DNone%2C%20**kwargs)%3A%0A%20%20%20%20%20%20%20%20params%20%3D%20%7B%22start%22%3A%20start%2C%20%22stop%22%3A%20stop%2C%20%22value%22%3A%20value%2C%20%22label%22%3A%20label%2C%20%22show_value%22%3A%20True%2C%20**kwargs%7D%0A%20%20%20%20%20%20%20%20if%20step%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20params%5B%22step%22%5D%20%3D%20step%0A%20%20%20%20%20%20%20%20return%20mo.ui.slider(**params)%0A%0A%20%20%20%20return%20(create_slider%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(create_slider%2C%20mo)%3A%0A%20%20%20%20alpha_slider%20%3D%20create_slider(0.5%2C%2050.0%2C%2030.0%2C%20%22Alpha%20(slope)%22%2C%20step%3D0.5)%0A%20%20%20%20beta_slider%20%3D%20create_slider(-10.0%2C%2010.0%2C%200.0%2C%20%22Beta%20(intercept)%22%2C%20step%3D0.5)%0A%20%20%20%20mo.hstack(%5Balpha_slider%2C%20beta_slider%5D%2C%20justify%3D%22space-around%22)%0A%20%20%20%20return%20alpha_slider%2C%20beta_slider%0A%0A%0A%40app.function(hide_code%3DTrue)%0Adef%20generate_regression_data(n_samples%3D300%2C%20n_features%3D2%2C%20noise%3D20%2C%20test_size%3D0.3%2C%20random_state%3D42%2C%20**kwargs)%3A%0A%20%20%20%20from%20sklearn.datasets%20import%20make_regression%0A%20%20%20%20from%20sklearn.model_selection%20import%20train_test_split%0A%20%20%20%20X%2C%20y%20%3D%20make_regression(n_samples%3Dn_samples%2C%20n_features%3Dn_features%2C%20noise%3Dnoise%2C%20random_state%3Drandom_state%2C%20**kwargs)%0A%20%20%20%20return%20train_test_split(X%2C%20y%2C%20test_size%3Dtest_size%2C%20random_state%3Drandom_state)%0A%0A%0A%40app.cell%0Adef%20_(ConfigurableWrapper%2C%20alpha_slider%2C%20beta_slider%2C%20np)%3A%0A%20%20%20%20%23%20Create%20wrapper%20with%20slider%20values%0A%20%20%20%20est%20%3D%20ConfigurableWrapper(%0A%20%20%20%20%20%20%20%20model%3DConfigurableRegressor%2C%0A%20%20%20%20%20%20%20%20alpha%3Dalpha_slider.value%2C%0A%20%20%20%20%20%20%20%20beta%3Dbeta_slider.value%2C%0A%20%20%20%20)%0A%0A%20%20%20%20X_train%2C%20X_test%2C%20y_train%2C%20y_test%20%3D%20generate_regression_data(n_features%3D1%2C%20noise%3D10)%0A%20%20%20%20est.fit(X_train%2C%20y_train)%0A%0A%20%20%20%20y_pred_train%20%3D%20est.predict(X_train)%0A%20%20%20%20y_pred_test%20%3D%20est.predict(X_test)%0A%20%20%20%20X_plot%20%3D%20np.linspace(X_train.min()%2C%20X_train.max()%2C%20100).reshape(-1%2C%201)%0A%20%20%20%20y_pred_plot%20%3D%20est.predict(X_plot)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20X_plot%2C%0A%20%20%20%20%20%20%20%20X_test%2C%0A%20%20%20%20%20%20%20%20X_train%2C%0A%20%20%20%20%20%20%20%20est%2C%0A%20%20%20%20%20%20%20%20y_pred_plot%2C%0A%20%20%20%20%20%20%20%20y_pred_test%2C%0A%20%20%20%20%20%20%20%20y_pred_train%2C%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20y_train%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(np)%3A%0A%20%20%20%20def%20calculate_r2_score(y_true%2C%20y_pred)%3A%0A%20%20%20%20%20%20%20%20return%201%20-%20np.mean((y_true%20-%20y_pred)%20**%202)%20%2F%20np.var(y_true)%0A%0A%20%20%20%20return%20(calculate_r2_score%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(calculate_r2_score)%3A%0A%20%20%20%20def%20calculate_train_test_scores(y_train%2C%20y_pred_train%2C%20y_test%2C%20y_pred_test)%3A%0A%20%20%20%20%20%20%20%20return%20(calculate_r2_score(y_train%2C%20y_pred_train)%2C%20calculate_r2_score(y_test%2C%20y_pred_test))%0A%0A%20%20%20%20return%20(calculate_train_test_scores%2C)%0A%0A%0A%40app.function(hide_code%3DTrue)%0Adef%20create_regression_scatter(X_train%2C%20y_train%2C%20X_test%2C%20y_test%2C%20X_plot%2C%20y_pred_plot%2C%20train_score%2C%20test_score%2C%20title_prefix%3D%22%22%2C%20**layout_kwargs)%3A%0A%20%20%20%20import%20plotly.graph_objects%20as%20go%0A%20%20%20%20fig%20%3D%20go.Figure()%0A%20%20%20%20fig.add_trace(go.Scatter(x%3DX_train.flatten()%2C%20y%3Dy_train%2C%20mode%3D%22markers%22%2C%20name%3D%22Training%20Data%22%2C%20marker%3Ddict(size%3D8%2C%20color%3D%22lightblue%22%2C%20line%3Ddict(width%3D1%2C%20color%3D%22darkblue%22))))%0A%20%20%20%20fig.add_trace(go.Scatter(x%3DX_test.flatten()%2C%20y%3Dy_test%2C%20mode%3D%22markers%22%2C%20name%3D%22Test%20Data%22%2C%20marker%3Ddict(size%3D8%2C%20color%3D%22lightcoral%22%2C%20line%3Ddict(width%3D1%2C%20color%3D%22darkred%22))))%0A%20%20%20%20fig.add_trace(go.Scatter(x%3DX_plot.flatten()%2C%20y%3Dy_pred_plot%2C%20mode%3D%22lines%22%2C%20name%3D%22Model%20Prediction%22%2C%20line%3Ddict(color%3D%22green%22%2C%20width%3D3)))%0A%20%20%20%20title%20%3D%20f%22Train%20R%C2%B2%20%3D%20%7Btrain_score%3A.3f%7D%2C%20Test%20R%C2%B2%20%3D%20%7Btest_score%3A.3f%7D%22%0A%20%20%20%20if%20title_prefix%3A%0A%20%20%20%20%20%20%20%20title%20%3D%20f%22%7Btitle_prefix%7D%3Cbr%3E%7Btitle%7D%22%0A%20%20%20%20fig.update_layout(title%3Dtitle%2C%20xaxis_title%3D%22Feature%22%2C%20yaxis_title%3D%22Target%22%2C%20height%3D500%2C%20showlegend%3DTrue%2C%20**layout_kwargs)%0A%20%20%20%20return%20fig%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20X_plot%2C%0A%20%20%20%20X_test%2C%0A%20%20%20%20X_train%2C%0A%20%20%20%20alpha_slider%2C%0A%20%20%20%20beta_slider%2C%0A%20%20%20%20calculate_train_test_scores%2C%0A%20%20%20%20y_pred_plot%2C%0A%20%20%20%20y_pred_test%2C%0A%20%20%20%20y_pred_train%2C%0A%20%20%20%20y_test%2C%0A%20%20%20%20y_train%2C%0A)%3A%0A%20%20%20%20train_r2%2C%20test_r2%20%3D%20calculate_train_test_scores(y_train%2C%20y_pred_train%2C%20y_test%2C%20y_pred_test)%0A%0A%20%20%20%20fig%20%3D%20create_regression_scatter(%0A%20%20%20%20%20%20%20%20X_train%2C%0A%20%20%20%20%20%20%20%20y_train%2C%0A%20%20%20%20%20%20%20%20X_test%2C%0A%20%20%20%20%20%20%20%20y_test%2C%0A%20%20%20%20%20%20%20%20X_plot%2C%0A%20%20%20%20%20%20%20%20y_pred_plot%2C%0A%20%20%20%20%20%20%20%20train_r2%2C%0A%20%20%20%20%20%20%20%20test_r2%2C%0A%20%20%20%20%20%20%20%20title_prefix%3Df%22%CE%B1%3D%7Balpha_slider.value%3A.1f%7D%2C%20%CE%B2%3D%7Bbeta_slider.value%3A.1f%7D%22%2C%0A%20%20%20%20)%0A%20%20%20%20fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(est%2C%20mo)%3A%0A%20%20%20%20params%20%3D%20est.get_params()%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%20%20%20%20%23%23%203.%20Inspecting%20get_params()%0A%0A%20%20%20%20%20%20%20%20%60%60%60python%0A%20%20%20%20%20%20%20%20%7Bparams%7D%0A%20%20%20%20%20%20%20%20%60%60%60%0A%0A%20%20%20%20%20%20%20%20Notice%20that%20%60get_params()%60%20returns%20every%20%60__init__%60%20parameter%20of%20the%20wrapped%20class%0A%20%20%20%20%20%20%20%20plus%20the%20%60model%60%20key%20(the%20class%20itself).%20This%20is%20exactly%20what%20%60GridSearchCV%60%20and%0A%20%20%20%20%20%20%20%20%60clone()%60%20use%20to%20discover%20and%20reproduce%20an%20estimator's%20configuration.%0A%20%20%20%20%20%20%20%20%22%22%22%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(%22%22%22%0A%20%20%20%20%23%23%204.%20Updating%20with%20set_params()%0A%0A%20%20%20%20We%20can%20update%20parameters%20dynamically%20without%20recreating%20the%20wrapper.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ConfigurableWrapper%2C%20X_test%2C%20X_train%2C%20y_train)%3A%0A%20%20%20%20%23%20Create%2C%20update%2C%20and%20fit%0A%20%20%20%20est2%20%3D%20ConfigurableWrapper(model%3DConfigurableRegressor%2C%20alpha%3D1.0%2C%20beta%3D0.0)%0A%0A%20%20%20%20%23%20set_params()%20returns%20self%20for%20method%20chaining%0A%20%20%20%20est2.set_params(alpha%3D2.5%2C%20beta%3D-1.0)%0A%20%20%20%20est2.fit(X_train%2C%20y_train)%0A%0A%20%20%20%20updated_params%20%3D%20est2.get_params()%0A%20%20%20%20y_pred_updated%20%3D%20est2.predict(X_test)%0A%0A%20%20%20%20%23%20Error%20demo%3A%20invalid%20parameter%0A%20%20%20%20error_msg%20%3D%20None%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20est2.set_params(invalid_param%3D999)%0A%20%20%20%20except%20ValueError%20as%20e%3A%0A%20%20%20%20%20%20%20%20error_msg%20%3D%20str(e)%0A%20%20%20%20return%20error_msg%2C%20updated_params%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(error_msg%2C%20mo%2C%20updated_params)%3A%0A%20%20%20%20mo.md(f%22%22%22%0A%20%20%20%20%23%23%23%20Updated%20Parameters%0A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20%7Bupdated_params%7D%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20Notice%20that%20%60set_params()%60%20validates%20names%20against%20the%20wrapped%20class's%20%60__init__%60%2C%0A%20%20%20%20updates%20the%20internal%20%60params%60%20dictionary%2C%20and%20returns%20%60self%60%20for%20method%20chaining.%0A%20%20%20%20Changes%20take%20effect%20on%20the%20next%20%60fit()%60%20call%2C%20when%20the%20wrapped%20instance%20is%20recreated.%0A%0A%20%20%20%20%23%23%23%20Invalid%20Parameter%20Error%0A%0A%20%20%20%20%60%60%60%0A%20%20%20%20%7Berror_msg%7D%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20Passing%20a%20parameter%20that%20does%20not%20exist%20in%20%60ConfigurableRegressor.__init__%60%20raises%0A%20%20%20%20a%20%60ValueError%60%20immediately%20-%20we%20never%20reach%20%60fit()%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20What%20We%20Built%0A%0A%20%20%20%20We%20used%20%60get_params()%60%20and%20%60set_params()%60%20to%20inspect%20and%20update%20a%20wrapped%20estimator's%0A%20%20%20%20configuration%20at%20runtime.%20The%20parameter%20interface%20is%20what%20makes%20%60BaseClassWrapper%60%0A%20%20%20%20compatible%20with%20%60GridSearchCV%60%2C%20%60Pipeline%60%2C%20and%20%60clone()%60.%0A%0A%20%20%20%20Next%3A%20%5Bgrid_search.py%5D(grid_search.py)%20puts%20this%20interface%20to%20work%20inside%20%60GridSearchCV%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20**More%20examples%3A**%20%5Bvalidation.py%5D(validation.py)%20%7C%20%5Bnested_wrappers.py%5D(nested_wrappers.py)%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
43356c8d000ca4aeb5029e4480ff3806