%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%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%20The%20Fit%20Context%20Decorator%0A%0AIn%20this%20notebook%2C%20we%20compare%20manual%20instantiation%20with%20the%20%60_fit_context%60%20decorator%0Aand%20explore%20how%20it%20automates%20validation%2C%20instantiation%2C%20and%20fitted%20state%20management.%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%20%20%20%20from%20sklearn_wrap%20import%20base%20as%20skw_base%0A%0A%20%20%20%20return%20BaseClassWrapper%2C%20np%2C%20skw_base%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%20notebook%2C%20we%20compare%20the%20manual%20approach%20to%20instantiation%20and%0A%20%20%20%20validation%20with%20the%20%60_fit_context%60%20decorator.%20We%20see%20how%20the%20decorator%0A%20%20%20%20automates%20boilerplate%20and%20handles%20%60partial_fit%60%20for%20incremental%20learning.%0A%0A%20%20%20%20**Prerequisites%3A**%20Familiarity%20with%20the%0A%20%20%20%20%5Bfirst%20wrapper%20notebook%5D(%2Fexamples%2Ffirst_wrapper%2F).%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%201.%20Manual%20vs%20Decorator%20Approach%0A%0A%20%20%20%20%60_fit_context%60%20automates%20sklearn's%20validation%20and%20fit%20context%20management.%0A%20%20%20%20It%20handles%3A%0A%0A%20%20%20%201.%20Parameter%20validation%20via%20%60_validate_params()%60%0A%20%20%20%202.%20Instantiation%20via%20%60instantiate()%60%0A%20%20%20%203.%20Context%20management%20for%20nested%20validation%0A%20%20%20%204.%20Setting%20%60fitted_%60%20attribute%20after%20successful%20fit%0A%0A%20%20%20%20Let's%20compare%20manual%20vs%20decorator-based%20approaches.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20class%20SimpleModel%3A%0A%20%20%20%20%20%20%20%20%22%22%22Non-sklearn%20model%20with%20custom%20methods.%22%22%22%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20alpha%3D1.0)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._param_alpha%20%3D%20alpha%0A%0A%20%20%20%20%20%20%20%20def%20train_model(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%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%20%20%20%20%20self._trained_coefficient%20%3D%20self._param_alpha%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self%0A%0A%20%20%20%20%20%20%20%20def%20get_predictions(self%2C%20X)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Get%20predictions%20(not%20'predict').%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20np.full(X.shape%5B0%5D%2C%20self._trained_coefficient)%0A%0A%20%20%20%20return%20(SimpleModel%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%23%20Manual%20Approach%20(Explicit%20Calls)%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(BaseClassWrapper)%3A%0A%20%20%20%20class%20ManualWrapper(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%23%20Must%20manually%20call%20these%0A%20%20%20%20%20%20%20%20%20%20%20%20self._validate_params()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instantiate()%0A%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%20%23%20instance_%20is%20not%20considered%20a%20fitted%20attribute%20by%20sklearn's%20check_is_fitted%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20so%20we%20need%20to%20define%20an%20attribute%20with%20a%20trailing%20underscore%20such%20as%20fitted_%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%20return%20self.instance_.get_predictions(X)%0A%0A%20%20%20%20return%20(ManualWrapper%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%23%20Decorator%20Approach%20(Automatic)%0A%0A%20%20%20%20The%20decorator%20accepts%20%60prefer_skip_nested_validation%60%20parameter.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(BaseClassWrapper%2C%20skw_base)%3A%0A%20%20%20%20class%20DecoratorWrapper(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%20%40skw_base._fit_context(prefer_skip_nested_validation%3DTrue)%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%23%20instantiate()%20called%20automatically%20by%20decorator%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%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%20return%20self.instance_.get_predictions(X)%0A%0A%20%20%20%20return%20(DecoratorWrapper%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%202.%20Validation%20Control%0A%0A%20%20%20%20The%20%60prefer_skip_nested_validation%60%20parameter%20controls%20validation%20in%20nested%20estimators.%0A%20%20%20%20Most%20wrappers%20should%20use%20%60True%60.%20Meta-estimators%20that%20accept%20user-provided%20estimators%0A%20%20%20%20(like%20GridSearchCV)%20should%20use%20%60False%60.%0A%0A%20%20%20%20For%20a%20deeper%20discussion%2C%20see%20the%20%5BConcepts%20page%5D(%2Fpages%2Fexplanation%2Fconcepts%2F).%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%23%20Let's%20Compare%20Both%20Approaches%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(DecoratorWrapper%2C%20ManualWrapper%2C%20SimpleModel%2C%20np)%3A%0A%20%20%20%20X%20%3D%20np.array(%5B%5B1%5D%2C%20%5B2%5D%2C%20%5B3%5D%5D)%0A%20%20%20%20y%20%3D%20np.array(%5B10%2C%2020%2C%2030%5D)%0A%0A%20%20%20%20%23%20Manual%20approach%0A%20%20%20%20manual%20%3D%20ManualWrapper(model%3DSimpleModel%2C%20alpha%3D2.0)%0A%20%20%20%20manual.fit(X%2C%20y)%0A%20%20%20%20manual_pred%20%3D%20manual.predict(X)%0A%0A%20%20%20%20%23%20Decorator%20approach%0A%20%20%20%20decorator%20%3D%20DecoratorWrapper(model%3DSimpleModel%2C%20alpha%3D2.0)%0A%20%20%20%20decorator.fit(X%2C%20y)%0A%20%20%20%20decorator_pred%20%3D%20decorator.predict(X)%0A%20%20%20%20return%20X%2C%20decorator_pred%2C%20manual_pred%2C%20y%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(decorator_pred%2C%20manual_pred%2C%20mo)%3A%0A%20%20%20%20mo.md(f%22%22%22%0A%20%20%20%20**Manual%20Predictions%3A**%20%7Bmanual_pred%7D%0A%0A%20%20%20%20**Decorator%20Predictions%3A**%20%7Bdecorator_pred%7D%0A%0A%20%20%20%20Notice%20that%20both%20produce%20identical%20results.%20The%20decorator%20approach%20removes%0A%20%20%20%20the%20boilerplate%20while%20validation%20happens%20automatically.%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%23%20What%20the%20Decorator%20Gives%20Us%0A%0A%20%20%20%20-%20**Automatic%20instantiation%3A**%20No%20need%20to%20call%20%60instantiate()%60%20explicitly%0A%20%20%20%20-%20**Validation%3A**%20%60_validate_params()%60%20called%20automatically%20before%20fit%0A%20%20%20%20-%20**Context%20management%3A**%20Integrates%20with%20sklearn's%20%60skip_parameter_validation%60%20config%0A%20%20%20%20-%20**Fitted%20flag%3A**%20Sets%20%60fitted_%60%20attribute%20automatically%20after%20successful%20fit%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%203.%20Incremental%20Learning%20with%20partial_fit%0A%0A%20%20%20%20The%20decorator%20handles%20%60partial_fit%60%20differently%3A%0A%20%20%20%20-%20Only%20instantiates%20on%20the%20first%20call%0A%20%20%20%20-%20Skips%20re-instantiation%20on%20subsequent%20calls%0A%20%20%20%20-%20Does%20not%20automatically%20set%20%60fitted_%60%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(BaseClassWrapper%2C%20np%2C%20skw_base)%3A%0A%20%20%20%20class%20IncrementalModel%3A%0A%20%20%20%20%20%20%20%20def%20__init__(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.sum_%20%3D%200.0%0A%20%20%20%20%20%20%20%20%20%20%20%20self.count_%20%3D%200%0A%0A%20%20%20%20%20%20%20%20def%20partial_fit(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.sum_%20%2B%3D%20y.sum()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.count_%20%2B%3D%20len(y)%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%20return%20np.full(X.shape%5B0%5D%2C%20self.sum_%20%2F%20self.count_)%0A%0A%20%20%20%20class%20IncrementalWrapper(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%20%40skw_base._fit_context(prefer_skip_nested_validation%3DTrue)%0A%20%20%20%20%20%20%20%20def%20partial_fit(self%2C%20X%2C%20y)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.instance_.partial_fit(X%2C%20y)%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%20return%20self.instance_.predict(X)%0A%0A%20%20%20%20return%20IncrementalModel%2C%20IncrementalWrapper%0A%0A%0A%40app.cell%0Adef%20_(IncrementalModel%2C%20IncrementalWrapper%2C%20X%2C%20y)%3A%0A%20%20%20%20incr%20%3D%20IncrementalWrapper(model%3DIncrementalModel)%0A%0A%20%20%20%20%23%20Multiple%20partial_fit%20calls%0A%20%20%20%20incr.partial_fit(X%5B%3A2%5D%2C%20y%5B%3A2%5D)%0A%20%20%20%20incr.partial_fit(X%5B2%3A%5D%2C%20y%5B2%3A%5D)%0A%0A%20%20%20%20incr_pred%20%3D%20incr.predict(X)%0A%20%20%20%20return%20(incr_pred%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(incr_pred%2C%20mo)%3A%0A%20%20%20%20mo.md(f%22%22%22%0A%20%20%20%20**Incremental%20Predictions%3A**%20%7Bincr_pred%7D%0A%0A%20%20%20%20Notice%20that%20%60partial_fit%60%20was%20called%20twice%20and%20the%20model%20accumulated%20state%0A%20%20%20%20across%20both%20calls%20without%20re-instantiation.%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%20compared%20manual%20instantiation%20with%20the%20%60_fit_context%60%20decorator%20and%20saw%0A%20%20%20%20how%20the%20decorator%20automates%20boilerplate.%20Along%20the%20way%2C%20we%3A%0A%0A%20%20%20%20-%20Saw%20manual%20vs%20decorator%20approaches%20produce%20identical%20results%0A%20%20%20%20-%20Used%20%60prefer_skip_nested_validation%60%20to%20control%20validation%20depth%0A%20%20%20%20-%20Handled%20%60partial_fit%60%20for%20incremental%20learning%0A%0A%20%20%20%20**Next%20steps%3A**%0A%0A%20%20%20%20-%20Grid%20search%20integration%3A%0A%20%20%20%20%20%20%5BView%5D(%2Fexamples%2Fgrid_search%2F)%20%C2%B7%20%5BOpen%20in%20marimo%5D(%2Fexamples%2Fgrid_search%2Fedit%2F)%0A%20%20%20%20-%20Nested%20wrapper%20parameters%3A%0A%20%20%20%20%20%20%5BView%5D(%2Fexamples%2Fnested_wrappers%2F)%20%C2%B7%20%5BOpen%20in%20marimo%5D(%2Fexamples%2Fnested_wrappers%2Fedit%2F)%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
4fae4200970f5460e9083c801404f217