相似性度量 Similarity Metric
了解不同相似性度量方式之间的区别和优缺点,为最佳相似性度量方式选择做出明智的决定
在下表中,您可以看到我们将在本文中讨论的相似性度量以及影响度量的向量的属性
欧几里得距离
角度和方向
余弦相似度
方向
点基相似度
角度和方向
欧几里得距离 Euclidean
distance
欧几里得距离是多维空间中两个向量之间的直线距离,计算向量相应分量之间的差的平方和的根
平面空间中的距离
向量之间的距离
Java 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class EuclideanDistance { public static double calculateDistance (double [] vector1, double [] vector2) { if (vector1.length != vector2.length) { throw new IllegalArgumentException ("Vector dimensions must be the same" ); } double sum = 0.0 ; for (int i = 0 ; i < vector1.length; i++) { double difference = vector1[i] - vector2[i]; sum += difference * difference; } return Math.sqrt(sum); } public static void main (String[] args) { double [] vector1 = {1.0 , 2.0 , 3.0 }; double [] vector2 = {4.0 , 5.0 , 6.0 }; double distance = calculateDistance(vector1, vector2); System.out.println("Euclidean distance: " + distance); } }
优势
缺点
高维诅咒(curse of dimensionality);在高维中表现不佳
用例
点积 Dot Product
也可以称为内积 Inner Product
向量的点积给出了两个向量之间的夹角余弦值,从而反映了它们的方向相似程度;当两个向量的点积为正时,它们的方向大致相同;当点积为负时,它们的方向大致相反;当点积为零时,它们的方向大致垂直
点积还可以用于计算向量在另一个向量上的投影。通过计算一个向量在另一个向量上的投影长度,可以了解一个向量在另一个向量方向上的分量大小
点积计算
使用转置矩阵表示
Java 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class DotProduct { public static void main (String[] args) { double [] vectorA = {1.0 , 2.0 , 3.0 }; double [] vectorB = {4.0 , 5.0 , 6.0 }; double dotProduct = calculateDotProduct(vectorA, vectorB); System.out.println("Dot product: " + dotProduct); } public static double calculateDotProduct (double [] vectorA, double [] vectorB) { if (vectorA.length != vectorB.length) { throw new IllegalArgumentException ("Vector dimensions do not match" ); } double dotProduct = 0.0 ; for (int i = 0 ; i < vectorA.length; i++) { dotProduct += vectorA[i] * vectorB[i]; } return dotProduct; } }
余弦相似度 Cosine Similarity
余弦相似性是两个向量之间角度的度量,它是通过取向量的点积并将其除以其大小的乘积来计算的,所以余弦相似度不受向量大小的影响,只受向量之间的角度的影响
即只要值大或值小的向量指向同一方向,它们就具有相同的余弦相似性
余弦相似度
范数
||A||
表示向量 A
的模(范数),也称为向量的长度或大小,是通过对向量的元素进行某种数学运算后得到的一个标量值,用于衡量向量的大小
常见的向量范数有多种定义,其中最常用的是欧几里得范数(L2 范数)
Java 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class CosineSimilarity { public static double calculateCosineSimilarity (double [] vector1, double [] vector2) { if (vector1.length != vector2.length) { throw new IllegalArgumentException ("Vector dimensions must be the same" ); } double dotProduct = 0.0 ; double normA = 0.0 ; double normB = 0.0 ; for (int i = 0 ; i < vector1.length; i++) { dotProduct += vector1[i] * vector2[i]; normA += Math.pow(vector1[i], 2 ); normB += Math.pow(vector2[i], 2 ); } double similarity; if (normA == 0 || normB == 0 ) { similarity = 0.0 ; } else { double denominator = Math.sqrt(normA) * Math.sqrt(normB); similarity = dotProduct / denominator; } return similarity; } public static void main (String[] args) { double [] vector1 = {1.0 , 2.0 , 3.0 }; double [] vector2 = {4.0 , 5.0 , 6.0 }; double similarity = calculateCosineSimilarity(vector1, vector2); System.out.println("Cosine similarity: " + similarity); } }
优势
主要考虑向量的方向,使其非常适合高维空间,如文本比较,其中文档的长度可能并不重要
缺点
当向量的大小很重要时,例如当基于像素强度比较图像嵌入时并不适用;如果数据不形成凸集,则可能无法提供准确的相似性度量
用例
文档分类、语义搜索、推荐系统以及涉及高维和规范化数据的任何其他任务
归一化 Normalization
归一化是将数据按比例缩放,使其落入特定的范围;在数据处理和分析中,归一化通常用于将不同范围和单位的数据转化为统一的标准,以消除由于数据尺度不同而引起的偏差
在向量的情况下,归一化也被称为向量的标准化,它是将向量按照其范数(模)进行缩放,使得向量的范数为一个固定值,通常为
1
通过归一化,可以消除向量长度的影响,只关注向量的方向,从而更好地比较和度量向量之间的相似性
举一个例子
假设我们有一个包含身高和体重的数据集,其中身高以厘米为单位,体重以千克为单位。数据集如下:
1
180
75
2
165
60
3
175
80
4
158
52
为了将身高和体重归一化,我们可以使用特定的归一化方法,例如将数据缩放到
0 到 1 之间的范围
身高的最大值 X_min_height = 158
身高的最小值 X_max_height = 180
1
(180 - 158) / (180 - 158) = 1.0
2
(165 - 158) / (180 - 158) ≈ 0.4286
3
(175 - 158) / (180 - 158) ≈ 0.8571
4
(158 - 158) / (180 - 158) = 0.0
体重的最小值:X_min_weight = 52
体重的最大值:X_max_weight = 80
1
(75 - 52) / (80 - 52) ≈ 0.6
2
(60 - 52) / (80 - 52) ≈ 0.2
3
(80 - 52) / (80 - 52) = 1.0
4
(52 - 52) / (80 - 52) = 0.0
在实际应用中,归一化可以帮助我们更好地比较和分析不同特征的数据,并减少由于数据尺度不同而引起的偏差
Java 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class Normalization { public static void main (String[] args) { double [] array = {1.0 , 2.0 , 3.0 , 4.0 , 5.0 }; double [] normalizedArray = normalize(array); for (double element : normalizedArray) { System.out.println(element); } } public static double [] normalize(double [] array) { double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; for (double element : array) { if (element < min) { min = element; } if (element > max) { max = element; } } double [] normalizedArray = new double [array.length]; for (int i = 0 ; i < array.length; i++) { normalizedArray[i] = (array[i] - min) / (max - min); } return normalizedArray; } }
凸集 Convex Set
如果一组向量数据被认为是凸集,那么对于这组向量中的任意两个向量,它们之间的线段上的所有点也属于这组向量数据;换句话说,这组向量数据中的任意两个向量之间的连接线段上的所有向量也属于这组向量数据
在余弦相似度中提到,如果数据不形成凸集,则可能效果不好
原因是相似度假设了向量之间的角度可以反映它们的相似性
对于非凸集的数据,由于数据的分布形状不符合凸集的特性,向量之间的角度可能无法准确地反映它们的相似性,非凸集的数据分布可能会导致向量之间的夹角不准确,从而影响余弦相似性的计算结果
Java 代码判断凸集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import java.util.ArrayList;import java.util.List;public class ConvexSetChecker { public static boolean isConvexSet (List<double []> vectors) { int n = vectors.size(); if (n < 3 ) { return true ; } for (int i = 0 ; i < n; i++) { double [] vector1 = vectors.get(i); double [] vector2 = vectors.get((i + 1 ) % n); double [] vector3 = vectors.get((i + 2 ) % n); double crossProduct = calculateCrossProduct(vector1, vector2, vector3); if (crossProduct < 0 ) { return false ; } } return true ; } private static double calculateCrossProduct (double [] vector1, double [] vector2, double [] vector3) { double x1 = vector2[0 ] - vector1[0 ]; double y1 = vector2[1 ] - vector1[1 ]; double x2 = vector3[0 ] - vector2[0 ]; double y2 = vector3[1 ] - vector2[1 ]; return x1 * y2 - x2 * y1; } public static void main (String[] args) { List<double []> vectors = new ArrayList <>(); vectors.add(new double []{0 , 0 }); vectors.add(new double []{1 , 0 }); vectors.add(new double []{0 , 1 }); boolean isConvex = isConvexSet(vectors); System.out.println("是否为凸集: " + isConvex); } }
参考
Which
vector similarity metric should I use? (imaurer.com)
Vector
Similarity Explained | Pinecone
推荐算法入门(1)相似度计算方法大全
- 知乎 (zhihu.com)
Hexo 数学公式支持: