【问题标题】:cosine similarity built-in function in matlabmatlab中的余弦相似度内置函数
【发布时间】:2018-06-14 13:17:52
【问题描述】:

我想在 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中是否有任何函数可以比上面的代码更快地计算矩阵行之间的余弦相似度?

【问题讨论】:

  • 我想你在找S2 = 1 - pdist(S1, 'cosine') , ch.mathworks.com/help/stats/pdist.html
  • S2 = 1 - pdist(S1, 'cosine') 返回一个数字,而我需要一个 n×n 矩阵,它的每个元素都包含 S2(i,j) =dot(S1(i,:), S1(j,:)) / (norm_r(i) * norm_r(j))
  • 什么是norm_r
  • @Cris Luengo norm_r = sqrt(sum(abs(S1).^2,2));

标签: matlab matrix cosine-similarity


【解决方案1】:

通过计算与pdist的相似度的简版:

S2 = squareform(1-pdist(S1,'cosine')) + eye(size(S1,1));

说明:

pdist(S1,'cosine') 计算S1 中所有行组合之间的余弦距离。因此所有组合之间的相似度为1 - pdist(S1,'cosine')

我们可以把它变成一个方阵,其中元素(i,j) 对应于行ijsquareform(1-pdist(S1,'cosine')) 之间的相似性。

最后我们必须将主对角线设置为 1,因为一行与自身的相似度显然是 1,但这不是 pdist 明确计算的。

【讨论】:

  • 有一个pdist2 函数可以准确地返回这个方阵。
【解决方案2】:

您的代码循环遍历所有行,并且对于每一行循环遍历(大约)一半的行,计算每个唯一行组合的点积:

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.');

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-12
    • 2017-09-27
    • 2011-01-01
    • 2017-12-12
    • 2013-05-24
    • 1970-01-01
    • 2020-03-16
    相关资源
    最近更新 更多