当前位置:首页 » 《随便一记》 » 正文

第3章 3.3 MATLAB中的矩阵(MATLAB入门课程)

3 人参与  2024年05月12日 08:57  分类 : 《随便一记》  评论

点击全文阅读


讲解视频:可以在bilibili搜索“MATLAB教程新手入门篇——数学建模清风主讲”。

MATLAB教程新手入门篇(数学建模清风主讲,适合零基础同学观看)_哔哩哔哩_bilibili

上一节中介绍了MATLAB中向量的基本操作,本节介绍MATLAB中矩阵的相关知识。因为向量可以看成矩阵的一个特例,所以它们有许多类似的操作。

3.3.1 矩阵的创建方法

在MATLAB中,矩阵的创建方法主要有三种,分别是:直接输入法、函数创建法和导入本地文件中的数据。大家可以打开本节的配套代码:“code_3_3_1”进行学习。

(1)直接输入法

我们先来看直接输入法,直接输入法适用于矩阵中元素数量较少的情况。

输入矩阵时要以中括号“[ ]”作为标识符号,矩阵的所有元素必须都在中括号内。矩阵的同行元素之间用空格或逗号分隔,行与行之间用分号或回车键分隔。

例如:命令a = [1 2 3; 4 5 6]; 可以在工作区创建出变量名为a的矩阵\left[ \begin{matrix} 1& 2& 3\\ 4& 5& 6\\ \end{matrix} \right]

(2)函数创建法

MATLAB提供了一些函数,这些函数可以用来生成某些特定的矩阵,我们这里介绍几组最常用到的函数。

第一组函数: zeros、ones和eye这三个函数分别用来创建全为0的矩阵、全为1的矩阵和单位矩阵。

以zeros函数为例,其常见的用法有两种:(1)zeros(n)可以创建一个n行n列全为0的矩阵;(2)zeros(m,n)可以创建一个m行n列全为0的矩阵。

例如:

 

ones和eye的用法类似,大家可以看配套的讲解视频或者查看MATLAB的帮助文档。

第二组函数: rand、randi和randn这三个函数分别用来创建均匀分布的随机数、均匀分布的随机整数和标准正态分布的随机数,以后会大量用到,请大家熟记。(数据的分布是概率论里面的知识点,没学过的同学可以搜索关键词自学)

rand函数用来创建区间0和1内均匀分布的随机数,其最常用的方法有两种:(1)rand(n)可以创建一个n行n列的随机数矩阵;(2)rand(m,n)可以创建一个m行n列的随机数矩阵。由rand函数创建的随机数矩阵的每个元素都随机取样自0和1之间的均匀分布。

randi函数用来创建均匀分布的随机整数,其最一般的用法为:randi([imin,imax],m,n),该命令可创建一个m行n列的随机数矩阵,随机数矩阵中的每个元素都是从区间[imin,imax]内随机抽取的整数。举个例子,假设我们要模拟投掷100次骰子,骰子有6个面,那么我们可以使用randi([1,6],1,100)得到一个长度为100的行向量,向量中的每个元素都是取自1,2,3,4,5,6中的一个整数。另外,如果imin等于1,那么可以简写为randi(imax,m,n);如果m和n相同,即生成一个n行n列的方阵,那么可以直接写成randi([imin,imax],n)。

randn函数用来创建标准正态分布的随机数,其使用方法和rand函数类似:(1)randn(n)可以创建一个n行n列的随机数矩阵;(2)randn(m,n)可以创建一个m行n列的随机数矩阵。由randn函数创建的随机数矩阵的每个元素都随机取样自标准正态分布。

注意:因为我们生成的是随机数,所以每次运行的结果可能会变化。除了上述这几个函数外,MATLAB还提供了其他一些与随机数生成相关的函数,感兴趣的同学可以在MATLAB官网搜索关键词:随机数。

第三组函数:diag和blkdiag

diag函数可用来创建对角矩阵或者获取矩阵的对角元素

情况1:如果输入的第一个参数是向量,则表示创建对角矩阵。

    diag(v, k) 将向量v的元素放置在第k条对角线上,其他位置元素为0。

    k=0 表示主对角线,k>0 位于主对角线上方,k<0 位于主对角线下方。

    如果k=0, 可以直接写成diag(v)。

 

情况2:如果输入的第一个参数是矩阵,则表示获取矩阵的对角元素。

    diag(A,k) 返回A的第k条对角线上元素的构成的列向量。

 

blkdiag函数可用来创建分块对角矩阵。

分块对角矩阵是相对于常规的对角矩阵而言的,常规的对角矩阵沿对角线具有单个元素,而分块对角矩阵的对角线的元素是矩阵。我们可采用以下形式表示一个分块对角矩阵:

 

(3)导入本地文件中的数据

MATLAB可读取本地的文件,支持的常见格式如下:

  .txt、.dat 或 .csv(适用于带分隔符的文本文件)

  .xls、.xlsb、.xlsm、.xlsx、.xltm、.xltx 或 .ods(适用于电子表格文件)

由于这一块的内容比较丰富且可能涉及我们没学过的知识点,所以会放在后面的章节进行讲解。到时候我们会重点学习MATLAB菜单栏:“主页——导入数据”这个功能。

3.3.2 矩阵元素的引用

在讲解矩阵元素的引用之前,我们先来回顾一下矩阵的表示方式:

上方给出了一个m行n列的矩阵,对于第i行第j列的元素,我们用a_{ij}表示。

因此,我们可以使用矩阵元素所处的行(row)和列(column)来进行引用矩阵的某一个元素,方式为:a(row_ind, column_ind).

这里的row_ind表示要引用的元素的行索引,column_ind表示列索引。如果row_ind和column_ind都是一个常数,则表示提取矩阵中的单个元素;如果row_ind或column_ind是包含有多个元素的向量,则表示同时提取多个位置的元素。与向量类似,end也可以用来替代最后一个索引,通常和冒号法一起使用。

下面我们来举两个例子,大家也可以打开本节的配套代码学习:“code_3_3_2”。

 

前面我们学过,可以使用length函数和numel函数来计算向量中包含的元素个数。那么,怎样计算一个矩阵的大小呢?我们可以使用size函数,它有两种常见的用法:

(1)size(A)返回一个行向量,其元素是A的各维度的长度。若A是一个3×4的矩阵,则size(A)返回向量[3 4];如果让[r,c] = size(A),那么r = 3,c = 4。

(2)size(A,dim)返回在维度dim上的长度。dim = 1时表示行;dim = 2时表示列。若A是一个3×4的矩阵,则size(A,1)返回3,size(A,2)返回4。

(length函数和numel函数也可以用在矩阵上。length函数会返回行和列的较大值:对上面的A矩阵,length(A)返回4;numel函数会返回矩阵中元素的总数,numel(A) 返回12)

有时候我们需要取出矩阵的某一行或者某一列。以取出矩阵A的第一行为例,我们可以使用代码A(1, 1:end),即row_ind取1表示第一行,column_ind取1:end表示从1到最后一列的索引。这时候我们可以直接将其简写为:A(1, :),逗号后面是列索引的位置,加一个冒号就表示取出每一列的元素。同理,要取第一列的所有元素,我们可以使用代码:A(:, 1).

总结:

 A(:, n) 表示矩阵A的第n列的所有元素。

 A(m, :) 表示矩阵A的第m行的所有元素。

练习:

 

前面我们介绍的是对矩阵的双下标进行索引,即同时指定行索引和列索引,中间用逗号隔开。有同学会问,我们能不能使用单个下标对矩阵进行索引呢?在MATLAB中是可以的,这种单下标的索引方法称为线性索引

事实上,在MATLAB中,矩阵的数据在计算机的内存中被存储为单列。以下图为例,下面的矩阵虽然显示为 3×3 矩阵,但MATLAB在内存中将它存储为单列,由它的各列顺次连接而成。例如,第2行第2列的元素的线性索引为5,第2行第3列的元素的线性索引为8。

 

我们可以利用线性索引来取出矩阵中的元素,尽管这种方式并不那么直观。

 

另外,A(:)命令可以将A中的所有元素按照线性索引的顺序重构成一个列向量。

 

最后,sub2ind和ind2sub函数可用于在矩阵的原始索引(双下标)和线性索引之间进行转换。他们的功能刚好相反,sub2ind将矩阵的下标转换为线性索引;ind2sub将线性索引转换为下标。

(1)    ind = sub2ind(sz,row,col) 针对大小为 sz 的矩阵返回由 row 和 col 指定的行列下标的对应线性索引 ind。此处,sz 是包含两个元素的向量,其中 sz(1) 指定行数,sz(2) 指定列数。

(2)    [row,col] = ind2sub(sz,ind) 返回数组 row 和 col,其中包含与大小为 sz 的矩阵的线性索引 ind 对应的等效行和列下标。此处,sz 是包含两个元素的向量,其中 sz(1) 指定行数,sz(2) 指定列数。

我们举两个例子:

 

3.3.3 矩阵元素的修改和删除

我们可以直接利用等号赋值的方法对矩阵中引用位置的元素进行修改,用法和对向量元素的修改类似。

 

当然,你也可以使用线性索引(单下标的索引)的方式对矩阵的元素进行修改:

 

注意,如果你在赋值时将一个或多个元素置于矩阵现有的行和列索引的边界之外,则会将矩阵的大小进行拓展,MATLAB会将没有赋值的位置的元素自动用0填充,使其保持为完整的矩形。

例如,A是一个2行3列的矩阵,在A的第三行第四列的位置插入一个元素88,矩阵A会自动进行拓展。

 

此外,我们还可以通过在现有索引范围之外插入一个新的矩阵来扩展原始矩阵的大小。

 

以上就是修改矩阵元素的方法,下面我们再来介绍删除矩阵元素的方法。

如果我们将等号右侧变成空向量[ ],则可以删除对应位置的元素。需要注意的是,通常只能删除矩阵的整行或者整列,否则会报错。

请看下面的例子:

 

注意,也可以通过线性索引来删除矩阵的元素。使用线性索引删除后,MATLAB会将矩阵中剩下的元素按照线性索引的顺序放入到一个向量中。另外,使用线性索引可以删除任意位置的元素,不需要删除矩阵的一整行或者一整列。

 

3.3.4 矩阵的拼接和重复

有时候我们需要对多个矩阵进行拼接,变成一个大的矩阵。根据矩阵拼接的方向,我们可以分为横向(水平)拼接和纵向(垂直)拼接,如下图所示:

 

如上图所示:横向拼接要求矩阵的行数相同;纵向拼接要求矩阵的列数相同。

在MATLAB中,我们可以使用命令[A, B] 或 [A  B]对矩阵A和B进行横向拼接,也可以使用MATLAB中的内置函数:horzcat(A,B);类似的,我们可以使用命令[A; B]对矩阵A和B进行纵向拼接,也可以使用MATLAB中的内置函数:vertcat(A,B)。

事实上,horzcat和vertcat两个函数来源自cat函数,这里的cat不是猫的意思,而是单词catenate的缩写,可以翻译成连接。

cat函数的用法如下:

命令cat(dim,A,B)表示沿着维度dim方向将矩阵B拼接到矩阵A的末尾。

dim = 1时表示沿着行方向从上往下进行拼接,即纵向拼接,因此cat(1,A,B)等价于vertcat(A,B);

dim = 2时表示沿着列方向从左自右进行拼接,即横向拼接,因此cat(2,A,B)等价于horzcat(A,B)。

(horzcat函数中的horz取自英文单词horizontal,表示水平的意思;vertcat函数中的vert取自英文单词vertical,表示竖直的意思)

总结:若A和B的行数相同,那么使用[A, B]、[A  B]、horzcat(A,B)以及cat(2,A,B)都能将A和B横向拼接成一个大的矩阵;若A和B的列数相同,那么使用[A; B]、vertcat(A,B)以及cat(1,A,B)都能将A和B纵向拼接成一个大的矩阵。

下面举几个例子:

(1)    横向拼接的例子

 

(2)    纵向拼接的例子

 

(3)    拼接时维度不一致导致的报错

如果横向拼接时矩阵的行数不相同,或者纵向拼接矩阵的列数不相同,那么MATLAB就会报错。

 

注意,如果要拼接的矩阵的个数大于2,也能使用上面的方法进行拼接,请看下面的例子:

 

除了对矩阵进行拼接外,有时候我们需要对同一个矩阵进行重复的堆叠。如下图所示,我们将矩阵A重复堆叠m×n次,得到一个新的矩阵:

 

在MATLAB中,对同一个矩阵进行重复的堆叠的代码为repmat(A,m,n)

(如何记住repmat这个函数?  repeat表示重复,matrix表示矩阵)

我们举两个例子:

 

除了对整个矩阵进行重复的堆叠外,MATLAB还可以对向量或者矩阵中的元素进行重复,使用到的函数是repelem(如何记住repelem: repeat重复 + element元素)

repelem函数有两种用法:

(1)    重复向量v中的元素:repelem(v, n)

当n为一个正整数时,表示把向量v中的每一个元素都重复n次;n也可以为一个向量,其长度必须和v的长度相同,它可以将v中第i个位置的元素v(i)重复n(i)次,其中n(i)表示n中第i个位置的元素。

 

(2)    重复矩阵A中的元素:repelem(A,m,n)

m和n分别表示沿着行方向(从上至下)以及沿着列方向(从左至右)将矩阵元素重复的次数,这里的m和n可以是正整数,也可以是向量。如果m是向量,则m的长度要和矩阵A的行数相同;如果n是向量,则n的长度要和矩阵A的列数相同。

 

3.3.5 矩阵的重构和重新排列

这一小节将介绍一些和矩阵的重构或重新排列相关的函数,下表给出了本小节要学的函数的名称和作用:

 

(1)reshape函数

reshape函数可以改变矩阵的形状,其常用语法为reshape(A, m, n)或者reshape(A,[m,n]),这可以将矩阵A的形状更改为m行n列,前提是转换前后的两个矩阵的元素总数要相同。

例如有一个矩阵A,它原来的形状是2行6列,如果我们需要将其形状变成3行4列,就可以使用命令:reshape(A, 3, 4). 

 

从上面的运行结果可以看出, reshape函数实际上是按矩阵的线性索引来重新组织矩阵元素的。也就是说,它先取矩阵A的第一列,然后是第二列,依此类推,再按新的维度重新组织这些元素。因此,转换后的B矩阵中的元素和A矩阵中的元素是完全相同的,即A(:)和B(:)的结果完全相同。

另外,我们不需要自己来计算转换后的矩阵有多少行或多少列。可以只给出转换后的行数,列数用空向量[ ]代替;或者只给出转换后的列数,行数用空向量[ ]代替。MATLAB会自动帮我们计算转换后的矩阵大小。例如:若A是一个由12个元素组成的矩阵,命令reshape(A,3,[ ])、reshape(A,[ ],4)可以实现和reshape(A,3,4)一样的效果。

如果你给出的转换后的行数和列数的乘积不等于原始矩阵中元素的个数,那么MATLAB就会报错:

 

(2)sort函数

sort函数是用于对向量或矩阵进行排序的。如果输入的参数是矩阵的话,还可以对矩阵的每一行或每一列分别进行排序。

①对向量排序

我们先来学习sort函数对向量排序,假设v是一个向量,有下面两种基础的用法:

sort(v) 可以将向量v按照从小到大的顺序进行升序排列;

sort(v, 'descend' )可以将向量v按照从大到小的顺序进行降序排列。

 

注意,上面的用法中,sort函数只有一个返回值,即排序后的向量;事实上,sort函数可以有两个返回值,基本用法为:[sort_v, ind] = sort(v)。这里,sort_v是排序后的向量,ind是排序后的向量(即sort_v)中的每个元素在原向量(即v)中的索引(即下标、位置)。我们来看一个具体的例子:

 

在上面的例子中,我们让sort函数返回了两个变量;sort_v和ind。它们是两个长度相等的向量,向量的方向和sort函数中输入的v向量的方向一致,都是行向量。向量v中所有元素的最小值为8,而8在v中的索引是4,因此sort_v中第一个元素为8,ind的第一个元素为4; 向量v中第二小的值为10,而10是v中的第1个元素,因此sort_v中第二个元素为10,ind的第二个元素为1;依次类推,可以得到sort_v和ind向量的值。事实上,这里有一个恒等关系成立:v(ind)运行的结果和sort_v的结果完全一样,大家可以自行验证。

下面我们看一个具体的应用场景。假设清风班上有10名同学,序号分别是1号、2号一直到10号。已知这10名同学的成绩构成的向量为:[84 70 61 90 69 78 88 74 92 76],问:清风班上哪三名同学的分数最高,分数分别是多少?

 

根据MATLAB返回的结果可以看出:9号、4号和7号这三名同学的分数排名前三,分别是92、90和88分。

上面这个问题比较简单,我们再来提一个问题:我们能不能知道这10名同学在班上的排名?例如:1号同学84分,在班上排名第4;2号同学70分,在班上排名第8;3号同学61分,排名第10;4号同学90分,排名第2;…… ;依此类推,最终我们想要得到的排名为:[4 8 10 2 9 5 3 7 1 6].

大家观察ind的值和我们想得到的排名的值,应该可以发现如下规律:1号同学排名第4,而ind中等于1的元素的索引也为4;2号同学排名第8,而ind中等于2的元素的索引也为8;3号同学排名第10,而ind中等于3的元素的索引也为10;4号同学排名第2,而ind中等于4的元素的索引也为2,依次类推,我们可以根据ind得到想要的排名。

根据上面的分析,我们可以将ind这个向量按照从小到大的顺序排列,排序后的向量是[1,2,3,…,10],且排序后的向量中的每个元素在向量ind中的索引就是我们要得到的排名!

因此,我们只需要加下面这行代码,new_ind就是我们想要计算的排名:

 

注意:如果存在同学的成绩相同的情况,那么这个代码就会存在问题,要想解决这个问题可以用到我们本章后面要学的ismember函数,这个问题也将放到本章最后的练习题中。

② 对矩阵排序

上面介绍的是sort函数对向量进行排序的应用,下面我们再来介绍sort函数对矩阵A进行排序的用法:sort(A, dim)

dim = 1时,沿着行方向(从上至下)对矩阵的每一列升序排列

dim = 2时,沿着列方向(从左至右)对矩阵的每一行升序排列

注意:(1)当dim=1时,sort(A,1)可以直接写成sort(A);(2)默认是升序排列的,我们可以在最后面加一个输入参数'descend',变成从大到小的降序排列;(3)可以有两个返回值,代表的含义和对向量排序类似,表示排序后的元素在原矩阵所在行或所在列中的索引。


(3)sortrows函数

sortrows函数可以基于矩阵的某一列对矩阵进行排序,排序后得到的新矩阵的同一行元素不会改变。这个函数的用法较多,下面我们直接用一个具体的实例来讲解它的主要用法。

假设清风老师有6名学生,下面这个矩阵保存着这六名同学在四门科目上的成绩。矩阵的每一行代表一名学生。这六名同学的四门科目的成绩对应着四列,例如第一名同学的第一科成绩为95,第二科成绩为80,依此类推。

 

请解决下面的问题:

(1)    请基于第一科的成绩按升序对这六名同学进行排序,得到排序后的成绩矩阵。若第一科成绩相同,则基于第二科成绩升序排列。如果第二科成绩还相同,就基于第三科成绩进行排序,依此类推。

 

(2)    请基于第一科的成绩按升序对这六名同学进行排序。当第一科成绩相同时,请保持其在矩阵中出现的先后顺序。

 

(3)    请基于第二科的成绩按升序对这六名同学进行排序。当第二科成绩相同时,请保持其在矩阵中出现的先后顺序。

 

(4)    请基于第一科的成绩按升序对这六名同学进行排序。当第一科成绩相同时,基于第三科成绩升序排列。如果第一科和第三科都相同,就保持在矩阵中出现的先后顺序。

 

事实上,sortrows(score)等价于sortrows(score, 1:size(score,2)),即sortrows(score, [1,2,3,4]). 

(5)    请基于第一科的成绩对这六名同学进行降序排列。当第一科成绩相同时,基于第三科成绩降序排列。如果第一科和第三科都相同,就保持在矩阵中出现的先后顺序。

 

(6)    请基于第一科的成绩对这六名同学进行降序排列。当第一科成绩相同时,基于第三科成绩升序排列。如果第一科和第三科都相同,就保持在矩阵中出现的先后顺序。

 

(7)    请基于第一科的成绩按升序对这六名同学进行排序。当第一科成绩相同时,请保持其在矩阵中出现的先后顺序,并返回索引值。

 

通过上面的例子可以看出,sortrows函数和sort函数的区别在于:sort函数会对矩阵的每一列分别进行排序;而sortrows函数是基于某一列进行排序的,排序后得到的新矩阵的同一行元素不会改变。

 

在实际的应用场景中,sort函数通常只用于对向量进行排序;如果是对矩阵或者表格数据进行排序,我们一般使用sortrows函数。如果大家熟悉Excel的话,就会发现Excel中对数据的排序就和sortrows函数类似。在以后的章节中,我们会专门讲解MATLAB中的表格数据类型,到时候还会用到sortrows函数。

以下是sortrows函数的常用用法的总结:

(1)    sortrows(A)基于矩阵A中第一列元素的值按升序对矩阵进行排序。当第一列包含重复值时,sortrows会根据下一列中的值进行升序,并对后续的重复值重复此行为。另外,sortrows(A)等价于sortrows(A, 1:size(A,2)).

(2)    sortrows(A,column)基于向量column中指定的列对矩阵A进行排序。例如,sortrows(A,2)会基于第二列中的元素按升序对矩阵A进行排序,如果第二列中有相同的元素,则保持其在矩阵中出现的先后顺序。sortrows(A,[2 3])首先基于第二列中的元素升序,若第二列元素相同,再基于第三列中的元素,对A矩阵进行升序排序。如果第三列也出现数值相同的情况,就保持其在矩阵中出现的先后顺序。

(3)    排序时可以指定每一列的排序方向,sortrows(___,direction)按direction指定的顺序对A进行排序。direction可以是'ascend'(默认值,对于升序排序)或 'descend'(对于降序排序)。direction 也可以是元素为 'ascend' 和 'descend' 的元胞数组,例如,sortrows(A,[1 3],{'ascend', 'descend'}) 首先基于第一列按升序对A进行排序,如果第一列中有数值相同,就基于第三列按降序排序。

(4)    除了返回排序后的矩阵,还可以返回排序后的各行在原矩阵中的位置索引。例如[sorted_A, index] = sortrows(A, column),此时A(index, :)的运行结果等于sorted_A。

(4)flip / fliplr / flipud 函数

下面我们来学习flip / fliplr / flipud这三个函数,它们可以用来对向量或矩阵进行翻转操作。其中,flip函数是一个通用的翻转函数,而fliplr和flipud是其特例,分别用于从左到右和从上到下的翻转。flip翻译成中文是翻转,而fliplr函数可以拆解为filp+ 左边left + 右边right,flipud则可以拆解为flip + 上边upper + 下边down,大家可以根据英文来进行记忆。

flip函数有两种用法:

用法1: flip(A)

 如果 A 为向量,flip(A) 将翻转向量中各元素的顺序,向量的方向不变。

 如果 A 为矩阵,flip(A) 将对矩阵进行上下翻转。

 

用法2: flip(A, dim)

flip(A,dim) 沿维度 dim 翻转 A 中元素的顺序。

dim为1时表示行,此时flip(A,1) 将沿着行方向对矩阵A上下翻转。

dim为2时表示列,此时flip(A,2) 将沿着列方向对矩阵A左右翻转。

 

请思考:若A是一个行向量,flip(A,1)返回的结果为什么还是A?

答案:此时A被当成了一个一行的矩阵,对A进行上下翻转不会有变化。因此这提示我们,要对向量进行翻转,直接使用flip(A)即可。

flip函数用法总结:

(1)    若要对向量A中的元素进行翻转且向量的方向不变,那么可以直接使用flip(A).

(2)    若要对矩阵A进行翻转,那么flip(A)、flip(A,1)和flipud(A)都能对矩阵A进行上下翻转;flip(A,2)和fliplr(A)能对矩阵A进行左右翻转。

(5)rot90函数

rot90函数是对矩阵进行旋转的函数,它源于英文rotate一词,中文翻译为旋转。rot90函数允许我们按90度或其倍数逆时针旋转矩阵。它的用法非常简单,rot90(A,k)将矩阵A按逆时针方向旋转k*90度,其中k是一个整数;不提供k时k默认取1。我们来看几个例子:

 

点击下方的CSDN专栏阅读下一篇文章:

MATLAB入门课程专栏


点击全文阅读


本文链接:http://zhangshiyu.com/post/107317.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1