数学建模社区-数学中国

标题: 详细讲解分类模型评估 [打印本页]

作者: 杨利霞    时间: 2020-4-19 11:53
标题: 详细讲解分类模型评估

- f) [& j$ B$ e  l& M详细讲解分类模型评估分类模型评估# v, c* X' ]8 e  P

+ j7 I' I; p  k; D; a) g1、分类模型
9 B6 \7 U; n  C主题:如何对分类模型进行评估  Q3 R& R- h( d: E& M2 j
目标:
, k3 p9 Y& f0 r) e" N7 ]0 C2、混淆矩阵& g! W  b! K- d  x  `! ]5 L/ X
3、评估指标! d/ w1 k9 O* M; x  L
3.1 正确率
: O9 v1 o2 q' V! w0 h7 X3.2 精准率9 @. ?. v0 b4 {# [+ `
3.3 召回率
# I9 j2 }$ _4 s: N3.4 调和平均值F1
' ]- T/ E. r: T  Z1 k6 r5 e4、ROC和AUC
% E3 i, f9 Y6 E' r6 h, Q" k4.1 ROC曲线8 {7 ~3 I3 [$ L; _5 |$ p( v- A
如何画ROC曲线:
$ Q* a: m# e" f* {8 z9 U4.2 AUC  p1 b- f8 ~% N; n* D. Y# ]! L
4.3 ROC曲线程序示例
1 H! B6 V  w! s4.3.1 roc_curve函数的参数
9 O5 G2 h2 `8 L* c* U6 L9 a4.3.2 roc_curve函数的返回值: A& Y: @# B5 e; z
4.3.3 绘制ROC曲线
4 Z9 i% Y: Y& ?* E" b% E5、总结$ N% p: o( }# \
1、分类模型8 h6 K, a, U+ {

9 o- t+ Q$ N# ~# s! A: ]分类问题在我们日常生活中处处可见,比如我们对帅哥的分类,可能对帅哥分为非常帅和一般帅。比如我们平时刷淘宝,淘宝根据我们平时的喜好给我们推送产品,那我们就会把产品分为感兴趣和不感兴趣两类。) b4 |0 G/ t1 @. ~9 k, W4 R
上述所说的问题就是典型的分类问题,确切的说其实就是二分类问题。5 R) f5 n: y; e  B7 Z; L6 G
能够解决这些二分类问题的数学模型就被称为二分类模型。
7 O/ v: o7 k2 N7 F8 \) p用数学的方式表达就是,给定自变量X,代入到我们的分类模型F,会输出因变量y,y的取值为0或1,其中0代表负样本(一般帅的帅哥、不感兴趣的推送),1代表正样本(非常帅气的帅哥、感兴趣的推送)。
. t% ]/ m, t/ I, s) g; y7 |
+ a' w4 w2 Z' ]6 m. q2 O$ Z1 q主题:如何对分类模型进行评估: b) k" X. c  o

" w" m& l6 u- k$ a) N1 D目标:2 ~/ _/ c4 h3 F! ~# J% _  f
1 Z& {$ z8 h& _& i+ b
能够熟知混淆矩阵的含义。$ h1 U; X% u7 j! F5 }' m6 m: t3 M* y
能够使用各种指标对分类模型进行评估。
9 S. A* B3 Y- |4 w0 g能够独立绘制ROC曲线,并熟悉该曲线细节。$ L: @$ J0 z- ~+ }
能够对样本不均衡进行处理(扩展内容)。
( H0 o. \  E6 A' _9 ]2、混淆矩阵
/ \7 {8 U( g+ |* ]5 r  v- z6 @$ q& @; \% {" `" s: _  a
混淆矩阵,可以用来评估模型分类的正确性。8 h" g" M  D5 \. K
该矩阵是一个方阵,矩阵的数值用来表示分类器预测的结果,包括真正例(True Positive),假正例(False Positive),真负例(True Negative),假负例(False Negative)。/ d7 ~' W- Q/ ~+ `; J
1.png
3 t( S1 b7 ?7 E$ Q& t矩阵的形状是2 x 2,其中, - 矩阵的左上角表示,预测值为1,实际值为1(True Positive,简称TP); - 右上角表示预测值为1,实际值为0(False Positive,简称FP); - 左下角表示预测值为0,实际值为1(False Negative,简称FN); - 右下角表示预测值为0,实际值为0(True Negative,简称TN);5 O& E5 }# `+ N

* e+ F' a$ Q6 K1 V' X' _2 `真负例(TN)+ 假正例(FP)——每个类别真实存在的负例的数量
/ h) ]- N) R6 e+ @( s假负例(FN)+ 真正例(TP)——每个类别真实存在的正例的数量
6 i7 U! }( A1 m6 N1 y3 ?  ]) R真负例(TN)+ 假负例(FN)——每个类别预测的真负例数量) T0 F/ U* y3 P* Z+ C
假正例(FP)+ 真正例(TP)——每个类别预测的真正例数量: d# Y- c* a# b3 o7 O8 P" L
其中:/ n+ }" `- w* I0 h% ~

0 B: z5 u3 _" I7 G5 H, ^) Q; ITP:真正例,实际为正预测为正;' B/ a* _& ~* n
FP:假正例,实际为负但预测为正;
' k. G1 l9 X4 p! q5 |FN:假反例,实际为正但预测为负;4 C2 a" V+ w9 ?4 N
TN:真反例,实际为负预测为负- h% \" y5 X, i2 ]
接下来,我们通过数据来看下鸢尾花的混淆矩阵:( o2 k# C4 V! G4 I4 P  w$ l* f
import numpy as np
2 g, u* }) V! ~% }# v; h3 r/ Ifrom sklearn.datasets import load_iris8 e2 [* r9 h8 \1 O
from sklearn.linear_model import LogisticRegression! s; B$ L1 s- t" k
from sklearn.model_selection import train_test_split
* V8 I3 W, f* \# 混淆矩阵
) y1 [, Q5 ^1 T. S- {from sklearn.metrics import confusion_matrix
- x& s$ U7 M2 d6 Himport matplotlib.pyplot as plt3 o) D( X. G* M! a9 X( o
import warnings
1 [$ Q3 z9 T+ h$ p2 V3 k6 ~% u" @  r& ~" F  D; G
plt.rcParams["font.family"] = "SimHei") c8 z8 R- f) g$ f
plt.rcParams["axes.unicode_minus"] = False) e1 W/ `/ y$ A9 P
plt.rcParams["font.size"] = 12
+ q+ _" b) b) Q! Kwarnings.filterwarnings("ignore")1 a7 q7 D6 n7 n- N

5 e: A* l! G/ W- eiris = load_iris()  #导入鸢尾花数据集$ l* [/ h  d% l$ f8 E6 c/ w- q7 Z
X, y = iris.data, iris.target
8 E4 q. o5 q* n- @5 SX = X[y != 0, 2:]
2 S7 ^; g% B: U* p9 e/ K# Zy = y[y != 0]; U4 L0 p: e2 n# k! @" {( v; A; |3 x
y[y == 1] = 0
3 z2 Z1 j  p5 I( z* yy[y == 2] = 1
' S- q; B1 b6 }. ~& m- m3 _X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=2)
1 x  W( A) Y" X# o9 j) _, [lr = LogisticRegression()  #使用逻辑回归+ N1 N& [1 ?  ]+ h0 a3 }
lr.fit(X_train, y_train)0 g% s" H3 Z6 v- g
y_hat = lr.predict(X_test)7 U" Q* K, \' Q
# 根据传入的真实值与预测值,创建混淆矩阵。
. h- M2 N; l! |3 v3 Amatrix = confusion_matrix(y_true=y_test, y_pred=y_hat)( p  c3 `$ t# q6 g/ `
print(matrix)- h$ s3 w" I0 ~9 _" {% |

7 K* l, ]8 p+ |* x
' z0 S# L4 ]3 _1 v输出结果:/ C3 Z1 ]( g# L4 b
2.png ! s9 a$ I) F: ]) g6 `8 C
我们还可以对其进行可视化操作:
1 ]4 g! E; U5 Vmat = plt.matshow(matrix, cmap=plt.cm.Blues, alpha=0.5)    #cmap 指定颜色图色系,alpha透明度
, \* f7 ?% u3 y( q" l7 Y/ j7 W; Plabel = ["负例", "正例"]0 z4 U0 Z9 A2 K, t
ax = plt.gca()* }2 B  D& p. N0 H) H' y
ax.set(xticks=np.arange(matrix.shape[1]), yticks=np.arange(matrix.shape[0]),
1 X/ r3 k- p7 Z( E: G+ b        xticklabels=label, yticklabels=label, title="混淆矩阵可视化\n",- s4 c6 W$ }9 V3 l2 j8 M. L2 \; M3 N
        ylabel="真实值", xlabel="预测值")( K* l8 J' h& w5 G/ X7 v
for i in range(matrix.shape[0]):
8 U. n! ~* R% O  R  F9 Z' V    for j in range(matrix.shape[1]):$ |0 D+ B0 W/ A: h) z' Y" t
        plt.text(x=j, y=i, s=matrix[i, j], va="center", ha="center")
$ \8 p7 C" q' f( ~' ua, b = ax.get_ylim()
6 Z3 a" l' E4 [, n% y4 z+ }6 k; Bax.set_ylim(a + 0.5, b - 0.5)+ L3 c  W& g- t7 t- P; F# x
plt.show()4 g7 J6 Q& _5 G3 e
/ k4 u6 q2 w2 n0 I8 Z% Z6 C

8 A# w% I( J2 c- C# C# B代码解析:# M9 ]) x: I6 b6 Y: `$ m
matshow( ) 绘制矩阵,alpha 透明度4 h0 u& r# d5 s* z+ n) ^. W$ C
结果:
1 z1 h& ^' J1 ? 3.png
- s" U' `. k7 B! n, y练习:
4 O! F3 o; t3 q3 Z# y: U. }, D. N& J5 M
关于混淆矩阵,说法正确的是( ABCD)。【不定项】
. u7 i/ R; p! W5 Z+ e! y; j: {A 混淆矩阵可以用来评估分类模型。
& v" s4 Q( I; z9 f7 y) X8 SB 混淆矩阵中,TP与TN的数值越大,则分类的效果越好。
! i$ k: P& Z6 L  p, oC 混淆矩阵一行元素的和代表某个类别的实际数量。# h4 L& M: b+ T5 N) C
D 混淆矩阵一列元素的和代表某个类别的预测数量。
: \8 Y8 f6 r4 k( x4 S* X: A3、评估指标7 i$ |5 ~6 D, l- I0 x4 z4 H

$ R. o( K" A3 Y对于分类模型,我们可以提取如下的评估指标:
6 g# D5 K9 n. s2 y9 B5 I* N
9 F, K) x' i- ?% [. E/ s, o0 e正确率(accuracy)# r7 U$ o" {+ r5 }
精准率(precision). t; J, T7 N8 M4 R
召回率(recall)
8 C& m5 h* L) c. O2 \( v, ZF1(调和平均值)7 C' j) j+ L6 ~+ x
3.1 正确率
# P6 n9 }+ i, m2 k 4.png
4 T" w" ]& n4 A4 K正确率(准确率)定义如下:9 x8 {% D3 t. \( _- \' _0 w
衡量所有样本被分类准确的比例。) W: [) }( M. }5 M. X4 J. [
Accuracy = (TP+TN) / (TP+FP+TN+FN)
- t7 ?0 G# ?5 m  n  V  I2 l. E/ G, ~  E! B! O! Q$ c& q4 D
预测正确的数量除以总数量。
. R9 @+ Q& }/ V: O: T2 x0 D2 r$ j& y: S3 Z+ ^" _3 J
3.2 精准率- _4 s' ]/ _9 O& a3 X7 K4 H
5.png 5 p5 L% o8 _0 ^: c) @8 e
查准率(精准率)定义如下:
: j0 U9 A5 v: U% ~衡量正样本的分类准确率,就是说被预测为正样本的样本有多少是真的正样本。
. J6 W7 N) o9 W# r0 ~0 U7 V9 xPrecision = TP / (TP+FP)
5 U0 ]0 L% f& \4 F2 @8 G2 w  z, r6 D% k! O1 i6 B1 V) f. s+ I1 }
精准率只考虑正例。
( v' _" E! p, ?2 u# E
1 Y' z/ k3 d  y3.3 召回率
8 U; u$ N1 s: Y; j$ l4 T2 @ 6.png ' c6 ?. a* J: }; Q
查全率(召回率)定义如下:) T! u# {/ Y) }3 [4 ^
表示分类正确的正样本占总的正样本的比例。
7 A7 p2 T' f9 K6 L0 K; I+ PRecall = TP / (TP+FN)$ @3 L+ r, z* U; k& t& X( ]

! q; v. u+ ^/ V5 _# C
8 V/ Z+ g. z3 C( n1 I3.4 调和平均值F1! ^+ S; g' f- e5 I" C, I/ \
7.png
! P+ l" o8 u  qF值(F1-scores)调和平均值F1定义如下:* S2 n% q7 |- z
精确率和召回率的调和平均。
0 p6 A8 O# S5 V5 w4 j+ ^2 v2 k精准率Precision和召回率Recall加权调和平均数,并假设两者一样重要。/ Z/ ?# ?3 }( _

. a2 D- g5 j- [- A' v7 ~6 SF1-score = (2Recall*Precision) / (Recall + Precision)+ I# g& V" b% J4 C- e8 g

% {  h6 X/ ?# q, ^" ?精准率和召回率是一对矛盾的度量。一般来说,精准率高时,召回率往往偏低;而召回率高时,精准率往往偏低。通常只有在一些简单任务中,才可能使二者都很高。
' K4 V+ X0 c# N/ s. @9 z# L最好的分类器当然是准确率、精确率,召回率都为1,但实际场景中几乎是不可能的,而且精确率和召回率往往会相互影响,一个高了另一个会有所下降,因此在实际应用中要根据具体需求做适当平衡。, \- \' m9 D2 N0 P
让我们做个练习加深下印象吧!
$ A2 C1 G1 {0 u$ s1 ]% d
, C/ N. S4 m" _4 k* |6 }- e以下说法正确的是( C )。
( p7 X& d+ A2 A: t3 X& `A 使用正确率去评估一个分类模型,效果会比精准率更好。
; j; o$ N* s  i/ i) mB 使用精准率去评估一个分类模型,效果会比召回率更好。$ d; f- E7 u" u
C 精准率与召回率通常要联合使用。/ N! Q9 b) A- h9 \- H" e' z
D 精准率与召回率如果有一个值较低,F1值也可能会较高。
+ I% T3 g% T# U7 M% x9 ~9 x% t如果精准率和召回率我们只能选择重视一个,我们会更看重( C )。
  e; b9 Q9 _" @$ G' B6 s5 c5 gA 精准率。
8 D  q1 L/ z3 ?B 召回率。
% ~6 Y9 E. n) }( YC 具体场景不同,重视谁也会不同。2 y. f4 O4 u3 u' e  C# N
接下来我们通过程序来说明下:& `: e! k2 [/ _& B$ D/ X- h- b
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score. i+ x+ M+ L8 _1 Y& G) l+ p! d  y" p

4 e* L9 }0 v8 n% Mprint("正确率:", accuracy_score(y_test, y_hat))" c/ {2 \$ ~4 K! l, q/ x4 i
# 默认将1类别视为正例,可以通过pos_label参数指定。2 T4 e% `$ J# Y/ Y
print("精准率:", precision_score(y_test, y_hat))
) C0 M, f1 z' p6 ]- ]% T+ a3 w) r' Gprint("召回率:", recall_score(y_test, y_hat))
5 O: v" x$ Z$ V: t0 G* Kprint("F1调和平均值:", f1_score(y_test, y_hat))
5 T! |7 N& e$ o2 V% f' ?% x6 z( ]# 我们也可以调用逻辑回归模型对象的score方法,也能获取正确率。; q8 v. s. D" C2 z7 C6 T  F  [! T
# 但是需要注意,score方法与f1_score函数的参数是不同的。' v+ H. t$ `0 A8 a7 q$ z7 Q7 L8 Z
print("score方法计算正确率:", lr.score(X_test, y_test))
: ]: v4 q8 j4 ?8 ?* ^% {, g5 f  \% n- W

0 I# E$ V4 o6 _. f7 p$ C结果:
" H- w! T8 v3 F$ S  _1 M# x8 O6 N/ X4 y 8.png " z- _) O( p) F2 ]
除此之外,我们也可以使用classification_report函数来查看模型的分类统计信息,该方法会返回字符串类型,给出相关的分类指标评估值。
/ b- a9 K3 I0 Pfrom sklearn.metrics import classification_report
% Q* ^2 _9 _, G9 v  z1 c8 J( B$ I
print(classification_report(y_true=y_test, y_pred=y_hat))
. p& D5 D, Y- V8 J# R7 B5 Z5 V% A. n6 R4 ~

* E* P* l! W; s: Y' R结果:
3 t4 a8 d4 z3 b* y; K 9.png 5 i. e8 ~0 d6 u

: ?. Y# o4 {" @6 q练习:& f% K5 B5 z9 V) r) h
4 h, t+ K- O5 L. e, x% }* l: D
如果使用精准率与召回率评估二分类模型时,我们应该将哪个类别设置为正例? (B)% S) M6 B& Y- ^. U" d1 o
A 随意" M8 d- o  m( v' a' Y0 }/ u$ L
B 关注的类别
; |/ U4 j+ {1 n: m+ ~C 不关注的类别
% t, {3 C& [9 o* W( S7 q1 y4、ROC和AUC/ W' ~' ?  B1 r9 \( Z4 m  E
' X1 o1 x/ l8 N" l
ROC(Receiver Operating Characteristic)曲线和AUC常被用来评价一个二值分类器(binary classifier)的优劣。
# x9 j' n. R9 Q$ b' J! S+ K8 r, g- N' m7 U! }- G) \
4.1 ROC曲线
  Z6 h# u4 A6 {/ I 10.png
' I2 J- v0 m2 `- pROC曲线(Receiver Operating Characteristic——受试者工作特征曲线),使用图形来描述二分类系统的性能表现。图形的纵轴为真正例率(TPR——True Positive Rate),横轴为假正例率(FPR——False Positive Rate)。其中,真正例率与假正例率定义为:
1 r1 ]* L$ \5 W1 Q' a
* b; B2 s# ^' m8 [4 tROC曲线通过真正例率(TPR)与假正例率(FPR)两项指标,可以用来评估分类模型的性能。真正例率与假正例率可以通过移动分类模型的阈值而进行计算。随着阈值的改变,真正例率与假负例率也会随之发生改变,进而就可以在ROC曲线坐标上,形成多个点。: W0 ?$ J3 t  T
, _( U, v# n- D+ a8 i9 [
ROC曲线反映了FPR与TPR之间权衡的情况,通俗来说,即在TPR随着FPR递增的情况下,谁增长得更快,快多少的问题。TPR增长得越快,曲线越往上凸,模型的分类性能就越好。
. F9 K/ O# ]7 V# V6 `  q9 G0 `& o% {+ k4 J
ROC曲线如果为对角线,则可以理解为随机猜测。如果在对角线以下,则其性能比随机猜测还要差。如果ROC曲线真正例率为1,假正例率为0,即曲线为与构成的折线,则此时的分类器是最完美的。
3 I5 b  N7 V0 }1 W/ ^
, P$ j( h0 g- b% R6 A% f$ l1 h. n下图就是ROC曲线的一个示意图:2 a# B5 x, h" t# }: d
11.png 3 z) h9 \! _3 }) E
ROC曲线横坐标是FPR(False Positive Rate),纵坐标是TPR(True Positive Rate)  S1 t6 S/ r8 F8 B: e
接下来我们考虑ROC曲线图中的四个点和一条线。" G& g% `1 r* Y) p9 ?: Y" ]3 |( s6 i
+ W4 z6 R) i4 i+ t! h" j- Z
第一个点,(0,1),即FPR=0, TPR=1,这意味着FN(false negative)=0,并且FP(false
- }% M5 r8 t. tpositive)=0。这是一个完美的分类器,它将所有的样本都正确分类。4 G. U9 N: Z. H9 U  L
第二个点,(1,0),即FPR=1,TPR=0,类似地分析可以发现这是一个最糟糕的分类器,因为它成功避开了所有的正确答案。: \4 z- S( r' p) O; x
第三个点,(0,0),即FPR=TPR=0,即FP(false positive)=TP(true
+ r, }+ `, `$ y9 Jpositive)=0,可以发现该分类器预测所有的样本都为负样本(negative)。( F) u- n  y& X$ X. X& ?  U
第四个点(1,1),分类器实际上预测所有的样本都为正样本。经过以上的分析,我们可以断言,ROC曲线越接近左上角,该分类器的性能越好。- w$ Q/ d- j, o! \2 f5 i4 i
如何画ROC曲线:# o1 J4 ~; K. z! r- I

1 _! Q/ D0 j4 e6 M对于一个特定的分类器和测试数据集,显然只能得到一组FPR和TPR结果,而要得到一个曲线,我们实际上需要一系列FPR和TPR的值,这又是如何得到的呢?我们先来看一下wikipedia上对ROC曲线的定义:
7 D5 e* b; C+ ^3 j3 s
8 Y; E: p8 [, j+ [% G5 ?' eA receiver operating characteristic curve, i.e. ROC curve, is a
9 i( Z  M& ~$ f: E+ Z0 X* cgraphical plot that illustrates the diagnostic ability of a binary7 t  L$ c9 R' p
classifier system as its discrimination threshold is varied.) u2 ]* C, y: u8 N
译:ROC曲线是由一系列因区分阈值变化产生的点,用于描述二分类模型的判断能力% @! z, a+ l% T$ c
这里的关键在于 “its discrimination threshold is varied” ,因为对于一个二分类模型,它的输出结果其实是判断这个样本属于正样本的概率值,假如我们已经得到了所有样本的概率输出(属于正样本的概率),现在的问题是如何改变“discrimination threashold”?我们根据每个测试样本属于正样本的概率值从大到小排序。下图是一个示例,图中共有20个测试样本,“Class”一栏表示每个测试样本真正的标签(p表示正样本,n表示负样本),“Score”表示每个测试样本属于正样本的概率, {* y* d" b8 Q1 X$ l# z, P
12.png ( E( W* p- }4 Z- z
然后我们按照样本的score值,从大到小依次作为阈值,当样本score值大于等于阈值时则判定为正样本,否则为负样本。
+ i' Z/ m5 |2 g+ V2 t2 Y例如第一个阈值取0.9,这时只有id=1的样本被预测为正样本,其余都是负样本,此时TPR=1/1+9=0.1, FPR=0/0+10=0。还例如:对于图中的第4个样本,其“Score”值为0.6,那么样本1,2,3,4都被认为是正样本,因为它们的“Score”值都大于等于0.6,而其他样本则都认为是负样本。# I+ z  @! U+ u- w
. h* ~7 Y- A4 Z7 d3 e9 @' G# ]
详细如下:
" o: \9 e5 @. l6 }8 z 13.png
2 V: o6 d2 g0 ^0 e, B3 _由此我们便得到了一组(FPR,TPR)的值,可以绘制出ROC曲线:
2 e, L0 ~/ z6 W6 x( X- ^ 14.png 5 a, i* _+ O+ D  f/ l3 w* S, Q7 ?
当我们将threshold设置为1和0时,分别可以得到ROC曲线上的(0,0)和(1,1)两个点。将这些(FPR,TPR)对连接起来,就得到了ROC曲线。当threshold取值越多,ROC曲线越平滑。1 N- |4 k: Z+ o4 i; z' Y9 i# B
2 j. k0 t" A8 Y; ~# ?3 u" \
4.2 AUC" ?5 r3 w, q1 a& N9 A) v2 t
15.png
, Z# J9 b  \' J5 cAUC(Area Under the Curve)是指ROC曲线下的面积,使用AUC值作为评价标准是因为有时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而AUC作为数值可以直观的评价分类器的好坏,值越大越好。: {+ ?2 F4 a' s/ e( L% N- A/ A
5 P$ L; I* L" ~/ y3 u% l- q
AUC是ROC曲线下的面积。" Y# p( v+ U* p# q
AUC的取值为[0.5-1],0.5对应于对角线的“随机猜测模型”。
! ?+ q- x$ I. J# p9 e! X* iAUC值是一个概率值,当你随机挑选一个正样本以及负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值,AUC值越大,当前分类算法越有可能将正样本排在负样本前面,从而能够更好地分类。
8 Z- {, W; W$ }6 b, |! Z( ~' J
' O1 q4 N9 v; B1 ?; f8 J4 ^从AUC判断分类器(预测模型)优劣的标准:
* J) f( V6 O; C9 \8 _* B+ {7 k$ \9 B( w) V: E% a* i
: D$ p9 F! j) X1 _+ }, d* \5 h
例如一个模型的AUC是0.7,其含义可以理解为:给定一个正样本和一个负样本,在70%的情况下,模型对正样本的打分(概率)高于对负样本的打分。; r4 W" n3 t% Y" O% Z8 x/ t8 A4 _
3 {) l' n! ^+ S+ l: c4 d
三种AUC值示例:
% }& ^6 l0 `* t, b 16.png 6 n& G: N6 i, j
简单说:AUC值越大的分类器,正确率越高。+ ?8 Z' y" E) J+ C5 U

' U3 ]( W  t+ |- `5 u5 \2 p那么为什么要用AUC作为二分类模型的评价指标呢?为什么不直接通过计算准确率来对模型进行评价呢?, [2 ^0 N9 c: [) _* p# v
因为机器学习中的很多模型对于分类问题的预测结果大多是概率,即属于某个类别的概率,如果计算准确率的话,就要把概率转化为类别,这就需要设定一个阈值,概率大于某个阈值的属于一类,概率小于某个阈值的属于另一类,而阈值的设定直接影响了准确率的计算。也就是说AUC越高说明阈值分割所能达到的准确率越高。
1 q) |, R! e- M5 [& ^
; {# H2 p) T7 m小练习:
2 I/ X/ {. d. p/ G$ Y* A
$ Y: G) b& H& M- Z, U0 S6 c以下说法正确的是( ABD)。【不定项】
& G  v) {. G" [2 h& w7 IA 随着阈值的降低,TPR与FPR都会增大。$ W9 R6 `) ?1 j" p0 N3 `0 M4 B
B TPR与召回率的值是相同的。
+ R; K' i7 l7 l' bC 如果AUC的值非常低,例如,0.1,则该模型效果很差,也很难调优。
8 R% u0 E3 c. c6 a" A2 t: {* ?4 yD 无论是什么分类模型,ROC曲线一定会经过(0, 0)与(1,1)这两个点。
6 I: s6 N' M! ]! d+ U* {4.3 ROC曲线程序示例8 K" p. V' @( v! x

( _& z6 _2 \8 `, S我们首先来看一个简单的程序示例,借此来说明sklearn库中,ROC曲线的实现细节。: @; N0 ^+ [/ I
2 j/ N$ }0 f2 K, K+ Y
4.3.1 roc_curve函数的参数
4 S  p% u) y. ?6 q  qimport numpy as np/ Y, u+ R8 l. j& A5 t6 Y$ F! b$ j# s
from sklearn.metrics import roc_curve, auc, roc_auc_score2 m1 ]) A: r: s0 M" e+ [4 C" L. I
y = np.array([0, 0, 1, 1])
) Y# Y! G0 L2 g4 I# S, \scores = np.array([0.2, 0.4, 0.35, 0.8])# @* E( z9 Q, I  o7 k
# 返回ROC曲线相关值。返回FPR,TPR与阈值。当分值达到阈值时,将样本判定为正类,6 r7 m5 d* G* V1 J8 n* T6 z
# 否则判定为负类。
. `+ A) N* D& A7 R& u2 a) V6 z: D# y_true:二分类的标签值(真实值)。
# Q6 |: g/ d9 C% m* r4 J4 W# y_score:每个标签(数据)的分值或概率值。当该值达到阈值时,判定为正例,否则判定为负例。' w$ i( F3 K. ~- p# A$ d% K
# 在实际模型评估时,该值往往通过决策函数(decision_function)或者概率函数(predict_proba)获得。
' h( i% d1 d, J' y# pos_label:指定正例的标签值。% P# s% F+ E% e6 e6 b/ O" ?( Q  Z
fpr, tpr, thresholds = roc_curve(y, scores, pos_label=1)
2 Y; ?* l1 m4 G4 z2 Tprint(f"fpr:{fpr}")" I+ }: T$ A/ E. {5 C% x" `- q1 L
print(f"tpr:{tpr}")
! B% A) c; ^6 r0 v1 ]print(f"thresholds:{thresholds}")
) {9 f9 ]8 f6 K# auc与roc_auc_score函数都可以返回AUC面积值,但是注意,两个函数的参数是不同的。
" f4 ]6 S4 J( \3 b: Zprint("AUC面积值:", auc(fpr, tpr))1 }/ v4 [4 F* f
print("AUC面积得分:", roc_auc_score(y_true=y, y_score=scores))
7 \8 X0 S8 D, X#### 3.3.2 roc_curve函数的返回值; I. K) i: d: V1 L
/ x! [# `' S- P/ d, L* l
结果:7 `) f3 w2 c4 Y: i- B+ a
17.png 1.8 是怎么来的?2 g, [2 B& T7 ^, @
1.8是阈值中最大值+1(0.8+1)得来的。为什么这么算?因为要使得最开始得到的所有阈值都不会超过这个值,才能过(0,0)和(1,1)这两个点。
- K, P: E1 P* q: B/ e( h# H! `: m& L3 M: V1 P" p" W# B' ]
4.3.2 roc_curve函数的返回值3 i* |* [3 O9 j3 `: N# L
# Z' K, f! c# |  g% ?% k
roc_curve函数具有3个返回值:
1 o- E7 Q) Q/ R3 U% I3 }+ w0 ~6 [( L- H8 V6 f
fpr 对应每个阈值(thresholds)下的fpr值。
3 v; ?0 p& O2 h1 C6 j; ttpr 对应每个阈值(thresholds)下的tpr值。
/ @  M5 Q3 i7 e( s! @: \thresholds 阈值。
6 J% a. t% P- z0 droc_curve函数会从y_score参数中,选择部分元素作为阈值(选择哪些元素属于实现细节,会根据sklearn版本的不同,也可能会有所差异。),然后进行降序排列,作为roc_curve函数的第3个返回值(thresholds)。同时,根据thresholds中的每个元素(阈值),分别计算fpr与tpr。
* u, I  s! ^1 V' A( }iris = load_iris()
: a0 ]) ]& X) V/ @' V" d0 pX, y = iris.data, iris.target
% Y4 L3 V0 l3 `9 h. Q# W( d! `X = X[y != 0, 2:]/ k' C8 O% }2 n! z; z. X' \0 d
y = y[y != 0]
, p* n! V1 X) Y! ay[y == 1] = 0' @& N) E' U4 D6 t$ m% B. o
y[y == 2] = 1
) [9 Z  g7 o) L1 s/ I; S4 DX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25,+ F8 _7 R4 A6 o1 B0 |) y  ~& f8 q
random_state=2), ?5 Z0 D5 j" g0 R/ o% r8 s, i3 u
# lr = LogisticRegression(multi_class="multinomial", solver="lbfgs")
3 Q! _6 S6 A9 x- h0 B4 {lr = LogisticRegression(multi_class="ovr", solver="liblinear")8 K& R; q4 K% G. r; P& w$ w0 w
lr.fit(X_train, y_train)% [* @7 ~8 D9 x$ B' X& e2 F
# 使用概率来作为每个样本数据的分值。" K8 V  e7 z: k6 O
probo = lr.predict_proba(X_test)0 E: Z- y& L, a' Y( ?7 ?, q
fpr, tpr, thresholds = roc_curve(y_true=y_test, y_score=probo[:, 1],
0 u* K. p0 N- v: X3 H% Spos_label=1)
( d+ x2 P. f$ L$ }7 i, k3 edisplay(probo[:, 1])
+ m/ [, H9 i7 p* d' k# 从概率中,选择若干元素作为阈值,每个阈值下,都可以确定一个tpr与fpr,
9 Q/ `" ~* M7 X& }" K" _+ |# 每个tpr与fpr对应ROC曲线上的一个点,将这些点进行连接,就可以绘制ROC曲线。; x4 m5 K& ]5 x; }! _
display(thresholds)# n8 O# _. ^  V1 m6 v, c

0 Q( [) [" b. t% E' K结果:$ d( @1 t4 T+ T: a& k# ?8 E
18.png , r8 Y0 \! [  c5 t; B+ [
9 y* z) \( U; X/ B: b! o* f' ?
3 E1 V4 t3 a) Q  G; F1 x9 M# ^# e
# 随着阈值的不断降低,fpr与tpr都在不断的增大。0 ~! ~, K1 W4 w, T2 O
fpr, tpr- \  U6 z* {) T, Q& l

4 |  ^0 ~" S) M* N5 I结果:8 u4 @& @. p9 c' c+ r
19.png ; J) g  }  V. Z8 ]

- y' N: o, B9 i# r4.3.3 绘制ROC曲线
, Z# c7 ]8 s1 Q; _有了fpr与tpr的值,绘制ROC曲线是非常容易的,只不过是最简单的一个plot而已。
1 d9 C7 M% M% y4 N$ L+ Bplt.figure(figsize=(10, 6)): f" B& ]+ t) E4 t( J; T
plt.plot(fpr, tpr, marker="o", label="ROC曲线")
2 X/ r, }" H3 lplt.plot([0,1], [0,1], lw=2, ls="--", label="随机猜测")* t6 |4 a0 k/ b! |
plt.plot([0, 0, 1], [0, 1, 1], lw=2, ls="-.", label="完美预测")2 B: x0 n3 z+ f4 q  f
plt.xlim(-0.01, 1.02)
& _/ p8 V+ n9 u4 g1 H; Aplt.ylim(-0.01, 1.02)
9 c# F* S# |" F% U7 Tplt.xticks(np.arange(0, 1.1, 0.1))# R4 m6 B. E6 `+ |4 C- h% e
plt.yticks(np.arange(0, 1.1, 0.1))2 p7 q+ u4 {! A
plt.xlabel("False Positive Rate(FPR)")
2 X! \( ]7 f$ U* Q7 cplt.ylabel("True Positive Rate(TPR)")
. ~, H/ V: ?  n; O+ @) F$ Yplt.grid(), q$ v- Z+ c" p+ _
plt.title(f"ROC曲线-AUC值为{auc(fpr, tpr):.2f}")3 v7 O4 K7 C& P, A
plt.legend()
! I# o( E5 _, g* zplt.show()
6 n3 J5 u7 K3 C& d' @ 20.png
/ S( Z5 w% R# p2 ~4 b7 S
% L" u. X& R3 e/ w/ l3 R( ~5、总结0 ]8 h; W$ {% e# S: i

! _$ W3 _. K1 d- \混淆矩阵的含义。. B1 r  S8 P* b
正确率,精准率,召回率与调和平均值F1的含义。3 w! p9 k$ k0 i, m& O* G+ S
ROC与AUC。
" \0 t5 \" |, @5 Q% a6 y3 S8 P) J3 B/ w
参考资料:& _0 G. M0 W, d
1、https://blog.csdn.net/zuolixiangfisher/article/details/81328297
; x7 y& H! W2 _. S5 t' E' g2、https://www.jianshu.com/p/2feb00839154
. R9 S; P! K' n" p& K3、https://www.cnblogs.com/kamekin/p/9788730.html
2 r7 B7 h2 C; G4、https://www.jianshu.com/p/c61ae11cc5f6
9 g5 u' j: `& p, V————————————————
0 U$ ^) j0 t; b1 O# c4 N版权声明:本文为CSDN博主「糖潮丽子~辣丽」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。+ d5 h: |- d7 z' ?9 @+ G
原文链接:https://blog.csdn.net/qq_39783601/article/details/105600700. p+ M9 M8 q, {* G& _/ b. N" Z3 W, e
! f+ W- ]0 Z- Y, R% M; k
0 J! U$ w0 v- u2 x( o1 A

作者: 1336671542    时间: 2020-4-19 12:50
非常感谢!!!!!!!!!!
& j! }$ N; F: f: K. Z! H




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5