假设我在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 ];
我想将A
转换为NxN
矩阵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];
这段代码符合我的要求:
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;
你能建议一种有效的矢量化方法吗?
答案 0 :(得分:13)
您可以使用矩阵的上下三角形部分(triu
和tril
)执行此操作。
然后它是1行解决方案:
B = [tril(A,-1) zeros(N, 1)] + [zeros(N,1) triu(A)];
编辑:基准
这是循环方法,Sardar's answer中的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
结果:
结论:
find
大型矩阵非常重要,可节省Sardar方法之间约35%的处理时间。 答案 1 :(得分:4)
生成一个矩阵,对角线为零,非对角线索引为零。用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
修改强>
suggested Wolfie对于相同的算法,您可以摆脱转换为double
并使用find
:
B = 1-eye(N);
B(logical(B)) = A.';
B = B.';
答案 2 :(得分:0)
如果要在矩阵的对角线上插入任何矢量,则可以使用普通索引。以下代码段为您提供了所需对角线的索引,其中给出了方阵n
(矩阵为n
乘n
的大小)以及对角线{{1} },其中k
对应于主对角线,k=0
的正数对应于上对角线,而k
的负数对应于下对角线。 k
终于为您提供了2D索引。
ixd
用法:
function [idx] = diagidx(n,k)
% n size of square matrix
% k number of diagonal
if k==0 % identity
idx = [(1:n).' (1:n).']; % [row col]
elseif k>0 % Upper diagonal
idx = [(1:n-k).' (1+k:n).'];
elseif k<0 % lower diagonal
idx = [(1+abs(k):n).' (1:n-abs(k)).'];
end
end