_模型评估

一、交叉验证模型

创建一个流水线,对数据进行预处理、训练模型,然后用交叉验证方法评估模型的性能。

from sklearn import datasets
from sklearn import metrics
from sklearn.model_selection import KFold,cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
digits=datasets.load_digits()
features=digits.data
target=digits.target
standardizer=StandardScaler()
logit=LogisticRegression()
pipeline=make_pipeline(standardizer,logit)
#创建k折交叉验证对象
kf=KFold(n_splits=10,shuffle=True,random_state=1)
cv_results=cross_val_score(pipeline,#流水线
                           features,#特征矩阵
                           target,#目标向量
                           cv=kf,#交叉验证方法
                           scoring="accuracy",#损失函数
                           )
cv_results.mean()

k折交叉验证(K-Fold Cross-Validation,KFCV)。在k折交叉验证中,数据被分为k份,训练模型时将k-1份数据组合起来作为训练集,剩下的那一份数据作为测试集。将上述过程重复k次,每次取一份不同的数据作为测试集,对模型在k次迭代中的得分取平均值作为总体得分。

在使用KFCV时需要考虑三点。首先,KFCV假定每个样本都是独立于其他样本的(即数据是独立同分布的,Independent Identically Distributed,IID)。如果数据是独立同分布的,最好在数据分组前将其顺序打乱。在scikit-learn中,可以通过设置shuffle=True来打乱数据。

其次,当我们使用KFCV来评估分类器时,通常将每一类数据大致平均地分配到k组数据中(这被称为分层k折)。例如,如果目标向量中包含性别,并且80%的样本时男性,则每组数据都包含80%的男性和20%的女性样本。在scikit-learn中,可以用StratifiedKFold替换KFold来使用分层k折交叉验证。

最后,使用Hold-out验证或交叉验证时,应该基于训练集对数据进行预处理,然后将这些预转换同时应用于训练集和测试集。例如,使用standardizer对数据进行标准化时,我们只需要计算训练集的平均值和方差,然后将这个预处理转换(使用transform方法)同时应用于训练集和测试集:

from sklearn.model_selection import train_test_split
features_train,features_test,target_train,target_test=train_test_split(features,
target,test_size=0.1,random_state=1)
standardizer.fit(features_train)
features_train_std=standardizer.transform(features_train)
features_test_std=standardizer.transform(features_test)

这样做是因为我们假定测试集时未知数据。如果使用训练集和测试集中的样本一起训练预处理器,测试集中的一些信息就会在训练过程中泄露。这个规则适用于任何预处理步骤,比如特征选择。

有了scikit-learn的pipeline。使用交叉验证就变得十分简单。首先创建一个处理数据的pipeline(如standardizer),然后训练一个模型(logit逻辑回归):

pipeline=make_pipeline(standardizer,logit)

然后只要对创建好的流水线执行cross_val_score方法,scikit-learn就会帮我们完成所有的工作。

cv_results=cross_val_score(pipeline,#流水线
                           features,#特征矩阵
                           target,#目标向量
                           cv=kf,#交叉验证方法
                           scoring="accuracy",#损失函数
                           n_jobs=-1#使用所有的CPU核)

cv参数用来指定使用什么样的交叉验证方法。k折交叉验证是迄今为止最常见的方法,也有一些其他的方法,如留一交叉验证法(leave-one-out-cross-validation),该方法的折数k等于样本数。scoring参数指定了衡量模型性能的标准。n_jobs=-1告诉scikit-learn使用所有可用的CPU核来进行计算。

二、创建一个基准回归模型

使用scikit-learn的DummyRegressor创建一个简单的基准回归模型:

from sklearn.dummy import DummyRegressor
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
boston = datasets.load_boston()
features,target=boston.data,boston.target
features_train,features_test,target_train,target_test=train_test_split(
    features,target,random_state=0)
dummy=DummyRegressor(strategy='mean')
dummy.fit(features_train,target_test)
#计算R方得分
dummy.score(features_test,target_test)

接下来训练自己的模型,计算性能得分,并与基准模型进行比较:

from sklearn.linear_model import LinearRegression
ols=LinearRegression()
ols.fit(features_train,target_train)
ols.score(features_test,target_test)

DummyRegressor允许我们创建一个简单的模型,以此作为基准核实际的模型进行对比。我们通常使用这种方法来模拟某个产品或系统中已有的原始预测系统。

DummyRegressor使用strategy参数设置所使用的预测方法,可选的方法包括训练集的均值或者中位数。此外,如果将strategy设置成constant并使用constant参数,则模型对所有样本的预测结果欧式一个常数。

默认情况下,score方法返回的是决定系数(R-squared),决定系数越接近1,就代表特征对目标向量的解释越好(即相关性越高)。

三、创建一个基准分类模型

from sklearn.datasets import load_iris
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import train_test_split
iris=load_iris()
features,target=iris.data,iris.target
features_train,features_test,target_train,target_test=train_test_split(
    features,target,random_state=0)
dummy=DummyClassifier(strategy='uniform',random_state=1)
dummy.fit(features_train,target_train)
dummy.score(features_test,target_test)

通过比较基准分类模型和我们训练的分类模型的得分,可以看到训练的模型在性能方面的提升:

from sklearn.ensemble import RandomForestClassifier
classifer=RandomForestClassifier()
classifer.fit(features_train,target_train)
classifer.score(features_test,target_test)

strategy参数提供了一些生成预测值方法的选项。第一个是stratified 方法,它使预测结果与训练集中数据类别的比例相同。例如,训练集中有20%是女性,则DummyClassifier会有20%概率给出女性作为预测结果;第二个是uniform方法,它随机生成均匀的预测,如果样本中包含20%的女性,80%的男性,那么uniform算法产生的预测结果中50%是女性50%是男性。

四、评估二元分类器

使用scikit-learn的cross_val_score方法进行交叉验证,同时使用scoring参数来决定性能评估指标,可以在准确率、精确率、召回率和F1分数等多种指标中选择。

我们可以通过设定scoring="accuracy"来使用3折(3为默认折数)交叉验证评估模型的准确率

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
x,y=make_classification(n_samples=10000,
                        n_features=3,
                        n_informative=3,
                        n_redundant=0,
                        n_classes=2,
                        random_state=1)
logit=LogisticRegression()
cross_val_score(logit,x,y,scoring="accuracy")

精确度(precision)是所有被预测为正类的样本中被正确预测的样本的百分比。我们可以把它看作一种衡量预测结果中的噪声的指标,即当样本被预测为正类时,预测正确的可能性有多大。具有高精度的模型是悲观的,因为它们仅在非常确定时才会预测样本为正类。

虽然准确率能够判断总的正确率,但是在样本不均衡的情况下,并不能作为很好的指标来衡量结果。在样本不平衡的情况下,得到的高准确率没有任何意义,此时准确率就会失效。例如如果一个肿瘤科医生看病,不经检验就告诉每个患者他们没有患病,检查的准确率为99.6%!(癌症患病率约为0.4%)。

召回率(Recall) 是针对原样本而言的,其含义是在实际为正的样本中被预测为正样本的概率。高的召回率意味着可能会有更多的误检,但是会尽力找到每一个应该被找到的对象。应用场景例如癌症筛查、排查安全隐患。

精确率和召回率互相影响,理想状态下肯定追求两个都高,但是实际情况是两者相互“制约”:追求精确率高,则召回率就低;追求召回率高,则通常会影响精确率。我们当然希望预测的结果精确率越高越好,召回率越高越好, 但事实上这两者在某些情况下是矛盾的。这样就需要综合考虑它们,最常见的方法就是F-score。

除了使用cross_val_score方法,如果已经得到样本的真实值和预测值,我们还可以直接计算出准确率和召回率等指标:

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
x_train,x_test,y_train,y_test=train_test_split(x,
                                               y,
                                               test_size=0.1,
                                               random_state=1)
#对测试集进行预测
y_hat=logit.fit(x_train,y_train).predict(x_test)
accuracy_score(y_test,y_hat)

五、评估二元分类器的阈值

受试者工作特征(Receiving Operating Charaterstic,ROC)曲线是评估二元分类器质量的常用方法。ROC曲线会对每一个概率阈值(即用来区分样本属于正类或负类的概率值)比较其真阳性和假阳性的比例。一个正确预测了每个样本的分类器,其ROC曲线直接从原点到顶部。而一个随机预测的分类器,其ROC曲线将显示为对角线。模型的性能越好,ROC曲线就越接近实心浅绿灰线。在scikit-learn中,我们可以使用roc_curve来计算每个阈值下的真阳性率(True Positive Rate)和假阳性率(False Positive Rate):

import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve,roc_auc_score
from sklearn.model_selection import train_test_split
features,target=make_classification(n_samples=10000,
                                    n_features=10,
                                    n_classes=2,
                                    n_informative=3,
                                    random_state=3)
features_train,features_test,target_train,target_test=train_test_split(
    features,target,test_size=0.1,random_state=1)
logit=LogisticRegression()
logit.fit(features_train,target_train)
#获取预测的概率
target_probabilities=logit.predict_proba(features_test)[:,1]
false_positive_rate,true_positive_rate,threshold=roc_curve(target_test,
                                                           target_probabilities)
plt.title("Receiver Operating Characteristic")
plt.plot(false_positive_rate,true_positive_rate)
plt.plot([0,1],ls="--")
plt.plot([0,0],[1,0],c=".7"),plt.plot([1,1],c=".7")
plt.ylabel("True Positive Rate")
plt.xlabel("False Positive Rate")

我们可以使用predict_proba查看第一个样本的预测概率:

可以使用classes_来查看分类:

在本例,第一个样本约有87%的概率属于负类(0),有约13%概率属于正类(1)。默认情况下,scikit-learn会将样本预测为概率大于50%(即阈值)的分类。然而,通常我们会由于某些原因显示地调整阈值而不是使用这个中间值。

如果将阈值提高到80%作用(即提高模型将样本预测为正类所需的确信度),则TPR和FPR的值都会显著下降。这是因为我们对样本被预测为正类的要求提高了,模型无法识别出一些正类样本(TPR较小),而且被错误预测为正类的负类样本也减少了(FPR较小)。

除了能够可视化TPR和FPR之间的关系,ROC曲线还可以用作模型的通用度量标准。模型越好曲线越高,曲线下的面积也就越大。出于这个原因,通常会计算ROC曲线下方的面积来判断在所有可能的阈值下模型的总体性能水平。AUCROC的值越接近1,模型的性能就越好。在scikit-learn中,可以使用roc_auc_score来计算AUCROC:

六、评估多元分类器

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
features,target=make_classification(n_samples=10000,
                                    n_features=3,
                                    n_informative=3,
                                    n_redundant=0,
                                    n_classes=3,
                                    random_state=1)
logit=LogisticRegression()
cross_val_score(logit,features,target,scoring='accuracy')

上面代码中,_macro指用来求各分类评估分数的平均值的方法:

macro

        计算每个分类的得分,然后取加权平均值,每个分类的权值相同。

weighted

        计算每个分类的得分,然后取加权平均值,权值为每个分类的样本数占总样本数的比例。

micro

        计算每个样本分类组合的得分,然后取平均值。

七、分类器性能的可视化

使用混淆矩阵(Confusion Matrix)来比较预测分类(Predicted Class)和真实分类(True Class)

import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
import pandas as pd
iris=datasets.load_iris()
features=iris.data
target=iris.target
class_names=iris.target_names
features_train,features_test,target_train,target_test=train_test_split(
    features,target,random_state=1)
classifier=LogisticRegression()
target_predicted=classifier.fit(features_train,
                                target_train).predict(features_test)
matrix=confusion_matrix(target_test,target_predicted)
dataframe=pd.DataFrame(matrix,index=class_names,columns=class_names)
#绘制热力图
sns.heatmap(dataframe,annot=True,cbar=None,cmap="Blues")
plt.title("Confusion Matrix"),plt.tight_layout()
plt.ylabel("True class"),plt.xlabel("Predicted Class")

矩阵(通常以热力图形式呈现)的每一列表示样本的预测分类,而每一行表示样本的真实分类。最终每个单元格都是预测分类和真实分类的一种可能的组合。

关于混淆矩阵有三点值得注意。首先,一个完美的模型,其混淆矩阵应该只有对角线上才有值,而其他位置应该全为零;而一个糟糕的模型,其混淆矩阵看起来像就是将样本均匀分配到了各个单元格上。其次,混淆矩阵不仅可以显示模型将哪些样本的分类预测错了,还可以显示它是怎么分错的,即误分类的模式。最后,对于任意数量的分类,混淆矩阵都适用(只是如果数据中有100万个分类,混淆矩阵可能就不那么直观了)。

八、评估回归模型

使用均方误差(Mean Squared Error,MSE):

from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
features,target=make_regression(n_samples=100,
                                n_features=3,
                                n_informative=3,
                                n_targets=1,
                                noise=50,
                                coef=False,
                                random_state=1)
ols=LinearRegression()
cross_val_score(ols,features,target,scoring='r2')

MES的值越大,总平方误差就越大,模型性能越差。平方误差项在数学上有许多好的特性,比如所有误差值都为正数,但有一个特性经常被忽略,即在误差的总绝对值相同的情况下,取平方值以后会给值较大的误差项施加更多的惩罚。

默认情况下,对于scikit-learn的scoring参数而言,scoring值较大的模型优于scoring值较小的模型。然而对MSE来说,刚好相反,MSE的值较大意味折模型性能较差。依次在scikit-learn中使用的是neg_mean_squared_error参数,它是MSE的相反数。

九、评价聚类模型

使用无监督学习对数据进行聚类,可能无法按预想的方式评估。

一种可选的方式是使用轮廓系数(silhouette coefficient)。

import numpy as np
from sklearn.metrics import silhouette_score
from sklearn import datasets
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
features,_=make_blobs(n_samples=1000,
                      n_features=10,
                      centers=2,
                      cluster_std=0.5,
                      shuffle=True,
                      random_state=1)
model=KMeans(n_clusters=2,random_state=1).fit(features)
target_predicted=model.labels_
silhouette_score(features,target_predicted)

使用聚类方法时,数据集没有目标向量。许多评估聚类模型的指标都要求有目标向量,但是当有可用的目标向量时,使用无监督学习(如聚类)方法训练模型可能会带来一些不必要的麻烦。

“好”的聚类中同类别样本间的距离非常小(即稠密聚类),不同类别的样本之间距离非常大(即分离的很彻底)。轮廓系数可以用一个值同时评估这两种特性。第i个样本的轮廓系数的计算公式为

其中,a ( i ) a(i)a(i)代表样本点的内聚度,计算方式如下

其中j代表与样本i在同一个类内的其他样本点,distance代表了求i与j的距离。所以a(i)越小说明该类越紧密。

silhouette_score返回的值是所有样本的平均轮廓系数。该轮廓系数的值介于-1和1之间,其中1表示内部密集,分离彻底(指与其他聚类的间隔较远)的聚类。

十、创建自定义评估指标

from sklearn.metrics import make_scorer,r2_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
from sklearn.datasets import make_regression
features,target=make_regression(n_samples=100,
                                        n_features=3,
                                        random_state=1)
features_train,features_test,target_train,target_test=train_test_split(
    features,target,test_size=0.10,random_state=1)
def custom_metric(target_test,target_predicted):
    r2=r2_score(target_test,target_predicted)
    return r2
#创建评分函数(评分器),并且定义分数越高代表模型越好
score=make_scorer(custom_metric,greater_is_better=True)
#创建岭回归(Ridge Regression)对象
classifier=Ridge()
model=classifier.fit(features_train,target_train)
score(model,features_test,target_test)

使用scikit-learn的make_scorer函数,我们能很轻松地创建自定义指标函数。首先,定义一个函数,它接受两个参数——真实的目标向量和预测值,并返回一个分数。然后使用make_scorer创建一个评分器对象,并指定较高的分数代表模型性能较好或较差(使用greater_is_better参数)

岭回归是一种改良的最小二乘估计法,通过放弃最小二乘法的无偏性,以损失部分信息、降低精度为代价获得回归系数,它是更为符合实际、更可靠的回归方法,对存在离群点的数据的拟合要强于最小二乘法。

不同与线性回归的无偏估计,岭回归的优势在于它的无偏估计,更趋向于将部分系数向0收缩。因此,它可以缓解多重共线问题,以及过拟合问题。但是由于岭回归中并没有将系数收缩到0,而是使得系数整体变小,因此,某些时候模型的解释性会大大降低,也无法从根本上解决多重共线问题。

十一、可视化训练集规模的影响

画出学习曲线(Learning Curve)

import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
digits=load_digits()
features,target=digits.data,digits.target
train_sizes,train_scores,test_scores=learning_curve(
    #分类器
    RandomForestClassifier(),
    #特征矩阵
    features,
    #目标向量
    target,
    #交叉验证的折数
    cv=10,
    #性能指标
    scoring='accuracy',

    #50个训练集的规模
    train_sizes=np.linspace(
        0.01,
        1.0,
        50))
train_mean=np.mean(train_scores,axis=1)
train_std=np.std(train_scores,axis=1)
test_mean=np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
#画线
plt.plot(train_sizes,train_mean,'--',color="#111111",label="Training score")
plt.plot(train_sizes,test_mean,color="#111111",label="Cross-validation score")
#画带状图
plt.fill_between(train_sizes,train_mean-train_std,
                 train_mean+train_std,color="#DDDDDD")
plt.fill_between(train_sizes,test_mean-test_std,
                 test_mean+test_std,color="#DDDDDD")
plt.title("Learning Curve")
plt.xlabel("Training Set Size"),plt.ylabel("Accuracy Score"),
plt.legend(loc="best")
plt.tight_layout()
plt.show()

十二、生成对评估指标的报告

from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
iris=datasets.load_iris()
features=iris.data
target=iris.target
class_names=iris.target_names
features_train,features_test,target_train,target_test=train_test_split(
    features,target,random_state=1)
classifier=LogisticRegression()
model=classifier.fit(features_train,target_train)
target_predicted=model.predict(features_test)
#生成分类器性能报告
print(classification_report(target_test,
                            target_predicted,
                            target_names=class_names))

support列是指每个分类中的样本数量。

十三、可视化超参数值的效果

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import validation_curve
digits=load_digits()
features,target=digits.data,digits.target
param_range=np.arange(1,250,2)
train_scores,test_scores=validation_curve(
    RandomForestClassifier(),
    features,
    target,
    #要查看的超参数
    param_name="n_estimators",
    #超参数值的范围
    param_range=param_range,
    cv=3,
    scoring="accuracy",)
train_mean=np.mean(train_scores,axis=1)
train_std=np.std(train_scores,axis=1)
test_mean=np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
#画出模型在训练集和测试集上的准确率的平均值
plt.plot(param_range,train_mean,label="Training score",color="black")
plt.plot(param_range,test_mean,label="Cross-validation score",
         color="dimgrey")
#画出模型在训练集和测试集上的准确率带状图
plt.fill_between(param_range,train_mean-train_std,
                 train_mean+train_std,color="gray")
plt.fill_between(param_range,test_mean-test_std,
                 test_mean+test_std,color="gainsboro")
plt.title("Validation Curve With Random Forest")
plt.xlabel("Number Of Trees")
plt.ylabel("Accuracy Score")
plt.tight_layout()
plt.legend(loc="best")

大多数算法都包含超参数,而且必须在模型训练开始之前就选好。例如,随机森林分类器创建决策树的“森林”,每个决策树对样本的预测分类投票。随机森林分类器有一个超参数是森林中树的数量。当树的数量较少时,训练集额交叉验证的准确率分数都很低,表明该模型欠拟合。当树的数量增加到250,两个准确率分数都没什么变化,表明使用更多计算资源训练大规模随机森林可能并不能带来很高的价值。

在scikit-learn中,我们可以使用validation_curve计算验证曲线,它包含3个重要参数:

param_name是需要变化的超参数的名字。

param_range是超参数取值的区间。

scoring是模型的评估指标。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值