如何评估和优化一个机器学习模型(1)?

62 阅读5分钟

1. 评估模型

一个模型在训练集上表现特别好,误差很小,一定是个好的模型吗? 不一定,因为创建模型的目的是能够预测新的数据。

在部署模型之前,如何测试一下模型的性能呢? 一般有两个办法:

  1. 将原始数据集拆分成训练集(Training)和测试集(Test)。 a. 使用训练数据拟合模型参数 b. 使用测试数据评估模型在新数据上的性能
  2. 使用 error 函数评估模型

1.1 拆分数据

建议数据的20%-40%作为测试集,使用sklearntrain_test_split函数拆分数据。 将18个数据拆分成训练集12个数据,测试集6个数据。训练数据和测试数据如图1所示。

image.png

2.2 线性回归模型的误差计算

在评估线性模型时,使用目标值和预测值之间的平方差进行平均,计算公式如下图。

image.png

2.3 比较测试数据和训练数据的表现

让我们构建一个高次多项式模型以最小化训练误差。然后计算该模型在测试数据和训练数据的误差值,如图3所示。

# create a model in sklearn, train on training data
degree = 10
lmodel = lin_model(degree)
lmodel.fit(X_train, y_train)

# predict on training data, find training error
yhat = lmodel.predict(X_train)
err_train = lmodel.mse(y_train, yhat)

# predict on test data, find error
yhat = lmodel.predict(X_test)
err_test = lmodel.mse(y_test, yhat)

结果表明,该模型在训练集上的误差为58.01, 但是在test集上的误差却高达:171215.01。 这样的模型会被描述为: 1) 过拟合 2) 高方差 3) 泛化性差

为什么呢? 把数据和模型曲线绘制出来就会发现:为了fit训练数据,模型是个非常复杂的函数,但是测试数据不是训练数据的一部分,所以这个复杂的高度定制的模型在测试数据上表现很差。如下图3:

image-2.png

如果把测试数据加入训练,模型在测试数据上也会变现的很好。问题是一旦把测试数据加入训练,那么测试数据也就不是新的Data了,也就无法测试模型在新的数据上的表现了。 因此,可以把数据分成三部分:训练数据、验证数据、测试数据。

3. 误差和方差

上面的例子,很明显是多项式模型的次数太高了。如何选择一个合适的呢? 测试集和验证集会给我们一些指导。通过尝试不同的degree值,在测试集和交叉验证集上评估性能,从而选择合适的次数。

3.2 寻找最佳的次数

使用不同的多项式次数训练模型。

max_degree = 9
err_train = np.zeros(max_degree)    
err_cv = np.zeros(max_degree)      
x = np.linspace(0,int(X.max()),100)  
y_pred = np.zeros((100,max_degree))  #columns are lines to plot

for degree in range(max_degree):
    lmodel = lin_model(degree+1)
    lmodel.fit(X_train, y_train)
    yhat = lmodel.predict(X_train)
    err_train[degree] = lmodel.mse(y_train, yhat)
    yhat = lmodel.predict(X_cv)
    err_cv[degree] = lmodel.mse(y_cv, yhat)
    y_pred[:,degree] = lmodel.predict(x)
    
optimal_degree = np.argmin(err_cv)+1

绘制不同的多项式次数获得的模型,分析不同的多项式对应的训练数据误差和交叉验证数据的误差。 我们把数据分成两部分,一部分数据用来fit模型,另一部分数据用来验证模型是否过拟合或者欠拟合。在这个例子中,我们通过增大所使用的多项式的次数,训练了一系列从过拟合到欠拟合的模型。

image-3.png

上图中的左边,实线代表不同次幂的模型。次幂为1的模型时一条直线,我们可以看到直线只与少数数据相交,而最高次幂的曲线非常接近于每个数据点。

右图,训练数据随着模型的复杂度增大,误差变小。交叉验证数据的误差最初随着模型开始拟合数据而减少,但随后随着模型开始在训练数据上过拟合(无法泛化)而增加。

3.3 调整正则化

正则化技术可以减少过拟合。 我们从高次多项式开始,调整正则化参数看看会发生什么?

lambda_range = np.array([0.0, 1e-6, 1e-5, 1e-4,1e-3,1e-2, 1e-1,1,10,100])
num_steps = len(lambda_range)
degree = 10
err_train = np.zeros(num_steps)    
err_cv = np.zeros(num_steps)       
x = np.linspace(0,int(X.max()),100) 
y_pred = np.zeros((100,num_steps))  #columns are lines to plot

for i in range(num_steps):
    lambda_= lambda_range[i]
    lmodel = lin_model(degree, regularization=True, lambda_=lambda_)
    lmodel.fit(X_train, y_train)
    yhat = lmodel.predict(X_train)
    err_train[i] = lmodel.mse(y_train, yhat)
    yhat = lmodel.predict(X_cv)
    err_cv[i] = lmodel.mse(y_cv, yhat)
    y_pred[:,i] = lmodel.predict(x)
    
optimal_reg_idx = np.argmin(err_cv) 

正则化参数·lambda· 从0逐渐变大到100时,多项式次数等于10,拟合到模型如下图所示: image-4.png

从图中可以看出,随着正则化参数的增大,模型逐渐从高方差过拟合过渡到高偏差欠拟合。右侧的直线部分是合适的正则化参数。

3.4 获取更多的数据,增大训练集大小

当模型过拟合的时候,增大训练集数据可以改善这一点。我们做实验验证这一点:

image-5.png

图中左侧表明,当训练数据最多时,拟合曲线丝滑的在数据点中间。在右侧,当训练数据逐渐变大时,训练集和交叉验证集的误差逐渐收敛到同一个值。虽然曲线并不丝毫,但这个趋势依然表明更多的数据能够改善泛化性。

这是第一部分针对线性模型的优化,第二部分讲神经网络的评估和优化。

注:文中的图来自于课程中的实验截图。