作业结构:
其中前面带星号的单变量线性回归的内容是必须完成的,而后面带十字架的多变量线性回归的内容是选做的。由于MATLAB和Octave的语法基本一样,而且学校里面用的MATLAB比较多,所以我这里就使用MATLAB来做这个作业了。
代码我已经上传到了GitHub上,需要的自取:代码地址
1 简单的Octave/MATLAB函数(Simple Octave/MATLAB function)
第一个任务需要将 warmUpExercise.m 文件中的 warmUpExercise() 函数补充完整,使其能够返回一个5x5的单位矩阵,构建n阶单位矩阵的函数为 eye(n),所以在函数中键入如下代码即可:
A = eye(5);
然后在到matlab的命令行里面测试函数是否正确:
>> warmUpExercise()
输出结果为:
ans =
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
2 单变量线性回归(Linear regression with one variable)
在这一部分中,我们将使用单变量线性回归来预测一家连锁餐厅的利润。假设你是一家餐厅的CEO,正在考虑在不同的城市开设一家新餐厅。因为该连锁店已经在多个城市开展,所以你可以获得这些城市的餐厅收益和人口的关系。现在希望你借助这些数据来预测下一次在哪个城市开连锁店受益最大。
ex1data1.txt文件包含本问题的数据集。第一列是城市的人口,第二列是连锁餐厅的利润,利润为负值代表亏损。
2.1 可视化数据(Plotting the Data)
在开始这项工作之前,我们可以通过将数据可视化的方式来更好的帮助我们理解这些数据。对于这个数据集,我们可以用散点图来可视化,因为只有两个参数(利润和人口)。
首先我们将plotData.m文件中的plotData(x, y)函数补充完整:
plot(x, y, 'rx', 'MarkerSize', 10); % Plot the data
ylabel('Profit'); % y轴为利润
xlabel('Population'); % x轴为人口
其中的 'rx' 代表红色的叉叉,后面的'MarkerSize', 10调节叉叉的大小。
将plotData(x, y)函数补充完整后在MATLAB命令行里面导入ex1data1.txt中的数据集,其中第一列为人口,这里放入矩阵x中;第二列为利润,这里放入矩阵y中,然后再调用函数plotData(x, y):
>> data = load('ex1data1.txt');
>> x = data(:, 1); y = data(:, 2);
>> plotData(x,y);
执行结果为:
2.2 梯度下降(Gradient Descent)
在这一部分,我们将使用梯度下降算法来找到该数据集的线性回归参数 θ 。
首先复习一下之前学习的几个公式:
-
假设函数(Hypothesis Function):
-
代价函数(Cost Function):
-
梯度下降(Gradient Descent):
不要忘了梯度下降算法需要同时更新 θj:
我们进行梯度下降算法的目标是为了找到最好的 θj 使得其对应的代价函数最小,在梯度下降算法的迭代过程中参数θj会不断接近最优值最后达到收敛。
2.2.1 计算代价函数
首先我们需要补充完整 computeCost.m文件中的 computeCost(x, y, theta) 函数来计算代价函数,根据代价函数的公式,我们不难写出:
m = length(y); % 数据集的数量
J = sum((x * theta - y) .^ 2) / (2*m); % 计算代价函数
为了验证代码是否正确,我们来执行一下。还是使用ex1data1.txt中的数据集,设置一些必要的参数,在命令行中执行如下代码:
>> data = load('ex1data1.txt');
>> x = [ones(m, 1), data(:,1)]; % 第一列全为1,第二列为人口
>> y = data(:, 2); % 利润
>> theta = zeros(2, 1); % 初始化一个全为0的2维向量 [θ0, θ1]T
>> J = computeCost(x, y, theta) % 执行函数
注:将x矩阵第一列设置为全1是为了方便矩阵运算:
运行结果为:2.2.2 实现梯度下降算法
我们需要补充完整 gradientDescent.m文件中的 gradientDescent(x, y, theta, alpha, num_iters) 函数来进行梯度下降,其中theta是我们要求的内容,alpha是学习率,num_iters是迭代次数,算法要求是经过num_iters次迭代后得到的theta能使代价函数J(θ)接近最小值**(因为经过num_iters次迭代不一定能达到最优值)。根据梯度下降的公式我们不难写出:
m = length(y); % 数据集的数量
for iter = 1:num_iters
theta = theta - alpha * (x' * (x * theta - y)) / m; % 梯度下降
c = computeCost(X, y, theta); % 计算更新后的theta值对应的代价函数
fprintf('%f\n', c); % 打印代价函数计算结果
end
判断一个梯度下降算法是否正常工作的方法是:每次迭代的代价函数值应该是永远不会增加的,并且是先下降然后收敛到一个稳定值。
然后我们来运行看看代码是否正确,首先初始化一些必要的参数,然后再运行gradientDescent函数:
>> x = [ones(m, 1), data(:,1)];
>> theta = zeros(2, 1);
>> iterations = 1500;
>> alpha = 0.01;
>> theta = gradientDescent(X, y, theta, alpha, iterations); % 运行梯度下降函数
结果如下:
可以看到代价函数值是在慢慢减小的,最终趋于稳定。
再打印一下求出的结果theta:
最后对数据进行可视化:
2.3 可视化代价函数(Visualizing J(θ))
这部分代码已经在ex1.m文件中写好:
theta0_vals = linspace(-10, 10, 100);
theta1_vals = linspace(-1, 4, 100);
J_vals = zeros(length(theta0_vals), length(theta1_vals));
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
J_vals = J_vals';
figure;
surf(theta0_vals, theta1_vals, J_vals)
xlabel('\theta_0'); ylabel('\theta_1');
figure;
contour(theta0_vals, theta1_vals, J_vals, logspace(-2, 3, 20))
xlabel('\theta_0'); ylabel('\theta_1');
hold on;
plot(theta(1), theta(2), 'rx', 'MarkerSize', 10, 'LineWidth', 2);
运行之后图像如下:
其中左边的是其等高线图,右边的则是其三维图像。
到这里必做部分就已经完成了,下面开始选做的部分,感兴趣的可以继续看下去。最后submit一下结果:
3 多变量线性回归(Linear regression with multiple variables)
在这一部分,我们会使用多变量线性回归来解决房价预测的问题。假设你想要出售你的房子并且想知道定一个怎样的价格才合适,对此,你可以采取收集最近的房屋交易数据,进而构建房屋价格模型。
ex1data2.txt 文件中包含了一系列训练集,其中第一列是房子的尺寸,第二列是卧室的数量,第三列是房子的价格。
3.1 特征归一化(Feature Normalization)
在训练集ex1data2.txt中可以看到,房子的尺寸和房子的卧室数量相差近1000倍,若此时使用特征归一化将特征变量的取值范围减小,可以使得梯度下降算法能够更快地收敛。
首先复习一下特征缩放的公式:
注:其中μn表示某一特征的平均值,sn表示某一特征的标准差(或该特征的最大值与最小值间的差)
根据特征缩放的公式,我们需要补充完整featureNormalize.m文件中的函数:
function [X_norm, mu, sigma] = featureNormalize(X)
X_norm = X;
mu = zeros(1, size(X, 2));
sigma = zeros(1, size(X, 2));
mu = mean(X); % 求平均值,返回一个1x2的矩阵
sigma = std(X); % 求标准差,返回一个1x2的矩阵
X_norm = (X - mu) ./ sigma; % 进行归一化
end
然后我们测试看代码是否正确,首先设置必要的参数,然后执行函数:
>> data = load('ex1data2.txt');
>> X = data(:, 1:2);
>> y = data(:, 3);
>> m = length(y);
>> [X mu sigma] = featureNormalize(X); % 执行特征缩放函数
然后我们打印缩放前后的X矩阵看看:
缩放前
缩放后
可以看到房子尺寸和房子卧室数量已经变成差不多数量级大小。
3.2 梯度下降(Gradient Descent)
多变量线性回归相较于上面的单变量多出了几个特征,相当于矩阵向量多加了几个维度,所以还是可以使用之前写的代码的:
故在 gradientDescentMulti.m 与 computeCostMulti.m 加入之前在单变量线性回归里写的代码即可:
J = sum((X*theta - y).^2) / (2*m); % 计算代价函数
theta = theta - alpha * (X' * (X * theta - y)) / m; % 更新参数
3.3 正规方程(Normal Equations)
首先是正规方程的公式:
根据公式我们可以写出代码:
theta = pinv( X' * X ) * X' * y;
注:使用正规方程求解theta时,我们可以不用特征缩放。pinv(X)函数可以求伪逆矩阵,而inv(X)函数只能对方阵求逆。
最后submit一下结果:
网友评论