机器学习之交叉验证~验证集的出现!

第一部分:使用交叉验证的背景和必要性

一般来说,我们将数据集分为训练集和测试集,其中训练集用于训练模型,测试集用来评估模型。

通常我们会用测试集的效果来反映训练过程中模型是否产生了“过拟合”。

但是有很小的概率,就是我们训练的这个模型本身就是“过拟合”,但是很碰巧的是(尽管概率很低),我们拿出来的测试集进行验证的过程中,这些测试集跟原本数据非常相似,得出的训练效果很好,因此就导致这次训练效果产生了错误的假象,本身应该是“过拟合”,却得出“正常”的效果。

解决思路:

为了防止这种非常小概率的极端情况的出现,我们能够想到,如果出现这种情况的概率为1/10,那我们完全可以多训练几回,这样回回都出错的概率将会更低,比如我们训练3回,全部都碰巧出现这种“极端情况”的概率将会是1/1000.

而实现这种训练多回,我们就需要有一个新的数据集来实现,也就是将数据集多分了一个部分,叫做“验证集”

第二部分:训练集+测试集+验证集

训练集:训练模型

测试集:评价最终效果

验证集:搜索最优超参数

以生活中的考试例子:

第三部分:K-fold交叉验证

将这K次的验证结果取平均,作为模型在该数据集上的最终表现。

第四部分:K-fold代码实现

我们以:“机器学习中的超参数(以鸢尾花数据集为例,knn算法,使用网格搜索最优化超参数)”为例:详细内容可以见我的博客:

机器学习中的超参数(以鸢尾花数据集为例,knn算法,使用网格搜索最优化超参数)!-CSDN博客

主要包含以下两种代码:

(1)手写-使用网格搜索实现最优化超参数

#第一步:导包
import numpy as np
from sklearn import datasets

#第二步:获取数据集
iris=datasets.load_iris()
#iris可以详细查看这个数据集里面的具体内容
#2.1获取特征数据X
X=iris.data
#iris.feature_names获取特征的名字
'''
结果为:
['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']
'''
#2.2获取标签值
Y=iris.target
#iris.target_names#获取特征的名字
'''
结果为:
array(['setosa', 'versicolor', 'virginica'], dtype='<U10')
'''
#第三步:划分数据集(训练集+测试集)
from sklearn.model_selection import train_test_split#这个是新增的
X_train,X_test,Y_train,Y_test=train_test_split(X,Y,train_size=0.7,random_state=233,stratify=Y)#train_size=0.7是测试集比例,233是随机数种子
#stratify=y作用是让这划分之后的训练集和测试集中三个样本的数量能够平均,不会出现某种类别多,某种类别少的情况

#第四步:设置超参数
#第一个超参数k,第二个超参数同等权重还是按距离递减权重
from sklearn.neighbors import KNeighborsClassifier
knn_classifer=KNeighborsClassifier(

)

#第四步:新修改的超参数-网格搜索
#初始化参数
best_score=-1;
best_n=-1;
best_weight='';
best_p=-1;
for k in range(1,20):#代表的是k值,邻居的数量
    for weight in ['uniform','distance']:
        for p in range(1,4):#代表三种距离
            knn_classifer=KNeighborsClassifier(
                n_neighbors=k,  # 设置初始的k=3
                weights=weight,  # distance这个代表按距离递减权重,#uniform是同等权重
                p=p  # 1代表是曼哈顿距离,2代表是欧式距离,3代表是明氏距离
            )
            # 调用fit进行训练
            knn_classifer.fit(X_train, Y_train)
            from sklearn.metrics import accuracy_score
            # 第五步:使用训练集开始进行预测
            Y_predict = knn_classifer.predict(X_test)
            #score=accuracy_score(Y_test, Y_predict)
            score=knn_classifer.score(X_test,Y_test)
            #上面这两个的结果是一样的
            if(score>best_score):
                best_score=score
                best_weight=weight
                best_p=p
                best_n=k

print("best_score=",best_score)
print("best_weight=",best_weight)
print("best_p=",best_p)
print("best_n=",best_n)

(2)sklearn实现超参数网格搜索(快捷版本)

#第一步:导包
import numpy as np
from sklearn import datasets

#第二步:获取数据集
iris=datasets.load_iris()
#iris可以详细查看这个数据集里面的具体内容
#2.1获取特征数据X
X=iris.data
#iris.feature_names获取特征的名字
'''
结果为:
['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']
'''
#2.2获取标签值
Y=iris.target
#iris.target_names#获取特征的名字
'''
结果为:
array(['setosa', 'versicolor', 'virginica'], dtype='<U10')
'''
#第三步:划分数据集(训练集+测试集)
from sklearn.model_selection import train_test_split#这个是新增的
X_train,X_test,Y_train,Y_test=train_test_split(X,Y,train_size=0.7,random_state=233,stratify=Y)#train_size=0.7是测试集比例,233是随机数种子
#stratify=y作用是让这划分之后的训练集和测试集中三个样本的数量能够平均,不会出现某种类别多,某种类别少的情况
#第四部分:KNN超参数搜索
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier

params = {
    'n_neighbors': [n for n in range(1, 20)],
    'weights': ['uniform', 'distance'],
    'p': [p for p in range(1, 7)]
}

grid = GridSearchCV(
    estimator=KNeighborsClassifier(),
    param_grid=params,
    n_jobs=-1
)
grid.fit(X_train, Y_train)
# 输出最优超参数
print(grid.best_params_)
print(grid.best_score_)

(3)两种计算结果的差异性对比

这个计算的结果不同,第一种计算的neighbors=5,第二回用内置函数计算得到的结果是neighbors=9,主要是因为 这个内置函数和我们实际计算的方法略有区别(sklearn里面用的有交叉验证,弥补了极端情况下无法检测到过拟合的情况)。

(4)再次手动代码验证上述交叉验证的结果

将“(1)手写-使用网格搜索实现最优化超参数”代码中:

在初始化参数部分加上best_cv_score=None:

#初始化参数
best_score=-1;
best_n=-1;
best_weight='';
best_p=-1;
best_cv_score=None#新加的

删掉下面这段代码:

            # 调用fit进行训练
            knn_classifer.fit(X_train, Y_train)
            from sklearn.metrics import accuracy_score
            # 第五步:使用训练集开始进行预测
            Y_predict = knn_classifer.predict(X_test)
            #score=accuracy_score(Y_test, Y_predict)
            #score=knn_classifer.score(X_test,Y_test)

替换成:

 from sklearn.model_selection import cross_val_score
            cv_scores=cross_val_score(knn_classifer,X_train,Y_train,cv=5)
            score=np.mean(cv_scores)

if语句里面加上 best_cv_score=cv_scores:

 if(score>best_score):
                best_score=score
                best_weight=weight
                best_p=p
                best_n=k
                best_cv_score=cv_scores#新加的

输出部分加上:

print("best_cv_score=",best_cv_score)

修改后的完整代码为:

#第一步:导包
import numpy as np
from sklearn import datasets

#第二步:获取数据集
iris=datasets.load_iris()
#iris可以详细查看这个数据集里面的具体内容
#2.1获取特征数据X
X=iris.data
#iris.feature_names获取特征的名字
'''
结果为:
['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']
'''
#2.2获取标签值
Y=iris.target
#iris.target_names#获取特征的名字
'''
结果为:
array(['setosa', 'versicolor', 'virginica'], dtype='<U10')
'''
#第三步:划分数据集(训练集+测试集)
from sklearn.model_selection import train_test_split#这个是新增的
X_train,X_test,Y_train,Y_test=train_test_split(X,Y,train_size=0.7,random_state=233,stratify=Y)#train_size=0.7是测试集比例,233是随机数种子
#stratify=y作用是让这划分之后的训练集和测试集中三个样本的数量能够平均,不会出现某种类别多,某种类别少的情况

#第四步:设置超参数
#第一个超参数k,第二个超参数同等权重还是按距离递减权重
from sklearn.neighbors import KNeighborsClassifier
knn_classifer=KNeighborsClassifier(

)

#第四步:新修改的超参数-网格搜索
#初始化参数
best_score=-1;
best_n=-1;
best_weight='';
best_p=-1;
best_cv_score=None
for k in range(1,20):#代表的是k值,邻居的数量
    for weight in ['uniform','distance']:
        for p in range(1,4):#代表三种距离
            knn_classifer=KNeighborsClassifier(
                n_neighbors=k,  # 设置初始的k=3
                weights=weight,  # distance这个代表按距离递减权重,#uniform是同等权重
                p=p  # 1代表是曼哈顿距离,2代表是欧式距离,3代表是明氏距离
            )

            from sklearn.model_selection import cross_val_score
            cv_scores=cross_val_score(knn_classifer,X_train,Y_train,cv=5)
            score=np.mean(cv_scores)
            #上面这两个的结果是一样的
            if(score>best_score):
                best_score=score
                best_weight=weight
                best_p=p
                best_n=k
                best_cv_score=cv_scores#新加的

print("best_score=",best_score)
print("best_weight=",best_weight)
print("best_p=",best_p)
print("best_n=",best_n)
print("best_cv_score=",best_cv_score)

最终结果为:

可以看到,上述的结果已经和“(2)sklearn实现超参数网格搜索(快捷版本)结果一样了”,同时也证明了交叉验证的效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

还不秃顶的计科生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值