¿Cómo puedo calcular el coseno de similitud de dos vectores?
-
21-08-2019 - |
Pregunta
¿Cómo puedo encontrar la similitud del coseno entre los vectores?
Necesito encontrar la similitud para medir la relación entre dos líneas de texto.
Por ejemplo, tengo dos frases como:
sistema para la interfaz de usuario
la interfaz de usuario de la máquina
... y sus respectivos vectores después de tF-idf, seguido por el uso de la normalización de la LSI, por ejemplo
[1,0.5]
y [0.5,1]
.
¿Cómo puedo medir la smiliarity entre estos vectores?
Solución
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;
}
}
Hice algunas cosas TF-IDF recientemente para mi unidad de Recuperación de Información en la Universidad. He utilizado este método de coseno similitud que utiliza Jama:. Java Matrix Paquete
Para el código fuente completo Ver IR Math con Java: medidas de similitud , muy buen recurso que cubre unas cuantas mediciones de similitud diferentes.
Otros consejos
Si desea evitar depender de bibliotecas de terceros para una tarea tan sencilla, aquí es una aplicación Java sencilla:
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));
}
Tenga en cuenta que la función asume que los dos vectores tienen la misma longitud. Es posible que desee comprobar que explicitamente para la seguridad.
Tener un vistazo a: http://en.wikipedia.org/wiki/Cosine_similarity .
Si usted tiene vectores A y B.
La similitud se define como:
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)
Ejemplo:
A = (1, 0.5), B = (0.5, 1)
cosine(theta) = (0.5 + 0.5) / sqrt(5/4) sqrt(5/4) = 4/5
Para el código de matriz en Java le recomiendo usar el Colt biblioteca. Si usted tiene esto, el código es el siguiente (no probado o incluso compilado):
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))
El código anterior también podría ser alterado para utilizar uno de los métodos Blas.dnrm2()
o Algebra.DEFAULT.norm2()
para el cálculo norma. Exactamente el mismo resultado, que es más fácil de leer depende del gusto.
Cuando estaba trabajando con la minería de texto hace algún tiempo, yo estaba usando el SimMetrics biblioteca que ofrece una amplia gama de diferentes métricas en Java. Si sucedió que necesita más, entonces siempre hay R y CRAN a la vista.
Sin embargo, la codificación que de la descripción en la Wikipedia es tarea bastante trivial, y puede ser un buen ejercicio.
Para la representación escasa de vectores usando Map(dimension -> magnitude)
He aquí una versión Scala (Usted puede hacer cosas similares en 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))
}
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))
}
versión Scala