一、Sklearn工具包介紹
scikit-learn,又寫作sklearn,是一個開源的基於python語言的機器學習工具包。它通過NumPy, SciPy和Matplotlib等python數值計算的庫實現高效的算法應用,並且涵蓋了幾乎所有主流機器學習算法。
官網:https://scikit-learn.org/stable/index.html
1、常用模塊
Sklearn中常用模塊:分類(Classification)、回歸(Regression)、聚類(Clustering)、降維(Dimensionality reduction)、模型選擇(Model selection)、數據預處理(Preprocessing)。
分類:識別某個對象屬於哪個類別,常用的算法有:SVM(支持向量機)、nearest neighbors(最近鄰)、random forest(隨機森林),常見的應用有:垃圾郵件識別、圖像識別。
回歸:預測與對象相關聯的連續值屬性,常見的算法有:SVR(支持向量機)、 ridge regression(嶺回歸)、Lasso,常見的應用有:葯物反應,預測股價。
聚類:將相似對象自動分組,常用的算法有:k-Means、 spectral clustering、mean-shift,常見的應用有:客戶細分,分組實驗結果。
降維:減少要考慮的隨機變量的數量,常見的算法有:PCA(主成分分析)、feature selection(特征選擇)、non-negative matrix factorization(非負矩陣分解),常見的應用有:可視化,提高效率。
模型選擇:比較,驗證,選擇參數和模型,常用的模塊有:grid search(網格搜索)、cross validation(交叉驗證)、 metrics(度量)。它的目標是通過參數調整提高精度。
預處理:特征提取和歸一化,常用的模塊有:preprocessing,feature extraction,常見的應用有:把輸入數據(如文本)轉換為機器學習算法可用的數據。
2、模型評估: 量化預測的質量
有 3 種不同的 API 用於評估模型預測的質量:
- Estimator score method(估計器得分的方法): Estimators(估計器)有一個
score(得分)
方法,為其解決的問題提供了默認的 evaluation criterion (評估標准)。 在這個頁面上沒有相關討論,但是在每個 estimator (估計器)的文檔中會有相關的討論。 - Scoring parameter(評分參數): Model-evaluation tools (模型評估工具)使用 cross-validation (如
model_selection.cross_val_score
和model_selection.GridSearchCV
) 依靠 internal scoring strategy (內部 scoring(得分) 策略)。這在 scoring 參數: 定義模型評估規則 部分討論。 - Metric functions(指標函數):
metrics
模塊實現了針對特定目的評估預測誤差的函數。這些指標在以下部分部分詳細介紹 分類指標, 多標簽排名指標, 回歸指標 和 聚類指標 。
二、SciKit-Learn數據集
sklearn.datasets 模塊 包含加載數據集的實用程序,包括加載和獲取流行引用數據集的方法。它還具有一些人工數據生成器。
更多細節查看: Dataset loading utilities
1、加載數據集
數據科學的第一步通常是加載數據,首先需要學會如何使用SciKit-Learn來加載數據集。
數據集的來源通常是自己准備或第三方處獲取。非研究人員,通常是從第三方獲取數據。可以下載獲取數據集的網站:
SciKit-Learn庫中,也有自帶一些數據集可以嘗試加載。
datasets
模塊中也包含了獲取其他流行數據集的方法,例如datasets.fetch_openml
可以從openml存儲庫獲取數據集。
在sklearn的0.2版本中,fetch_mldata函數已經被fetch_openml函數取代,例如加載MNIST數據集。
def get_data(): """ Get MNIST data ready to learn with. :return: """ # 在sklearn的0.2版本中,fetch_mldata函數已經被fetch_openml函數取代 from sklearn.datasets import fetch_openml # 通過名稱或數據集ID從openml獲取數據集 # 查詢到我電腦上的scikit data home目錄 from sklearn.datasets.base import get_data_home print(get_data_home()) # C:\Users\hqs\scikit_learn_data # Mnist 數據是圖像數據:(28,28,1)的灰度圖 mnist = fetch_openml('mnist_784') # print(mnist) X, y = mnist["data"], mnist["target"] X.shape # (70000, 784) y.shape # (70000,)
2、數據集切分
將數據集切分為訓練集、測試集。
def get_data(): """ Get MNIST data ready to learn with. :return: """ # 在sklearn的0.2版本中,fetch_mldata函數已經被fetch_openml函數取代 from sklearn.datasets import fetch_openml # 通過名稱或數據集ID從openml獲取數據集 # 查詢到我電腦上的scikit data home目錄 from sklearn.datasets.base import get_data_home print(get_data_home()) # C:\Users\hqs\scikit_learn_data # Mnist 數據是圖像數據:(28,28,1)的灰度圖 mnist = fetch_openml('mnist_784') # print(mnist) X, y = mnist["data"], mnist["target"] X.shape # (70000, 784) y.shape # (70000,) # 切分為訓練集和測試集 X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:] # 洗牌操作,打亂當前數據集順序 shuffle_index = np.random.permutation(60000) X_train, y_train = X_train[shuffle_index], y_train[shuffle_index] # 索引值回傳相當於洗牌操作 print(X_train, y_train) """ [[0. 0. 0. ... 0. 0. 0.] [0. 0. 0. ... 0. 0. 0.] [0. 0. 0. ... 0. 0. 0.] ... [0. 0. 0. ... 0. 0. 0.] [0. 0. 0. ... 0. 0. 0.] [0. 0. 0. ... 0. 0. 0.]] ['7' '3' '8' ... '0' '0' '4'] """
三、模型評估——交叉驗證(cross validation)
1、交叉驗證定義
交叉驗證是用來驗證分類器的性能一種統計分析方法,基本思想是把在某種意義下將原始數據(data set)進行分組,一部分做為訓練集(training set),另一部分做為測試集(validation set),首先用訓練集對分類器進行訓練,在利用測試集來測試訓練得到的模型(model),以此來做為評價分類器的性能指標。
2、三種實現方法
(1)留出法(holdout cross validation)
將原始數據集分為三部分:訓練集、驗證集和測試集。訓練集用於訓練模型,驗證集用於模型的參數選擇配置,測試集對於模型來說是未知數據,用於評估模型的泛化能力。
優點:操作簡單
缺點:樣本數比例,模型對數據划分敏感,分成三部分使得訓練數據變少。
(2)k折交叉驗證(k-fold cross validation)
將數據集無替換的隨機分為k份,k-1份用來訓練模型,剩下一份用來模型性能評估。重復k次,得到k個模型和性能評估結果。得到k個性能評估后,取平均求出最終性能評估。即:
第一步:不重復抽樣將原始數據隨機分為k份。
第二步:每一次挑選其中 1 份作為測試集,剩余k-1份作為訓練集用於模型訓練。
第三步:重復第二步k次,每個子集都有一次作為測試集,其余子集作為訓練集。在每個訓練集上訓練后得到一個模型,用這個模型在相應測試集上測試,計算並保存模型的評估指標。
第四步:計算k組測試結果的平均值作為模型精度的估計,並作為當前k折交叉驗證下模型的性能指標。
優點:分組后取平均減少方差,使得模型對數據划分不敏感。
缺點:k取值需要嘗試。
分成五份,示例如下所示:
(3)留一法(leave one out cross validation)
當k折交叉驗證法的k=m,m為樣本總數時,稱為留一法,即每次的測試集都只有一個樣本,要進行m次訓練和預測。
優點:適合數據缺乏時使用
缺點:計算繁瑣,訓練復雜度增加。
3、交叉驗證代碼實現
import numpy as np import os import matplotlib as mpl import matplotlib.pyplot as plt import warnings mpl.rcParams['axes.labelsize'] = 14 mpl.rcParams['xtick.labelsize'] = 12 mpl.rcParams['ytick.labelsize'] = 12 warnings.filterwarnings('ignore') np.random.seed(42) # 保存圖片的地址 PROJECT_ROOT_DIR = "." CHAPTER_ID = "classification"def sort_by_target(mnist): reorder_train = np.array(sorted([(target, i) for i, target in enumerate(mnist.target[:60000])]))[:, 1] reorder_test = np.array(sorted([(target, i) for i, target in enumerate(mnist.target[60000:])]))[:, 1] mnist.data[:60000] = mnist.data[reorder_train] mnist.target[:60000] = mnist.target[reorder_train] mnist.data[60000:] = mnist.data[reorder_test + 60000] mnist.target[60000:] = mnist.target[reorder_test + 60000] def get_data(): """ Get MNIST data ready to learn with. :return: """ # 在sklearn的0.2版本中,fetch_mldata函數已經被fetch_openml函數取代 from sklearn.datasets import fetch_openml # 通過名稱或數據集ID從openml獲取數據集 # 查詢到我電腦上的scikit data home目錄 from sklearn.datasets.base import get_data_home print(get_data_home()) # C:\Users\hqs\scikit_learn_data # Mnist 數據是圖像數據:(28,28,1)的灰度圖 """注意: fetch_openml返回的是未排序的MNIST數據集。 fetch_mldata返回按目標排序的數據集。 在SciKit-Learn 0.20后已經棄用fetch_mldata(),需要使用fetch_openml()。 如果要得到和之前相同的結果,需要排序數據集。 """ mnist = fetch_openml('mnist_784', version=1, cache=True) # fetch_openml返回一個未排序的數據集 mnist.target = mnist.target.astype(np.int8) sort_by_target(mnist) # print(mnist.data.shape) # (70000, 784) X, y = mnist["data"], mnist["target"] print(X.shape) # (70000, 784) print(y.shape) # (70000,) # 切分為訓練集和測試集 X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:] # 洗牌操作,打亂當前數據集順序 shuffle_index = np.random.permutation(60000) X_train, y_train = X_train[shuffle_index], y_train[shuffle_index] # 索引值回傳相當於洗牌操作 print(X_train, y_train) # 訓練二分類器 y_train_5 = (y_train == 5) # 修改便簽為是否等於5 y_test_5 = (y_test == 5) from sklearn.linear_model import SGDClassifier # 引入線性分類器 # 使用scikit-learn的SGDClassifier類來創建分類器,區分圖片是否是數字5 sgd_clf = SGDClassifier( max_iter=5, # 訓練迭代次數 tol=-np.infty, random_state=42 # 傳入隨機種子,每次隨機結果一樣 ) # fit方法:用隨機梯度下降法擬合線性模型 sgd_clf.fit(X_train, y_train) # predict方法:預測當前的結果 sgd_clf.predict([X[35000]]) # 采用准確率為衡量指標查看交叉驗證的結果 from sklearn.model_selection import cross_val_score cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring='accuracy') """ [0.96225 0.9645 0.94765] """ # StratifiedKFold方法:按自己的想法平均切割數據集 from sklearn.model_selection import StratifiedKFold from sklearn.base import clone # 引入克隆可以在估算器中對模型進行深層復制,構造一個具有相同參數的新估算器 skfolds = StratifiedKFold( n_splits=3, random_state=42 # 設置隨機種子 ) for train_index, test_index in skfolds.split(X_train, y_train_5): # 切割訓練的數據集和標簽集 clone_clf = clone(sgd_clf) # 克隆構建模型 X_train_folds = X_train[train_index] y_train_folds = y_train_5[train_index] X_test_folds = X_train[test_index] y_test_folds = y_train_5[test_index] # fit方法:用隨機梯度下降法擬合線性模型 clone_clf.fit(X_train_folds, y_train_folds) # 預測 y_pred = clone_clf.predict(X_test_folds) # 做對了的個數 n_correct = sum(y_pred == y_test_folds) print(n_correct / len(y_pred)) """ 0.96225 0.9645 0.94765 """ get_data()
上面先是使用了sklearn.model_selection.cross_val_score()方法查看了交叉驗證結果。
隨后使用StratifiedKFold方法按自己的想法平均切割數據集,計算做對了的個數/預測數,計算得到交叉驗證結果。
(1)cross_val_score函數
使用交叉檢驗最簡單的方法是在估計器上調用cross_val_score函數。該函數可返回交叉驗證每次運行的評分數組。
def cross_val_score(estimator, X, y=None, *, groups=None, scoring=None,
cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch='2*n_jobs', error_score=np.nan):
參數:
- estimator:數據對象
- X:數據
- y:預測數據
- scoring:定義模型評估規則
- cv:交叉驗證生成器或可迭代的次數
- n_jobs:同時工作的cpu個數(-1代表全部)
- verbose:詳細程度
- fit_params:傳遞給估計器的擬合方法的參數
- pre_dispatch:控制並行執行期間調度的作業數量。減少這個數量對於避免在CPU發送更多作業時CPU內存消耗的擴大是有用的。該參數可以是:
- 沒有,在這種情況下,所有的工作立即創建並產生。將其用於輕量級和快速運行的作業,以避免由於按需產生作業而導致延遲
- 一個int,給出所產生的總工作的確切數量
- 一個字符串,給出一個表達式作為n_jobs的函數,如'2 * n_jobs'
參數介紹詳見:https://blog.csdn.net/marsjhao/article/details/78678276
(2)StratifiedKFold函數
分層K折交叉驗證器:提供訓練/測試索引以將數據拆分為訓練/測試集。此交叉驗證對象是KFold的變體,它返回分層的折疊。折疊是通過保留每個類別的樣品百分比來進行的。
class StratifiedKFold(_BaseKFold):
@_deprecate_positional_args
def __init__(self, n_splits=5, *, shuffle=False, random_state=None): super().__init__(n_splits=n_splits, shuffle=shuffle, random_state=random_state)
參數:
- n_splits:折數(int數據類型),默認為5,至少為2。(0.22版本中,將默認值從3改為5)
- shuffle:bool數據類型,默認為False。在拆分成批次之前是否對每個樣本進行混洗。
- random_state:int或RandomState實例,默認為None。當
shuffle
為True時,random_state
會影響索引的順序,從而控制每個類別的每個折疊的隨機性。否則,保留random_state
為None
。為多個函數調用傳遞可重復輸出的int值。
四、模型評估——混淆矩陣(Confusion Matrix)
混淆矩陣是機器學習中總結分類模型預測結果的情形分析表,以矩陣形式將數據集中的記錄按照真實的類別與分類模型預測的類別判斷兩個標准進行匯總。
其中矩陣的行表示真實值,矩陣的列表示預測值。
1、案例
已知條件:班級總人數100人,其中男生80人,女生20人。
目標:找出所有的女生。
結果:從班級中選擇了50人,其中20人是女生,還錯誤的把30名男生挑選出來了。
相關(Relevant),正類 | 無關(NonRelevant),負類 | |
被檢索到(Retrieved) | true positives(TP 正類判定為正類,例子中就是正確的判定“這位是女生”) | false positives(FP 負類判定為正類,“存偽”,例子就是分明是男生卻判斷為女生,當下偽娘橫行) |
未被檢索到(Not Retrieved) | false negatives(FN正類判定為負類,“去真”,例子中就是,分明是女生,這哥們卻判斷為男生) | true negatives(TN 負類判定為負類,也就是一個男生判斷為男生) |
通過這張表,我們可以很容易得到這幾個值:TP=20;FP=30;FN=0;TN=50;
1)TP(True Positive):將正類預測為正類數,positive 表示他判定為女生。 true表示,判定是對的。 TP=20
2)FN(False Negative):將正類預測為負類數,negative 表示他判定為男生。 false表示,判定是錯的。 FN=0
3)FP(False Positive):將負類預測為正類數, positive 表示他判定為女生。 false表示,判定是錯的。 FP=30
4)TN(True Negative):將負類預測為負類數,negative 表示他判定為男生。 true表示, 他的判定是對的。 TN=50
2、混淆矩陣代碼實現
import numpy as np import os import matplotlib as mpl import matplotlib.pyplot as plt import warnings mpl.rcParams['axes.labelsize'] = 14 mpl.rcParams['xtick.labelsize'] = 12 mpl.rcParams['ytick.labelsize'] = 12 warnings.filterwarnings('ignore') np.random.seed(42) # 保存圖片的地址 PROJECT_ROOT_DIR = "." CHAPTER_ID = "classification" def sort_by_target(mnist): reorder_train = np.array(sorted([(target, i) for i, target in enumerate(mnist.target[:60000])]))[:, 1] reorder_test = np.array(sorted([(target, i) for i, target in enumerate(mnist.target[60000:])]))[:, 1] mnist.data[:60000] = mnist.data[reorder_train] mnist.target[:60000] = mnist.target[reorder_train] mnist.data[60000:] = mnist.data[reorder_test + 60000] mnist.target[60000:] = mnist.target[reorder_test + 60000] def get_data(): """ Get MNIST data ready to learn with. :return: """ # 在sklearn的0.2版本中,fetch_mldata函數已經被fetch_openml函數取代 from sklearn.datasets import fetch_openml # 通過名稱或數據集ID從openml獲取數據集 # 查詢到我電腦上的scikit data home目錄 from sklearn.datasets.base import get_data_home print(get_data_home()) # C:\Users\hqs\scikit_learn_data # Mnist 數據是圖像數據:(28,28,1)的灰度圖 """注意: fetch_openml返回的是未排序的MNIST數據集。 fetch_mldata返回按目標排序的數據集。 在SciKit-Learn 0.20后已經棄用fetch_mldata(),需要使用fetch_openml()。 如果要得到和之前相同的結果,需要排序數據集。 """ mnist = fetch_openml('mnist_784', version=1, cache=True) # fetch_openml返回一個未排序的數據集 mnist.target = mnist.target.astype(np.int8) sort_by_target(mnist) # print(mnist.data.shape) # (70000, 784) X, y = mnist["data"], mnist["target"] print(X.shape) # (70000, 784) print(y.shape) # (70000,) # 切分為訓練集和測試集 X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:] # 洗牌操作,打亂當前數據集順序 shuffle_index = np.random.permutation(60000) X_train, y_train = X_train[shuffle_index], y_train[shuffle_index] # 索引值回傳相當於洗牌操作 print(X_train, y_train) # 訓練二分類器 y_train_5 = (y_train == 5) # 修改便簽為是否等於5 y_test_5 = (y_test == 5) from sklearn.linear_model import SGDClassifier # 引入線性分類器 # 使用scikit-learn的SGDClassifier類來創建分類器,區分圖片是否是數字5 sgd_clf = SGDClassifier( max_iter=5, # 訓練迭代次數 tol=-np.infty, random_state=42 # 傳入隨機種子,每次隨機結果一樣 ) # fit方法:用隨機梯度下降法擬合線性模型 sgd_clf.fit(X_train, y_train) from sklearn.model_selection import cross_val_predict y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3) print(y_train_pred.shape) # (60000,):60000個樣本的預測結果 print(X_train.shape) # (60000, 784):訓練樣本也是60000個,與預測結果數量一致 from sklearn.metrics import confusion_matrix confusion_matrix(y_train_5, y_train_pred) """ array([[53417 1162], [1350 4071]], dtype=int64) """ get_data()
(1)cross_val_predict函數
得到經過K折交叉驗證計算得到的每個訓練驗證的輸出預測。
分別在K-1上訓練模型,在余下的1折上驗證模型,並將余下1折中樣本的預測輸出作為最終輸出結果的一部分
def cross_val_predict(estimator, X, y=None, *, groups=None, cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch='2*n_jobs', method='predict'):
cross_val_predict
與cross_val_score
很相像,不過不同於返回的是評測效果,cross_val_predict
返回的是estimator
的分類結果(或回歸值),這個對於后期模型的改善很重要,可以通過該預測輸出對比實際目標值,准確定位到預測出錯的地方,為我們參數優化及問題排查十分的重要。
(2)confusion_matrix函數
計算混淆矩陣以評估分類的准確性。
def confusion_matrix(y_true, y_pred, *, labels=None, sample_weight=None, normalize=None):
y_true:是樣本真實分類結果,y_pred 是樣本預測分類結果 ,labels是所給出的類別,通過這個可對類別進行選擇 ,sample_weight 是樣本權重。
(3)confusion_matrix返回結果解析
返回結果是:array([[53417 1162],[1350 4071]], dtype=int64)。
negative class [[true negative, false posotives],
positive class [false negative, true positives]]
- true negatives: 53417個數據被正確的分為非5類別
- false positves: 1162個被錯誤的分為5類別
- false negatives: 1350個被錯誤的分為非5類別
- true positives: 4071個被正確的分為5類別
一個完美的分類器應該只有true positives 和 true negatives,即主對角線元素不為0,其余元素為0。
五、模型評價指標——Precision/Recall
機器學習(ML),自然語言處理(NLP),信息檢索(IR)等領域,評估(Evaluation)是一個必要的 工作,而其評價指標往往有如下幾點:准確率(Accuracy),精確率(Precision),召回率(Recall)和F1-Measure。
1、准確率、精確率、召回率、F值對比
准確率/正確率(Accuracy)= 所有預測正確的樣本 / 總的樣本 (TP+TN)
精確率(Precision) = 正類預測為正類(TP) / 所有預測為正類(TP+TN)
召回率(Recall) = 正類預測為正類(TP) / 所有真正的正類(TP+FN)
F值(F-Measure) = 精確率 * 召回率 * 2 / (精確率 + 召回率) —— F值即為精確率和召回率的調和平均值
2、精確率、召回率計算公式
(1)精確率計算公式

理解:
TP+FP: 也就是全體Positive, 也就是預測的圖片中是正類的圖片的數目
TP: 也就是正類也被預測為正類的圖片的個數
總之:預測正確的圖片個數占總的正類預測個數的比例(從預測結果角度看,有多少預測是准確的)
(2)召回率計算公式
理解:
TP+FN: 也就是全體完全滿足圖片標注的圖片的個數
TP:正類被預測為正類的圖片個數
總之:確定了正類被預測為正類圖片占所有標注圖片的個數(從標注角度看,有多少被召回)
3、F1 score指標
P和R指標有時候會出現的矛盾的情況,這樣就需要綜合考慮他們,最常見的方法就是F-Measure(又稱為F-Score)。
將Precision 和 Recall 結合到一個稱為F1 score 的指標,調和平均值給予低值更多權重。因此,如果召回和精確度都很高,分類器將獲得高F1分數。
F-Measure是Precision和Recall加權調和平均:
當參數α=1時,就是最常見的F1,也即
可知F1綜合了P和R的結果,當F1較高時則能說明試驗方法比較有效。
4、代碼實現
def get_data(): """代碼略""" # 准確率(Precision)和召回率(Recall) from sklearn.metrics import precision_score, recall_score print(precision_score(y_train_5, y_train_pred)) # 0.7779476399770686 print(recall_score(y_train_5, y_train_pred)) # 0.7509684560044272 # F1 score from sklearn.metrics import f1_score print(f1_score(y_train_5, y_train_pred)) # 0.7642200112633752 get_data()
(1)precision_score函數
計算精確率。精度是 TP/(TP+FP) 比率,TP是 true positives 與 FP是 false positives。
def precision_score(y_true, y_pred, *, labels=None, pos_label=1, average='binary', sample_weight=None, zero_division="warn"):
參數:
y_true:真實標簽
y_pred:預測標簽
average:評價值的平均值的計算方式。
(2)recall_score函數
計算召回率。召回率是 TP/(TP+FN)的比率,FN是false negatives。
def recall_score(y_true, y_pred, *, labels=None, pos_label=1, average='binary', sample_weight=None, zero_division="warn"):
參數:
y_true:真實標簽
y_pred:預測標簽
average:評價值的平均值的計算方式。
(3)f1_score函數
計算F1 score,也稱為F-score或F-measure。
F1 = 2 * (precision * recall) / (precision + recall)
def f1_score(y_true, y_pred, *, labels=None, pos_label=1, average='binary', sample_weight=None, zero_division="warn"):
六、模型評價——選擇合適閾值
Scikit-Learn不允許直接設置閾值,但它可以得到決策分數,調用其decision_function()方法,而不是調用分類器的predict()方法,該方法返回每個實例的分數,然后使用想要的閾值根據這些分數進行預測。
- 對於這種分類問題,不同的分類閾值可以給出不同的輸出結果,但是在sklearn中,無法直接通過直接修改閾值而輸出結果,但是我們可以首先得到決策函數得到的結果,然后再手動確定閾值,得到預測的結果。
- 為了使得模型更加完善,我們需要選擇合適的閾值,即使得准確率和召回率都比較大,因此在這里我們可以首先繪制出准確率和召回率隨閾值的變化關系,然后再選擇合適的閾值。
1、選擇閾值示例
def plot_precision_recall_vs_threshold(precisions, recalls, thresholds): plt.plot( thresholds, precisions[:-1], "b--", label="Precision" ) plt.plot( thresholds, recalls[:-1], "g-", label="Recall" ) plt.xlabel("Threshold", fontsize=16) plt.legend(loc="upper left", fontsize=16) plt.ylim([0, 1]) def get_data(): """代碼略""" # 閾值 # y_scores = sgd_clf.decision_function([X[35000]]) y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3, method="decision_function") print(y_scores) t = 5000 y_pred = (y_scores > t) print(y_pred) print(y_train_5.shape) print(y_scores.shape) from sklearn.metrics import precision_recall_curve precisions, recalls, thresholds = precision_recall_curve(y_train_5, y_scores) # print(precisions, recalls, thresholds) plt.figure(figsize=(8, 4)) plot_precision_recall_vs_threshold(precisions, recalls, thresholds) plt.xlim([-700000, 700000]) plt.show()
執行后顯示效果:
隨着閾值變化,precision和recall值變化情況。
2、recall變化precision的變化情況
def plot_precision_vs_recall(precisions, recalls): plt.plot( recalls, precisions, "b-", linewidth=2 ) plt.xlabel("Recall", fontsize=16) plt.ylabel("Precision", fontsize=16) plt.axis([0, 1, 0, 1]) def get_data(): """代碼略""" # 隨着recall變化precision的變化情況 plt.figure(figsize=(8, 6)) plot_precision_vs_recall(precisions, recalls) plt.show()
執行后顯示效果:
七、模型評價——ROC curves
receiver operating characteristic(ROC)曲線是二元分類中的常用評估方法。
- 它與精確度/召回曲線非常相似,但ROC曲線不是繪制精確度與召回率,而是繪制true positive rate(TPR)與false positive rate(FPR)
- 要繪制ROC曲線,首先需要使用roc_curve()函數計算各種閾值的TPR和FPR:
- TPR = TP / (TP + FN)(Recall)
- FPR = FP / (FP + TN)
TPR:在所有實際為陽性的樣本中,被正確地判斷為陽性的比率 TRP = TP / (TP + FN)。TPR也被稱為正樣本的召回率,或者覆蓋率。
FPR:在所有實際為陰性的樣本中,被錯誤地判斷為陽性的比率 FPR = FP / (FP + TN)。FPR也被稱為負樣本的召回率,或者取偽率。
1、繪制ROC曲線示例
def plot_roc_curve(fpr, tpr, label=None): plt.plot(fpr, tpr, linewidth=2, label=label) plt.plot([0, 1], [0, 1], 'k--') plt.axis([0, 1, 0, 1]) plt.xlabel('False Positive Rate', fontsize=16) plt.ylabel('True Positive Rate', fontsize=16) def get_data(): """略""" # ROC 曲線 from sklearn.metrics import roc_curve fpr, tpr, thresholds = roc_curve(y_train_5, y_scores) plt.figure(figsize=(8, 6)) plot_roc_curve(fpr, tpr) plt.show()
執行得到繪圖如下所示:
虛線表示純隨機分類器的ROC曲線:一個好的分類器應盡可能遠離該線(左上角最優)。
2、ROC-AUC(ROC曲線下面積)
AUC(Area Under Curve) 被定義為ROC曲線下的面積,因為ROC曲線一般都處於y=x這條直線的上方,所以取值范圍在0.5和1之間,使用AUC作為評價指標是因為ROC曲線在很多時候並不能清晰地說明哪個分類器的效果更好,而AUC作為一個數值,其值越大代表分類器效果更好。
AUC是一個概率值,當隨機挑選一個正樣本以及一個負樣本,當前的分類算法根據計算得到的分數將這個正樣本排在負樣本前面的概率就是AUC值。所以,AUC的值越大,當前的分類算法越有可能將正樣本排在負樣本值前面,既能夠更好的分類。
# AUC曲線下面積 from sklearn.metrics import roc_auc_score print(roc_auc_score(y_train_5, y_scores)) # 0.9562435587387078
測量曲線下面積(AUC)是比較分類器的一種方法。完美分類器的ROC AUC等於1,而純隨機分類器的ROC AUC等於0.5。