有没有一种更快的方法来从一个方阵中移除所有非对角线元素?
有没有一种更快的方法来从一个方阵中移除所有非对角线元素?
我在一个需要从一个大的方阵中移除非对角元素的应用程序中遇到了一个小的性能瓶颈。所以,矩阵 x
\n
17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9
\n变成了\n
17 0 0 0 0 0 5 0 0 0 0 0 13 0 0 0 0 0 21 0 0 0 0 0 9
\n问题:到目前为止,下面的bsxfun和diag解决方案是最快的解决方案,我怀疑在保持代码在Matlab中的情况下,我能找到更快的方法吗?\n
解决方案
\n这是我目前想到的解决方案。\n对矩阵进行逐元素的乘法,使用单位矩阵。这是最简单的解决方案:\n
y = x .* eye(n);
\n使用bsxfun和diag:\n
y = bsxfun(@times, diag(x), eye(n));
\n下三角/上三角矩阵:\n
y = x - tril(x, -1) - triu(x, 1);
\n使用循环的各种解决方案:\n
y = x; for ix=1:n for jx=1:n if ix ~= jx y(ix, jx) = 0; end end end
\n和\n
y = x; for ix=1:n for jx=1:ix-1 y(ix, jx) = 0; end for jx=ix+1:n y(ix, jx) = 0; end end
\n
计时
\n实际上,bsxfun
的解决方案是最快的。这是我的计时代码:\n
function timing() clear all n = 5000; x = rand(n, n); f1 = @() tf1(x, n); f2 = @() tf2(x, n); f3 = @() tf3(x); f4 = @() tf4(x, n); f5 = @() tf5(x, n); t1 = timeit(f1); t2 = timeit(f2); t3 = timeit(f3); t4 = timeit(f4); t5 = timeit(f5); fprintf('t1: %f s\n', t1) fprintf('t2: %f s\n', t2) fprintf('t3: %f s\n', t3) fprintf('t4: %f s\n', t4) fprintf('t5: %f s\n', t5) end function y = tf1(x, n) y = x .* eye(n); end function y = tf2(x, n) y = bsxfun(@times, diag(x), eye(n)); end function y = tf3(x) y = x - tril(x, -1) - triu(x, 1); end function y = tf4(x, n) y = x; for ix=1:n for jx=1:n if ix ~= jx y(ix, jx) = 0; end end end end function y = tf5(x, n) y = x; for ix=1:n for jx=1:ix-1 y(ix, jx) = 0; end for jx=ix+1:n y(ix, jx) = 0; end end end
\n它返回:\n
t1: 0.111117 s t2: 0.078692 s t3: 0.219582 s t4: 1.183389 s t5: 1.198795 s
这篇文章讨论了如何从方阵中快速移除非对角线元素的问题。作者通过测试了多种方法来实现这个目标,最后发现调用两次diag函数是最快的方法。下面是测试结果:
c1: 193.18毫秒 // 乘以单位矩阵
c2: 102.16毫秒 // 使用bsxfun函数
c3: 342.24毫秒 // 使用tril和triu函数
c4: 6.03毫秒 // 调用两次diag函数
作者还提到,在他的机器上,调用两次diag函数比bsxfun函数快了22倍,这是非常好的结果。他还猜测bsxfun函数在其他机器上相对于其他方法较慢的原因。
文章还谈到了使用tic和toc函数来进行基准测试的不准确性,并推荐使用内置的timeit函数来进行基准测试。
最后,作者回答了一个关于函数包装的问题,指出可以使用匿名函数来包装多行函数。
根据以上内容,可以得出这个问题的出现原因是为了找到一种快速移除方阵非对角线元素的方法。解决方法是调用两次diag函数。
代码如下:
y = diag(diag(x));
在处理方形矩阵时,有一个问题是如何更快地删除所有非对角线元素。根据测试,发现以下几种方法可以更快地实现这一目标:
方法一:使用diag函数
diag(diag(x))
通过使用diag函数,可以更快地删除方形矩阵x中的非对角线元素。
方法二:使用索引
diag(x(1:size(x,1)+1:end))
通过使用索引,可以更快地删除方形矩阵x中的非对角线元素。
方法三:使用预分配
x2(n,n)=0; x2(1:n+1:end)=x(1:n+1:end);
通过预先分配矩阵x2的大小,并使用索引将x中的非对角线元素赋值给x2,可以更快地实现删除非对角线元素的目标。
需要注意的是,在预分配x2时,使用x2=zeros(n)
会导致速度较慢的解决方案。可以在这个讨论中了解更多相关信息。
根据测试结果,以上三种方法在对比使用bsxfun函数时,速度提高了大约20倍。因此,可以在处理方形矩阵时选择其中一种方法来更快地删除非对角线元素。