You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义sklearn模型.fit()方法在Pipeline中触发NotFittedError问题

解决自定义基准模型加入Sklearn Pipeline后触发NotFittedError的问题

我正在用多个Pipeline做交叉验证对比,想加一个固定系数的基准模型——不依赖训练数据,直接加载预存的模型。于是我继承了sklearn的LinearRegression,重写了.fit()方法,让它不读取训练数据,直接加载预存模型。单独用这个自定义模型一切正常,但放进Pipeline后就触发了NotFittedError。

我的代码细节

1. 创建并存储基准模型

import numpy as np
import pickle
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
X = np.array([[1],[2],[3]])
y = [10,20,30]
model = LinearRegression(fit_intercept=False).fit(X,y)
pickle.dump(model, open('benchmark_model.txt', 'wb'))
print(model.coef_)
# 输出: [10.]

2. 定义自定义基准模型

class benchmark_model(LinearRegression):
    def fit(self, X, y = None):
        self = pickle.load(open('benchmark_model.txt', 'rb'))
        return self

3. 单独测试自定义模型(运行正常)

X=np.array([[1],[2],[3]])
y=[5,10,15]
model = benchmark_model()
model = model.fit(X,y)
print(model.coef_)
print(model.predict(X))
# 输出:
# [10.]
# [10. 20. 30.]

4. 普通LinearRegression在Pipeline中正常运行

pipe = Pipeline([('model',LinearRegression())])
pipe.fit(X,y).predict(X)
# 输出: array([ 5., 10., 15.])

5. 自定义模型加入Pipeline报错

pipe = Pipeline([('model',benchmark_model())])
pipe.fit(X,y).predict(X)
# 报错: NotFittedError: This benchmark_model instance is not fitted yet. Call 'fit' with appropriate arguments before using this method.

问题根源

你的.fit()方法犯了一个关键错误:你在方法里把self替换成了从pickle加载的新实例,然后返回这个新实例,但Pipeline仍然持有最初创建的那个benchmark_model实例。

当Pipeline调用pipe.fit(X,y)时,它会调用benchmark_model.fit(),但它并不会接收你返回的新实例——而是继续使用原来的那个未被拟合的实例。所以当后续调用predict()时,原实例并没有被正确初始化(没有设置coef_等拟合后的属性),自然就触发了NotFittedError。

单独测试时没问题,是因为你手动把model变量重新赋值为fit()返回的新实例,但Pipeline不会这么做,它会保持对初始实例的引用。


正确的实现方式

不要替换self,而是把加载的模型的所有必要属性复制到当前的self实例上。这样,Pipeline持有的原实例就会被正确“拟合”(其实是加载预存的参数)。

修改后的自定义模型代码:

class benchmark_model(LinearRegression):
    def fit(self, X, y=None):
        # 加载预存模型
        loaded_model = pickle.load(open('benchmark_model.txt', 'rb'))
        # 复制加载模型的核心拟合属性到当前self
        for attr_name in ['coef_', 'intercept_', 'fit_intercept']:
            if hasattr(loaded_model, attr_name):
                setattr(self, attr_name, getattr(loaded_model, attr_name))
        # 标记模型已拟合(sklearn内部判断拟合状态的标志)
        self._is_fitted = True
        return self

测试修改后的代码:

pipe = Pipeline([('model',benchmark_model())])
pipe.fit(X,y).predict(X)
# 输出: array([10., 20., 30.])

这样就能正常运行了,因为现在fit()方法是在原实例上设置了拟合后的属性,而不是返回一个新实例,Pipeline持有的实例已经被正确初始化。

如果想要更通用的方式,也可以遍历加载模型的所有属性并复制,但上面的方式更明确,避免复制不必要的内部属性。

内容的提问来源于stack exchange,提问作者Fredz0r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:22:21