Lui*_*uis 1 optimization performance matlab normalize matrix
我有一个矩阵:
S = [ -1.0400 4.9100 4.1000 -3.5450 -0.6600 -0.9300 4.3950 -1.0650 2.9850 -4.9800 0.2100;
-0.5200 -4.3150 -3.0950 0.5700 4.4700 1.1500 3.1350 0.6450 0.3750 -4.9150 -2.1150;
5.0000 5.0000 5.0000 5.0000 5.0000 5.0000 5.0000 5.0000 5.0000 5.0000 5.0000 ];
Run Code Online (Sandbox Code Playgroud)
我想将列转换为单位向量,所以我使用for循环
for i=1:size(S,2)
S(:,i) = S(:,i) / norm( S(:,i) );
end
Run Code Online (Sandbox Code Playgroud)
有没有办法在MATLAB中更有效地完成这项工作?
TLDR
如果您有MATLAB 2016b或更新版本,并且没有兼容性问题,我会使用
S = S ./ sqrt(sum(S.^2,1));
Run Code Online (Sandbox Code Playgroud)
编辑:请参阅底部的基准测试,以获取替代品的性能基准.
上下文
我们可以手动计算范数并按列分割.
根据定义,norm(x) = sqrt( sum( x(:).^2 ) ).我在(:)这里用来表明norm是在整个矩阵上计算的.对我们有用的是sum默认情况下按列方式工作,因此列方式规范的定义如下:
nrm = sqrt( sum( x.^2 ) );
Run Code Online (Sandbox Code Playgroud)
请注意,如果您的矩阵可能S只有1行,则应使用明确强制执行逐列求和nrm = sqrt(sum(x.^2,1)).
现在我们有几种选择:
隐式扩展(MATLAB R2016b或更新版本)
S = S ./ nrm;
Run Code Online (Sandbox Code Playgroud)使用bsxfun(所有MATLAB版本)的隐式扩展
S = bsxfun( @mrdivide, S, nrm );
Run Code Online (Sandbox Code Playgroud)使用repmat(所有MATLAB版本)手动扩展
S = S ./ repmat(nrm, size(S,1), 1);
Run Code Online (Sandbox Code Playgroud)如果你有MATLAB R2017b或更新,并且再次没有兼容性问题,你可以使用vecnorm,它可以用来代替手动规范计算
S = S ./ vecnorm(S, 2, 1);
Run Code Online (Sandbox Code Playgroud)
基准测试:
既然你要求性能,这里有一个简单的基准来测试这些不同方法的速度.特别是你问题中的原始循环与使用vecnorm或手动计算的隐式扩展.
结果(使用R2017b运行)
size(S): 1e3*1e2 1e5*1e3 1e3*1e6
Looping: 0.0005 1.0186 12.7788
Implicit manual: 0.0001 1.1236 10.4031
Implicit vecnorm: 0.0002 0.5774 6.8058
Run Code Online (Sandbox Code Playgroud)结论
vecnorm大约是其他大型矩阵方法的两倍.1e5*1e3,循环与隐式扩展相当.码
function benchie()
S = rand( 1e3, 1e2 )*5;
f1 = @() loopingNorm(S);
f2 = @() implicitManual(S);
f3 = @() implicitVecnorm(S);
fprintf( 'Looping: %.4f\nImplicit manual: %.4f\nImplicit vecnorm: %.4f\n', ...
timeit(f1), timeit(f2), timeit(f3) );
end
function S = loopingNorm(S)
for ii = 1:size(S,2)
S(:,ii) = S(:,ii) / norm( S(:,ii) );
end
end
function S = implicitManual(S)
S = S ./ sqrt(sum(S.^2,1));
end
function S = implicitVecnorm(S)
S = S ./ vecnorm( S, 2, 1 );
end
Run Code Online (Sandbox Code Playgroud)