对于分类器的评价指标,我们已经在之前的文章中说到了正确率(accuracy)、精准率(precision)、召回率(recall)、敏感性(sensitivity)、特异性(specificity)等评价指标,具体可参见以下两篇文章:
机器学习分类器评价指标详解(Precision, Recall, PR, ROC, AUC等)(一)
机器学习分类器评价指标详解(Precision, Recall, PR, ROC, AUC等)(二)

虽然上述指标都很常用,但是其只是对分类器性能整体的**“笼统的”**评价。
比如最常用的正确率,它只关心分类器一共正确分类了多少比例的样本,但是对于每类样本的正确率却不能进行很好地刻画。

所谓每类样本的正确率,也就是分类器对每一类的分类结果与真实标签的一致性。
这就让我们想到了混淆矩阵的对角线,混淆矩阵对角线上的元素,就是分类器对每类样本正确分类的统计。
因为正确率的计算公式正是混淆矩阵对角线元素之和除以所有样本数,即
A c c u r a c y = T P + T N T P + F P + F N + T N Accuracy=\frac{TP+TN}{TP+FP+FN+TN} Accuracy=TP+FP+FN+TNTP+TN

虽然Accuracy的计算简单,正常情况下也能够很好地刻画分类器的分类性能,
但是,在一些样本不均衡的非正常情况下,如果使用Accuracy作为评价指标的话,会使得分类器“偷懒”。
比如对于样本数服从长尾分布的多分类问题,有些头部类别样本量比较多,而尾部类样本量较少,
如果只为了得到较高的准确率,分类器会直接忽略样本量较少的尾部类,而只致力于将头部类样本分对。
这样就巧妙地避开了非常hard的“努力学习”,同时还能取得较好成绩(accuracy),即模型有了偏向性(偏向于头部样本)。

可是,这并不是我们期望的,虽然尾部类数量少,但是很可能它们对我们很重要。
如何让分类器不偷懒,对所有类别的样本都一视同仁呢?
即尽量减少模型的偏向性,
为此,我们可以通过对偏向性进行惩罚,
而kappa系数就给出了一种进行惩罚的方式。

Kappa系数
也称为Cohen’s Kappa系数,是一种统计量,用于衡量两个评估者(或分类器,一般是模型与Ground Truth)在分类问题上的一致性。
所谓一致性就是模型预测结果和实际分类结果是否一致。
kappa系数的计算也是基于混淆矩阵的,取值为-1到1之间,通常大于0。
其公式如下:
k a p p a = p o − p e 1 − p e kappa=\frac{p_{o}-p_{e}}{1-p_{e}} kappa=1pepope
其中
Kappa系数计算及其python代码实现-LMLPHP

Kappa系数计算及其python代码实现-LMLPHP
可以发现, p o p_{o} po就是accuracy,
p e p_{e} pe表示的意思是:所有类别分别对应的“实际与预测数量的乘积”之总和,除以“样本总数的平方”

通过kappa的定义公式可知,其是通过对 p e p_{e} pe的使用来实现对偏向性的惩罚的,
具体而言,对于不平衡的样本,越不平衡的混淆矩阵(即分类器的偏向性越高),
p e p_{e} pe的值就越高,则kappa的值就越低,从而实现了对偏向性的惩罚。

代码实现
方法1:根据定义自定义计算函数

def calculate_kappa(confusion_matrix):
    # 计算po(对角线元素之和除以整个矩阵元素之和)
    po = np.trace(confusion_matrix) / np.sum(confusion_matrix)
    
    # 计算pe(所有类别分别对应的“实际与预测数量的乘积”之总和除以“样本总数的平方”)
    row_sums = np.sum(confusion_matrix, axis=1)
    col_sums = np.sum(confusion_matrix, axis=0)
    pe = np.sum(row_sums * col_sums) / (np.sum(confusion_matrix) ** 2)
    
    # 计算kappa
    kappa = (po - pe) / (1 - pe)
    
    return kappa

方法2:使用sklearn中的内置函数进行计算

from sklearn.metrics import cohen_kappa_score

y_true = [2, 0, 2, 2, 0, 1]
y_pred = [0, 0, 2, 2, 0, 2]
kappa_value = cohen_kappa_score(y_true, y_pred)
print("kappa值为 %f" % kappa_value)
kappa值为 0.428571

需要注意的是自定义的函数的输入为混淆矩阵
而sklearn内置函数的输入为真实标签与分类器的预测标签。

参考:
https://zhuanlan.zhihu.com/p/67844308

10-18 06:35