超越准确率用Python实战Kappa系数破解分类模型评估陷阱当你在处理医疗诊断报告时发现模型对罕见病的识别率几乎为零但总体准确率却高达95%——这种令人不安的矛盾现象正是类别不平衡数据集中的典型陷阱。本文将带你用Python从零实现Kappa系数评估彻底解决单一准确率指标的局限性。1. 为什么准确率会欺骗我们上周我参与了一个信用卡欺诈检测项目数据集里正常交易占比99.7%欺诈交易只有0.3%。当我们用最简单的随机森林模型时准确率轻松达到99.6%看起来简直完美。但细看混淆矩阵才发现模型把所有交易都预测为正常实际上一个欺诈案例都没抓到这就是准确率指标的致命缺陷from sklearn.metrics import confusion_matrix y_true [0]*997 [1]*3 # 真实标签 y_pred [0]*1000 # 全预测为正常 print(准确率:, sum(np.array(y_true)np.array(y_pred))/len(y_true)) print(confusion_matrix(y_true, y_pred))输出结果准确率: 0.997 [[997 0] [ 3 0]]类别不平衡问题在真实场景中无处不在医疗诊断罕见病识别工业质检缺陷产品检测金融风控欺诈交易识别网络安全异常流量检测传统准确率计算方式ACC (TP TN) / (TP TN FP FN)但当负样本占比90%时即使模型全部预测为负ACC也能达到0.9——这显然不能反映真实模型性能。2. Kappa系数的数学本质Cohens Kappa系数通过引入偶然一致性的概念有效消除了类别分布带来的评估偏差。其核心公式κ (p₀ - pₑ) / (1 - pₑ)其中p₀观察一致性即准确率ACCpₑ期望一致性随机预测时的一致性计算示例 假设我们有如下3×3混淆矩阵真实\预测ABC总计A505560B10301050C553040总计654045150计算步骤p₀ (503030)/150 110/150 ≈ 0.733pₑ (60×65 50×40 40×45)/(150²) ≈ 0.338κ (0.733 - 0.338)/(1 - 0.338) ≈ 0.597Kappa系数解读标准κ值范围一致性等级≤0无一致性0.01-0.20极轻微一致性0.21-0.40一般一致性0.41-0.60中等一致性0.61-0.80高度一致性0.81-1.00几乎完全一致3. Python实战从零实现到sklearn应用3.1 基础版本实现我们先手动实现Kappa计算加深理解import numpy as np def kappa(confusion_matrix): n_classes confusion_matrix.shape[0] sum_total np.sum(confusion_matrix) # 计算p0 p0 np.trace(confusion_matrix) / sum_total # 计算pe row_sums np.sum(confusion_matrix, axis1) col_sums np.sum(confusion_matrix, axis0) pe np.sum(row_sums * col_sums) / (sum_total ** 2) # 计算kappa k (p0 - pe) / (1 - pe) return k # 测试前文示例 mat np.array([[50,5,5], [10,30,10], [5,5,30]]) print(手动实现Kappa:, kappa(mat)) # 输出约0.5973.2 sklearn专业实现实际项目中推荐使用sklearn的现成实现from sklearn.metrics import cohen_kappa_score # 模拟医疗诊断数据0:健康, 1:疾病 y_true [0]*90 [1]*10 # 9:1的不平衡数据 y_pred_random [0]*80 [1]*20 # 随机猜测型预测 y_pred_biased [0]*100 # 全预测为健康 print(随机预测Kappa:, cohen_kappa_score(y_true, y_pred_random)) print(全健康预测Kappa:, cohen_kappa_score(y_true, y_pred_biased))输出结果随机预测Kappa: 0.012345679012345677 全健康预测Kappa: 0.03.3 可视化对比分析用seaborn绘制指标对比图更直观import matplotlib.pyplot as plt import seaborn as sns from sklearn.metrics import accuracy_score metrics { 全负预测: { ACC: accuracy_score(y_true, y_pred_biased), Kappa: cohen_kappa_score(y_true, y_pred_biased) }, 随机预测: { ACC: accuracy_score(y_true, y_pred_random), Kappa: cohen_kappa_score(y_true, y_pred_random) } } plt.figure(figsize(10,6)) sns.barplot(xlist(metrics.keys()), y[v[ACC] for v in metrics.values()], colorblue, alpha0.6, labelACC) sns.barplot(xlist(metrics.keys()), y[v[Kappa] for v in metrics.values()], colororange, alpha0.6, labelKappa) plt.legend() plt.title(ACC与Kappa在不平衡数据上的表现对比) plt.ylabel(得分) plt.show()4. 进阶加权Kappa(QWK)详解当分类标签具有顺序关系时如产品评级ABC简单的Kappa系数可能无法充分反映预测误差的严重程度。这时就需要引入二次加权Kappa(Quadratic Weighted Kappa, QWK)。4.1 权重矩阵原理QWK通过权重矩阵量化不同误判的严重性w_ij (i-j)² / (N-1)²其中N为类别数量i和j分别为真实和预测的类别索引从0开始。示例3分类问题的权重矩阵真实\预测012000.25110.2500.25210.2504.2 Python实现QWKdef quadratic_weighted_kappa(y_true, y_pred, n_classes): confusion np.zeros((n_classes, n_classes)) for t, p in zip(y_true, y_pred): confusion[t, p] 1 # 计算权重矩阵 weights np.zeros((n_classes, n_classes)) for i in range(n_classes): for j in range(n_classes): weights[i,j] (i-j)**2 / (n_classes-1)**2 # 计算观察值和期望值 hist_true np.sum(confusion, axis1) hist_pred np.sum(confusion, axis0) expected np.outer(hist_true, hist_pred) / np.sum(confusion) # 计算QWK numerator np.sum(weights * confusion) denominator np.sum(weights * expected) return 1 - numerator / denominator # 测试学生成绩评级ABC y_true [0,1,2,0,1,2,0,1,2] y_pred [0,1,1,0,2,1,0,1,2] # 有轻微误差 print(QWK:, quadratic_weighted_kappa(y_true, y_pred, 3))4.3 实际应用场景QWK特别适合以下场景医学症状严重程度评估产品质量分级信用评级预测教育考试评分在Kaggle的许多比赛中如PetFinder.my收养预测比赛QWK都是核心评估指标。