概述
在上一节中,我们介绍了如何创建一个矩阵,并且介绍了MATLAB中的一些运算符。在本节中,我们将在深入学习MATLAB中的矩阵。
本次的内容有点多,划一下重点:
- size函数:创建矩阵和确定循环结构的循环次数
- reshape函数:重新排列矩阵
- sort函数:内置的sort函数比自己编写的排序更高效
- [ ]运算符:串联矩阵最重要的步骤
- repmat函数:重复矩阵的拼接
- 索引:功能强大,针对性的选取数组元素
矩阵的属性
复习一下之前介绍过的MATLAB命令:(>> whos)。
功能为显示所有变量的属性。有时候我们需要根据矩阵的属性来做一些操作就需要用到矩阵的一些相关属性。常用的属性都可以通过函数来调用:size,length,isrow,numel等。
size
size函数返回矩阵的各个维度的长度,调用方法为:sz = size(A)
% size ()
% 命令行输入
A = zeros(3,4); % 先创建一个3×4的零矩阵,观察以下几个值
S = size(A)
[m,n] = size(A)
% 补充:这样写是能够让函数返回两个不同的输出参数。
% 调用函数时,系统会告诉函数有多少个输入参数和输出参数
% 函数本身则根据输入输出参数的数量决定自己的输出参数。
mm = size(A,1)
nn = size(A,2)
将以上命令输入至命令行,将得到以下输出:
% 命令行输出
S =
3 4
% 直接调用返回一个输出参数时:
% size函数返回一个矩阵包含各个维度长度的矩阵。
m =
3
n =
4
% 直接调用返回两个输出参数时:
% size函数返回两个标量各自表示各个维度长度。
mm =
3
nn =
4
% 调用size函数时,加上想查询的具体维度,可以返回该维度上的长度
% 在这里,1指横坐标,2指纵坐标,3指竖坐标
length
length函数返回矩阵的最长维度的长度,调用方法为:L = length(A)
% length ()
% 命令行输入
A = zeros(3,4); % 先创建一个3×4的零矩阵
S = length(A)
将以上命令输入至命令行,将得到以下输出:
% 命令行输出
S =
4
% length 函数返回矩阵的最长维度的长度,相当于size(A)的最大值。
isrow
isrow如其名,作用就是询问矩阵是不是行向量。
同样作用的还有iscolumn确定矩阵是不是列向量,isempty确定矩阵是不是为空
% isrow ()
% 命令行输入
A = zeros(1,4); % 创建一个1×4的矩阵,观察以下几个值
S1 = isrow(A)
S2 = iscolumn(A)
S3 = isempty(A)
whos S1
将以上命令输入至命令行,将得到以下输出:
% 命令行输出
S1 =
1
S2 =
0
S3 =
0
Name Size Bytes Class Attributes
S1 1x1 1 logical
% isrow 函数返回一个布尔值1或0
% 用whos命令可以看到返回的类型是logical(逻辑值非一即零,非真即假)。
numel
numel函数返回数组元素的数量,
A = zeros(3,4); % 创建一个1×4的矩阵,观察以下几个值
n = numel(A)
将以上命令输入至命令行,将得到以下输出:
% 命令行输出
n =
12
% 返回矩阵所有元素的个数
矩阵的排列
矩阵的另一类操作是排列,对矩阵内的元素的相对位置重新处理,(很抽象的描述,还是看看函数的功能比较容易)。常见的的函数有reshape,sort,flip,circshift等
reshape
reshape 函数顾名思义就是对矩阵重排,
A = magic(4) % 创建一个4×4的矩阵,观察以下几个值
AA = reshape(A,2,8)
将以上命令输入至命令行,将得到以下输出:
% 命令行输出
% reshape 之前
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
% reshape 之后
AA =
16 9 2 7 3 6 13 12
5 4 11 14 10 15 8 1
% 这里又有另一个关注的点:重排的顺序,可以看到A的每一列分成了两列
% 原理:所有的矩阵在计算机中都是储存在线性空间里,实际上的顺序就是一列一列的拼接:
% 16 5 9 4 2 11 7 14 3 10 6 15 13 8 12 1
% 重排的时候仍然依照这个顺序取出。
sort
对矩阵进行排序,默认升序(从小到大)
A1 = [ 23 5 -1 4 7 0]
B1 = sort(A1)
A2 = [7 8 9; 2 4 -2; 10 2 4]
B2 = sort(A2,2) % 另一个输入参数为排序的维度
% 1指横坐标,2指纵坐标,3指竖坐标的规则仍适用
B2 = sort(A2) % 若不输入另一个参数,则默认另一个参数是1,按列排序
A3 = [ 23 5 -1 4 7 0]
B3 = sort(A3,'descend')
% 默认情况下,sort为升序('ascend'),使用降序时,可以使用输入参数'descend'来使用降序方法
A4 = [ 23 5 -1 4 7 0]
[B,I] = sort(A4)
A(I)
% sort返回两个输出参数时,
% 第一个变量返回排序后的数组,
% 第二个变量返回排序后的数组对应原有的数组索引A(I)和B是一样的。
将以上命令输入至命令行,将得到以下输出:
A1 =
23 5 -1 4 7 0
B1 =
-1 0 4 5 7 23
% sort排序一维矩阵时,返回排序后的一维矩阵
A2 =
7 8 9
2 4 -2
10 2 4
B2 =
7 8 9
-2 2 4
2 4 10
% 另一个输入参数为2,也就是按纵坐标排序
B2 =
2 2 -2
7 4 4
10 8 9
% 若不输入另一个参数,则默认另一个参数是1,按列排序
A3 =
23 5 -1 4 7 0
B3 =
23 7 5 4 0 -1
% 可以sort(A3,'descend')
A4 =
23 5 -1 4 7 0
B =
-1 0 4 5 7 23
I =
3 6 4 2 5 1
ans =
-1 0 4 5 7 23
% B为排序后的矩阵,I是一个索引(稍后会介绍索引:表示对应的关系)
% 可以看到B 和 A(I) 是完全一致的。
flip
flip就是反转矩阵的元素
A1 = [3 7 6 -1 0]
B1 = flip(A1)
A2 = [ 2 5 7;-5 3 5;0 6 5]
B2 = flip(A2)
A3 = [ 2 5 7;-5 3 5;0 6 5]
B3 = flip(A3,2)
将以上命令输入至命令行,将得到以下输出:
A1 =
3 7 6 -1 0
B1 =
0 -1 6 7 3
% flip函数用于快速反转一个矩阵
A2 =
2 5 7
-5 3 5
0 6 5
B2 =
0 6 5
-5 3 5
2 5 7
二维矩阵的反转默认按列反转
A3 =
2 5 7
-5 3 5
0 6 5
B3 =
7 5 2
5 3 -5
5 6 0
二维矩阵的反转也可以用flip(__,2)指定按行反转
circshift
循环移位:所有元素向后移位,超出的部分自动补回到最前面
A1 = [3 7 6 -1 0 2 8 0 ]
B1 = circshift(A1,[0,3])
% circshift(__,[m,n])表示,矩阵向下循环移动m位,矩阵向右循环移动n位
A2 = [ 1 0 0;0 0 0;0 0 0]
B2 = circshift(A2,[1,2])
将以上命令输入至命令行,将得到以下输出:
A1 =
3 7 6 -1 0 2 8 0
B1 =
2 8 0 3 7 6 -1 0
% circshift(__,[m,n])表示,矩阵向下循环移动m位,矩阵向右循环移动n位
A2 =
1 0 0
0 0 0
0 0 0
B2 =
0 0 0
0 0 1
0 0 0
拼接矩阵
拼接矩阵是另一类创建矩阵的特殊手段,需要对矩阵元素直接的关系有足够的理解。我们先介绍([ ]),再介绍类似于 repmat,cat,repelem的函数用法。
[ ]
我们将左右中括号用于创建矩阵,我们其实就是将若干个数用中括号实现了元素和矩阵的拼接。
a = [1,2]
b = [3,4] % 用来拼接
c = [a,0,b]
d = [a;b]
e = [a,a;a,b]
% f = [a,a,a;b,b] % 这样做矩阵不匹配
g = [c;a,0,1,2]
将以上命令输入至命令行,将得到以下输出:
a =
1 2
b =
3 4
c =
1 2 0 3 4
% 矩阵和数字可以混合拼接
d =
1 2
3 4
% 分号换行就是在列方向上拼接
e =
1 2 1 2
1 2 3 4
% 二维矩阵也可以拼接
g =
1 2 0 3 4
1 2 0 1 2
% 只要总的可以组成矩阵,矩阵可以任意拼接。
repmat
创建重复矩阵组成的拼接矩阵
A = [1,0;0,-1]
B1 = repmat(A,2)%
B2 = repmat(A,2,3) %
B3 = repmat(A,[2,3])%
% repmat(__,[m,n])和repmat(__,m,n)完全一致。
将以上命令输入至命令行,将得到以下输出:
A =
1 0
0 -1
B1 =
1 0 1 0
0 -1 0 -1
1 0 1 0
0 -1 0 -1
% 只传一个参数时,会在两个维度上都进行重复
B2 =
1 0 1 0 1 0
0 -1 0 -1 0 -1
1 0 1 0 1 0
0 -1 0 -1 0 -1
B3 =
1 0 1 0 1 0
0 -1 0 -1 0 -1
1 0 1 0 1 0
0 -1 0 -1 0 -1
% repmat(__,[m,n])和repmat(__,m,n)完全一致。
% m为在列方向重复次数,n为在行方向重复次数。
cat
cat函数是中括号的函数形式,唯一不同的地方是cat函数可以连接三维矩阵
A = [1, 2;3, 4]
B = [5, 6;7, 8]
C1 = cat(1,A,B)
C2 = cat(2,A,B)
C3 = cat(3,A,B)
将以上命令输入至命令行,将得到以下输出:
A =
1 2
3 4
B =
5 6
7 8
C1 =
1 2
3 4
5 6
7 8
% 维度一,列方向
C2 =
1 2 5 6
3 4 7 8
% 维度二,行方向
C3(:,:,1) =
1 2
3 4
C3(:,:,2) =
5 6
7 8
% 维度三,竖方向这样做可以创建三维矩阵
repelem
复写矩阵里的元素
A1 = [ 1 2 3]
B1 = repelem(A1,2)
% 对于一维矩阵而言,repelem(__,m)相当于每个元素都重复m次。
B2 = repelem(A1,[2 3 4])
% 如果附加的参数是一个等长度的一维矩阵,那么会以对应的频数复写元素。
A3 = [1 2; 3 4]
B3 = repelem(A3,2,3)
% 对于任意的矩阵而言都可以repelem(__,m,n),将每个元素以m×n复写
将以上命令输入至命令行,将得到以下输出
A1 =
1 2 3
B1 =
1 1 2 2 3 3
% 输入的第二个参数是2,对应将A1的元素复写2次
B2 =
1 1 2 2 2 3 3 3 3
% 输入的第二个参数是[2 3 4],对应将A1的元素复写2,3,4次
A3 =
1 2
3 4
B3 =
1 1 1 2 2 2
1 1 1 2 2 2
3 3 3 4 4 4
3 3 3 4 4 4
% 输入的第二个参数是2,输入的第三个参数是3
% 对应将A3的元素在列方向复写2次,行方向复写3次
索引
前面讲了那么多,终于可以讲最重要的索引部分。索引是什么?索引相当于编号,我们可以利用索引精确地找到我们想要的元素。无论是操作的输入还是输出,都要利用索引来实现。
A1 = [9 8 7 6 5 4 3 2 1]
B1_1 = A1(1) % 与很多程序语言不一样的是,MATLAB的索引从1开始,所以这一项返回第一个元素。
B1_2 = A1([1 3 5 2 1]) % 如果索引不止一个,以矩阵形式传入,可以一次性返回。
B1_3 = A1(1:2:7) % 冒号是使用索引的好助手
B1_4 = A1(2:6) % 冒号也可以这样使用
B1_5 = A1(:) % 只输入冒号相当于全部取出
B1_7 = A1(end) % 另一个强大的标记是end,表示该列(或者行)的最后一个索引
B1_8 = A1(3:end) % (如果矩阵的长度会变,这会避免不少麻烦)。
A2 = [4 5 6 7;5 7 9 0; 12 4 6 8; 0 -1 2 5]
B2_1 = A2(2,2) %二维矩阵可以用对应坐标取出
B2_2 = A2(2,:) %二维矩阵冒号相当于一行(或者一列)
B2_3 = A2(2:end,1:3) % 可以一次取出对应多行多列的元素组成新的矩阵。
% 特别的我们刚刚提到了一点:所有的矩阵在计算机中都是储存在线性空间里
% 那么下面这两个例子就是最好的演示
A3 = [1 2 3 4;5 6 7 8]
B3_1 = A3(5)
B3_2 = A3(5:7)
B3_3 = A3(:)
B3_4 = A3(:,:)
将以上命令输入至命令行,将得到以下输出:
A1 =
9 8 7 6 5 4 3 2 1
B1_1 =
9
% MATLAB的索引从1开始! MATLAB的索引从1开始! MATLAB的索引从1开始!
B1_2 =
9 7 5 8 9
% 多个索引以矩阵形式输入即可,允许重复索引,顺序无关
B1_3 =
9 7 5 3
B1_4 =
8 7 6 5 4
% 冒号运算符可以线性关系的索引
B1_5 =
9
8
7
6
5
4
3
2
1
% 只输入冒号运算符索引全部元素,但是这个时候变成了列向量(元素都是在内存中按列排放的)
B1_7 =
1
% end是矩阵最后一个元素的索引
B1_8 =
7 6 5 4 3 2 1
% end和冒号运算符的结合运用可以快捷取出元素
A2 =
4 5 6 7
5 7 9 0
12 4 6 8
0 -1 2 5
B2_1 =
7
% 二维矩阵的元素可以用对应二维坐标取出
B2_2 =
5 7 9 0
% 冒号作为矩阵行列索引,就是对应取出整行整列
B2_3 =
5 7 9
12 4 6
0 -1 2
% 利用冒号运算符可以一次取出对应多行多列的元素组成新的矩阵。
A3 =
1 2 3 4
5 6 7 8
B3_1 =
3
% 所有的矩阵在计算机中都是储存在线性空间里
% 实际上A3的线性排列 [1 5 2 6 3 7 4 8]
% 矩阵的第五个元素就是对应元素3
B3_2 =
3 7 4
% 这种索引方式也可以用矩阵输入索引
B3_3 =
1
5
2
6
3
7
4
8
% 只输入冒号运算符索引全部元素,以列向量输出
B3_4 =
1 2 3 4
5 6 7 8
% A3(:,:)的形式可以取出整个二维矩阵,而不至于转成列向量
补充内容
本次的内容有点多,重点内容需要巩固:
- size函数:目前来说最常见用于创建矩阵和确定循环结构的循环次数。
%% 1.模仿大师——创建一个一样大小的矩阵
a = [1 2 3 5;3 4 6 7];
b = zeros(size(a)); % 这就创建了一个大小完全一致的全零矩阵
% 试想如果a是外部输入的长度不确定的变量,这种方法就很高效
%% 2.循环次数
x = -1 : 0.1 : 3;
y = x;
for index = 1:size(x,2)
y(index) = (x(index)-1) * (x(index)-2) + index;
end
plot(x,y,'r--','LineWidth',3); % 曲线绘图函数
- reshape函数:重新排列矩阵,快速处理数据的手段
A = 1:15;
% 这样可以按列创建顺序的矩阵
B1 = reshape(A,3,5)
% 这样可以按行创建顺序的矩阵
B2 = reshape(A,5,3)'
% 三维数组为未尝不可
B3 = reshape(A,5,1,3)
- sort函数:内置的sort函数比自己编写的排序更高效
x = [ 8 9 2 4 0 10 3 6 7 1];
y = x.*x;
plot(x,y,'r*-');
% 点还是那些点,但顺序不对会影响绘图质量
% 这时排序可以用上
[x1,index] = sort(x);
plot(x1,y(index),'r*-');
- [ ]运算符:串联矩阵最重要的步骤
% 绘制斐波那契数列的曲线
x = 1:15;
y = [1,1];
for index = 3:size(x,2)
y = [y y(end)+ y(end-1)];
end
plot(x,y,'ro-','LineWidth',3); % 曲线绘图函数
- repmat函数:重复矩阵的拼接
% 字符串也可以拼接
a = ['hello']
b = repmat(a,3,2)
- 索引:功能强大,针对性的选取数组元素
% 仍使用sort的案例
% 这里我并没有重新计算y1 = x*x,是因为索引能直接找到对应的y
x = [ 8 9 2 4 0 10 3 6 7 1];
y = x.*x;
plot(x,y,'r*-');
% 点还是那些点,但顺序不对会影响绘图质量
% 这时排序可以用上
[x1,index] = sort(x);
plot(x1,y(index),'r*-');
%% 索引的具体应用更重要的是逻辑变量和find函数(篇幅有限,之后补充)。
思考
每一行代码执行后,对应变量会有什么变化?
a = 2:3:8;
b = [a' a' a'];
c = b(1:2:3,1:2:3);
d = a + b(2,:);
w = [zero(1,3) ones(1,3)' 3:5'];
b([1,3],2) = b([3,1],2);
e = 1:-1:5;
解答:
a是一个1×3的矩阵 [ 2 5 8 ]
b是一个3×3的矩阵 [ 2 2 2;
5 5 5;
8 8 8 ]
c是一个2×2的矩阵[ 2 2;
8 8 ]
d是一个1×3的矩阵[ 7 10 13 ]
e是一个1×9的矩阵[ 0 0 0 1 1 1 3 4 5 ]
b([1 3],2)=[ 8 2 ]修改了原有b矩阵的值
实际上b发生改变 [ 2 8 2;
5 5 5;
8 2 8 ]
(g)e是一个空矩阵
总结
本次的内容更多,已经划出重点,最大的重点是索引,结合逻辑矩阵能形成非常高效的作用。