我想在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中是否有任何函数可以比上面的代码更快地计算矩阵行之间的余弦相似度?
答案 0 :(得分:7)
通过计算与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
未明确计算。
答案 1 :(得分:5)
您的代码循环遍历所有行,并且每行循环(大约)一半行,计算每个唯一行组合的点积:
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
。在这里,我将两个向量相乘以产生一个方阵,用以下标准化:
S2 = (S1 * S1.') ./ (norm_r * norm_r.');