EX5 Bias v.s.Variance

EX5 偏差v.s.方差在正则线性回归下的体现

​ 在练习的前半段,你将利用正则化线性回归模型根据水库中水位变化来预测流出大坝的水量,之后的下半段练习中,将通过调试所学的算法的诊断效果,检查是偏差还是方差的影响。

数据的可视化

​ 首先对大坝保存的历史记录中德数据进行可视化,包括水位的变化x以及从坝流出的水量y,数据集主要分为以下三类:

  • 训练集:从中学习--建立模型 X,y
  • 交叉验证集:用于决定正则化的参数 Xval,yval
  • 测试集:用于检验模型的性能 Xtest,ytest
![1.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fh88xq3r99j20af07paa2.jpg)
**正则线性回归下的代价函数**

​ 计算公式为:2.jpg

​ 其中λ是控制正则化程度的正则化参数(从而有助于防止过拟合的出现)。 正则化项对过度成本J构成惩罚。随着模型参\(\theta_j\)的大小增加,惩罚也增加。 这里同样不需要正规化\(\theta_0\)项。

htheta = X*theta;
J = (sum((htheta-y).^2))/(2*m)+(lambda/(2*m))*(sum(theta(2:end,:).^2));

正则线性回归下的梯度计算

​ 相应的,其对\(\theta_j\)得偏微分定义为:3.jpg

grad = (X'*(X*theta-y))./m + lambda/m*theta;
grad(1) = grad(1) - lambda/m*theta(1);

拟合线性回归

​ 在这部分中,我们将正则化参数λ设置为零。 因为我们目前的线性回归实现是试图拟合一个二维的θ,正则化对于这样的低维度的θ将不会是非常有帮助的。 在后半段练习中将使用正则化的多项式回归。

![4.jpg](http://wx1.sinaimg.cn/mw690/7b8d2108gy1fh88xrg7a8j20c608s74f.jpg)
​ 最佳拟合线可以看出,该模型不适合原样本数据,因为原数据具有非线性模式。 虽然可视化最佳拟合被显示为调试学习算法的可能方法,但并不总能够可视化数据和模型。接下来我们将实现利用一个函数来生成学习曲线,以帮助对于不容易将数据可视化的情形下调试学习算法。

方差-偏差

​ 机器学习中的一个重要概念是偏差-方差的折衷(tradeoff)。 具有高偏差的模型对于原数据样本不够复杂,易出现欠拟合情形,而具有高方差的模型对训练数据的适应性很强却易出现过拟合。在这节练习中,将通过绘制在学习曲线上的训练和测试误差以诊断偏差方差 问题。

​ 要绘制学习曲线,需要针对不同大小的数据集计算训练和交叉验证集误差。 故首先应该使用原始训练集X的不同子集。具体对于训练集大小为i时,应该使用前i个样本(即,X(1:i,:)和y(1:i)。我们首先使用trainLinearReg函数来查找θ参数。 请注意,lambda作为参数传递给learningCurve函数。 学习θ参数后,应该计算训练和交叉验证集的错误。 回想一下,数据集的训练误差被定义为:

![5.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fh88xrw3hbj207k01sa9x.jpg)
​ 特别要注意,训练误差不应该包含正规化项。 计算训练误差的一种方法是使用现有的代价函数,并且只有在使用它来计算训练误差和交叉验证误差时,才将λ设置为0。

​ 在计算训练集误差时,应该确保在训练子集(即X(1:n,:)和y(1:n))上计算(而不是整个训练集)。 但是,对于交叉验证误差,应该在整个交叉验证集上进行计算(交叉验证是在默认样本集为规定数目下进行的)。learningCurve .m代码如下:

% ---------------------- Sample Solution ----------------------
for i = 1:m
    theta = trainLinearReg(X(1:i,:),y(1:i),lambda);
    error_train(i) = linearRegCostFunction(X(1:i,:),y(1:i),theta,0);
    error_val(i) = linearRegCostFunction(Xval,yval,theta,0);
end

​ 图形如下:

![6.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fh9fgxmvthj20a407jt8s.jpg)
从中易见,随着训练样本数目的增多,训练误差和交叉验证误差都很大。根据之前学习的内容知道该模型由high bias即高偏差的问题,线性系统过于简单从而不能很好的适应数据集。

多项式回归

​ 对于多项式回归的假设函数形式为:

\(h_\theta(x)=\theta_0+\theta_1*(waterLevel)+\theta_2*(waterLevel)^2+...+\theta_p*(waterLevel)^p\)

\(=\theta_0+\theta_1x_1+\theta_2x_2+...+\theta_px_p\)

​ 其中我们定义了\(x_1=(waterLevel),x_2=(waterLevel)^2,...,x_p=(waterLevel)^p\),我们得到一个线性回归模型,其中添加的特征features是原始值(waterLevel)的各次幂。

​ 现在需要完成polyfeatures.m中的程序,利用现存的特征x添加更多的特征,对大小为m × 1 的训练集X,你需要生成大小为m×p 的矩阵集X_poly。其中列1保存X的原始值,列2保持X^ 2,列 3保存X ^ 3的值,依此类推。代码如下:

% You need to return the following variables correctly.
X_poly = zeros(numel(X), p);%numel返回数组X中元素个数,该函数用于计算数组中满足指定条件的元素个数

for i = 1:p
    X_tmp = X.^i;
    X_poly(:,i) = X_tmp;
en

​ 在练习的ex5.m程序中预先给出了以下程序段:

%% =========== Part 6: Feature Mapping for Polynomial Regression =============
%  One solution to this is to use polynomial regression. You should now
%  complete polyFeatures to map each example into its powers
%
p = 8;

% Map X onto Polynomial Features and Normalize
X_poly = polyFeatures(X, p);
[X_poly, mu, sigma] = featureNormalize(X_poly);  % Normalize(特征缩放)-归一化与标准化
X_poly = [ones(m, 1), X_poly];                   % Add Ones

% Map X_poly_test and normalize (using mu and sigma)
X_poly_test = polyFeatures(Xtest, p);
X_poly_test = bsxfun(@minus, X_poly_test, mu);
X_poly_test = bsxfun(@rdivide, X_poly_test, sigma);
X_poly_test = [ones(size(X_poly_test, 1), 1), X_poly_test];         % Add Ones

% Map X_poly_val and normalize (using mu and sigma)
X_poly_val = polyFeatures(Xval, p);
X_poly_val = bsxfun(@minus, X_poly_val, mu);
X_poly_val = bsxfun(@rdivide, X_poly_val, sigma);
X_poly_val = [ones(size(X_poly_val, 1), 1), X_poly_val];           % Add Ones

fprintf('Normalized Training Example 1:\n');
fprintf('  %f  \n', X_poly(1, :));

上述代码中出现了特征缩放函数featureNormalize.m和bsxfun函数,特征缩放(Normalize)的具体内容补充如下:

function [X_norm, mu, sigma] = featureNormalize(X)
%FEATURENORMALIZE Normalizes the features in X 
%   FEATURENORMALIZE(X) returns a normalized version of X where
%   the mean value of each feature is 0 and the standard deviation
%   is 1. This is often a good preprocessing step to do when
%   working with learning algorithms.
mu = mean(X);
X_norm = bsxfun(@minus, X, mu);

sigma = std(X_norm);
X_norm = bsxfun(@rdivide, X_norm, sigma);
% ============================================================
end

这里又一次出现了bsxfun函数,尝试搜索后:

函数功能:applies an element-by-element binary operation to arrays a and b, with singleton expansion enabled.-->两个数组间元素逐个计算的二值操作。

熟知的外乘,即size为3×1的数组a和size为1×3的数组b相乘结果为size为3*3的矩阵c,c即为a和b中逐个元素相乘的结果。

@minus为相减操作,@rdivide为右除,相应的左除为:ldivide ,参考bsxfun

训练多项式回归

​ 请记住,即使我们在特征向量中有多项式项,我们仍然在解决线性回归优化问题。 多项式项简单地变成我们可以用于线性回归的特征。 因此我们任然能够使用本练习前面部分相同的成本函数和梯度计算。在学习多项式回归的参数θ之前,ex5.m将首先调用featureNormalize并对训练集的特征进行归一化,分别存储mu,sigma参数。 在学习参数θ 之后,我们可以绘出两条在λ = 0 下的多项式回归融合与学习曲线图像,如下所示:

![7.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fh9fgy1mgkj20ax07p3yn.jpg)
​ 上图可以看到多项式拟合效果很好,进而获得较低训练误差。 然而,多项式参与拟合的项是非常复杂的,多项式回归模型会出现过拟合现象,不能很好地推广。
![8.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fh9fgyu9a3j20ai07pglq.jpg)
​ 为了更好地理解非正则(λ= 0)模型下的问题,可以看出在学习曲线(图5)显示了低训练误差低的相同效果,但交叉验证误差较高。 培训和交叉验证错误之间存在差距,表明高方差问题。

​ 解决过拟合(高方差)问题的一个方法是对模型加正则化。 在本节中,将了解正则化参数如何影响正则多项式回归的偏差方差。 尝试修改ex5.m中的lambda参数,并令λ= 1,100; 对于这些值中的每一个,脚本应该生成对数据的多项式拟合以及学习曲线。

​ 对于λ= 1,您应该看到遵循数据趋势的多项式拟合和学习曲线(如下图所示),显示交叉验证和训练误差都收敛到相对较低的值。 这表明λ= 1正则多项式回归模型没有高偏差或高方差问题。 实际上,它实现了很好的权衡偏差和方差。

![9.jpg](http://wx2.sinaimg.cn/mw690/7b8d2108gy1fh9fh0pxrlj20al07qjrh.jpg)

10.jpg

​ 对于λ= 100,看到的是一个不符合数据的多项式拟合。 在这种情况下,正则化权重过大,模型不能适应训练数据。
![11.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fh9fh4g2tyj20ax07tdfy.jpg)

利用交叉验证集选择参数λ

​ 从以前的练习部分,可以观察到λ的值显着影响训练和交叉验证集上的正则多项式回归的结果。 特别地,没有正则化的模型(λ= 0)对训练集拟合效果很好,但不具备概括性(即对新的样本拟合效果差)。 相反,具有太多正则化(λ= 100)的模型不适合训练集和测试集合。 λ(例如,λ= 1)的良好选择可以提供对数据的良好拟合。

​ 在本节中,将实现一种自动化选择λ参数的方法。 具体来说,使用交叉验证集来评估每个λ值的拟合效果。 在使用交叉验证集选择最佳λ值后,我们可以对测试集上的模型进行评估,以估计模型对实际看不见的数据的执行情况。

​ 利用之前的函数trainLinearReg 训练模型在不同的参数λ 下的训练误差和交叉验证误差,参数λ 范围是:{0; 0:001; 0:003; 0:01; 0:03; 0:1; 0:3; 1; 3; 10},完成的函数validationCurve 如下:

function [lambda_vec, error_train, error_val] = ...
    validationCurve(X, y, Xval, yval)
    
% Selected values of lambda (you should not change this)
lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10]';

% You need to return these variables correctly.
error_train = zeros(length(lambda_vec), 1);
error_val = zeros(length(lambda_vec), 1);
for i = 1:length(lambda_vec)
    lambda = lambda_vec(i);
    theta = trainLinearReg(X,y,lambda);
    error_train(i) = linearRegCostFunction(X,y,theta,0);
    error_val(i) = linearRegCostFunction(Xval,yval,theta,0);
end

end
posted @ 2017-07-05 23:37  SrtFrmGNU  阅读(273)  评论(0编辑  收藏  举报