Label Propagation结合网格搜索与交叉验证的自定义评分问题咨询
解决方案
核心逻辑是拆分和评分全用全量真实标签,仅在模型训练阶段给训练集标签打-1掩码,有两个低成本实现方式:
方案一:自定义估计器包装器(无需改动GridSearchCV逻辑)
将带掩码的标签提前注入自定义的半监督模型包装类,训练时自动替换训练集标签为带-1的版本,全程用真实标签做拆分和评分:
from sklearn.base import BaseEstimator, ClassifierMixin from sklearn.semi_supervised import LabelPropagation from sklearn.model_selection import GridSearchCV, StratifiedShuffleSplit from sklearn.metrics import accuracy_score import numpy as np # 1. 提前准备两份标签 y_true_full = np.array([0,0,0,1,1,1]) # 全真实标签,无-1,用于拆分、评分 y_masked = np.array([0,0,-1,1,1,-1]) # 带无标注掩码的标签,仅用于模型训练 # 2. 自定义模型包装器 class MaskedLabelPropagation(BaseEstimator, ClassifierMixin): def __init__(self, y_masked, kernel='rbf', gamma=20): self.y_masked = y_masked self.kernel = kernel self.gamma = gamma self.model = None def fit(self, X, y): # 取X第一列存储的全局索引,匹配对应掩码标签,训练用X除第一列外的原始特征 global_idx = X[:,0].astype(int) train_X = X[:,1:] train_y_masked = self.y_masked[global_idx] self.model = LabelPropagation(kernel=self.kernel, gamma=self.gamma) self.model.fit(train_X, train_y_masked) return self def predict(self, X): test_X = X[:,1:] return self.model.predict(test_X) # 3. 构造带全局索引的输入,保证拆分后索引与样本对应 X_origin = # 填入你的原始特征,shape为(n_samples, n_features) X_with_idx = np.hstack([np.arange(len(X_origin)).reshape(-1,1), X_origin]) # 4. 正常执行GridSearchCV,全程用y_true_full做拆分和评分 param_grid = {'gamma': [10,20,30]} cv = StratifiedShuffleSplit(n_splits=5, test_size=0.5, random_state=42) grid = GridSearchCV( estimator=MaskedLabelPropagation(y_masked=y_masked), param_grid=param_grid, cv=cv, scoring='accuracy', # 直接用原生评分函数即可,拿到的y都是真实0/1 n_jobs=-1 ) grid.fit(X_with_idx, y_true_full)
方案二:手动遍历参数网格(代码量更少,灵活度更高)
如果不想做封装,直接先生成所有折的拆分索引,手动遍历参数网格,训练时加掩码、评分用真实标签即可:
from sklearn.model_selection import ParameterGrid, StratifiedShuffleSplit param_grid = ParameterGrid({'gamma':[10,20,30], 'kernel':['rbf','knn']}) cv = StratifiedShuffleSplit(n_splits=5, test_size=0.5, random_state=42) best_score = 0 best_params = None for params in param_grid: fold_scores = [] for train_idx, test_idx in cv.split(X_origin, y_true_full): # 训练阶段用带-1的掩码标签 train_y = y_masked[train_idx] model = LabelPropagation(**params) model.fit(X_origin[train_idx], train_y) # 评分阶段用全真实标签 pred = model.predict(X_origin[test_idx]) fold_scores.append(accuracy_score(y_true_full[test_idx], pred)) mean_score = np.mean(fold_scores) if mean_score > best_score: best_score = mean_score best_params = params print(f"最优参数{best_params}, 平均得分{best_score}")
两种方案都不需要重写复杂的网格搜索逻辑,方案二更适合半监督这类需要自定义训练/评分逻辑的场景,维护成本更低。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

