机器学习模型评估指标

机器学习模型评估指标

机器学习模型的评估指标汇总
分类模型和回归模型的评估指标
各评估指标简单例子说明
对应各指标的python样例脚本

实际应用中,评估指标依具体问题灵活使用,在选择模型和调整参数过程中选择正确的指标十分重要。模型评估目标应以业务目标为导向,选择最合适的评估指标。

无论选择哪个指标,对机器学习应用的最终目标需要明确清晰。实践中,我们通常不仅仅要做出正确的预测,而且需要将这些预测作为更大决策过程中的部分。在选择一个机器学习指标前,我们需要思考清楚应用目标,即业务指标。为机器学习应用选择特定算法的结果就是业务影响。当选择一个模型或调整指标时,应该使其最大化正面影响业务指标。对特定模型商务影响的评估需要结合其应用在实际生产环境中具体情况。

当讨论预测模型时,往往既指回归模型也指分类模型,不过每类模型的衡量指标有所不同。对分类模型,通常会输出类别结果(如SVM、KNN等)和概率结果(如LR、RF、GBDT)。而对回归模型通常输出连续值。

评估方法,如交叉检验cross validation、留出法hold-out、自助法bootstrapping以及损失函数、正则化等,再另汇总。

分类模型评估指标

可从混淆矩阵Confusion Matrix说起。对于二分类问题,一个样本只能是0或1两种类别,当用一个分类器进行类别的概率预测时,对于真实为0的样本,我们可能预测其为0或1;真实为1的样本,我们也可能预测其为1或0,这样的四种可能性:

  • 真实为1,预测为1,True Positive
  • 真实为0,预测为0,True Negative
  • 真实为0,预测为1,False Positive
  • 真实为1,预测为0,False Negative

真实1

真实0

预测1

True Positive样本数量为TP

False Positive样本数量为FP

预测0

False Negative样本数量为FN

True Negative样本数量为TN

基于Confusion Matrix,我们讨论准确率和错误率Accuracy & Error rate、查全率和查准率Recall & Precision,以及F1值和误检率和漏检率FPR & FNR等。

350px-Sensitivity_and_specificity.svg.png

机器学习的时候会将学习样例(example)分为正例(positive)和反例(negative)。当你训练一个分类器后,进行测试。对于正例,分类器可能正确的将其分类为正例,也可能错误的拒绝了这个样例,对于反例也是一样。

false-positive rate 是分类器将正例错误的分类为反例的数量与正例数量的比值,这类错误称为第一类错误,或是alpha错误。而 false-negative rate是分类器将反例错误的分类为正例的数量与反例数量的比值,这类错误称为第二类错误,或是beta错误。举个具体的例子:没病看成有病,第一类错误,有病看成没病,第二类错误。

假设我们有 2000个人脸的图片和 4000个非人脸的图片。训练一个分类器进行测试。分类器将2000个人脸图片中的1980个图片都分到了人脸一类,还有20个人脸图片被分错了;将 4000个非人脸图片中的3000个都分到了非人脸类中,但是剩下的1000个都分错了。那么false-positive rate= 20/2000 =1%而false-negative rate=1000/4000=25%

False positive paradox,这是false positive比true positive更可能发生的统计结果

准确率&错误率

Accuracy vs. Error rate

  • 准确(分类)率Accuracy rate = /frac{TP+TN}{TP+FN+FP+TN} ,正确预测的样本数量占样本总量的比例
  • 错误(分类)率Error rate = 1 – Accuracy rate = /frac{FN+FP}{TP+FN+FP+TN},错误预测的样本数量占样本总量的比例

准确分类率和错误分类率不能满足所有任务需求,比如错误率衡量了有多少比例的病人被判断错误,但若我们关心的是所有有病的患者中有多少比例的被检测出来,那么错误率显然不够用了,这时需要使用查全率。

我们用python中skit-learn库中的metrics为例,展示如何用python代码计算指标:

 import numpy as np
 from sklearn.metrics import accuracy_score
 y_pred = [0, 2, 1, 3]  #一共有四个样本,模型输出每个样本的预测类别结果
 y_true = [0, 1, 2, 3]  #四个样本真实的标签
 accuracy_score(y_true, y_pred) # 调用skit-learn中实现的函数
 
 0.5 #返回预测的准确率,在上例中第一个样本和第四个样本预测正确,准确率为50% 
 错误率:
 1-accuracy_score(y_true, y_pred)
 0.5

分类准确性即为所有预测中正确预测的比率。这是对分类问题最通用的衡量指标,也是最容易误用的。只有当各类别的数量均等时、且所有预测和预测误差同等重要时才适合使用,而这种情况的问题较少。举例

# Cross Validation Classification Accuracy
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7

kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LogisticRegression()
scoring = 'accuracy'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)
print(("Accuracy: %.3f (%.3f)") % (results.mean(), results.std()))
# print("Accuracy: {0:.3f} ({1:.3f})".format(results.mean(), results.std()))

查全率&查准率

Recall vs. Precision (对正例)

  • 查全率Recall R = /frac{TP}{TP+FN},覆盖率=正确预测到的正例个数/实际正例总数
  • 查准率Precision P = /frac{TP}{TP+FP},命中率=正确预测到的正例个数/预测正例总数

查全率Recall,又称Sensitivity、True positive rate,刻画的是分类器所识别出的正实例占所有正实例的比例,反映正类覆盖程度,Sensitivity越大,说明“得病的被判断为得病的”越大,“漏检”(FN)越小。查准率Precision,又称Positive predicted value、PV+ (对正例)。

某池塘有1400条鱼,300只虾,300只鳖。现在以捕鲤鱼为目的。撒一大网,逮着了700条鱼,200只虾,100只鳖。那么,这些指标分别如下:
  正确率 = 700 / (700 + 200 + 100) = 70%
  召回率 = 700 / 1400 = 50%
  F1值 = 70% * 50% * 2 / (70% + 50%) = 58.3%

  不妨看看如果把池子里的所有的鱼、虾和鳖都一网打尽,这些指标又有何变化:
  正确率 = 1400 / (1400 + 300 + 300) = 70%
  召回率 = 1400 / 1400 = 100%
  F1值 = 70% * 100% * 2 / (70% + 100%) = 82.35%
  
  由此可见,正确率是评估捕获的成果中目标成果所占得比例;召回率,顾名思义,就是从关注领域中,召回目标类别的比例;而F值,则是综合这二者指标的评估指标,用于综合反映整体的指标。

  当然希望检索结果Precision越高越好,同时Recall也越高越好,但事实上这两者在某些情况下有矛盾的。比如极端情况下,我们只搜索出了一个结果,且是准确的,那么Precision就是100%,但是Recall就很低;而如果我们把所有结果都返回,那么比如Recall是100%,但是Precision就会很低。因此在不同的场合中需要自己判断希望Precision比较高或是Recall比较高。如果是做实验研究,可以绘制Precision-Recall曲线来帮助分析。
from sklearn.metrics import recall_score
y_pred = [0, 1, 1, 1]  #一共有四个样本,模型输出每个样本的预测类别结果
y_true = [0, 1, 1, 0]  #四个样本真实的标签

recall_score(y_true, y_pred)  
1.0 #召回率 100%, 因为所有的正例都被找到了


precision_score(y_true, y_pred)  
0.6666666666666666 # precision为2/3, 因为TP=2,TP+FP=3

F1值

F1 Score

综合考虑precision和sensitivity会使用指标F1值F1 = /frac{2TP}{2TP+FN+FP}

F1 = /frac{2/cdot P/cdot R}{P + R}=/frac{2/cdot TP}{Total+TP-TN}=/frac{2TP}{2TP+FN+FP}

  • F1为基于查全率和查准率的调和平均:/frac{1}{F1}=/frac{1}{2}(/frac{1}{P}+/frac{1}{R})
  • 在一些应用中,对查准率和查全率的重视程度有所不同。如在推荐系统中,为了尽可能少打扰用户,更希望推荐内容确是用户感兴趣的,此时查准率更重要;而在逃犯信息检索中,更希望尽可能少漏掉逃犯,此时查全率更重要;
  • F1的一般形式F_/beta = /frac{(1+/beta^2)PR}{/beta^2P + R},其中/beta>0表示查全率对查准率的相对重要性
    /beta<1时查准率有更大影响
    /beta>1时查全率有更大影响
    /beta=1时退化为标准的F1
 from sklearn.metrics import f1_score
 y_pred = [0, 1, 1, 1]  #一共有四个样本,模型输出每个样本的预测类别结果
 y_true = [0, 1, 1, 0]  #四个样本真实的标签
 f1_score(y_true, y_pred, average='macro')  
 0.8  # 上面提到这个例子中recall为1,precision为2/3.那么F1= (2*1*2/3)/(1+2/3)=0.8

负例查全率&负例查准率

Specificity vs. PV- (对负例)

  • 负例查全率Specificity = /frac{TN}{FP+TN},负例的覆盖率=正确预测到的负例个数/实际负例总数
  • 负例查准率Negative predictive value = /frac{TN}{FN+TN} ,负例的命中率=正确预测到的负例个数/预测负例总数

负例的覆盖率Specificity,又称True negative rate真负类率,Specificity越大,说明“健康的被判断为健康的”越大,“误检”(FP)越小。负例的命中率Negative predicted value又称PV-。

import numpy as np
from imblearn.metrics import sensitivity_specificity_support
y_true = np.array(['cat', 'dog', 'pig', 'cat', 'dog', 'pig'])
y_pred = np.array(['cat', 'pig', 'dog', 'cat', 'cat', 'dog'])
sensitivity_specificity_support(y_true, y_pred, average='macro')

误检率&漏检率

FP vs. FN

  • False positive rate = /frac{FP}{FP+TN},刻画的是分类器错认为正类的负实例占所有负实例的比例,误检
  • False negative rate = /frac{FN}{TP+FN} ,刻画的是分类器错认为负类的正实例占所有正实例的比例,漏检

Macro & Micro Measure

  • 很多时候我们有多个二分类混淆矩阵,例如进行多次训练或者在多个数据集上进行训练,此时我们希望计算出全局性能,综合考虑 n 个混淆矩阵上的 Precision 和 Recall
  • 方法 1:先在各混淆矩阵上分别计算 P 和 R,在计算平均值,这样就得到 macro-P、macro-R 和 macro-F1

在skit-learn中,只要在相应的函数中指定"macro"参数即可:


from sklearn.metrics import f1_score

from sklearn.metrics import recall_score

from sklearn.metrics import precision_score

y_true = 0, 1, 2, 0, 1, 2 # 模型预测的结果

y_pred = 0, 2, 1, 0, 0, 1 # 标签

f1_score(y_true, y_pred, average='macro') # 计算f1,采用macro方式

0.26666666666666666

recall_score(y_true, y_pred, average='macro') # 计算recall

0.3333333333333333 # macro-R为1/3

precision_score(y_true, y_pred, average='macro') # 计算precision

0.2222222222222222


  • 方法 2:先将各混淆矩阵的对应元素进行平均,再基于这些平均值计算得到 micro-P、micro-R 和 micro-F1

在python中需要计算该指标时,只需要类似方法1中,将average='macro' 改为average = 'micro'即可。

Log-Loss对数损失

以logistic regression模型为例,logloss实际上就是log likelihood的相反数。似然函数越大,logloss自然就越小。logloss和熵有着一样的数学表达式。

logistic regression的损失函数是怎么来的?为什么定义成logloss?

/text{logloss} = -/frac{1}{n}/sum_{i=1}^n (y_i /log p_i+(1-y_i)/log(1-p_i))

logistic regression的loss function是根据logistic regression本身式子中系数的最大似然估计推导出的,logistic regression式子:

Pr(y_i = 1) = /frac{1}{1+e^{-(/theta_0+/theta_1 x_i)}}

可以写出logistic regression中/theta_0/theta_1的似然函数:

L(/theta_0,/theta_1)=/prod_{i=1}^n p(Y=y_i | X=x_i)=/prod_{i=1}^n p(x_i)^{y_i}(1-p(x_i))^{1-y_i}

其中(x_i, y_i)表示训练集中的每一个样本点。我们对似然函数取对数,可得:

/log L(/theta_0, /theta_1)=/sum_{i=1}^n(y_i /log(p(x_i))+(1-y_i)/log(1-p(x_i)))

我们希望上式越大越好,换句话说,对于给定样本数量n,我们希望-/frac{1}{n}/log L(/theta_0, /theta_1)越小越好,这个也就是logloss。

/text{logloss} = -/frac{1}{n}/sum_{i=1}^n (y_i/log(p(x_i))+(1-y_i)/log(1-p(x_i)))

所以说logistic regression的损失函数不是定义出来的,而是更具最大似然估计推导出来的。

我们同样可以将Logloss扩展到多分类问题中:

在多分类问题中,logloss的计算公式为:

LogLoss= – /frac{1}{N}/sum_{i=1}^{N}/sum_{j=1}^{M}{y_{ij}} log(p_{ij})

这个公式中的各个字母含义为:

  • N:样本数
  • M:类别数,二分类中M=2,多分类问题中M大于2.
  • y_{ij}:第i个样本属于分类j时为为1,否则为0
  • p_{ij}:第i个样本被预测为第j类的概率

logloss用来衡量给定类别的概率预测指标。0到1之间的标量值可被看做是算法预测信度的测量。预测正确被奖励、预测错误被惩罚,均与预测信度成比例。计算Pima Indians onset of diabetes的方法为

# Cross Validation Classification LogLoss
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7

kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LogisticRegression()
scoring = 'neg_log_loss'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)

# print("Logloss: %.3f (%.3f)") % (results.mean(), results.std())
print("Logloss: {0:.3f} ({1:.3f})".format(results.mean(), results.std()))

较小的logloss表示更好的效果。

举另一个简单例子:

from sklearn.metrics import log_loss
log_loss(["spam", "ham", "ham", "spam"],   #y_true,样本的标签
        [[.1, .9], [.9, .1], [.8, .2], [.35, .65]])# y_pred,每个样本属于各个类别的概率
0.21616187468057912

参考文献

http://sofasofa.io/forum_main_post.php?postid=1000352

http://blog.csdn.net/v_july_v/article/details/40508465

ROC&AUC

ROC曲线的纵轴是真正例率TPR=TP/(TP+FN),横轴是假正例率FPR=FP/(FP+TN),ROC曲线越远离对角线,模型效果越好,ROC曲线下的区域面积即为AUC值,AUC值越接近1模型效果越好。

在一个二分类模型中,对于所得到的连续结果,假设已确定一个阀值,比如说0.6,大于这个值的实例划归为正类,小于这个值则划到负类中。如果减小阀值,减到0.5,固然能识别出更多的正类,也就是提高了识别出的正例占所有正例的比类,即查全率Recall、TPR,但同时也将更多的负实例当作了正实例,即提高了FPR(减少了Specificity负例覆盖率减小)。为了形象化这一变化,在此引入ROC。

以上我们求覆盖率等指标时需要指定一个阈值(threshold)。同样,我们看到针对不同的阈值,而产生的相应的覆盖率。我们还可以看到,随着阈值的减小(更多的用户就会被归为正例),Sensitivity 和 1-Specificity 也相应增加(也即 Specificity 相应减少)。把基于不同的阈值而产生的一系列Sensitivity 和 Specificity 描绘到直角坐标上,就能更清楚地看到它们的对应关系。由于 Sensitivity 和 Specificity 的方向刚好相反,我们把Sensitivity 和 1-Specificity 描绘到同一个图中,它们的对应关系,就是传说中的 ROC 曲线,全称是Receiver Operating Characteristic curve,中文叫 “接受者操作特性曲线”。

这里y轴为Sensitivity(覆盖率,True Positive Rate),而x轴为1-Specificity (Specificity, 负例的覆盖率,True Negative Rate)。随着阈值的减小(更多的客户就会被归为正例),Sensitivity 和 1-Specificity 也相应增加(也即 Specificity 相应减少),所以 ROC 呈递增态势(至于ROC曲线凹向原点而非凸向原点,不知道有无直观的解释,不提)。那条 45 度线是作为参照(baseline model)出现的,就是说,ROC 的好坏,乃是跟 45 度线相比的,为什么呢?

如不用模型,根据原始数据分布来随机把客户归为某个类别,那么得到的True positive rate对False positive rate之比应该等于actual positive对actual negative之比,即/frac{A}{C} = /frac{A+B}{C+D}/frac{A}{A+B}/(1-/frac{D}{C+D}) =/frac{A(C+D)}{C(A+B)}=1 。在不使用模型的情况下,Sensitivity 和 1-Specificity 之比恒等于 1,这就是 45 度线的来历。一个模型要有所提升,首先就应该比这个 baseline 表现要好。

在最好的情况下,Sensitivity 为 1(正确预测到的正例就刚好等于实际的正例总数),同时 Specificity 为 1(正确预测到的负例个数就刚好等于实际的负例数),在上图中,就是左上方的点 (0,1)。因此,ROC 曲线越往左上方靠拢,Sensitivity 和 Specificity 就越大,模型的预测效果就越好。同样的思路,你还可以解释为什么 ROC 曲线经过点(0,0) 和(1.1)。

https://cosx.org/2008/12/measure-classification-model-performance-roc-auc/

AUC是对二分类问题的性能指标。AUC代表了模型区分正类和负类能力的区分度。值为1代表模型可以完美预测,值为0.5代表模型和随机预测结果一样。

ROC可以被分解为敏感度和特异度。一个二分类问题就是在敏感度和特异度之间平衡。

  • 敏感度是true positive rate,即召回。也就是在正类里被预测对的实例数量。
  • 特异性是true negative rate,也就是负类里被预测对的实例数量。
# Cross Validation Classification ROC AUC
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7

kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LogisticRegression()
scoring = 'roc_auc'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)

# print("AUC: %.3f (%.3f)") % (results.mean(), results.std())
print("AUC: {0:.3f} ({1:.3f})".format(results.mean(), results.std()))

AUC vs 准确率

关于使用accuracy以及auc的取舍,所以作一些补充。其实auc和accuracy是两个层次的统计量。举个例子,十个病人,判断是否为癌症。classifier做的事情是,把这十个人按照得癌症概率p从高到低进行排队。最高的人排在一号位置,最低的排在十号位置。然后呢,我们提出一个阈值m,如果病人数目是连续变量那m就从0逐渐增大到1,但因为我们只有十个病人,所以就取m逐次为每个病人得病概率p。在这个过程中,每获得一个m,就定义具有大于等于m的p的病人为癌症,小于m的p的病人为健康,此时可以计算这个点的各种统计量,例如sensitivity啊或者你说的acc啊。然而这只是在选定的阈值m下。只有选取了所有m才能把各个点连起来绘制出ruc,从而计算auc。因此auc在目前的classifier评判时,更加具有意义。

换句话说,我们现在有两个模型A和B,对十个病人进行排队。要知道排队本身这个行为并不是一个二分类的过程,仅仅是通过模型计算得到患病概率p然后sort 了一下而已。在这种情况下,acc无法计算,因为阈值m的选择没办法固定在某个常数。当然你可以说,我固定m为0.5,那么确实可以计算在m=0.5条件下的acc,然而这个0.5是否准确或者有意义?难说。因此不选择固定阈值是最佳方法。我们选择所有可能的阈值,即0-1。auc就是涵盖了全部阈值下模型的综合分类能力。因此从这一点来说,评判模型或者说分类器的好坏,就在于评判这个模型让病人排队sort方式的本事有多大。

P-R曲线

PR曲线的纵轴是查准率Precision=TP/(TP+FP),横轴是查全率Recall=TP/(TP+FN),PR曲线反映了分类器在识别正例的准确率和覆盖率之间的权衡。

便于理解查全率和查准率,考虑一个资讯推荐的场景,我们想将一则资讯推荐给哪些有可能点击这则资讯的人,于是通过分析模型选了一批人作为推荐对象,请问:

  1. 选的这批人里面,真正会点击的有多少比例?
  2. 这些会点击的人中,占了真正点击的人的比例?(有些不在名单中的人也会点击的)

这个场景中,第一个问题的答案是查准率,第二个问题的答案是查准率。

  • 查准率Precision P = /frac{A}{A+C}=/frac{TP}{TP+FP}
  • 查全率Recall R = /frac{A}{A+B}=/frac{TP}{TP+FN}

一般来说,查准率高时,查全率往往偏低;而查全率高时,查准率往往偏低。如现实场景,当我想要提高查全率(接触更多可能点击的人),就可能使得查准率降低(花费更多的成本来接触更多人);如果想要提升查准率(降低成本),就可能使得查全率降低(只能找比较少的目标对象)。通常只有在一些简单任务中,才可能使查全率和查准率都很高。

  • 左上角时,Precision=1 Recall=0,TP+FP=0即所有的实例被预测为负类,TP=0 FP=0,但FN有值,Precision=1即没有假结果
  • 右下角时,Precision=0 Recall=1,TP+FN=0即在数据中没有正例,TP=0 FN=0,但FP有值,Recall=1所有的TP都被找到

前文有讨论通俗理解AUC指标时提到了ROC曲线,ROC-AUC广泛应用于二分类问题中用来评估分类器的可信度,但是当处理一些高度不均衡的数据集时,P-R曲线能辅助表征出一些信息,帮助发现更多的问题。

在很多情形下,我们可以根据预测结果对样例进行排序,排在最前面的是有可能是正例的样本,排在最后的是最不可能是正例的样本,按此顺序逐个把样本作为正例进行预测,则每次均可计算出一对 Precision 和 Recall,分别以 Precision 和 Recall 为纵轴和横轴,就可以得到“P-R 曲线”

  • 若分类器a的P-R曲线被分类器b的曲线完全包住,则可推断b性能优于a;
  • 若分类器a和b的P-R曲线发生了交叉,只能在具体的查准率和查全率条件下进行比较;
  • 平衡点Break-Even Point(BEP)为查全率=查准率时的取值,值越大性能越优;
  • 比较P-R曲线下的面积大小,在一定程度上表征分类器在查准率和查全率上取得双高的比例。

参考文献

Lift Chart

简而言之,Lift实际上计算的是/frac {查全率}{正样本比例}。Lift提升曲线的纵轴是lift值,横轴是预测正例占比。Lift提升曲线衡量的是,与不利用模型相比,模型的预测能力“变好”了多少。Lift提升指数越大,模型的运行效果越好。

主要关注检测概率的排名排序,第一步计算每项观察的概率,第二步对这些概率值递减排序,第三步分群每组10%的观察,第四步计算每步的反应率

Lift衡量的是,与不利用模型相比,模型的预测能力 “变好” 了多少。不利用模型,我们只能利用 “正例的比例”这个样本信息来估计正例的比例(baseline model),而利用模型之后,我们不需要从整个样本中来挑选正例,只需要从我们预测为正例的那个样本的子集中挑选正例,这时预测的准确率为 TP/(TP+FN)。

显然,Lift(提升指数)越大,模型的运行效果越好。如果这个模型的预测能力跟 baseline model 一样,那么TP/(TP+FN)就等于(TP+FN)/(TP+FN+FP+TN)(lift 等于 1),这个模型就没有任何 “提升” 了(套一句金融市场的话,它的业绩没有跑过市场)。这个概念在数据库营销中非常有用,举个例子:

比如说你要向选定的 1000 人邮寄调查问卷(TP+FN+FP+TN=1000)。以往的经验告诉你大概 20% 的人会把填好的问卷寄回给你,即 1000 人中有 200 人会对你的问卷作出回应(response,TP+FN=200),用统计学的术语,我们说 baseline response rate 是 20%(TP+FN/TP+FN+FP+TN=20%)。

如果你现在就漫天邮寄问卷,1000 份你期望能收回 200 份,这可能达不到一次问卷调查所要求的回收率,比如说工作手册规定邮寄问卷回收率要在 25% 以上。通过以前的问卷调查,你收集了关于问卷采访对象的相关资料,比如说年龄、教育程度之类。利用这些数据,你确定了哪类被访问者对问卷反应积极。假设你已经利用这些过去的数据建立了模型,这个模型把这 1000 人分了类,现在你可以从你的千人名单中挑选出反应最积极的 100 人来(TP+FP=100),这 10% 的人的反应率 (response rate)为 60%(TP/TP+FP=60%,TP=60)。那么,对这 100 人的群体(我们称之为 Top 10%),通过运用我们的模型,相对的提升 (lift value) 就为 60%/20%=3;换句话说,与不运用模型而随机选择相比,运用模型而挑选,效果提升了 3 倍。


from scipy.stats import scoreatpercentile

import seaborn as sns

import matplotlib.pyplot as plt

import pandas as pd

from sklearn.metrics import roc_curve, auc

###result like result'target','proba'# result为两列的DataFrame,第一列为target(样本标签),第二列为probability(模型预测概率)。

def liftcurve(result):

    result.columns = 'target','proba'

    result_ = result.copy()

    proba_copy = result.proba.copy()

    for i in range(10):

        point1 = scoreatpercentile(result_.proba, i*(100/10))

        point2 = scoreatpercentile(result_.proba, (i+1)*(100/10))

        probacopy[(result.proba >= point1) & (result_.proba <= point2)] = ((i+1))

    result_'grade' = proba_copy

    dfgain = result.groupby(by='grade', sort=True).sum()/(len(result)/10)*100

    plt.plot(df_gain'target', color='red')

    for xy in zip(df_gain'target'.reset_index().values):

        plt.annotate("%s" % round(xy0,2), xy=xy0, xytext=(-20, 10), textcoords='offset points')  

    plt.plot(df_gain.index,sum(result'target')_100.0/len(result'target')_len(df_gain.index), color='blue')

    plt.title('Lift Curve')

    plt.xlabel('Decile')

    plt.ylabel('Bad Rate (%)')

    plt.xticks(1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0)

    fig = plt.gcf()

    fig.set_size_inches(10,8)

    plt.savefig("train.png")

    plt.show()


参考文献

https://blog.csdn.net/xw_classmate/article/details/51334422

https://blog.csdn.net/lz_peter/article/details/79296431

Gain Chart

Gain增益与Lift提升类似,Gain曲线纵轴是Precision=TP/(TP+FP),横轴是预测正例占比,与Lift的区别在于纵轴坐标的不同。

                                      ![Gain Chart SPSS](指标汇总.assets/Gain Chart SPSS.PNG)

比如上图中正样本的比例不同时,红线代表随机的情况下预测的precision,而蓝线代表模型得到的结果。

参考文献

https://blog.csdn.net/xw_classmate/article/details/51334422

Kolmogorov Smirnov Chart

K-S曲线x轴是阈值,这里的阈值是指分类时对概率的划分点,比如样本输入给模型后,返回的是一个概率值,对于二分类问题,通常我们会把0.5作为阈值,选取不同的值作为阈值会导致TPR和FPR随之变化。纵轴是TPR和FPR的差值。 K-S曲线实际上是正样本洛伦兹曲线(TPR)与负样本洛伦兹曲线(FPR)的差值曲线,用来度量阳性与阴性分类区分程度,KS值越大,模型从阴性数据中区分阳性数据的能力越强。

K-S曲线的计算步骤如下:

  1. 按照分类模型返回的概率降序排列
  2. 把0-1之间等分N份,等分点为1中返回的概率值作为阈值,计算TPR、FPR
  3. 对TPR、FPR描点画图即可
    KS值即为Max(TPR-FPR)

参考资料:https://blog.csdn.net/wendaomudong_l2d4/article/details/72872206

Gini Coefficient

Gini coefficient 是指绝对公平线(line of equality)和洛伦茨曲线(Lorenz Curve)围成的面积与绝对公平线以下面积的比例,即gini coefficient = A面积 / (A面积+B面积) 。用在评判分类模型的预测效力时,是指ROC曲线曲线和中线围成的面积与中线之上面积的比例。

在机器学习中,图中绿线代表的绝对公平线实际上相当于随机猜测时的分类结果,如果洛伦茨曲线高于绝对公平线,则说明模型的效果好于随机分类的结果。

Concordant – Discordant Ratio

我们用一个例子来解释该评估指标。 假设我们有三个样本A,B,C,模型预测它们为正类的概率分别维0.9,0.5和0.3。 三个样本两两组合共有三种情况(A,B),(A,C)和(B,C)。 而实际上,A和C的真实标签是正类,B则属于负类。

那么包含了通过考试者和未通过考试者的构成的样本对有(A,B)和(B,C)。 对于(A,B)样本对而言, A的预测概率值大于B,实际情况也确实是A属于正类,B属于负类,所以这是一个concordant的样本对,但是(B,C)的情况则相反,所以(B,C)是一个Discordant的样本对。

在这两个样本对中,Concordant的有1个,所以Concordant-Discordant Ratio 为50%。

MCAUC

Mean Columnwise Area Under Receiver Operating Characteristic Curve

MeanUtility

  • Mean consequential error

Mean consequential error又被称为0-1损失。 对于单个样本而言,损失函数为:

L_i(y_i,f(x_i))=/left/{ /begin{aligned}&1,/quad y_i/ne f(x_i)//& 0,/quad y_=f(x_i) /end{aligned} /right.

对所有样本的损失函数值求平均值后即为Mean consequential error的值。
  • Hamming loss

函数hamming_loss()计算两组样本之间的平均汉明损失或汉明距离。如果/hat{y} _j是给定样本的第j个标签的预测值,则y_j是相应的真实值,而n_{labels}是类或标签的数量,则两个样本之间的汉明损失L_{Hamming}定义为:

L_{Hamming}(y, /hat{y}) = /frac{1}{n_/text{labels}} /sum_{j=0}^{n_/text{labels} – 1} 1(/hat{y}_j /neq y_j)

  • Matthews Correlation Coefficient

马修斯相关系数是用于评估二分类问题中机器学习的性能的一种指标。在样本不均衡的情况下能够很好地反映模型的分类能力。

其计算公式为:

MCC=/frac{TP /times TN – FP/times FN}{/sqrt{(TP+FP)(TP+FN)(TN+FP)}}


回归模型评估指标

MAE (Mean Absolute Error)

/text{MAE}=/frac{/sum_{i=1}^n|y_i – /hat{y}_i|}{n}

例如我们预测5个人的收入情况,这五个人的真实收入分别为1K,2K,3K,4K,5K, 模型预测的结果为1.5K,3K,2.5K,3.8K,5.2K, 那么容易计算出预测结果与真实标签之间的绝对差值,再取平均之后即为MAE结果。

(0.5+1+0.5+0.2+0.2)/5=0.48


from sklearn.metrics import mean_absolute_error

y_true = 3, -0.5, 2, 7

y_pred = 2.5, 0.0, 2, 8

mean_absolute_error(y_true, y_pred)


平均绝对误差是预测和真实值之间绝对差值之和。表示预测有多大程度有误。这个指标给出了错误的幅度,但没有给出方向,如高估还是低估。

# Cross Validation Regression MAE
import pandas
from sklearn import model_selection
from sklearn.linear_model import LinearRegression

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data"
names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
dataframe = pandas.read_csv(url, delim_whitespace=True, names=names)
array = dataframe.values
X = array[:,0:13]
Y = array[:,13]
seed = 7

kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LinearRegression()
scoring = 'neg_mean_absolute_error'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)

# print("MAE: %.3f (%.3f)") % (results.mean(), results.std())
print("MAE: {0:.3f} ({1:.3f})".format(results.mean(), results.std()))

MSE (Mean Squared Error)

均方误差类似平均绝对误差,它提供了误差幅度的度量。对均方误差开根号可以得到和原始输出变量同单位有意义的值,称为RMSE均方根误差。

   # Cross Validation Regression MSE
   import pandas
   import numpy as np
   from sklearn import model_selection
   from sklearn.linear_model import LinearRegression

   url = "https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data"
   names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
   dataframe = pandas.read_csv(url, delim_whitespace=True, names=names)
   array = dataframe.values
   X = array[:,0:13]
   Y = array[:,13]
   seed = 7

   kfold = model_selection.KFold(n_splits=10, random_state=seed)
   model = LinearRegression()
   scoring = 'neg_mean_squared_error'
   results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)

   # print("MSE: %.3f (%.3f)") % (results.mean(), results.std())
   print("MSE: {0:.3f} ({1:.3f})".format(results.mean(), results.std()))
   print("RMSE: {0:.3f} ({1:.3f})".format(np.sqrt(-results.mean()), np.sqrt(results.std())))

WMAE (Weighted Mean Absolute Error)

/text{WMAE}=/frac{1}{n}/sum_{i=1}^n w_i |y_i-/hat{y}_i|


Example solution:

id,val,weight,indicator

1,10,.1,Public

2,200,.01,Public

3,3000,.001,Public

4,40000,.0001,Public

5,5,1,Private

6,0.6,10,Private

7,.07,100,Private

Example submission:

id,val

1,11

2,200

3,3300

4,44000

5,5.5

6,0.66

7,0.077

PublicScore = (1.0/(4.0))((.1(11 – 10)) + (.01(200 – 200)) + (.001(3300 – 3000)

PrivateScore = (1.0/(3.0))(1(5.5 – 5.0) + 10(0.66 – 0.6) + 100(0.077 – .07))


RMSE (Root Mean Squared Error)

/text{RMSE}=/sqrt{/frac{/sum_{i=1}^n(y_i – /hat{y}_i)^2}{n}}

RMSLE (Root Mean Squared Logarithmic Error)

/text{RMSLE} = /sqrt{/frac{1}{n}/sum_{i=1}^n (/log(y_i+1) – /log(/hat{y}_i+1))^2}

如果预测的值的范围很大,RMSE会被一些大的值主导。这样即使你很多小的值预测准了,但是有一个非常大的值预测不准,RMSE就会很大。相应的,如果另外一个比较差的算法对这一个大的值预测准确一些,但很多小的值都有偏差,可能RMSE会比前一个小,RMSE在值范围较大时loss会过大,RMSLE bound更tight。RMSLE惩罚欠预测大于过预测。

Correlation Coefficient

相关关系是一种非确定性的关系,相关系数是研究变量之间线性相关程度的量。由于研究对象的不同,相 关系数有如下几种定义方式。

简单相关系数:又叫相关系数或线性相关系数,一般用字母r 表示,用来度量两个变量间的线性关系。

r(X,Y)=/frac{Cov(X,Y)}{/sqrt{Var|X|Var|Y|}}

其中,Cov(X,Y)为X与Y的协方差,VarX为X的方差,VarY为Y的方差。

软件公司在全国有许多代理商,为研究它的财务软件产品的广告投入与销售额的关系,统计人员随机选择10家代理商进行观察,搜集到年广告投入费和月平均销售额的数据,并编制成相关表,见表1:

表1 广告费与月平均销售额相关表 单位:万元

年广告费投入

月均销售额

12.5  15.3  23.2  26.4  33.5  34.4  39.4  45.2  55.4  60.9

21.2  23.9  32.9  34.1  42.5  43.2  49.0  52.8  59.4  63.5

参照表1,可计算相关系数如表2:

序号

广告投入(万元)  x

月均销售额(万元)  y

x^2

y^2

xy

1  2  3  4  5  6  7  8  9  10

12.5  15.3  23.2  26.4  33.5  34.4  39.4  45.2  55.4  60.9

21.2  23.9  32.9  34.1  42.5  43.2  49.0  52.8  59.4  63.5

156.25  234.09  538.24  696.96  1122.25  1183.36  1552.36  2043.04  3069.16  3708.81

449.44  571.21  1082.41  1162.81  1806.25  1866.24  2401.00  2787.84  3528.36  4032.25

265.00  365.67  763.28  900.24  1423.75  1486.08  1930.60  2386.56  3290.76  3867.15

合计

346.2

422.5

14304.52

19687.81

16679.09

相关系数为0.9942,说明广告投入费与月平均销售额之间有高度的线性正相关关系。

  import numpy as np

  a=np.array([[1, 1, 2, 2, 3],
         [2, 2, 3, 3, 5],
         [1, 4, 2, 2, 3]])
  print(np.corrcoef(a)) # 使用np.corrcoef(a)可计算行与行之间的相关系数
  print(np.corrcoef(a,rowvar=0)) #np.corrcoef(a,rowvar=0)用于计算各列之间的相关系数

参考文献

  • https://www.cnblogs.com/zeroone/p/3263952.html
  • MAE (Mean Absolute Error) regression
  • MCRMSE (Mean Columnwise Root Mean Squared Error) regression
  • NormalizedGini (Normalized Gini Index) regression
  • NWMAE (Normalized Weighted Mean Absolute Error) regression
  • RMSE (Root Mean Squared Error) regression
  • RMSLE (Root Mean Squared Logarithmic Error) regression
  • SpearmanR (SpearmanR) regression

其他

多分类评估指标

  • Multi Class Log Loss
  • Categorization Accuracy
  • Multiclass Loss

概率分布函数错误率

Error Metrics for probability distribution function

排序敏感类指标

Metrics only sensitive to the order


MAP是反映系统在全部相关文档上性能的单值指标。系统检索出来的相关文档越靠前(rank 越高),MAP就可能越高。如果系统没有返回相关文档,则准确率默认为0。

例如:假设有两个主题,主题1有4个相关网页,主题2有5个相关网页。某系统对于主题1检索出4个相关网页,其rank分别为1, 2, 4, 7;对于主题2检索出3个相关网页,其rank分别为1,3,5。对于主题1,平均准确率为(1/1+2/2+3/4+4/7)/4=0.83。对于主题 2,平均准确率为(1/1+2/3+3/5+0+0)/5=0.45。则MAP=(0.83+0.45)/2=0.64。

MRR是把标准答案在被评价系统给出结果中的排序取倒数作为它的准确度,再对所有的问题取平均。

MAP可以由它的三个部分来理解:P,AP,MAP

P(Precision)精度,正确率。在信息检索领域用的比较多,和正确率一块出现的是找回率Recall。对于一个查询,返回了一系列的文档,正确率指的是返回的结果中相关的文档占的比例,定义为:precision=返回结果中相关文档的数目/返回结果的数目;

而召回率则是返回结果中相关文档占所有相关文档的比例,定义为:Recall=返回结果中相关文档的数目/所有相关文档的数目。

正确率只是考虑了返回结果中相关文档的个数,没有考虑文档之间的序。对一个搜索引擎或推荐系统而言返回的结果必然是有序的,而且越相关的文档排的越靠前越好,于是有了AP的概念。对一个有序的列表,计算AP的时候要先求出每个位置上的precision,然后对所有的位置的precision再做个average。如果该位置的文档是不相关的则该位置precision=0.


检索类指标

Error Metrics for Retrieval Problems

NDCG常用于作为对rank的评价指标,当我们通过模型得出某些元素的ranking的时候,便可以通过NDCG来测评这个rank的准确度。

首先需要介绍一下DCG:

DCG, Discounted Cumulative Gain ,累计收益折扣.

A measure of ranking quality. 是信息检索领域中, 对排序问题的一个评价指标, 因素有文档相关性排序位置.

使用场景举例:

  • 用户输入一个query, 得到了很多结果, 这个指标可以对有序的结果进行评价.
  • 相关场景: 文档打标签, 把程序的标签输出也看成有序的, 就也可以用该指标评价.
DCG, Discounted Cumulative Gain ,累计收益折扣. 
A measure of ranking quality. 是信息检索领域中, 对排序问题的一个评价指标, 因素有`文档相关性`与`排序位置`.
使用场景举例:
- 用户输入一个query, 得到了很多结果, 这个指标可以对有序的结果进行评价.
- 相关场景: 文档打标签, 把程序的标签输出也看成有序的, 就也可以用该指标评价.

/mathrm{DCG_p} = rel_1 + /sum_{i=2}^{p} /frac{rel_{i}}{/log_{2}(i+1)}

rel_i 表示第i个文档的相关度得分,$$p$$是排序位置

nDCG, Normalized DCG , 归一化的累计收益折扣.不同的query, 搜索结果的个数不一致, 所以需要正规化.

IDCG, 表示在理想情况下, 这些文档按照相关性单调递减排序时的DCG得分.

/mathrm{nDCG_{p}} = /frac {DCG_p} {IDCG_p}

MAP(Mean Average Precision):单个主题的平均准确率是每篇相关文档检索出后的准确率的平均值。主集合的平均准确率(MAP)是每个主题的平均准确率的平均值。 MAP 是反映系统在全部相关文档上性能的单值指标。系统检索出来的相关文档越靠前(rank 越高),MAP就可能越高。如果系统没有返回相关文档,则准确率默认为0。

例如:假设有两个主题,主题1有4个相关网页,主题2有5个相关网页。某系统对于主题1检索出4个相关网页,其rank分别为1, 2, 4, 7;对于主题2检索出3个相关网页,其rank分别为1,3,5。对于主题1,平均准确率为(1/1+2/2+3/4+4/7)/4=0.83。对于主题 2,平均准确率为(1/1+2/3+3/5+0+0)/3=0.7555。则MAP= (0.83+0.7555)/2=0.79。

其他

  • 莱文斯坦距离Levenshtein Distance:两个序列中不同的个数
  • 平均查准率Average Precision
  • 绝对误差Absolute Error
  • MAP@{K} () other
  • GestureNormalizedLevenshteinMean (Gesture Normalized Levenshtein Mean) other
  • IntegerLevenshteinMean (Integer Levenshtein Mean) other
  • LevenshteinMean (Levenshtein Mean) other
  • MCE (Mean Consequential Error) other
  • MeanFScore (Mean F-Score) other

混淆矩阵

对二分类或多分类,混淆矩阵是模型准确性的一般表示,表格中x轴为预测、y轴为准确性结果,表格中的单元代表机器学习算法做出预测的判断数量。

   # Cross Validation Classification Confusion Matrix
   import pandas
   from sklearn import model_selection
   from sklearn.linear_model import LogisticRegression
   from sklearn.metrics import confusion_matrix

   url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
   names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
   dataframe = pandas.read_csv(url, names=names)
   array = dataframe.values
   X = array[:,0:8]
   Y = array[:,8]
   test_size = 0.33
   seed = 7

   X_train, X_test, Y_train, Y_test = model_selection.train_test_split(X, Y, test_size=test_size, random_state=seed)
   model = LogisticRegression()
   model.fit(X_train, Y_train)
   predicted = model.predict(X_test)
   matrix = confusion_matrix(Y_test, predicted)

   print(matrix)

对角线上的值即为预测正确的值。

分类报告

scikit-learn讨论分类问题提供了一个便利的报告,可以较方便的给出模型的准确性概念。

   # Cross Validation Classification Report
   import pandas
   from sklearn import model_selection
   from sklearn.linear_model import LogisticRegression
   from sklearn.metrics import classification_report

   url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
   names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
   dataframe = pandas.read_csv(url, names=names)
   array = dataframe.values
   X = array[:,0:8]
   Y = array[:,8]
   test_size = 0.33
   seed = 7

   X_train, X_test, Y_train, Y_test = model_selection.train_test_split(X, Y, test_size=test_size, random_state=seed)
   model = LogisticRegression()
   model.fit(X_train, Y_train)
   predicted = model.predict(X_test)

   report = classification_report(Y_test, predicted)
   print(report)

参考文献:

原创文章,作者:3628473679,如若转载,请注明出处:https://blog.ytso.com/212372.html

(0)
上一篇 2021年12月16日
下一篇 2021年12月16日

相关推荐

发表回复

登录后才能评论