背景
在机器学习分类问题中,评估模型性能的标准是必须深入思考的重要环节,对于二分类问题,常用的指标有ROC曲线、AUC值等,而在多分类问题中,类似的指标也有其对应的版本,但复杂性也随之增加,今天,作者将带你了解一种用于多分类模型评估的指标—— Obuchowski指数 ,并通过实际代码演示如何计算该指数
Obuchowski指数简介
Obuchowski指数是一种评估多分类问题下分类器性能的工具,它通过考虑各类之间的两两比较,综合计算模型在所有类对上的AUC值,进而为多分类问题提供一个整体的评估,它的计算方式类似于二分类中的AUC,只不过是将各类别之间的分类效果纳入考量
该指数可以为你提供一个更全面的视角去评估多分类模型,因为它不仅关注每个类别的表现,还特别注重模型区分不同类别的能力,主要用于医疗影像或诊断测试的评估,最终评估模型在多个类别上区分不同病情的能力
代码实现
数据读取处理
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_csv('Multiclass Diabetes Dataset.csv')
from sklearn.model_selection import train_test_split
# 分割数据集
X = df.drop(['Class'], axis = 1)
y = df['Class']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3,
stratify=df['Class']) #分离训练集和测试
df.head()
从一个多分类糖尿病数据集中分离出特征和标签,然后将数据集划分为训练集和测试集,以便后续进行模型训练和测试,这个数据集通过生化指标(如尿素、肌酐、HbA1c等)结合人口统计信息(如性别和年龄)来预测个体的糖尿病状态,来自 Mendeley 数据,用于构建糖尿病的多分类预测模型
模型构建
from sklearn.ensemble import RandomForestClassifier
# 初始化随机森林分类器,添加更多参数
rf_model = RandomForestClassifier(
n_estimators=100, # 树的数量
max_depth=5, # 树的最大深度
min_samples_split=5, # 分裂内部节点所需的最小样本数
min_samples_leaf=4, # 叶节点所需的最小样本数
max_features='sqrt', # 考虑分裂的最大特征数量,'sqrt' 是默认值用于分类问题
bootstrap=True, # 是否进行放回抽样
class_weight='balanced', # 平衡类间权重
random_state=42 # 随机种子,以便结果复现
)
# 训练模型
rf_model.fit(X_train, y_train)
初始化一个带有特定参数的随机森林分类器来训练模型,以便在平衡类别权重的情况下对训练数据 X_train 和 y_train 进行分类
混淆矩阵绘制
from sklearn.metrics import confusion_matrix
import seaborn as sns
# 输出混淆矩阵
conf_matrix = confusion_matrix(y_test, pred)
# 绘制热力图
plt.figure(figsize=(10, 7), dpi=1200)
sns.heatmap(conf_matrix, annot=True, annot_kws={'size':15},
fmt='d', cmap='YlGnBu', cbar_kws={'shrink': 0.75})
plt.xlabel('Predicted Label', fontsize=12)
plt.ylabel('True Label', fontsize=12)
plt.title('Confusion matrix heat map', fontsize=15)
plt.savefig('Confusion matrix heat map.pdf', format='pdf', bbox_inches='tight')
plt.show()
生成并可视化随机森林分类模型的混淆矩阵,展示预测结果的正确和错误分类情况
多分类任务——宏平均ROC曲线
AUC计算
from sklearn import metrics
from sklearn.preprocessing import label_binarize
# 预测并计算概率
ytest_proba_rf = rf_model.predict_proba(X_test)
# 将y标签转换成one-hot形式
ytest_one_rf = label_binarize(y_test, classes=[0, 1, 2])
# 宏平均法计算AUC
rf_AUC = {}
rf_FPR = {}
rf_TPR = {}
for i in range(ytest_one_rf.shape[1]):
rf_FPR[i], rf_TPR[i], thresholds = metrics.roc_curve(ytest_one_rf[:, i], ytest_proba_rf[:, i])
rf_AUC[i] = metrics.auc(rf_FPR[i], rf_TPR[i])
print(rf_AUC)
# 合并所有的FPR并排序去重
rf_FPR_final = np.unique(np.concatenate([rf_FPR[i] for i in range(ytest_one_rf.shape[1])]))
# 计算宏平均TPR
rf_TPR_all = np.zeros_like(rf_FPR_final)
for i in range(ytest_one_rf.shape[1]):
rf_TPR_all += np.interp(rf_FPR_final, rf_FPR[i], rf_TPR[i])
rf_TPR_final = rf_TPR_all / ytest_one_rf.shape[1]
# 计算最终的宏平均AUC
rf_AUC_final = metrics.auc(rf_FPR_final, rf_TPR_final)
AUC_final_rf = rf_AUC_final # 最终AUC
print(f"Macro Average AUC with Random Forest: {AUC_final_rf}")
通过计算各类的ROC曲线和AUC(曲线下面积),并最终得到宏平均的AUC值,为后续宏平均ROC曲线绘制做准备
可视化
plt.figure(figsize=(8, 8), dpi=1200)
# 使用不同的颜色和线型
plt.plot(rf_FPR[0], rf_TPR[0], color='#1f77b4', linestyle='-', label='Class 0 ROC AUC={:.4f}'.format(rf_AUC[0]), lw=2)
plt.plot(rf_FPR[1], rf_TPR[1], color='#ff7f0e', linestyle='-', label='Class 1 ROC AUC={:.4f}'.format(rf_AUC[1]), lw=2)
plt.plot(rf_FPR[2], rf_TPR[2], color='#2ca02c', linestyle='-', label='Class 2 ROC AUC={:.4f}'.format(rf_AUC[2]), lw=2)
# 宏平均ROC曲线
plt.plot(rf_FPR_final, rf_TPR_final, color='#000000', linestyle='-', label='Macro Average ROC AUC={:.4f}'.format(rf_AUC_final), lw=3)
# 45度参考线
plt.plot([0, 1], [0, 1], color='gray', linestyle='--', lw=2, label='45 Degree Reference Line')
plt.xlabel('False Positive Rate (FPR)', fontsize=15)
plt.ylabel('True Positive Rate (TPR)', fontsize=15)
plt.title('Random Forest Classification ROC Curves and AUC', fontsize=18)
plt.grid(linestyle='--', alpha=0.7)
plt.legend(loc='lower right', framealpha=0.9, fontsize=12)
plt.savefig('RF_optimized.pdf', format='pdf', bbox_inches='tight')
plt.show()
绘制随机森林的宏平均ROC曲线,并显示不同类别及宏平均的AUC值,结果表明模型在不同类别的分类性能(Class 0 AUC=0.9932,Class 1 AUC=1.0000,Class 2 AUC=0.9887),以及总体的宏平均AUC(0.9969),展示了模型的优秀表现,这部分代码具体解释参考文章——多分类如何绘制ROC曲线--宏平均ROC曲线
Obuchowski指数
from sklearn.metrics import roc_auc_score
from itertools import combinations
def calculate_obuchowski_index(model, X_test, y_test):
"""
计算随机森林模型的Obuchowski指数。
参数:
- model: 训练好的随机森林模型
- X_test: 测试集的特征
- y_test: 测试集的标签
返回:
- Obuchowski指数
"""
# 获取类别数量
unique_classes = np.unique(y_test)
n_classes = len(unique_classes)
# 获取模型的预测概率
y_pred_proba = model.predict_proba(X_test)
auc_sum = 0
# 遍历所有类的两两组合,计算每个类对之间的AUC
for class_a, class_b in combinations(unique_classes, 2):
# 为每个类创建二进制标签
y_binary_a = np.where(y_test == class_a, 1, 0)
y_binary_b = np.where(y_test == class_b, 1, 0)
# 计算每个类别的预测概率
y_pred_a = y_pred_proba[:, class_a]
y_pred_b = y_pred_proba[:, class_b]
# 计算 AUC
auc_a = roc_auc_score(y_binary_a, y_pred_a)
auc_b = roc_auc_score(y_binary_b, y_pred_b)
# 累加两个类别对的AUC
auc_sum += (auc_a + auc_b) / 2
# 计算Obuchowski指数
obuchowski_index = auc_sum / (n_classes * (n_classes - 1) / 2)
return obuchowski_index
# 假设你已经训练好了模型并有X_test和y_test
obuchowski_index = calculate_obuchowski_index(rf_model, X_test, y_test)
print(f"Obuchowski指数: {obuchowski_index}")
通过计算各类别之间所有可能的两两组合的AUC值,Obuchowski指数评估模型在多分类问题上的表现。当前结果中的Obuchowski指数为0.9939,表明模型具有非常优秀的整体分类性能。该指数范围在0到1之间,接近1的值表明模型在区分不同类别时表现出色,尤其是在处理类别不平衡问题时,Obuchowski指数相较于传统的AUC更具解释力和优势
宏平均ROC曲线和Obuchowski指数差异
计算方式
- 宏平均ROC曲线通过对每个类别与其余类别的二分类ROC曲线进行平均,不考虑类别之间的差异
- Obuchowski指数则是基于类别的两两比较(比如类别A对类别B,类别A对类别C等)分别计算ROC曲线,考虑了类别之间的区分度,并且可以加权平均
适用场景
- 宏平均ROC曲线主要用于评估模型在多类别分类任务中的整体性能,适用于通用的机器学习问题
- Obuchowski指数更适用于在不同类别之间有特定区分要求的场景,例如医学领域,强调类别对之间的区分
往期推荐
不止 SHAP 力图:LIME 实现任意黑盒模型的单样本解释
微信号|deep_ML
欢迎添加作者微信进入Python、ChatGPT群
进群请备注Python或AI进入相关群
无需科学上网、同步官网所有功能、使用无限制
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~
个人观点,仅供参考
