最近画ROC曲线遇到了些困难,解决后留个档,分享一下,希望能帮助到有同样问题的大家~
问题:
画出来的ROC图像只有一个折点(图1),但正确的ROC曲线应该是看起来圆润的(图2),那么如何画正确的图像?
问题所在:要用预测的score分数(选择正类概率),而非预测的标签与真实标签进行ROC计算!
先以逻辑回归为例:
from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) # 分数据集
model = LogisticRegression()
model.fit(X_train, y_train)
y_scores = model.predict_proba(X_test)[:, 1] # 选择正类的概率!
fpr1, tpr1, thread1 = roc_curve(y_test, y_scores) # 注意用的是y_scores!
roc_auc = auc(fpr1, tpr1)
# 绘图
plt.figure()
lw = 2
plt.plot(fpr1, tpr1, color='darkred',
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('ROC')
plt.legend(loc="lower right")
plt.savefig('roc.png')
plt.show()
这里的y_scores是概率哦,后续再绘图就是正确的啦。
再多算几个SVM、随机森林的score:
# SVM
from sklearn.svm import SVC
svm_model = SVC(probability=True)
svm_model.fit(X_train, y_train)
y_scores_svm = svm_model.predict_proba(X_test)[:, 1] # 选择正类的概率!
y_pred_svm = svm_model.predict(X_test) # 计算准确率
print("SVM Accuracy:", accuracy_score(y_test, y_pred_svm))
# 随机森林
from sklearn.ensemble import RandomForestClassifier
rf_model = RandomForestClassifier(random_state=0)
rf_model.fit(X_train, y_train)
y_scores_rf = rf_model.predict_proba(X_test)[:, 1] # 选择正类的概率!
y_pred_rf = rf_model.predict(X_test) # 计算准确率
print("Random Forest Accuracy:", accuracy_score(y_test, y_pred_rf))
深度学习也是一样,举个小例子:
import torch
import numpy as np
from torch.utils.data import DataLoader
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
# 加载模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 调到GPU
model = net(hidden_size=512) # 调模型
weight = torch.load('./model.pth', map_location=device) # 训练的最佳参数权重
model.load_state_dict(weight,strict=False)
model = model.to(device)
model.eval() # 将模型设置为评估模式
# 存储预测分数概率
y_score = []
with torch.no_grad(): # 不需要计算梯度
for data, target in dataloader_test:
data = data.to(device) # 将数据移到正确的设备上
output = model(data) # 获取模型的输出
y_score.extend(output.cpu().numpy()) # 存储分数概率
# 计算ROC
fpr, tpr, thread = roc_curve(y_test, y_score)
roc_auc = auc(fpr, tpr)
# 后续绘图同上
如果想在一张图上同时绘制多条ROC曲线:
# 绘图
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='SVM ROC curve (area = %0.2f)' % roc_auc1)
plt.plot(fpr1, tpr1, color='green',
lw=lw, label='Random forest ROC curve (area = %0.2f)' % roc_auc2)
plt.plot(fpr,tpr,color = 'darkred',label = 'deproc area:(%0.2f)'%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()
这里由于数据量较少原因,图也没有特别特别圆润哈哈,依然存在折线,不过也是正确的!
未来遇到其代码问题,也将持续分享~希望能帮助到大家!加油!