偏差-方差分解,学习和验证曲线评估模型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/winycg/article/details/80342038

偏差-方差分解

参考链接:https://www.zhihu.com/question/20448464
https://blog.csdn.net/simple_the_best/article/details/71167786
算法在不同的训练集的上学得的模型是不同的,即使训练集来自同一分布。对测试样本xx,令yDy_{D}x\mathbf{x}在数据集上的标记,yyx\mathbf{x}的真实标记,f(x;D)f(\mathbf{x};D)为训练集DD上训练所得模型ffx(xD)\mathbf{x}(\mathbf{x}不一定\in D)上的预测输出。
算法在不同数据集DD上的期望预测为:fˉ(x)=ED[f(x;D)]\bar{f}(x)=E_{D}[f(x;D)]
上式为从不同训练集DD上训练的不同的ff,对输入的x\mathbf{x}的预测值的期望。

泛化误差:
以回归问题为例,模型的平方误差期望为:err(x)=ED[(yDf(x;D))2]err(\mathbf{x})=E_{D}[(y_{D}-f(\mathbf{x};D))^{2}]
上式为从不同训练集DD上训练的不同的ff,对输入的x\mathbf{x}的预测值误差的期望。
偏差:模型期望预测值与真实值之间的偏离程度,刻画了模型的拟合能力。
bias2(x)=(fˉ(x)y)2bias^{2}(x)=(\bar{f}(x)-y)^{2}
方差:度量了相同样本数量的不同训练集的变动所导致的学习性能变化,刻画了数据扰动所造成的影响。
var(x)=ED[(f(x;D)fˉ(x))2]var(x)=E_{D}[(f(x;D)-\bar{f}(x))^{2}]
噪声: 样本在数据集中的标记与真实标记的误差。表示了算法期望泛化误差的下限,刻画了问题本身的难度。因为假设数据很烂,噪声高,此时模型再厉害也很难学习好,造成了该问题很难解决。ε2=ED[(yDy)2]\varepsilon^{2}=E_{D}[(y_{D}-y)^{2}]
为便于讨论,假定无噪声,ED[yDy]=0E_{D}[y_{D}-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})]=0,展开过程如下:
ED[f(x;D)fˉ(x)f(x;D)yDfˉ2(x)+fˉ(x)yD)]=ED[f(x;D)fˉ(x)fˉ2(x)]+ED[fˉ(x)yDf(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})=0
泛化误差可分解为偏差、方差和噪声之和。偏差-方差分解说明,为了取得好的泛化性能,则需使偏差较小,能够充分拟合数据,并且使方差较小,使得数据扰动产生的影响小。
偏差与方差是有冲突的,称为偏差-方差窘境(bias-variance dilemma).在训练不足时,模型的拟合能力不强,训练数据的扰动不足以使得模型产生显著变化,此时偏差在主导了泛化误差;随着训练程度的加深,学习器的拟合能力增强,训练数据产生的扰动渐渐能被渐渐能被学到,方差主导了泛化错误率;在训练程度充足时,模型的拟合能力非常强,训练数据的发生的轻微扰动都会使得模型发生显著变化。
在这里插入图片描述

这里写图片描述
如图所示为多项式的次数与误差的关系。
高偏差:相当于图中的左侧。
Jtrain(θ)Jtrain(θ)JCV(θ)J_{train}(\theta)较大,J_{train}(\theta) \approx J_{CV}(\theta)

高方差:相当于图中的右侧。
Jtrain(θ)Jtrain(θ)JCV(θ)J_{train}(\theta)较小,J_{train}(\theta) \ll J_{CV}(\theta)
训练得到的模型太拟合训练数据了。不同的训练数据训练的模型效果波动很大。

#学习曲线
参考: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()
# 将类标从字符串(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))
])
'''
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样本数量之后,模型趋于饱和和稳定,并具有轻微的过拟合现象。
这里写图片描述
#验证曲线
验证曲线是准确率与模型超参数之间的关系,可以从关系中看出超参数在什么时候泛化能力最强,以及什么时候会陷入欠拟合或者过拟合。
使用逻辑斯谛回归中的正则化参数CC绘制验证曲线:

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值越大,训练准确率逐渐上升,验证准确率下降,说明模型处于过拟合。
这里写图片描述

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试