Как рассчитать косинусное сходство двух векторов?

Как найти косинусное сходство между векторами?

Мне нужно найти сходство, чтобы измерить взаимосвязь между двумя строками текста.

Например, у меня есть два предложения:

система для пользовательского интерфейса

машина с пользовательским интерфейсом

… И их соответствующие векторы после tF-idf с последующей нормализацией с использованием LSI, например [1,0.5] и [0.5,1].

Как мне измерить сходство между этими векторами?


person Community    schedule 06.02.2009    source источник


Ответы (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 с Java: Измерения сходства, действительно хороший ресурс, который охватывает несколько хороших различных измерений сходства.

person Mark Davidson    schedule 06.02.2009

Если вы не хотите полагаться на сторонние библиотеки для такой простой задачи, вот простая реализация 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));
}

Обратите внимание, что функция предполагает, что два вектора имеют одинаковую длину. Вы можете явно проверить его на безопасность.

person Alphaaa    schedule 07.04.2014
comment
Спасибо, просто мне было лень это сделать. :) - person Enrichman; 20.08.2016

Взгляните на: 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
person Community    schedule 06.02.2009

Для матричного кода на 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() для расчета нормы. Точно такой же результат, более читаемый, зависит от вкуса.

person Nick Fortescue    schedule 06.02.2009

Когда я некоторое время назад работал с интеллектуальным анализом текста, я использовал библиотеку SimMetrics, которая предоставляет широкий диапазон различных показателей в Java. Если случилось так, что вам нужно больше, тогда всегда есть R и CRAN, на которые можно посмотреть.

Но кодировать его по описанию в Википедии - довольно тривиальная задача и может быть хорошим упражнением.

person Anonymous    schedule 06.02.2009
comment
Похоже, ваша ссылка на SimMetrics сгнила и теперь указывает на спам-блог об обуви. github.com/Simmetrics/simmetrics выглядит лучше. - person Kaypro II; 12.11.2015

Для разреженного представления векторов с использованием Map(dimension -> 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))
}
person Thamme Gowda    schedule 18.11.2016

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

person 裴帅帅    schedule 30.09.2018
comment
Это выглядит очень похоже на java tbh - person Yeikel; 07.01.2019