Experiment 1: Linear Regression
2024/3/6
1.导入数据
figure % open a new figure window
plot(x, y, 'o');
ylabel( Height in meters )
xlabel( Age in years )
这里plot(x, y, o );
里的o表示绘图里代表数据点的符号。
m = length(y); % store the number of training examples
x = [ones(m, 1), x]; % Add a column of ones to x
语句 x = [ones(m, 1), x];
表示将一个由 m
行、1列且所有元素均为1的矩阵(即向量)连接到矩阵 x
的左侧。这里的 m
代表的是训练样本的数量,因此 ones(m, 1)
生成了一个大小为 m×1
的列向量,每一行都是1。
2.梯度下降求θ
% 梯度下降
theta = zeros(size(x(1,:)))';
alpha = 0.07; % given
All_its = 1500; % 共迭代1500次
for i_its = 1:All_its % 开始循环,从1迭代到指定的最大迭代次数
grad = (1/m).* x' * ((x * theta) - y); % 计算梯度
theta = theta - alpha .* grad; % 更新theta,采用梯度下降法逐步逼近最小化损失函数的目标
end
在 MATLAB 或 Octave 等数学软件中,.
符号用于元素级别的运算,也称为点运算符。在表达式 theta = theta - alpha .* grad
中,.
作用于两个矩阵或向量之间,指示要进行逐元素(element-wise)的乘法。
这里的 alpha
是一个标量值(学习率),而 grad
是一个与 theta
同型的向量或矩阵,表示梯度。通过点运算符 .*
,程序将会分别计算 alpha
与 grad
中每个对应元素的乘积,然后再将结果逐个地从 theta
对应的元素中减去。
此处对梯度的计算,来自于梯度下降算法:
其中对
J
(
θ
)
J(θ)
J(θ)求偏导的结果(实验中为求导)即为grad。grad = (1/m).* x' * ((x * theta) - y);
hold on % Plot new data without clearing old plot
plot(x(:, 2), x * theta, '-')
legend('Training data', 'Linear regression')
hold off
x * theta
:这是一个矩阵乘法操作,x
是包含截距项的特征矩阵,theta
是线性回归模型的参数向量。经过矩阵乘法后,得到一个新的向量,它的每个元素是根据当前参数值计算出的对应训练样本的预测值。plot(x(:, 2), x * theta, '-')
:plot
函数用于绘制二维图形,第一个参数是 x 轴坐标(这里是年龄),第二个参数是 y 轴坐标(这里是根据当前theta
计算出的高度预测值),最后一个字符串'-'
表示绘制连续线段,即折线图。
这条命令实际上在图形上绘制了一条直线(或近似直线)。
此时theta为一个包含两个参数的二维向量:
测试样例:
predict1 = [1, 3.5] *theta;
predict2 = [1, 7] * theta;
3.对 J ( θ ) J(θ) J(θ)的理解
J_vals=zeros(100, 100); % 初始化一个零矩阵,目的是后续存储不同theta0和theta1的值下由J(θ)计算出的损失
theta0_vals = linspace(-3, 3, 100);
theta1_vals = linspace(-1, 1, 100);
for i = 1 :length(theta0_vals)
for j = 1 : length(theta1_vals)
t = [theta0_vals(i); theta1_vals(j)];
J_vals(i, j) = (0.5 / m) * (x * t - y)' * (x * t - y);
end
end
-
在MATLAB中,
linspace
函数是用来生成一系列等间距的数值向量。1linspace(start_value, end_value, num_of_points)
start_value
:指定生成向量的第一个元素的值。end_value
:指定生成向量的最后一个元素的值。num_of_points
:指定生成向量包含的元素个数。
对于
theta0_vals = linspace(-3, 3, 100);
这行代码,它意味着创建一个从-3
开始到3
结束的向量,并且在这个区间内均匀分配100
个点。所以,theta0_vals
向量将包含100
个介于-3
和3
之间的浮点数,它们之间的间隔是相同的:for i =1
从向量的第一个索引开始遍历直到最后一个索引。 -
t = [theta0_vals(i); theta1_vals(j)];
是用对应的theta0和theta1生成一个2*1的矩阵(二维列向量)。分号用来区分行。 -
J_vals(i, j) = (0.5 / m) * (x * t - y)' * (x * t - y);
是根据代价函数计算出在该theta0与theta1下的损失。并存储在之前申请的矩阵的对应位置。% 画图 J_vals = J_vals'; figure; surf(theta0_vals, theta1_vals, J_vals) xlabel('\theta_0'); ylabel('\theta_1');
因为J_vals
最初是以列优先的方式存储的(MATLAB和Octave默认的存储方式),则它对应的应该是Y轴方向上的变化,而非X轴方向。为了使surf
命令正确地按照预期展现三维曲面,即X轴方向变化对应Z值的第一维(行),Y轴方向变化对应Z值的第二维(列),就需要在调用surf
函数之前,对J_vals
矩阵进行转置操作。
4.附录
本次实验代码如下:
x = load('ex1x.dat');
y = load('ex1y.dat');
figure;
plot(x, y, 'o');
ylabel('Height in meters');
xlabel('Age in years');
m = length(y);
x = [ones(m, 1),x];
theta = zeros(size(x(1,:)))';
alpha = 0.07; % given
All_its = 1500; % 共迭代1500次
for i_its = 1:All_its % 开始循环,从1迭代到指定的最大迭代次数
grad = (1/m).* x' * ((x * theta) - y); % 计算梯度
theta = theta - alpha .* grad; % 更新theta,采用梯度下降法逐步逼近最小化损失函数的目标
end
hold on % Plot new data without clearing old plot
plot(x(:, 2), x * theta, '-');
legend('Training data', 'Linear regression');
hold off
predict1 = [1, 3.5] *theta;
predict2 = [1, 7] * theta;
% understanding J(θ)
J_vals=zeros(100, 100);
theta0_vals = linspace(-3, 3, 100);
theta1_vals = linspace(-1, 1, 100);
for i = 1 :length(theta0_vals)
for j = 1 : length(theta1_vals)
t = [theta0_vals(i); theta1_vals(j)];
J_vals(i, j) = (0.5 / m) * (x * t - y)' * (x * t - y);
end
end
J_vals = J_vals';
figure;
surf(theta0_vals, theta1_vals, J_vals)
xlabel('\theta_0');
ylabel('\theta_1');