斯坦福斯坦福机器学习第六周课后练习

来源:互联网 发布:淘宝查看足迹 编辑:程序博客网 时间:2024/05/16 17:07

本文整理自Coursera Machine Learning Exercise 5,提取出了训练一个模型的主要步骤。
matlab源码地址weekend6/LinearReg

1. visualizing the dataset
2. Model selection
2.0 Feature mapping and normalization
2.1 Model selection for p
2.2 Model selection for λ
3. Estimating generalization on test set

下面是分步解释
1.visualizing the dataset

一般情况下,要是数据集能事先可视化,那么在选择模型的时候就相对的有了一点谱;但如果不能可视化,凭后面的学习曲线来分析,我想也是能达到一样效果的。

%% Visualzing.m% Load from ex5data1: load('ex5data1.mat');m = size(X,1);plot(X,y,'rx','MarkerSize',10,'LineWidth',1.5);xlabel('Change in water level (x)');ylabel('Water flowing out of the dam (y)');

载入数据集之后我们可以看到,里面一共有三组分别是:训练集,验证集,测试集;且数据集的特征只有一个维度。

2.Model selection

原练习中直接选取了一个模型,不具有说明性;我们现在来假设几个模型,然后来进行筛选;下面列举了10个模型

1.hθ(x)2.hθ(x)3.hθ(x)10.hθ(x)=θ0+θ1x;p=1=θ0+θ1x+θ2x2;p=2=θ0+θ1x++θdxd++θ3x3;p=3=θ0+θ1x++θdxd++θ10x10;p=10

需要注意的是,现在虽然么个模型中有p个特征,且最高每个模型的最高幂次为p,但我们依然可以把它们看做线性模型,因为对于每一个特征xd我们都可以看成是xd=xd,也就是说把原来的xd次幂后看成一个新特征,就变成如下形式:

hθ(x)=θ0+θ1x1++θdxd++θpxp

所以我们就需要一个把原数据集映射到p维的函数。

2.0 Feature mapping and normalization

%% polyFeatures.mfunction [X_poly] = polyFeatures(X, p)X_poly = zeros(numel(X), p);X_poly = X;for i = 2:p    X_poly = [X_poly,X .^ i];endend

在映射完之后,我们就会发现特征值之间的范围差距特别大,比如x=40,x8=x8=408=6.5×1012,所以此时我们就需要进行Standardization,且后面的验证集,测试集都需要映射且要标准化。

%% featureNormalizaion.mfunction [X_norm, mu, sigma] = featureNormalize(X)% standardazationmu = mean(X);X_norm = bsxfun(@minus, X, mu);sigma = std(X_norm);X_norm = bsxfun(@rdivide, X_norm, sigma);end

里面关于bsxfun()函数的用法戳此处

2.1 Model selection for p

hθ(x)=θ0+θ1x++θdxd++θ5x5;p=5

当我们任意选取一个模型之后,接下来的工作就是训练参数了。下面用到的训练方法依然是ng提供的fmincg,我们前面也多次用到过这个函数,只需要提供代价函数,一个关于每个参数的梯度就能得到训练好的参数。(当然也可以梯度下降)

下面是代价函数以及梯度的求解,之所以一开始就预留了参数λ的位置,是因为:到底进不进行规则化我们开始是不知道的,要通过学习曲线来分析,如果不需要,我们在训练模型的时候把λ设为0就行了;如果需要,则传递相应的值即可,这样就更方便了。

%% linearRegCostFuntionfunction [J, grad] = linearRegCostFunction(X, y, theta, lambda)m = length(y); % number of training examplesJ = 0;grad = zeros(size(theta));h_theta = X*theta;squar_error = (1/(2*m))*(sum((h_theta-y).^2));regular_term = (lambda/(2*m))*(sum(theta.^2) - theta(1)^2);J = squar_error + regular_term;grad(1) = (1/m)*sum((h_theta - y).*X(:,1));for j = 2:size(theta,1)    grad(j) =  (1/m)*sum((h_theta - y).*X(:,j))+(lambda/m)*theta(j);endgrad = grad(:);end

下面是调用fminc来训练参数的函数

%% trainLinearReg.mfunction [theta] = trainLinearReg(X, y, lambda)initial_theta = zeros(size(X, 2), 1); % Create "short hand" for the cost function to be minimizedcostFunction = @(t) linearRegCostFunction(X, y, t, lambda);% Now, costFunction is a function that takes in only one argumentoptions = optimset('MaxIter', 200, 'GradObj', 'on');% Minimize using fmincgtheta = fmincg(costFunction, initial_theta, options);end
%%  p = 5lambda = 0;theta = trainLinearReg(X_poly,y,lambda);J_error = linearRegCostFunction(X_poly_val,yval,0);

此时,我们已经训练得到了当p=5时参数Θ(注意没有规则化),并且在验证集上计算出了代价值;接下来,我们也算出其余模型下的参数和代价值;

注意,在任何时候,我们只在训练的时候可能会要正则化项;但在训练好参数后计算误差时,都不需要正则化项,所以第四个参数我直接写成了0,不管前面λ是多少。

J_error = 29.433818 when p = 1.000000J_error = 6.994650  when p = 2.000000J_error = 5.768795  when p = 3.000000J_error = 9.216278  when p = 4.000000J_error = 15.629587 when p = 5.000000J_error = 21.576766 when p = 6.000000J_error = 9.19248   when p = 7.000000J_error = 7.810592  when p = 8.000000J_error = 8.389444  when p = 9.000000J_error = 8.618122  when p = 10.000000

后面两个是我顺便计算的,可以发现,只有当p=3的时候Jcverror(θ)是最小的,所以自然就选择了它;同样,我们再来看看其模型随p变化学习曲线:(关于学习曲线,参见此处)

learningCurveP

横坐标是p的值,也也可以看到:当p=3时,Jcverror(θ)最小;但此时我们仍然不清楚p=3这个模型的泛化能力怎么样,到底有没有达到欠拟合的状态,所以接下来我们就需要画出模型随数据集增长得学习曲线来进行分析。

这里写图片描述

我们可以明显的发现,随着训练集的增长,Jcverror仍然有下降的趋势,这就说明模型出现了过拟合的现象,泛化误差大需要规则化(或者增大数据集)。

2.2 Model selection for λ

p的选择一样,在选择λ的时候,也是先列出一系列的值,然后选择使得Jcverror(θ)值最小的模型对应的λ。同样,我们可以画出模型随λ变化的学习曲线,来选择最佳的值:

这里写图片描述

我们可以看出,当λ=1时,Jcverror(θ)最小,所以当然也就选择它了。此时,我们再来画出模型随数据集增长得学习曲线来分析其泛化能力:

这里写图片描述

可以发现,明显比没有规则化之前好多了。但是随着数据集的增大,Jcverror(θ)仍然有减小的趋势,说明该模型还是可能有点过拟合(高方差);而此时也就只能通过增大数据集来解决了。

3.Estimating generalization on test set

theta = trainLinearReg(X_poly,y,lambda);J_error = linearRegCostFunction(X_poly_test,ytest,theta,0);fprintf('J_error = %f\twhen p = %f\tlambda = %f\n',J_error,p,lambda);%% output J_error = 5.025814  when p = 3.000000   lambda = 1.000000

这里写图片描述

但是,其实原练习中选取的模型是p=8,λ=3,与这里的结果又一点差异。对于为什么p选8,我估计用的是两个嵌套循环来遍历了所有情况。

原创粉丝点击