在第一次介绍 Matlab 的时候就说过 Matlab 这个名字的由来,显然,它的主打优势就是矩阵操作。很多同学的线性代数基础不太扎实,一听矩阵就头皮发麻。我们在这里只关心矩阵这样一种特殊的数据存储形态,它本身的数学意义,不做探讨。
为了简化起见,我们在这里把矩阵看作是一个 N 行 M 列的一种有序结构。你可以想象一下阅兵式上的那些兵哥哥们排成的方队。兵哥哥的整个方队,你可以看作是一个矩阵,方队中的每一个兵哥哥,是矩阵中的元素。
Matlab 为了将矩阵与其他数据类型区分开来,用[]
把矩阵中的元素括起来。所以,也可以这么说,用[]
括起来的东西,都是矩阵。
这里的 N 与 M 可以取任意值,有同学可能也觉得比较困惑,N 或 M 取 0 时,有什么意义,又有什么用?这是一个空矩阵,它就是一个矩阵,只是里面没有元素。实验一下:
>> a = ones(0)
a =
[]
大家help
一下ones
就明白上面这个命令的意思了。
在程序设计中经常先创建一个空矩阵,再将运算过程中得到的结果往这个空矩阵里面塞。
矩阵同一行的元素之间用空格或逗号
,
分隔,行与行之间用分号;
分隔。看一个例子:
>> a = [1, 2, 3, 4, 5; 6, 7, 8, 9, 10]
a =
1 2 3 4 5
6 7 8 9 10
前面我们也说过矩阵可以存储几乎所有的数据类型,比如元素是矩阵的矩阵,不同数据类型的元素混在一起的矩阵等等。另外,一个字符串其实也是一个矩阵,有兴趣的同学可以自己查阅相关的资料。
矩阵操作
1 创建矩阵
最直接的方法当然是逐个写出矩阵中的元素。有些特殊的矩阵可以使用Matlab提供的函数直接创建。例如:
>> ones (3, 4)
ans =
1 1 1 1
1 1 1 1
1 1 1 1
>> zeros (2)
ans =
0 0
0 0
>> a = [1, 2, 3]
a =
1 2 3
>> b = [1; 2; 3]
b =
1
2
3
>> rand(2)
ans =
0.8147 0.1270
0.9058 0.9134
ones
, zeros
, rand
这几个函数的功能,大家自己help
一下就能了解了。
2 引用矩阵元素
直接看例子:
>> a = [1, 3, 5, 7; 9, 11, 13, 15; 17, 19, 21, 23]
a =
1 3 5 7
9 11 13 15
17 19 21 23
>> a (2, 4)
ans =
15
这就好比你不知道这家伙的名字,但是你知道他排在方队第二行第四列,所以你喊“第二行,第四列的那个家伙,你妈妈喊你回家吃饭了”,这就是引用矩阵元素最直接的方法。上例就是取第二行第四列的元素。
注意,这里的第二行第四列,数字“2”与“4”,也称索引(index),要用()
括起来,不要与矩阵的[]
弄混。行索引与列索引用,
分隔。
取第三行第二到第四列的所有元素
>> a(3, 2: 4)
ans =
11 13 15
又出现了一个新符号:
,它的完整用法是start: step: end
,意思就是从起点每隔一个步长到终点。
不指定 start 与 end 的值的话,就默认取指定范围内的头与尾。在这个三行四列的矩阵中,对于行来说,start默认值为1,end的默认值为3。
不指定step
值的话就取默认值1。
本例中,3
的意思是第三行,2: 4
的意思是从2到4,步长为1,也即第2、3、4三列。
:
的使用比较多,经常用于循环,也常常用于创建矩阵。例如,我们创建一个矩阵,矩阵中元素是1到16中的所有奇数。可以这样写:
>> b = [1:2:16]
b =
1 3 5 7 9 11 13 15
取第2行所有列的数据
>> a(2, :)
ans =
9 11 13 15
取第3列所有行的数据
>> a(:,3)
ans =
5
13
21
请结合例子,仔细体会:
的用法。
取最后一行,例数第二列的数据
>> a(end, end-1)
ans =
21
有时候,我们不知道也不想知道矩阵的大小,只想取它的最后行的数据,可以使用end
关键字。显然,end
是最后一列,那end-1
就是倒数第二列。
特别地,对于只有一行(行向量)或只有一列(列向量)的矩阵来说,可以直接使用a(n)
这样的形式来获得第n
个元素,大家可以自己试一下。
顺便插播一个东西:行向量与列向量可以通过'
操作符相互转化:
>> [1,2,3]'
ans =
1
2
3
>> [1;2;3]'
ans =
1 2 3
对于引用矩阵元素的操作,还有一个比较灵活的用法:结合逻辑表达式进行逻辑索引。
假设有矩阵r
如下
>> r = rand(5)
r =
0.6324 0.9649 0.8003 0.9595 0.6787
0.0975 0.1576 0.1419 0.6557 0.7577
0.2785 0.9706 0.4218 0.0357 0.7431
0.5469 0.9572 0.9157 0.8491 0.3922
0.9575 0.4854 0.7922 0.9340 0.6555
取矩阵r
中所有大于0.5的值:
>> r1 = r(r > 0.5)
r1 =
0.6324
0.5469
0.9575
0.9649
0.9706
0.9572
0.8003
0.9157
0.7922
0.9595
0.6557
0.8491
0.9340
0.6787
0.7577
0.7431
0.6555
为了搞清楚这个命令到底做了什么工作,我们先看看r > 0.5
是什么。
>> r > 0.5
ans =
5×5 logical 数组
1 1 1 1 1
0 0 0 1 1
0 1 0 0 1
1 1 1 1 0
1 0 1 1 1
这样一来,我们就很容易看出r1 = r(r > 0.5)
是分两步走的:先通过r > 0.5
获得了每个元素是否满足条件的逻辑值(逻辑数组)。r1 = r(r > 0.5)
将每个符合条件的元素提取出来并赋值给r1
。
逻辑数组有很多灵活的用法。比如,假设有一个逻辑数组logi
(通过logical函数转换得到)以及另外一个数组x
如下:
>> logi = logical ( [1,0,1;0,0,1;1,0,0])
logi =
3×3 logical 数组
1 0 1
0 0 1
1 0 0
>> x = [1,2,3;5,6,7;4,8,9]
x =
1 2 3
5 6 7
4 8 9
我们看看x(logi)
的输出是什么
>> x(logi)
ans =
1
4
3
7
它把x
矩阵中对应于logi
矩阵中元素值为true
位置的元素输出为结果。
改变矩阵元素的值
这个比较简单,想改变哪一个元素的值,就把这个值先索引出来,然后直接用赋值操作就可以了。举例如下:
>> a(2,3) = 0
a =
1 3 5 7
9 11 0 15
17 19 21 23
也可以采用逻辑索引的方式进行批量操作:
>> x = rand(4)
x =
0.1712 0.0462 0.3171 0.3816
0.7060 0.0971 0.9502 0.7655
0.0318 0.8235 0.0344 0.7952
0.2769 0.6948 0.4387 0.1869
>> x(x > 0.5) = 1
x =
0.1712 0.0462 0.3171 0.3816
1.0000 0.0971 1.0000 1.0000
0.0318 1.0000 0.0344 1.0000
0.2769 1.0000 0.4387 0.1869
删除矩阵的行或列
矩阵的“矩”是“方”的意思,所以矩阵的构成上有一个特殊的要求,行与行或者列与列的元素个数要相等。所以对于一个矩阵的删除与增加元素操作来讲,只能增加或删除完整的一行或一列。删除操作一般使用赋空矩阵来完成。
例如,删除第二行
>> a(2, :) = []
a =
1 3 5 7
17 19 21 23
增加矩阵行或列
这种操作在 Matlab 中也被称为矩阵连接。举例说明:
>> a = [1:2:7; 17:2:23]
a =
1 3 5 7
17 19 21 23
>> b = [2:2:8]
b =
2 4 6 8
>> d = [2;4]
d =
2
4
>> [a, d]
ans =
1 3 5 7 2
17 19 21 23 4
>> con = [a;b]
con =
1 3 5 7
17 19 21 23
2 4 6 8
>> con = [con(1,:); b; con(2:end, :)]
con =
1 3 5 7
2 4 6 8
17 19 21 23
2 4 6 8
肯定有很多小伙伴要晕了。
先说[a,d]
,看变量a
与变量d
之间,用的是,
,记得我们前面说过行内元素之间用,
分隔,行与行之间用;
分隔。所以这里的意思就是把矩阵a
与矩阵d
在行上“连接”。
我们分别写一下矩阵a
与矩阵d
,观察下这个“连接”。
1 3 5 7 | 2
17 19 21 23 | 4
竖线左边的是矩阵a
,竖线右边的是矩阵d
,再结合输出结果,应该明白怎么回事了吧。[a; b]
也是类似的,只不过是变成了增加行。
如果你试一下[a,b]
或者[a;d]
,你会发现输出错误。想一想,为什么会出现这样的情况?
那如果不是在行末或列末添加,而是要在中间某行之后插入新的一行怎么做?最后一个命令做的就是这件事情。
[con(1,:); b; con(2:end, :)]
在这个[]
里面,;
分隔了三个部分。
con(1,:)
是矩阵con
中的第一行,通过;
将矩阵b
增加到第一行之后,接着又将矩阵con
剩下的行增加进去便完成了整个插入行的操作。
插入列也是类似的操作,不再赘述。