机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归

分成两部分,一是本节课程内容的简要回顾,二是作业步骤的推导
程序打包网盘地址提取码1111

一、(Week 6)内容回顾

(按上课视频的顺序来)

  • 1.1第一部分:Advice for Applying Machine Learning

    1.将由训练集得到的假设函数应用到测试集,发现有很大的误差,可以用一些常见的调参方法。
    2.在数据集划分上,训练集:交叉验证集:测试集=6:2:2。首先对不同的多项式次数d,训练训练集得到对应的参数theta,然后将这些参数应用到交叉验证集上,选取代价最小的d,如d=4,最后将这个d对应的参数应用到测试集上,评估参数的表现效果。
    3.常用的调参方法如下:
    机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第1张图片
    (1)获得更多的训练实例——解决高方差
    (2)尝试减少特征的数量——解决高方差
    (3)尝试获得更多的特征——解决高偏差
    (4)尝试增加多项式特征——解决高偏差
    (5)尝试减少正则化程度 λ——解决高偏差
    (6)尝试增加正则化程度 λ——解决高方差

    对上面内容我的理解是,高方差为过拟合情况,即此时低偏差,如:机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第2张图片
    训练集误差0.1,测试集误差0.3,处于高方差情况。高偏差为训练集训练效果不好。调参方法的理解:
    (1)训练集数据过少,如只有单个样本数据,训练集很好拟合,但测试集误差会很大。
    (2)、(3)特征过多,会导致过拟合情况,此时会出现高方差。
    (4)多项式特征过少,不能很好的拟合测试集,此时出现高偏差。
    (5)、(6)正则化是为了解决过拟合问题,即增加λ来解决高方差,减少λ解决高偏差。

  • 1.2第一部分:Machine Learning System Design

1.机器学习系统设计的例子:垃圾邮件分类,其常用方法是统计邮件数据集中前20000个出现频率最高的词,遍历查询某封邮件中是否出现对应的词,以向量形式作为输入集。
2.类偏斜skewed classes问题中,用查准率P precision和查全率R recall评估算法效果,如下图的P=0.8,R=0.5。综合权衡两者的关系式为2/(1/P+1/R),称为F score。
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第3张图片
需要编辑以下的红色文件。(后续部分,需要填入的代码为深色框,已经提供的代码为浅色框。)

文件 内容
ex5.m 正则化线性回归主程序
ex4data1.mat 数据集
featureNormalize.m 特征标准化函数
fmincg.m 优化函数
plotFit.m 绘制多项式拟合图
trainLinearReg.m 训练线性回归
linearRegCostFunction.m 正则化的线性回归代价函数
learningCurve.m 学习曲线
polyFeatures.m 得到特征多项式
validationCurve.m 输出交叉验证数据集的曲线
random_learningCurve.m (可选作业)随机选择数据集的学习曲线

二、作业- Regularized Linear Regression 正则化线性回归

在作业的前半部分,实现正则化的线性回归-根据水库水位的变化(输入数据集)来预测从大坝流出的水量,后半部分通过调试学习算法来比较偏差bias - 方差variance的变化特点。

2.1 Part 1: Loading and Visualizing Data 绘图

一如往常,主程序提供加载数据及数据画图的代码。

load (‘ex5data1.mat’);
% m = Number of examples
m = size(X, 1);
% Plot training data
plot(X, y, ‘rx’, ‘MarkerSize’, 10, ‘LineWidth’, 1.5);
xlabel(‘Change in water level (x)’);
ylabel(‘Water flowing out of the dam (y)’);

输出:
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第4张图片注意到,这里只加载了training set训练集X和对应的输出集y,可以用下列代码查看mat文件的变量名:

b=whos(’-file’,‘ex5data1.mat’);
b.name

得到输出:

ans = X %121
ans = Xtest %21
1
ans = Xval %21*1
ans = y
ans = ytest
ans = yval

2.2 Part 2: Regularized Linear Regression Cost 正则化线性回归代价函数

主函数ex5提供了代价函数及测试接口,如下:

theta = [1 ; 1];
J = linearRegCostFunction([ones(m, 1) X], y, theta, 1);
fprintf(['Cost at theta = [1 ; 1]: %f '…
‘\n(this value should be about 303.993192)\n’], J);

正则化线性回归的代价函数为:
在这里插入图片描述
在向量化的基础下,需要在linearRegCostFunction.m文件中填入以下代码:

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

与之前一样,因为正则项regularization的第一项对应输入的特征量1,因此,约定俗成,在这里只选取2:end进行计算,对于θ0不进行正则化。

2.3 Part 3: Regularized Linear Regression Gradient 正则化线性回归梯度计算

主函数这部分提供梯度函数接口及验证函数准确性:

theta = [1 ; 1];
[J, grad] = linearRegCostFunction([ones(m, 1) X], y, theta, 1);
fprintf(['Gradient at theta = [1 ; 1]: [%f; %f] '…
‘\n(this value should be about [-15.303016; 598.250744])\n’], …
grad(1), grad(2));

机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第5张图片
linearRegCostFunction.m文件中填入代码:

grad = X' * (X * theta - y) / m;
grad(2:end) = grad(2:end) + lambda / m * theta(2:end);

2.4 Part 4: Train Linear Regression 训练线性回归

主函数:

lambda = 0;
[theta] = trainLinearReg([ones(m, 1) X], y, lambda);
% Plot fit over the data
plot(X, y, ‘rx’, ‘MarkerSize’, 10, ‘LineWidth’, 1.5);
xlabel(‘Change in water level (x)’);
ylabel(‘Water flowing out of the dam (y)’);
hold on;
plot(X, [ones(m, 1) X]*theta, ‘–’, ‘LineWidth’, 2)
hold off;

function [theta] = trainLinearReg(X, y, lambda)
% Initialize Theta
initial_theta = zeros(size(X, 2), 1);
% Create “short hand” for the cost function to be minimized
costFunction = @(t) linearRegCostFunction(X, y, t, lambda);
options = optimset(‘MaxIter’, 200, ‘GradObj’, ‘on’);
theta = fmincg(costFunction, initial_theta, options);
end

与之前一样,利用fmincg函数,迭代计算得到代价函数最小时的theta值,将其绘制到数据图中。
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第6张图片

2.5 Part 5: Learning Curve for Linear Regression 线性回归的学习曲线

主函数提供学习曲线函数入口,加载函数存储的训练集误差、交叉验证集误差。

lambda = 0;
[error_train, error_val] = …
learningCurve([ones(m, 1) X], y, …
[ones(size(Xval, 1), 1) Xval], yval, …
lambda);
plot(1:m, error_train, 1:m, error_val);
title(‘Learning curve for linear regression’)
legend(‘Train’, ‘Cross Validation’)
xlabel(‘Number of training examples’)
ylabel(‘Error’)
axis([0 13 0 150])
fprintf(’# Training Examples\tTrain Error\tCross Validation Error\n’);
for i = 1:m
fprintf(’ \t%d\t\t%f\t%f\n’, i, error_train(i), error_val(i));
end

learningCurve.m的前半部分:

m = size(X, 1);
% You need to return these values correctly
error_train = zeros(m, 1);
error_val = zeros(m, 1);

learningCurve.m文件中填入下列代码:

for i = 1:m
   X_train = X(1:i, :);
   y_train = y(1:i);
   theta = trainLinearReg(X_train,y_train, lambda);
   [J_train, grad] = linearRegCostFunction(X_train, y_train, theta, 0);   %lambda =0调用
   [J_val, grad] = linearRegCostFunction(Xval, yval, theta, 0);   %lambda =0调用
   
   error_train(i) =  J_train;
   error_val(i)   =  J_val;
end

由于要输出两个代价随训练集数目变化的关系,这里采用1:m的循环(注意到正则化代价是在求解theta参数中引入的,因此在描述训练集代价、交叉集代价时,不需加入正则项。),第i次循环中,选取训练集前i个数据,迭代训练出theta参数,代回到代价计算函数中,得到训练集代价和交叉集代价并存储。输出:
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第7张图片
从这个图可以看出,随着训练集数目增加,训练集代价和交叉集代价都很大,因此属于高偏差的情况。作业中也有这种情况的题:
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第8张图片
出现的原因为线性回归不能很好地拟合训练集、交叉验证集,因此下面用多项式回归来进行拟合。

2.6 Part 6: Feature Mapping for Polynomial Regression 多项式回归的特征缩放

主函数:

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, : ));

由于数据集中只有一个X输入,因此在多项式回归上这里采用增加x的n次幂项来添加多项式,需要在polyFeatures.m文件中填入下列代码:

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

从主函数中可以看到,这里采用p=8的最高次幂,如果x=40,则多项式特征为x8 =408=6.5×1012,训练效果会很差,因此在多项式特征上还需进行缩放:

function [X_norm, mu, sigma] = featureNormalize(X)
mu = mean(X); %X为129,mu为19
X_norm = bsxfun(@minus, X, mu);
sigma = std(X_norm);
X_norm = bsxfun(@rdivide, X_norm, sigma);

这部分代码已提前给出,不需修改。可以看到,首先mean计算矩阵X_poly每一列的平均值,bsxfun(@minus,)计算X_poly与平均值mu的差值(bsxfun会复制向量mu,即隐式扩展为9*9,实现两者的减法),相当于:

(A - mean(A))./std(A - mean(A))

注意到代码中测试集和交叉验证集都是使用训练集的平均值和方差,原因在于:测试集和交叉验证集是模拟真实环境的输入数据,无法提前求取平均值和方差。

2.7 Part 7: Learning Curve for Polynomial Regression 多项式回归的学习曲线

主程序:

lambda = 0;
[theta] = trainLinearReg(X_poly, y, lambda);
% Plot training data and fit
figure(1);
plot(X, y, ‘rx’, ‘MarkerSize’, 10, ‘LineWidth’, 1.5);
plotFit(min(X), max(X), mu, sigma, theta, p);
xlabel(‘Change in water level (x)’);
ylabel(‘Water flowing out of the dam (y)’);
title (sprintf(‘Polynomial Regression Fit (lambda = %f)’, lambda));
figure(2);
[error_train, error_val] = …
learningCurve(X_poly, y, X_poly_val, yval, lambda);
plot(1:m, error_train, 1:m, error_val);
title(sprintf(‘Polynomial Regression Learning Curve (lambda = %f)’, lambda));
xlabel(‘Number of training examples’)
ylabel(‘Error’)
axis([0 13 0 100])
legend(‘Train’, ‘Cross Validation’)
fprintf(‘Polynomial Regression (lambda = %f)\n\n’, lambda);
fprintf(’# Training Examples\tTrain Error\tCross Validation Error\n’);
for i = 1:m
fprintf(’ \t%d\t\t%f\t%f\n’, i, error_train(i), error_val(i));
end

这里画出多项式回归的拟合线图以及随训练数目增加的学习曲线图。
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第9张图片机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第10张图片

2.8 Part 8: Validation for Selecting Lambda 利用交叉验证集选择λ

主函数:

[lambda_vec, error_train, error_val] = …
validationCurve(X_poly, y, X_poly_val, yval);
close all;
plot(lambda_vec, error_train, lambda_vec, error_val);
legend(‘Train’, ‘Cross Validation’);
xlabel(‘lambda’);
ylabel(‘Error’);
fprintf(‘lambda\t\tTrain Error\tValidation Error\n’);
for i = 1:length(lambda_vec)
fprintf(’ %f\t%f\t%f\n’, …
lambda_vec(i), error_train(i), error_val(i));
end

validationCurve.m文件中已有代码:

function [lambda_vec, error_train, error_val] = …
validationCurve(X, y, Xval, yval)
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);

函数要输出不同lambda下的训练集误差和交叉验证集误差值,以选择交叉验证误差最低时的λ作为正则项系数。
因此,需要在validationCurve.m中填入代码:

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

在第i次循环中,首先计算出当前λ值的theta参数,然后求出对应的训练集误差和交叉验证集误差并存储。得到输出:
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第11张图片
可以看出,在λ=3时,交叉验证集误差取得最小值,因此选择该值作为正则化参数。

2.9 (可选作业)Computing test set error 计算测试集误差

前面已经由训练集和交叉验证集求得了最佳参数theta和λ,为了评估最终模型的效果,还需要计算该模型下测试集的误差。
本部分需要在主程序中添加以下代码:

%% =========== Part 9: Computing test set error =============
fprintf('Computing test set error:\n');
theta = trainLinearReg(X_poly, y, 3);
error_test = linearRegCostFunction(X_poly_test, ytest, theta, 0);

fprintf(['test set error = %f \n'...
        '(this value should be about 3.8599 for lambda =3)\n'],error_test);

fprintf('Program paused. Press enter to continue.\n');
pause;

由于之前得出λ=3为最佳参数,因此,这里只需将由λ=3求得的theta参数代回代价函数中,注意lambda仍取0(由于这里是计算误差,即评估模型效果),即可求得测试集误差error_test 。

2.10 (可选作业)Plotting learning curves with randomly selected examples 绘制随机选择训练集时的学习曲线

之前绘制学习曲线时,是利用前i个训练集作为i个训练集时的数据,为了体现随机性(尤其是在训练集数目较少时),应该随机选择i个训练集和i个交叉验证集,进行theta参数的求解。
需要在主函数中加入下列代码:

%% =========== Part 10:Plotting learning curves with randomly selected examples =============
lambda = 0.01;
[error_train, error_val] = ...
    random_learningCurve([ones(m, 1) X_poly], y, ...
                  [ones(size(Xval, 1), 1) X_poly_val], yval, ...
                  lambda);

plot(1:m, error_train, 1:m, error_val);
title('Learning curve for linear regression')
legend('Train', 'Cross Validation')
xlabel('Number of training examples')
ylabel('Error')


fprintf('# Training Examples\tTrain Error\tCross Validation Error\n');
for i = 1:m
    fprintf('  \t%d\t\t%f\t%f\n', i, error_train(i), error_val(i));
end

fprintf('Program paused. Press enter to continue.\n');
pause;

可以看到,这里和part5相近,不同的是选取λ=0.01,由于要随机选取样本,因此这里选择新建random_learningCurve.m文件并填入下列代码:

function [error_train, error_val] = ...
    random_learningCurve(X, y, Xval, yval, lambda)
m = size(X, 1);
error_train = zeros(m, 1);
error_val   = zeros(m, 1);

A1=[X y];
A2=[Xval yval];
for i = 1:m
   B1=A1(randperm(m,i),:);
   X_train = B1(:,1:size(X,2));
   y_train = B1(:,size(X,2)+1:size(A1,2));

   B2=A2(randperm(m,i),:);
   Xval = B2(:,1:size(Xval,2));
   yval = B2(:,size(Xval,2)+1:size(A2,2));

   theta = trainLinearReg(X_train,y_train, lambda);
   [J_train, grad] = linearRegCostFunction(X_train, y_train, theta, 0);   %lambda =0调用
   [J_val, grad] = linearRegCostFunction(Xval, yval, theta, 0);   %lambda =0调用

   error_train(i) =  J_train;
   error_val(i)   =  J_val;

end

这里与之前的learningCurve函数相似,只不过多了从训练集和交叉验证集中随机选取i个数据的代码,需要注意到,随机选择的输入输出集需要一一对应,故上面先将X、y装配成一个矩阵,再来选取。得到以下输出:
机器学习编程作业ex5(matlab/octave实现)-吴恩达coursera 多项式线性回归_第12张图片
由于随机选取数据的不确定性,上面的学习曲线可能每次都有不同,但随着训练集数目增加,验证集误差逐渐减小的趋势是相同的。

参考资料

吴恩达机器学习ex5
吴恩达机器学习编程作业ex5-Matlab版
吴恩达机器学习第六周学习笔记及编程作业答案

你可能感兴趣的:(机器学习,机器学习,matlab)