最近在画交叉验证的ROC曲线。由于我采用的是留一法来做10折交叉,这就导致我每一折的样本数量是不固定的,但我又想画一个平均的校验验证性能曲线,并且把置信区间也画出来,找了很久资料,我画了一个这样的。先看效果图,如下图:
中间蓝色的是平均的ROC,周围蓝色的带是所有的交叉验证触及的最大范围。因为交叉验证需要多次抽样,但我用的是深度学习,很难做到抽样,所以就用最大范围代替置信区间。具体做法如下:
from my_utils.utils import *
from sklearn.metrics import auc, plot_roc_curve, roc_curve
import my_utils.file_util as fu
import matplotlib.pyplot as plt
class_type = '1p19q'
#图表的保存路径
save_path = ''
#存放所有交叉验证的预测结果和label的文件路径
record_dir = ''
#find_file是我自己写的寻找路径下所有best-auc.csv文件的函数,用的时候可以替换成自己的
#返回的是所有csv文件的绝对路径。文件格式是第一和第二列是预测值,第三列label。
#因为我用的是one hot做二分类,所以有两个值
flods_dir = find_file(record_dir, 2,1, suffix='best_auc.csv')
pre_record = []
#获取所有交叉验证的预测值和label
for record_file in flods_dir:
temp = fu.csv_reader(record_file)
temp_fold_record = []
#因为是二分类,所有只取第一个预测值,第二个不要
temp_fold_record.append([i[0] for i in temp])
#取label值
temp_fold_record.append([i[2] for i in temp])
pre_record.append(temp_fold_record)
roc_record, value, fpr, tpr = [], [], [], []
for record in pre_record:
label = np.array([int(i) for i in record[1]]).squeeze()
pred = np.array([float(i) for i in record[0]]).squeeze()
#计算roc曲线
t_fpr, t_tpr, thre = roc_curve(label, 1-pred)
#计算AUC
auc_score = auc(t_fpr, t_tpr)
fpr.append([float(i) for i in t_fpr])
value.extend([float(i) for i in t_fpr])
tpr.append([float(i) for i in t_tpr])
mean_fpr, min_fpr, max_fpr = [],[],[]
mean_tpr, min_tpr, max_tpr= [],[],[]
#这个是为了对曲线进行插值,因为每个曲线的样本不一样,所以获取到的fpr和tpr也不一样长度,
#所以需要进行插值
#插值的原理是,获取所有fpr的值,然后将每个交叉验证的roc都插值成和fpr的值一样多的长度。
#插值并不会改变每个roc曲线的形状,这个可以放心使用
unique = np.unique(np.array(value).flatten())
#对fpr和tpr进行插值
for l in range(len(fpr)):
tpr[l] = np.interp(unique, fpr[l], tpr[l], 0, 1)
fpr[l] = np.interp(unique, fpr[l], fpr[l], 0, 1)
#将每个交叉验证的ROC都画出来
plt.plot(fpr[l], tpr[l])
fpr = np.array(fpr)
tpr = np.array(tpr)
#求fpr和tpr的极大极小,获取每个实验所能触及的最大指标范围
min_fpr = np.min(fpr, axis=0)
max_fpr = np.max(fpr, axis=0)
min_tpr = np.min(tpr, axis=0)
max_tpr = np.max(tpr, axis=0)
#获取均值,为了得到交叉验证的平均曲线
mean_tpr = np.mean(tpr, axis=0)
mean_fpr = np.mean(fpr, axis=0)
mean_tpr[0] = 0
plt.figure(dpi=300)
plt.title(class_type)
plt.style.use('seaborn')
plt.xlabel('1-Specificity')
plt.ylabel('Sencitivity')
#画平均曲线
p1 = plt.plot(mean_fpr, mean_tpr, marker='.',
linestyle='--',c='b', linewidth=1,
alpha=0.65, label='20X')#markeredgecolor='b',
plt.legend(loc='lower right')
#将极大极小值的范围填充淡蓝色
p2 = plt.fill_between(min_fpr,max_tpr, min_tpr,color='blue', alpha=0.08)
#展示图象
plt.show()
下面附上每个交叉验证的图像来验证范围画的对不对。
再对比我们画的
可以看到啊,我们画的范围与所有ROC的曲线的范围是吻合的,平均曲线也像模像样。