模型评估方法(交叉验证,混淆矩阵,阈值,ROC曲线)

本文介绍了如何使用scikit-learn库中的工具进行手写数字识别,包括数据集加载、数据切分、交叉验证方法、模型训练(如SGDClassifier)以及性能评估指标如混淆矩阵、ROC曲线和F1分数。作者详细展示了如何使用这些技术调整模型参数和理解阈值对结果的影响。
摘要由CSDN通过智能技术生成

        前言

        工具包地址:https://scikit-learn.org

        

        这里有sklearn各种算法,数据集的调用方法,例子,读者可以使用右上角的搜索框。

数据集切分

        本文用手写数字识别作为例子。

#导入工具包
import numpy as np
import os
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
import warnings
warnings.filterwarnings('ignore')
np.random.seed(42)

#加载数据集 值得注意的是 28x28x1的灰度图 
from sklearn.datasets import fetch_openml
X, y = fetch_openml(
    "mnist_784", version=1, return_X_y=True, as_frame=False, parser="pandas"
)
print(X.shape) #(70000,784) 70000个样本 784个特征值

X_train,X_test,y_train,y_test = X[:60000],X[60000:],y[:60000],y[60000:]#划分数据集

 洗牌操作(把数据打乱顺序,数据之间独立)

shuffle_index = np.random.permutation(60000)
X_train,y_train = X_train[shuffle_index],y_train[shuffle_index]

交叉验证

        前60000分样本划分为训练集 用来作为交叉验证 调整模型参数

        在使用训练集对参数进行训练的时候,通常会将一整个训练集分为三个部分(比如mnist手写训练集)。一般分为:训练集(train_set),评估集(valid_set),测试集(test_set)这三个部分。这其实是为了保证训练效果而特意设置的。其中测试集很好理解,其实就是完全不参与训练的数据,仅仅用来观测测试效果的数据。而训练集和评估集则牵涉到下面的知识了。

        因为在实际的训练中,训练的结果对于训练集的拟合程度通常还是挺好的(初始条件敏感),但是对于训练集之外的数据的拟合程度通常就不那么令人满意了。因此我们通常并不会把所有的数据集都拿来训练,而是分出一部分来(这一部分不参加训练)对训练集生成的参数进行测试,相对客观的判断这些参数对训练集之外的数据的符合程度。这种思想就称为交叉验证(Cross Validation)。

        交叉验证(Cross Validation),有的时候也称作循环估计(Rotation Estimation),是一种统计学上将数据样本切割成较小子集的实用方法。

        在给定的建模样本中,拿出大部分样本进行建模型,留小部分样本用刚建立的模型进行预报,并求这小部分样本的预报误差,记录它们的平方加和。这个过程一直进行,直到所有的样本都被预报了一次而且仅被预报一次。把每个样本的预报误差平方加和,称为PRESS(predicted Error Sum of Squares)。

#调整为2分类(和后面的类容有关) 训练模型
y_train_4 = (y_train == '4')
y_test_4 = (y_test == '4')
from sklearn.linear_model import SGDClassifier 
sgd_clf = SGDClassifier(max_iter=5,random_state=42)
sgd_clf.fit(X_train,y_train_4)

工具包提供的交叉验证方法 直接得出评分(本文把训练集分为3部分)

from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf,X_train,y_train_4,cv=3,scoring='accuracy')

 

也可以自己来实现交叉验证

from sklearn.model_selection import KFold
from sklearn.base import clone
kfold = KFold(n_splits=3,shuffle=True,random_state=42)
for train_index,test_index in kfold.split(X_train,y_train_4):
    clone_clf = clone(sgd_clf)
    X_train_folds = X_train[train_index]
    y_train_folds = y_train_4[train_index]
    X_test_folds = X_train[test_index]
    y_test_folds = y_train_4[test_index]
    clone_clf.fit(X_train_folds,y_train_folds)

    y_pred = clone_clf.predict(X_test_folds)
    num_correct = sum(y_pred == y_test_folds)
    print(num_correct/len(y_pred))

 

混淆矩阵

        混淆矩阵也称误差矩阵,是表示精度评价的一种标准格式,用n行n列的矩阵形式来表示。在人工智能中,混淆矩阵(confusion matrix)是可视化工具,特别用于监督学习,在无监督学习一般叫做匹配矩阵。在图像精度评价中,主要用于比较分类结果和实际测得值,可以把分类结果的精度显示在一个混淆矩阵里面。

        举个栗子:已知班级总人数:100人,男80人,女20人 目标是找到班级的所有女生 结果是:分类器选了50人(认为是女生),其中20人是女生,30人是男生。

相关(Relevant),正类无关(NonRelevant),负类
被检测到

true positive(TP)正类判定为正类

即本来是女生被判定为女生

(正确的当作正类,原本是正类)

false positive(FP)负类判定为正类

即本来是男生被判定为女生

(错误的当作正类,原本是负类)

未被检测到

false negatives(FN)正类判定为负类

即本来是女生被判定为男生

(错误的当作负类,原本是正类)

true negatives(TP)负类判定为负类

即本来是男生被判定为男生

(正确的当作负类,原本是负类)

        作者认为,可以把true flase当作动词,就好理解了。

        得到TP=20,FP=30,FN=0,TN=50

from sklearn.model_selection import cross_val_predict #直接验证集 交叉验证
from sklearn.metrics import ConfusionMatrixDisplay, confusion_matrix
y_train_pred = cross_val_predict(sgd_clf,X_train,y_train_4,cv=3)
#这里是把3次预测值放在一起


cm = confusion_matrix(y_train_4,y_train_pred)
print(cm)
cm_display = ConfusionMatrixDisplay(cm).plot()

注意:得到混淆矩阵为

true negativesfalse positive
false negatives

true positive

        完美的分类器,副对角线上的元素为0

得到精度:precision = TP/(TP+FP) 召回率:recall = TP/(TP+FN) 

from sklearn.metrics import precision_score,recall_score
print(precision_score(y_train_4,y_train_pred))
print(recall_score(y_train_4,y_train_pred))

 

 

F1 score 指标:将precision 和 recall 结合,调和平均值 F1 = 2/((1/precision)+(1/recall))=TP/(TP+(FN+FP)/2) 其是在precision 和 recall之间的值

from sklearn.metrics import f1_score
f1_score(y_train_4,y_train_pred)

 

阈值对结果的影响

        分类器的predict()方法其实是根据实例得到的分数来做出决策的,比如把某一个事物归为A的得分为100,而归为B类的得分为200,这样事物是B类的概率大,即做出预测。

 

        可以看出分类器做出分类,是4的值越往positive predictions方向越多,而自己可以根据得分设置阈值,得到不同的Precision和Recall,也能得到Precision和Recall的关系是此消彼长的。

y_scores = sgd_clf.decision_function([X[500]])#调用其decision_funcrion()方法 得到样本分数
print(y_scores)
#设置不同阈值 ,查看预测结果
t = 0
y_pred = (y_scores > t)
print(y_pred)
t = -239479
y_pred = (y_scores > t)
print(y_pred)

 

 

ROC曲线

        scikit-learn 不允许直接设置阈值,但它可以得到决策分数,调用其decision_funcrion()方法,而不是调用分类器的predict(),

该方法返回每个实例的分数,然后使用想要的阈值,根据这些分数进行预测:

from sklearn.metrics import precision_recall_curve
precisions,recalls,thresholds = precision_recall_curve(y_train_4,y_scores)
def plot_precision_recall_vs_threshold(precisions,recalls,thresholds):
    plt.plot(thresholds,precisions[:-1],
             'b--',label = 'Precision')
    plt.plot(thresholds,recalls[:-1],
             'g-',label = 'Recall')
    plt.xlabel('Threshold',fontsize=16)
    plt.legend(loc='upper left',fontsize=16)
    plt.ylim([0,1])
plt.figure(figsize=(8,4))
plot_precision_recall_vs_threshold(precisions,recalls,thresholds)
plt.xlim([-70000,70000])
plt.show()

 

        查看Precision和Recall之间的关系

        

def plot_precision_vs_recall (precisions,recalls):
    plt.plot(recalls,precisions,'b-',linewidth=2)
    plt.xlabel('Recall',fontsize=16)
    plt.ylabel('Precision',fontsize=16)
    plt.axis([0,1,0,1])
plt.figure(figsize=(8,6))
plot_precision_vs_recall(precisions,recalls)
plt.show()

 

         绘制ROC曲线,

        ROC curves : receiver operating charateristic(ROC)曲线是二分类中常用的评估方法,它与精确度/召回率非常相似,但ROC曲线不是绘制精确度与召回率,而是绘制 true positive rate(TPR) 与 false positive rate(FPR)要绘制ROC曲线首先需要使用roc_curve()函数计算各种阈值的TPR和FPR TPR=TP/(TR+FN) FPR=FP/(FP+FN)

from sklearn.metrics import roc_curve
fpr,tpr,thresholds = roc_curve(y_train_4,y_scores)
def plot_roc_curve(fpr,tpr,label=None):
    plt.plot(fpr,tpr,linewidth=2,label=label)
    plt.plot([0,1],[0,1],'k--')
    plt.axis([0,1,0,1])
    plt.xlabel('False Positive Rate',fontsize = 16) 
    plt.ylabel('True Positive Rate',fontsize = 16) 
plt.figure(figsize=(8,6))
plot_roc_curve(fpr,tpr)
plt.show()

 

        虚线表示纯随机分类器的ROC曲线;一个好的分类器尽可能远离该线(朝着左上角)

        比较分类器的一种方法是测量曲线下的面积(AUC)完美的分类器的ROC 的AUC等于1,而纯随机分类器的ROC AUC等于0.5

        scikit-learn 提供了计算ROC AUC的函数

from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_4,y_scores)

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值