简介
如何在实际运用中平价一个模型的好坏?
用性能度量的方法可以对学习模型的泛化或者分类能力进行评估,下面我们来简单介绍下各种性能度量的方法
具体介绍
均方误差
就是测试集本身的结果与预测结果做差的平方,再除总的数据个数。
M
S
E
=
1
m
∑
i
=
0
d
(
f
(
x
i
)
−
y
i
)
2
MSE = \frac{1}{m} \sum_{i=0}^d (f(x_i) - y_i)^2
MSE=m1i=0∑d(f(xi)−yi)2
f(xi)是模型结果,yi是真实数据。
def MeanSquarederror(test,result):
'''
test与result一个是测试集本身的映射结果,一个是测试集经过模型的映射
:param test:
:param result:
:return:
'''
sum = 0
n = len(test)
i = 0
while i < n:
sum += (test[i] - result[i])*(test[i] - result[i])
i += 1
return sum
错误率与准确率
错误率:就是分类错误的样本数量
R
E
C
=
1
m
∑
i
=
0
d
I
(
f
(
x
i
)
≠
y
i
)
REC= \frac{1}{m} \sum_{i=0}^d I(f(x_i) ≠ y_i)
REC=m1i=0∑dI(f(xi)=yi)
主要用于分类了
def REC(test, result):
"""
:param test:
:param result:
:return:
"""
sum = 0
n = len(test)
i = 0
while i < n:
if test[i] != result[i]:
sum += 1
i += 1
return sum / n
准确率:分类正确的样本数量
A
C
C
=
1
m
∑
i
=
0
d
I
(
f
(
x
i
)
=
y
i
)
ACC= \frac{1}{m} \sum_{i=0}^d I(f(x_i) = y_i)
ACC=m1i=0∑dI(f(xi)=yi)
主要用于分类了
def ACC(test, result):
"""
:param test:
:param result:
:return:
"""
sum = 0
n = len(test)
i = 0
while i < n:
if test[i] == result[i]:
sum += 1
i += 1
return sum / n
查准率、查全率与F1
上面的方法已经能解决大部分问题了,但是如果这时候有人问:正确的样本中有多少个在训练集中?训练集中有多少正确的样本?
首先先认识一个混淆矩阵:
横是预测结果,竖着是真实情况 | 正例 | 反例 |
---|---|---|
正例 | TP(真正例) | FN(假反例) |
反例 | FP(假正例) | TN(真反例) |
用python绘制混淆矩阵:
def ConfusionMatrix(test, result):
'''
记得这是分类的任务,如果你当成回归的话很可能运行失败
:param test:
:param result:
:return:
'''
return confusion_matrix(test, result)
查准率查全率
查准率:信息中有多少信息是目标感兴趣的
P
=
T
P
T
P
+
F
P
P=\frac{TP}{TP+FP}
P=TP+FPTP
def Precision(y_test, y_pre):
"""
:param y_test:
:param y_pre:
:return:
"""
TP = confusion_matrix(y_test, y_pre)[0, 0]
FP = confusion_matrix(y_test, y_pre)[1, 0]
return TP / (TP + FP)
查全率:信息中有多少正确的信息被提取出来
R
=
T
P
T
P
+
F
N
R=\frac{TP}{TP+FN}
R=TP+FNTP
def Recall(y_test, y_pre):
"""
:param y_test:
:param y_pre:
:return:
"""
TP = confusion_matrix(y_test, y_pre)[0, 0]
FN = confusion_matrix(y_test, y_pre)[1, 1]
return TP / (TP + FN)
F1-score
查准率跟查全率很矛盾,查全率高的时候查准率低,你把所有样本选上了查全率就高了,但是这样查准率会低。如果你只选一部分正确的样本,查准率高,查全率就低,为了更全面的研究问题,引入F1-score的概念:
F
1
=
2
∗
T
P
样
例
总
数
+
T
P
−
T
N
F1=\frac{2*TP}{样例总数+TP-TN}
F1=样例总数+TP−TN2∗TP
def F1_Score(y_test, y_pre):
"""
记得这是分类的任务,如果你当成回归的话很可能运行失败
:param test:
:param result:
:return:
"""
matrix = confusion_matrix(y_test, y_pre)
n = len(y_test)
TP = matrix[0,0]
TN = matrix[1,1]
return (2*TP)/(n+TP-TN)
Fβ-score
再考虑周全的前提下,尽量可以让用户选择偏向于P还是R。
β>1查全率有更大影响,反之查准率有大影响。
F β = ( 1 + β ) 2 ∗ P ∗ R ( β 2 ∗ P ) + R Fβ=\frac{(1+β)^2*P*R}{(β^2*P)+R} Fβ=(β2∗P)+R(1+β)2∗P∗R
def Fβ_score(y_test, y_pre,beta = 0.5):
"""
:param y_test:
:param y_pre:
:param beta:
:return:
"""
R = Recall(y_test,y_pre)
P = Precision(y_test,y_pre)
b = beta*beta
return ((1+b)*P*R)/((b*P)+R)
宏F1
有时候我们有很多个混淆矩阵怎么办?那么我们就求出全部P与R的平均值,然后再做F1-score的计算。
微F1
我们先求出不同的混淆矩阵对应的F1-score,多个F1-score结果做平均运算。
以上两个操作就不写例子了
ROC与AUC
如果我们有一个算法,输出结果为[0,1]区间的值,满足这个算法条件的数据接近1,如果我们追求查准率就尽量取大于0.5的地方找一个截断点,大于截断点的为正确的数据,追求查全率取小于0.5的地方找一个截断点,大于截断点的为正确的数据。
但是这个点的寻找是不确定的,我们希望找一个平均状态下的最优的点,我们就需要用ROC图去考虑这些情况。
ROC图的横轴为真正例率:
T
P
R
=
T
P
T
P
+
F
N
TPR = \frac{TP}{TP+FN}
TPR=TP+FNTP
def TruePositiverate(y_test,y_pre):
TP = confusion_matrix(y_test, y_pre)[0, 0]
FN = confusion_matrix(y_test, y_pre)[0, 1]
return TP / (TP + FN)
ROC图的纵轴为假正例率:
F
P
R
=
F
P
F
P
+
F
N
FPR = \frac{FP}{FP+FN}
FPR=FP+FNFP
def FalsePositiverate(y_test,y_pre):
FP = confusion_matrix(y_test, y_pre)[1, 0]
FN = confusion_matrix(y_test, y_pre)[0, 1]
return FP / (FP + FN)
这样我们可以得到一个损失函数
l
o
s
s
r
a
n
k
=
∑
x
+
∈
D
+
∑
x
−
+
∈
D
−
(
I
(
f
(
x
+
)
<
f
(
x
−
)
)
+
1
2
I
(
f
(
x
+
)
=
f
(
x
−
)
)
正
例
的
数
量
+
反
例
的
数
量
loss_{rank} = \frac{\sum_{x^+∈D^+}\sum_{x-+∈D^-}(I(f(x^+)<f(x^-))+\frac{1}{2}I(f(x^+)=f(x^-))}{正例的数量+反例的数量}
lossrank=正例的数量+反例的数量∑x+∈D+∑x−+∈D−(I(f(x+)<f(x−))+21I(f(x+)=f(x−))
D+与D-代表正例与反例的集合,这就是考虑每一对正例、反例多正例的预测值小于反例则记一个罚分,若相等记0.5个罚分,很容易看出这个loss函数对应的是ROC曲线上的面积,若一个正例在ROC曲线上对应的坐标为(x,y)则x恰巧是排在前面的反例所占的比例,即假正例率,因此有AUC = 1 - lossrank。
代价敏感错误率与代价曲线
在现实生活中会遇到不同类型的错误所造成的后果是不同的,错误的把健康的人分类为病人与错误的把病人分类为健康的人所带来的后果是不一样的。
以二分任务为例,我们建立一个代价矩阵。costij是把第i类错误分为j类所造成的样本的代价,通过这个矩阵来模拟现实生活中不同的代价所带来的影响。
横轴是预测类别,纵轴是真实类别 | 第0类 | 第1类 |
---|---|---|
第0类 | 0 | cost01 |
第1类 | cost10 | 0 |
我们可以对应的修改上面提到的损失函数,写一个代价敏感错误率(按照上面的代价矩阵建立)
l
o
s
s
r
a
n
k
=
∑
x
i
∈
D
+
I
(
f
(
x
i
)
≠
f
(
x
−
)
∗
c
o
s
t
01
+
∑
x
i
∈
D
−
I
(
f
(
x
i
)
≠
y
i
)
∗
∗
c
o
s
t
10
m
loss_{rank} = \frac{\sum_{x_i∈D^+}I(f(x_i)≠f(x^-)*cost_{01}+\sum_{x_i∈D^-}I(f(x_i)≠y_i)**cost_{10}}{m}
lossrank=m∑xi∈D+I(f(xi)=f(x−)∗cost01+∑xi∈D−I(f(xi)=yi)∗∗cost10
同样的我们的ROC也无法之间反映出模型的期望总体代价,而代价曲线则可以达到目的,代价曲线的横轴是取值为[0,1]的正概率代价,p是样例为正例的概率:
P
(
+
)
c
o
s
t
=
p
∗
c
o
s
t
01
p
∗
c
o
s
t
01
+
(
1
−
p
)
∗
c
o
s
t
10
P(+)cost=\frac{p*cost_{01}}{p*cost_{01}+(1-p)*cost_{10}}
P(+)cost=p∗cost01+(1−p)∗cost10p∗cost01
纵轴是取值欸[0,1]的归一化代价:
c
o
s
t
n
o
r
m
=
F
N
R
∗
p
∗
c
o
s
t
01
+
F
P
R
∗
(
1
−
p
)
∗
c
o
s
t
10
p
∗
c
o
s
t
01
+
(
1
−
p
)
∗
c
o
s
t
10
cost_{norm}=\frac{FNR*p*cost_{01}+FPR*(1-p)*cost_{10}}{p*cost_{01}+(1-p)*cost_{10}}
costnorm=p∗cost01+(1−p)∗cost10FNR∗p∗cost01+FPR∗(1−p)∗cost10
代价曲线的绘制很简单:ROC曲线上每一点对应了代价平面上的一条线段,设ROC曲线上点的坐标为(FPR,TPR)则可相应计算出FNR,然后在代价平面上绘制一条从(0,FPR)到(1,FNR)的线段,线段下面的面积表示了该条件下的期望的总体代价,把ROC曲线上的每一个点都转化为这样的一条限电,然后取所有线段的下界,就获得在所有条件下学习器的期望总体代价。
主要参考
参考:
[1] 周志华 《机器学习》