MATLAB小技巧(学习中跑偏发现)

MATLAB小技巧(学习中跑偏发现)

转自https://mp.weixin.qq.com/s/a3Is8WzwCtmCjsNkK-JUtA

任意给定一维数组(矢量)a和b ,例如:

a = [ a 1 , a 2 , a 3 , a 4 , a 5 ] , b = [ b 1 , b 2 , b 3 , b 4 , b 5 , b 6 ] , a = \begin{bmatrix} a_1, & a_2, & a_3, & a_4, & a_5 \end{bmatrix}, \quad b = \begin{bmatrix} b_1, & b_2, & b_3, & b_4, & b_5, & b_6 \end{bmatrix}, a=[a1,a2,a3,a4,a5],b=[b1,b2,b3,b4,b5,b6],如何构造具有如下形式的二维数组(矩阵)c呢:

C = \\begin{bmatrix} a_1 b\^T\\ a_2 b\^T \\ a_3 b\^T \\ a_4 b\^T \\ a_5 b\^T \\end{bmatrix} = \\begin{pmatrix} a_1 b_1 \& a_2 b_1 \& a_3 b_1 \& a_4 b_1 \& a_5 b_1 \\\\ a_1 b_2 \& a_2 b_2 \& a_3 b_2 \& a_4 b_2 \& a_5 b_2 \\\\ a_1 b_3 \& a_2 b_3 \& a_3 b_3 \& a_4 b_3 \& a_5 b_3 \\\\ a_1 b_4 \& a_2 b_4 \& a_3 b_4 \& a_4 b_4 \& a_5 b_4 \\\\ a_1 b_5 \& a_2 b_5 \& a_3 b_5 \& a_4 b_5 \& a_5 b_5 \\\\ a_1 b_6 \& a_2 b_6 \& a_3 b_6 \& a_4 b_6 \& a_5 b_6 \\end{pmatrix}

方法一

利用循环语句来解决问题,即对的每一行每一列元素循环,观察发现:

  • 第1行第1列元素是的第1个元素乘以的第1个元素;
  • 第1行第2列元素是的第2个元素乘以的第1个元素;
  • 第1行第j列元素是的第j个元素乘以的第1个元素;
  • 第2行第1列元素是的第1个元素乘以的第2个元素;
  • 第2行第2列元素是的第2个元素乘以的第1个元素;
  • ......
  • 第i行第j列元素是的第j个元素乘以的第i个元素;

因此可以看出,矩阵的列数和矢量的长度相同,矩阵的行数和矢量的长度相同(上面C矩阵的形式即可见)。

具体代码如下:

a=[1 2 3 4 5]; 
b=[0.1 0.2 0.3 0.4 0.5 0.6]; % 先任意给出两个矢量a b

% 最原始的方法:循环
tic % 计时开始
C=zeros(length(b),length(a)); % 注意C矩阵的维度
for j=1:length(a)
    for i=1:length(b)
        C(i,j)=a(j)*b(i); % 第i行第j列的元素填充进来
    end
end
C % 显示结果
toc % 计时结束

方法二

注意到矩阵的形式为:

\\mathrm{C}=\\left(\\begin{array}{cccc} a_1\\boldsymbol{b}\^T \& a_2\\boldsymbol{b}\^T \& a_3\\boldsymbol{b}\^T \& a_4\\boldsymbol{b}\^T \& a_5\\boldsymbol{b}\^T \\end{array}\\right).

可以看出,由于是作为一个整体参与运算,我们可以把中的每一个元素与相乘得到的结果"整体填充"进的每一列!

具体代码如下:

% 较高级的方法:数组整体操作
tic % 计时开始
C=repmat(zeros(size(a)),length(b),1); % 先产生对应维度的C矩阵
for j=1:length(a)
    C(:,j)=a(j)*b'; % 将a(j)乘以b矢量得到的结果整体放进C矩阵的第j列!
end
C % 显示结果
toc % 计时结束

方法三

重新审视一下我们的问题,两个矢量,,最后"组合"成一个矩阵,且

\\mathrm{C}_{i,j}=a_j\*b_i.

注意矩阵的形式为:

\\mathrm{C}=\\left(\\begin{array}{cccc} a_1\\boldsymbol{b}\^T \& a_2\\boldsymbol{b}\^T \& a_3\\boldsymbol{b}\^T \& a_4\\boldsymbol{b}\^T \& a_5\\boldsymbol{b}\^T \\end{array}\\right).

结合上面的示意图,即"先分块,再替换块"的操作过程,可以发现我们要求的矩阵其实就是先将矢量的每一个元素分块,再将各个"块"用来替换!

代码如下:

% 高效的方法:外积运算
tic % 计时开始
C=kron(a,b')  % a矢量和b矢量做张量积!一行指令,完事...
toc % 计时结束

方法四

第四种方法需要用到一个很强大的函数:bsxfun

通俗的解释就是,如果你想对矩阵A和矩阵B中的每一个元素进行某种函数fun运算,利用bsxfun​就可以"一次性完成",而不需要你一个元素一个元素地去循环操作。

该函数强大的地方在于,你可以随意指定一个fun函数,使它整体作用于矩阵A和B。形象一点就是你可以让自己的"黑箱"具有任意指定的功能!

需要将中的每一个元素与中的每一个元素相乘得到矩阵中的一个元素,恰好可以利用bsxfun​函数来实现,从而避免循环。

具体代码如下:

% 高大上的方法:bsxfun
tic % 计时开始
C=bsxfun(@times,a,b') % 将乘法运算(times)作用于a行矢量和b列矢量的每一个元素!也是一行完事...
toc % 计时结束

其中,指定了一个乘法运算(times)来整体作用于a数组和b'数组中的每一个元素,得到C矩阵。