利用学习和验证曲线评估模型

偏差和方差

参考链接:https://www.zhihu.com/question/20448464
算法在不同的训练集的上学得的模型是不同的,即使训练集来自同一分布。对测试样本 x ,令 y D x 在数据集上的标记, y x 的真实标记, f ( x ; D ) 为训练集 D 上训练所得模型 f x 上的预测输出。 D 表示为相同样本的不同训练集。相同算法的期望预测为:

f ¯ ( x ) = E D [ f ( x ; D ) ]

偏差:期望预测值的期望与真实值之间的偏离程度。
b i a s 2 ( x ) = ( f ¯ ( x ) y ) 2

方差:度量了相同样本数量的不同训练集的变动所导致的学习性能变化,刻画了数据扰动所造成。 跟真实值没有直接关系。
v a r ( x ) = E D [ ( f ( x ; D ) f ¯ ( x ) ) 2 ]

噪声:样本在数据集中的标记与真实标记的误差。表示了算法期望泛化误差的下限,刻画了问题本身的难度。
ε 2 = E D [ ( y D y ) 2 ]

为便于讨论,假定 E D [ y D y ] = 0 ,因为 y D y 有正有负,结合后相互抵消。对算法的期望泛化误差进行分解:
E D [ ( f ( x ; D ) y D ) 2 ] = E D [ ( f ( x ; D ) f ¯ ( x ) ) 2 ] + ( f ¯ ( x ) y ) 2 + E D [ ( y D y ) 2 ] = b i a s 2 ( x ) + v a r ( x ) + ε 2

泛化误差可分解为偏差、方差和噪声之和。

这里写图片描述
如图所示为多项式的次数与误差的关系。
高偏差:相当于图中的左侧。
J t r a i n ( θ ) J t r a i n ( θ ) J C V ( θ )

高方差:相当于图中的右侧。
J t r a i n ( θ ) J t r a i n ( θ ) J C V ( θ )
训练得到的模型太拟合训练数据了。不同的训练数据训练的模型效果波动很大。

学习曲线

参考: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样本数量之后,模型趋于饱和和稳定,并具有轻微的过拟合现象。
这里写图片描述

验证曲线

验证曲线是准确率与模型超参数之间的关系,可以从关系中看出超参数在什么时候泛化能力最强,以及什么时候会陷入欠拟合或者过拟合。
使用逻辑斯谛回归中的正则化参数 C 绘制验证曲线:

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

猜你喜欢

转载自blog.csdn.net/winycg/article/details/80342038
今日推荐