连续值目标做分层5折交叉验证报单样本类别过少,该如何实现?
错误原因
你触发报错是因为sklearn的分层逻辑默认将每个不同的y取值视为独立类别,要求每个类别至少有2个样本才能完成拆分,而你的y是连续型变量,存在大量仅出现1次的取值,因此直接传stratify=y会触发报错。
方案1:合并低频次bin(推荐,适配原生sklearn分层交叉验证)
该方案可以满足你合并小样本bin的需求,不需要依赖第三方包,逻辑可控:
import pandas as pd import numpy as np from sklearn.model_selection import StratifiedKFold # 步骤1:统计y各取值的出现频次 y_series = pd.Series(y) value_counts = y_series.value_counts() # 步骤2:合并小样本取值,5折交叉验证要求每个分层组至少有5个样本 # 对y的唯一值排序后做相邻合并 unique_y = np.sort(value_counts.index) y_map = {} current_group = None current_group_cnt = 0 for val in unique_y: cnt = value_counts[val] if current_group is None: current_group = val current_group_cnt = cnt else: if current_group_cnt < 5: # 当前组样本数不足5,合并当前值到该组 y_map[val] = current_group current_group_cnt += cnt else: current_group = val current_group_cnt = cnt y_map[val] = current_group # 生成分层专用的标签 stratify_y = y_series.map(y_map).values # 直接使用原生StratifiedKFold实现5折分层交叉验证 skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) for train_idx, val_idx in skf.split(x, stratify_y): x_train, x_val = x[train_idx], x[val_idx] y_train, y_val = y[train_idx], y[val_idx] # 此处写入你的模型训练、验证逻辑
如果不需要严格按取值合并,也可以用更简单的等频分箱生成分层标签:
# q为分箱数量,可根据总样本量调整,确保每个箱样本数≥5即可 stratify_y = pd.qcut(y, q=20, labels=False, duplicates='drop')
方案2:基于verstack的scsplit实现5折交叉验证
verstack的scsplit原生支持连续值分层拆分,不需要提前合并小样本bin,通过循环拆分即可实现5折验证:
from verstack import scsplit import numpy as np # 生成全量样本索引 all_idx = np.arange(len(x)) remaining_idx = all_idx.copy() folds = [] for i in range(5): if i == 4: # 最后一折直接取剩余所有样本 folds.append(remaining_idx) break # 每次从剩余样本中拆分1/(剩余折数)作为验证集 test_size = 1/(5 - i) _, val_idx, _, _ = scsplit(remaining_idx, y[remaining_idx], stratify=y[remaining_idx], test_size=test_size, random_state=42) folds.append(val_idx) remaining_idx = np.setdiff1d(remaining_idx, val_idx) # 遍历5折训练 for val_idx in folds: train_idx = np.setdiff1d(all_idx, val_idx) x_train, x_val = x[train_idx], x[val_idx] y_train, y_val = y[train_idx], y[val_idx] # 此处写入你的模型训练、验证逻辑
内容的提问来源于stack exchange,提问作者Mona Jalal
相关产品推荐
相关产品推荐

