计算两个数组之间余弦相似度的正确方法?

Posted

技术标签:

【中文标题】计算两个数组之间余弦相似度的正确方法?【英文标题】:Right way to compute cosine similarity between two arrays? 【发布时间】:2015-08-04 21:55:13 【问题描述】:

我正在做一个项目,该项目检测两个输入图像(手写签名)的一些特征,并使用余弦相似度比较这两个特征。这里当我指的是两个输入图像时,一个是原始图像,另一个是复制图像。 假设我正在提取一张图像(原始图像)的 15 个这样的特征并将其存储在一个数组中(例如,Array_ORG),而其他图像的特征类似地存储在 Array_DUP 中。 现在,我正在尝试计算这两个数组之间的余弦相似度。这些数组是双精度数据类型。

我列出了我遵循的两种方法:

1)手动计算余弦相似度:

main()

for(int i=0;i<15;i++)
    sum_org += (Array_org[i]*Array_org[i]);
for(int i=0;i<15;i++)
    sum_dup += (Array_dup[i]*Array_dup[i]);
double magnitude = sqrt(sum_org +sum_dup );
double cosine_similarity = dot_product(Array_org, Array_dup, sizeof(Array_org)/sizeof(Array_org[0]))/magnitude;


double dot_product(double *a, double* b, size_t n)
double sum = 0;
    size_t i;

    for (i = 0; i < n; i++) 
            sum += a[i] * b[i];
    

    return sum;

2) 将值存储到 Mat 中并调用点函数:

Mat A = Mat(1,15,CV_32FC1,&Array_org);
Mat B = Mat(1,15,CV_32FC1,&Array_dup);
double similarity = cal_theta(A,B);

double cal_theta(Mat A, Mat B)
double ab = A.dot(B);
double aa = A.dot(A);
double bb = B.dot(B);
return -ab / sqrt(aa*bb);

我读过余弦相似度值的范围是 -1 到 1,-1 表示两者完全相反,1 表示两者相等。但是第一个函数给了我 1000 的值,第二个函数给了我超过 1 的值。 请指导我哪个过程是正确的,为什么? 另外,如果余弦相似度值大于 1,我如何推断相似度?

【问题讨论】:

【参考方案1】:

余弦相似度的正确定义是:

您的代码没有计算分母,因此值是错误的。

double cosine_similarity(double *A, double *B, unsigned int Vector_Length)

    double dot = 0.0, denom_a = 0.0, denom_b = 0.0 ;
     for(unsigned int i = 0u; i < Vector_Length; ++i) 
        dot += A[i] * B[i] ;
        denom_a += A[i] * A[i] ;
        denom_b += B[i] * B[i] ;
    
    return dot / (sqrt(denom_a) * sqrt(denom_b)) ;

【讨论】:

对不起,似乎有一个错字,我只是将 dot_product 与幅度分开。我在发布时更改了变量的名称以便更好地理解,结果出现了一个错字。 哦,看看我修改过的代码。你计算的分母是错误的!应该是sqrt(sum_org*sum_dup)。您是在相加而不是相乘。 谢谢!弄错了:) 现在,两种方法都得出相同的答案,但你知道如果值大于 1,我该如何推断相似度吗? @ShruthiKodi 值的大小不能大于1,如|AB|^2 &lt;= norm(A)norm(B)(Cauchy-Schwartz 不等式) @vsoftco,没错!这是我的担忧。上面的代码给了我像 "2.6821e+006" 这样的值。我很困惑我应该从这个值中理解什么?任何线索都会有所帮助。【参考方案2】:

只需添加一个用 Opencv(C++) 计算特征向量余弦相似度的方法:

float cosSim = f1.dot(f2) / (cv::norm(f1) * cv::norm(f2));

其中f1f2 都是一维cv::Mat,大小为(1, xx)

【讨论】:

以上是关于计算两个数组之间余弦相似度的正确方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何编写返回两个文档之间余弦相似度的方法

余弦计算相似度理解以及计算

Spark笔记(1) :余弦相似度计算

在给定稀疏矩阵数据的情况下,Python 中计算余弦相似度的最快方法是啥?

计算两个向量的余弦相似度

计算两个向量的余弦相似度