之前讲到用验证集和测试集对模型进行评定,但除了单纯使用准确率(accuracy)外,在二分类中,还可以使用查全率(precision)和召回率(recall)进行。当然,正如一句俗话:一张图剩于千个字。除了上面干巴巴的数字之外,我们更习惯于用图进行说话,在二分类中,我们常用的是ROC曲线和PR曲线,在本文中仅讲述ROC曲线。
ROC曲线的全称为“受试者工作特征”,在介绍ROC曲线之前首先要引入混淆矩阵的概念:混淆矩阵其实就是一个比较分类结果和实际测得值的东西,如下图:
而对于ROC曲线来说,主要考察下面两个指标。其中,横轴为假正率(FPR),纵轴为真正率(TPR)
然后,我们根据学习器的预测结果对样例进行排序,按照顺序逐个把样本作为正例进行预测,每次计算FPR和TPR,分别做点,最后连接起来即为ROC曲线,由TPR可知,我们希望其值越大越好,而对于FPR我们则希望其越低越好,因此,在给定FPR时(横轴),TPR越大模型即越好。所以说,如果一条ROC曲线完全盖住另一条,则其分类效果越好。实际中,两条ROC曲线往往会出现交叉的情况,此时不同完全判断,我们则引进AUC值,即ROC曲线于X=1,X=0,Y=0围成图形的面积。在Python中,我们可以使用sklearn算出其ROC值,再用Matplotlib包对其进行画图描述:
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt
plt.figure()
###############画cart的ROC-AUC曲线########################
prob_predict_y_validation_cart = cart.predict_proba(x_test)#给出带有概率值的结果,每个点所有label的概率和为1
predictions_validation_cart = prob_predict_y_validation_cart[:, 1]
fpr_cart, tpr_cart, _ = roc_curve(y_test, predictions_validation_cart)
roc_auc_cart = auc(fpr_cart, tpr_cart)
plt.plot(fpr_cart, tpr_cart, 'b', label='cart = %0.2f' % roc_auc_cart)
###############画svm的ROC-AUC曲线########################
prob_predict_y_validation_svm = svc.predict_proba(x_test)#给出带有概率值的结果,每个点所有label的概率和为1
predictions_validation_svm = prob_predict_y_validation_svm[:, 1]
fpr_svm, tpr_svm, _ = roc_curve(y_test, predictions_validation_svm)
roc_auc_svm = auc(fpr_svm, tpr_svm)
plt.plot(fpr_svm, tpr_svm, 'm', label='svm = %0.2f' % roc_auc_svm)
###############画logistic的ROC-AUC曲线########################
prob_predict_y_validation_logistic = logistic.predict_proba(x_test)#给出带有概率值的结果,每个点所有label的概率和为1
predictions_validation_logistic = prob_predict_y_validation_logistic[:, 1]
fpr_logistic, tpr_logistic, _ = roc_curve(y_test, predictions_validation_logistic)
roc_auc_logistic = auc(fpr_logistic, tpr_logistic)
plt.plot(fpr_logistic, tpr_logistic, 'g', label='logistic = %0.2f' % roc_auc_logistic)
###############画KNN的ROC-AUC曲线########################
prob_predict_y_validation_knn = knn.predict_proba(x_test)#给出带有概率值的结果,每个点所有label的概率和为1
predictions_validation_knn = prob_predict_y_validation_knn[:, 1]
fpr_knn, tpr_knn, _ = roc_curve(y_test, predictions_validation_knn)
roc_auc_knn = auc(fpr_knn, tpr_knn)
plt.plot(fpr_knn, tpr_knn, 'y', label='knn = %0.2f' % roc_auc_knn)
###############画nn的ROC-AUC曲线########################
prob_predict_y_validation_nn = nn.predict_proba(x_test)#给出带有概率值的结果,每个点所有label的概率和为1
predictions_validation_nn = prob_predict_y_validation_nn[:, 1]
fpr_nn, tpr_nn, _ = roc_curve(y_test, predictions_validation_nn)
roc_auc_nn = auc(fpr_nn, tpr_nn)
plt.plot(fpr_nn, tpr_nn, 'c', label='nn = %0.2f' % roc_auc_nn)
###############画rf的ROC-AUC曲线########################
prob_predict_y_validation_rf = rf.predict_proba(x_test)#给出带有概率值的结果,每个点所有label的概率和为1
predictions_validation_rf = prob_predict_y_validation_rf[:, 1]
fpr_rf, tpr_rf, _ = roc_curve(y_test, predictions_validation_rf)
roc_auc_rf = auc(fpr_rf, tpr_rf)
plt.plot(fpr_rf, tpr_rf, '#9932CC', label='rf = %0.2f' % roc_auc_rf)
###############################roc auc公共设置##################################
plt.title('ROC Validation')
plt.legend(loc='lower right')
plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0, 1])
plt.ylim([0, 1])
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
其输出图形为:
可以发现,每个模型都拟合得特别好,所以单纯的精度比较用处不大,在如此高的准确率的情况下,我们可以尝试精简模型。
模型的改善:
在我们模型的精度已经基本都超过 95%的情况下,我们可以考虑用牺牲一部分的准确度而使用更少的变量进行求解。
对变量的选择属于特征工程的一部分,其方法有很多,包括方差选择法,相关系数法,卡方检验,互信息法等等。然而,这些方法大多适用于自变量和因变量同时是连续变量或者自变量和因变量同时为离散变量的情况,而在此,我们则是自变量为连续变量,因变量为离散变量。因此,传统的方法失效。
但我们可以从已有模型进行变量的选择。我们发现,在此问题中,无论是是否进行标准化,树的结构都是相当的稳定,而随机森林也是基于决策树堆砌而成。因此,我们可以依赖树的机构进行变量的选择。
from sklearn.feature_selection import SelectFromModel
model = SelectFromModel(cart, prefit=True)
x_new = model.transform(x)
x_train, x_test, y_train, y_test = train_test_split(x_new , y, test_size=0.3)
然后发现,在默认配置下,新的x_new中只使用其中2个变量。在ipython直接输入cart.feature_importances_
得到的结果如下:
array([0.00165401, 0. , 0.00205923, 0.00334628, 0. ,
0.06288901, 0.00166557, 0. , 0.00636451, 0.01559437,
0.00979786, 0.00312154, 0.84076444, 0.02717923, 0.00378918,
0.0026317 , 0.00178339, 0.00603816, 0.00580406, 0.00551745])
可以发现,第六个变量和第十三个变量总比重已经占整颗cart树的90%以上,因此,我们猜测,仅使用这两个变量可能即可达到很好的结果。(还是那句老话,数据分析和处理没有最优解,大多凭借经验进行判断)。
但为了进一步判断,我们可以使用Matplotlib看一下仅靠两个变量(经查询为IQR和meanfun变量)的分布图:
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
voice_data=pd.read_csv('voice.csv')
male=voice_data.iloc[:1583,:]
male_x1=male['IQR']
male_x2=male['meanfun']
female=voice_data.iloc[1584:,:]
female_x1=female['IQR']
female_x2=female['meanfun']
plt.figure()
plt.scatter(male_x1,male_x2,c='b',alpha=0.5,label='male')
plt.scatter(female_x1,female_x2,c='r',alpha=0.5,marker="p",label='female')
plt.xlabel('IQR')
plt.ylabel('meanfun')
plt.legend(loc='upper right')
plt.show()
所得结果为:
好吧,看来两个变量仅靠简单的数据直觉就可以知道......他们已经能够区分male和female了
因此,我们只使用新的值跑一下模型,所得到的结果如下:
svc train Accuracy Score:
0.9693279206134416
svm test Accuracy Score:
0.9695057833859095
logistic train Accuracy Score:
0.9630130807397383
logistic test Accuracy Score:
0.9695057833859095
knn train Accuracy Score:
0.9769959404600812
knn test Accuracy Score:
0.9705573080967402
nn train Accuracy Score:
0.9688768606224628
nn test Accuracy Score:
0.9684542586750788
rf train Accuracy Score:
0.993234100135318
rf test Accuracy Score:
0.9726603575184016
我们用2个变量替代了原模型的20个变量,而准确率仅仅简单了2~3%左右,可以说是非常成功的。因此这次优化也是很有成效的。