前言
最近在刷视频的时候,刷到一个视频推荐的后台逻辑算法,其中之一就是余弦相似度算法。
想到了大学做商城项目,做商品推荐功能也用到了这个算法,当时觉得很难的知识,现在看看视频就能轻松理解了。
这篇文章是我最近学习余弦相似度的笔记,其中也附带了我个人的一些理解。
定义
余弦相似度,又称为余弦相似性,是通过计算两个向量的夹角余弦值来评估他们的相似度。余弦相似度将向量根据坐标值,绘制到向量空间中,如最常见的二维空间。------《百度百科》
公式
计算余弦相似度离不开高中数学向量的知识
向量 A 表示为 (a1,a2,⋯ ,an)(a_1, a_2, \cdots, a_n)(a1,a2,⋯,an)
向量 B 表示为 (b1,b2,⋯ ,bn)(b_1, b_2, \cdots, b_n)(b1,b2,⋯,bn)
数学向量计算点积的公式:
A⋅B=∣∣A∣∣×∣∣B∣∣×cosθ
A \cdot B=
||A|| \times ||B||
\times
cos \theta
A⋅B=∣∣A∣∣×∣∣B∣∣×cosθ
余弦相似度由数学点积公式转换而得,cosθcos \thetacosθ 就代表余弦相似度。计算A 、B向量的余弦相似度的公式:
cosθ=A⋅B∣∣A∣∣×∣∣B∣∣
cos \theta =
\frac
{ A \cdot B}
{||A|| \times ||B||}
cosθ=∣∣A∣∣×∣∣B∣∣A⋅B
其中 A⋅BA \cdot BA⋅B 是两个向量的点积,点积的计算公式:
A⋅B=∑i=1n(ai×bi)=a1×b1+a2×b2+⋯+an×bn
A \cdot B
= \sum_{i=1}^n(a_i \times b_i)
= a_1 \times b_1 + a_2 \times b_2 + \cdots + a_n \times b_n
A⋅B=i=1∑n(ai×bi)=a1×b1+a2×b2+⋯+an×bn
∣∣A∣∣×∣∣B∣∣||A|| \times ||B||∣∣A∣∣×∣∣B∣∣ 是A、B向量的模的乘积:
∣∣A∣∣=∑i=1n(ai)2=(a1)2+(a2)2+⋯+(an)2
||A|| = \sqrt{\sum_{i=1}^n(a_i)^2} = \sqrt{(a_1)^2 +(a_2)^2+ \cdots+ (a_n)^2 }
∣∣A∣∣=i=1∑n(ai)2=(a1)2+(a2)2+⋯+(an)2
∣∣B∣∣=∑i=1n(bi)2=(b1)2+(b2)2+⋯+(bn)2
||B|| = \sqrt{\sum_{i=1}^n(b_i)^2} = \sqrt{(b_1)^2 +(b_2)^2 + \cdots+ (b_n)^2 }
∣∣B∣∣=i=1∑n(bi)2=(b1)2+(b2)2+⋯+(bn)2
余弦相似度公式展开:
cosθ=∑i=1n(ai×bi)∑i=1n(ai)2×∑i=1n(bi)2=a1×b1+a2×b2+⋯+an×bn(a1)2+(a2)2+⋯+(an)2×(b1)2+(b2)2+⋯+(bn)2
cos \theta =
\frac
{
\sum_{i=1}^n(a_i \times b_i)
}
{
\sqrt{\sum_{i=1}^n(a_i)^2}
\times
\sqrt{\sum_{i=1}^n(b_i)^2}
} =
\frac
{
a_1 \times b_1 + a_2 \times b_2 + \cdots + a_n \times b_n
}
{
\sqrt{(a_1)^2 +(a_2)^2+ \cdots+ (a_n)^2 }
\times
\sqrt{(b_1)^2 +(b_2)^2 + \cdots+ (b_n)^2 }
}
cosθ=∑i=1n(ai)2×∑i=1n(bi)2∑i=1n(ai×bi)=(a1)2+(a2)2+⋯+(an)2×(b1)2+(b2)2+⋯+(bn)2a1×b1+a2×b2+⋯+an×bn
cosθ\thetaθ 的值域为 [-1, 1], 计算出的结果永远处于 [-1, 1] 区间。
代码实现
public class CosineSimilarityManual {
public static double compute(double[] v1, double[] v2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (int i = 0; i < v1.length; i++) {
dotProduct += v1[i] * v2[i];
norm1 += Math.pow(v1[i], 2);
norm2 += Math.pow(v2[i], 2);
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
public static void main(String[] args) {
double[] v1 = {1, 2, 3};
double[] v2 = {4, 5, 6};
double similarity = compute(v1, v2);
System.out.println("Cosine Similarity (Manual): " + similarity);
}
}
计算结果的数学解释
余弦相似度测量的是两个向量在方向上的差异
计算结果处于 (0, 1] 区间时,两个向量才会有正相关,并且越接近 1,相关性越高。
当计算结果为 1,表示两个向量方向完全相同。
当计算结果为 0,表示两个向量互相独立(正交)。
当计算结果为 -1,表示两个向量方向完全相反。
余弦相似度在平面直角坐标系的几何意义
余弦相似度就是两个向量的夹角余弦值,只和向量的夹角有关。
以二维平面直角坐标系,以下四个向量为例
A (2, 0)
B (3\sqrt{3}3, 1)
C (1, 3\sqrt{3}3)
D (0,2)
如图所示
AB的夹角θ1\theta_1θ1 = BC的夹角θ2\theta_2θ2 = CD的夹角θ3\theta_3θ3
所以在这个例子中
AB夹角的余弦相似度cosθ1cos \theta_1cosθ1 = BC夹角的余弦相似度cosθ2cos \theta_2cosθ2 = CD夹角的余弦相似度cosθ3cos \theta_3cosθ3
代码中计算结果如下,发现和上述一致
公式的计算结果永远处于 [-1, 1] 这个区间。
在三维情况下,我们仍然可以想象得到两个向量,在一个三维空间内,产生一个夹角,并且计算夹角的余弦值。
在四维以上的情况下,就没办法建立对应的坐标系画出对应的图形了,但是并不影响计算的结果,结果也处于 [-1, 1] 这个区间,也不影响其结果代表的含义。
应用场景
余弦相似度的应用场景
1.求职软件技术栈匹配,为求职者推荐岗位,或者为hr推荐牛人
2.对文字进行分词之后,可以做文章查重、论文查重、代码查重
3.在交友软件中,可以推荐与我志同道合的好友
4.在娱乐软件中,可以做歌单推荐、视频推荐
5.分析足球运动某位置需要的能力与球员的能力匹配度
6.考勤打卡、刷脸支付人脸比对
注意事项
余弦相似度只能根据两个向量的夹角求相似度,与向量本身的模并没有关系。
所以有时候要结合向量的模一起使用。
以上述应用场景1求职软件为例:
假设岗位需要:精通mysql、精通java、精通RabbitMQ,精通redis
一个求职者在给自己的简历标签是:了解mysql、了解java、了解RabbitMQ,了解redis。
用【1, 2, 3, 4, 5】来代表 【了解, 熟悉, 掌握, 熟练, 精通】
岗位向量:(5, 5, 5, 5, 5)
求职者向量:(1, 1, 1, 1, 1)
计算得到的 cosθcos \thetacosθ=1 完全匹配
但是在这个业务场景中,很显然,一个对技术只有了解的开发者,大概率不能胜任这个岗位,因此,这个场景需要结合向量的模来一起做判断。
总结
余弦相似度关注方向而非距离,当数据的大小不重要而方向重要时,余弦相似度比欧氏距离更合适。