You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中多分类任务的ROC/CAP曲线绘制问题求助

嘿,我刚好在多分类任务里踩过ROC和CAP曲线绘制的坑,给你整理了两个实用的解决方案,附带直接能跑的Python代码,你可以直接套用到自己的数据集上!

一、多分类ROC曲线的绘制

多分类任务里的ROC曲线主要有两种常用的实现思路:One-vs-Rest(OvR,一对其余)和One-vs-One(OvO,一对一)。其中OvR因为直观易懂,是我平时做项目用得最多的方式。

1. One-vs-Rest(OvR)方法

原理

把每个类别单独当作“正类”,剩下的所有类别合并成“负类”,然后为每个类别生成一条二分类ROC曲线,最后把所有曲线画在同一张图里,就能清晰对比每个类别的区分能力。

代码实现

import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_curve, auc
from sklearn.preprocessing import label_binarize

# 1. 加载示例数据集(替换成你自己的X和y即可)
iris = datasets.load_iris()
X = iris.data
y = iris.target

# 2. 将标签二值化(OvR需要每个类别对应一个二分类标签)
y_bin = label_binarize(y, classes=[0, 1, 2])
n_classes = y_bin.shape[1]

# 3. 拆分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y_bin, test_size=0.3, random_state=42)

# 4. 训练分类器(这里用随机森林,你可以换成SVM、XGBoost等支持概率输出的模型)
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train)

# 5. 获取每个类别的预测概率
y_score = clf.predict_proba(X_test)

# 6. 计算每个类别的FPR、TPR和AUC值
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
    fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
    roc_auc[i] = auc(fpr[i], tpr[i])

# 7. 绘制所有类别的ROC曲线
plt.figure(figsize=(8, 6))
colors = ['blue', 'red', 'green']
for i, color in zip(range(n_classes), colors):
    plt.plot(fpr[i], tpr[i], color=color, lw=2,
             label=f'ROC curve of class {i} (AUC = {roc_auc[i]:.2f})')

# 绘制随机猜测的基准线
plt.plot([0, 1], [0, 1], 'k--', lw=2)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Multi-class ROC Curve (One-vs-Rest)')
plt.legend(loc="lower right")
plt.show()

小提示

  • 如果你用的是自己的数据集,只需要替换X和y即可,label_binarize会自动处理整数或字符串类型的标签。
  • 如果你的模型不支持predict_proba(比如部分SVM模型),可以用decision_function代替获取分类得分。

2. One-vs-One(OvO)方法

原理

每两个类别之间都做一次二分类ROC曲线,比如3个类别会生成3条曲线(0vs1、0vs2、1vs2)。这种方法更细致,但曲线数量会随类别数激增(k个类别会有k*(k-1)/2条曲线),适合类别数较少的场景。

代码实现(简略版)

from sklearn.multiclass import OneVsOneClassifier

# 用OneVsOneClassifier包装模型
ovo_clf = OneVsOneClassifier(RandomForestClassifier(n_estimators=100, random_state=42))
ovo_clf.fit(X_train, y.argmax(axis=1))

# 以类别0和1为例绘制OvO的ROC曲线
mask = (y_test.argmax(axis=1) == 0) | (y_test.argmax(axis=1) == 1)
X_ovo = X_test[mask]
y_ovo = y_test[mask].argmax(axis=1)
y_ovo_score = ovo_clf.predict_proba(X_ovo)[:, 0]  # 取类别0的预测概率

fpr_ovo, tpr_ovo, _ = roc_curve(y_ovo, y_ovo_score, pos_label=0)
roc_auc_ovo = auc(fpr_ovo, tpr_ovo)

plt.figure(figsize=(8,6))
plt.plot(fpr_ovo, tpr_ovo, lw=2, label=f'ROC curve (Class 0 vs 1, AUC={roc_auc_ovo:.2f})')
plt.plot([0,1],[0,1],'k--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('One-vs-One ROC Curve')
plt.legend()
plt.show()
二、多分类CAP曲线的绘制

CAP曲线(Cumulative Accuracy Profile)用来评估模型对样本的排序能力——简单说就是看“按预测概率从高到低排序后,前N%的样本里能抓到多少真实正样本”,比ROC更直观反映模型的排序效果。

原理

针对每个类别:

  1. 把测试集样本按属于该类别的预测概率从高到低排序。
  2. 计算累计的真实正样本数量占总正样本数的比例。
  3. 和随机模型(直线)、完美模型(阶梯线)对比,就能看出模型的性能差距。

代码实现

import numpy as np

def plot_cap_curve(y_true, y_score, class_name):
    # 1. 按预测概率从高到低排序样本
    sorted_indices = np.argsort(y_score)[::-1]
    y_true_sorted = y_true[sorted_indices]
    y_score_sorted = y_score[sorted_indices]
    
    # 2. 计算累计正样本数和累计样本数
    total_pos = np.sum(y_true)
    cumulative_pos = np.cumsum(y_true_sorted)
    cumulative_samples = np.arange(1, len(y_true)+1)
    
    # 3. 计算CAP曲线的纵坐标(累计正样本比例)
    cap_curve = cumulative_pos / total_pos if total_pos !=0 else np.zeros_like(cumulative_samples)
    
    # 4. 绘制三条曲线:模型、完美、随机
    plt.figure(figsize=(8,6))
    plt.plot(cumulative_samples / len(y_true), cap_curve, lw=2, label='Model CAP Curve')
    plt.plot([0, total_pos/len(y_true), 1], [0, 1, 1], 'g--', lw=2, label='Perfect Model')
    plt.plot([0,1], [0,1], 'k--', lw=2, label='Random Model')
    
    plt.xlabel('Proportion of Samples Selected')
    plt.ylabel('Proportion of True Positives Captured')
    plt.title(f'CAP Curve for Class {class_name}')
    plt.legend(loc='lower right')
    plt.show()

# 为每个类别绘制CAP曲线
for i in range(n_classes):
    plot_cap_curve(y_test[:,i], y_score[:,i], class_name=i)

小提示

  • 如果某个类别在测试集里没有正样本,函数会自动处理避免除以0的错误。
  • 从CAP曲线里能快速看出:模型曲线越靠近完美模型,排序能力越强;越靠近随机模型,性能越差。

内容的提问来源于stack exchange,提问作者Sai Shree

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:08:08