Comment trouver la similarité cosinus entre les vecteurs?
Je dois trouver la similarité pour mesurer la relation entre deux lignes de texte.
Par exemple, j'ai deux phrases comme:
système d'interface utilisateur
machine d'interface utilisateur
… Et leurs vecteurs respectifs après tF-idf, suivis d'une normalisation à l'aide de LSI, par exemple [1,0.5]
et [0.5,1]
.
Comment puis-je mesurer la similarité entre ces vecteurs?
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;
}
}
J'ai récemment effectué quelques tâches tf-idf pour mon unité de recherche d'informations à l'université .J'ai utilisé cette méthode de similarité Cosinus qui utilise Jama: Java Matrix Package .
Pour le code source complet, voir Math IR avec Java: Mesures de similarité , une très bonne ressource qui couvre un bon nombre de mesures de similarité différentes.
Si vous souhaitez éviter de vous fier à des bibliothèques tierces pour une tâche aussi simple, voici une implémentation Java simple:
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));
}
Notez que la fonction suppose que les deux vecteurs ont la même longueur. Vous voudrez peut-être vérifier explicitement pour des raisons de sécurité.
Consultez: http://fr.wikipedia.org/wiki/Cosine_similarity .
Si vous avez les vecteurs A et B.
La similitude est définie comme suit:
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)
Exemple:
A = (1, 0.5), B = (0.5, 1)
cosine(theta) = (0.5 + 0.5) / sqrt(5/4) sqrt(5/4) = 4/5
Pour le code de matrice en Java, je vous recommande d'utiliser la bibliothèque Colt . Si vous avez cela, le code ressemble à (non testé ni même compilé):
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))
Le code ci-dessus peut également être modifié pour utiliser l'une des méthodes Blas.dnrm2()
ou Algebra.DEFAULT.norm2()
pour le calcul de la norme. Le même résultat, qui est plus lisible, dépend du goût.
Lorsque je travaillais avec l'exploration de texte il y a quelque temps, j'utilisais la bibliothèque SimMetrics qui fournit une vaste gamme de métriques différentes en Java. Si vous aviez besoin de plus, il y a toujours R et CRAN à regarder.
Mais le coder à partir de la description dans Wikipedia est une tâche plutôt triviale, et peut être un exercice de Nice.
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))
}
version scala
Pour la représentation fragmentaire des vecteurs utilisant Map(dimension -> magnitude)
Voici une version scala (vous pouvez faire des choses similaires 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))
}