如何判別模型的優劣?


引言

  選擇用於評估機器學習算法的指標非常重要。度量的選擇會影響如何測量和比較機器學習算法的性能。 它們會影響您如何權衡結果中不同特征的重要性以及您選擇哪種算法的最終選擇。在這篇文章中,您將了解如何使用scikit-learn在Python中選擇和使用不同的機器學習性能指標。

回歸問題:

  • 平均絕對誤差
  • 均方誤差
  • 均方根誤差
  • R2

分類問題:

  • Classification Accuracy 分類問題准確率
  • Logarithmic Loss 對數損失函數
  • Confusion Matrix 混淆矩陣
  • Area Under ROC Curve   ROC曲線下的面積
  • Classification Report 分類報告

更多參考:here

回歸問題

平均絕對誤差(Mean Absolute Error)

  平均絕對誤差(MAE)是預測值與實際值之間的絕對差值之和。該度量給出了誤差幅度的概念,但不知道方向(例如,過度或低於預測),MSE可以評價數據的變化程度,MSE的值越小,說明預測模型描述實驗數據具有更好的精確度。

以下示例演示了計算波士頓房價數據集的平均絕對誤差。

# Cross Validation Regression MAE
import pandas
from sklearn import model_selection
from sklearn.linear_model import LinearRegression

url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.data"
names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']

dataframe = pandas.read_csv(url, delim_whitespace=True, names=names)
array = dataframe.values
X = array[:,0:13]
Y = array[:,13]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LinearRegression()
scoring = 'neg_mean_absolute_error'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)
print(("MAE: (%.3f.) (%.3f.)") % (results.mean(), results.std()))

MAE: (-4.005.) (2.084.

均方誤差(Mean Squared Error)

  MSE是參數估計值與參數真值之差的平方的期望值

這個應用應該是最廣的,因為他能夠求導,所以經常作為loss function。計算的結果就是你的預測值和真實值的差距的平方和。

# Cross Validation Regression MSE
import pandas
from sklearn import model_selection
from sklearn.linear_model import LinearRegression
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.data"
names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
dataframe = pandas.read_csv(url, delim_whitespace=True, names=names)
array = dataframe.values
X = array[:,0:13]
Y = array[:,13]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LinearRegression()
scoring = 'neg_mean_squared_error'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)
print(("MSE: (%.3f.) (%.3f.)") % (results.mean(), results.std()))

MSE: (-34.705.) (45.574.)

均方根誤差(Root Mean Square Error)

 均方根值(RMSE):也稱方均根值有效值,它的計算方法是先平方、再平均、然后開方。

  • 是觀測值與真值偏差的平方和與觀測次數m比值的平方根。
  • 是用來衡量觀測值同真值之間的偏差

 

R2

R ^ 2(或R Squared)度量提供了一組預測與實際值的擬合優度的指示。 在統計文獻中,該度量被稱為可決系數。對於不適合和完美貼合,這是介於0和1之間的值。

表達式:R2=SSR/SST=1-SSE/SST

其中:SST=SSR+SSE,SST(total sum of squares)為總平方和,SSR(regression sum of squares)為回歸平方和,SSE(error sum of squares) 為殘差平方和。

以下示例提供了計算一組預測的平均R ^ 2的演示.

import pandas
from sklearn import model_selection
from sklearn.linear_model import LinearRegression
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.data"
names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
dataframe = pandas.read_csv(url, delim_whitespace=True, names=names)
array = dataframe.values
X = array[:,0:13]
Y = array[:,13]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LinearRegression()
scoring = 'r2'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)
print(("R^2: (%.3f.) (%.3f.)") % (results.mean(), results.std()))

R^2: (0.203.) (0.595.)

note:scoring可選

['accuracy', 'adjusted_mutual_info_score', 'adjusted_rand_score', 'average_precision', 
'completeness_score', 'explained_variance', 'f1', 'f1_macro', 'f1_micro', 'f1_samples', 'f1_weighted', 'fowlkes_mallows_score', 'homogeneity_score', 'mutual_info_score',
'neg_log_loss', 'neg_mean_absolute_error', 'neg_mean_squared_error', 'neg_mean_squared_log_error', 'neg_median_absolute_error', 'normalized_mutual_info_score', 'precision',
'precision_macro', 'precision_micro', 'precision_samples', 'precision_weighted', 'r2', 'recall', 'recall_macro', 'recall_micro', 'recall_samples', 'recall_weighted', 'roc_auc',
'v_measure_score']

分類問題

分類的准確率(Classification Accuracy )

確定准確度是作為所有預測的比率而作出的正確預測的數量。

這是分類問題最常見的評估指標,也是最常用的評估指標。 它實際上只適用於每個類別中觀察數量相同的情況(很少這種情況),並且所有預測和預測誤差都同樣重要。

以下是計算分類准確度的示例。
# Cross Validation Classification Accuracy
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LogisticRegression()
scoring = 'accuracy'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)
print(("Accuracy: (%.3f.) (%.3f.)") % (results.mean(), results.std()))

Accuracy: (0.770.) (0.048.)

 對數損失函數(Logarithmic Loss)

對數損失(或logloss)是用於評估給定類的成員概率的預測的性能度量。可以將0和1之間的標量概率視為對算法預測的置信度的度量。 正確或不正確的預測會與預測的置信度成比例地得到獎勵或懲罰。

以下是計算Pima Indians糖尿病數據集開始時Logistic回歸預測的logloss的示例。

# Cross Validation Classification LogLoss
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LogisticRegression()
scoring = 'neg_log_loss'
results = model_selection.cross_val_score(model, X, Y, cv=kfold, scoring=scoring)
print(("Logloss:( %.3f.) (%.3f.)") % (results.mean(), results.std()))

Logloss:( -0.492.) (0.047.)

混淆矩陣(Confusion Matrix)

  混淆矩陣是具有兩個或更多類的模型的准確性的便利表示。 該表提供了關於x軸的預測和y軸上的准確度結果。 表格的單元格是機器學習算法所做的預測次數。
例如,機器學習算法可以預測0或1,並且每個預測實際上可以是0或1.對於0的實際為0的預測出現在用於預測的單元格中= 0並且實際= 0,而對於0的預測是0  實際上1出現在單元格中,用於預測= 0和實際= 1。

 

其中,精准率(accracy),召回率(recall)和F1得分將在分類報告中給出。

# Cross Validation Classification Confusion Matrix
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
url
= "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = pandas.read_csv(url, names=names) array = dataframe.values
X
= array[:,0:8] Y = array[:,8]

test_size = 0.33
seed = 7
X_train, X_test, Y_train, Y_test = model_selection.train_test_split(X, Y, test_size=test_size, random_state=seed)
logreg = LogisticRegression()
logreg.fit(X_train, Y_train)

 

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,

          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
          penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False)

# make class predictions for the testing set
y_pred_class = logreg.predict(X_test) 

 分類准確度(Classification accuracy):正確預測的百分比

# calculate accuracy
from sklearn import metrics
print(metrics.accuracy_score(Y_test, y_pred_class))

0.7559055118110236

 分類准確率為69%。

混淆矩陣(Confusion Matrix)

matrix = confusion_matrix(Y_test, y_pred_class)
print(matrix)

[[141  21]
 [ 41  51]]
   n =
254

Predicted:

0

Predicted:

1

Actual:

0

141 21

Actual:

1

41 51

 

 

 

 

 

 

 

測試集中的每個觀察都只用一個框表示,它是一個2x2矩陣,因為有2個響應類.

注意:此處的矩陣與圖的格式並不一致。

基本術語

  • 真陽性(True Positive,,TP):我們正確地預測他們確實患有糖尿病
  • 51
  • 真陰性(Ture Negatives,TN):我們正確地預測他們沒有糖尿病
  • 141
  • 誤報(False Positives,FP):我們錯誤地預測他們確實患有糖尿病(“I型錯誤”)
  • 21
  • 虛假地預測積極的
  • 輸入I錯誤
  • 假陰性(False Negatives,FN):我們錯誤地預測他們沒有糖尿病(“II型錯誤”)
  • 41
  • 虛假地預測消極
  • II型錯誤
  • 0: negative class
  • 1: positive class
# save confusion matrix and slice into four pieces
confusion = metrics.confusion_matrix(Y_test, y_pred_class)
print(confusion)
#[row, column]
TP = confusion[1, 1]
TN = confusion[0, 0]
FP = confusion[0, 1]
FN = confusion[1, 0]

[[
141 21] [ 41 51]] 

 根據混淆矩陣計算度量

分類准確度

# use float to perform true division, not integer division
print((TP + TN) / float(TP + TN + FP + FN))
#用於對比
print(metrics.accuracy_score(Y_test, y_pred_class))

0.7559055118110236
0.7559055118110236

結果一致 .

分類錯誤(Classification Error)

也被稱為誤分類率(Misclassification Rate)

classification_error = (FP + FN) / float(TP + TN + FP + FN)

print(classification_error)
print(1 - metrics.accuracy_score(Y_test, y_pred_class))

0.2440944881889764
0.2440944881889764

靈敏度(Sensitivity

靈敏度(Sensitivity):當實際值為正時,預測的正確頻率是多少?即分類正確的正樣本個數占正樣本個數的比例。我們想要最大化的東西,測正面實例的分類器有多“敏感”。

也被稱為“真正的正面率(True Positive Rate)”或“召回率(Recall)”

  • TP /全部為陽性
      •  Rcall= TP / TP + FN
sensitivity = TP / float(FN + TP)

print(sensitivity)
print(metrics.recall_score(Y_test, y_pred_class))


0.5543478260869565
0.5543478260869565

 特異性(Specificity)

特異性:當實際值為負時,預測正確的頻率是多少?即分類正確的負樣本個數占負樣本個數的比例我們想要最大化的東西,在預測正面實例時,“特定”(或“選擇性”)是如何分類的?

  • TN /全部為負數
      • TN= TN + FP
specificity = TN / (TN + FP)

print(specificity)

0.8703703703703703

可以看出,我們的分類器:高特異性,不靈敏。

誤報率(False Positive Rate)

誤報率:當實際值為負時,預測錯誤的頻率是多少?即分類錯誤的正樣本個數占總分類錯誤樣本個數的比例。

false_positive_rate = FP / float(TN + FP)

print(false_positive_rate)
print(1 - specificity)

0.12962962962962962
0.12962962962962965

精度(Precision)

精度:預測正值時,預測的正確頻率是多少?

在預測正面實例時,分類器的“精確”程度如何?

precision = TP / float(TP + FP)

print(precision)
print(metrics.precision_score(Y_test, y_pred_class))

0.7083333333333334
0.7083333333333334

 F1得分

以上討論了precise(精確率)recall(召回率),接下來將使用一個新的機器學習指標F1分數,F1分數會同時考慮精確率和回召率,以便重新計算新的分數。

F1分數可以理解為:精確率和召回率的加權平均值。其中F1分數的最佳為1,最差為0;

F1 = 2 * (precise * recall)  /  (precise + recall)

f1_score = 2*( precision*sensitivity)/(precision+sensitivity)

print(f1_score)
print(metrics.f1_score(Y_test, y_pred_class))

0.6219512195121951
0.6219512195121951

 宏F1得分(Macro F1)

我們已經知道,標准F1分數,即精度和召回的調和平均值:

對於多類問題,我們必須平均每個類的F1分數。 宏觀F1分數平均每個級別的F1分數,而不考慮標簽不平衡。

換句話說,當使用宏時,每個標簽的出現次數不計入計算中.

 有關差異的更多信息,請查看針對F1分數的Scikit-Learn文檔 (Scikit-Learn Documention for F1 Score ) 或Stack Exchange問題和答案Stack Exchange question and answers.

from sklearn.metrics import f1_score
f1_score(y_true, y_predicted, average = 'macro`)

分類報告

分類報告可以方便簡潔的幫助我們得到各項指標

report=metrics.classification_report(Y_test, y_pred_class)
print(report)

更進一步

據混淆矩陣計算度量,調整分類閾值(threshold)。

# print the first 10 predicted responses
# 1D array (vector) of binary values (0, 1)
logreg.predict(X_test)[0:10]

array([0., 1., 1., 0., 0., 0., 0., 0., 1., 0.])
# print the first 10 predicted probabilities of class membership
logreg.predict_proba(X_test)[0:10]

從直接的結果到概率的輸出,可以更直觀看到概率情況。

預測概率的重要性

我們可以根據糖尿病的概率對觀察結果進排序,優先選擇那些概率更高的人。

分類閾值為0.5

  • 如果概率> 0.5,則預測1級
  • 如果概率<0.5,則預測0級
# print the first 10 predicted probabilities for class 1
logreg.predict_proba(X_test)[0:10, 1]

array([0.129807  , 0.78467658, 0.69456039, 0.24535031, 0.38456149,
       0.48236779, 0.11001023, 0.37309512, 0.87571131, 0.20003843])
# store the predicted probabilities for class 1
y_pred_prob = logreg.predict_proba(X_test)[:, 1]

# allow plots to appear in the notebook

import matplotlib.pyplot as plt

# adjust the font size 
plt.rcParams['font.size'] = 12

# histogram of predicted probabilities

# 10 bins
plt.hist(y_pred_prob,bins=10)

# x-axis limit from 0 to 1
plt.xlim(0,1)
plt.title('Histogram of predicted probabilities')
plt.xlabel('Predicted probability of diabetes')
plt.ylabel('Frequency')

 

我們可以從第三個欄看到:

  • 大約45%的觀測值的概率從0.2到0.3
  • 少量觀察概率> 0.5
  • 這低於0.5的閾值
  • 在這種情況下,大多數人會被預測為“無糖尿病”

解決辦法

  • 降低預測糖尿病的閾值(threshold)
  • 增加分類器的靈敏度(sensitivity)
    • 這會增加TP的數量
    • 對積極情況更敏感
# sensitivity has increased (used to be 0.87)
print (81 / float(81 + 11))

# specificity has decreased (used to be 0.55)
print(101 / float(101 + 61))
# predict diabetes if the predicted probability is greater than 0.3
from sklearn.preprocessing import binarize
# it will return 1 for all values above 0.3 and 0 otherwise
# results are 2D so we slice out the first column
y_pred_class = binarize(y_pred_prob.reshape(1,-1), 0.3)[0]


# print the first 10 predicted probabilities
y_pred_prob[0:10]

array([0.129807  , 0.78467658, 0.69456039, 0.24535031, 0.38456149,
       0.48236779, 0.11001023, 0.37309512, 0.87571131, 0.20003843])
# print the first 10 predicted classes with the lower threshold
y_pred_class[0:10]

array([0., 1., 1., 0., 1., 1., 0., 1., 1., 0.])
# new confusion matrix (threshold of 0.3)
print(metrics.confusion_matrix(Y_test, y_pred_class))

[[101  61]
 [ 11  81]]


# previous confusion matrix (default threshold of 0.5)
print(confusion)

[[141  21]
 [ 41  51]]

 

可以看到:

  • 默認情況下使用閾值0.5(對於二進制問題)將預測概率轉換為類預測
  • 可以調整閾值以增加靈敏度或特異性
  • 敏感性和特異性具有相反的關系
  • 增加一個會減少另一個
  • 調整閾值應該是您在模型構建過程中執行的最后一步
  • 最重要的步驟是
  1. 建立模型
  2. 選擇最佳模型

Receiver Operating Characteristic (ROC) Curves

  如果我們能夠看到靈敏度和特異性如何受到各種閾值的影響而不實際改變閾值,那不是很好嗎?那就需要繪制ROC曲線。ROC曲線是靈敏度和(1-特異性,即誤報率)之間的曲線。 (1-特異性)也稱為假陽性率,靈敏度也稱為真陽性率。

 

一些解釋:

  • 橫坐標是false positive rate(FPR) = FP / (FP+TN)  直觀解釋:實際是0中,錯猜多少
    • FPR越大,預測正類中實際負類越多
  • 縱坐標是true positive rate(TPR) = TP / (TP+FN)   直觀解釋:實際是1中,猜對多少
    • TPR越大,預測正類中實際正類越多
  • 最優目標:
    • TPR=1,FPR=0,即圖中(0,1)點,故ROC曲線越靠攏(0,1)點,越偏離45度對角線越好,Sensitivity、Specificity越大效果越好。

 繪制ROC曲線:

# IMPORTANT: first argument is true values, second argument is predicted probabilities

# we pass y_test and y_pred_prob
# we do not use y_pred_class, because it will give incorrect results without generating an error
# roc_curve returns 3 objects fpr, tpr, thresholds
# fpr: false positive rate
# tpr: true positive rate
fpr, tpr, thresholds = metrics.roc_curve(Y_test, y_pred_prob)

plt.plot(fpr, tpr)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.rcParams['font.size'] = 12
plt.plot([0, 1], [0, 1],'r-')
plt.title('ROC curve for diabetes classifier')
plt.xlabel('False Positive Rate (1 - Specificity)')
plt.ylabel('True Positive Rate (Sensitivity)')
plt.grid(True)

 

ROC曲線可以幫助我們選擇一個閾值,以一種對特定環境有意義的方式平衡靈敏度和特異性。

# define a function that accepts a threshold and prints sensitivity and specificity
def evaluate_threshold(threshold):
    print('Sensitivity:', tpr[thresholds > threshold][-1])
    print('Specificity:', 1 - fpr[thresholds > threshold][-1])

import numpy as np

for  i in np.arange(0. , 1. ,0.1):
    print(evaluate_threshold(i))

AUC

  ROC曲線下面積(Area Under ROC Curve,AUC)是二元分類問題的性能指標。AUC代表模型區分正面和負面類別的能力。 面積為1.0表示完美地預測所有預測的模型。 面積為0.5表示與隨機一樣好的模型。 ROC可以分解為敏感性和特異性。 二元分類問題實際上是敏感性和特異性之間的權衡。

  首先AUC值是一個概率值,當你隨機挑選一個正樣本以及一個負樣本,當前的分類算法根據計算得到的Score值將這個正樣本排在負樣本前面的概率就是AUC值。當然,AUC值越大,當前的分類算法越有可能將正樣本排在負樣本前面,即能夠更好的分類。

# IMPORTANT: first argument is true values, second argument is predicted probabilities
print(metrics.roc_auc_score(Y_test, y_pred_prob))

0.8240740740740741

 交叉驗證中AUC

# calculate cross-validated AUC
from sklearn.cross_validation import cross_val_score
cross_val_score(logreg, X, Y, cv=10, scoring='roc_auc').mean()

0.824683760683760

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM