機器學習“傻瓜式”理解(10)模型評估

過擬合與欠擬合問題

我們進行機器學習的目標是尋找出一個模型,使得這個模型對於我們的預測點能夠給予準確的解答,而不是讓其最大程度的擬合我們的訓練數據集的樣本點。我們將這種能力稱之爲模型的泛化能力。(解決模型泛化能力可以稱之爲機器學習領域十分重要的問題。)
評價方法
我們在之前的KNN中講過均方誤差(MSE),主要用來描述兩組數之間的相同程度。我們通過對X_predict預測出y_predict,然後讓其與y進行均方誤差的評估,均方誤差越小,擬合程度越高,模型就越可能產生過擬合現象;均方誤差越大,擬合程度越低,模型就越可能產生欠擬合。當均方誤差爲0時,模型擬合住了所有的數據。
模型複雜度
我們上面提到,在我們進行數據的擬合過程中會產生過擬合和欠擬合現象,產生過擬合的現象便是模型的複雜度較高,反之欠擬合的現象則模型的複雜度較低。
對於我們前面所講的算法,我們都可以通過超參數的調整來調整模型的複雜度。
在這裏插入圖片描述
概念解釋:
欠擬合:我們所得到的模型無法完整的表述數據間的關係。
過擬合:我們所得到的的模型過多的表述了數據間的關係,通常情況下我們的模型可能學習到了噪音。
對應於過擬合和欠擬合,尤其是過擬合現象,是我們在機器學習的過程中一直要重點解決的問題。
解決的方案我們之前提到過,將數據分爲訓練數據集和測繪數據集,通過網格搜索的方式尋找在測試數據集上最優的模型。(此種方式仍不是最好,後續我們接着介紹其他方式)
案例代碼 (使用scikit-learn)
①導入相關工具

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.pipeline import Pipeline

②生成數據,進行線性擬合,計算MSE

np.random.seed(666)
x = np.random.uniform(-3.0,3.0,size = 100)
X = x.reshape(-1,1)
y = 0.5 * x**2 + x + 2 + np.random.normal(0, 1, size=100)

X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=666)
lin = LinearRegression()
lin.fit(X_train,y_train)
y_predict = lin.predict(X_test)
result =  mean_squared_error(y_test,y_predict)
print(result)  #均方誤差:2.2199965269396573

③使用多項式迴歸

# degree = 2
poly_2 = polyCom(degree=2)
poly_2.fit(X_train,y_train)
y2_predict = poly_2.predict(X_test)
y2_result = mean_squared_error(y_test,y2_predict)
print(y2_result) #均方誤差:0.80356410562979

# degree = 10
poly_10 = polyCom(degree=10)
poly_10.fit(X_train,y_train)
y10_predict = poly_10.predict(X_test)
y10_result = mean_squared_error(y_test,y10_predict)
print(y10_result) #均方誤差:0.9212930722150794

# degree = 100
poly_100 = polyCom(degree=100)
poly_100.fit(X_train,y_train)
y100_predict = poly_2.predict(X_test)
y100_result = mean_squared_error(y_test,y100_predict)
print(y100_result) #均方誤差:14075796419.234262

如何得出的結果很差,則很有可能產生了過擬合。

學習曲線

通過上節的解釋我們可以瞭解到我們可以使用均方誤差(MSE)來具體的評估機器學習算法的評估性能。我們這一節將使用學習曲線來進行評估性能。
學習曲線的具體作用便是查看模型的學習效果,然後我們可以直觀可視化的查看到過擬合和欠擬合的現象。定義便是:隨着訓練樣本的逐漸增多,算法訓練出的模型的表現能力。
代碼封裝:

def plot_learning_curve(algo,X_train,y_train,X_test,y_test):
    train_score = []
    test_score = []

    for i in range(1,len(X_train) + 1):
        algo.fit(X_train[:i],y_train[:i])

        y_train_predict = algo.predict(X_train[:i])
        train_score.append(mean_squared_error(y_train[:i],y_train_predict))

        y_test_train = algo.predict(X_test[:i])
        test_score.append(mean_squared_error(y_test[:i],y_test_train))

    plt.plot([i for i in range(1,len(X_train) + 1)],np.sqrt(train_score),label="train")
    plt.plot([i for i in range(1, len(X_train) + 1)], np.sqrt(test_score), label="test")

    plt.legend()
    plt.axis([0,len(X_train)+1,0,4])
    plt.show()

然後我們在根據上節進行的步驟進行擬合:
通過一張圖片分析學習曲線:
在這裏插入圖片描述

驗證數據集和交叉驗證

我們進行模型評估的目的是爲了得出最佳的模型,也就是在測試數據集上表現比較好的模型,因爲這種方式得到的模型泛化能力強。爲了得到這種最佳的模型,我們需要通過不同的調參進行確定最佳模型。
通過劃分數據集進行調整參數有下面幾種方式:
①全部使用
將所有的數據全部投入試驗,得到模型後直接用於生產,這樣的做法看起來是在當前的數據集上誤差相對較小,但是如果發生了過擬合現象我們無從得知,因此此種方法不推薦。
②從筆記一開始我們便使用的方法,訓練測試分離,我們將在訓練數據集上訓練模型,然後通過測試數據集調整參數,目標便是使得在測試數據集上的均方誤差最小。但是此種方式也存在一定的弊端,那便是我們有可能實現產生在測試數據集上進行過擬合。
③此種方式是第二種方法的改進,我們將數據分爲訓練,驗證,測試數據集,相應的,每個數據集的功能一目瞭然,我們在訓練數據集上進行訓練模型,然後在驗證數據集上訓練適宜的超參數,然後拿到測試數據集上進行測試,但是這樣做同樣存在着問題,我們很有可能在驗證數據集上產生過擬合現象。因爲我們只有一份驗證數據集,如果驗證數據集上存在極端的數據然後通過此得到的準確率高的模型是不準確的。
④由此我們便得到了第四種方式,交叉驗證方式,我們將訓練數據集分爲三份,一份做驗證,另外兩份做訓練,每一種都進行這樣的劃分,得出的m個模型的性能平均值作爲最終衡量該組參數的對應的模型的性能指標。缺點便是性能較慢。極端情況下,這種方法可演變爲“留一法”,也就是訓練集一個爲驗證,其餘都是訓練,循環m次。
案例代碼演示
我們之前使用網格搜索(GridSearchCV:CV便是cross validation)就是使用的交叉驗證的方式。

import numpy as np
from sklearn.kneighbors import KNeighborsClassifier
# 使用scikit中的手寫數字數據集
from sklearn import datasets
from sklearn.model_selectino import train_test_split
# 交叉驗證
from sklearn.model_selection import GridSearchCV

digits = datasets.load_digits()
X = digits.data
y = digits.target

X_train,X_test,y_train,y_test = train_test_split(X,y)

param_grid = [
	{
		'weights',['distance'],
		'n_neighbors',[i for i in range(1,10)],
		'p',[i for i in range(1,6)]
	}
]
knn_clf = KNeighborsClassifier()
gd = GridSearchCV(knn_clf, param_grid, verbose=1, cv=3)
gd.fit(X_train, y_train)

# 學習
gd.best_params_
# 輸出:{'n_neighbors': 2, 'p': 2, 'weights': 'distance'}

# 獲取最佳的分類器,也就是最佳的模型,
best = gd.best_estimator_
best.score(X_test,y_test)
# 輸出:0.980528511821975 這便是真生的泛化能力值

偏差方差問題

我們在機器學習預測出的模型中會產生各種誤差,其中包括主要的兩種:
①偏差(Bias):結果偏離目標位置
②方差(Variance):數據間的分佈狀態,數據分佈的越集中方差越低,數據分佈的越分散,方差越高。
一般來說,我們在預測模型時產生的錯誤包括偏差+方差+不可避免的誤差。
我們通常的目標是去尋求一個偏差與方差的均衡。
原因分析
偏差產生的原因:
首先我們可能對模型本來的假設便不準確,例如最終模型將是一個多項式迴歸模型,但是我們的假設確實普通的線性模型,另外一個,模型的欠擬合現象也會導致偏差的產生。
方差產生的原因:
有可能模型在學習的過程中學習到很多的噪音,或者來說產生了過擬合現象,或者是預測出來的模型太過複雜,都有可能導致方差產生。

另外,方差和偏差兩者相互矛盾,在機器學習領域,我們解決的主要的問題是高方差的問題。

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