scikit-learn 中的交叉验证方法

scikit-learn中提供了多种用于交叉验证的数据集分割方法。这里对这些方法的区别和应用场景做一个梳理。

基本的分割方法

首先,最常用的交叉检验方法是KFold、StratifiedKFold。
sklearn.model_selection.KFold 方法就是最简单的KFold折叠,将指定数据分为 K等分。

sklearn.model_selection.StratifiedKFold 则根据数据 label 分层。保证分割 后的K等份数据集中,每个 label 类别的数据比重与原数据集中各类别的比重基本相同。这对于分类学习来说是很重要的,因为严重的数据不均衡会影响学习效果。

KFold 和 StratifiedKFold 的split 方法也因此有所不同。KFold的split方法只需要传入数据集X;而StratifiredKFold 的split方法除了传入数据集 X 外,还要传入标签数据 y,否则会提少缺少参数。

skfolds = StratifiedKFold(n_splits=5)
skfolds.split(X)
>>>TypeError: split() missing 1 required positional argument: 'y'

实际上根据sklearn的API文档,KFold的split方法也可以接受标签数据 y,只是不会使用。


另一个 KFold 方法的变种就是GroupKFold。和StratifiedKFold 相反,不将相同类别的数据均匀分割,而是将相同类别的数据放在同一个分割数据集中。所依据的不是 数据标签label,而是可以自定义的类别 group 参数。如下面 y 是原数据标签,而 groups 是另外定义的类别。

X = np.array([[1, 2], [3, 4], [5, 6], [7, 8]]) # 训练数据
y = np.array([1, 2, 3, 4]) # 训练标签
groups = np.array([0, 0, 2, 2]) # 类别

分割后的数据集在数据量上不一定是平均的,但各自含有的 groups 类别数量上是相对均衡的。
其split方法需要输入 groups参数指定类别。

group_kfold = GroupKFold(n_splits=5)
group_kfold.split(X, y, groups) # 和KFold一样,可省略y

GroupKFold方法的存在是因为很多时候数据采集的过程存在不一致性。比如不同的时间,不同的采集对象,这些采集过程中的隐含类别,可能带来潜在影响。所以将相同隐含类别的数据放在同一组,能够知道类别间是否存在差异。在一部分类别上训练的学习器会不会对这些类别过拟合,从而了解到这些隐含类别的潜在影响程度。
由此自然地想到,groups参数 往往可以是采集数据中的时间、实体标号等等非标签数据。

Leave-Out 方法

leave-out是一种常见的验证方法,从样本中抽取一个或指定个数P个作为测试集,其他作为训练集。
这在sklearn中分别对应 LeaveOneOut和LeavePOut方法。

结合上面提到的GroupKFold方法,sklearn还提供了LeaveOneGroupOut、LeavePGroupOut方法。两者以group类别为单位来抽取测试集,也就是抽取某group类别或某P个group类别作为测试集,其他group类别作为训练集。

Shuffle随机方法

sklearn.model_selection.ShuffleSplit是比较简单粗暴的分割方法。不考虑标签类别和group类别,只将数据按指定次数随机排序后,再按指定的比例分割为训练集和测试集。

# n_splits 指定随机洗牌和分割迭代的次数 ,也就是得到训练测试集的组数
# test_size、tran_size为0~1之间的数,用于指定数据集比例,默认test_size = 0.1。
rs = ShuffleSplit(n_splits=5, test_size=.25, random_state=0)
rs.split(X)

进一步还有 StratifiedShuffleSplit 方法和 GroupShuffleSplit 方法。分别保证训练测试集中各label类别数据量均衡,以及同一group类别的数据只存在于训练集和测试集两者之一。

shuffle方法的意义一定程度上体现在,当Leave-Out方法用于大规模数据时,要得到所有可能的分组可能代价过大,这时使用shuffle方法指定次数,得到有限数目的训练测试集(可重复)。

Repeated重复方法

sklearn.model_selection.RepeatedKFold 方法是多次重复KFold的方法。
如下面只用KFold方法会执行一个K层叠。而使用RepeatedKFold方法,指定重复次数n_repeats=2,则执行两次KFold,且可以在一个for循环中取出分割数据。

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([0, 0, 1, 1])

kf = KFold(n_splits=2)
for train_index, test_index in kf.split(X):
  print("TRAIN:", train_index, "TEST:", test_index)
  X_train, X_test = X[train_index], X[test_index]
  y_train, y_test = y[train_index], y[test_index]
>>>
TRAIN: [2 3] TEST: [0 1]
TRAIN: [0 1] TEST: [2 3]

rkf = RepeatedKFold(n_splits=2, n_repeats=2, random_state=2652124)
for train_index, test_index in rkf.split(X):
  print("TRAIN:", train_index, "TEST:", test_index)
  X_train, X_test = X[train_index], X[test_index]
  y_train, y_test = y[train_index], y[test_index]
>>>
TRAIN: [0 1] TEST: [2 3]
TRAIN: [2 3] TEST: [0 1]
TRAIN: [1 2] TEST: [0 3]
TRAIN: [0 3] TEST: [1 2]

类似的还有RepeatedStratifiedKFold方法。

Predefined预定义方法

sklearn.model_selection.PredefinedSplit 方法用来自定义数据分割。在定义时通过test_fold参数接受一个与样本长度一样的数据,使用0或1指定每个样本属于训练集或测试集。
该方法返回两组训练测试集,0和1的样本分别作为训练集和测试集。样本还可以被指定为-1,表示两次都属于训练集。

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([0, 0, 1, 1])
test_fold = [0, 1, -1, 1]
ps = PredefinedSplit(test_fold)

for train_index, test_index in ps.split():
  print("TRAIN:", train_index, "TEST:", test_index)
  X_train, X_test = X[train_index], X[test_index]
  y_train, y_test = y[train_index], y[test_index]
>>>
TRAIN: [1 2 3] TEST: [0]
TRAIN: [0 2] TEST: [1 3]


时间序列数据分割

时间序列的数据由于其时间上的关联性,不能进行重排序。sklearn.model_selection.TimeSeriesSplit 方法也是KFold方法的一个变种,在第k次分割时,只返回前 k 份数据作为训练集,第k+1份数据作为测试集。

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4, 5, 6])
tscv = TimeSeriesSplit(n_splits=3) # 可通过参数 max_train_size 指定训练集大小的上限

for train_index, test_index in tscv.split(X):
  print("TRAIN:", train_index, "TEST:", test_index)
  X_train, X_test = X[train_index], X[test_index]
  y_train, y_test = y[train_index], y[test_index]
>>>
TRAIN: [0 1 2] TEST: [3]
TRAIN: [0 1 2 3] TEST: [4]
TRAIN: [0 1 2 3 4] TEST: [5]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容