對於迴歸問題,一般有 MSE、MAE、RMSE、R^2 四種方法來評判模型的效果。對於分類問題,最簡單的辦法是採用準確率來評估模型的效果。好比 sklearn 中對於分類問題默認的 score 都是根據準確率來統計的。python
使用準確率來評估理解很是簡單,可是對於極度偏斜的數據的預測會有很大問題。好比對於癌症預測問題,健康 vs 患病的比例多是 10000:1。對於這種極度偏斜的數據,咱們能夠作一個最簡單的模型,直接預測全部樣本都屬於健康類,這樣模型準確率均可以達到 99.99%。git
對於這類型數據,分類算法模型的 score 能夠藉助混淆矩陣來評估。算法
下面爲了方便解釋混淆矩陣以及準確率和召回率等名詞術語,先以二分類問題爲例來分析。app
真實/預測 | 0 | 1 |
---|---|---|
0 | TN | FP |
1 | FN | TP |
上面說的有些抽象,下面舉一個具體的例子。dom
真實/預測 | 0 | 1 |
---|---|---|
0 | 9980 | 10 |
1 | 3 | 7 |
對於精準率的定義是:預測關注事件的結果中(總共 17 次)預測正確的機率,7 次正確,10 次錯誤。post
精準率 = TP / (TP + FP) = 7 / (10+7),也就是說沒作 17 次患病預測的時候,平均有 7 次正確的。spa
召回率的定義是:對所關注的類型(也就是 10 個患者),將其預測出的機率(預測出 7 個)。code
召回率 = TP / (TP + FN) = 7 / (7 + 3) = 70%,也就是說每當有 100 個患者,算法平均可以成功找出 70 個,會漏掉 30 個。cdn
對於有些場景,選擇精準率更合適,好比股票預測場景,要預測股票是漲仍是降,業務需求是更精準的找到可以上升的股票。而對於疾病預測場景,要預測就診人員是否患病,這個時候的業務需求是找出全部患病的病人不要漏掉任何一個患者,能夠說將健康者診斷爲患者可能沒太多關係,只要不將患者診斷爲健康者。blog
可是在有些場景,須要同時綜合精準率和召回率,這個時候怎麼辦呢?可使用 f1-score 來解決,f1 是精準率和召回率的調和平均值:
爲了演示上面提到的三個概念,首先咱們先構建一個極度偏斜的數據,咱們選擇 sklearn 提供手寫識別數據集,自己在這個數據集中,0-9 十個數字都分佈比較均勻,咱們將這個十分類數據轉換成二分類數據,一類等於 9,另一類不等於 9 來製造數據偏斜。
import numpy as np
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()
y[digits.target==9] = 1
y[digits.target!=9] = 0
複製代碼
使用邏輯迴歸來進行預測:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
log_reg.score(X_test, y_test)
複製代碼
因爲數據是極度偏斜的,即便預測全部樣本的類型都是 0,準確度都能達到 90% 左右。準確度只能說明模型對每個樣本預測的準確度,並不能真正準確找出類型爲 1 的樣本,也就是說準確度並不能反映模型是否精準找出了類型爲 1 的樣本。sklearn metrics 包中直接提供了對於混淆矩陣、精準率、召回率的支持。
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, y_log_predict)
from sklearn.metrics import precision_score
precision_score(y_test, y_log_predict)
from sklearn.metrics import recall_score
recall_score(y_test, y_log_predict)
from sklearn.metrics import f1_score
f1_score(y_test, y_log_predict)
複製代碼
對於二分類問題,咱們能夠調節分類邊界值來調節精準率和召回率的比重。score > threshold 時分類爲 1,score < threshold 時分類爲 0。閾值增大,精準率提升,召回率下降;閾值減少,精準率下降,召回率提升。精準率和召回率是相互牽制,互相矛盾的兩個變量,不能同時增高。
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()
y[digits.target==9] = 1
y[digits.target!=9] = 0
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
decision_scores = log_reg.decision_function(X_test)
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
precisions = []
recalls = []
thresholds = np.arange(np.min(decision_scores), np.max(decision_scores), 0.1)
for threshold in thresholds:
y_predict = np.array(decision_scores >= threshold, dtype='int')
precisions.append(precision_score(y_test, y_predict))
recalls.append(recall_score(y_test, y_predict))
複製代碼
plt.plot(precisions, recalls)
plt.show()
複製代碼
ROC(Receiver Operation Characteristic Curve)用來描述 TPR 和 FPR 之間的關係,其中:
import numpy as np
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()
y[digits.target==9] = 1
y[digits.target!=9] = 0
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
decision_scores = log_reg.decision_function(X_test)
from sklearn.metrics import roc_curve
fprs, tprs, thresholds = roc_curve(y_test, decision_scores)
import matplotlib.pyplot as plt
plt.plot(fprs, tprs)
plt.show()
複製代碼
ROC 曲線與圖形邊界圍成的面積,做爲衡量模型優劣的標準,面積越大,模型越優。