MATLABで次のようにベクトルVを正規化します。
normalized_V = V/norm(V);
しかし、MATLABでベクトルを正規化する最もエレガントな(効率的な)方法ですか?
提案する元のコードが最善の方法です。
Matlabは少なくともこのようなベクトル化された操作で、少なくとも大きなベクトルに対しては非常に優れています。
組み込みのノルム関数は非常に高速です。タイミングの結果は次のとおりです。
V = Rand(10000000,1);
% Run once
tic; V1=V/norm(V); toc % result: 0.228273s
tic; V2=V/sqrt(sum(V.*V)); toc % result: 0.325161s
tic; V1=V/norm(V); toc % result: 0.218892s
V1は、最初の呼び出しで重要なキャッシュペナルティがないことを確認するために、ここで2回計算されます。
ここでのタイミング情報は、Windows上のR2008a x64で生成されました。
編集:
ノービスの提案に基づいて修正された回答(コメントを参照)。マトリックス数学(ほとんど)が勝ちます:
clc; clear all;
V = Rand(1024*1024*32,1);
N = 10;
tic; for i=1:N, V1 = V/norm(V); end; toc % 6.3 s
tic; for i=1:N, V2 = V/sqrt(sum(V.*V)); end; toc % 9.3 s
tic; for i=1:N, V3 = V/sqrt(V'*V); end; toc % 6.2 s ***
tic; for i=1:N, V4 = V/sqrt(sum(V.^2)); end; toc % 9.2 s
tic; for i=1:N, V1=V/norm(V); end; toc % 6.4 s
私見では、「norm(V)」と「sqrt(V '* V)」の違いは十分に小さいため、ほとんどのプログラムでは、より明確なものを使用するのが最善です。私にとって、「norm(V)」はより明確で読みやすいですが、Matlabでは「sqrt(V '* V)」は今でも慣用的です。
私はMATLABを知らず、それを使用したことはありませんが、あなたは分割しているように思えます。どうして?このようなものははるかに高速になります:
d = 1/norm(V)
V1 = V * d
遭遇する唯一の問題は、[〜#〜] v [〜#〜]のノルムがゼロ(またはそれに非常に近い)である場合です。 。これにより、InfまたはNaNと、ゼロ除算の警告。 InfまたはNaNを取得する必要がない場合、 [〜#〜] warning [〜#〜] を使用して、警告をオンまたはオフにすることができます。
oldState = warning('off','MATLAB:divideByZero'); % Return previous state then
% turn off DBZ warning
uV = V/norm(V);
warning(oldState); % Restore previous state
InfまたはNaN値が必要ない場合は、最初にノルムのサイズを確認するには:
normV = norm(V);
if normV > 0, % Or some other threshold, like EPS
uV = V/normV;
else,
uV = V; % Do nothing since it's basically 0
end
プログラムでそれが必要な場合、通常はunitと呼ばれる独自の関数に上記のコードを入れます(基本的にベクトルを単位に変えるため)同じ方向を指すベクトル)。
Fooz氏のコードを取り、Arlenのソリューションも追加しました。Octaveで得たタイミングは次のとおりです。
clc; clear all;
V = Rand(1024*1024*32,1);
N = 10;
tic; for i=1:N, V1 = V/norm(V); end; toc % 7.0 s
tic; for i=1:N, V2 = V/sqrt(sum(V.*V)); end; toc % 6.4 s
tic; for i=1:N, V3 = V/sqrt(V'*V); end; toc % 5.5 s
tic; for i=1:N, V4 = V/sqrt(sum(V.^2)); end; toc % 6.6 s
tic; for i=1:N, V1 = V/norm(V); end; toc % 7.1 s
tic; for i=1:N, d = 1/norm(V); V1 = V*d;end; toc % 4.7 s
次に、現在見ているもののために、各行の合計が1になることを確認するためにこのコードをテストしました。
clc; clear all;
m = 2048;
V = Rand(m);
N = 100;
tic; for i=1:N, V1 = V ./ (sum(V,2)*ones(1,m)); end; toc % 8.2 s
tic; for i=1:N, V2 = bsxfun(@rdivide, V, sum(V,2)); end; toc % 5.8 s
tic; for i=1:N, V3 = bsxfun(@rdivide, V, V*ones(m,1)); end; toc % 5.7 s
tic; for i=1:N, V4 = V ./ (V*ones(m,m)); end; toc % 77.5 s
tic; for i=1:N, d = 1./sum(V,2);V5 = bsxfun(@times, V, d); end; toc % 2.83 s
tic; for i=1:N, d = 1./(V*ones(m,1));V6 = bsxfun(@times, V, d);end; toc % 2.75 s
tic; for i=1:N, V1 = V ./ (sum(V,2)*ones(1,m)); end; toc % 8.2 s
すべてを乗算するという合理性により、リストの最後にエントリを追加します
clc; clear all;
V = Rand(1024*1024*32,1);
N = 10;
tic; for i=1:N, V1 = V/norm(V); end; toc % 4.5 s
tic; for i=1:N, V2 = V/sqrt(sum(V.*V)); end; toc % 7.5 s
tic; for i=1:N, V3 = V/sqrt(V'*V); end; toc % 4.9 s
tic; for i=1:N, V4 = V/sqrt(sum(V.^2)); end; toc % 6.8 s
tic; for i=1:N, V1 = V/norm(V); end; toc % 4.7 s
tic; for i=1:N, d = 1/norm(V); V1 = V*d;end; toc % 4.9 s
tic; for i=1:N, d = norm(V)^-1; V1 = V*d;end;toc % 4.4 s
最速(Jacobsと比較して時間が):
clc; clear all;
V = Rand(1024*1024*32,1);
N = 10;
tic;
for i=1:N,
d = 1/sqrt(V(1)*V(1)+V(2)*V(2)+V(3)*V(3));
V1 = V*d;
end;
toc % 1.5s