偏差-方差分解
參考鏈接:https://www.zhihu.com/question/20448464
https://blog.csdn.net/simple_the_best/article/details/71167786
算法在不同的訓練集的上學得的模型是不同的,即使訓練集來自同一分布。對測試樣本xxx,令yDy_{D}yD?為x\mathbf{x}x在數據集上的標記,yyy為x\mathbf{x}x的真實標記,f(x;D)f(\mathbf{x};D)f(x;D)為訓練集DDD上訓練所得模型fff在x(x不一定∈D)\mathbf{x}(\mathbf{x}不一定\in D)x(x不一定∈D)上的預測輸出。
算法在不同數據集DDD上的期望預測為:fˉ(x)=ED[f(x;D)]\bar{f}(x)=E_{D}[f(x;D)]fˉ?(x)=ED?[f(x;D)]
上式為從不同訓練集DDD上訓練的不同的fff,對輸入的x\mathbf{x}x的預測值的期望。
泛化誤差:
以回歸問題為例,模型的平方誤差期望為:err(x)=ED[(yD?f(x;D))2]err(\mathbf{x})=E_{D}[(y_{D}-f(\mathbf{x};D))^{2}]err(x)=ED?[(yD??f(x;D))2]
上式為從不同訓練集DDD上訓練的不同的fff,對輸入的x\mathbf{x}x的預測值誤差的期望。
偏差:模型期望預測值與真實值之間的偏離程度,刻畫了模型的擬合能力。
bias2(x)=(fˉ(x)?y)2bias^{2}(x)=(\bar{f}(x)-y)^{2}bias2(x)=(fˉ?(x)?y)2
方差:度量了相同樣本數量的不同訓練集的變動所導致的學習性能變化,刻畫了數據擾動所造成的影響。
var(x)=ED[(f(x;D)?fˉ(x))2]var(x)=E_{D}[(f(x;D)-\bar{f}(x))^{2}]var(x)=ED?[(f(x;D)?fˉ?(x))2]
噪聲: 樣本在數據集中的標記與真實標記的誤差。表示了算法期望泛化誤差的下限,刻畫了問題本身的難度。因為假設數據很爛,噪聲高,此時模型再厲害也很難學習好,造成了該問題很難解決。ε2=ED[(yD?y)2]\varepsilon^{2}=E_{D}[(y_{D}-y)^{2}]ε2=ED?[(yD??y)2]
為便于討論,假定無噪聲,ED[yD?y]=0E_{D}[y_{D}-y]=0ED?[yD??y]=0。對算法的期望泛化誤差進行分解:
上式推理中:ED[2(f(x;D)?fˉ(x))(fˉ(x)?yD)]=0E_{D}[2(f(\bm{x};D)-\bar{f}(\bm{x}))(\bar{f}(\bm{x})-y_{D})]=0ED?[2(f(x;D)?fˉ?(x))(fˉ?(x)?yD?)]=0,展開過程如下:
ED[f(x;D)fˉ(x)?f(x;D)yD?fˉ2(x)+fˉ(x)yD)]=ED[f(x;D)fˉ(x)?fˉ2(x)]+ED[fˉ(x)yD?f(x;D)yD]=fˉ(x)ED[f(x;D)]?fˉ2(x)+fˉ(x)ED(yD)?ED[f(x;D)yD]=fˉ2(x)?fˉ2(x)+fˉ(x)ED(yD)?fˉ(x)ED(yD)=0E_{D}[f(\bm{x};D)\bar{f}(\bm{x})-f(\bm{x};D)y_{D}-\bar{f}^{2}(\bm{x})+\bar{f}(\bm{x})y_{D})] \\ =E_{D}[f(\bm{x};D)\bar{f}(\bm{x})-\bar{f}^{2}(\bm{x})]+E_{D}[\bar{f}(\bm{x})y_{D}-f(\bm{x};D)y_{D}] \\ =\bar{f}(\bm{x})E_{D}[f(\bm{x};D)]-\bar{f}^{2}(\bm{x})+\bar{f}(\bm{x})E_{D}(y_{D})-E_{D}[f(\bm{x};D)y_{D}]\\ =\bar{f}^{2}(\bm{x})-\bar{f}^{2}(\bm{x})+\bar{f}(\bm{x})E_{D}(y_{D})-\bar{f}(\bm{x})E_{D}(y_{D})=0ED?[f(x;D)fˉ?(x)?f(x;D)yD??fˉ?2(x)+fˉ?(x)yD?)]=ED?[f(x;D)fˉ?(x)?fˉ?2(x)]+ED?[fˉ?(x)yD??f(x;D)yD?]=fˉ?(x)ED?[f(x;D)]?fˉ?2(x)+fˉ?(x)ED?(yD?)?ED?[f(x;D)yD?]=fˉ?2(x)?fˉ?2(x)+fˉ?(x)ED?(yD?)?fˉ?(x)ED?(yD?)=0
泛化誤差可分解為偏差、方差和噪聲之和。偏差-方差分解說明,為了取得好的泛化性能,則需使偏差較小,能夠充分擬合數據,并且使方差較小,使得數據擾動產生的影響小。
偏差與方差是有沖突的,稱為偏差-方差窘境(bias-variance dilemma).在訓練不足時,模型的擬合能力不強,訓練數據的擾動不足以使得模型產生顯著變化,此時偏差在主導了泛化誤差;隨著訓練程度的加深,學習器的擬合能力增強,訓練數據產生的擾動漸漸能被漸漸能被學到,方差主導了泛化錯誤率;在訓練程度充足時,模型的擬合能力非常強,訓練數據的發生的輕微擾動都會使得模型發生顯著變化。
如圖所示為多項式的次數與誤差的關系。
高偏差:相當于圖中的左側。
Jtrain(θ)較大,Jtrain(θ)≈JCV(θ)J_{train}(\theta)較大,J_{train}(\theta) \approx J_{CV}(\theta)Jtrain?(θ)較大,Jtrain?(θ)≈JCV?(θ)
高方差:相當于圖中的右側。
Jtrain(θ)較小,Jtrain(θ)?JCV(θ)J_{train}(\theta)較小,J_{train}(\theta) \ll J_{CV}(\theta)Jtrain?(θ)較小,Jtrain?(θ)?JCV?(θ)
訓練得到的模型太擬合訓練數據了。不同的訓練數據訓練的模型效果波動很大。
#學習曲線
參考:http://scikit-learn.org/stable/modules/learning_curve.html#learning-curve
學習曲線即為準確率隨訓練樣本數量的變化曲線。更多的訓練樣本有助于降低過擬合程度,在實踐中,收集更多的數據會帶來高昂的成本。通過將模型的訓練及驗證準確率看作是訓練數據集大小的函數,并繪制圖像,可以很容易看出收集更多的數據是否有助于解決問題。
使用威斯康星乳腺癌數據集繪制學習曲線:
import matplotlib
.pyplot
as plt
from sklearn
.model_selection
import learning_curve
from sklearn
.linear_model
import LogisticRegression
from sklearn
.preprocessing
import StandardScaler
from sklearn
.pipeline
import Pipeline
import pandas
as pd
import numpy
as np
from sklearn
.preprocessing
import LabelEncoder
from sklearn
.model_selection
import train_test_split
'''
讀取乳腺癌數據集
數據集前兩列存儲樣本ID和診斷結果(M代表惡性,B代表良性)
3~32列包含了30個特征
'''
df
= pd
.read_csv
('https://archive.ics.uci.edu/ml/machine-learning-databases'+ '/breast-cancer-wisconsin/wdbc.data',header
=None)
X
= df
.loc
[:, 2:].values
y
= df
.loc
[:, 1].values
le
=LabelEncoder
()
y
= le
.fit_transform
(y
)
X_train
, X_test
, y_train
, y_test
= train_test_split
(X
, y
, test_size
=0.2, random_state
=0)'''
在流水線中集成標準化操作以及分類器
PipeLine對象采用元組的序列作為輸入,每個元組第一個值為字符串,
可以通過字符串訪問流水線的元素,第二個值為sklearn中的轉換器或評估器
'''
pipe_lr
= Pipeline
([('scl', StandardScaler
()),('clf', LogisticRegression
(penalty
='l2', random_state
=0))
])
'''
learning_curve默認使用分層K折交叉驗證
'''
train_sizes
, train_scores
, valid_scores
= \learning_curve
(estimator
=pipe_lr
,X
=X_train
,y
=y_train
,train_sizes
=np
.linspace
(0.1, 1.0, 10),cv
=10)train_mean
= np
.mean
(train_scores
, axis
=1)
train_std
= np
.std
(train_scores
, axis
=1)
valid_mean
= np
.mean
(valid_scores
, axis
=1)
valid_std
= np
.std
(valid_scores
, axis
=1)plt
.plot
(train_sizes
, train_mean
, c
='blue', marker
='o', markersize
=5,label
='training accuracy')
plt
.fill_between
(train_sizes
,train_mean
- train_std
,train_mean
+ train_std
,alpha
=0.15, color
='blue')plt
.plot
(train_sizes
, valid_mean
, c
='green', marker
='o', markersize
=5,linestyle
='--', label
='validation accuracy')
plt
.fill_between
(train_sizes
,valid_mean
- valid_std
,valid_mean
+ valid_std
,alpha
=0.15, color
='green')plt
.grid
()
plt
.xlabel
('Number of training samples')
plt
.ylabel
('Accuracy')
plt
.legend
(loc
='best')
plt
.ylim
([0.8, 1.01])
plt
.show
()
從圖中可以看出,數據集樣本的數量在300~350之間時,泛化能力最強。模型在數據集較小的情況下,隨著樣本數量的增多訓練準確率下降,說明模型陷入了過擬合。在250樣本數量之后,模型趨于飽和和穩定,并具有輕微的過擬合現象。
#驗證曲線
驗證曲線是準確率與模型超參數之間的關系,可以從關系中看出超參數在什么時候泛化能力最強,以及什么時候會陷入欠擬合或者過擬合。
使用邏輯斯諦回歸中的正則化參數CCC繪制驗證曲線:
import matplotlib.pyplot as plt
from sklearn.model_selection import validation_curve
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split'''
讀取乳腺癌數據集
數據集前兩列存儲樣本ID和診斷結果(M代表惡性,B代表良性)
3~32列包含了30個特征
'''
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases'+ '/breast-cancer-wisconsin/wdbc.data',header=None)
X = df.loc[:, 2:].values
y = df.loc[:, 1].values
le =LabelEncoder()
# 將類標從字符串(M或B)變為整數的(0,1)
y = le.fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)'''
在流水線中集成標準化操作以及分類器
PipeLine對象采用元組的序列作為輸入,每個元組第一個值為字符串,
可以通過字符串訪問流水線的元素,第二個值為sklearn中的轉換器或評估器
'''
pipe_lr = Pipeline([('scl', StandardScaler()),('clf', LogisticRegression(penalty='l2', random_state=0))
])param_range = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
train_scores, valid_scores = \validation_curve(estimator=pipe_lr,X=X_train,y=y_train,# 可以通過estimator.get_params().keys()獲取param索引名param_name='clf__C',param_range=param_range,cv=10)train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
valid_mean = np.mean(valid_scores, axis=1)
valid_std = np.std(valid_scores, axis=1)plt.plot(param_range, train_mean, c='blue', marker='o', markersize=5,label='training accuracy')
plt.fill_between(param_range,train_mean - train_std,train_mean + train_std,alpha=0.15, color='blue')plt.plot(param_range, valid_mean, c='green', marker='o', markersize=5,label='validation accuracy')
plt.fill_between(param_range,valid_mean - valid_std,valid_mean + valid_std,alpha=0.15, color='green')plt.grid()
plt.xscale('log')
plt.xlabel('Parameter C')
plt.ylabel('Accuracy')
plt.legend(loc='best')
plt.ylim([0.8, 1.0])
plt.show()
從圖中可以看出,最優點在C=0.1附件。C值較小時,隨著C值越大,訓練準確率和驗證準確率逐漸上升,說明模型處于欠擬合;C值較大時,隨著C值越大,訓練準確率逐漸上升,驗證準確率下降,說明模型處于過擬合。
總結
以上是生活随笔為你收集整理的偏差-方差分解,学习和验证曲线评估模型的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。