机器学习分类的几种评价指标:准确率Accuracy, AUC, Precision, Recall, F1,MAPE,SMAPE

分类评价指标有准确率(accuracy)、精确率(precision)、召回率(recall)、AUC面积、F值等。

1. 准确率Accuracy

也称精度, 分类准确的样本数占该类样本总数的比例。

此外,分类错误的样本数占样本总数的比例称为“错误率”(error rate)。

假如,m个样本有 a个样本分类错误。
E = a / m a c c = 1 − a / m E= a/m \\ acc = 1 - a/m E=a/macc=1a/m

# calculate accuracy
from sklearn import metrics
print( metrics.accuracy_score(y_test, y_pred) )

空准确率 null accuracy
使用样本比例最多的类别进行预测时的准确率。

y_count = np.bincount(y_test)
ii = np.nonzero(y_count)[0]
print(y_count)
zip(ii, y_count[ii])
print('null acc', y_count[0]/ len(y_test) )

每类的accuracy

def cal_acc(true_labels, pred_labels):
    '''
    true_labels: like[2,1,4],
    pred_labels: like[1,2,3]
    output: the acc of each class.
    '''
    from collections import Counter
    total = Counter(true_labels)
    keys = np.unique(true_labels)
    acc = {}
    for key in keys:
        acc[key] = 0
    for i in range(len(pred_labels)):
        if pred_labels[i] == true_labels[i]:
            acc[pred_labels[i]] += 1
    for key in keys:
        acc[key] = acc[key] / total[key]
    return acc

2. AUC,Precision,Recall,ROC曲线

AUC是衡量二分类模型优劣的一种评价指标,表示正例的预测值比负例预测值大的概率

在这里插入图片描述
精确率 P
precision = TP/(TP +FP),即正类预测对的个数和所有预测成正类样本数比值。
召回率 R
recall = TP/(TP +FN),即预测正类样本和原来一共正类样本数的比值。
准确率 Acc
Accuracy = (TP + TN)/(P + N)

ROC曲线 与 AUC面积
FPR:假正例率/假阳率(ROC的 x 轴);
FPR的含义是,把负类错误预测为正类的个数占总共负类的个数的比例。

F P R = F P T N + F P FPR = \frac{FP}{TN + FP} FPR=TN+FPFP

TPR:真正例率/真阳率(ROC的 y 轴);
TPR的含义是,正确预测为正类的个数占总共预测正类的个数的比例。

T P R = T P T P + F N TPR = \frac{TP}{TP+FN} TPR=TP+FNTP

ROC曲线, Receiver Operating Characteristic Curve, 受试者工作特征曲线, 是以假阳率(FPR)为横坐标,以真阳率(TPR)为纵坐标绘制的曲线。

ROC曲线与X坐标轴所围成的面积叫做AUC面积,这个面积也可以作为分类器的性能评价指标。面积越大,分类器性能越好。
值得注意的是,由于需要获得一系列的TPR,FPR,我们需要给出预测为正样本的概率。

假如我们已经得到了所有样本的概率输出(属于正样本的概率),现在的问题是如何改变“discrimination threashold”?我们根据每个测试样本属于正样本的概率值从大到小排序

下图是一个示例,图中共有20个测试样本,“Class”一栏表示每个测试样本真正的标签(p表示正样本,n表示负样本),“Score”表示每个测试样本属于正样本的概率4。

按照概率排序:
在这里插入图片描述
接下来,我们从高到低,依次将“Score”值作为阈值threshold,当测试样本属于正样本的概率大于或等于这个threshold时,我们认为它为正样本,否则为负样本。

举例来说,对于图中的第4个样本,其“Score”值为0.6,那么样本1,2,3,4都被认为是正样本,因为它们的“Score”值都大于等于0.6,而其他样本则都认为是负样本。
每次选取一个不同的threshold,就可以得到一组FPRTPR,即ROC曲线上的一点。这样一来,一共得到了20组FPRTPR的值,将它们画在ROC曲线的结果如下图:

在这里插入图片描述
当我们将threshold设置为10时,分别可以得到ROC曲线上的(0,0)(1,1)两个点。将这些(FPR,TPR)对连接起来,就得到了ROC曲线。当threshold取值越多,ROC曲线越平滑。
这里,阈值为1, 预测为正类的样本为0;
阈值为0, 预测为正类的样本为所有样本。正类样本预测对的个数= 正类样本个数,即TPR=1;负类样本预测成正类样本的个数 = 负类样本个数,FPR = 1.

ROC曲线的几个性质:

  1. ROC 曲线越靠近左上角,准确度越高;且最高仅左上角的ROC曲线的点对应的阈值是,错误最小的阈值(即FP,FN总数最小);
  2. ROC曲线不会随类别分布改变而改变,可以用于评价样本不平衡模型的效果.

计算 AUC 代码
公式一:
根据AUC的定义, A U C = ∑ F P N ∗ T P P AUC = \sum \frac{FP}{N}*\frac{TP}{P} AUC=NFPPTP,离散化,即可得

A U C = ∑ I ( P 正样本  , P 负样本  ) M ∗ N AUC = \frac{\sum I\left(P_{\text {正样本 }}, P_{\text {负样本 }}\right)}{M^{*} N} AUC=MNI(P正样本 ,P负样本 )

其中, M , N M,N M,N分布表示正、负样本的个数。这里 I 是指示函数,如果正样本对应的预测概率比负样本预测的概率大,值为1;值相等为0.5, 否则为0。

import numpy as np
from sklearn.metrics import roc_auc_score


def naive_auc(labels, preds):
    """
    最简单粗暴的方法
    先排序,然后统计有多少正负样本对满足:正样本预测值>负样本预测值, 计数1;如果相等,计数0.5, 再除以总的正负样本对个数
     复杂度 O(NlogN), N为样本数
    auc =  I(positive, negative)/M*N
    M: 正类样本数;N:负类样本数
    """
    n_pos = sum(labels)
    n_neg = len(labels) - n_pos
    total_pair = n_pos * n_neg

    labels_preds = zip(labels, preds)
    # O((M+N)log(M+N))
    labels_preds = sorted(labels_preds, key=lambda x: (x[1],x[0]))
    accumulated_neg = 0
    satisfied_pair = 0
    for i in range(len(labels_preds)):
        if labels_preds[i][0] == 1:
            # 如果是正类,加上累计的负类样本个数。
            satisfied_pair += accumulated_neg
            j = i-1
            # 由于会出现正类和负类预测概率相等情况,这个时候需要-0.5.
            while j>=0:
                if labels_preds[j][0] == 0:
                    if labels_preds[i][1] == labels_preds[j][1]:
                        satisfied_pair -= 0.5
                    else:
                        break
                j -= 1
        else:
            accumulated_neg += 1
    auc = satisfied_pair / float(total_pair)
    return auc

if __name__ == "__main__":
    y_true = np.array([1,1,0,0,1,1,0])
    y_scores = np.array([0.8,0.7,0.5,0.5,0.5,0.5,0.3])

    auc1 = roc_auc_score(y_true, y_scores)
    auc2 = naive_auc(y_true,y_scores)
    print("auc1",auc1)
    print("auc2",auc2)

运行结果:

auc1 0.8333333333333334
auc2 0.8333333333333334

公式二:
变形:
A U C = ∑ i ∈ positiveclass rank ⁡ i − M ( 1 + M ) 2 M × N A U C=\frac{\sum_{i \in \text {positiveclass}} \operatorname{rank}_{i}-\frac{M(1+M)}{2}}{M \times N} AUC=M×Nipositiveclassranki2M(1+M)
同样的,如果是遇到预测值相等的,排序 rank - 0.5. rank的取值是1到M+N.

def cal_auc2(labels,preds):
    sort_label = sorted(zip(labels,preds),key=lambda x: (x[1],x[0]))
    pos = sum(labels)
    neg = len(labels) - pos
    total_pairs = pos*neg
    satisfied_pair = 0
    for rank,item in enumerate(sort_label):
        if item[0] == 1:
            satisfied_pair += (rank+1)
            j = rank - 1
            while j >= 0:
                if sort_label[j][0] == 0:
                    if item[1] == sort_label[j][1]:
                        satisfied_pair -= 0.5
                    else:
                        break
                j -= 1
    auc = (satisfied_pair - pos*(1+pos)/2)/total_pairs
    return auc

ROC曲线和P-R曲线的区别
P-R曲线是以precision作为纵坐标, recall作为横坐标绘制的曲线图。
当测试集中的负样本数量增加是,P-R曲线会发生明显的变化, ROC曲线形状基本不变:
在这里插入图片描述

3. F1 评价指标

F 1 = 2 1 /  precision  + 1 /  recall  \mathrm{F}_1=\frac{2}{1 / \text { precision }+1 / \text { recall }} F1=1/ precision +1/ recall 2

或者写成:
F 1 = N − T N N + T P − T N F_1 = \frac{N- TN}{N + TP - TN} F1=N+TPTNNTN

其中, N 为总样本个数.

实际中,为了遍历找出使 F 1 F_1 F1最大的阈值(模型预测的概率,常规是大于0.5预测为pos.)。

import numpy as np

def f1_smart(y_true, y_pred):
    '''
    f1 = 2*P*R/(P + R);
    P = TP/(TP + FP)
    R = TP/(TP + FN)'''
    args = np.argsort(y_pred)
    tp = y_true.sum()
    fs = (tp - np.cumsum(y_true[args[:-1]])) / np.arange(y_true.shape[0] + tp - 1, tp, -1)
    res_idx = np.argmax(fs)
    return 2 * fs[res_idx], (y_pred[args[res_idx]] + y_pred[args[res_idx + 1]]) / 2

y_true = np.array([1, 1, 0, 0,0])
y_pred = np.array([0.2, 0.3, 0.5, 0.1, 0.1])
f1, threshold = f1_smart(y_true, y_pred)

类似的找最佳阈值的方法有,

def threshold_search(y_true, y_proba):
    best_threshold = 0
    best_score = 0
    for threshold in tqdm([i * 0.01 for i in range(100)], disable=True):
        score = f1_score(y_true=y_true, y_pred=y_proba > threshold)
        if score > best_score:
            best_threshold = threshold
            best_score = score
    search_result = {'threshold': best_threshold, 'f1': best_score}
    return search_result

4. Averaging

首先,F1 , ROC, AUC这里都是二分类评估指标,但是,也可以应用于多分类。
比如,在三分类中,可以对每个类别进行计算它的精确度 P,召回率R,然后平均(macro-averaging)。
或者,我们把这三个类别各自的二分类TN、TP、FN、FP计算出来,最后才求 PR(micro-averaging)。

宏平均Macro-averaging:
宏平均是所有类别每一个统计指标的算术平均值。
宏精度、宏召回率R_macro 、宏F值分别定义如下。

P macro = 1 n ∑ i = 1 n P i P_{\text {macro}}=\frac{1}{n} \sum_{i=1}^{n} P_{i} Pmacro=n1i=1nPi

R macro = 1 n ∑ i = 1 n R i R_{\text {macro}}=\frac{1}{n} \sum_{i=1}^{n} R_{i} Rmacro=n1i=1nRi

F macro = 2 × P macro × R macro P macro + R macro F_{\text {macro}}=\frac{2 \times P_{\text {macro}} \times R_{\text {macro}}}{P_{\text {macro}}+R_{\text {macro}}} Fmacro=Pmacro+Rmacro2×Pmacro×Rmacro

微平均micro-averaging:
对每一个类别进行混淆矩阵统计。

微平均(Micro-averaging)是对数据集中的每一个示例不分类别进行统计建立全局混淆矩阵,然后计算相应的指标。其计算公式如下:
P micro = T P ‾ T P ‾ + F P ‾ = ∑ i = 1 n T P i ∑ i = 1 n T P i + ∑ i = 1 n F P i R micro = T P ‾ T P + F N ‾ = ∑ i = 1 n T P i ∑ i = 1 n T P i + ∑ i = 1 n F N i F micro = 2 × P micro  × R micro  P micro  + R micro  \begin{aligned} P_{\text {micro}} &=\frac{T \overline{P}}{T \overline{P}+\overline{F P}}=\frac{\sum_{i=1}^{n} T P_{i}}{\sum_{i=1}^{n} T P_{i}+\sum_{i=1}^{n} F P_{i}} \\ R_{\text {micro}} &=\frac{\overline{T P}}{T P+F \overline{N}}=\frac{\sum_{i=1}^{n} T P_{i}}{\sum_{i=1}^{n} T P_{i}+\sum_{i=1}^{n} F N_{i}} \\ F_{\text {micro}} &=\frac{2 \times P_{\text {micro }} \times R_{\text {micro }}}{P_{\text {micro }}+R_{\text {micro }}} \end{aligned} PmicroRmicroFmicro=TP+FPTP=i=1nTPi+i=1nFPii=1nTPi=TP+FNTP=i=1nTPi+i=1nFNii=1nTPi=Pmicro +Rmicro 2×Pmicro ×Rmicro 

区别:
宏平均把所有的类别平等对待,导致宏平均偏向于反映数量小的类别分类情况;
微平均把所有样本决策平等对待,导致微平均偏向于反映数量多的类别的评判。
如果类别均衡的情况下,使用两个评价指标都可以。

5. 混淆矩阵

混淆矩阵是把一个包含评估指标precision 、recall 、f1-score 值的矩阵。

import numpy as np
from sklearn.metrics import classification_report, \
confusion_matrix


ref = np.array([1,1,2,2,3,3])

pred = np.array([1,2,2,3,3,1])

report = classification_report(ref, pred, digits=4)
print("report", report)
conf_mat = confusion_matrix(ref, pred)
print("Accuracy", np.sum(np.diag(conf_mat))/len(ref))

这里,利用classification_report可以把精确度P, 召回率 RF1计算出来。
而 准确率 Accuracy,需要计算混淆矩阵的对角元素个数和(TPFN)与元素总个数之比。

report              precision    recall  f1-score   support

          1     0.5000    0.5000    0.5000         2
          2     0.5000    0.5000    0.5000         2
          3     0.5000    0.5000    0.5000         2

avg / total     0.5000    0.5000    0.5000         6

Accuracy 0.5

6. MAPE

在实际中,RMSE损失虽然能够刻画回归预测值和真实值的偏离度,但是,如果存在离群点,rmse指标会很差。
MAPE是比RMSE更加鲁棒的指标。

mape, mean absolute percent error, 平均绝对百分比误差。
在这里插入图片描述
where At is the actual value and Ft is the forecast value.

相比与RMSE, MAPE相当于把每个点的误差进行了归一化,降低了个别离群点带来的绝对误差的影响。

from sklearn.utils import check_arrays
def mean_absolute_percentage_error(y_true, y_pred): 
    y_true, y_pred = check_arrays(y_true, y_pred)

    ## Note: does not handle mix 1d representation
    #if _is_1d(y_true): 
    #    y_true, y_pred = _check_1d_array(y_true, y_pred)

    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

7. SMAPE

SMAPE是对MAPE进行了修正, 对称的平均绝对百分比误差。

如果真实数值本身很小的话,预测偏差一点百分比就会差很多。
在这里插入图片描述
where At is the actual value and Ft is the forecast value.

实现:

def smape(A, F):
    return 100/len(A) * sum(2 * abs(F - A) / (abs(A) + abs(F)))

最近开通了个公众号,主要分享推荐系统,风控等算法相关的内容,感兴趣的伙伴可以关注下。
在这里插入图片描述


reference:

  1. blog 非常好解释AUC
  2. csdn blog 分类指标
  3. csdn blog 分类器的性能评价指标
  4. zhihu【机器学习理论】分类问题中常用的性能评估指标;
  5. csdn blog多类别分类问题由 confusion matrix 到分类准确率(accuracy)的计算;
  6. csdn blog【scikit-learn】评估分类器性能的度量,像混淆矩阵、ROC、AUC等;
  7. Mean absolute percentage error;
  8. MAPE实现
  9. AUC详解与python实现;
  10. 百面机器学习;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rosefunR

你的赞赏是我创作的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值