【Coursera】Machine Learning Linear Regression 第一次编程作业

一、概述

作业分两部分,第一部分必做,第二部分选做。

简单到爆炸,很容易满分,就是有几个小细节要注意。

首先是submit错误问题,报错Submission failed: Error using submitWithConfiguration>validateResponse ,这里要配置curl和环境变量,当然win10是已经配置好的,可以略过这一步。

配置好之后修改作业中的lib文件夹中的submitWithConfiguration文件,修改131行和134行代码,在POST后加-s,如下:

json_command = sprintf('echo jsonBody=%s | curl -k -X POST -s -d @- %s', body, url);

然后就可以正常返回了,其实不正常返回的话,网站也收到你的代码并判分了,只是看不到optional部分是否做对,因为网站上只有分数,没有nice work的提示,因此还需要这个。

二、分析

1、单变量线性回归

其他的函数都是现成的,只需要自己写两个函数,一个是代价函数cost,一个是梯度下降函数Gradient descent。

代价函数指的是预测值与真实值之差,求出这个差的平方和再除以2m即可,类似方差。

注意以下几点:

代价函数的公式如下:

对应的代码如下:

J=(X*theta-y)'*(X*theta-y)/(2*m);

在这里,我们的X、theta、y都是矩阵,X*theta求出的是一个向量,也就是预测值组成的向量,减去y则是误差,求出的是一个误差向量。

我们需要误差的平方和——这时使用矩阵计算可以省去循环计算。

对向量取转置然后与原向量相乘,则可以直接得到平方和,然后除以2m即可。

一定要明确这里的变量都是矩阵或者向量,而公式中的都是实数,因此需要明确实数运算与矩阵运算的关系,对应起来,也就不难了。

梯度下降函数是为了更新theta的值,从而求出符合条件的theta。

原理就是求出某点的梯度,沿着梯度方向走alpha的长度,求出新的点坐标,更新,直到求出的新的坐标与原坐标的差极小,这时就是收敛了,可以返回符合条件的theta。

公式如下:

对应的代码如下:

for iter = 1:num_iters
    temp0=theta(1)-alpha/m*(sum(X*theta-y));
    temp1=theta(2)-alpha/m*(sum((X*theta-y).*X(:,2)));
    if(abs(theta(1)-temp0)<=0.0001&&abs(theta(2)-temp1)<=0.0001)
        theta(1)=temp0;
        theta(2)=temp1;
        break;
    end
    theta(1)=temp0;
    theta(2)=temp1;
    J_history(iter) = computeCost(X, y, theta);
end

首先注意一点,theta中的元素要求都改变之后,一起更新,这也就要求要用temp暂时保存theta的值,然后一起赋值。

注意到这里的求和是求一个向量的和,因此使用sum函数,求theta(2)的时候,比求theta(1)多了一个乘xi,这个xi指的不是X,而是“X的第二列的对应项”,因此要用点乘。

我在这里设置了一个收敛判断,如果变化量下雨等于0.0001,则视为收敛,退出循环。

这样基础分的100分就拿到了。

2、多变量线性回归

选做部分又分为两部分,其一是梯度下降求theta,其二是正规方程求theta。它们如果最后结果相同,说明计算正确。

①、梯度下降

与单变量不同,多变量的梯度下降有两个要点:

其一是Feature Normalization,也就是数据标准化。

在课程中这是通过求出每个特征的平均值和范围,然后令每个特征值减去平均值,再除以范围得到的。

这里的范围就是最大值减去最小值。但是题目中不同,题目中分母部分要求是standard deviations,也就是标准差,用它来代替范围。

其二是对于代价函数和梯度下降函数,要令其对n个特征的样本仍能正确求解,这要对代码进行更改。

首先是数据标准化,代码如下:

mu=mean(X);
sigma=std(X);
for i=1:size(X,2)
    X_norm(:,i)=(X_norm(:,i)-mu(i))/sigma(i);
end

matlab中的mean函数,求的是矩阵每一列元素的平均值,返回的是一个横着的向量;

std函数也一样,求的是每一列元素的标准差,返回横着的向量;

然后需要做的就是对X中的每一个值,减去对应的平均值,再除以对应的标准差。

注意这里是矩阵除以实数,实数都不一样,因此不能直接除,但可以按列循环除。

然后是多元变量的代价函数,代码如下:

J=((X*theta-y)'*(X*theta-y))/(2*m);

没有变化,因为我们使用矩阵计算,一元和多元在算法上没有任何区别。

最后是梯度下降函数,代码如下:

m = length(y); % number of training examples
J_history = zeros(num_iters, 1);
temp=zeros(length(theta),1);
for iter = 1:num_iter
    for i=1:length(theta)
        temp(i)=theta(i)-alpha/m*(sum((X*theta-y).*X(:,i)));
    end
    for i=1:length(theta)
        theta(i)=temp(i);
    end 
    J_history(iter) = computeCostMulti(X, y, theta);
end

这里由于theta的元素不止两个,因此temp也要开一个向量来存储,然后循环计算temp的值,循环更新theta即可。

这样就完成了多元线性回归有关梯度下降方面的代码。

接下来要实现选择不同的theta值画图像。

这个有点麻烦,最开始我是直接将下面这段代码复制多次来实现在一张图上画多个图像的:

% Choose some alpha value
alpha = 0.2;
num_iters = 400;

% Init Theta and Run Gradient Descent 
theta = zeros(3, 1);
[theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters);

% Plot the convergence graph
figure;
plot(1:numel(J_history), J_history, '-g', 'LineWidth', 2);
hold on
% Display gradient descent's result
fprintf('Theta computed from gradient descent: \n');
fprintf(' %f \n', theta);
fprintf('\n');

但是只能在多个窗口画多个图像,hold on没有用,接下来我只好选择为theta开矩阵,循环计算theta和J_history了,如下:

% Choose some alpha value
alpha=[0.01 0.05 0.1 0.2 0.5];
num_iters = 400;
% Init Theta and Run Gradient Descent 
theta = zeros(3, 5);
J_history=zeros(num_iters, 5);
for i=1:5
[theta(:,i), J_history(:,i)] = gradientDescentMulti(X, y, theta(:,i), alpha(i), num_iters);
fprintf('Theta computed from gradient descent: \n');
fprintf(' %f \n', theta(:,i));
fprintf('\n');
end
% Plot the convergence graph
figure;
plot(1:numel(J_history(:,1)), J_history(:,1), '-b', 'LineWidth', 2);
hold on
plot(1:numel(J_history(:,2)), J_history(:,2), '-g', 'LineWidth', 2);
plot(1:numel(J_history(:,3)), J_history(:,3), '-r', 'LineWidth', 2);
plot(1:numel(J_history(:,4)), J_history(:,4), '-y', 'LineWidth', 2);
plot(1:numel(J_history(:,5)), J_history(:,5), '-k', 'LineWidth', 2);
xlabel('Number of iterations');
ylabel('Cost J');
hold off

注意是theta(:,i)而不是theta(i),画图也要选多个颜色才看的清楚。

效果如图:

可以看出,在一定范围内,alpha越大,收敛得越快。

在计算1650,3这一样例的时候,注意把特征标准化,然后再计算,如下:

price = 0; % You should change this
sell=zeros(1,2);
sell(1)=(1650-mu(1))/sigma(1);
sell(2)=(3-mu(2))/sigma(2);
sell=[1 sell];
price=sell*theta(:,5);

如果计算正确,则这一结果会与下面的正规方程的结果相等。

②、正规方程法

这个简单多了,没有数据标准化,没有梯度下降,很简洁,代码量也很少。只有一行,如下:

theta=(inv(X'*X))*X'*y;

只需要把公式翻译过去即可。如果对方程的推导有疑问,可以参见下面这一博客:

线性回归 正规方程详细推导过程

然后直接计算即可。

③、结果

如图,最终预测结果都是293081.464335美刀,说明计算正确。

三、总结

机器学习的第一次上机学习,感觉还不错,应该是难度有点低,没有什么挑战性,但可能是第一次的缘故吧,对于matlab的一些函数调用还不是很熟,应该多加练习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值