使用 Armadillo C++ 的余弦相似度给出了负面结果
Cosine similarity using Armadillo C++ gives me negative results
我已经实现了一个使用犰狳 c++ 线性库的余弦相似度函数。我的代码是下一个:
double cosine_similarity(rowvec A, rowvec B)
{
double dot = as_scalar(A*B.t());
double denomA = as_scalar(A*A.t());
double denomB = as_scalar(B*B.t());
return dot / (sqrt(denomA) * sqrt(denomB)) ;
}
我以这个矩阵为例:
-0.0261 -0.6780 -0.7338 0.0345
-0.0230 0.0082 -0.0400 -0.7056
-0.2590 -0.7052 0.6590 -0.0371
-0.9650 0.2072 -0.1551 0.0426
-0.0230 0.0082 -0.0400 -0.7056
当我计算第二行与所有行之间的余弦相似度时,我得到以下结果:
相似度[1,0]:-1.07944e-16
相似度[1,1]: 1
相似度[1,2]:-1.96262e-17
相似度[1,3]:-1.71729e-16
相似度[1,4]: 1
这是正确的吗?我担心负面结果,即使它们的意思是零。我想知道我是否做错了什么。 cosine_similarity是这样使用的:
for (unsigned int row = 0; row < redV.n_rows ; row++)
{
double ans = cosine_similarity(redV.row(indicate), redV.row(row));
cout << "Similarity [" << indicate << "," << row << "]: " << ans << endl;
cout << "Similarity [" << indicate << "," << row << "]: " << norm_dot(redV.row(indicate), redV.row(row)) << endl;
}
您的代码似乎是正确的,您只是遇到了机器精度问题。 A
第三行的 A*B.t()
和第二行的 B
(反之亦然)应该为零但不是,但在机器精度范围内。 Scipy’s cosine
有同样的问题:
In [10]: from scipy.spatial.distance import cosine
In [11]: 1 - cosine([-0.2590, -0.7052, 0.6590, -0.0371], [-0.0230, 0.0082, -0.0400, -0.7056])
Out[11]: -1.114299639159988e-05 # <=============== should not be negative!
(我减 1 只是因为 Scipy 定义 cosine
的方式。而且这个答案与您的答案不匹配,因为您只发布了四个小数点——但重点是,它是否定的。 )
如果您想检查一个浮点数 x
是否在另一个 y
的机器精度范围内,请比较它们与 std::numeric_limits::epsilon
的差异。参见 almost_equal
here 的定义。您可能希望 cosine_similarity
检查结果是 almost_equal
到 0 还是 1,在这种情况下 return 0 或 1。
我已经实现了一个使用犰狳 c++ 线性库的余弦相似度函数。我的代码是下一个:
double cosine_similarity(rowvec A, rowvec B)
{
double dot = as_scalar(A*B.t());
double denomA = as_scalar(A*A.t());
double denomB = as_scalar(B*B.t());
return dot / (sqrt(denomA) * sqrt(denomB)) ;
}
我以这个矩阵为例:
-0.0261 -0.6780 -0.7338 0.0345
-0.0230 0.0082 -0.0400 -0.7056
-0.2590 -0.7052 0.6590 -0.0371
-0.9650 0.2072 -0.1551 0.0426
-0.0230 0.0082 -0.0400 -0.7056
当我计算第二行与所有行之间的余弦相似度时,我得到以下结果:
相似度[1,0]:-1.07944e-16
相似度[1,1]: 1
相似度[1,2]:-1.96262e-17
相似度[1,3]:-1.71729e-16
相似度[1,4]: 1
这是正确的吗?我担心负面结果,即使它们的意思是零。我想知道我是否做错了什么。 cosine_similarity是这样使用的:
for (unsigned int row = 0; row < redV.n_rows ; row++)
{
double ans = cosine_similarity(redV.row(indicate), redV.row(row));
cout << "Similarity [" << indicate << "," << row << "]: " << ans << endl;
cout << "Similarity [" << indicate << "," << row << "]: " << norm_dot(redV.row(indicate), redV.row(row)) << endl;
}
您的代码似乎是正确的,您只是遇到了机器精度问题。 A
第三行的 A*B.t()
和第二行的 B
(反之亦然)应该为零但不是,但在机器精度范围内。 Scipy’s cosine
有同样的问题:
In [10]: from scipy.spatial.distance import cosine
In [11]: 1 - cosine([-0.2590, -0.7052, 0.6590, -0.0371], [-0.0230, 0.0082, -0.0400, -0.7056])
Out[11]: -1.114299639159988e-05 # <=============== should not be negative!
(我减 1 只是因为 Scipy 定义 cosine
的方式。而且这个答案与您的答案不匹配,因为您只发布了四个小数点——但重点是,它是否定的。 )
如果您想检查一个浮点数 x
是否在另一个 y
的机器精度范围内,请比较它们与 std::numeric_limits::epsilon
的差异。参见 almost_equal
here 的定义。您可能希望 cosine_similarity
检查结果是 almost_equal
到 0 还是 1,在这种情况下 return 0 或 1。