機器學習第二週:如何評價模型的好壞

機器學習第二週:如何評價模型的好壞

一、目標

數據拆分:訓練數據集&測試數據集

評價分類結果:精準度、混淆矩陣、精準率、召回率、F1 Score、ROC曲線等

評價迴歸結果:MSE、RMSE、MAE、R Squared

二、學習資料參考

  1. 《機器學習的敲門磚:kNN算法(中)》(https://mp.weixin.qq.com/s/vvCM0vWH5kmRfrRWxqXT8Q)全文,學習數據拆分,劃分訓練數據集&測試數據集的方法。分類準確度。

  2. 閱讀《評價分類結果(上):混淆矩陣、精準率、召回率》(https://mp.weixin.qq.com/s/Fi13jaEkM5EGjmS7Mm_Bjw)

  3. 《評價分類結果(下):F1 Score、ROC、AUC》**,全面瞭解評價分類結果

  4. 閱讀《模型之母:線性迴歸的評價指標》(https://mp.weixin.qq.com/s/BEmMdQd2y1hMu9wT8QYCPg),學習評價迴歸結果:MSE、RMSE、MAE、R Squared

    注:本文是上面這四篇文章的筆記,均來自與公衆號 數據科學家聯盟組織的學習小組,木東居士和餅乾等分享的文章。

三、學習開始

  1. 數據拆分:

    KNN算法中:對數據集進行劃分,包括訓練集和測試集,在劃分過程中儘可能隨機選擇,訓練集數據要足夠多,可以採用隨機後採集0.8比例的數據作爲訓練集,剩餘0.2作爲測試數據集的數據進行。

    方法命名:https://mp.weixin.qq.com/s/vvCM0vWH5kmRfrRWxqXT8Q l來源: 數據科學家聯盟 作者:Japson

    def  train_test_split(X, y, test_ratio = 0.2 , seed = None):
        if seed:
            np.random.seed(seed)
        shuffle_index = np.random.permutation(len(X))
        
        test_size = int(len(X) * test_ratio)
        test_index = shuffle_index[:test_size]
        train_index = shuffle_index[test_size:]
        X_train = X[train_index]
        X_test = X[test_index]
        y_train = y[train_index]
        y_test = y[test_index]
        
        return X_train , X_test, y_train ,y_test
    

    參考下面鏈接:sklearn在代碼中引入model_selection.train_test_split,可以隨機分割訓練集和測試集(隨機數種子)。如果該方法不加random_state可能會造成確定模型和初始參數後,每運行一次都可能得到不同的準確率。

    from  sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
    

    https://blog.csdn.net/Tony_Stark_Wang/article/details/80407923

  2. 分類準確度accuracy

    在劃分出測試數據集後,根據訓練數據集訓練出的模型,需要進行對模型驗證,評價 其好壞。

    accuracy_score 計算分類準確率,返回被正確分類的樣本比例(默認)或者數量

    在多標籤分類問題中,該函數返回子集的準確率,對於一個給定的多標籤樣本,如果預測得到的標籤集合與該樣本真正的標籤集嚴格吻合,則subset accuracy = 1.0 否則是0.0。但有些場合使用精度(查準率)和召回率(查全率)等更好些。

    def accuracy_score(y_true, y_predict):
        """計算y_true和y_predict之間的準確率"""
        assert y_true.shape[0] == y_predict.shape[0],"the size of y_true must be equal to the size of y_predict"
        return sum(y_true == y_predict) / len(y_true)
    

    有時只關心對應的測試結果,可以使用score,進一步進行分裝

    def score(self, X_test, y_test):
        """根據X_test進行預測, 給出預測的真值y_test,計算預測算法的準確度"""
        y_predict = self.predict(X_test)    
    	return accuracy_score(y_test, y_predict)
    
  3. 超參數

    knn_clf = KNeighborsClassifier(n_neighbors=3)

    這裏的數值,是傳遞一個默認的k值,但是這個參數該如何選擇。

    超參數,在機器學習算法模型執行之前需要制定的參數。調參數理解調的就是超參數,如該處算法KNN中的k。

    在對於KNN算法中,最容易想到的就是利用訓練數據,通過循環1…k,選擇其中得到的score最佳的一個結果對應的K

    # 指定最佳值的分數,初始化爲0.0;設置最佳值k,初始值爲-1
    best_score = 0.0
    best_k = -1
    for k in range(1, 11):  # 暫且設定到1~11的範圍內
        knn_clf = KNeighborsClassifier(n_neighbors=k)
        knn_clf.fit(X_train, y_train)
        score = knn_clf.score(X_test, y_test)    
        if score > best_score:
            best_k = k
            best_score = score
    print("best_k = ", best_k)
    print("best_score = ", best_score)
    
  4. 超參數:權重

    在KNN算法中,我們是利用對應的k個鄰近點,每個點的權重都是1,如果根據距離遠近增加判斷結果所起的作用,影響大的增加權重大點。可以使用f(x)=1/x,對每種分類點距離倒數求和,判斷數值那個最大,然後該點所屬對應分類。

    感覺可以調整f(x)

    在sklearn.neighbors的構造函數 KNeighborsClassifier中有一個參數:weights ,默認uniform 是不考慮距離,也可以寫distance來考慮距離權重(默認是歐拉距離,如果要是曼哈頓距離,則可以寫參數P?)

    在找兩個超參數,公衆號介紹使用了雙重循環,在每種距離運算下尋求k,最終尋求出一個最佳的兩個參數

    # 兩種方式進行比較
    best_method = ""
    best_score = 0.0
    best_k = -1
    for method in ["uniform","distance"]:    
    	for k in range(1, 11):
            knn_clf = KNeighborsClassifier(n_neighbors=k, weights=method, p=2)
            knn_clf.fit(X_train, y_train)
            score = knn_clf.score(X_test, y_test)        
    		if score > best_score:
                best_k = k
                best_score = score
                best_method = method
    print("best_method = ", method)
    print("best_k = ", best_k)
    print("best_score = ", best_score)
    
    輸出:
    best_method =  distance
    best_k =  4
    best_score =  0.9916666666666667
    

    method循環uniform,distance ,每種循環裏面嵌套子循環,子循環再遍歷k,在尋找最佳的score過程中,通過遍歷比較最終獲得一個滿意的k ,method

  5. 當有多個參數需要找尋最優時,是不是需要自己寫多個循環去搜索最優參數

    餅乾說,超參數過多,超參數之間互相依賴等都是在具體超參數搜索過程中遇到的問題。如何一次性把想要的“最好”的超參數組合出來,sklearn中專門封裝了一個參數網格搜索方法GridSearch。使用時需要首先定義一個參數param_search。他是一個數據,數組中的每個元素是一個字典,字典中是對應的一組網格搜索,每一組網格搜索是這一組網格搜索每個參數的取值範圍。鍵是參數名稱,值是鍵所對應的的參數列表。

    param_search = [
        {        "weights":["uniform"],        "n_neighbors":[i for i in range(1,11)]
        },
        {        "weights":["distance"],        "n_neighbors":[i for i in range(1,11)],        "p":[i for i in range(1,6)]
        }
    ]
    
    knn_clf = KNeighborsClassifier()
    # 調用網格搜索方法
    from sklearn.model_selection import GridSearchCV
    # 定義網格搜索的對象grid_search,其構造函數的第一個參數表示對哪一個分類器進行算法搜索,
    #第二個參數表示網格搜索相應的參數
    grid_search = GridSearchCV(knn_clf, param_search)
    
    %%time 在網格中尋找最佳參數組
    grid_search.fit(X_train, y_train)
    
    輸出:CPU times: user 2min 21s, sys: 628 ms, total: 2min 21s
    Wall time: 2min 23s
    GridSearchCV(cv=None, error_score='raise',
           estimator=KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
               metric_params=None, n_jobs=1, n_neighbors=5, p=2,
               weights='uniform'),
           fit_params=None, iid=True, n_jobs=1,
           param_grid=[{'weights': ['uniform'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}, {'weights': ['distance'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'p': [1, 2, 3, 4, 5]}],
           pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
           scoring=None, verbose=0)
    
    # 返回的是網格搜索搜索到的最佳的分類器對應的參數 grid_search.best_estimator_
    
    輸出:KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
               metric_params=None, n_jobs=1, n_neighbors=3, p=3,
               weights='distance')
    
    #best_score
    grid_search.best_score_
    
    輸出:0.9853862212943633
    grid_search.beat_params_
    
    輸出:{'n_neighbors':3, 'p':3, 'weights':'distance'}
    
    knn_clf = grid_search.beat_estimator_
    knn_clf.score(X_test, y_test)
    
    輸出:0.9833333333328
    
  6. 評價分類結果:混淆矩陣、精準率、召回率

    在機器學習中如何評價一個算法的好壞,在迴歸問題中可以使用MSE/RMSE/MAE/R方。在使用分類精準度上,可能存在陷阱的,這是需要更加全面的信息。

    在對於極度偏斜skewed data的數據,在使用分類準確度是不能衡量的,還需要使用混淆矩陣confusion matrix 做分析。

    預測值0 預測值1
    真實值0 TN FP
    真實值1 FN TP

    TN:真實值是0,與測試值也是0,預測negative,預測正確

    FP:真實值是0,預測值是1,預測positive,但預測錯誤了

    FN:真實值是1,預測值是0,預測是negative,但預測錯誤了

    TP:真實值是1,預測值是1,預測是positive,預測正確了

    混淆矩陣的信息更多謝,提供更多一些指示的指標。

    精準率和召回率

    預測值0 預測值1
    真實值0 9978(TN) 12(FP)
    真實值1 2(FN) 8(TP)

    precision=TPTP+FP8/(8+12)=40 精準率 precision = \frac{TP}{TP+FP},即精準率爲8/(8+12)=40%

    所謂的精準率是:分母爲所有預測爲1的個數,分子是其中預測對了的個數。即預測值爲1,且預測對了的比例。

    現實情況中我們更關注“患病”、“有風險”,且在“有風險”中且判斷正確的概率。如在100次結果爲患病的預測中,平均有40次是預測對的。精準率是我們關注的那個事件,預測的有多準。
    recall=TPTP+FN=88+2=80 召回率:recall=\frac{TP}{TP+FN}=\frac{8}{8+2}=80%
    召回率:所有真實值爲1的數據中,預測對了的個數。每當有100個癌症患者,算法可以成功的預測出8個。是在我們關注的那個事件真實的發生情況下,我們成功預測的比例是多少。

    舉個例子在知道算法準確率的情況下,爲什麼需要精準率和召回率

    預測值0 預測值1
    真實值0 9978 12
    真實值1 2 8

    如果簡單粗暴認爲所有人都是健康的,那麼算法準確率是99.78%,這個數據應該是毫無意義。如果算精準率則是40%,召回率是80%。也就是說在預測有病的人中預測準的概率是40%,在實際有病的人中成功預測的有80%。這兩個指標在本次分類中才能看出比準確率要實用。

    總之:

    精準率:我們關注的那件事,預測的有多準。

    召回率:我們關注的那個事件真實的發生情況下,我們成功預測的比例是。

  7. 評價分類結果(下):F1 Score、ROC、AUC

    當精準率和召回率一個高一個低時該如何選擇取捨那?適場景而定

    在實際業務場景中,有很多沒有明顯的選擇,該如何在精準率和召回率中平衡,可以使用一個新的指標:F1 SCORE

    F1 SCORE: 是精準率和召回率的調和平均值:
    F1=2precisionrecallprecision+recall F1=\frac{2*precision*recall}{precision+recall}
    調和平均值,當其中某一個值高、另一個值低時,得到的Fs1 score也低;只有而且都非常高,F1纔會高。

    import numpy  as np
    def f1_score(precision, recall):
        try:
            return 2*precision*recall /(precision + recall)
        except:
            return 0.0
    

    0.9 0.1 --》 0.18…

    ROC曲線

    分類閾值、TPR和FPR

    分類閾值:設置判斷樣本爲正例的閾值threshold ?

    如果某個邏輯迴歸模型預測得到一個分數,但是這個分數是不是歸到一個類中,它需要一個判斷的條件,或者說是一個閾值,大於它,或者是小於他。

    sklearn中有一個方法:decision_function

    decision_scores = log_reg.decision_function(X_test)

    y_predict = np.array(decision_scores >=5, dtype = ‘int’)

    img

    TPR :預測爲1,且預測對了的數量,佔真實值爲1的數據百分比。(召回率)
    TPR=recall=TPTP+FN TPR=recall=\frac{TP}{TP+FN}

img

FPR:預測值爲1,單預測錯了的數量
FPR=FPTN+FP FPR=\frac{FP}{TN+FP}
ROC曲線:receiver operation characteristic Cureve,描述TPR和FPR之間的關係。x座標軸是FPR,y座標軸是TPR

TPR是所有真實值爲1中被判斷爲1的比例;FPR是真實值爲0中被錯誤判斷爲1的概率。理想情況下TPR=1 ,FPR=0。閾值取得最小正例預測值與最大負例預測值之間的值即可。
在這裏插入圖片描述

根據ROC曲線,x座標軸是FPR,y座標軸是TPR,我們想要真實值1中預測的越準確越好,即TPR越高越好,FPR是負例中錯誤的預測 成正確,這個值應該越少越好。因此也就是在左上角,說明效果越好。

當TPR=1,FPR=0,稱爲完美分類。當兩個算法的ROC曲線中隨便一點的TPR都要比兩外一個算法好,此時可以任務好的那個算法是兩個算法中我們想要的。

當兩個算法有交叉,這時無法判斷那個分類器較好時,按照餅乾哥的文章中說的可以計算曲線顯得面積AUC,作爲性能度量。???如何計算,請看AUC

AUC,在ROC曲線中,曲線下面的面試稱爲area under curve 。這個面積是小於1的。

AUC可以看做是由多個梯形的面積的和。

AUC=1,完美分類器;(0.5,1)優於隨機猜測。需要選取一個合適的閾值。AUC=0.5模型沒有預測價值;AUC<0.5 比隨機預測還差。

sklearn.metrics  roc_auc_score
roc_auc_score(y_test,decision_scores)
  1. 線性迴歸的評價指標:MSE、RMSE、MAE、R Squared

    線性迴歸模型,在使用最小二乘法,使訓練集與預測值的差的平方和最小,求出截距和係數,之後使用測試集進行測試,以此來衡量算法的好壞。

    均方誤差MSE:在最小二乘法的計算過程中均方和往往在項數越多時,結果越相差很大。因此需要將測試的數據集的個數進行抵消,因此:mean squared error
    1mi=1m(ytestiy^testi)2 \frac{1}{m}\sum_{i=1}^{m}(y_{test}^{i}-\hat{y}_{test}^{i})^2
    均方根誤差RMSE(解決量綱問題):root mean squarde error
    1mi=1m(ytestiy^testi)2=MSEtest \sqrt{\frac{1}{m}\sum_{i=1}^{m}(y_{test}^{i}-\hat{y}_{test}^{i})^2}=\sqrt{MSE_{test}}
    平均絕對誤差MAE: mean absolute error
    1mi=1mytest(i)y^test(i) \frac{1}{m}\sum_{i=1}^{m}|y_{test}^{(i)}-\hat{y}_{test}^{(i)}|
    R Square
    R2=1SSresidualSStotal=1(y^(i)y(i))2(yy(i))2 R^2=1-\frac{SS_{residual}}{SS_{total}}=1-\frac{\sum{(\hat{y}^{(i)}-y^{(i)})^2}}{\sum{(\overline{y}-y^{(i)})^2}}
    R Square <=1,

    它越大越好,因爲減數的分子這樣就越小,即預測值和真實值之差的平方和越小,錯誤率低。其最大值是1.

    當爲0時,則是基準模型,什麼叫做基準模型???

四、總結

​ 本文中分別介紹了:數據拆分,將數據拆分爲訓練數據集&測試數據集。同時對於分類KNN,介紹了結果的評價指標,他們分別是精準度、混淆矩陣、精準率、召回率、F1 Score、ROC曲線等,各類指標都有其應用的場景。最後介紹了線性迴歸算法的評價,可以用MSE、RMSE、MAE、R Squared,其中效果最好的是R Squared。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章