Matlabの行列の異なる行間のコサイン類似度を計算したいと思います。私はmatlabで次のコードを書きました:
for i = 1:n_row
for j = i:n_row
S2(i,j) = dot(S1(i,:), S1(j,:)) / (norm_r(i) * norm_r(j));
S2(j,i) = S2(i,j);
行列S1は11000 * 11000であり、コードの実行には非常に時間がかかります。だから、私は知りたいです上記のコードよりも速く行列行間のコサイン類似度を計算する関数がmatlabにありますか?
コードはすべての行をループし、各行は(約)半分の行をループし、行の一意の組み合わせごとに内積を計算します。
n_row = size(S1,1);
norm_r = sqrt(sum(abs(S1).^2,2)); % same as norm(S1,2,'rows')
S2 = zeros(n_row,n_row);
for i = 1:n_row
for j = i:n_row
S2(i,j) = dot(S1(i,:), S1(j,:)) / (norm_r(i) * norm_r(j));
S2(j,i) = S2(i,j);
end
end
(実際に実行されるようにコードを完成させるために自由を取りました。ループの前にS2
を初期化することに注意してください。これにより、多くの時間を節約できます!)
内積が行ベクトルと列ベクトルの行列積であることに注意すると、正規化ステップを除いた上記は、次のようになります。
S2 = S1 * S1.';
これは、対称性を使用できない場合でも、明示的なループよりもはるかに高速に実行されます。正規化とは、各行をnorm_r
で除算し、各列をnorm_r
で除算することです。ここでは、2つのベクトルを乗算して、正規化する正方行列を生成します。
S2 = (S1 * S1.') ./ (norm_r * norm_r.');
pdist
との類似性を計算することによる短いバージョン:
_S2 = squareform(1-pdist(S1,'cosine')) + eye(size(S1,1));
_
pdist(S1,'cosine')
は、_S1
_の行のすべての組み合わせ間のコサイン距離を計算します。したがって、すべての組み合わせの類似性は1 - pdist(S1,'cosine')
です。
これを正方行列に変換できます。ここで、要素_(i,j)
_は、行i
とj
とsquareform(1-pdist(S1,'cosine'))
の類似性に対応します。
最後に、主対角を1に設定する必要があります。これは、行とそれ自体との類似性が明らかに1であるためですが、これはpdist
によって明示的に計算されません。