模型评估与轨道
一、模型评估的基本方法
1.1监督学习下的泛化、过拟合与欠拟合
在有监督的学习过程中,首先在训练数据上学得模型参数来构建模型,然后根据学得的模型,对新数据做出预测。用来训练的数据集称为训练集,用来测试预测结果是否准确的新数据称为测试集。注意:测试集中的数据不能再训练集中出现过。
在训练集上构建模型时,可以通过调整模型的复杂度,让模型的曲线尽可能经过训练集上的点,使构建的模型在训练集上的准确率非常高。
在训练集上学得的模型如果能够对没有见过的新数据做出比较准确的预测,就说这个模型能够从训练集泛化到测试集。表示泛化能力的泛化准确率越高越好。
如果训练集与测试集的数据分布足够相似,则在训练集上准确率越高的模型,在测试集中的泛化准确率也越高。然而,当模型越来越复杂,在训练集上的准确率不断提高的时候,训练得到的模型与测试集数据越来越不吻合,反而导致泛化准确率逐步降低。
在训练集上训练学习模型时,如果过于关注训练数据的细节,会得到一个模型复杂度较高,在训练集上拟合程度很好,但在测试集上拟合程度较差的模型。这种情况称为模型的过拟合。在此阶段,随着模型复杂度的提高,在训练集上的准确率可以继续提高,泛化准确率不断下降。
从训练集上学得的模型如果过于简单,无法全面反应训练集与测试集数据的分布情况,那么此时模型的训练集准确率和泛化准确率均较差,这种情况称为模型的欠拟合。在欠拟合阶段,随着模型复杂度的提高,训练准确率与泛化准确率均不断提升。
从上面分析来看,随着模型复杂度从低到高的提升,训练准确率会不断提高,而泛化准确率会先提升,当提升到一个高度后会逐步下降。
1.2、模型评估指标
1、分类学习性能指标
在分类学习中,对结果进行正确预测的比例称为准确率,一般来说准确率越高越好。但对于实际的分类问题,不能光看准确率。评估分类模型性能的一个重要方法是使用混淆矩阵。下面以一个例子来说明:
在二分类中,分类标签被区分为正类和负类。可以选择一个类别为正类,其他均为负类。将预测的分类标签与实际标签比较,如果将实际为正类的实例预测为正类,则称为真正类;如果将实际为正类的实例预测为负类,则称为假负类。
预测分类 | ||
---|---|---|
实际分类 | 正类 | 负类 |
正类 | TP | FN |
负类 | FP | TN |
基于混淆矩阵,预测准确率(Accuracy)可以用以下式子表示:
$$
Accuracy = (TP+TN) / (TP+TN+FN+FP)
$$
"""
Sklearn中自带的乳腺癌数据集中的样本分两类
分为恶性和良性。
其中恶性的分类标签为0
良性的分类标签为1
"""
#从数据库中获取乳腺癌数据集
from sklearn.datasets import load_breast_cancer
#对训练数据集和测试数据集进行分隔
from sklearn.model_selection import train_test_split
#数据预处理,标准化数据
from sklearn.preprocessing import StandardScaler
#构建模型对象,向量分类器
from sklearn.svm import LinearSVC
#评估模型性能
from sklearn.metrics import *
#获取数据信息
"""
可以通过设置as_frame属性来设置数据类型
"""
bc = load_breast_cancer()
#返回bunch类型,可以像字典一样被调用
# print(type(bc)) #<class 'sklearn.utils._bunch.Bunch'>
x = bc.data
y = bc.target
print("样本分类标签:",bc["target_names"]) # malignant 恶性;benign 良性。
#划分训练集与测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=0,stratify=y)
#先对特征数据标准化,标准化训练集数据
scaler = StandardScaler()
scaler.fit(x_train)
#调用标准化数据
x_train_scaler = scaler.transform(x_train)
x_test_scaler = scaler.transform(x_test)
#从训练集中学习模型
cls = LinearSVC(random_state=0)
cls.fit(x_train_scaler,y_train)
#对测试集数据进行预测
y_test_pred = cls.predict(x_test_scaler)
acc_test = accuracy_score(y_test,y_test_pred)
print("测试集准确率:",acc_test)
#通过参数pos_label=0指定标签0为正类
recall_test = recall_score(y_test,y_test_pred,pos_label=0)
print("测试集召回率(真正率):",recall_test)
#通过参数pos_label=0指定标签0为正类
precision_test = precision_score(y_test,y_test_pred,pos_label=0)
print("测试集精度:",precision_test)
f1_test = f1_score(y_test,y_test_pred,pos_label=0)
print("测试集f1-score:",f1_test)
#通过labels指定混淆矩阵中各类别标签的排列顺序
print("混淆矩阵:\n",confusion_matrix(y_test,y_test_pred,labels=[1,0]),sep="")
tn,fp,fn,tp = confusion_matrix(y_test,y_test_pred,labels=[1,0]).ravel()
print("手工计算的测试集准确率:",(tn+tp)/(tn+tp+fn+fp))
print("分类报告:\n",classification_report(y_test,y_test_pred))
样本分类标签: ['malignant' 'benign']
测试集准确率: 0.9736842105263158
测试集召回率(真正率): 0.9523809523809523
测试集精度: 0.975609756097561
测试集f1-score: 0.963855421686747
混淆矩阵:
[[71 1]
[ 2 40]]
手工计算的测试集准确率: 0.9736842105263158
分类报告:
precision recall f1-score support
0 0.98 0.95 0.96 42
1 0.97 0.99 0.98 72
accuracy 0.97 114
macro avg 0.97 0.97 0.97 114
weighted avg 0.97 0.97 0.97 114
2、回归学习性能指标
统计学中用决定系数R**2来评估回归模型的性能。在sklearn中,可以使用回归模型对象的score()方法计算决定系数的值。
3、聚类学习性能指标
聚类模型的性能评估没有分类模型的性能评估直观。
如果数据集没有已知的类别属性,那么模型聚类的标签没有可比较的对象,这时可采用轮廓系数来衡量聚类的质量。轮廓系数计算一个簇的紧致度,取值为-1~1,轮廓系数越大,表示聚类效果越好,最大值为1,可以用sklearn.metrics包中的silhouette_score()函数计算轮廓系数。
1.3、交叉验证
交叉验证是一种评估模型泛化能力的统计学方法,通过多次划分训练集和测试集,评估给定算法在特定数据集上训练后的泛化能力。
sklearn支持多种交叉验证方法,其中常用的有k折交叉验证、分层k折交叉验证、留一法交叉验证、分组交叉验证等。
最常用的交叉验证方法是k折交叉验证。k是由用户指定的数字。如果k为3,则为3折交叉验证。将数据集划分为3个数量基本相同的部分,每部分称为一个折。指定的算法对模型训练三次,每次取其中一个折作为测试集,其余折合起来作为训练集。
1、回归模型中的k折交叉验证
import pandas as pd
#训练模型
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import cross_val_predict
from sklearn.model_selection import KFold
#获取数据
ccpp_data = pd.read_excel(io="Folds5x2_pp.xlsx",index_col=None)
print(type(ccpp_data))
x = ccpp_data.iloc[:,:4].values.astype(float)
y = ccpp_data.iloc[:,-1:].values.astype(float)
m = LinearRegression() #创建模型对象
#3折交叉验证,默认采用标准交叉验证
scores = cross_val_score(m,x,y,cv=3)
print(f"各次迭代的决定系数:{scores}")
print(f'平均决定系数:{scores.mean()}')
#也可以通过交叉分离器来打乱数据,达到类似分层交叉的效果
kfold = KFold(n_splits=3,shuffle=True,random_state=10)
print("------打乱数据后----------")
scores = cross_val_score(m,x,y,cv=kfold)
print(f"各次迭代的决定系数:{scores}")
print(f'平均决定系数:{scores.mean()}')
y_pred = cross_val_predict(m,x,y,cv=kfold)
print("前两个样本的预测目标值:\n",y_pred[:2],sep="")
各次迭代的决定系数:[0.92929563 0.9312216 0.92522815]
平均决定系数:0.9285817923317791
------打乱数据后----------
各次迭代的决定系数:[0.93313583 0.92437607 0.92792968]
平均决定系数:0.9284805286134005
前两个样本的预测目标值:
[[467.24829864]
[444.11689024]]
二、轨道的创建与使用
大多数机器学习应用需要经过数据预处理、模型训练等一系列连续步骤的过程,前一步骤的输出作为后一步骤的输入。使用轨道pipeline可以简化中间过程,自动将前一步骤的输出作为后一步骤的输入。放在轨道中的处理步骤,除最后一步外,必须都是有transform()方法的转换器,使其转换后生成的数据成为下一步的输入。最后一步是一个计数器,如分类、回归、聚类等模型。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
iris = load_iris()
x,y = iris.data,iris.target
#划分训练集与测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=0)
scaler = StandardScaler()
scaler.fit(x_train) #必须从训练集中学习标准化参数
x_train_std = scaler.transform(x_train)
#测试集的标准化也要使用从训练集中学到的标准化参数
x_test_std = scaler.transform(x_test)
#创建线性分类支持向量机模型
cls = SVC(kernel="linear",random_state=0)
cls.fit(x_train_std,y_train) #用标准化后的数据训练模型
print("模型在训练集上预测的准确率:",cls.score(x_train_std,y_train))
print("模型在测试集上预测的准确率:",cls.score(x_test_std,y_test))
print("预测测试集第一个样本的类别编码:",cls.predict(x_test_std[:1]))
上述程序中,先对数据集特征进行标准化,接着利用支持向量机算法对标准化后的训练集进行学习,获得模型。然后可以利用模型对标准化后的新数据进行预测。连续多个步骤的处理可以放在一个pipline轨道中完成,只要除最后一个步骤外前面的处理对象具有transform()方法即可。
1、创建和使用轨道
iris = load_iris()
x,y = iris.data,iris.target
#划分训练集与测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=0)
#创建轨道方式1
pipe = Pipeline([("scaler",StandardScaler()),("svc",SVC(kernel="linear",random_state=0))])
#训练轨道
pipe.fit(x_train,y_train)
print("模型在训练集上预测的准确率:",pipe.score)
print("模型在测试集上预测的准确率:",pipe.score(x_test,y_test))
print("预测测试集第一个样本的类别编码:",pipe.predict(x_test[:1]))
创建轨道后,和普通的学习器模型一样,使用fit()方法进行训练。使用fit(x_train,y_train)方法的时候,先调用第一个步骤中名为StandardScaler的fit(x_train)方法将x_train数据集转换为标准化后的数据集,可以将这个数据集命名为x_train_std。接着调用下一步方法。以此类推。
2、交叉验证中使用轨道
在交叉验证过程中,每次需要留出一部分数据作为测试集。测试集数据的缩放、特征选择等操作是根据训练集学到的缩放模型、特征选择模型来做的。做交叉验证之前不能对特征数据做缩放、特征选择等操作。如果在交叉验证之前做缩放、特征选择等操作,那么测试集的数据也参与了缩放模型、特征选择模型的训练,测试数据的特征就会泄漏到拟合的模型中,容易造成模型的过拟合。
通常采用cross_val_score()及后面要学到的带交叉验证的网格搜索等函数来自动完成交叉验证,中间无法每次根据训练集来训练缩放模型、特征选择模型,然后对测试集做同样的缩放、特征选择等操作。而采用轨道,可以在每轮交叉验证之前自动插入特征数据缩放、特征选择等操作,并且这个缩放模型或特征选择模型只从每轮的训练集中学习,然后用学得的缩放模型、特征选择模型对训练集和测试集进行缩放操作。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通