在前面的一篇文章我们给出了使用Sklearn 中的SVM进行分类时如何使用留一法来进行分类。python基于sklearn的SVM和留一法(LOOCV)进行二分类
如何在使用留一法时绘制ROC曲线和AUC
什么是ROC曲线和AUC?这个可以参考如下的文章。
部分内容摘抄于此 原文链接
- ROC曲线,全称The Receiver Operating Characteristic Curve,译为受试者操作特性曲线。这是一条以不同阈值下的假正率FPR为横坐标,不同阈值下的召回率Recall为纵坐标的曲线。
- 我们希望理解,每判断正确一个少数类,就有多少个多数类会被判断错误。假正率正好可以帮助我们衡量这个能力的变化。我们使用Recall和FPR之间的平衡,来替代Recall和Precision之间的平衡,让我们衡量模型在尽量捕捉少数类的时候,误伤多数类的情况如何变化,这就是我们的ROC曲线衡量的平衡。
- 如果我们是使用decision_function来画ROC曲线,那我们选择出来的最佳阈值其实是最佳距离。
- 如果我们使用的是概率,我们选取的最佳阈值就会使一个概率值了。
- 只要我们让这个距离/概率以上的点,都为正类,让这个距离/概率以下的点都为负类,模型就是最好的:即能够捕捉出少数类,又能够尽量不误伤多数类,整体的精确性和对少数类的捕捉都得到了保证。
定义绘制ROC曲线的阈值
- 通过上述的解释我们可以知道,想要绘制ROC曲线我们需要找到一个最佳阈值
- 这个阈值的定义有两种方式,分别是使用decision_function定义的距离以及使用predict_proba定义概率这两种方式。本文采用第一种方式decision_function定义。
不使用LOOCV时如何绘制ROC曲线与AUC
- 不使用LOOCV时我们会有独立的训练集和测试集,当我们得到训练之后的模型.X_train,Y_train(训练集的label);X_test,Y_test(测试集的label);
- 通过X_train,Y_train 我们可以得到训练模型
- 将X_test作为模型的输入,可以得到分类结果
- 简单的代码示例
clf = SVC(kernel='linear', C=1.0)
clf.fit(X_test, Y_test)
Y_prediect = clf.predict(X_test)
- 如何进一步得到ROC曲线呢,首先使用decision_function得到测试集的分数,这是后面绘制曲线的输入
Y_score = clf.decision_function(X_test)
- 接下来使用roc_curve, auc计算相关绘制结果。roc_curv的输入分别为测试集的label,和测试集的decision_function计算结果Y_score
from sklearn.metrics import roc_curve, auc
# 为每个类别计算ROC曲线和AUC
roc_auc = dict()
fpr, tpr, threshold = roc_curve(Y_test,Y_score)
roc_auc = auc(fpr, tpr)
- 在计算结果基础上绘图
plt.figure()
lw = 3
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
使用LOOCV时SVM的结果怎么绘制ROC和AUC和?
- 思考一下,和独立的测试集与训练集相比,留一法的差别在哪里? 使用留一法时,我们的测试集每次只有一个,测试得到的结果也只有一个,同样通过clf.decision_function(X_test)得到的距离值也只有一个。
- 但是我们使用留一法会循环n次,每一次都会得到一个Y_score和一个Y_prediect 。
- 上一篇文章python基于sklearn的SVM和留一法(LOOCV)进行二分类中我们将每次的Y_prediect 使用一个list保存下来,最后用于F1,ACC等的计算,同理我们也可以用一个list将每次的Y_score保存下来,最后用于后面绘制AUC和ROC曲线。
代码详解
- 在上一篇文章的基础上 主要定义保存距离的列表,以及在LOOCV中定义计算每次测试集的Y_score
Y_score_list = []
....
loocv代码中
Y_score_temp = clf.decision_function(X_test)
Y_score_list.append(Y_score_temp)
完整代码
import numpy as np
from sklearn.model_selection import LeaveOneOut
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
import scipy.io as scio
###################功能性函数###################################################
# 将一个任意嵌套的列表整理为一个列表
def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested
# 获取一个预测结果的TP TN FP FN
def get_TpTN_FpFn(list1, list2):
# list1 为真实的label list2 为预测的label
reallabel_list = list(flatten(list1))
predictlabel_list = list(flatten(list2))
TP_count = 0
TN_count = 0
FP_count = 0
FN_count = 0
for i in range(len(reallabel_list)):
if reallabel_list[i] == 1 and predictlabel_list[i] == 1:
TP_count += 1
if reallabel_list[i] == -1 and predictlabel_list[i] == -1:
TN_count += 1
if reallabel_list[i] == -1 and predictlabel_list[i] == 1:
FP_count += 1
if reallabel_list[i] == 1 and predictlabel_list[i] == -1:
FN_count += 1
return TP_count, TN_count, FP_count, FN_count
if __name__ == '__main__':
# ################# 数据的读取与整理了#############################################
path2 = 'C:\\Users\\Administer\\Desktop\\classer\\dataset'
MSN_HC = scio.loadmat(path2 + '\\HC_coupling_str_fun_20201022.mat')
train_data1= MSN_HC['all_coupling'].T
MSN_GTCS = scio.loadmat(path2 + '\\GTCS_coupling_str_fun.mat')
train_data2= MSN_GTCS['all_coupling'].T
# 以上代码按照自己的数据要求输入,可以自己删除。
dataset = (np.hstack((train_data1, train_data2))).T
data1_label = list(-1 for i in range(np.size(train_data1, 1)))
data2_label = list(1 for i in range(np.size(train_data2, 1)))
datalabels = data1_label + data2_label
#####################################LOOVC#####################################
loo = LeaveOneOut()
loo.get_n_splits(dataset)
predictlabel_list = []
reallabel_list = []
scaler = StandardScaler()
dataset = scaler.fit_transform(dataset)
clf = SVC(C=1, kernel='linear', gamma='auto')
count_right_label = 0
count = 0 # 循环次数
# 用留一法进行验证
Y_score_list = []
for train_index, test_index in loo.split(dataset):
X_train, X_test = dataset[train_index], dataset[test_index]
Y_train, Y_test = np.array(datalabels)[train_index], np.array(datalabels)[test_index]
clf.fit(X_train, Y_train)
predictlabel_list.append(list(clf.predict(X_test)))
reallabel_list.append(list(Y_test))
#######相比较于前文新增代码
Y_score_temp = clf.decision_function(X_test) # 得到的结果为该类到超平面的距离
Y_score_list.append(Y_score_temp)
#######
if Y_test == clf.predict(X_test):
count_right_label += 1
count += 1
print('第{}次循环'.format(count))
accurancy = count_right_label / len(datalabels)
print('******循环结束!************')
print('准确率为:%.2f%%' % (accurancy * 100))
print('******运行结束!************')
TP_count, TN_count, FP_count, FN_count = get_TpTN_FpFn(reallabel_list, predictlabel_list)
F1_score = (2 * TP_count) / (2 * TP_count + FP_count + FN_count)
ACC = (TP_count + TN_count) / (TP_count + FN_count + TN_count + FP_count)
SEN = TP_count / (TP_count + FN_count)
SPE = TN_count / (TN_count + FP_count)
print('F1_SCORE为:%.2f%%' % (F1_score * 100))
print('ACC(准确率)为:%.2f%%' % (ACC * 100))
print('SEN(敏感度)为:%.2f%%' % (SEN * 100))
print('SPE(特异性)为:%.2f%%' % (SPE * 100))
# ###############################################
##绘制ROC和计算AUC
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
real = np.array(list(flatten(reallabel_list)))
roc_auc = dict()
fpr, tpr, threshold = roc_curve(real, np.array(Y_score_list))
roc_auc = auc(fpr, tpr)
plt.figure()
lw = 3
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()