如何选择最优的模型?
这就需要对模型进行评估。评估的标准一定是看模型的泛化误差。
但是只有数据集D这么多样本,怎么办?
将D划分,一部分用来训练模型,一部分用来测试模型的表现。
上面所说的对数据集D进行划分的方法有三种:留出法、交叉验证法、自助法
留出法
最简单,直接将D分为 训练集 和 测试集。训练集训练出模型,然后在测试集上测试性能。
sklearn里面train_test_split()函数可以实现这个功能,随机划分数据。
- 留出法太简单了,如果模型需要调超参数,那就还要在上面的训练集中划分出一部分作为验证集。这样用于训练的数据又变少了,而且划分不同,训练出来的模型也会不同…所以需要交叉验证。
- 注:验证集的存在就是为了调参。测试集是用来看最终确定下来的模型(超参数已经确定)的好坏。
交叉验证
交叉验证还可分为:普通k折交叉验证Kfold、p次k折交叉验证RepeatedKfold、留一法LeaveOneOut
1.交叉验证进行数据划分/交叉验证迭代器
KFold
sklearn里KFold是一个类,创建对象的时候记得给参数n_split。
官网解释
class sklearn.model_selection.KFold(n_splits=5, *, shuffle=False, random_state=None)
参数:
n_splits : int, default=5 折数。必须至少为2。0.22版本中:n_splits默认值从3更改为5。)
shuffle : bool, default=False 在切分之前是否打乱数据。注意,每次切分内的样本都不会被打乱。
random_state : int or RandomState instance, default=None 当shuffle为True时,random_state会影响索引的顺序,从而控制每折交叉的随机性。否则,此参数无效。
方法 :
get_n_splits(self[, X, y, groups]) 返回交叉验证器中的切分迭代次数。
split(self,X[, y, groups]) 生成索引以将数据切分为训练集和测试集。
注意:split()方法是生成一个迭代器,并且遍历时取出的是index。
from sklearn.model_selection import KFold
xx = np.array(['a', 'b', 'c', 'd'])
kkff = KFold(n_splits=2, shuffle=True, random_state=0)
for x, y in kkff.split(xx):
print(x, y)
print(xx[x], xx[y])
[0 1] [2 3]
['a' 'b'] ['c' 'd']
[2 3] [0 1]
['c' 'd'] ['a' 'b']
Leave One Out(LOO)
交叉验证的特例,即交叉验证的折数等于样本的个数。训练集是除去一个样本后剩余的样本,验证集是除去的那一个样本。
LOO不会浪费很多数据,不会受集合划分方式的影响,但是开销很大。
注:作为通用规则,大多数作者,及实际经验表明,5-或者10-交叉验证会优于LOO。
class sklearn.model_selection.LeaveOneOut
方法
get_n_splits(self, X[, y, groups]) 返回交叉验证器中的切分迭代次数
split(self, X[, y, groups]) 生成索引以将数据切分为训练集和测试集
from sklearn.model_selection import LeaveOneOut
loo = LeaveOneOut()
print(loo.get_n_splits(xx))
for x, y in loo.split(xx):
print(x, y)
print(xx[x], xx[y])
4
[1 2 3] [0]
['b' 'c' 'd'] ['a']
[0 2 3] [1]
['a' 'c' 'd'] ['b']
[0 1 3] [2]
['a' 'b' 'd'] ['c']
[0 1 2] [3]
['a' 'b' 'c'] ['d']
Leave P Out(LPO)
和KFold不同的是,它产生 C n p C_n^p Cnp种训练-测试组合。所以p>1时,测试集会重叠。
from sklearn.model_selection import LeavePOut
lpo = LeavePOut(p=2)
for x, y in lpo.split(xx):
print(x, y)
print(xx[x], xx[y])
[2 3] [0 1]
['c' 'd'] ['a' 'b']
[1 3] [0 2]
['b' 'd'] ['a' 'c']
[1 2] [0 3]
['b' 'c'] ['a' 'd']
[0 3] [1 2]
['a' 'd'] ['b' 'c']
[0 2] [1 3]
['a' 'c'] ['b' 'd']
[0 1] [2 3]
['a' 'b'] ['c' 'd']
2.交叉验证进行模型评估
在1.中,讲的是如何使用交叉验证划分数据。sklearn也直接提供了用交叉验证对模型评分的方法。
cross_value_score()函数
官网文档
不像数据集划分要先创建类对象,这直接使用一个函数完成。
sklearn.model_selection.cross_val_score(estimator, X, y=None, *, groups=None, scoring=None, cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch='2*n_jobs', error_score=nan)
参数:
estimator:模型算法对象。比如lin_reg.
X : 训练样本。
y:样本标签。
cv : int, cross-validation generator or an iterable, default=None. 确定交叉验证的数据集划分策略。
cross-validation generator的话就是1.中讲的那些放方法,所以可以传kf,loo,lpo,
int的话,就是指几折,然后用普通的kfold。
- cross_val_score这一个函数干了很多事情,划分数据集、对每个划分进行了训练、对每个划分进行了测试评分。
# 使用交叉验证评估模型
# 这里用普通线性模型来拟合CCPP数据
lin_reg = LinearRegression()
# 先划分训练集和测试集,75%训练
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, shuffle=True, random_state=0)
# 10折交叉验证评分
score = cross_val_score(estimator=lin_reg, X=X_train, y=y_train, cv=10)
print('交叉验证评分:\n', score, sep='')
# cross_val_score这一个函数干了很多事情,划分数据集、对每个划分进行了训练、对每个划分进行了测试评分。
cross_val_predict()函数
用法和cross_val_score一样,它返回的是预测值y。是所有训练样本的预测值,因为交叉验证在每个折上都测试过一次。
predicts = cross_val_predict(estimator=lin_reg, X=X_train, y=y_train, cv=10)
print('交叉验证预测:\n', predicts, sep='')
交叉验证预测:
[469.76829631 446.026313 471.37838697 ... 464.07242275 471.18232228
444.01500631]
cross_validate()函数
cross_validate方法和cross_validate_score有个两个不同点:它允许传入多个评估方法,可以使用两种方法来传入,一种是列表的方法,另外一种是字典的方法。最后返回的scores为一个字典,字典的key为:dict_keys([‘fit_time’, ‘score_time’, ‘test_score’, ‘train_score’])