【问题标题】:How do I calculate the cosine similarity of two vectors?如何计算两个向量的余弦相似度?
【发布时间】:2010-10-05 22:27:17
【问题描述】:

如何找到向量之间的余弦相似度?

我需要找到相似度来衡量两行文本之间的相关性。

例如,我有两句话:

用户界面系统

用户界面机器

…以及它们各自的向量在 tF-idf 之后,然后使用 LSI 进行归一化,例如 [1,0.5][0.5,1]

如何测量这些向量之间的相似度?

【问题讨论】:

    标签: java vector trigonometry tf-idf


    【解决方案1】:
    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))
    }
    

    scala 版本

    【讨论】:

    • 这看起来很像 java tbh
    【解决方案2】:

    对于向量的稀疏表示,使用Map(dimension -&gt; magnitude) 这是一个 scala 版本(你可以在 Java 8 中做类似的事情)

    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))
    }
    

    【讨论】:

      【解决方案3】:

      看看: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
      

      【讨论】:

        【解决方案4】:

        当我前段时间从事文本挖掘工作时,我使用了SimMetrics 库,该库在 Java 中提供了广泛的不同指标。如果碰巧您需要更多,那么总有R and CRAN 可以查看。

        但是根据 Wikipedia 中的描述对其进行编码是相当微不足道的任务,并且可以是一个很好的练习。

        【讨论】:

        【解决方案5】:

        如果你想避免依赖第三方库来完成这样一个简单的任务,这里有一个简单的 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));
        }
        

        请注意,该函数假定两个向量具有相同的长度。您可能需要明确检查它的安全性。

        【讨论】:

        • 谢谢,我只是懒得做。 :)
        【解决方案6】:

        对于 Java 中的矩阵代码,我建议使用 Colt 库。如果你有这个,代码看起来像(未经测试甚至编译):

        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() 进行范数计算。完全相同的结果,更易读的结果取决于口味。

        【讨论】:

          【解决方案7】:
          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 的工作。 我使用了这种使用 Jama: Java Matrix Package 的余弦相似度方法。

          有关完整源代码,请参阅IR Math with Java : Similarity Measures,这是一个非常好的资源,涵盖了好几个不同的相似性测量。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-07-11
            • 2017-09-07
            • 2016-03-06
            • 2019-12-27
            • 2014-03-25
            • 2016-03-08
            • 2015-05-24
            相关资源
            最近更新 更多