多维特征(Multiple Features)
多元线性回归,即包含多个变量,比如房子的房龄、面积、房间数等,标记如下:
假设函数就变成了:
可以理解为:
θ0表示基础价格
θ1为每平方价格,X1为平米数
θ2为每层价格,X2为层数
假设函数简写为:
梯度下降就变成了:
左图是之前单变量时的梯度下降,右图是多变量的梯度下降,二者对比如下:
特征值预处理
当几个特征的量级相差过大时,会出现左图的情况,收敛路径复杂且缓慢;
最好将特征都缩放到接近[-1, 1],就能像右图一样收敛形成圆润的等高线,加快收敛,减少迭代次数。
可以使用以下两个技术。
特征缩放(Feature Scaling)
将特征值除以 Xmax - Xmin,得到新的取值范围在1以内的特征。
均值归一(mean normalization)
将xi 替换为xi - ui 来使均值接近0。
两个技术同时应用,即采用以下公式:
ui = mean(x)
si = xmax - xmin
学习速率——α
debug梯度学习
为了确保梯度下降正常工作,可以观察 迭代次数 - 代价函数 的图像:
当J(θ)减少量少于 10-3 时可视为收敛。
学习速率 α 的选取
如果α 太大,可能会出现左侧两图的情况,要么J持续变大,要么上下波动。
但若α 太小,会造成收敛速度过慢。所以可按照以下序列尝试:
α = 0.001,0.003,0.01, 0.03, 0.1, 0.3,1 …
一边画出如上J与iter的函数图,观察效果。
多项式回归
观察面积和价格的关系,假设函数不一定是线性的,也可以是多项式的:
如果选用上面的多项式函数,那么假设函数在x继续增大时会下降,这是不合理的。
此时可选用下面蓝框中的平方根函数(或者三次函数)。
注意,此时特征缩放就很重要了。x x2 x3的量级可能相差巨大。
正态方程(Normal Equation)
不同于梯度下降法,正态方程能用代数方法直接求解最佳的θ值。
即分别令各个偏导为0,求解出θ值:
例如以下例子,可以构造出X和Y后,直接用下面红框里的公式计算出θ的值(具体为啥先不深究):
对比梯度下降法。
梯度下降:
- 需要选择α
- 需要多次迭代
- 当n很大时效果良好,复杂度O(kn2)
正态方程:
- 无需选择α
- 无需多次迭代
- 当n很大时,XT X是一个n * n的矩阵,计算n * n矩阵转置复杂度为O(n3)
- 无法解决逻辑回归和分类等问题
当 n < 1000时(1000个特征以内),会优先使用正态方程。
正态方程中XTX不可逆的情况
- 有多余特征,比如若x1 和 x2是线性相关的,那么XTX不可逆。
- 过多特征,比如 m <= n,样本数小于特征数时,需要删除一些特征,或做正则化(regularization)
Matlab / Octave 常用操作
参考:https://codeantenna.com/a/mVcQGKR7LB#1_3
基础操作
计算数值
>> 5 + 6
ans = 11
>> 3 * 4
ans = 12
>> 1/3
ans = 0.3333
>> 2^6
ans = 64
计算逻辑值
>> 1 == 2
ans = 0
>> 1 ~= 2
ans = 1
>> 1 && 0
ans = 0
>> 1 || 0
ans = 1
变量
>> a = 6
a = 6
>> a = 6; %加上分号可以使变量不打印输出
>>
打印变量
>> a = pi;
>> a
a = 3.1416
>> disp(a) %仅输出a的值
3.1416
>> disp(sprintf("2 decimals : %0.2f",a)) %打印字符串(用c语言的格式)
2 decimals : 3.14
>>
建立矩阵和向量
>> A = [1 2;3 4;5 6] %分号代表矩阵的换行
A =
1 2
3 4
5 6
>> v = [1 2 3] %表示行向量(1*3的矩阵)
v =
1 2 3
>> v = [1;2;3] %表示列向量(3*1的矩阵)
v =
1
2
3
>> v = 1:0.1:2 %表示从1~2每隔0.1取数,得到的是一个行向量
v =
1 至 8 列
1.0000 1.1000 1.2000 1.3000 1.4000 1.5000 1.6000 1.7000
9 至 11 列
1.8000 1.9000 2.0000
>> v = 1:6 %当然也可以不取间隔
v =
1 2 3 4 5 6
用特殊方法建立矩阵
>> ones(2,3) %建立2*3的矩阵,元素全部为1
ans =
1 1 1
1 1 1
>> 2*ones(2,3) %用2*矩阵,元素全部为2
ans =
2 2 2
2 2 2
>> zeros(2,2) %生成零矩阵
ans =
0 0
0 0
>> rand(1,3) %生成0~1的随机矩阵
ans =
0.8147 0.9058 0.1270
>> randn(1,3) %生成高斯分布矩阵(正态分布)均值为0,标准差为1
ans =
0.8622 0.3188 -1.3077
>> >> w = -6 + sqrt(10)*(randn(1,10000)); % 生成均值为-6,方差为10的10000个数据的矩阵
>> hist(w) %将这个矩阵用直方图的形式画出来
>> hist(w,50) %用50个竖条的直方图显示
>> eye(4) %生成单位矩阵
ans =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
>> eye(3)
ans =
1 0 0
0 1 0
0 0 1
移动数据
矩阵的大小
>> A = [1 2;3 4;5 6]
A =
1 2
3 4
5 6
>> size(A) %size()可以查看矩阵的大小
ans =
3 2
>> s = size(A)
s =
3 2
>> size(s) %size()本身返回的就是一个矩阵
ans =
1 2
>> size(A,1) %将返回A矩阵第一维度的大小(行数)
ans =
3
>> size(A,2) %将返回A矩阵第二维度的大小(列数)
ans =
2
>> v = [1 2 3 4]
v =
1 2 3 4
>> length(v) %返回行向量的长度
ans =
4
>> length(A) %返回较大的维度长度3
ans =
3
加载文件
>> load('ex1data1.txt') %使用load直接可以将文件中的数据读出来
>> who %显示当前工作区的变量
Your variables are:
A ans ex1data1 s v
>> size(ex1data1) %刚刚读的矩阵,查看长度
ans =
97 2
>> whos %查看当前工作区变量的详细信息
Name Size Bytes Class Attributes
A 3x2 48 double
ans 1x1 8 double
ex1data1 97x2 1552 double
s 1x2 16 double
v 1x4 32 double
>> clear(v) %删除变量,不加指定则删除全部变量
>> v = ex1data1(1:10) %取前10个元素
v =
1 至 8 列
6.1101 5.5277 8.5186 7.0032 5.8598 8.3829 7.4764 8.5781
9 至 10 列
6.4862 5.0546
>> save v.mat v %将v矩阵中的数据存到文件v.mat中去
以上是以二进制格式存储的,进行了压缩。如果想变得易读,可以用以下参数:
>> save v.txt v -ascii
操作矩阵数据
>> A
A =
1 2
3 4
5 6
>> A(3,2) %取A矩阵中第三行第二列的元素
ans =
6
>> A(2,:) %取A矩阵中第二行的所有元素
ans =
3 4
>> A(:,2) %取第二列的所有元素
ans =
2
4
6
>> A([1 3],:) %取A矩阵第一行和第三行的所有元素
ans =
1 2
5 6
>> A(:,2) = [10 15 20] %取出元素之后其实可以对其进行赋值
A =
1 10
3 15
5 20
>> A = [A,[100;150;200]] %在A矩阵后面追加一列
A =
1 10 100
3 15 150
5 20 200
>> A(:) %把A矩阵的所有元素放到一个列向量中
ans =
1
3
5
10
15
20
100
150
200
>> A = [1 2;3 4;5 6];
>> B = [11 12;13 14;15 16];
>> C = [A,B] %将两个矩阵拼接到一起
C =
1 2 11 12
3 4 13 14
5 6 15 16
>> C = [A;B] %分号表示换行,B矩阵放在A矩阵的下面
C =
1 2
3 4
5 6
11 12
13 14
15 16
计算数据
矩阵间运算
>> A = [1 2;3 4;5 6];
>> B = [11 12;13 14;15 16];
>> C = [1 1;2 2]
C =
1 1
2 2
>> A * C %A与C进行矩阵相乘
ans =
5 5
11 11
17 17
>> A .* B %'.*'代表矩阵中对应元素相乘
ans =
11 24
39 56
75 96
>> A .^ 2 %'.'代表对矩阵中的所有元素,乘方
ans =
1 4
9 16
25 36
>> v = [1 2 3]
>> v = 1 ./ v %取v矩阵的倒数
v =
1.0000 0.5000 0.3333
>> log(v) %对v取log运算
ans =
0 -0.6931 -1.0986
>> exp(v) %对v取e^v次方运算
ans =
2.7183 1.6487 1.3956
>> abs([-1;-2;3]) %对矩阵取绝对值运算
ans =
1
2
3
>> -v %对矩阵取相反数
ans =
-1.0000 -0.5000 -0.3333
>> v = [1;2;3];
>> v = v + ones(length(v),1) %将v中所有元素+1,先构造一个和v维度相同的矩阵(元素全为1),再把他们相加
v =
2
3
4
>> v = v +1 %实际上用+号就可以实现
v =
3
4
5
>> A' %一个撇号是求矩阵的转置
ans =
1 3 5
2 4 6
函数
>> a = [-0.2 9.8 4.5 8 2.0]
a =
-0.2000 9.8000 4.5000 8.0000 2.0000
>> val = max(a) %求矩阵的最大值
val =
9.8000
>> [val index] = max(a) %求矩阵的最大值并返回他的下标索引
val =
9.8000
index =
2
>> a < 3 %拿a中的所有元素和3比较返回结果
ans =
1×5 logical 数组
1 0 0 0 1
>> find(a<3) %返回满足条件的元素在a中的索引
ans =
1 5
>>A = magic(3) %幻方矩阵,每一行每一列包括对角线元素之和相等
A =
8 1 6
3 5 7
4 9 2
>> [r,c] = find(A>=7) %寻找A中大于等于7的元素索引,行和列
r =
1
3
2
c =
1
2
3
>> sum(a) %对矩阵中的元素求和
ans =
24.1000
>> prod(a) %对矩阵中的元素相乘
ans =
-141.1200
>> floor(a) %向下取整
ans =
-1 9 4 8 2
>> ceil(a) %向上取整
ans =
0 10 5 8 2
>> A
A =
8 1 6
3 5 7
4 9 2
>> max(A) %默认取每一列的最大值
ans =
8 9 7
>> max(A,[],1) %取每一列的最大值,1代表是第一维度
ans =
8 9 7
>> max(A,[],2) %取每一行的最大值
ans =
8
7
9
>> max(max(A)) %取A矩阵所有元素的最大值
ans =
9
>> max(A(:)) %或者先将矩阵A转化为列向量,在取最大值
ans =
9
>> sum(A,1) %求A每一列的和
ans =
15 15 15
>> sum(A,2) %求A每一行的和
ans =
15
15
15
>> A .* eye(3) %将单位矩阵与A中的元素相乘得到对角线的元素
ans =
8 0 0
0 5 0
0 0 2
>> sum(sum(A .* eye(3))) %求对角线元素的和
ans =
15
>> pinv(A) %求逆矩阵
ans =
0.1472 -0.1444 0.0639
-0.0611 0.0222 0.1056
-0.0194 0.1889 -0.1028
>> temp = pinv(A);
>> A*temp %发现这就是单位矩阵
ans =
1.0000 -0.0000 0.0000
0.0000 1.0000 -0.0000
-0.0000 0.0000 1.0000
绘制数据
>> t = [0:0.01:0.98];
>> y1 = sin(2*pi*4*t);
>> plot(t,y1); %用plot就可以画出对应的sin函数图像
>> y2 = cos(2*pi*4*t);
>> hold on; %在同一界面上画图像
>> plot(t,y2,'r'); %画出cos的函数图像,用red
>> xlabel('time'); %设置x轴坐标
>> ylabel('value'); %设置y轴坐标
>> legend('sin','cos'); %设置标识
>> title('my plot'); %设置标题
>> print -dpng 'myplot.PNG'; %将图像保存为PNG格式
>> figure(1); plot(t,y1); %对图像进行标号这样每个图象一个界面
>> figure(2); plot(t,y2);
>> subplot(1,2,1); %将界面分为1*2的区域,用第一块区域
>> plot(t,y1); %第一块区域画y1的图像
>> subplot(1,2,2); %用第二块区域
>> plot(t,y2); %第二块区域画y2的图像
>> axis([0.5 1 -1 1]); %设置图像的横纵坐标范围
>> A = magic(5) %5*5的幻方矩阵
A =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
>> imagesc(A); %矩阵也可以可视化
流程控制
>> v = zeros(10,1)
>> for i = 1:10, %i = 1:10,之后把v(i)的值变为2的i次方
v(i) = 2^i;
end %注意结束的时候加上end
>> v
v =
2
4
8
16
32
64
128
256
512
1024
>> i = 1;
>> while true, %while循环
v(i) = 999; %设置v(i)的值为999
i = i + 1;
if i == 6, %当i=6时跳出循环
break;
end
end
>> v
v =
999
999
999
999
999
64
128
256
512
1024
函数
将下面代码存储为squareThisNumber.m:
function y = squareThisNumber(x) %y是返回值,x为传入的参数
y = x^2
end
在该目录下执行下面语句,即可调用该函数:
>> squareThisNumber(5);
y =
25
多返回值的函数:
function [a,b] = squareTwoNumber(x)
a = x^2
b = x^3
end
>> squareTwoNumber(5) %y是返回值,x为传入的参数
a =
25
b =
125
ans =
25
定义代价函数如下:
function J = costFunctionJ(X,y,theta)
m = size(X,1); %数据集的个数
predictions = X*theta; %假设函数预测的结果矩阵
sqrErrors = (predictions - y) .^ 2; %与实际值得误差
J = 1/(2*m) * sum(sqrErrors); %计算代价函数
end
调用函数:
>> X = [1 1;1 2;1 3];
>> Y = [1;2;3];
>> X
X =
1 1
1 2
1 3
>> Y
Y =
1
2
3
>> theta = [0;1]
theta =
0
1
>> costFunctionJ(X,Y,theta) %theta0=0,theta0=1刚好拟合,故代价函数为0
ans =
0
>> theta = [0;0]
theta =
0
0
>> costFunctionJ(X,Y,theta)
ans =
2.3333
向量化
向量化的代码会更加简单明了。
假设函数
左侧的假设函数公式,可用右侧的向量化方式计算:
假设函数:
matlab函数:
function pre = prediction(X,theta)
pre = theta' * X; % ' 代表矩阵的转置
end
梯度下降
梯度下降更新公式:
matlab代码:
function Theta = UpdateTheta(X,Y,theta,alpha)
m = size(X,1);
Error = X * theta - Y;
delta = alpha/m * (X' * Error);
Theta = theta - delta;
end
作业
warmUpExercise.m
function A = warmUpExercise()
%WARMUPEXERCISE Example function in octave
% A = WARMUPEXERCISE() is an example function that returns the 5x5 identity matrix
% ============= YOUR CODE HERE ==============
% Instructions: Return the 5x5 identity matrix
% In octave, we return values by defining which variables
% represent the return values (at the top of the file)
% and then set them accordingly.
A = eye(5);
% ===========================================
end
plotData.m
function plotData(x, y)
%PLOTDATA Plots the data points x and y into a new figure
% PLOTDATA(x,y) plots the data points and gives the figure axes labels of
% population and profit.
figure; % open a new figure window
% ====================== YOUR CODE HERE ======================
% Instructions: Plot the training data into a figure using the
% "figure" and "plot" commands. Set the axes labels using
% the "xlabel" and "ylabel" commands. Assume the
% population and revenue data have been passed in
% as the x and y arguments of this function.
%
% Hint: You can use the 'rx' option with plot to have the markers
% appear as red crosses. Furthermore, you can make the
% markers larger by using plot(..., 'rx', 'MarkerSize', 10);
plot(x, y, 'rx', 'MarkerSize', 10); % Plot the data
ylabel('Profit in $10,000s'); % Set the y−axis label
xlabel('Population of City in 10,000s'); % Set the x−axis label
% ============================================================
end
computeCost.m
function J = computeCost(X, y, theta)
%COMPUTECOST Compute cost for linear regression
% J = COMPUTECOST(X, y, theta) computes the cost of using theta as the
% parameter for linear regression to fit the data points in X and y
% Initialize some useful values
m = length(y); % number of training examples
% You need to return the following variables correctly
% J = 0;
% ====================== YOUR CODE HERE ======================
% Instructions: Compute the cost of a particular choice of theta
% You should set J to the cost.
h = X * theta;
sqrErrors = (h - y) .^ 2;
J = 1 / (2 * m) * sum(sqrErrors);
% =========================================================================
end
gradientDescent.m
function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)
%GRADIENTDESCENT Performs gradient descent to learn theta
% theta = GRADIENTDESCENT(X, y, theta, alpha, num_iters) updates theta by
% taking num_iters gradient steps with learning rate alpha
% Initialize some useful values
m = length(y); % number of training examples
J_history = zeros(num_iters, 1);
for iter = 1:num_iters
% ====================== YOUR CODE HERE ======================
% Instructions: Perform a single gradient step on the parameter vector
% theta.
%
% Hint: While debugging, it can be useful to print out the values
% of the cost function (computeCost) and gradient here.
%
theta = theta - alpha / m * (X' * (X * theta - y))
% ============================================================
% Save the cost J in every iteration
J_history(iter) = computeCost(X, y, theta);
end
end
梯度下降公式:
theta = theta - alpha / m * (X' * (X * theta - y))
其中 X * theta - y
是 m * 1矩阵,
X'
是 (n+1) * m 矩阵,
(X' * (X * theta - y))
就是(n+1) * 1矩阵,
alpha / m
是标量,
结果得到theta
仍然是(n+1) * 1矩阵。
最后面的 xj(i) ,当j=0时,就是x0(i) ,用到的是X的第0列。
更新每个θ,只用到对应X的一个维度的值。
所以每次更新的矩阵是 alpha / m * (X' * (X * theta - y))
,X'
将X转置,每次相乘就用到了一列的值。