机器学习--利用学习曲线观察模型泛化能力详解

前言

上一节说到了模型欠拟合和过拟合的概念知道,过拟合会导致模型的泛化能力很差,增加新的数据的话并不能预测较为准确的值,甚至错的离谱。那么我们怎么知道一个模型泛化能力的好坏呢?很容易想到的就是使用训练集测试集分离,我们用训练集进行模型的fit,然后拿测试集进行预测,最后对比测试集的特征数据预测出来的结果 对比测试集合的真实结果,就能知道这个模型预测的准确性和泛化能力。

除此之外也可以通过学习曲线取看一个模型的泛化能力,学习曲线随着样本的增多,算法训练出的模型的变现能力。让你能够清楚的知道使用train_test_split的意义,测试数据集的意义。 如果只有训练数据集,我们fit出来的模型进行测试的时候可能很好,出现可过拟合也不知到。通过测试集可以判断模型的好坏,不好的话,调整超参数等从新训练模型。但是也有问题,也有可能拟合测试数据集,即我们针对了测试数据集进行调参,一直到测试数据集达到好的效果,这就有可能出现这个模型效果好是只针对这个测试数据集。那么怎么解决呢?解决办法就是:验证数据集。验证数据集给训练数据集fit好的模型,然后调参等是模型达到较好效果,这样的话测试数据集就整个过程就没接触到模型的调整,最后进行预测就不会出现拟合测试数据集的情况,拿到泛化能力更好的模型。

动手实践

首先生成这样一个数据

np.random.seed(888)
x=np.random.uniform(-3.0,3.0,size=100) #生成x特征 -3到3  100个
X=x.reshape(-1,1)#将x编程100行1列的矩阵
y=0.5*x**2+x+2+np.random.normal(0,1,size=100)#模拟的是标记y  对应的是x的二次函数
plt.scatter(x,y)

机器学习--利用学习曲线观察模型泛化能力详解_第1张图片

绘制学习曲线,得到模型在训练数据集和测试数据集上的表现,训练数据集和测试数据集的性能变化。

from sklearn.model_selection import train_test_split#导入测试集训练集分隔函数
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=10)#分割出训练集和测试集

from sklearn.metrics import mean_squared_error#导入MSE函数
train_score=[]#及记录使用训练集数据的mse
test_score=[]#记录使用测试集的mse
#因为有75个样本  需要记录他们的学习过程
for i in range(1,76):
    lin_reg4=LinearRegression()#线性回归函数
    lin_reg4.fit(X_train[:i],y_train[:i])#拟合0到i的训练集
    
    #记录0到i训练数据的预测结果
    y_train_pre=lin_reg4.predict(X_train[:i])
    #记录0到i使用训练数据集得到的mse  
    train_score.append(mean_squared_error(y_train[:i],y_train_pre))
    
    #使用训练数据集0到i拟合后的模型,记录使用测试数据预测的结果
    y_test_pre =lin_reg4.predict(X_test)
    #测试数据集mse
    test_score.append(mean_squared_error(y_test,y_test_pre))
#画出的是均方根误差
plt.plot([i for i in range(1,76)],np.sqrt(train_score),label="train")
plt.plot([i for i in range(1,76)],np.sqrt(test_score),label="test")
plt.legend()
plt.show()

机器学习--利用学习曲线观察模型泛化能力详解_第2张图片

观察图可得,趋势上,训练数据集的误差是逐渐生高的,数据越多越难拟合。测试数据集的误差是下滑的曲线,使用非常少的样本训练的时候训练出的模型使用测试集误差很大,随着样本量的增多测试的误差就会逐渐减小,到达一定程度区域不变。总体趋于1.7,误差比较大,属于欠拟合情况

将以上求学习曲线方式封装成函数,只需要传入机器学习算法,即可得到学习曲线。

#封装成函数
def plot_learning_curve(algo,X_train,X_test,y_train,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_pre=algo.predict(X_train[:i])
        train_score.append(mean_squared_error(y_train[:i],y_train_pre))

        y_test_pre =algo.predict(X_test)
        test_score.append(mean_squared_error(y_test,y_test_pre))
        
    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()
plot_learning_curve(LinearRegression(),X_train,X_test,y_train,y_test)

利用以上函数 求多项式回归的学习曲线首先构建Pipeline,使用Pipeline进行多项式回归预测,Pipeline直接封装了将特征扩展多项式,数据归一化,构建线性回归,使用直接三部自动调用,sklearn并没有多项式回归的包。

degree=2的情况。

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures

def PolynomialRegression(degree):
    return Pipeline([#构建Pipeline
    ("poly",PolynomialFeatures(degree=degree)),#构建PolynomialFeatures
    ("std_scaler",StandardScaler()),#构建归一化StandardScaler
    ("lin_reg",LinearRegression())#构建线性回归LinearRegression
])

#
poly_reg2=PolynomialRegression(degree=2)
plot_learning_curve(poly_reg2,X_train,X_test,y_train,y_test)

机器学习--利用学习曲线观察模型泛化能力详解_第3张图片

对比观察线性回归学习曲线的区别,前者误差最终总体区趋于1.7左右,多项式回归总体趋于1.0左右。二阶的多项式拟合的结果比较好。这既是正好拟合的情况

degree=20的情况

poly_reg20=PolynomialRegression(degree=20)
plot_learning_curve(poly_reg10,X_train,X_test,y_train,y_test)

整体趋势到1.0, 稳定是间距还是比较大, 在训练数据上表现好,但是测试数据集上表现很差,说明出现了过拟合的情况

机器学习--利用学习曲线观察模型泛化能力详解_第4张图片

 

总结:

机器学习--利用学习曲线观察模型泛化能力详解_第5张图片

机器学习--利用学习曲线观察模型泛化能力详解_第6张图片

 

 

补充:

机器学习--利用学习曲线观察模型泛化能力详解_第7张图片

过拟合验证数据集,验证数据集出现极端数据,解决方法 交叉验证:

机器学习--利用学习曲线观察模型泛化能力详解_第8张图片

 

你可能感兴趣的:(Machine,Learning)