算法模型的性能度量

2020-03-19  本文已影响0人  巴拉巴拉_9515

性能度量是指模型泛化能力的衡量,泛化能力可以理解为对于未知数据的预判能力

1、回归场景

(1)均方误差MSE

回归预测最常用的性能度量是“均方误差”(MSE mean squared error), 又称为L2范数损失。
预测值与实际值的差值平方求和求平均的过程

E(f,D) = \frac{1}{m}\sum_{i=1}^m(f(x_i)-y_i)^2

实践测试
调用python的sklearn快速计算一下。显然y_pred_2的预测效果比y_pred_1效果好,与y_true更接近。

from sklearn.metrics import mean_squared_error
y_true = [3000,1323,4234,6567]
y_pred_1 = [4212,2000,5002,6004]
y_pred_2 = [4124,1252,4341,6534]
print(mean_squared_error(y_true,y_pred_1))  # 708516.5
print(mean_squared_error(y_true,y_pred_2))  # 320238.75

看来MSE值越小说明预测能力越好(其实看公式也能看出来的)

(2)RMSE

提到均方误差(MSE,mean squared error)就不能不说说均方根误差(RMSE,root mean squared error)
RMSE = \sqrt{MSE}

两者有什么差异吗?说是RMSE消除了对量纲的影响。

import numpy as np
print(np.sqrt(mean_squared_error(y_true,y_pred_1)))  # 841.7342217113428
print(np.sqrt(mean_squared_error(y_true,y_pred_2)))  # 565.8964127824102

算法评估为什么要消除量纲?误差相关值不是越小就可以了吗?而且做完根号以后值还是很大的啊?不多运行比较几次都不知道拟合效果好不好?(解答待定)

(3)R^2

R²(亦称可决系数、确定系数),取值范围在0-1之间,值越大模型的越好。

from sklearn.metrics import r2_score
y_true = [3000,1323,4234,6567]
y_pred_1 = [4212,2000,5002,6004]
y_pred_2 = [4124,1252,4341,6534]
r2_score(y_true, y_pred_1)  # 0.8061345958233034
r2_score(y_true, y_pred_2)  # 0.9123757672520116

既然R2那么好用,但实际上我们比较常见的还是mse、rmse这类性能度量指标,R2有什么局限吗?(解答待定)

2、分类场景

(1)错误率和精度

错误率(error rate) = 分类错误数a/总数m
精度(accuracy) = 分类正确数1-a/总数m

# 分为5类:0,1,2,3,4
from sklearn.metrics import accuracy_score
y_true = [0, 2, 1, 3,4,4,3,1,0]
y_pred = [1, 2, 1, 4,2,4,3,2,0]  # 4个分错
accuracy_score(y_true, y_pred)  # 0.55555556
(2)TP、FP、TN、FN
预测正例 预测反例
实际正例 TP(true positive) FN(false negative)
实际反例 FP(false positive) TN(true negative)

在TP、FP、TN、FN做文章的相关性能度量有:查准率precision、查全率recall、P-R曲线、ROC曲线、F1

(3)查准率与查全率

查准率又叫准确率,查全率又叫召回率。

查准率(准确率)precision = \frac{TP}{TP+FP},指所有预测为正例的数据中,真正例所占的比例(越大越好)
查全率(召回率)recall = \frac{TP}{TP+FN},指预测为正例的数据占所有真正例数据的比例(越大越好)

from sklearn import metrics
y_true =  [0, 1, 1, 0,0,1,0,1,0,0,0,0,1,0,0,0,1]
y_pred = [0, 0, 0, 0,0,1,0,1,0,0,0,0,0,0,1,0,1]
metrics.precision_score(y_true, y_pred, average='binary')  # 0.75
metrics.recall_score(y_true, y_pred, average='binary')  # 0.5

在准确率和召回率的基础上扩建的概念有P-R曲线F1两个概念,与P-R曲线类似的有ROC曲线

(4)P-R曲线

以precision为纵轴,recall为横轴绘制P-R曲线,一般用于模型选择和参数调优。

【疑问】上面计算precision和recall不是都只有一个值吗?怎么能绘制曲线?
算法对样本进行分类时,都会有阈值(threshold),我们一般设置阈值为0.5,如果预测为1的概率大于0.5,则判断分类结果为1,否则分类为0。
通过调节阈值,改变预测正例的数量,从而改变precision和recall的值。详细案例可参考P-R曲线过程如何理解一文

【参数调优】因此P-R权限调优的参数是这个“阈值”threshold,选择使P-R曲线面积最大的阈值。

【模型选择】根据面积与BEP选择最优模型

1)例如模型C的P-R曲线完全被A,B包裹,显然AB模型对于该样本更合适。
2)对于P-R曲线相交的情况,我们比较曲线的平衡点(Break-Event Point, BEP),是准确率与召回率一致时的得分,显然A模型在该样本上优于B模型。


(5)F1

F1是precision和recall的调和平均,同时兼顾了分类模型的精确率和召回率,取值范围在0-1之间,当然还是越大越好。
\frac{1}{F1} = \frac{1}{2}(\frac{1}{P} + \frac{1}{R})

# P = 0.75; R = 0.5
metrics.f1_score(y_true, y_pred, average='binary')  # 0.6
(6)ROC曲线

基本原理与P-R曲线相似,也是通过改变阈值threshold来获得横轴与纵轴值的变更,主要在于横轴与纵轴的变化。

【纵轴】纵轴为真正例率(TPR,True positive rate,真阳率)
TPR = \frac{TP}{TP+FN}
可以发现Recall = TPR(当然P-R曲线纵轴是P,横轴是R),这里TPR为纵轴。真正例率,越大越好。

【横轴】横轴为假正例率(FPR,False positive rate,假阳率)
FPR = \frac{FP}{TN+FP}
假正例率,当然是值越小越好

【ROC曲线】

怎样理解ROC曲线呢?先来看一下四个顶点(0,0),(0,1),(1,0),(1,1)
(0,0),FPR=0,TPR=0,即TP=0,FP=0,实际为正例的预测为反例,实际为反例的也全预测为反例,即该模型对正例的预测无效。
(0,1),FPR=0,TPR=1,即FP=0,FN=0,那就是实际为正例的全部预测为正例,实际为反例的全部预测为反例,最完美的模式。
(1,0),FPR=1,TPR=0,即TN=0,TP=0,不管正例反例都没判断对
(1,1),FPR=1,TPR=1,即TN=0,FN=0,实际为正例的预测为正例,实际为反例的也全预测为正例,即该模型对反例的预测无效。

使用AUC(Area Under ROC Curve)描述曲面下的面积,AUC值越大表示模型的预测能力越好。

三、多分类场景

对于多分类场景,可以使用哪些性能衡量指标呢?

性能度量指标 描述 是否适用多分类
accuracy 预测正确/总量 yes
error 预测错误/总量 yes
precision 转型升级 yes
recall 转型升级 yes
F1 转型升级 yes
ROC 转型升级 yes

多分类问题除了accuracy和error的衡量外,也有precision、recall、F1的度量,不过需要做个转型升级。

(1)macro宏

先计算出每个分类的precision、recall、F1,然后计算平均值,作为该模型对多分类的macro-P、macro-R、macro-F1。

结合代码按步骤进行计算

计算案例的macro-P、macro-R、macro-F1
1、把目标类设置为1,其他为0,模拟每个类的二分类场景
2、计算每个类的P、R、F1
3、macro-P、macro-R、macro-F1为均值
具体代码参见附录macro-P、macro-R、macro-F1,计算结果为macro-P = 0.6389,macro-R= 0.5633、macro-F1=0.5790

from sklearn.metrics import confusion_matrix
from sklearn.metrics import precision_score,recall_score,f1_score
y_true = [0, 2, 1, 3,4,4,3,1,0,0,0,1,1,2,3,2,2,4,2,1]
y_pred = [1, 2, 1, 4,2,4,3,2,0,0,0,1,2,3,2,2,2,2,2,1]
confusion_matrix(y_true,y_pred)
precision_score(y_true,y_pred,labels=[0,1,2,3,4],average='macro')  # 0.638888888888889
recall_score(y_true,y_pred,labels=[0,1,2,3,4],average='macro')  # 0.5633333333333335
f1_score(y_true,y_pred,labels=[0,1,2,3,4],average='macro')  # 0.5790476190476189

和直接调用sklearn结果是一样的。

(2)micro微

先计算出每个分类的TP,TN,FP,FN,然后获得TP,TN,FP,FN的平均值,带入precision、recall、F1的计算公式即可获得micro-P、micro-R、micro-F1

结合代码按步骤进行计算

计算案例的micro-P、micro-R、micro-F1
1、把目标类设置为1,其他为0,模拟每个类的二分类场景
2、计算每个类的TP,TN,FP,FN
3、计算每个类的TP,TN,FP,FN均值
4、带入公式,计算micro-P、micro-R、micro-F1
具体代码参见附录macro-P、macro-R、macro-F1,计算结果为micro-P = 0.6,micro-R= 0.6、micro-F1=0.6,与直接调用sklearn计算结果一致

# micro微
precision_score(y_true,y_pred,labels=[0,1,2,3,4],average='micro')
recall_score(y_true,y_pred,labels=[0,1,2,3,4],average='micro')
f1_score(y_true,y_pred,labels=[0,1,2,3,4],average='micro')
(3)多分类的ROC曲线

多分类问题可以把目标类设置为1,其他为0,模拟每个类的二分类场景。

但感觉多分类的roc曲线用起来一点也不方便,不像二分类的ROC一个函数解决,有点麻烦不是很想用

【问题】

四、聚类场景

聚类算法的性能衡量指标是什么?不像有监督学习那样可以根据标签计算accuracy、error等值。
聚类是将样本划分为若干互不相交的子集,簇内相似度高,簇间相似度低。聚类的性能度量指标分为外部指标和内部指标

聚类性能度量 指标名称
外部指标 jaccard系数(jaccard coefficient,JC)
FM指数(fowlkes and Mallows Index, FMI)
Rand指数(Rand Index, RI)
内部指标 DB指数
Dunn指数

详细性能度量指标可以参考聚类性能度量和距离计算一文。

参考资料

[1]《机器学习》周志华
[2] P-R曲线过程如何理解:https://www.zhihu.com/question/348073311/answer/837781413
[3] 聚类的性能度量:https://blog.csdn.net/qq_36396104/article/details/78166317

附录

1、precision与recall的计算

import numpy as np
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
y_true =  [0, 1, 1, 0,0,1,0,1,0,0,0,0,1,0,0,0,1]
y_pred = [0, 0, 0, 0,0,1,0,1,0,0,0,0,0,0,1,0,1]
accuracy_score(y_true, y_pred)
confusion_matrix(y_true,y_pred)
# 判断为1实际也为1
TP = np.sum(np.logical_and(np.equal(y_true,1),np.equal(y_pred,1)))
# 判断为0实际也为0
TN = np.sum(np.logical_and(np.equal(y_true,0),np.equal(y_pred,0)))
# 判断为1实际为0
FP = np.sum(np.logical_and(np.equal(y_true,0),np.equal(y_pred,1)))
# 判断为0实际为1
FN = np.sum(np.logical_and(np.equal(y_true,1),np.equal(y_pred,0)))
precision = TP/(TP+FP)  # 0.75
recall = TP/(TP+FN)  # 0.5

2、macro-P、macro-R、macro-F1

# 数据处理:把目标类设置为1,其他为0,模拟该类的二分类
def deal_list(y,labels):
    new_list = []
    for i in y:
        if i==labels:
            new_list.append(1)
        else:
            new_list.append(0)
    return new_list

# 计算目标类的P、R、F1
def count_p_r_f1(y_true,y_pred,labels):
    new_true = deal_list(y_true,labels)
    new_pred = deal_list(y_pred,labels)
    a = precision_score(new_true, new_pred, average='binary')
    b = recall_score(new_true, new_pred, average='binary')
    c = f1_score(new_true, new_pred, average='binary')
    return a,b,c

y_true = [0, 2, 1, 3,4,4,3,1,0,0,0,1,1,2,3,2,2,4,2,1]
y_pred = [1, 2, 1, 4,2,4,3,2,0,0,0,1,2,3,2,2,2,2,2,1]
p_score = []
r_score = []
f1 = []
for i in range(5):
    a,b,c = count_p_r_f1(y_true,y_pred,i)
    p_score.append(a)
    r_score.append(b)
    f1.append(c)

# 计算macro-P,macro-R,macro-F1
def count_mean(score_list):
    s = sum(score_list)/len(score_list)
    return s
count_mean(p_score)  # 0.638888888888889
count_mean(r_score)  # 0.5633333333333335
count_mean(f1)  # 0.5790476190476189

3、 计算micro-P,micro-R,micro-F1

import numpy as np
def count_tp_tn_fp_fn(new_true,new_pred):
    # 判断为1实际也为1
    TP = np.sum(np.logical_and(np.equal(new_true,1),np.equal(new_pred,1)))
    # 判断为0实际也为0
    TN = np.sum(np.logical_and(np.equal(new_true,0),np.equal(new_pred,0)))
    # 判断为1实际为0
    FP = np.sum(np.logical_and(np.equal(new_true,0),np.equal(new_pred,1)))
    # 判断为0实际为1
    FN = np.sum(np.logical_and(np.equal(new_true,1),np.equal(new_pred,0)))
    return TP,TN,FP,FN

y_true = [0, 2, 1, 3,4,4,3,1,0,0,0,1,1,2,3,2,2,4,2,1]
y_pred = [1, 2, 1, 4,2,4,3,2,0,0,0,1,2,3,2,2,2,2,2,1]
TP_list,TN_list,FP_list,FN_list = [],[],[],[]
for i in range(5):
    new_true = deal_list(y_true,i)
    new_pred = deal_list(y_pred,i)
    TP,TN,FP,FN = count_tp_tn_fp_fn(new_true,new_pred)
    TP_list.append(TP)
    TN_list.append(TN)
    FP_list.append(FP)
    FN_list.append(FN)

TP_mean = count_mean(TP_list)
TN_mean = count_mean(TN_list)
FP_mean = count_mean(FP_list)
FN_mean = count_mean(FN_list)

precision = TP_mean/(TP_mean+FP_mean)  # 0.6
recall = TP_mean/(TP_mean+FN_mean)  # 0.6
f1 = 2*precision*recall/(precision+recall)  # 0.6
上一篇下一篇

猜你喜欢

热点阅读