sklearn——交叉验证

一、简介

  在用机器学习训练模型的时候,会将数据集D划分成训练集和测试集,因为如果在相同的数据上训练并测试无法评估模型的效果,常用的划分方法有K折交叉验证、p次k折交叉验证、留出法、留一法、留P法、随机分配、自助法等。另外,在训练模型的时候,经常需要进行调参,当我们有一堆参数的时候,也可以用类似的较差验证的方式依次使用不同的参数建模,最后选择最好的一个参数。在sklearn中要实现主要用sklearn.model_selection包的各种类,下面进行详细介绍。

 

 

二、数据集交叉验证方法

1、留出法

  留出法的方法很简单,将数据集D分为两个部分,一个作为训练集另一个作为测试集,一般会选择70%的数据作为训练集。

 

对应的方法:

  sklearn.model_selection.train_test_split(*arrays, **options)

  • *arrays:数组,可以传入多个,例如同时传入x,y或者传入x,y,z。传入的数据类型为lists,、numpy arrays、scipy-sparse matrices、pandas dataframes。
  • test_size:如果是float数据,表示测试集的占比;如果是None则默认取占比0.25;如果是int数据,则表示测试集样本个数。
  • train_size:如果是float数据,表示训练集的占比;如果是None则默认取占比0.25;如果是int数据,则表示训练集样本个数。
  • random_state:随机数种子。
  • shuffle:是否清洗数据,若false,则不清洗。
  • stratify:数据是否按Y的class分层的方式来划分,若Ture则是。例如Y的class=[‘a’,'b'],其中a占0.9、b占0.1,则划分训练集与测试集之后,训练集与测试集中a、b的占比不变。

 

方法return:

  一个包含分裂后训练集、测试集的列表,列表形式为[x_train,x_test,y_train,y_test,....]。

 

代码示例:

from sklearn.model_selection import train_test_split
import numpy as np

x = np.arange(10)  # 创建一维属性x
y = np.arange(10)  # 创建一维属性y

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)  # 划分测试集与训练集

print('x_train:', x_train)
print('x_test:', x_test)
print('y_train:', y_train)
print('y_test:', y_test)

'''
结果:
x_train: [2 0 1 7 5 9 4 8]
x_test: [3 6]
y_train: [2 0 1 7 5 9 4 8]
y_test: [3 6]
'''

 

 

2、K折交叉验证

  将数据集分为k等份,每次训练时,将其中k-1份用作训练集,单独的那一份用作测试集,依次训练K次,可以选择训练效果较好的那份或者以平均模型优度作为模型优度。

 

对应的类:

  sklearn.model_selection.KFold(n_splits=3, shuffle=False, random_state=None)

  • n_splits:几折,划分为几等分。

  • shuffle:在每次划分时,是否进行洗牌,不洗牌的话则按顺序划分。

    • 若为Falses时,其效果等同于random_state等于整数,每次划分的结果相同

    • 若为True时,每次划分的结果都不一样,表示经过洗牌,随机取样的

  • random_state:随机种子数

 

类的方法:

  • get_n_splits(X=None, y=None, groups=None):获取参数n_splits的值,返回交叉验证的train-test的个数。
  • split(X, y=None, groups=None):将数据集划分成训练集和测试集,返回索引生成器(即每一份样本在数据集D中的位置)。

 

代码示例:

from sklearn.model_selection import KFold
import numpy as np

x = np.arange(12)   #创建一维属性x

fold = KFold(3) #创建3折交叉验证

for train_index, test_index in fold.split(x):
    print('训练集索引:', train_index)
    print('测试集索引:', test_index)
    print('-------------------------------')


'''
结果:
训练集索引: [ 4 5 6 7 8 9 10 11] 测试集索引: [0 1 2 3] ------------------------------- 训练集索引: [ 0 1 2 3 8 9 10 11] 测试集索引: [4 5 6 7] ------------------------------- 训练集索引: [0 1 2 3 4 5 6 7] 测试集索引: [ 8 9 10 11] -------------------------------
'''

 

 

3、p次K折交差验证

  有时候,依次K折交叉验证不能够满足训练要求,可以进行p次,经典的例如10次10折交叉验证。

 

对应的类:

  sklearn.model_selection.RepeatedKFold(n_splits=5,n_repeats=2,random_state =0)

  • n_splits:几折,划分为几等分。
  • n_repeats:重复的次数,即p次K折的p。
  • random_state :随机数种子。

 

类的方法:

  • get_n_splits(X=None, y=None, groups=None):获取参数n_splits的值,即返回交叉验证的train-test的个数。
  • split(X, y=None, groups=None):将数据集划分成训练集和测试集,返回索引生成器(即每一份样本在数据集D中的位置)。

 

注意:

  RepeatedKFold在划分的时候,重复p次,每次重复会进行1次k折划分,每次划分都是随机的,这个与KFold默认方式是不同的。

 

代码示例:

from sklearn.model_selection import RepeatedKFold
import numpy as np

x = np.arange(12)   #创建一维属性x

fold = RepeatedKFold(n_splits=3,n_repeats=2) #创建3折交叉验证

for train_index, test_index in fold.split(x):
    print('训练集索引:', train_index)
    print('测试集索引:', test_index)
    print('-------------------------------')


'''
结果:
训练集索引: [ 1 2 3 4 5 8 10 11] 测试集索引: [0 6 7 9] ------------------------------- 训练集索引: [ 0 3 4 6 7 9 10 11] 测试集索引: [1 2 5 8] ------------------------------- 训练集索引: [0 1 2 5 6 7 8 9] 测试集索引: [ 3 4 10 11] ------------------------------- 训练集索引: [0 2 3 5 6 7 8 9] 测试集索引: [ 1 4 10 11] ------------------------------- 训练集索引: [ 1 4 6 7 8 9 10 11] 测试集索引: [0 2 3 5] ------------------------------- 训练集索引: [ 0 1 2 3 4 5 10 11] 测试集索引: [6 7 8 9] ------------------------------- '''

 

 

4、留一较差验证

  留一法就是Kflod的特殊形式k=1,即每次取1个样本作为测试集,其余做训练集。

 

对应的类:

  sklearn.model_selection.train_test_split()

 

类的方法:

  • get_n_splits(X=None, y=None, groups=None):返回较差验证的train-test数据对的个数。
  • split(X, y=None, groups=None):将数据集划分成训练集和测试集,返回索引生成器(即每一份样本在数据集D中的位置)。

 

代码示例:

from sklearn.model_selection import LeaveOneOut
import numpy as np

x = np.arange(4)  # 创建一维属性x
leaveoneout=LeaveOneOut()

for train,test in leaveoneout.split(x) : # 划分测试集与训练集
    print('x_train:', train)
    print('x_test:', test)
    print('------------------------------------------------------')


'''
结果:
x_train: [1 2 3]
x_test: [0]
------------------------------------------------------
x_train: [0 2 3]
x_test: [1]
------------------------------------------------------
x_train: [0 1 3]
x_test: [2]
------------------------------------------------------
x_train: [0 1 2]
x_test: [3]
------------------------------------------------------
'''

 

 

5、留P交叉验证

  从数据集D中选P个样本作为测试集,其余作为训练集,直到选出所有的可能的P个组合为止。当P=1的时候就是留一交叉验证。

 

对应的类:

  sklearn.model_selection.LeavePOut(p)

  • p:测试集的样本数。

 

类的方法:

  • get_n_splits(X=None, y=None, groups=None):返回较差验证的train-test数据对的个数。
  • split(X, y=None, groups=None):将数据集划分成训练集和测试集,返回索引生成器(即每一份样本在数据集D中的位置)。

 

代码示例:

from sklearn.model_selection import LeavePOut
import numpy as np

x = np.arange(4)  # 创建一维属性x
leavePout=LeavePOut(2)

for train,test in leavePout.split(x) : # 划分测试集与训练集
    print('x_train:', train)
    print('x_test:', test)
    print('------------------------------------------------------')


'''
结果:
x_train: [2 3]
x_test: [0 1]
------------------------------------------------------
x_train: [1 3]
x_test: [0 2]
------------------------------------------------------
x_train: [1 2]
x_test: [0 3]
------------------------------------------------------
x_train: [0 3]
x_test: [1 2]
------------------------------------------------------
x_train: [0 2]
x_test: [1 3]
------------------------------------------------------
x_train: [0 1]
x_test: [2 3]
------------------------------------------------------
'''

 

 

6、随机交叉验证

  从数据集D中随机选择样本划分训练集与测试集,可以根据需要选择需要重复几次,重复n次能获得n个train-test样本对。

 

对应的类:

  sklearn.model_selection.ShuffleSplit(n_splits=10, test_size=None, train_size=None, random_state=None)

  • n_splits:几折,划分为几等分。

  • test_size:如果是float数据,表示测试集的占比;如果是None则自动设置;如果是int数据,则表示测试集样本个数。
  • train_size:如果是float数据,表示训练集的占比;如果是None则自动设置;如果是int数据,则表示训练集样本个数。
  • random_state:随机种子数

 

类的方法:

  • get_n_splits(X=None, y=None, groups=None):返回较差验证的train-test数据对的个数。
  • split(X, y=None, groups=None):将数据集划分成训练集和测试集,返回索引生成器(即每一份样本在数据集D中的位置)。

 

代码示例:

from sklearn.model_selection import ShuffleSplit
import numpy as np

x = np.arange(10)  # 创建一维属性x
SS=ShuffleSplit(3,test_size=0.2)

for train,test in SS.split(x) : # 划分测试集与训练集
    print('x_train:', train)
    print('x_test:', test)
    print('------------------------------------------------------')


'''
结果:
x_train: [5 3 2 9 6 8 1 7]
x_test: [4 0]
------------------------------------------------------
x_train: [9 1 5 8 0 3 7 4]
x_test: [6 2]
------------------------------------------------------
x_train: [4 9 3 7 5 6 2 8]
x_test: [1 0]
------------------------------------------------------
'''

 

 

7、其它特殊情况的数据划分方法

1:对于分类数据来说,它们的target可能分配是不均匀的,比如在医疗数据当中得癌症的人比不得癌症的人少很多,这个时候,使用的数据划分方法有  StratifiedKFold  ,StratifiedShuffleSplit

2:对于分组数据来说,它的划分方法是不一样的,主要的方法有 GroupKFold,LeaveOneGroupOut,LeavePGroupOut,GroupShuffleSplit

3:对于时间关联的数据,方法有TimeSeriesSplit

 

 

三、模型评估交叉验证

  对数据集可以进行交叉验证从而建立交叉验证模型,也可以对模型的评估利用交叉验证的方法。sklearn的一些评估方法同样可以用于交叉验证。

 

1、模型准确度评分交叉验证

对应的方法:

  sklearn.model_selection.cross_val_score(estimator, X, y=None,  cv=’warn’,......)

  • estimator:sklearn的estimator类,即各种模型。
  • cv:几折验证,默认是3。

 

方法return:

  一个包含所有交叉验证的score的列表。

 

代码示例:

from sklearn import datasets
from sklearn import svm
from sklearn.model_selection import cross_val_score

iris = datasets.load_iris()

clf = svm.SVC(kernel='linear', C=1)
scores = cross_val_score(clf, iris.data, iris.target, cv=5)

print(scores)


'''
结果:
[0.96666667 1.         0.96666667 0.96666667 1.        ]

 

 

2、其他评估方法交叉验证

对应方法:

  sklearn.model_selection.cross_validate(estimator, X, y=None, scoring=None, cv=’warn’,......)  

  • estimator:sklearn的estimator类,即各种模型。
  • scoring:sklearn的评估方法,可以有很多个,可以用字典或列表方式传入。
  • cv:几折验证,默认是3。

 

方法return:

  一个字典,加入有n个方法,则字典的key=['fit_time', 'score_time', 'test_scoringname1', 'test_scoringname2',...,'test_scoringnamen'],表示[训练时间, 测试时间, 测试分1, 测试分2, ..., 测试分n],每个key对应的值为所有交叉验证的值组成的数组。如5折交叉验证,'fit_time'的值为5次交叉验证的训练时间。

 

代码示例:

from sklearn.model_selection import cross_validate
from sklearn.svm import SVC
from sklearn.datasets import load_iris

iris = load_iris()

scoring = ['precision_macro', 'recall_macro']  # 两个方法,非字典
clf = SVC(kernel='linear', C=1, random_state=0)
scores = cross_validate(clf, iris.data, iris.target, scoring=scoring, cv=5, return_train_score=False)

print(scores.keys())  # 显示dict的key
print(scores['test_recall_macro'])  # 打印其中一个方法的值

'''
结果:
dict_keys(['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro'])
[0.96666667 1.         0.96666667 0.96666667 1.        ]
'''
from sklearn.model_selection import cross_validate
from sklearn.svm import SVC
from sklearn.metrics import make_scorer,recall_score
from sklearn.datasets import load_iris
iris = load_iris()

#传入字典
scoring = {'prec_macro': 'precision_macro','rec_micro': make_scorer(recall_score, average='macro')}

clf = SVC(kernel='linear', C=1, random_state=0)
scores = cross_validate(clf, iris.data, iris.target, scoring=scoring,cv=5, return_train_score=False)

print(scores.keys())
print(scores['test_rec_micro'])

'''
结果:
dict_keys(['fit_time', 'score_time', 'test_prec_macro', 'test_rec_micro'])
[0.96666667 1.         0.96666667 0.96666667 1.        ]
'''

 

 

3、预测交叉验证

对应方法:

  cross_val_predict

说明:

  cross_val_predict 和 cross_val_score的使用方法是一样的,但是它返回的是一个使用交叉验证以后的输出值

 

 

三、利用交叉验证进行模型调参

  通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。在sklearn中有一个方法GridSearchCV可以用来进行方便的调参,只需要提前设置后要传入的超参数就可以。

  

对应的类:

  sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, n_jobs=None, iid=’warn’, refit=True, cv=’warn’, verbose=0, pre_dispatch=‘2*n_jobs’, error_score=’raise-deprecating’, return_train_score=False)

  • estimator:估计器。
  • param_grid:估计器参数,用字典的形式传入,字典的key对应估计器的参数,字典key的value对应估计器参数要传入的值。
  • scoring:模型评价方法。
  • n_jobs:线程数,默认1,-1表示全部线程。
  • cv:几折,默认3.

 

类的方法:

  • fit(x,y):传入训练数据。
  • score():返回评估准确率。

 

类的属性:

  • bestscore:在交叉验证中验证的最好结果。
  • bestestimator:最好的参数模型。
  • cvresults:每次交叉验证后的验证集准确率结果和训练集准确率结果。

 

代码示例:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

# 加载数据
iris = load_iris()

# 划分数据集
x_train,x_test,y_train,y_test = train_test_split(iris.data,iris.target,test_size=0.3,random_state=8)

# 标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 指定算法及模型选择与调优——网格搜索和交叉验证
estimator = KNeighborsClassifier()
param_dict = {"n_neighbors": [1, 3, 5]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)

# 训练模型
estimator.fit(x_train,y_train)

# 模型评估
# 方法一 比对真实值与预测值
y_predict = estimator.predict(x_test)
y_test == y_predict
# 方法二 计算准确率
estimator.score(x_test,y_test)

# 然后进行评估查看最终选择的结果和交叉验证的结果
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的准确率结果:\n", estimator.cv_results_)

 

posted @ 2019-11-06 18:48  我不是高斯分布  阅读(1345)  评论(0编辑  收藏  举报