2009-02-06 22 views
27

¿Cómo encuentro la similitud del coseno entre los vectores?¿Cómo calculo la similitud del coseno de dos vectores?

Necesito encontrar la similitud para medir la relación entre dos líneas de texto.

Por ejemplo, tienen dos frases como:

sistema para interfaz de usuario

máquina de interfaz de usuario

... y sus respectivos vectores después de Tf-idf, seguido de la normalización utilizando LSI, por ejemplo [1,0.5] y [0.5,1].

¿Cómo mido la similitud entre estos vectores?

Respuesta

18
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 de tf-idf recientemente para mi unidad de Recuperación de Información en la Universidad. Utilicé este método de similitud Cosine que usa Jama: Java Matrix Package.

Para obtener el código fuente completo, consulte IR Math with Java : Similarity Measures, un recurso realmente bueno que cubre unas pocas medidas de similitud diferentes.

+0

suena perfecto ... gracias –

29

Eche un vistazo a: http://en.wikipedia.org/wiki/Cosine_similarity.

Si tiene vectores A y B.

se define la similitud 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 
2

Cuando estaba trabajando con la minería de texto hace algún tiempo, estaba usando la biblioteca SimMetrics que proporciona una amplia gama de métricas diferentes en Java. Si sucedió que necesita más, entonces siempre hay R and CRAN para mirar.

Pero codificarlo de la descripción en la Wikipedia es una tarea bastante trivial, y puede ser un buen ejercicio.

+1

Parece que sus SimMetrics enlazar podrida y ahora apunta a un blog no deseado sobre los zapatos . https://github.com/Simmetrics/simmetrics parece uno mejor. –

5

Para código de matriz en Java, recomiendo usar la biblioteca Colt. 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 usar uno de los métodos Blas.dnrm2() o Algebra.DEFAULT.norm2() para el cálculo norma. Exactamente el mismo resultado, que es más legible, depende del gusto.

38

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 comprobarlo explícitamente por seguridad.

+2

Gracias, yo era demasiado flojo para hacerlo. :) – Enrichman

+0

¡Gracias, alivió mi trabajo! – Techiee

0

Para la escasa representación de vectores usando Map(dimension -> magnitude) Aquí es 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)) 
} 
Cuestiones relacionadas