%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%5Bconfig%5D%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%22%22%22%0A%23%20How%20to%20Configure%20Estimators%20with%20YAML%0A%0ADefine%2C%20save%2C%20and%20load%20scikit-learn%20estimator%20configurations%20as%20validated%20YAML%20files.%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%20tempfile%0A%20%20%20%20import%20textwrap%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20from%20sklearn.linear_model%20import%20Ridge%0A%20%20%20%20from%20sklearn.pipeline%20import%20Pipeline%0A%20%20%20%20from%20sklearn.preprocessing%20import%20StandardScaler%0A%0A%20%20%20%20from%20sklearn_wrap.config%20import%20EstimatorConfig%2C%20config_context%2C%20get_config%2C%20set_config%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20EstimatorConfig%2C%0A%20%20%20%20%20%20%20%20Path%2C%0A%20%20%20%20%20%20%20%20Ridge%2C%0A%20%20%20%20%20%20%20%20config_context%2C%0A%20%20%20%20%20%20%20%20get_config%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20tempfile%2C%0A%20%20%20%20%20%20%20%20textwrap%2C%0A%20%20%20%20)%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%20This%20guide%20covers%20the%20%60EstimatorConfig%60%20API%3A%20building%20estimators%20from%20YAML%2C%0A%20%20%20%20capturing%20configs%20from%20existing%20estimators%2C%20composing%20multi-file%20configs%20with%0A%20%20%20%20%60!include%60%2C%20and%20validating%20parameters%20at%20build%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%20mo.md(%22%22%22%0A%20%20%20%20%23%23%201.%20Build%20an%20Estimator%20from%20a%20Config%0A%0A%20%20%20%20Create%20an%20%60EstimatorConfig%60%20with%20a%20dotted%20import%20path%20and%20parameters%2C%0A%20%20%20%20then%20call%20%60.build()%60%20to%20get%20a%20ready-to-use%20estimator.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig)%3A%0A%20%20%20%20config%20%3D%20EstimatorConfig(%0A%20%20%20%20%20%20%20%20estimator_class%3D%22sklearn.linear_model.Ridge%22%2C%0A%20%20%20%20%20%20%20%20params%3D%7B%22alpha%22%3A%202.0%2C%20%22fit_intercept%22%3A%20True%7D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20estimator%20%3D%20config.build()%0A%20%20%20%20print(f%22Built%3A%20%7Bestimator%7D%22)%0A%20%20%20%20print(f%22alpha%3D%7Bestimator.alpha%7D%2C%20fit_intercept%3D%7Bestimator.fit_intercept%7D%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.%20Capture%20a%20Config%20from%20an%20Existing%20Estimator%0A%0A%20%20%20%20Use%20%60EstimatorConfig.from_estimator()%60%20to%20inspect%20any%20sklearn-compatible%0A%20%20%20%20estimator%20and%20produce%20a%20reproducible%20config.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig%2C%20Ridge)%3A%0A%20%20%20%20original%20%3D%20Ridge(alpha%3D5.0%2C%20fit_intercept%3DFalse)%0A%0A%20%20%20%20captured%20%3D%20EstimatorConfig.from_estimator(original)%0A%20%20%20%20print(f%22estimator_class%3A%20%7Bcaptured.estimator_class%7D%22)%0A%20%20%20%20print(f%22params%3A%20%7Bcaptured.params%7D%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.%20YAML%20Roundtrip%0A%0A%20%20%20%20Save%20a%20config%20with%20%60.to_yaml()%60%2C%20load%20it%20with%20%60.from_yaml()%60%2C%20then%0A%20%20%20%20%60.build()%60%20to%20reconstruct%20the%20estimator.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig%2C%20Path%2C%20Ridge%2C%20tempfile)%3A%0A%20%20%20%20work_dir%20%3D%20Path(tempfile.mkdtemp())%0A%0A%20%20%20%20%23%20Save%0A%20%20%20%20est%20%3D%20Ridge(alpha%3D7.0)%0A%20%20%20%20cfg%20%3D%20EstimatorConfig.from_estimator(est)%0A%20%20%20%20yaml_path%20%3D%20work_dir%20%2F%20%22ridge.yaml%22%0A%20%20%20%20cfg.to_yaml(yaml_path)%0A%20%20%20%20print(%22Saved%20YAML%3A%22)%0A%20%20%20%20print(yaml_path.read_text())%0A%0A%20%20%20%20%23%20Load%20and%20rebuild%0A%20%20%20%20loaded%20%3D%20EstimatorConfig.from_yaml(yaml_path)%0A%20%20%20%20rebuilt%20%3D%20loaded.build()%0A%20%20%20%20print(f%22Rebuilt%20alpha%3A%20%7Brebuilt.alpha%7D%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%204.%20Use%20YAML%20Anchors%20for%20Shared%20Defaults%0A%0A%20%20%20%20Define%20shared%20parameter%20defaults%20with%20anchors%20(%60%26name%60)%20and%20merge%20keys%0A%20%20%20%20(%60%3C%3C%3A%20*name%60)%2C%20then%20override%20per%20estimator.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig%2C%20Path%2C%20tempfile)%3A%0A%20%20%20%20anchor_dir%20%3D%20Path(tempfile.mkdtemp())%0A%20%20%20%20anchor_yaml%20%3D%20anchor_dir%20%2F%20%22anchors.yaml%22%0A%20%20%20%20anchor_yaml.write_text(%0A%20%20%20%20%20%20%20%20%22_defaults%3A%20%26defaults%5Cn%22%0A%20%20%20%20%20%20%20%20%22%20%20fit_intercept%3A%20true%5Cn%22%0A%20%20%20%20%20%20%20%20%22%20%20solver%3A%20auto%5Cn%22%0A%20%20%20%20%20%20%20%20%22%5Cn%22%0A%20%20%20%20%20%20%20%20%22estimator_class%3A%20sklearn.linear_model.Ridge%5Cn%22%0A%20%20%20%20%20%20%20%20%22params%3A%5Cn%22%0A%20%20%20%20%20%20%20%20%22%20%20%3C%3C%3A%20*defaults%5Cn%22%0A%20%20%20%20%20%20%20%20%22%20%20alpha%3A%200.5%5Cn%22%0A%20%20%20%20)%0A%0A%20%20%20%20anchor_config%20%3D%20EstimatorConfig.from_yaml(anchor_yaml)%0A%20%20%20%20anchor_est%20%3D%20anchor_config.build()%0A%20%20%20%20print(f%22alpha%3D%7Banchor_est.alpha%7D%20(overridden)%22)%0A%20%20%20%20print(f%22fit_intercept%3D%7Banchor_est.fit_intercept%7D%20(from%20defaults)%22)%0A%20%20%20%20print(f%22solver%3D%7Banchor_est.solver!r%7D%20(from%20defaults)%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%205.%20Compose%20Configs%20with%20%60!include%60%0A%0A%20%20%20%20Split%20complex%20configurations%20across%20files.%20The%20%60!include%60%20tag%20loads%20another%0A%20%20%20%20YAML%20file%20inline%2C%20with%20paths%20resolved%20relative%20to%20the%20including%20file.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig%2C%20Path%2C%20tempfile%2C%20textwrap)%3A%0A%20%20%20%20include_dir%20%3D%20Path(tempfile.mkdtemp())%0A%0A%20%20%20%20%23%20Write%20component%20configs%0A%20%20%20%20(include_dir%20%2F%20%22scaler.yaml%22).write_text(textwrap.dedent(%22%22%22%5C%0A%20%20%20%20%20%20%20%20estimator_class%3A%20sklearn.preprocessing.StandardScaler%0A%20%20%20%20%20%20%20%20params%3A%0A%20%20%20%20%20%20%20%20%20%20with_mean%3A%20true%0A%20%20%20%20%20%20%20%20%20%20with_std%3A%20true%0A%20%20%20%20%22%22%22))%0A%0A%20%20%20%20(include_dir%20%2F%20%22ridge.yaml%22).write_text(textwrap.dedent(%22%22%22%5C%0A%20%20%20%20%20%20%20%20estimator_class%3A%20sklearn.linear_model.Ridge%0A%20%20%20%20%20%20%20%20params%3A%0A%20%20%20%20%20%20%20%20%20%20alpha%3A%200.1%0A%20%20%20%20%22%22%22))%0A%0A%20%20%20%20%23%20Write%20the%20pipeline%20config%20that%20includes%20them%0A%20%20%20%20(include_dir%20%2F%20%22pipeline.yaml%22).write_text(textwrap.dedent(%22%22%22%5C%0A%20%20%20%20%20%20%20%20estimator_class%3A%20sklearn.pipeline.Pipeline%0A%20%20%20%20%20%20%20%20params%3A%0A%20%20%20%20%20%20%20%20%20%20steps%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20-%20-%20scaler%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20!include%20scaler.yaml%0A%20%20%20%20%20%20%20%20%20%20%20%20-%20-%20ridge%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20!include%20ridge.yaml%0A%20%20%20%20%22%22%22))%0A%0A%20%20%20%20pipeline_config%20%3D%20EstimatorConfig.from_yaml(include_dir%20%2F%20%22pipeline.yaml%22)%0A%20%20%20%20pipeline%20%3D%20pipeline_config.build()%0A%20%20%20%20print(f%22Pipeline%20steps%3A%20%7B%5Bname%20for%20name%2C%20_%20in%20pipeline.steps%5D%7D%22)%0A%20%20%20%20print(f%22Scaler%20with_mean%3A%20%7Bpipeline.steps%5B0%5D%5B1%5D.with_mean%7D%22)%0A%20%20%20%20print(f%22Ridge%20alpha%3A%20%7Bpipeline.steps%5B1%5D%5B1%5D.alpha%7D%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%206.%20Fit%20and%20Predict%20from%20a%20YAML%20Config%0A%0A%20%20%20%20Load%20a%20config%2C%20build%20the%20estimator%2C%20fit%2C%20and%20predict%20-%20end%20to%20end.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig%2C%20Path%2C%20np%2C%20tempfile%2C%20textwrap)%3A%0A%20%20%20%20fit_dir%20%3D%20Path(tempfile.mkdtemp())%0A%20%20%20%20(fit_dir%20%2F%20%22model.yaml%22).write_text(textwrap.dedent(%22%22%22%5C%0A%20%20%20%20%20%20%20%20estimator_class%3A%20sklearn.pipeline.Pipeline%0A%20%20%20%20%20%20%20%20params%3A%0A%20%20%20%20%20%20%20%20%20%20steps%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20-%20-%20scaler%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20estimator_class%3A%20sklearn.preprocessing.StandardScaler%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20params%3A%20%7B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20-%20-%20ridge%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20estimator_class%3A%20sklearn.linear_model.Ridge%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20params%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alpha%3A%201.0%0A%20%20%20%20%22%22%22))%0A%0A%20%20%20%20model%20%3D%20EstimatorConfig.from_yaml(fit_dir%20%2F%20%22model.yaml%22).build()%0A%0A%20%20%20%20X_train%20%3D%20np.array(%5B%5B1%2C%202%5D%2C%20%5B3%2C%204%5D%2C%20%5B5%2C%206%5D%2C%20%5B7%2C%208%5D%5D)%0A%20%20%20%20y_train%20%3D%20np.array(%5B1.0%2C%202.0%2C%203.0%2C%204.0%5D)%0A%20%20%20%20X_test%20%3D%20np.array(%5B%5B2%2C%203%5D%2C%20%5B4%2C%205%5D%5D)%0A%0A%20%20%20%20model.fit(X_train%2C%20y_train)%0A%20%20%20%20predictions%20%3D%20model.predict(X_test)%0A%20%20%20%20print(f%22Predictions%3A%20%7Bpredictions%7D%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%207.%20Validate%20Parameters%0A%0A%20%20%20%20%60build()%60%20validates%20parameter%20names%20against%20the%20target%20class%20constructor%0A%20%20%20%20before%20instantiation.%20Typos%20in%20YAML%20are%20caught%20immediately.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig%2C%20mo)%3A%0A%20%20%20%20bad_config%20%3D%20EstimatorConfig(%0A%20%20%20%20%20%20%20%20estimator_class%3D%22sklearn.linear_model.Ridge%22%2C%0A%20%20%20%20%20%20%20%20params%3D%7B%22alpha%22%3A%201.0%2C%20%22allpha%22%3A%202.0%7D%2C%20%20%23%20typo!%0A%20%20%20%20)%0A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20bad_config.build()%0A%20%20%20%20except%20ValueError%20as%20exc%3A%0A%20%20%20%20%20%20%20%20mo.output.replace(mo.md(f%22**Caught%20at%20build%20time%3A**%20%60%7Bexc%7D%60%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%20If%20a%20class%20accepts%20%60**kwargs%60%20(like%20%60Pipeline%60)%2C%20extra%20parameter%20names%20are%0A%20%20%20%20allowed.%20You%20can%20also%20disable%20validation%20with%20%60validate_params%3DFalse%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig)%3A%0A%20%20%20%20%23%20Pipeline%20accepts%20**kwargs%20-%20no%20false%20positives%0A%20%20%20%20pipe_cfg%20%3D%20EstimatorConfig(%0A%20%20%20%20%20%20%20%20estimator_class%3D%22sklearn.pipeline.Pipeline%22%2C%0A%20%20%20%20%20%20%20%20params%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22steps%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%22ridge%22%2C%20%7B%22estimator_class%22%3A%20%22sklearn.linear_model.Ridge%22%7D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22memory%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20)%0A%20%20%20%20pipe%20%3D%20pipe_cfg.build()%0A%20%20%20%20print(f%22Pipeline%20built%20with%20validation%3A%20%7B%5Bname%20for%20name%2C%20_%20in%20pipe.steps%5D%7D%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%208.%20Manage%20Trusted%20Modules%0A%0A%20%20%20%20By%20default%20only%20%60sklearn%60%20and%20%60sklearn_wrap%60%20classes%20can%20be%20resolved.%0A%20%20%20%20Use%20%60set_config%60%20to%20register%20packages%20globally%2C%20or%20%60config_context%60%20for%0A%20%20%20%20a%20temporary%20scope.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(EstimatorConfig%2C%20config_context%2C%20get_config%2C%20mo)%3A%0A%20%20%20%20%23%20Check%20the%20defaults%0A%20%20%20%20defaults%20%3D%20get_config()%5B%22trusted_modules%22%5D%0A%20%20%20%20mo.output.replace(mo.md(f%22Default%20trusted%20modules%3A%20%60%7Bsorted(defaults)%7D%60%22))%0A%0A%20%20%20%20%23%20Temporarily%20trust%20builtins%0A%20%20%20%20with%20config_context(trusted_modules%3Dfrozenset(%7B%22sklearn%22%2C%20%22sklearn_wrap%22%2C%20%22builtins%22%7D))%3A%0A%20%20%20%20%20%20%20%20d%20%3D%20EstimatorConfig(estimator_class%3D%22builtins.dict%22).build()%0A%20%20%20%20%20%20%20%20print(f%22Inside%20context%3A%20built%20%7Btype(d).__name__%7D%22)%0A%0A%20%20%20%20%23%20Back%20to%20defaults%20outside%20the%20context%0A%20%20%20%20print(f%22After%20context%3A%20trusted%20modules%20%3D%20%7Bsorted(get_config()%5B'trusted_modules'%5D)%7D%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
d22712232924a9fc9f388bd0a0f7e912