如何在Sklearn的10折CV中手动固定20%验证集大小且不打乱数据
问题解答
当然可以用Sklearn实现你需要的这种自定义交叉验证策略。核心思路是自定义验证集的拆分规则,因为Sklearn允许传入自定义的交叉验证生成器来替代默认的KFold等方法。
具体实现步骤
你的需求是:10次迭代、每次验证集固定20%(1165个样本)、数据不打乱、验证集按顺序滑动覆盖整个数据集。可以通过两种方式实现:
方式1:直接生成拆分索引
先计算验证集大小,然后手动生成10组训练/验证索引对,传给cross_val_score的cv参数:
import numpy as np from sklearn.model_selection import cross_val_score # 计算验证集大小 val_size = int(0.2 * 5829) # 1165 n_splits = 10 n_samples = 5829 # 生成自定义拆分 def custom_split(): # 计算步长,确保10次迭代能覆盖整个数据集 step = (n_samples - val_size) // (n_splits - 1) for i in range(n_splits): val_start = i * step val_end = val_start + val_size # 处理最后一次可能超出数据集长度的情况 if val_end > n_samples: val_end = n_samples val_start = n_samples - val_size # 生成训练集和验证集索引 train_idx = np.concatenate([np.arange(val_start), np.arange(val_end, n_samples)]) val_idx = np.arange(val_start, val_end) yield train_idx, val_idx # 使用自定义拆分进行交叉验证 scores = cross_val_score(your_model, X, y, cv=custom_split())
方式2:自定义交叉验证类(更规范)
继承Sklearn的BaseCrossValidator类,封装拆分逻辑,适合复用:
import numpy as np from sklearn.model_selection import BaseCrossValidator, cross_val_score class SlidingWindowCV(BaseCrossValidator): def __init__(self, n_splits, val_size): self.n_splits = n_splits self.val_size = val_size def get_n_splits(self, X=None, y=None, groups=None): return self.n_splits def split(self, X, y=None, groups=None): n_samples = len(X) step = (n_samples - self.val_size) // (self.n_splits - 1) if self.n_splits > 1 else 0 for i in range(self.n_splits): val_start = i * step val_end = val_start + self.val_size if val_end > n_samples: val_end = n_samples val_start = n_samples - self.val_size train_idx = np.concatenate([np.arange(val_start), np.arange(val_end, n_samples)]) val_idx = np.arange(val_start, val_end) yield train_idx, val_idx # 实例化自定义交叉验证器 cv = SlidingWindowCV(n_splits=10, val_size=1165) # 执行交叉验证 scores = cross_val_score(your_model, X, y, cv=cv)
关键说明
- 两种方式都完全符合你的要求:数据不打乱、验证集固定20%大小、10次迭代、验证集按顺序滑动。
- 代码中加入了对最后一次迭代的边界处理,确保验证集不会超出数据集范围,始终保持1165个样本。
内容的提问来源于stack exchange,提问作者Murilo
相关产品推荐
相关产品推荐

