GridSearchCV输出nan分数及TypeError: fit()缺少必填参数'y'问题排查求助
解决GridSearchCV中的fit报错与score=nan问题
咱们一步步拆解你遇到的两个核心问题:TypeError: fit() missing 1 required positional argument: 'y'和所有交叉验证分数全为nan的情况。
1. 为什么会出现fit参数缺失的报错?
这是因为你自定义的Foo类违反了Sklearn Estimator的核心规则:fit方法必须返回自身(self)。
你当前的fit方法最后返回的是处理后的X,而不是类实例本身。当GridSearchCV调用estimator.fit(X_train, y_train)后,它期望得到一个训练好的Foo实例,结果拿到的却是一个numpy数组。后续流程中,GridSearchCV会尝试用这个“假estimator”继续执行操作,自然会抛出参数错误——因为数组根本没有fit方法,更别说接收y参数了。
修复方案:修改fit方法,最后返回self,同时把需要保留的训练数据存为实例属性:
def fit(self, X, y): # 先复制原始X,避免污染外部数据 X_copy = X.copy().reshape(-1, 1) # 转为二维数组,符合Sklearn输入规范 X_, X_val, y_, y_val = train_test_split(X_copy, y, test_size=0.20, random_state=42) # 防止索引越界:取end和X长度的最小值 end_idx = min(self.end, len(X_copy)) for i in range(self.start, end_idx): X_copy[i] = X_copy[i]**2 * y[i] # 把处理后的X存为实例属性,供predict使用 self.X_processed = X_copy return self
2. 为什么score全是nan?
这个问题的直接诱因是fit执行失败,交叉验证无法计算有效分数,只能返回nan。另外你的自定义评分函数也不符合Sklearn的要求:
Sklearn的make_scorer要求评分函数必须接受至少两个参数:y_true(真实标签)和y_pred(模型预测结果)(无监督场景可调整,但你这里属于监督任务)。而你的accuracy方法只接受一个参数x,这会导致GridSearchCV传递参数时不匹配,即使修复了fit,评分还是会出错。
修复评分函数:
def accuracy(self, y_true, y_pred): # 这里可以根据你的实际需求调整逻辑,以下是贴合你原逻辑的示例 if y_pred > 50: return 100 else: return 1
创建scorer时,直接传递类方法即可:
scoring = make_scorer(Foo.accuracy, greater_is_better=False)
3. 其他需要注意的细节
predict方法逻辑:你当前的predict直接取输入X的最大值,但没有应用训练时的处理逻辑(对指定索引的元素平方)。修复后可以在predict中复用训练时的处理规则,保证前后逻辑一致。- 输入维度问题:Sklearn要求输入的X是二维数组(形状为
(n_samples, n_features)),你原来的X是一维的,所以需要在fit和predict中转为二维,避免潜在错误。
修复后的完整代码示例
import numpy as np from sklearn.model_selection import GridSearchCV from sklearn.metrics import make_scorer from sklearn.base import BaseEstimator from sklearn.model_selection import train_test_split class Foo(BaseEstimator): def __init__(self, start=0, end=0): self.start = start self.end = end self.X_processed = None # 初始化实例属性 def fit(self, X, y): X_copy = X.copy().reshape(-1, 1) X_, X_val, y_, y_val = train_test_split(X_copy, y, test_size=0.20, random_state=42) end_idx = min(self.end, len(X_copy)) for i in range(self.start, end_idx): X_copy[i] = X_copy[i]**2 * y[i] self.X_processed = X_copy return self def predict(self, X): # 对测试数据应用相同的处理逻辑 X_test = X.copy().reshape(-1, 1) end_idx = min(self.end, len(X_test)) for i in range(self.start, end_idx): X_test[i] = X_test[i]**2 val = np.max(X_test) return val def accuracy(self, y_true, y_pred): if y_pred > 50: return 100 else: return 1 # 主程序 X = np.array(np.random.random(200)*100) y = np.array(np.random.randint(2,size=200)) param_grid = {'start':[0, 10, 50], 'end':[60, 80, 100]} foo = Foo() scoring = make_scorer(Foo.accuracy, greater_is_better=False) grid = GridSearchCV(foo, param_grid=param_grid, scoring=scoring, verbose = 3, cv=2, refit=True) grid.fit(X, y) print(grid.best_params_)
内容的提问来源于stack exchange,提问作者BasicTex
相关产品推荐
相关产品推荐

