矩阵和数组
本章的目标是:
正如我们已经看到的,MATLAB这个名字代表矩阵实验室,因为MATLAB系统是专门为处理以矩阵(二维数组)形式排列的数据而设计的。在本章中,“矩阵”一词有两个不同的含义:
- 一种数学对象,为其定义了特定的数学运算,如“矩阵”乘法。
本章(在第6.1、6.2和6.3节中)将从第一种意义上的矩阵开始,总结和扩展我们在第二章所学到的知识。然后我们继续简单地看一下矩阵的数学运算。在后面的章节中,我们将看到这些操作如何应用于许多不同的领域,如线性方程系统、种群动力学和马尔可夫过程。
6.1矩阵
6.1.1具体示例
6.1.2创建矩阵
6.1.3下标
6.1.4转置
6.1.5冒号操作符
6.1矩阵
6.1.1具体示例
>> c = [3 12 10; 17 18 35; 7 10 24];
x = [4 0 0; 6 6 0; 0 3 5];
>> total = c .* x
total =
12 0 0
102 108 0
0 30 120
>> sum(total)
ans =
114 138 120
在这段代码中,首先定义了两个矩阵c
和x
,其中c是一个3x3
的矩阵,x是一个3x3
的矩阵。接下来,代码使用逐元素乘法运算符.*
对这两个矩阵进行逐元素相乘,得到一个新的矩阵total
,其中每个元素都是对应位置上c和x的元素相乘的结果。
最后,代码使用sum
函数对total矩阵进行求和,得到一个包含三个元素的行向量,其中每个元素表示total矩阵在对应列上的元素之和。具体来说,sum(total)将对total矩阵的每一列进行求和,得到一个1x3
的行向量,其中第一个元素是total矩阵第一列的元素之和,第二个元素是total矩阵第二列的元素之和,第三个元素是total矩阵第三列的元素之和。在这个例子中,sum(total)的结果是[114 138 120],表示total矩阵在第一列上的元素之和是114,在第二列上的元素之和是138,在第三列上的元素之和是120。
>> sum(sum( total ))
ans =
372
接下来,代码再次使用sum函数对这个行向量进行求和,得到一个标量值,表示total矩阵所有元素之和。具体来说,sum(sum(total))将对total矩阵的所有元素进行求和,得到一个标量值,其中第一次sum函数对total矩阵的每一列进行求和,得到一个1x3的行向量,第二次sum函数对这个行向量进行求和,得到一个标量值。在这个例子中,sum(sum(total))的结果是372,表示total矩阵所有元素之和是372。
6.1.2创建矩阵
在输入矩阵时使用分号表示行结束。较大的矩阵可以由较小的矩阵构造而成,
a = [1 2; 3 4];
x = [5 6];
a = [a; x]
a =
1 2
3 4
5 6
具体来说,如果要输入一个3x3的矩阵,可以使用以下语句:
A = [1 2 3; 4 5 6; 7 8 9];
其中,分号表示行结束,每个分号后面的数字表示该行对应位置上的元素。这个语句将创建一个名为A的3x3矩阵,其中第一行是[1 2 3],第二行是[4 5 6],第三行是[7 8 9]。
较大的矩阵可以由较小的矩阵构造而成。例如,可以使用以下语句构造一个4x4的矩阵B,其中前三行和前三列与矩阵A相同,最后一行和最后一列都是0:
B = [A zeros(3,1); zeros(1,3) 0];
其中,zeros
函数用于创建一个指定大小的全0矩阵。这个语句将创建一个名为B的4x4
矩阵,其中前三行和前三列与矩阵A相同,最后一行和最后一列都是0。具体来说,B的第一行到第三行和第一列到第三列与矩阵A相同,最后一行和最后一列都是0,因此B的第四行是[0 0 0 0],第四列是[0; 0; 0; 0]。
6.1.3下标
a =
1 2
3 4
5 6
矩阵的单个元素用两个下标引用,第一个下标用于行,第二个下标用于列,例如,a(3,2)的返回值为6。
另外一种不太常见的情况是,可以使用单个下标。在这种情况下,你可以把矩阵想象成一列一列地“展开”。所以上面例子中的a(5)返回4。
如果您引用的下标超出了范围,例如上面a的a(3,3),则会得到错误消息。但是,如果给下标超出范围的元素赋值,则矩阵将被放大以容纳新元素,例如:a(3,3) = 7
将在A中添加第三列,除A(3,3)为7以外, 该列其他的所有数都为0.
6.1.4转置
>> a = [1:3; 4:6]
b = a'
a =
1 2 3
4 5 6
b =
1 4
2 5
3 6
转置运算符'(撇号)将行转换为列,反之亦然
6.1.5冒号操作符
冒号运算符非常强大,提供了处理矩阵的非常有效的方法,例如,如果a是矩阵
>> a =[1 2 3;4 5 6;7 8 9]
a =
1 2 3
4 5 6
7 8 9
返回第二行和第三行,第一列和第二列 :
>> a(2:3,1:2)
ans =
4 5
7 8
在MATLAB中,a(2:3,1:2)
表示对矩阵a的第2到第3行和第1到第2列进行切片操作,得到一个2x2
的子矩阵。具体来说,这个语句将返回一个2x2的矩阵,其中第一行是a矩阵的第2行第1列和第2列的元素,第二行是a矩阵的第3行第1列和第2列的元素。注意,MATLAB中的索引从1开始,因此a(2:3,1:2)实际上是指矩阵a的第2行到第3行和第1列到第2列。
>> a(3,:)
ans =
7 8 9
在MATLAB中,a(3,:)
表示对矩阵a
的第3行进行切片操作,得到一个包含该行所有元素的行向量。具体来说,这个语句将返回一个1xn
的行向量,其中n
是矩阵a
的列数,包含a矩阵的第3行所有元素。注意,冒号表示对整个维度进行切片操作,因此a(3,:)实际上是指矩阵a的第3行的所有元素。
>> a(1:2,2:3) = ones(2)
%将由第一、第二行和第二、第三列组成的2 × 2子矩阵替换为1的方阵
a =
1 1 1
4 1 1
7 8 9
a(1:2,2:3) = ones(2)
表示将矩阵a的第1到第2行、第2到第3列的元素赋值为1。具体来说,这个语句将返回一个修改后的矩阵a,其中第一行第二列和第二行第二、第三列的元素都被赋值为1,而其他元素保持不变。因此,修改后的矩阵a为:
a =
1 1 1
4 1 1
7 8 9
从本质上讲,在上面的例子中发生的事情是冒号操作符被用来创建向量下标。但是,冒号本身代替下标表示相应行或列的所有元素。所以a(3,:)
表示第三行中的所有元素
这个功能可以用来构建表格,例如,假设我们想要一个包含0°到180°之间每隔30°的角度对应的正弦和余弦值的表格trig。下面的语句可以实现这个目标:
>> x = [0:30:180]';
trig(:,1) = x;
trig(:,2) = sin(pi/180*x);
trig(:,3) = cos(pi/180*x);
>> trig
trig =
0 0 1.0000
30.0000 0.5000 0.8660
60.0000 0.8660 0.5000
90.0000 1.0000 0.0000
120.0000 0.8660 -0.5000
150.0000 0.5000 -0.8660
180.0000 0.0000 -1.0000
接着上面的
a =
1 1 1
4 1 1
7 8 9
可以使用矢量下标来获得更复杂的效果
b = ones(3,4);
a(:,[1 3]) = b(:,[4 2])
这个操作用b的第四列和第二列替换a的第一列和第三列(a和b必须具有相同的行数)
首先创建一个3行4列的矩阵b,其中所有元素都被赋值为1。具体来说,这个语句将返回一个修改后的矩阵a,其中第一列和第三列的元素被替换为矩阵b的第4列和第2列的元素,而其他元素保持不变。注意,方括号内的数字表示要选择的列的索引,因此[1 3]表示选择矩阵a的第1列和第3列,[4 2]表示选择矩阵b的第4列和第2列。
冒号运算符在高斯消元(一种数值数学技术)中执行的行操作非常理想。在高斯消元中,我们需要对矩阵的行进行一系列操作,例如交换行、将一行乘以一个常数、将一行加到另一行上等等。冒号运算符可以用来选择矩阵的特定行,例如a(1,:)
表示选择矩阵a的第一行。通过使用冒号运算符,我们可以轻松地执行这些行操作,例如a([2 1],:)
表示交换矩阵a的第一行和第二行。
>> a =[1 -1 2;2 1 -1;3 0 1]
a =
1 -1 2
2 1 -1
3 0 1
>>a(2,:) = a(2,:) - a(2,1)*a(1,:)
%从第二行减去第一行乘以第二行中的第一个元素
a =
1 -1 2
0 3 -5
3 0 1
在MATLAB中,a(2,:) = a(2,:) - a(2,1)*a(1,:)
表示将矩阵a的第二行减去矩阵a的第一行乘以a(2,1)
后的结果,然后将这个结果赋值给矩阵a的第二行。具体来说,这个语句将返回一个修改后的矩阵a,其中第二行的元素被更新为原来的第二行减去原来的第一行乘以a(2,1)后的结果。这个操作通常用于高斯消元中的行变换,可以将矩阵转化为上三角矩阵。
关键字end指数组的最后一行或最后一列,例如,如果r是行向量,则语句sum(r(3:end))
表示计算向量r的第三个元素到最后一个元素的总和。
假设向量r为[1 2 3 4 5],那么r(3:end)将选择向量r的第三个元素到最后一个元素,即[3 4 5]。然后,sum函数将计算这个子集的总和,即3+4+5=12。因此,sum(r(3:end))
将返回12。
冒号操作符也可以用作单个下标,在这种情况下,它在赋值操作的右侧或左侧的行为是不同的。在赋值操作的右侧,a(:)给出由列串成的一个长列向量的所有元素,例如,
a =
1 -1 2
0 3 -5
3 0 1
>> b = a(:)
b =
1
0
3
-1
3
0
2
-5
1
然而,在赋值操作的左边,a(:)会重塑一个矩阵。其中矩阵a必须已经存在。那么a(:)表示与a具有相同维数(形状)的矩阵,但是从右边取了新的内容。
换句话说,右边的矩阵被重塑成左边的a的形状。
>> b =[1 2 3;4 5 6]
b =
1 2 3
4 5 6
>> a =[0 0;0 0;0 0]
a =
0 0
0 0
0 0
>> a(:) = b
a =
1 5
4 3
2 6
b的内容被串成一长列,然后输送到a的每一列
a =
%已知
1 5
4 3
2 6
%再对a进行操作
>> a(:) = 1:6
a =
1 4
2 5
3 6
a(:) = 1:6表示将向量[1 2 3 4 5 6]的元素赋值给矩阵a的所有元素(按照列,一列一列往里面输入)。具体来说,这个语句将返回一个修改后的矩阵a,其中所有元素都被赋值为向量[1 2 3 4 5 6]的元素。
无论冒号操作符出现在赋值操作的右侧还是左侧,赋值操作两侧的矩阵或子矩阵都具有相同的形状(下面的特殊情况除外)。
作为一种特殊情况,可以使用单个冒号下标将矩阵中的所有元素替换为标量,例如:
a =
1 4
2 5
3 6
>> a(:) = -1
a =
-1 -1
-1 -1
-1 -1