在MATLAB中将矩形对角线添加到矩阵中

use*_*148 8 matlab matrix vectorization

假设我在MATLAB中有一个A维度矩阵Nx(N-1),例如

N=5;
A=[1  2  3  4;
   5  6  7  8;
   9  10 11 12;
   13 14 15 16;
   17 18 19 20 ];
Run Code Online (Sandbox Code Playgroud)

我想通过添加零对角线转换ANxN矩阵B,即

B=[ 0  1   2   3   4;
    5  0   6   7   8;
    9  10  0   11  12;
    13 14  15  0   16;
    17 18  19  20  0];
Run Code Online (Sandbox Code Playgroud)

这段代码做我想要的:

B_temp = zeros(N,N); 
B_temp(1,:) = [0 A(1,:)];
B_temp(N,:) = [A(N,:) 0];
for j=2:N-1
    B_temp(j,:)= [A(j,1:j-1) 0 A(j,j:end)];
end
B = B_temp; 
Run Code Online (Sandbox Code Playgroud)

你能建议一种有效的矢量化方法吗?

Wol*_*fie 13

您可以使用矩阵的上三角和下三角部分(triutril)来完成此操作.

然后它是1行解决方案:

B = [tril(A,-1) zeros(N, 1)] + [zeros(N,1) triu(A)];
Run Code Online (Sandbox Code Playgroud)

编辑:基准

这是循环方法,Sardar答案中的2种方法和上面的方法的比较.

基准代码,timeit用于计时和直接从问题和答案中提取代码:

function benchie()
    N = 1e4; A = rand(N,N-1); % Initialise large matrix
    % Set up anonymous functions for input to timeit
    s1 = @() sardar1(A,N); s2 = @() sardar2(A,N); 
    w =  @() wolfie(A,N); u = @() user3285148(A,N);
    % timings
    timeit(s1), timeit(s2), timeit(w), timeit(u)
end
function sardar1(A, N) % using eye as an indexing matrix
    B=double(~eye(N)); B(find(B))=A.'; B=B.';
end
function sardar2(A,N) % similar to sardar1, but avoiding slow operations
    B=1-eye(N); B(logical(B))=A.'; B=B.';
end
function wolfie(A,N) % using triangular parts of the matrix
    B = [tril(A,-1) zeros(N, 1)] + [zeros(N,1) triu(A)];
end
function user3285148(A, N) % original looping method
    B = zeros(N,N); B(1,:) = [0 A(1,:)]; B(N,:) = [A(N,:) 0];
    for j=2:N-1; B(j,:)= [A(j,1:j-1) 0 A(j,j:end)]; end
end
Run Code Online (Sandbox Code Playgroud)

结果:

  • Sardar方法1:2.83秒
  • Sardar方法2:1.82秒
  • 我的方法:1.45秒
  • 循环方式:3.80秒(!)

结论:

  • 你对它进行矢量化的愿望是有根据的,循环比其他方法慢.
  • 避免数据转换和find大型矩阵非常重要,可以节省Sardar方法之间约35%的处理时间.
  • 通过避免索引都在一起,你可以节省进一步的 20%的处理时间.


Sar*_*ama 5

生成一个矩阵,对角线索引为零,非对角索引为 1。将非对角元素替换为 的转置A(因为 MATLAB 是列主数)。再次转置以获得正确的顺序。

B = double(~eye(N));  %Converting to double since we want to replace with double entries
B(find(B)) = A.';     %Replacing the entries
B = B.';              %Transposing again to get the matrix in the correct order
Run Code Online (Sandbox Code Playgroud)

编辑:

正如Wolfie对于相同算法的建议,您可以摆脱转换为和使用with:doublefind

B = 1-eye(N);
B(logical(B)) = A.'; 
B = B.';
Run Code Online (Sandbox Code Playgroud)