TransformedTargetRegressor克隆回归器的原因及禁用该行为的方法
TransformedTargetRegressor克隆行为解析与问题解决
克隆行为的设计依据与作用
- 隔离拟合状态:避免传入的原始回归器对象被修改,保留其未拟合的初始状态,方便后续重复使用(比如基于同一个干净模型做不同参数或数据集的实验)。
- 遵循Scikit-learn API规范:Scikit-learn所有估计器的
fit方法都被设计为不修改输入的原始实例,而是生成并返回一个拟合后的新对象,这种设计保证了API的一致性,让用户可以放心复用初始模型。 - 支持无干扰重复拟合:如果多次调用
TransformedTargetRegressor的fit方法,每次都会基于原始未拟合的回归器克隆新实例,不会受到前一次拟合状态的影响,确保每次拟合都是独立的。
解决代码报错的方法
方法1:获取拟合后的回归器实例(推荐)
报错的核心原因是原model对象并未被拟合,拟合的是TransformedTargetRegressor内部克隆出的实例。只需从拟合后的TransformedTargetRegressor对象中取出内部拟合好的管道和模型即可:
import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.ensemble import RandomForestRegressor from sklearn.pipeline import Pipeline from sklearn.compose import TransformedTargetRegressor X = np.random.default_rng(seed=1).normal(size=(100,3)) y = np.random.default_rng(seed=1).normal(size=100) model = RandomForestRegressor() pipeline = Pipeline( steps=[ ('normalize', StandardScaler()), ('model', model), ], ) tt = TransformedTargetRegressor(regressor=pipeline, transformer=StandardScaler()) tt.fit(X, y) # 从拟合后的TransformedTargetRegressor中取出管道 fitted_pipeline = tt.regressor_ # 从管道中获取拟合好的随机森林模型 fitted_model = fitted_pipeline.named_steps['model'] print(fitted_model.feature_importances_)
方法2:自定义包装类跳过克隆(不推荐)
虽然Scikit-learn官方不建议这么做(会破坏API设计原则),但如果一定要让原始模型被直接拟合,可以通过自定义包装类绕过克隆机制:
import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.ensemble import RandomForestRegressor from sklearn.pipeline import Pipeline from sklearn.compose import TransformedTargetRegressor class NoCloneRegressor: def __init__(self, regressor): self.regressor = regressor def fit(self, X, y): self.regressor.fit(X, y) return self def predict(self, X): return self.regressor.predict(X) # 转发所有未定义的属性和方法到内部回归器 def __getattr__(self, name): return getattr(self.regressor, name) X = np.random.default_rng(seed=1).normal(size=(100,3)) y = np.random.default_rng(seed=1).normal(size=100) model = RandomForestRegressor() pipeline = Pipeline( steps=[ ('normalize', StandardScaler()), ('model', model), ], ) # 用包装类包裹管道,避免被克隆 tt = TransformedTargetRegressor(regressor=NoCloneRegressor(pipeline), transformer=StandardScaler()) tt.fit(X, y) # 此时原model已被拟合 print(model.feature_importances_)
注意:这种方法会导致多次调用fit时覆盖原始模型的状态,违背Scikit-learn的无副作用设计原则,可能引发意外问题,仅在特殊场景下使用。
内容的提问来源于stack exchange,提问作者a_guest
相关产品推荐
相关产品推荐

