如何计算两个向量的余弦相似?
-
21-08-2019 - |
题
如何找到向量之间的余弦相似?
我需要找到的相似性来测量两行文本之间的相关性。
例如,我有两个这样的句子:
系统,用于用户接口
用户接口机
...和TF-IDF后它们各自的载体,使用LSI,例如随后归一化
[1,0.5]
和[0.5,1]
。
如何测量这些矢量之间的smiliarity?
解决方案
public class CosineSimilarity extends AbstractSimilarity {
@Override
protected double computeSimilarity(Matrix sourceDoc, Matrix targetDoc) {
double dotProduct = sourceDoc.arrayTimes(targetDoc).norm1();
double eucledianDist = sourceDoc.normF() * targetDoc.normF();
return dotProduct / eucledianDist;
}
}
我做了一些TF-IDF的东西最近在大学我的信息检索装置。 我使用利用贾马此余弦相似度方法:爪哇矩阵包
有关的完整源代码见 IR数学与Java:类似措施的,覆盖了好几张不同的相似性度量真的很好的资源。
其他提示
如果你想避免依赖于第三方库这样一个简单的任务,这里是一个纯Java实现:
public static double cosineSimilarity(double[] vectorA, double[] vectorB) {
double dotProduct = 0.0;
double normA = 0.0;
double normB = 0.0;
for (int i = 0; i < vectorA.length; i++) {
dotProduct += vectorA[i] * vectorB[i];
normA += Math.pow(vectorA[i], 2);
normB += Math.pow(vectorB[i], 2);
}
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}
请注意的是,函数假定两个矢量具有相同的长度。您可能需要显式地检查它的安全性。
看一看: http://en.wikipedia.org/wiki/Cosine_similarity
如果你有向量A和B
的相似性被定义为:
cosine(theta) = A . B / ||A|| ||B||
For a vector A = (a1, a2), ||A|| is defined as sqrt(a1^2 + a2^2)
For vector A = (a1, a2) and B = (b1, b2), A . B is defined as a1 b1 + a2 b2;
So for vector A = (a1, a2) and B = (b1, b2), the cosine similarity is given as:
(a1 b1 + a2 b2) / sqrt(a1^2 + a2^2) sqrt(b1^2 + b2^2)
示例:
A = (1, 0.5), B = (0.5, 1)
cosine(theta) = (0.5 + 0.5) / sqrt(5/4) sqrt(5/4) = 4/5
有关在Java中矩阵码我建议使用柯尔特库。如果你有这样的代码看起来像(未测试,甚至编译):
DoubleMatrix1D a = new DenseDoubleMatrix1D(new double[]{1,0.5}});
DoubleMatrix1D b = new DenseDoubleMatrix1D(new double[]{0.5,1}});
double cosineDistance = a.zDotProduct(b)/Math.sqrt(a.zDotProduct(a)*b.zDotProduct(b))
上面的代码也可以被改变,以使用的Blas.dnrm2()
方法或Algebra.DEFAULT.norm2()
用于规范化计算一个。完全相同的结果,这是更可读取决于味道。
当我与文本挖掘前一段时间的工作,我用它提供了 SimMetrics 库一个广泛的范围中的Java不同度量。如果它发生了,你需要更多的,那么总有 R和CRAN 来关注一下。
但它的编码从维基百科的描述是相当简单的任务,并且可以是一个很好的锻炼。
有关使用Map(dimension -> magnitude)
矢量的稀疏表示
这里是一个阶版本
def cosineSim(vec1:Map[Int,Int],
vec2:Map[Int,Int]): Double ={
val dotProduct:Double = vec1.keySet.intersect(vec2.keySet).toList
.map(dim => vec1(dim) * vec2(dim)).sum
val norm1:Double = vec1.values.map(mag => mag * mag).sum
val norm2:Double = vec2.values.map(mag => mag * mag).sum
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2))
}
def cosineSimilarity(vectorA: Vector[Double], vectorB: Vector[Double]):Double={
var dotProduct = 0.0
var normA = 0.0
var normB = 0.0
var i = 0
for(i <- vectorA.indices){
dotProduct += vectorA(i) * vectorB(i)
normA += Math.pow(vectorA(i), 2)
normB += Math.pow(vectorB(i), 2)
}
dotProduct / (Math.sqrt(normA) * Math.sqrt(normB))
}
def main(args: Array[String]): Unit = {
val vectorA = Array(1.0,2.0,3.0).toVector
val vectorB = Array(4.0,5.0,6.0).toVector
println(cosineSimilarity(vectorA, vectorA))
println(cosineSimilarity(vectorA, vectorB))
}
阶版本
不隶属于 StackOverflow