week2
4 多变量线性回归
4.1 多维特征
目前为止,我们探讨了单变量/特征的回归模型,现在我们对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为
(
x
1
,
x
2
,
…
,
x
n
)
(x_1,x_2,\ldots,x_n)
(x1,x2,…,xn)
增添更多特征后,我们引入一系列新的注释:
n
n
n 代表特征的数量
x
(
i
)
x^{(i)}
x(i) 代表第
i
i
i 个训练实例,是特征矩阵中的第
i
i
i 行,是一个向量(vector)。
例:
x
j
(
i
)
x^{(i)}_j
xj(i)代表特征矩阵中第
i
i
i 行的第
j
j
j 个特征,也就是第
i
i
i 个训练实例的第
j
j
j 个特征。
支持多变量的假设
h
h
h 表示为:
这个公式中有
n
+
1
n+1
n+1 个参数和
n
n
n 个变量,为了使得公式能够简化一些,引入
x
0
=
1
x_0=1
x0=1,则公式转化为:
此时模型中的参数是一个
n
+
1
n+1
n+1 维的向量,任何一个训练实例也都是
n
+
1
n+1
n+1 维的向量,特征矩阵
X
X
X 的维度是
m
∗
(
n
+
1
)
m * (n+1)
m∗(n+1)。
公式可以简化为:
其中上标
T
T
T 代表矩阵转置
4.2 多变量梯度下降
与单变量线性回归类似,在多变量线性回归中,我们也构建一个代价函数,则这个代价函数是所有建模误差的平方和,即:
其中:
多变量线性回归模型如下。为了简化,我们加入
X
0
=
1
X_0 = 1
X0=1,参数
θ
\theta
θ 为一个
n
+
1
n+1
n+1 维向量 vector。算法会同步更新每一个
θ
j
(
j
=
0
到
n
)
\theta_j (j = 0到n)
θj(j=0到n)
我们的目标和单变量线性回归问题中一样,是要找出使得代价函数最小的一系列参数。 多变量线性回归的批量梯度下降算法为:
即:
求导数后得到:
当
n
>
=
1
n>=1
n>=1 时
我们开始随机选择一系列的参数值,计算所有的预测结果后,再给所有的参数一个新的值,如此循环直到收敛。
代码示例:
1、计算代价函数
Python 代码:
def computeCost(X, y, theta):
inner = np.power(((X * theta.T) - y), 2)
return np.sum(inner) / (2 * len(X))
4.3 梯度下降法实践1-特征缩放
多维特征问题中,帮助梯度下降算法更快地收敛,特征需要具有相近的尺度(similar scale),这就需要我们进行 特征缩放Feature Scaling
假设两个特征,房屋尺寸的值为 0-2000 平方英尺,而房间数量的值为 0-5,对应的代价函数等高线图会显得很扁(skewed elliptical shape),梯度下降算法需要非常多次的迭代才能收敛(左图)
把房屋尺寸除以2000,房屋数量除以5,尝试将所有特征的尺度都尽量缩放到 -1 到 1 之间,得到了近乎圆形的等高线(右图)
尺度也不是必须要 -1 到1,但是范围不能很大,也不能很小
最简单的方法是均值归一化(Mean normalization)
x i = x i − μ i s i x_i = \frac{x_i-\mu_i}{s_i} xi=sixi−μi ,其中 μ i \mu_i μi 是平均值, s i s_i si 是标准差。
4.4 梯度下降法实践2-学习率
为保证梯度下降算法正确运行,可以绘制 迭代次数 iteration numbers 和 代价函数的图表,观测算法在何时趋于收敛(左边)
还有一些自动测试是否收敛的方法 (automatic convergence test),例如使用阈值 ε(右边)。因为阈值的大小很难选取,还是左侧的图表比较好
随着迭代次数增加,代价函数应该呈下降趋势。如果上升或者频繁升降,说明 α 取得太大,可能导致不能收敛。如果 α 取值太小,算法会运行的很慢,但还是下降的,通常会迭代很多次后收敛
学习率可以尝试如下值:
α
=
0.001
,
0.003
,
0.01
,
0.03
,
0.1
,
0.3
,
1
,
3
,
10
\alpha = 0.001,0.003,0.01,0.03,0.1,0.3,1,3,10
α=0.001,0.003,0.01,0.03,0.1,0.3,1,3,10
4.5 特征和多项式回归
不一定非要用已有特征,可以创造新的特征,例如:面积 = 长 * 宽。这时二次函数变成了单变量函数
h
θ
(
x
)
=
θ
0
+
θ
1
×
f
r
o
n
t
a
g
e
+
θ
×
d
e
p
t
h
h_\theta(x) = \theta_0+\theta_1\times frontage + \theta\times depth
hθ(x)=θ0+θ1×frontage+θ×depth
则
h
θ
(
x
)
=
θ
0
+
θ
1
x
h_\theta(x) = \theta_0+\theta_1x
hθ(x)=θ0+θ1x
线性回归并不适用于所有数据,有时我们需要曲线来适应我们的数据
二次方程模型:
h θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 2 h_\theta(x) = \theta_0+\theta_1x_1+\theta_2x_2^2 hθ(x)=θ0+θ1x1+θ2x22
三次方程模型:
h θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 2 + θ 3 x 3 3 h_\theta(x) = \theta_0+\theta_1x_1+\theta_2x_2^2+\theta_3x_3^3 hθ(x)=θ0+θ1x1+θ2x22+θ3x33
因为实际生活中,随着房屋面积上升、房价不可能减小,而二次曲线会先上升后下降。选择三次方模型,引入另外的变量替换高次幂,将其转换为线性回归模型
通常我们需要先观察数据然后再决定准备尝试怎样的模型。 另外,我们可以令:
x
2
=
x
2
2
,
x
3
=
x
3
3
x_2=x_2^2,x_3=x_3^3
x2=x22,x3=x33,从而将模型转化为线性回归模型
为了和曲线拟合的更好,还可以使用 平方根 square root
注:如果我们采用多项式回归模型,在运行梯度下降算法前,特征缩放非常有必要
4.6 正规方程
(1)正规方程的思想:假设代价函数 J(Θ) 的偏导数等于0,求解方程,得到使代价函数 J(Θ) 最小的参数 Θ。即求曲线的最低点(切线斜率为0)
最简单的情况,只有一维,代价函数是二次曲线:
如果有
n
n
n 个特征,则
θ
\theta
θ 为
n
+
1
n+1
n+1 维。针对代价函数
J
(
θ
)
J(\theta)
J(θ) 的每一项
J
(
θ
j
)
J(\theta_j)
J(θj) ,设其偏导数为 0 。通过数学方法求解方程,得到使代价函数
J
(
θ
j
)
J(\theta_j)
J(θj) 最小的
θ
j
\theta_j
θj。
正规方程是通过求解下面的方程来找出使得代价函数最小的参数的:
∂
∂
θ
j
J
(
θ
j
)
=
0
\frac{\partial}{\partial\theta_j}J(\theta_j)=0
∂θj∂J(θj)=0
(2)假设训练集特征矩阵为 X X X(包含 x 0 = 1 x_0 = 1 x0=1),训练集结果为向量 y y y ,则利用正规方程解出向量 θ = ( X T X ) − 1 X T y \theta=(X^TX)^{-1}X^Ty θ=(XTX)−1XTy 。 上标 T T T 代表矩阵转置,上标 − 1 -1 −1 代表矩阵的逆。设矩阵 A = X T X A=X^TX A=XTX ,则: ( X T X ) − 1 = A − 1 (X^TX)^{-1}=A^{-1} (XTX)−1=A−1 ,则解 θ \theta θ 可以通过公式求出:
θ = ( X T X ) − 1 X T y \theta=(X^TX)^{-1}X^Ty θ=(XTX)−1XTy
例子,四个数据:
即:
解
θ
\theta
θ 为:
在 Octave 中,正规方程写作:
pinv(X'*X)*X'*y
注:对于那些不可逆的矩阵(通常是因为特征之间不独立,如同时包含英尺为单位的尺寸和米为单位的尺寸两个特征,也有可能是特征数量大于训练集的数量),正规方程方法是不能用的
(3)梯度下降和正规方程的比较
梯度下降 | 正规方程 |
---|---|
需要选择学习率 α \alpha α | 不需要 |
需要多次迭代 | 一次运算得出 |
当特征数量 n n n 大时也能较好适用 | 需要计算 ( X T X ) − 1 (X^TX)^{-1} (XTX)−1 如果特征数量 n n n 较大则运算代价大,因为矩阵逆的计算时间复杂度为 O ( n 3 ) O(n^3) O(n3) ,通常来说当 n n n 小于10000 时还是可以接受的 |
适用于各种类型的模型 | 只适用于线性模型,不适合逻辑回归模型等其他模型 |
总结:
1、特征变量的数目 n 不大的时候,推荐使用正规方程。
2、n 比较大的时候(例如10000),考虑梯度下降。
3、某些算法(例如分类算法中的逻辑回归)不能使用正规方程法,只能使用梯度下降。
当我们讲到分类算法,像逻辑回归算法,我们会看到,实际上对于那些算法,并不能使用正规方程法。对于那些更复杂的学习算法,我们将不得不仍然使用梯度下降法。因此,梯度下降法是一个非常有用的算法,可以用在有大量特征变量的线性回归问题。或者我们以后在课程中,会讲到的一些其他的算法,因为正规方程法不适合或者不能用在它们上。但对于这个特定的线性回归模型,正规方程法是一个比梯度下降法更快的替代算法。所以,根据具体的问题,以及你的特征变量的数量,这两种算法都是值得学习的。
正规方程的python实现:
import numpy as np
def normalEqn(X, y):
theta = np.linalg.inv(X.T@X)@X.T@y #X.T@X等价于X.T.dot(X)
return theta
4.7 正规方程及不可逆性
当矩阵 X T X X^TX XTX 不可逆怎么办? 不可逆的问题很少发生,即使发生,使用 p i n v ( ) pinv() pinv() 也能正常算出结果
- | - | - |
---|---|---|
pinv() | pseudo-inverse伪逆 | 即使 singular degenerate 也能算出来逆矩阵 |
inv() | inverse逆 | 引入了先进的数值计算的概念 |
两种情况可能导致不可逆:
1、有冗余特征 redundant features,即特征值线性相关(例如 x1 = 常数 * x2)
解决:删除冗余特征
2、特征维数 n ≤ 数据规模 m (例如10个样本适应100+1个参数)
解决:删除特征,或者使用线性代数中的正则化 regularization方法
首先,看特征值里是否有一些多余的特征,像这些
x
1
x_1
x1 和
x
2
x_2
x2 是线性相关的,互为线性函数。同时,当有一些多余的特征时,可以删除这两个重复特征里的其中一个,无须两个特征同时保留,将解决不可逆性的问题。因此,首先应该通过观察所有特征检查是否有多余的特征,如果有多余的就删除掉,直到他们不再是多余的为止,如果特征数量实在太多,我会删除些用较少的特征来反映尽可能多内容,否则我会考虑使用正规化方法。 如果矩阵
X
′
X
X'X
X′X 是不可逆的,(通常来说,不会出现这种情况),如果在Octave里,可以用伪逆函数
p
i
n
v
(
)
pinv()
pinv() 来实现。这种使用不同的线性代数库的方法被称为伪逆。即使
X
′
X
X'X
X′X 的结果是不可逆的,但算法执行的流程是正确的。总之,出现不可逆矩阵的情况极少发生,所以在大多数实现线性回归中,出现不可逆的问题不应该过多的关注
X
T
X
X^TX
XTX 是不可逆的
5 Octave教程
5.1 基本操作
(1)简单运算
不等于符号的写法是这个波浪线加上等于符号 ( ~= ),而不是等于感叹号加等号( != ):
1 == 1 % 判断相等
1 ~= 2 % 判断不等
1 && 0 % 求逻辑与
1 || 0 % 求逻辑或
xor(1, 0) % 求异或
简化命令行:
PS1('>> ');
分号 semicolon 不打印结果:
>> a = 3; %semicolon supressing output
浮点数的输出:
>> a = pi;
>> a
a = 3.1416
>> disp(a);
3.1416
>> disp(sprintf('2 decimals: %0.2f', a))
2 decimals: 3.14
>> disp(sprintf('6 decimals: %0.6f', a))
6 decimals: 3.141593
控制输出格式的长短:
>> format long
>> a
a = 3.141592653589793
>> format short
>> a
a = 3.1416
(2)向量和矩阵
>> A = [1 2; 3 4; 5 6]
1 2
3 4
5 6
>> A = [1 2;
3 4;
5 6]
1 2
3 4
5 6
>> v = [1 2 3]
1 2 3
>> v = [1; 2; 3]
1
2
3
通过步长生成行向量:
>> v = 1:0.1:2
v =
Columns 1 through 4:
1.0000 1.1000 1.2000 1.3000
Columns 5 through 8:
1.4000 1.5000 1.6000 1.7000
Columns 9 through 11:
1.8000 1.9000 2.0000
>> v = 1:6
1 2 3 4 5 6
全是1, 或者全是0 的矩阵:
>> v = ones(2,3)
1 1 1
1 1 1
>> v = ones
v = 1
>> v = ones(3)
1 1 1
1 1 1
1 1 1
>> v = 2*ones(2,3)
2 2 2
2 2 2
>> w = zeros(1,3)
0 0 0
使用eye() 函数生成单位矩阵:
>> I = eye(6)
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
矩阵大小:
>> A = [1 2; 3 4; 5 6]
1 2
3 4
5 6
>> sz = size(A) % 矩阵大小
3 2
>> size(sz)
1 2
>> size(A,1) % 矩阵行数
ans = 3
>> size(A,2) % 矩阵列数
ans = 2
>> length(A) % length输出矩阵最大维的大小
ans = 3
获取元素:
>> A = [1 2; 3 4; 5 6; 7 8; 9 10];
>> A(3,2) % 获取一个元素
6
>> A(2, :) % 获取一行元素,冒号指所有列
3 4
>> A([1 3], :) % 返回 1、3 两行的元素
1 5
2 6
>> A(2:4, :) % 返回 2、3、4 三行元素(注意和上一个的区别)
3 4
5 6
7 8
>> A(2:3) % 这里很奇怪,是从上到下依次返回
3 5
>> A(2:5)
3 5 7 9
>> A(1:10)
1 3 5 7 9 2 4 6 8 10
矩阵转置:
21> A'
ans =
1 3 5
2 4 6
22> (A')'
ans =
1 2
3 4
5 6
(3)矩阵赋值和拼接
矩阵赋值:
>> A(:,2) = [10; 11; 12] % 给A的第二列赋值
A =
1 10
3 11
5 12
扩充矩阵:
>> A = [A , [100; 101; 102]] % 给矩阵添加一列
A =
1 10 100
3 11 101
5 12 102
>> A = [A ; [100 101 102]] % 给矩阵添加一行
A =
1 10 100
3 11 101
5 12 102
100 101 102
矩阵转换成列向量:
>> A(:) % 冒号含义很特殊,将A中所有元素都放于一个列向量中
ans =
1
3
5
100
10
11
12
101
100
101
102
102
拼接两个矩阵:
>> A = [1 2; 3 4; 5 6]
A =
1 2
3 4
5 6
>> B = [11 12; 13 14; 15 16]
B =
11 12
13 14
15 16
>> C = [A B]
% “横”着连接
1 2 11 12
3 4 13 14
5 6 15 16
>> C = [A, B]
% “横”着连接
C =
1 2 11 12
3 4 13 14
5 6 15 16
>> C = [A; B]
% “竖”着连接
C =
1 2
3 4
5 6
11 12
13 14
15 16
(4)随机数
取随机数,定义维度,随机数大小总在0到1之间:
>> w = rand(3,3)
w =
0.19782 0.42514 0.10275
0.83117 0.66312 0.37967
0.27300 0.92920 0.62790
生成一个一行三列的 高斯随机分布 :
>> w = randn(1,3)
w =
-0.025352 0.023321 1.729415
生成一个一行10000列,均值为6的高斯随机分布矩阵:
>> w = - 6 + sqrt(10) * (randn(1,10000));
使用hist()函数展示直方图:
hist(w)
生成50个条的直方图:
hist(w, 50)
5.2 移动数据
pwd 指令: | 得到Octave默认路径; |
cd 指令: | change direction 即改变路径,自己指定路径,但路径名中不要包含汉字 |
ls 指令: | 列出默认路径中包含的所有路径或者文件 |
load test.dat : | 加载文件中的数据到test变量中 |
load(‘test.dat’) : | 同上 |
test : | 显示test变量里的数据内容 |
who/whos : | 列出目前Octave工作空间中包含的所有变量 |
clear test : | 删除工作空间的变量test |
V = test(1 : 10) : | 取test中的前十个赋值给变量v |
save hello.mat V : | 将变量V保存在hello.mat文件中,注意当再次加载进来时,变量的名称仍然是V 而非文件名hello |
save hello.txt V -ascii: | 存为可以看的 txt 文件 |
从文件中加载数据到变量:
>> ls % 查看路径下的文件
Directory of D:\myc_learn\machine_learning\code\week2
[.] [..] featuresX.dat priceY.dat
2 File(s) 658 bytes
2 Dir(s) 770,788,524,032 bytes free
>> load featuresX.dat % 使用load 加载房屋特征文件
>> featuresX % 打印featuresX
featuresX =
2343 3
4343 6
2222 3
1245 2
2345 5
2234 2
2123 6
... ...
>> size(featuresX) % 矩阵大小
ans =
47 2
>> load('priceY.dat') % 加载文件
>> size(priceY)
ans =
47 1
使用who 和whos 查看都有哪些变量:
>> who
Variables in the current scope:
A ans featuresX priceY sz
>> whos
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
A 3x2 48 double
ans 1x2 16 double
featuresX 47x2 752 double
priceY 47x1 376 double
sz 1x2 16 double
Total is 151 elements using 1208 bytes
删除变量:
>> clear featuresX
>> who
Variables in the current scope:
A ans priceY sz
保存变量到文件:
>> V = priceY(1:10) % 将priceY的前10个元素赋值给V
V =
3048
4702
6069
5001
6321
3274
2183
4205
8270
7704
>> save hello.mat V % 将V保存到文件hello.dat中
>> clear V % 清除变量V
>> whos % 查看都有哪些变量
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
A 3x2 48 double
ans 1x2 16 double
priceY 47x1 376 double
sz 1x2 16 double
28 Total is 57 elements using 456 bytes
保存的 hello.mat 是二进制格式。 如果保存成 dat 格式,文件中数据如下:
从文件中加载回变量V:
>> load hello.mat
>> whos
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
A 3x2 48 double
V 10x1 80 double
ans 1x2 16 double
priceY 47x1 376 double
sz 1x2 16 double
Total is 67 elements using 536 bytes
>> V
V =
3048
4702
6069
5001
6321
3274
2183
4205
8270
7704
保存成可以看的 txt 文件:
save hello.txt V -ascii
因为用到房屋价格数据,干脆用Octave生成了一些随机数,粘贴进了文件 priceY.dat 里:
A = 10000 * rand(1,47) % 生成47个0-1的随机数,并且乘以10000
disp(sprintf('%0.0f\n',A)) % 打印成整数形式
5.3 计算数据
(1)矩阵相乘
矩阵相乘 矩阵点乘:
> A = [1 2; 3 4; 5 6]
> C = [1 1 ; 2 2]
> A * C % 矩阵相乘
5 5
1 11
17 17
B =
11 12
13 14
15 16
> A .* B % 矩阵点乘 各元素逐一相乘
11 24
39 56
75 96
A .^ 2 % 每个元素取平方
1 ./ A % 取倒数
(2)向量计算
最大值:
> a = [1 15 2 0.5]
> val = max(a)
val = 15
> [val, ind] = max(a) % ind 返回最大值位置
val = 15
ind = 2
向量逻辑判断:
a < 3 % 对每个元素进行逻辑判断
1 0 1 1
find(a < 3) % 在上面进行逻辑判断的基础上,返回结果为真的索引
1 3 4
向量常用函数:
sum(a) % 所有元素求和
prod(a) % 所有元素相乘
floor(a) % round down 向下取整
ceil(a) % round up 向上取整
round(a) % 四舍五入
std(a) % 求标准差
mean(a) % 求平均值
abs([-1;2;-3]) % 取绝对值
log(v) % 取log
exp(v) % 取e为底的指数, e=2.71828
向量运算:
> v
1
2
3
> -v
-1
-2
-3
> v + ones(length(v), 1)
2
3
4
> ones(3,1)
1
1
1
> v + ones(3,1)
2
3
4
> v + 1
2
3
4
(3)矩阵最大值
随机矩阵中的最大值:
>> rand(3)
0.64927 0.22644 0.61599
0.87125 0.68797 0.60553
0.69778 0.25321 0.12596
>> max(rand(3), rand(3)) % 随机矩阵中的最大值
0.51841 0.89632 0.75562
0.21897 0.68484 0.75206
0.97807 0.73515 0.75578
求矩阵的行最大值、列最大值:
>> A
8 1 6
3 5 7
4 9 2
>> max(A) % 返回每一列的最大值
8 9 7
>> max(A,[],1) % 返回每一列的最大值
8 9 7
>> max(A,[],2) % 返回每一行的最大值
8
7
9
两种求矩阵中所有元素最大值的方法:
>> max(max(A))
ans = 9
>> max(A(:))
ans = 9
(4)矩阵相乘
A = magic(3) | % 生成一个magic squares。其行、列、对角线 元素和等于同一个数 |
[r,c] = find(A>=7) | %返回符合条件元素的行坐标和列坐标 |
sum(A,1) | % 矩阵每一列相加 |
sum(A,2) | % 矩阵每一行相加 |
A .* eye(9) | % 矩阵主对角线的值 |
sum(sum(A .* eye(9))) | % 主对角线求和 |
flipud(eye(9)) | % 次对角线的值 |
sum(sum(A .* flipud(eye(9)))) | % 次对角线求和 |
> A = magic(3)
8 1 6
3 5 7
4 9 2
> [r,c] = find(A>=7) % 返回符合条件元素的行坐标和列坐标
r =
1
3
2
c =
1
2
3 % 即(1,1)(3,2)(2,3)三个元素>=7
矩阵列相加,行相加:
>> A = magic(9)
47 58 69 80 1 12 23 34 45
57 68 79 9 11 22 33 44 46
67 78 8 10 21 32 43 54 56
77 7 18 20 31 42 53 55 66
6 17 19 30 41 52 63 65 76
16 27 29 40 51 62 64 75 5
26 28 39 50 61 72 74 4 15
36 38 49 60 71 73 3 14 25
37 48 59 70 81 2 13 24 35
>> sum(A,1) % 矩阵每一列相加
369 369 369 369 369 369 369 369 369
>> sum(A,2) % 矩阵每一行相加
369
369
369
369
369
369
369
369
369
矩阵主对角线的值:
>> A .* eye(9) % 矩阵主对角线的值
47 0 0 0 0 0 0 0 0
0 68 0 0 0 0 0 0 0
0 0 8 0 0 0 0 0 0
0 0 0 20 0 0 0 0 0
0 0 0 0 41 0 0 0 0
0 0 0 0 0 62 0 0 0
0 0 0 0 0 0 74 0 0
0 0 0 0 0 0 0 14 0
0 0 0 0 0 0 0 0 35
>> sum(sum(A .* eye(9))) % 主对角线求和
ans = 369
矩阵次对角线的值:
>> flipud(eye(9)) % 次对角线的值
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 1 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
>> sum(sum(A .* flipud(eye(9)))) % 次对角线求和
ans = 369
5.4 绘制数据图
(1)绘制曲线
1、画一个sin曲线
>> t = [0:0.01:0.98];
>> y1 = sin(2 * pi * 4 * t);
>> plot(t,y1);
2、画一个cos曲线
>> y2 = cos(2 * pi * 4 * t);
>> plot(t,y2);
3、将两个曲线合并在一起
>> plot(t,y1);
>> hold on
>> plot(t,y2,'r');
4、给图像添加信息
>> xlabel('time') % X轴标签
>> ylabel('value') % Y轴标签
>> legend('sin','cos') % 添加曲线名称
>> title('my plot') % 添加标题
5、保存到文件
>> print -dpng 'myPlot.png'
>> ls
Directory of D:\myc_learn\machine_learning\code\week2
[.] 5.m hello.dat myPlot.png
[..] featuresX.dat hello.txt priceY.dat
>> close
6、绘制多张图
绘制多张图,需要指定将哪个曲线放在哪个图中。否则会一直绘制在当前窗口,覆盖之前的图形
>> figure(1); plot(t,y1);
% 在figure1中绘制
>> figure(2); plot(t,y2);
% 在figure2中绘制
7、将两个图显示在一张图片中
>> subplot(1,2,1); % 将图片划分为两个格子,访问第一个格子
>> plot(t,y1) % 画第一个图像
>> subplot(1,2,2); % 访问第二个格子
>> plot(t,y2) % 画第二个图像
8、改变坐标轴范围
>> axis([0.5 1 -1 1])
点击一下第一张图片,再运行一下上面那行代码,图变为:
9、清空和关闭图片
>> clf % 清空
>> close % 关闭
(2)绘制可视化矩阵
1、生成矩阵图
根据矩阵的值生成图像,不同的颜色对应矩阵中不同的值
>> A = magic(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)
2、显示颜色条
>> colorbar
或者直接使用下面的一行代码:
>> imagesc(magic(5)), colorbar;
3、生成灰度图
>> imagesc(A), colorbar, colormap gray;
生成一个15行15列灰度图
>> imagesc(magic(15)),colorbar,colormap gray;
以 imagesc(magic(15)),colorbar,colormap gray; 为例。
这种几个逗号隔开的命令一起运行的方式,叫做逗号连接函数调用 comma chaining of function calls 或 comma chaining commands 。
比如赋值操作可以写成:a=1, b=2, c=3;
(3)散点图
plot(x,y,'rx', 'MarkerSize', 10);
xlabel('Population of City in 10,000s');
ylabel('Profit in $10,000s');
title('POPULATION AND PROFIT');
图像绘制在Octave官方文档的 15.2.1 Two-Dimensional Plots ,图形属性设置在15.3.3.4 Line Properties。
如果想设置某个属性,直接写属性名,后面跟一个值。plot (x, y, property, value, …)
例如 plot (x, y, ‘linewidth’, 2, …);
5.5 控制语句: for, while, if 语句
1、for 循环 通过 index 访问列向量
>> v = zeros(10,1)
v =
0
0
0
0
0
0
0
0
0
0
>> for i = 1 : 10,
v(i) = 2 ^ i;
end;
>> v
v =
2
4
8
16
32
64
128
256
512
1024
2、for 循环 直接访问列向量元素
>> indices = 1 : 10;
>> indices
indices =
1 2 3 4 5 6 7 8 9 10
>> for i = indices,
disp(i);
end;
1
2
3
4
5
6
7
8
9
10
3、while 循环访问列向量
>> i = 1;
>> while i <= 5,
v(i) = 100;
i = i + 1;
end;
>> v
v =
100
100
100
100
100
64
128
256
512
1024
4、while(true) 和 break
>> i = 1 ;
>> while(true),
v(i) = 999;
i = i + 1;
if i == 6,
break;
end;
end;
>> v
v =
999
999
999
999
999
64
128
256
512
1024
5、if else 语句
>> v(1) = 2;
>> if v(1) == 1,
disp('The value is one');
elseif v(1) == 2,
disp('The value is two');
else,
disp('The value is not one or two');
end;
The value is two
6、自定义函数 function
定义函数 squareThisNumber(x),内容如下:
function y = squareThisNumber(x)
y = x^2;
endfunction
将函数保存为squarethisnumber.m,注意此时是小写。
这时候调用函数 squareThisNumber(2) 提示找不到函数
>> squareThisNumber(2);
error: 'squareThisNumber' undefined near line 1 column 1
>>
>> ls
[.] featuresX.dat priceY.dat
[..] hello.dat squarethisnumber.m
将文件命名为函数一致squareThisNumber.m(大小写也一致),这时候调用函数成功
>> ls
[.] featuresX.dat priceY.dat
[..] hello.dat squareThisNumber.m
>> squareThisNumber(2);
>> a = squareThisNumber(2);
>> a
a = 4
这说明:Octave 是大小写敏感的,文件名必须和函数名大小写一致。
7、多个返回值的函数
Octave 函数有和其他语言不一样的地方是可以返回多个值。定义方法squareAndCubeThisNumber(x)如下:
function [y1, y2] = squareAndCubeThisNumber(x),
y1 = x ^ 2;
y2 = x ^ 3;
endfunction
调用:
>> a = squareAndCubeThisNumber(2) % 接受了第一个返回值
a = 4
>> [a, b] = squareAndCubeThisNumber(2) % 接受两个返回值
a = 4
b = 8
8、更复杂的函数
保存下面的函数到costFunctionJ.m中
function J = costFunctionJ(X, y, theta),
% X is the "design matrix" containing our training examples
% y is the class labels
m = size(X, 1); % number of training examples, size of rows
predictions = X * theta; % predictions of hapothesis on all m examples
sqrErrors = (predictions - y) .^ 2; % squared errors .^ 指的是对数据中每个元素平方
J = 1 / (2 * m) * sum(sqrErrors);
endfunction
针对上边的数据集初始化矩阵。调用函数,计算代价函数的值。
>> X = [1 1; 1 2 ; 1 3];
>> y = [1;2;3];
>> theta = [0;1]; % Θ为0,1 h(x)=x 此时完全拟合数据,代价函数的值为0
>> j = costFunctionJ(X,y,theta)
j = 0
5.6 向量化
下面是向量化的小例子,如果将所有u(j) 、所有v(j)、所有w(j)都看成列向量,则公式变为为向量加法 u = 2v + 5w
有时我们使用几十或几百个特征量来计算线性回归,当使用向量化地实现线性回归,通常运行速度就会比 for 循环快的多