分类器性能评价:图形方法(1)

时间:2022-12-08 10:25:32

原文地址:http://site.douban.com/182577/widget/notes/10567212/note/348006411/

1.几个基本概念

对于二元分类器,我们可以把分类样本的真实值记为1(positive,正例/阳性),-1(或0,negative,负例/阴性)分类结果记作1(success)和-1(或0,failure)。分类器分类正确,为真(true);分类器分类错误为假(false) 那么分类结果会有四种可能: TP,真正例/真阳性,预测为1且预测正确 TN,真反例/真阴性,预测为-1且预测正确 FP,假正例/假阳性,预测为1且预测错误 FN,假反例/假阴性,预测为-1且预测错误

把上面的这四种结果构造列联表,就得到混淆矩阵(Confusion Matrix)

例:使用caret包的GermanCredit数据。信用卡的评分,包括多个预测变量,其中多数为0-1属性变量。分类为Good和Bad两类。采用logistic回归作为分类器,输出结果是分类为正例的概率。对这个概率取一个阈值(这里取的是1/2),大于阈值的判为正例小于阈值的判为反例。

library(caret)
## Loading required package: lattice
## Loading required package: ggplot2
data(GermanCredit)
GermanCredit$Class <- factor(GermanCredit$Class, levels = c("Bad", "Good", 0, 
    1))
class <- GermanCredit$Class
GermanCredit$Class[which(class == "Bad")] <- 0
GermanCredit$Class[which(class == "Good")] <- 1
GermanCredit$Class <- factor(GermanCredit$Class, levels = c(0, 1))
# remove near-zero variance predictors then get rid of a few predictors that
# duplicate values
GermanCredit <- GermanCredit[, -nearZeroVar(GermanCredit)]
GermanCredit$CheckingAccountStatus.lt.0 <- NULL
GermanCredit$SavingsAccountBonds.lt.100 <- NULL
GermanCredit$EmploymentDuration.lt.1 <- NULL
GermanCredit$EmploymentDuration.Unemployed <- NULL
GermanCredit$Personal.Male.Married.Widowed <- NULL
GermanCredit$Property.Unknown <- NULL
GermanCredit$Housing.ForFree <- NULL

# create training amd prediction datasets
set.seed(1)
train <- sample(1:1000, 900)
credit.train <- GermanCredit[train, ]
credit.test <- GermanCredit[-train, ]
credit.glm <- glm(Class ~ ., family = binomial, data = credit.train)
# Now to prediction
credit.p <- predict(credit.glm, newdata = credit.test, type = "response")
credit.n <- data.frame(credit.test$Class, credit.p)
head(credit.n)
## credit.test.Class credit.p
## 16 0 0.4874
## 18 1 0.1227
## 19 0 0.5552
## 26 1 0.8185
## 27 1 0.8539
## 43 1 0.8482

# set cutoff=1/2
cut = 1/2
Class.p <- floor(credit.p + cut)
confusion <- table(credit.test$Class, Class.p)
# confunsion matrix
confusion
## Class.p
## 0 1
## 0 15 13
## 1 10 62
记全部样本个数为T,正例个数为P,负例个数为N。 可以计算各种比率,其中TPR=TP/P称为灵敏度(sensitivity)/召回率(recall), TNR=TN/N称为特指度(specicity),FPR=FP/P称误警率(Fallout),FNR=FP/N称为漏查率(miss).
分类器预测正确的比例称正确率(accuracy):(TP+TN)/T 分类器预测错误的比例称错误率(error rate):(FP+FN)/T


TP <- confusion[4]
TN <- confusion[3]
FP <- confusion[2]
FN <- confusion[1]
N <- sum(credit.test$Class == 0)
P <- sum(credit.test$Class == 1)
TPR <- TP/P
TNR <- TN/N
FPR <- FP/P
FNR <- FP/N
ACC <- (sum(TN) + sum(TP))/sum(confusion)
ERR <- (sum(FN) + sum(FP))/sum(confusion)
很多时候,我们更关心正例的分类精确与否,因此可以定义下面两个比率: TPR又可称为查全率,表示正确分类的正例占实际正例(TP/(TP+FN))的比例,用于衡量分类器预测正例的可信程度。 相对应的概念有查准率(precision),表示正确分类的正例占全部预测正例的比例(TP/(TP+FP))。

ROC和AUC
对于更关注于正例的情况,ROC(Receiver Operating Characteristic)是很常用的一种图形评价方法。 ROC曲线使用了上面定义的两种比率,灵敏度和误警率。 sensitivity(TPR):正确分类的正例数占实际正例的比例; specicity(TNR):正确分类的反例数占实际反例的比例; 1-specicity=FPR,错误分类的反例(“报警”)占实际反例的比例。 ROC曲线描述的是二元分类器TPR和FPR的相对变化情况。

如果二元分类模型输出的是分类为正例的概率,那么设置分类一个阈值就可以计算相应阈值下的sensitivity和1-specicity。如果取一组阈值,把对每个阈值计算得到的sensitivity和1-specicity绘制在图中,就得到ROC曲线。ROC曲线表示在尽量少的误判的基础上,尽可能多的判出正例的个体。

roc <- function(p, y, n) {
    y <- factor(y)
    l <- length(p)
    criteria <- p > matrix(rep(seq(1, 0, length = n), l), ncol = n, byrow = T)
    fpr <- colSums((y == levels(y)[1]) * criteria)/sum(y == levels(y)[1])
    tpr <- colSums((y == levels(y)[2]) * criteria)/sum(y == levels(y)[2])
    roc <- data.frame(tpr, fpr)
}
roc.result <- roc(credit.p, credit.test$Class, 100)
library(ggplot2)
ggplot(roc.result, aes(x = fpr, y = tpr)) + geom_line(color = "blue") + 
geom_segment(aes(x = 0, y = 0, xend = 1, yend = 1), color = "grey", lty = 2)

分类器性能评价:图形方法(1)
 



如果ROC曲线可以经过点(0,1),即特指度和灵敏度都是1,那么就是一个最优的分类器。但是绝大多数分类器做不到这一点。因此,引入AUC:ROC曲线下的面积来度量不同分类器的表现。AUC越大,则分类性能越好。