Skip to content

模型选择:选择估计器及其参数

分数和交叉验证的分数

如我们所见,每个估计器都有一个score可以判断新数据的拟合(或预测)程度的方法。该值越大越好

>>> from sklearn import datasets, svm
>>> X_digits, y_digits = datasets.load_digits(return_X_y=True)
>>> svc = svm.SVC(C=1, kernel='linear')
>>> svc.fit(X_digits[:-100], y_digits[:-100]).score(X_digits[-100:], y_digits[-100:])
0.98

为了更好地衡量预测的准确度(我们可以将预测的准确度认为是模型拟合程度的指标),我们可以将数据分多个fold,用于训练和测试:

>>> import numpy as np
>>> X_folds = np.array_split(X_digits, 3)
>>> y_folds = np.array_split(y_digits, 3)
>>> scores = list()
>>> for k in range(3):
...     # 我们使用 'list' 去复制, 为了后面可以使用'pop'方法
...     X_train = list(X_folds)
...     X_test = X_train.pop(k)
...     X_train = np.concatenate(X_train)
...     y_train = list(y_folds)
...     y_test = y_train.pop(k)
...     y_train = np.concatenate(y_train)
...     scores.append(svc.fit(X_train, y_train).score(X_test, y_test))
>>> print(scores)
[0.934..., 0.956..., 0.939...]

这称为KFold交叉验证。

交叉验证生成器

Scikit-learn具有一组类,这些类可用于根据流行的交叉验证策略来生成训练/测试索引列表。

他们都有split方法,该方法接收要拆分的数据集,并根据所选的交叉验证策略,每次迭代生成训练/测试集的索引。

本示例显示了该split方法的使用。

>>> from sklearn.model_selection import KFold, cross_val_score
>>> X = ["a", "a", "a", "b", "b", "c", "c", "c", "c", "c"]
>>> k_fold = KFold(n_splits=5)
>>> for train_indices, test_indices in k_fold.split(X):
...      print('Train: %s | test: %s' % (train_indices, test_indices))
Train: [2 3 4 5 6 7 8 9] | test: [0 1]
Train: [0 1 4 5 6 7 8 9] | test: [2 3]
Train: [0 1 2 3 6 7 8 9] | test: [4 5]
Train: [0 1 2 3 4 5 8 9] | test: [6 7]
Train: [0 1 2 3 4 5 6 7] | test: [8 9]

然后可以轻松执行交叉验证:

>>> [svc.fit(X_digits[train], y_digits[train]).score(X_digits[test], y_digits[test])
...  for train, test in k_fold.split(X_digits)]
[0.963..., 0.922..., 0.963..., 0.963..., 0.930...]

可以使用cross_val_score方法可以直接计算交叉验证的分数 。需要给定一个估计器,交叉验证对象和数据集,cross_val_score将数据集重复拆分为训练集和测试集,使用训练集训练估计器,并根据测试集为交叉验证的每次迭代计算分数。

默认情况下,cross_val_score使用估计器的score方法来计算各个分数。

请参阅测量模块以了解有关可用计算分数方法的更多信息。

>>> cross_val_score(svc, X_digits, y_digits, cv=k_fold, n_jobs=-1)
array([0.96388889, 0.92222222, 0.9637883 , 0.9637883 , 0.93036212])

n_jobs=-1 意味着计算机的所有CPU都将参与运算。

或者,可以改变scoring的值以修改评分方法。

>>> cross_val_score(svc, X_digits, y_digits, cv=k_fold,
...                 scoring='precision_macro')
array([0.96578289, 0.92708922, 0.96681476, 0.96362897, 0.93192644])

交叉验证生成器

KFold (n_splits, shuffle, random_state)

将数据集拆分为K份,在K-1份上训练,然后在剩下的第K份上进行测试。

StratifiedKFold (n_splits, shuffle, random_state)

与KFold相同,但保留每个份内的类别分布

GroupKFold (n_splits)

确保同一组数据不会同时在训练集和测试集中。

ShuffleSplit (n_splits, test_size, train_size, random_state)

随机生成训练/测试索引。

StratifiedShuffleSplit

与shuffleSplit相同,但保留每次迭代内的类别分布。

GroupShuffleSplit

确保同一组数据不会同时在训练集和测试集中。

LeaveOneGroupOut ()

采用数组对组进行观察。

LeavePGroupsOut (n_groups)

忽略P组。

LeaveOneOut ()

忽略一个观察组。

LeavePOut (p)

忽略P个观测值。

PredefinedSplit

根据预定义的拆分策略生成训练/测试索引。

练习

https://scikit-learn.org/stable/_images/sphx_glr_plot_cv_digits_001.png

在手写数字识别数据集上,绘制参数是C的线性核SVC 的交叉验证的分数(使用对数网格,从1到10)。

import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn import datasets, svm

X, y = datasets.load_digits(return_X_y=True)

svc = svm.SVC(kernel='linear')
C_s = np.logspace(-10, 0, 10)

scores = list()

答案:手写数字识别数据集练习的交叉验证

网格搜索和交叉验证估计器

网格搜索

scikit-learn提供了一个对象,该对象在给定数据的情况下,在参数网格上训练估计器和计算分数,并选择参数以最大化交叉验证的分数。该对象在创建过程中接收一个估计器对象,并提供一个估计器的API:

>>> from sklearn.model_selection import GridSearchCV, cross_val_score
>>> Cs = np.logspace(-6, -1, 10)
>>> clf = GridSearchCV(estimator=svc, param_grid=dict(C=Cs),
...                    n_jobs=-1)
>>> clf.fit(X_digits[:1000], y_digits[:1000])        
GridSearchCV(cv=None,...
>>> clf.best_score_                                  
0.925...
>>> clf.best_estimator_.C                            
0.0077...

>>> # 测试集上的预测结果没有在训练集上面的好
>>> clf.score(X_digits[1000:], y_digits[1000:])      
0.943...

默认情况下,GridSearchCV使用3-fold交叉验证。但是,如果检测到接收的是分类器而不是回归器,则使用分层的3-fold。默认值将在版本0.22中更改为5-fold交叉验证。

嵌套交叉验证

>>> cross_val_score(clf, X_digits, y_digits) 
array([0.938..., 0.963..., 0.944...])

并行执行两个交叉验证循环:一个是 GridSearchCV估计器来设置gamma,另一个是 cross_val_score测量估计器的预测性能。所得分数是对新数据的预测分数的无偏估计。

警告

您不能使用并行计算(n_jobs不等于1)嵌套对象。

交叉验证的估计器

可以在逐个算法的基础上更高效地完成交叉验证以设置参数。这就是为什么对于某些估计器,scikit-learn会提供交叉验证:评估估计器的性能 估计器,这些估计器可以通过交叉验证自动设置其参数。

>>> from sklearn import linear_model, datasets
>>> lasso = linear_model.LassoCV()
>>> X_diabetes, y_diabetes = datasets.load_diabetes(return_X_y=True)
>>> lasso.fit(X_diabetes, y_diabetes)
LassoCV()
>>> # 估计器会自动选择它的lambda值:
>>> lasso.alpha_
0.00375...

这些交叉验证估计器的名称与估计器的名称相似,所以在它们的名字后面有“CV”。

练习

在糖尿病数据集上,找到最佳正则化参数alpha。

奖励 : 您对所选择的alpha参数的值有多相信?

from sklearn import datasets
from sklearn.linear_model import LassoCV
from sklearn.linear_model import Lasso
from sklearn.model_selection import KFold
from sklearn.model_selection import GridSearchCV

X, y = datasets.load_diabetes(return_X_y=True)
X = X[:150]

答案: 糖尿病数据集练习的交叉验证

©2007-2019,scikit-learn开发人员(BSD许可证)。 显示此页面源码