1.評估分類方法的性能
- 擁有能夠度量實用性而不是原始准確度的模型性能評價方法是至關重要的。
- 3種數據類型評價分類器:真實的分類值;預測的分類值;預測的估計概率。之前的分類算法案例只用了前2種。
- 對於單一預測類別,可將predict函數設定為class類型,如果要得到預測的概率,可設為為prob、posterior、raw或probability等類型。predict大部分情況下返回對結果不同水平的預測概率。
#朴素貝斯分類的預測概率
predicted_prob=predict(model,test_data,type="raw")
#決策樹C5.0分類器
predicted_proc=predict(model,test_data,type="prob")
- 一般而言,預測值和真實值都是同一類時的預測概率會比較極端(接近0或1),但總有一些相反的,概率值介於中間,這時判斷模型是否可用,可通過對測試數據應用各種誤差度量的方法。
# obtain the predicted probabilities
sms_test_prob <- predict(sms_classifier, sms_test, type = "raw")
head(sms_test_prob)
1.1 混淆矩陣
混淆矩陣是一張二維表(第一維是所有可能的預測類別,第二維是真實的類別),按照預測值是否匹配真實值來對預測值進行分類。二值分類是2X2混淆矩陣,三值分類模型是3X3混淆矩陣。
- 陽性和陰性:相對的概念,無任何隱含的價值判斷。一般將感興趣的類別(或目標)設為陽性。
- 度量性能:准確度(成功率)
- 錯誤率
gmodels::CrossTable
代碼示例:
數據下載鏈接: https://pan.baidu.com/s/1YiFdOHX8rWrVKB97FRY8Iw 提取碼: eka6
## Confusion matrixes in R ----
sms_results <- read.csv("sms_results.csv")
# the first several test cases
head(sms_results)
# test cases where the model is less confident
head(subset(sms_results, prob_spam > 0.40 & prob_spam < 0.60))
# test cases where the model was wrong
head(subset(sms_results, actual_type != predict_type))
# specifying vectors
table(sms_results$actual_type, sms_results$predict_type)
# alternative solution using the formula interface (not shown in book)
xtabs(~ actual_type + predict_type, sms_results)
# using the CrossTable function
library(gmodels)
CrossTable(sms_results$actual_type, sms_results$predict_type)
# accuracy and error rate calculation --
# accuracy
(152 + 1203) / (152 + 1203 + 4 + 31)
# error rate
(4 + 31) / (152 + 1203 + 4 + 31)
# error rate = 1 - accuracy
1 - 0.9748201
1.2 其他評價指標
分類和回歸訓練R包caret提供了更多的計算性能度量指標的函數。
## Beyond accuracy: other performance measures ----
library(caret)
confusionMatrix(sms_results$predict_type,
sms_results$actual_type,
positive = "spam") #檢測垃圾信息是目標,將其設為陽性
1)Kappa統計量
- Kappa對准確度進行調整,表示的是預測值和真實值之間的一致性。
- Kappa計算公式:
Pr是預測值和真實值之間的真實一致性a和期望一致性e的比例。Kappa統計量使用期望的一致性Pr(e)對准確度進行調整,Pr(e)是完全的偶然性導致的預測值和實際值相同的概率。
計算示例:
pr(a)=0.865+0.111=0.976
pr(e)=0.868*0.886+0.132*0.114=0.784096
kappa=(pr(a)-pr(e))/(1-pr(e))=0.89
- 其他計算Kappa的函數:
# calculate kappa via the vcd package
library(vcd)
Kappa(table(sms_results$actual_type, sms_results$predict_type))
- vcd::Kappa函數計算出來的kappa有加權和沒加權的,對於二分類,加不加權都一樣,一般關注不加權的就好。加權主要用於存在不同尺度一致性的情況。
# calculate kappa via the irr package
library(irr)
kappa2(sms_results[1:2])
- irr::kappa2函數可直接使用數據框中的預測值向量和實際分類向量來計算Kappa值。
注意不要用內置的kappa函數,它與Kappa統計量沒關系。
2)靈敏度與特異性
- 用來權衡做決策時保守or激進的度量。權衡時最典型的做法是:對模型進行調整或者使用不同的模型,直到能通過靈敏度和特異性的閾值為止。
- 靈敏度(真陽性率):度量陽性樣本被正確分類的比例。
- 特異性(真陰性率):度量陰性樣本被正確分類的比例。
如上面的混淆矩陣中,手動計算:
# Sensitivity and specificity
# example using SMS classifier
sens <- 152 / (152 + 31)
sens
spec <- 1203 / (1203 + 4)
spec
caret包中的sensitivity和specificity函數可直接計算:
# example using the caret package
library(caret)
sensitivity(sms_results$predict_type,
sms_results$actual_type,
positive = "spam")
specificity(sms_results$predict_type,
sms_results$actual_type,
negative = "ham")
3)精確度與回溯精確度
- 這兩者也與分類時的折中方案有關。
- 精確度(陽性預測值):真陽性在所有預測為陽性案例中的比例。
- 回溯精確度:度量結果的完備性,真陽性與陽性總數的比例(計算與靈敏度一樣,只是解釋不同:捕捉大量陽性樣本,具有很寬的范圍)。
手動計算:
# Precision and recall
prec <- 152 / (152 + 4)
prec
rec <- 152 / (152 + 31)
rec
caret包中的posPredValue函數計算:
# example using the caret package
library(caret)
posPredValue(sms_results$predict_type,
sms_results$actual_type,
positive = "spam")
sensitivity(sms_results$predict_type,
sms_results$actual_type,
positive = "spam")
4)F度量
- F度量(F1記分/F記分):將精確度和回溯精確度合並成一個單一值(通過調和平均值來整合)的模型性能度量方式。
計算:
# F-measure
f <- (2 * prec * rec) / (prec + rec)
f
f <- (2 * 152) / (2 * 152 + 4 + 31)
f
- 整合成一個單一值比較方便,但需要假設精確度和回溯精確度具有同樣的權重。
1.3 性能權衡可視化(ROC曲線)
- 可視化可以考察度量如何在大范圍的值之間變化,還可以在單個圖形中同時比較多個分類器的方法。
- ROC(受試者工作特征)曲線:常用來檢查在找出真陽性和避免假陽性之間的權衡。
- ROC曲線橫軸表假陽性比例(1-特異性),縱軸表真陽性比例(靈敏度),所以也稱為靈敏度/特異性圖。
- ROC曲線上的點表示不同假陽性閾值上的真陽性的比例。
- AUC(Area Under the ROC):ROC曲線下面積來度量識別陽性值的能力。位於0.5(無預測值分類器)-1(完美分類器)之間,解釋AUC得分可參考(比較主觀):
- ROC+AUC:兩個ROC曲線可能形狀不同,但具有相同的AUC,因此AUC可能具有誤導性,最好是和ROC曲線定性分析結合使用。
代碼示例:
## Visualizing Performance Tradeoffs ----
library(ROCR)
pred <- prediction(predictions = sms_results$prob_spam,
labels = sms_results$actual_type)
# ROC curves
perf <- performance(pred, measure = "tpr", x.measure = "fpr")
plot(perf, main = "ROC curve for SMS spam filter", col = "blue", lwd = 2)
# add a reference line to the graph
abline(a = 0, b = 1, lwd = 2, lty = 2)
定性分析可看到上圖ROC曲線占據了圖形左上角的區域,接近完美分類器;定量分析則通過函數來計算AUC。
# calculate AUC
perf.auc <- performance(pred, measure = "auc")
#返回S4對象,存儲信息的位置稱為槽(slots),槽的前綴為@
str(perf.auc) #查看所有槽
unlist(perf.auc@y.values) #簡化為數值向量
AUC值可達到0.98。但這個模型對其他數據集是否也表現好呢?需要測試外部數據來推斷模型的預測性能。
2.評估未來的性能
- 當訓練數據進行了錯誤的預測時會產生再帶入誤差。與信賴再帶入誤差相比,更好的方式時評估模型對其從未見過數據的性能。一般就是將數據分為訓練集和測試集,但當數據集很小時,這樣的划分會減小樣本量,是不合適的。
2.1 保持法
- 保持法就是常見的數據划分訓練集和測試集的過程:訓練集用來生成模型,應用到測試集來生成預測結果進行評估。一般1/3的數據用於測試,2/3用於訓練。
- 保持法不允許測試集的結果影響模型,但如果基於重復測試的結果選擇一個最好的模型,則會違反這個原則。因此可再分出第三個數據集,集驗證集。(注:前面的章節中我們只划分了訓練和測試集兩類數據,實際上違反了這一原則,那些測試集更准確地應該稱為驗證集。如果我們使用測試集來做決策,從結果中挑選最好的模型,那么評估將不再是對未來性能的無偏估計)
- 驗證集用來對模型迭代和改善。測試集只使用一次,最后輸出對未來預測的錯誤率估計。一般數據划分50%訓練集,25%測試集,25%驗證集。
- 分層隨機抽樣:確保隨機划分后每個類別的比例與總體數據中的比例近似相等。可用caret:::createDataPartition函數實現。
數據下載鏈接: https://pan.baidu.com/s/1O9JYXUZnQfVGIU-VWGTptA 提取碼: 7q7q
# partitioning data
library(caret)
credit <- read.csv("credit.csv")
# Holdout method
# using random IDs
random_ids <- order(runif(1000))
credit_train <- credit[random_ids[1:500],]
credit_validate <- credit[random_ids[501:750], ]
credit_test <- credit[random_ids[751:1000], ]
# using caret function
#返回行號
in_train <- createDataPartition(credit$default,
p = 0.75, #該划分中樣本的比例
list = FALSE) #防止結果存儲成列表
credit_train <- credit[in_train, ]
credit_test <- credit[-in_train, ]
- 一般的,模型在更大的數據集中訓練可得到更好的性能,所以常見的做法是:在選擇和評估了最終的模型之后,將模型在整個數據集(訓練集+測試集+驗證集)上重新訓練,使模型最大化地利用所有數據。
- 重復保持法:保持法的一種特殊形式,對多個隨機保持樣本的模型分別評估,然后用結果的均值來評價整個模型的性能。
2.2 交叉驗證
- 重復保持法使k折交叉驗證(k折CV,將數據隨機分成k個完全分隔的部分)的基礎,k折交叉驗證已稱為業界評估模型性能的標准。
- 最常用10折交叉驗證(每一折包含總數據的10%),機器學習模型使用剩下的90%數據建模,包含10%數據的這一折用來評估,訓練和評估模型進行不同的10次,將輸出所有折的平均性能指標。
- 留一交叉驗證法:將每個樣本作為1折,用最大數目的樣本來建模,但計算量太大,很少用。
- 使用caret::createFolds函數創建交叉驗證數據集:
# 10-fold CV
folds <- createFolds(credit$default, k = 10)
str(folds)
credit01_test <- credit[folds$Fold01, ]
credit01_train <- credit[-folds$Fold01, ]
可以用不同數據集手動執行以上步驟10次,然后建模評估,最后將所有性能度量取均值作為總體的性能。但我們肯定可以通過編程來實現自動化,這里以10折CV建立C5.0決策樹模型為例,然后估計Kappa統計量:
## Automating 10-fold CV for a C5.0 Decision Tree using lapply() ----
library(caret)
library(C50)
library(irr)
credit <- read.csv("credit.csv")
set.seed(123)
folds <- createFolds(credit$default, k = 10)
cv_results <- lapply(folds, function(x) {
credit_train <- credit[-x, ]
credit_test <- credit[x, ]
credit_model <- C5.0(default ~ ., data = credit_train)
credit_pred <- predict(credit_model, credit_test)
credit_actual <- credit_test$default
kappa <- kappa2(data.frame(credit_actual, credit_pred))$value
return(kappa)
})
str(cv_results)
mean(unlist(cv_results))
kappa值很低,總體模型性能差,下一章會講如何改進。
2.3 自助法抽樣
- 自助法抽樣(bootstrap):主要指一些統計方法,通過對數據進行隨機抽樣的方式來估計大數據集的內容。各種隨機產生的數據集的結果可以通過平均值計算得到一個最終的估計值,用來評估未來的性能。
- 與k折CV的不同:交叉驗證將數據分隔開來,每個樣本只能出現一次,而自助法是有放回的抽樣,每個樣本可以被選擇多次。因此自助法抽樣對完整數據集的代表性更弱,但它對於小數據集的效果更好。除了度量性能之外,它還能提高模型性能。
- 0.632自助法:每個樣本包含在訓練集中的概率是63.2%。通過訓練數據集(過於樂觀)和測試集(過於悲觀)的函數來計算最終的性能度量:
機器學習與R語言系列推文匯總:
【機器學習與R語言】1-機器學習簡介
【機器學習與R語言】2-K近鄰(kNN)
【機器學習與R語言】3-朴素貝葉斯(NB)
【機器學習與R語言】4-決策樹
【機器學習與R語言】5-規則學習
【機器學習與R語言】6-線性回歸
【機器學習與R語言】7-回歸樹和模型樹
【機器學習與R語言】8-神經網絡
【機器學習與R語言】9-支持向量機
【機器學習與R語言】10-關聯規則
【機器學習與R語言】11-Kmeans聚類
【機器學習與R語言】12-如何評估模型的性能?
【機器學習與R語言】13-如何提高模型的性能?