线性回归(Linear Regression)
简单的Octave/MATLAB函数(Simple Octave/MATLAB function)
将warmUpExercise.m文件中的warmUpExercise()补充完整,使其能够返回一个5*5的单位矩阵。在函数相应位置键入如下代码即可:
A = eye(5);
然后,我们在Octave中的CLI中键入如下命令测试warmUpExercise()是否正确:
% 先用cd命令“前往”warmUpExercise.m所在的文件目录
octave:2> warmUpExercise()
其输出结果为:
ans =
Diagonal Matrix
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
单变量线性回归(Linear regression with one variable)
假设你是一家连锁餐厅的CEO,且该连锁餐厅在各个城市开设了连锁店,因此你可以获得收益和城市人口相关的数据。现在希望你借助这些数据来预测在不同地方开设连锁店的收益。
ex1data1.txt文件为本问题的训练集,第一列表示城市人口,第二列为连锁店的利润,其中负值代表连锁店的亏损。在ex1.m文件中已经编写了相关代码将数据导入其中。
data = load('ex1data1.txt');
X = data(:, 1);
y = data(:, 2);
m = length(y); % number of training examples
任务一 可视化数据(Plotting the Data)
因此,我们需在plotData.m文件中将plotData()补充完整。
plot(x, y, 'rx', 'MarkerSize', 10);
xlabel('Population');
ylabel('Revenue');
将上述代码键入函数相应的地方,然后在Octave中测试一下。
octave:10> plotData(X, y);
其运行结果为:
在进行后两个任务之前,我们先把要用到的公式全部列一下:
- 假设函数hθ(x):hθ(x) = θ0 + θ1x
- 代价函数J:
- 梯度下降算法:
注:梯度下降算法是同时更新θj。
任务二 计算代价函数J(θ)(Computing the cost J(θ))
根据代价函数J(θ)的公式,我们不难写出如下代码:
J = sum((X*theta - y).^2) / (2*m);
好了,我们在Octave中键入如下代码来测试一下吧:
octave:7> X = [ones(m, 1), data(:, 1)];
octave:8> theta = zeros(2, 1);
octave:9> iterations = 1500;
octave:10> alpha = 0.01;
octave:11> J = computeCost(X, y, theta);
其输出结果为:
octave:12> J
J = 32.073
任务三 梯度下降算法(Gradient Descent)
我们可以设置一个临时变量theta_s,将变量theta的值赋值给这个临时变量theta_s,以保证计算完毕后θj同时更新。
在for循环之前,我们先将theta的值赋值给theta_s:
theta_s = theta;
然后再在for循环中添加计算θj的代码:
theta(1) = theta(1) - alpha / m * sum(X * theta_s - y);
theta(2) = theta(2) - alpha / m * sum((X * theta_s - y) .* X(:,2));
theta_s = theta;
注:我们在使用梯度下降算法时在矩阵X中新增了一列1(使其成为了第一列)。
X = [ones(m, 1), data(:,1)]; % Add a column of ones to x
之所以增加这一列是因为代价函数J中的θ0的系数为1,为了方便矩阵的运算,故添加此列。
我们在Octave中键入如下代码测试一下:
octave:7> X = [ones(m, 1), data(:, 1)];
octave:8> theta = zeros(2, 1);
octave:9> iterations = 1500;
octave:10> alpha = 0.01;
octave:11> J = computeCost(X, y, theta);
octave:12> J
J = 32.073
octave:13> theta = gradientDescent(X, y, theta, alpha, iterations);
其输出结果为:
octave:14> theta
theta =
-3.6303
1.1664
任务四 验证梯度下降算法(Debugging)
ex1.m文件中已将代码写好,我们将其键入Octave中观察输出结果:
octave:15> hold on;
octave:16> plot(X(:, 2), X*theta, '-');`
其输出结果为:
任务五 可视化代价函数J(θ)(Visualizing J(�))
该部分代码也在ex1.m文件中写好,我们将其键入Octave中观察输出结果:
octave:18> theta0_vals = linspace(-10, 10, 100);
octave:19> theta1_vals = linspace(-1, 4, 100);
octave:20> J_vals = zeros(length(theta0_vals), length(theta1_vals));
octave:22> for i = 1:length(theta0_vals)
> for j = 1:length(theta1_vals)
> t = [theta0_vals(i); theta1_vals(j)];
> J_vals(i, j) = computeCost(X, y, t);
> end
> end
octave:23> J_vals = J_vals';
octave:24> figure;
octave:25> surf(theta0_vals, theta1_vals, J_vals);
octave:26> xlabel('\theta_0');
octave:27> ylabel('\theta_1');
octave:28> figure;
octave:29> contour(theta0_vals, theta1_vals, J_vals, logspace(-2, 3, 20));
octave:30> xlabel('\theta_0');
octave:31> ylabel('\theta_1');
octave:32> hold on;
octave:33> plot(theta(1), theta(2), 'rx', 'MarkerSize', 10, 'LineWidth', 2);
其输出结果为:
选做题
多元线性回归(Linear regression with multiple variables)
假设你想要出售你的房子,你想知道现在你的房子在房屋交易中可以卖到什么价位。对此,你可以采取收集最近的房屋交易数据,进而构建房屋价格模型的方法。
ex1data2.txt文件中包含了房屋价格模型的训练集,第一列是房屋的大小,第二列是房间的数量,第三列是房屋的交易价格。
任务一 特征归一化(Feature Normalization)
在这个案例中,由于两个特征变量取值范围差异较大(在实际操作过程中,我们为了方便矩阵运算会添加一个值为1的特征变量)。如若直接使用梯度下降算法,其迭代次数较多。因此,我们先将特征归一化,即特征缩放,来让特征变量的取值范围缩小,使得在使用梯度下降算法时能够更快地收敛。
我们先把特征缩放的公式列一下:
其中μn表示某一特征的平均值,sn表示某一特征的标准差(或最大值与最小值间的差,即max-min)。
因此,我们在featureNormalize.m文件中可以照着公式添加如下代码:
mu = mean(X); % 求均值,返回值为1*2的矩阵
sigma = std(X); % 求标准差
X_norm = (X - mu) ./ sigma;
任务二 梯度下降(Gradient Descent)
与之前一样,我们先在X矩阵中添加一列1:
X = [ones(m, 1), X];
在此情况下,代价函数可以写成如下向量形式:
因此,我们可以在computeCostMulti.m文件中使用computeCost.m的代码(因为computeCost.m中的代码已经考虑到了多变量的情况),在gradientDescentMulti.m文件中添加如下代码:
theta = theta - alpha / m * X' * (X * theta - y);
任务三 正规方程(Normal Equations)
正规方程的公式为:
因此,我们在normalEqn.m文件中不难写出如下代码:
theta = pinv( X' * X ) * X' * y;
到了这里大家可以submit了,但还有一个附加作业——选择学习率α并预测1650 平方英尺 3 个卧室的房子的价格,我们还没有写。因此,我们现在来完成它。
我们在ex1_multi.m文件中修改学习率α的值来找到一个合适的学习率α。
fprintf('Running gradient descent ...\n');
% Choose some alpha value
alpha = 0.1;
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, '-b', 'LineWidth', 2);
plot(1:numel(J_history), J_history, 'r');
xlabel('Number of iterations');
ylabel('Cost J');
% Display gradient descent's result
fprintf('Theta computed from gradient descent: \n');
fprintf(' %f \n', theta);
fprintf('\n');
fprintf('Running gradient descent ...\n');
% Choose some alpha value
alpha = 0.03;
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, '-b', 'LineWidth', 2);
hold on;
plot(1:numel(J_history), J_history, 'g');
% Display gradient descent's result
fprintf('Theta computed from gradient descent: \n');
fprintf(' %f \n', theta);
fprintf('\n');
fprintf('Running gradient descent ...\n');
% Choose some alpha value
alpha = 0.01;
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, '-b', 'LineWidth', 2);
hold on;
plot(1:numel(J_history), J_history, 'y');
legend('alpha = 0.1', 'alpha = 0.03', 'alpha = 0.01');
% Display gradient descent's result
fprintf('Theta computed from gradient descent: \n');
fprintf(' %f \n', theta);
fprintf('\n');
其输出结果为:
根据此图,我们大概可以认为alpha = 0.1时,其学习率α较为合适。
最后我们通过梯度下降算法(alpha = 0.1)和正规方程法来预测一下房价,其中我们设置price=2000,即每平方英尺的售价为2000美元,其结果如下:
Predicted price of a 1650 sq-ft, 3 br house (using gradient descent):
$182861695.021679
Predicted price of a 1650 sq-ft, 3 br house (using normal equations):
$293081.464335
我们发现两种算法预测出的房价相差甚远,考虑到此处n=2,所以我们优先考虑正规方程法。