小之的公众号 : WeaponZhi
前言
上一篇我们介绍了 Octave 的一些基本情况,大家对 Octave 应该已经有了一个基本的了解,我相信看这篇文章的朋友已经在自己的电脑中安装好 Ocatve 了。矩阵的操作是 Octave 的一大特色。这一节,我将讲述 Octave 对于矩阵的一些操作,希望大家在看文章的过程中可以跟着一起敲一下代码,加深一下印象。
矩阵的生成
Octave 中,我们用一个中括号来表示一个矩阵,用分号来分隔每一行,即使在输入的时候不在同一行就像下面这样:
>> A = [1 2; 3 4; 5 6]A = 1 2 3 4 5 6>> A = [1 2;> 3 4;> 5 6]A = 1 2 3 4 5 6>> A = [1,2; 3,4; 5,6]A = 1 2 3 4 5 6复制代码
注意到,你可以通过逗号来区分每行中的每一个元素,但我们一般不这样用,这样看起来不太清晰。那么如果要表示向量该怎么做呢?我们知道,行向量和列向量分别是一行三列和三行一列的矩阵,那举一反三的你一定知道该怎么定义了吧?
>> A = [1 2 3]A = 1 2 3>> A = [1; 2; 3]A = 1 2 3复制代码
可以通过冒号来实现具有递进规则的行向量,两个冒号之间的数代表递进的 step 大小,很容易理解,和 Python 的操作有点像。
>> A = 1:0.1:1.5A = 1.0000 1.1000 1.2000 1.3000 1.4000 1.5000>> A = 1:5A = 1 2 3 4 5复制代码
通过一些函数可以快速生成一些特殊矩阵
>> ones(2,3)ans = 1 1 1 1 1 1>> 2*ones(2,3)ans = 2 2 2 2 2 2>> zeros(2,3)ans = 0 0 0 0 0 0>> eye(3)ans = Diagonal Matrix 1 0 0 0 1 0 0 0 1>> rand(2,3)ans = 0.480397 0.505024 0.056767 0.336853 0.774152 0.535887>> magic(3)ans = 8 1 6 3 5 7 4 9 2复制代码
ones() 生成全是 1 的矩阵,你可以使用数字和 ones() 生成的矩阵相乘,它和 zeros() 还有 rand() 一样,第一个参数代表行数,第二个参数代表列数。zeros() 生成元素全是 0 的矩阵,而 rand() 可以生成元素是 0-1 之间随机数的矩阵。eye()可以生成单位矩阵,熟悉线性代数的朋友可能会对单位矩阵比较熟悉,它很有用,但线性代数的知识不是本文的重点。形式上可以理解为正斜对角线都是 1 的矩阵。
magic(n) 生成一个 n 阶矩阵,这个矩阵的特点就是不论横线,竖线还是对角线,加起来的值都是一样的,数字还不能重复,必须是从 1 到 n 的平方,很有趣吧。
矩阵的操作
讲述矩阵的操作之前,让我们先来定义一个 3x2 的矩阵 A,方便我们理解代码
>> A = [1 2; 3 4; 5 6]A = 1 2 3 4 5 6复制代码
我们可以通过 size 和 length 函数来获取矩阵维度的相关信息
>> size(A)ans = 3 2>> size(A,1)ans = 3>> size(A,2)ans = 2>> length(A)ans = 3复制代码
size(A) 返回一个行向量,这个行向量代表了 A 的维度,这里输出的 3 2 代表 A 是一个 3 行 2 列的矩阵。size()还可以添加第二个参数,size(A,1) 输出 A 的第一个维度的数量,也就是行数,2 代表的是列数。length(A) 返回的是 A 矩阵中最大维度的大小,所以这里返回的是 A 的行数 3,一般我们都是对向量使用 length() 来直接返回向量的长度。
我们来看看对于矩阵的各种读取操作吧。
>> A(3,2)ans = 6>> A(:)ans = 1 2 3 4 5 6>> A(1:6)ans = 1 3 5 2 4 6复制代码
A(3,2) 代表取 A 矩阵第三行第二列的元素,这个比较好理解。A(:) 会将矩阵转化为一个列向量,A(1:6) 将按列顺序输出 A 矩阵第 1 到 第 6 个元素。这些都还是比较简单的,后两个往往在求和的时候用的比较多,我们后面会说到。
我们来看一波天秀操作
>> A(:,2)ans = 2 4 6>> A(2,:)ans = 3 4>> A([2,3],:)ans = 3 4 5 6>> A(:,2) = [1; 3; 5]A = 1 1 3 3 5 5>> A = [A,[1; 2; 3]]A = 1 1 1 3 3 2 5 5 3 >> B = 5*ones(3)B = 5 5 5 5 5 5 5 5 5>> [A B] % [A,B] % 号是注释ans = 1 1 1 5 5 5 3 3 2 5 5 5 5 5 3 5 5 5>> [A; B]ans = 1 1 1 3 3 2 5 5 3 5 5 5 5 5 5复制代码
来,我们一点点看。A(:,2) 输出 A 的第二列,A(2,:) 输出 A 的第二行,A([2,3],:) 输出第二行和第三行,你可以把冒号换成数字这样就可以输出这几行的第几个元素了。A(:,2) = [1; 3; 5] 将 A 的第二列替换成 [1; 3; 5] 这个列向量。[A B] 和 [A, B] 的含义一样,将 B 并到 A 的右边。[A; B] 则是把 B 并到 A 的下面。
矩阵的运算
这节将讲一些矩阵运算的操作,涉及到一些线代的知识,如果有疑惑,可以自己去重温下,你大概只要知道矩阵相乘和逆矩阵是怎么一回事就行了。先来看一段代码
>> A = [1 2; 3 4; 5 6];>> B = [1 1 1;2 2 2;];>> C = [11 12; 13 14; 15 16];>> A * Bans = 5 5 5 11 11 11 17 17 17>> A .* Cans = 11 24 39 56 75 96复制代码
我们先定义了三个矩阵,还记得吗,末尾加分号将不会打印出来。A * B 代表矩阵 A 和 B 的乘积,这是数学上的乘积方式,所以一个三行两列的矩阵乘以两行三列的矩阵,将得到一个三行三列的矩阵,这里就不具体说乘积运算的规则了。A .* C 会将 A 和 C 的同位置元素相乘,这就代表了 A 和 C 的维度必须要一样。
我们来看下矩阵和数字的操作
>> A + 1ans = 2 3 4 5 5 6>> A * 2ans = 2 4 6 8 10 12>> A .^ 2ans = 1 4 9 16 25 36>> A / 2ans = 0.50000 1.00000 1.50000 2.00000 2.50000 3.00000>> 1 ./ Aans = 1.00000 0.50000 0.33333 0.25000 0.20000 0.16667复制代码
A+1 将每个元素作加法,A * 2 把 A 中每个元素都乘以 2,当然 2 * A 也可以,结果一致,我们在上面曾经使用 5 * ones(3) 来快速生成三阶全是 5 的矩阵。A .^ 2 代表对 A 每个元素进行次方操作。A / 和 ./ 含义是一样的,但 1 / A 将会报错
>> 1 / Aerror:operator /:nonconformat arguments>> 1 / [2]ans = 0.50000>> 1 / 2ans = 0.50000复制代码
除数必须得是 1x1 的矩阵或者是个数,总而言之它这是真正的算数除法运算了。
当然还有一些对元素做操作的运算,比如 log(A) 是每个元素求对数,exp(A) 是对每个元素求 e 的指数,abs(A) 是求绝对值,当然还有很多,就不一一列举了。大家可以通过 help 指令直接进行文档查阅。
下面看看转置矩阵和逆矩阵如何表示
>> A'ans = 1 3 5 2 4 6>> (A')'ans = 1 2 3 4 5 6>> flipud(A)ans = 5 6 3 4 1 2>> B = pinv(A)B = -1.33333 -0.33333 0.66667 1.08333 0.33333 -0.41667>> A * B % B * Aans = 1.00000 0.00000 -0.00000 1.00000复制代码
用单引号 ' 来表示矩阵的转置矩阵。flipud(A) 将矩阵翻转,这个函数一般用在翻转范围矩阵 flipud(eye(n)) ,这样就可以获得一个反对角线单位矩阵了。
pinv(A) 表示 A 的逆矩阵,逆矩阵和原矩阵相乘是单位矩阵,值得注意的是,不是每一个矩阵都有逆矩阵,但 pinv() 始终都能得到结果,实际上 pinv() 获取的是一个伪逆矩阵,但这不重要,你可以把 pinv() 当作对矩阵的求逆,这里就不具体深究了。
到目前为止,矩阵的运算还是比较简单的,相比起来,下面的运算就有点蒂花之秀了。
>> max(A)ans = 5 6>> max(A,[],1)ans = 5 6 >> max(A,[],2)ans = 2 4 6>> [val, ind] = max(A)val = 5 6ind = 3 3>> max(A,[3 3; 3 3; 3 3])ans = 3 3 3 4 5 6>> A > 3ans = 0 0 0 1 1 1>> find([1 2 3] > 1)ans = 2 3>> [r,c] = find(A > 3)r = 3 2 3c = 1 2 2复制代码
max(A) 将求每列的最大值,并以行向量形式输出,默认形式等同于 max(A,[],1),如果求每列最大值,则把第三个参数改为2。用 [val, ind] 接收的话,val 的值为最大值,ind 为这个值在该列的索引位置。max(A,B) 将取每个位置中 A 与 B 较大的元素。min 和 max 操作是一样的。
A > 3 输出一个同维度的矩阵,符合条件的为 1 ,不符合条件的为 0。find() 函数中如果是一个向量,则返回符合条件的索引位置,如果是一个矩阵,则用 [r,c] 返回元素的索引,r 代表行号,c 代表列号,比如例子中第一个匹配值 A(3,1) 是 5 ,的确大于 3。
最后看下求和
>> sum(A,1)ans = 9 12>> sum(A,2)ans = 3 7 11>> sum(sum(A))ans = 21复制代码
sum 和 max 一样,默认情况下是列运算,行向量输出,但参数设置为 2 的时候,则是行求和,列向量输出。所以就像例子中一样,如果我们要求一个矩阵所有元素的和,只需要做两次 sum(sum(A)) 即可。
总结
Octave 矩阵方面的介绍就这么多了,写的很多,权当一个笔记吧,实际上还有很多操作,大家可以使用 help 指令或者观看官方文档来进行学习。
欢迎关注我的公众号