分成两部分,一是本节课程内容的简要回顾,二是作业步骤的推导
程序打包网盘地址提取码1111
(按上课视频的顺序来)
1.将由训练集得到的假设函数应用到测试集,发现有很大的误差,可以用一些常见的调参方法。
2.在数据集划分上,训练集:交叉验证集:测试集=6:2:2。首先对不同的多项式次数d,训练训练集得到对应的参数theta,然后将这些参数应用到交叉验证集上,选取代价最小的d,如d=4,最后将这个d对应的参数应用到测试集上,评估参数的表现效果。
3.常用的调参方法如下:
(1)获得更多的训练实例——解决高方差
(2)尝试减少特征的数量——解决高方差
(3)尝试获得更多的特征——解决高偏差
(4)尝试增加多项式特征——解决高偏差
(5)尝试减少正则化程度 λ——解决高偏差
(6)尝试增加正则化程度 λ——解决高方差
对上面内容我的理解是,高方差为过拟合情况,即此时低偏差,如:
训练集误差0.1,测试集误差0.3,处于高方差情况。高偏差为训练集训练效果不好。调参方法的理解:
(1)训练集数据过少,如只有单个样本数据,训练集很好拟合,但测试集误差会很大。
(2)、(3)特征过多,会导致过拟合情况,此时会出现高方差。
(4)多项式特征过少,不能很好的拟合测试集,此时出现高偏差。
(5)、(6)正则化是为了解决过拟合问题,即增加λ来解决高方差,减少λ解决高偏差。
1.机器学习系统设计的例子:垃圾邮件分类,其常用方法是统计邮件数据集中前20000个出现频率最高的词,遍历查询某封邮件中是否出现对应的词,以向量形式作为输入集。
2.类偏斜skewed classes问题中,用查准率P precision和查全率R recall评估算法效果,如下图的P=0.8,R=0.5。综合权衡两者的关系式为2/(1/P+1/R),称为F score。
需要编辑以下的红色文件。(后续部分,需要填入的代码为深色框,已经提供的代码为浅色框。)
文件 | 内容 |
---|---|
ex5.m | 正则化线性回归主程序 |
ex4data1.mat | 数据集 |
featureNormalize.m | 特征标准化函数 |
fmincg.m | 优化函数 |
plotFit.m | 绘制多项式拟合图 |
trainLinearReg.m | 训练线性回归 |
linearRegCostFunction.m | 正则化的线性回归代价函数 |
learningCurve.m | 学习曲线 |
polyFeatures.m | 得到特征多项式 |
validationCurve.m | 输出交叉验证数据集的曲线 |
random_learningCurve.m | (可选作业)随机选择数据集的学习曲线 |
在作业的前半部分,实现正则化的线性回归-根据水库水位的变化(输入数据集)来预测从大坝流出的水量,后半部分通过调试学习算法来比较偏差bias - 方差variance的变化特点。
一如往常,主程序提供加载数据及数据画图的代码。
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)’);
输出:
注意到,这里只加载了training set训练集X和对应的输出集y,可以用下列代码查看mat文件的变量名:
b=whos(’-file’,‘ex5data1.mat’);
b.name
得到输出:
ans = X %121
ans = Xtest %211
ans = Xval %21*1
ans = y
ans = ytest
ans = yval
主函数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不进行正则化。
主函数这部分提供梯度函数接口及验证函数准确性:
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));
在linearRegCostFunction.m文件中填入代码:
grad = X' * (X * theta - y) / m;
grad(2:end) = grad(2:end) + lambda / m * theta(2:end);
主函数:
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值,将其绘制到数据图中。
主函数提供学习曲线函数入口,加载函数存储的训练集误差、交叉验证集误差。
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参数,代回到代价计算函数中,得到训练集代价和交叉集代价并存储。输出:
从这个图可以看出,随着训练集数目增加,训练集代价和交叉集代价都很大,因此属于高偏差的情况。作业中也有这种情况的题:
出现的原因为线性回归不能很好地拟合训练集、交叉验证集,因此下面用多项式回归来进行拟合。
主函数:
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))
注意到代码中测试集和交叉验证集都是使用训练集的平均值和方差,原因在于:测试集和交叉验证集是模拟真实环境的输入数据,无法提前求取平均值和方差。
主程序:
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
这里画出多项式回归的拟合线图以及随训练数目增加的学习曲线图。
主函数:
[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参数,然后求出对应的训练集误差和交叉验证集误差并存储。得到输出:
可以看出,在λ=3时,交叉验证集误差取得最小值,因此选择该值作为正则化参数。
前面已经由训练集和交叉验证集求得了最佳参数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 。
之前绘制学习曲线时,是利用前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
吴恩达机器学习编程作业ex5-Matlab版
吴恩达机器学习第六周学习笔记及编程作业答案