Quelqu'un peut-il donner un exemple de similarité cosinus, très simplement, de manière graphique?
article de similitude Cosine sur Wikipedia
Pouvez-vous montrer les vecteurs ici (dans une liste ou quelque chose) et ensuite faire le calcul, et voyons comment ça marche?
je suis débutant.
10 réponses
voici deux textes très courts à comparer:
-
Julie loves me more than Linda loves me
-
Jane likes me more than Julie loves me
Nous voulons savoir comment ces textes sont, purement en termes de nombre de mots (et en ignorant l'ordre des mots). Nous commençons par faire une liste des mots des deux textes:
me Julie loves Linda than more likes Jane
maintenant nous comptons le nombre de fois chacun de ces mots apparaît dans chaque texte:
me 2 2
Jane 0 1
Julie 1 1
Linda 1 0
likes 0 1
loves 2 1
more 1 1
than 1 1
Nous ne sommes pas intéressés par les mots eux-mêmes. Nous nous intéressons uniquement à ces deux vecteurs verticaux des comptes. Par exemple, il y a deux instances de "moi" dans chaque texte. Nous allons décider de la manière de combler ces deux textes sont à chaque d'autres par le calcul d'une fonction de ces deux vecteurs, à savoir le cosinus de l'angle entre eux.
les deux vecteurs sont, encore une fois:
a: [2, 0, 1, 1, 0, 2, 1, 1]
b: [2, 1, 1, 0, 1, 1, 1, 1]
Le cosinus de l'angle entre eux est d'environ 0.822.
ces vecteurs sont en 8 Dimensions. Une vertu de l'utilisation de la similarité cosinus est clairement qu'il convertit une question qui est au-delà de la capacité humaine pour visualiser un cela peut être. Dans ce cas, vous pouvez penser ce que l'angle d'environ 35 degrés qui est une certaine "distance" de zéro ou accord parfait.
je suppose que vous êtes plus intéressé à obtenir un aperçu dans " pourquoi " la similitude cosinus fonctionne (pourquoi il fournit une bonne indication de la similitude), plutôt que " comment " il est calculé (les opérations spécifiques utilisées pour le calcul). Si votre intérêt est avec ce dernier, voir la référence indiquée par Daniel dans ce post, ainsi que une question liée ainsi .
pour expliquer les deux le comment et encore plus le pourquoi, il est utile, au premier abord, pour simplifier le problème et de travailler uniquement en deux dimensions. Une fois que vous obtenez cela en 2D, il est plus facile d'y penser en 3 dimensions, et bien sûr plus difficile à imaginer dans beaucoup plus de dimensions, mais d'ici là, nous pouvons utiliser l'algèbre linéaire pour faire les calculs numériques et aussi pour nous aider à penser en termes de lignes/vecteurs / "plans" / "sphères" en n dimensions, même si nous ne pouvons pas les dessiner.
So... en deux dimensions : en ce qui concerne la similarité du texte, cela signifie que nous nous concentrerions sur deux termes distincts, disons les mots" Londres "et" Paris", et nous compterions combien de fois chacun de ces mots se trouve dans chacun des deux documents que nous souhaitons comparer. Cela nous donne, pour chaque document un point dans le plan x-y, par exemple si Doc1 avait Paris une fois, et Londres quatre fois, un point à (1,4) présenterait ce document (en ce qui concerne cette évaluation diminutive des documents). Ou, parler en termes de vecteurs, ce Doc1 document serait une flèche allant de l'origine au point (1,4). Avec cette image à l'esprit, réfléchissons à ce que cela signifie d'être similaire pour deux documents et comment cela se rapporte aux vecteurs.
des documents très similaires (toujours en ce qui concerne cet ensemble limité de dimensions) auraient le même nombre de références à Paris, et le même nombre de références à Londres, ou peut-être, ils pourraient avoir le même ratio de ces références (dire un Le document Doc2, avec 2 références à Paris et 8 références à Londres, serait aussi très similaire, seulement peut-être un texte plus long ou quelque peu plus répétitif des noms des villes, mais dans la même proportion: peut-être que les deux documents sont des guides sur Londres, ne faisant que des références à Paris (et à quel point cette ville n'est pas cool; -) je plaisante!!!). Maintenant, des documents moins similaires, peuvent aussi inclure des références aux deux villes, mais dans des proportions différentes, peut-être que Doc2 ne citerait Paris Qu'une fois et Londres 7 fois.
retour à notre plan x-y, si nous dessinons ces documents hypothétiques, nous voyons que quand ils sont très similaires leurs vecteurs se chevauchent (bien que certains vecteurs peuvent être plus longs), et comme ils commencent à avoir moins en commun, ces vecteurs commencent à diverger, pour avoir un plus grand angle entre eux.
Bam! en mesurant l'angle entre les vecteurs, nous pouvons avoir une bonne idée de leur similitude , et, pour rendre les choses encore plus facile, par en prenant le Cosine de cet angle, Nous avons une bonne valeur de 0 à 1 (ou -1 à 1, selon ce que nous rendons compte et comment) qui est indicative de cette similitude. Plus l'angle est petit, plus la valeur de cosinus est grande (plus près de 1), et plus la similarité est grande.
à l'extrême, si Doc1 ne cite que Paris et Doc2 ne cite que Londres, les documents n'ont absolument rien en commun. Doc1 aurait son vecteur sur l'axe x, Doc2 sur l'axe y, l'angle 90 degrés, cosinus 0. (BTW c'est ce que nous voulons dire quand nous disons que deux choses sont orthogonales l'une à l'autre )
ajout de dimensions :
Avec ce sentiment intuitif de similitude exprimé sous un petit angle (ou grand cosinus), nous pouvons maintenant imaginer des choses en 3 dimensions, disons en introduisant le mot "Amsterdam" dans le mélange. Et visualisez, assez bien, comment un document avec deux références de chacun aurait un vectoriel va dans une direction particulière et nous pouvons voir comment cette direction se comparerait à un document citant Paris et Londres 3 fois chacun mais pas Amsterdam etc.. Comme dit, Nous pouvons essayer d'imaginer cet espace de fantaisie pour 10 ou 100 villes, difficile à dessiner, mais facile à conceptualiser.
je conclurai en disant quelques mots sur la formule elle-même . Comme il a été dit, d'autres références fournissent de bonnes informations sur les calculs.
encore une fois premier en 2 dimensions. La formule du cosinus de l'angle entre deux vecteurs est dérivée de la différence trigonométrique (entre l'angle a et l'angle b)
cos(a - b) = (cos(a) * cos(b)) + (sin (a) * sin(b))
cette formule ressemble beaucoup à la formule du produit dot:
Vect1 . Vect2 = (x1 * x2) + (y1 * y2)
où cos(A) correspond à la valeur x et sin (a) à la valeur y, pour le premier vecteur. etc. Le seul problème, c'est que x, y, etc. ne sont pas exactement les valeurs cos et sin, pour ces valeurs besoin d'être lu sur le cercle unité. C'est là que le dénominateur de la formule entre en jeu: en se divisant par le produit de la longueur de ces vecteurs, les coordonnées x et y deviennent normalisées.
Voici mon implémentation en C#.
using System;
namespace CosineSimilarity
{
class Program
{
static void Main()
{
int[] vecA = {1, 2, 3, 4, 5};
int[] vecB = {6, 7, 7, 9, 10};
var cosSimilarity = CalculateCosineSimilarity(vecA, vecB);
Console.WriteLine(cosSimilarity);
Console.Read();
}
private static double CalculateCosineSimilarity(int[] vecA, int[] vecB)
{
var dotProduct = DotProduct(vecA, vecB);
var magnitudeOfA = Magnitude(vecA);
var magnitudeOfB = Magnitude(vecB);
return dotProduct/(magnitudeOfA*magnitudeOfB);
}
private static double DotProduct(int[] vecA, int[] vecB)
{
// I'm not validating inputs here for simplicity.
double dotProduct = 0;
for (var i = 0; i < vecA.Length; i++)
{
dotProduct += (vecA[i] * vecB[i]);
}
return dotProduct;
}
// Magnitude of the vector is the square root of the dot product of the vector with itself.
private static double Magnitude(int[] vector)
{
return Math.Sqrt(DotProduct(vector, vector));
}
}
}
par souci de simplicité, je réduis le vecteur a et b:
Let :
a : [1, 1, 0]
b : [1, 0, 1]
Puis similarité cosinus (Theta):
(Theta) = (1*1 + 1*0 + 0*1)/sqrt((1^2 + 1^2))* sqrt((1^2 + 1^2)) = 1/2 = 0.5
alors l'inverse de cos 0.5 est de 60 degrés.
ce code Python est ma tentative rapide et sale d'implémenter l'algorithme:
import math
from collections import Counter
def build_vector(iterable1, iterable2):
counter1 = Counter(iterable1)
counter2 = Counter(iterable2)
all_items = set(counter1.keys()).union(set(counter2.keys()))
vector1 = [counter1[k] for k in all_items]
vector2 = [counter2[k] for k in all_items]
return vector1, vector2
def cosim(v1, v2):
dot_product = sum(n1 * n2 for n1, n2 in zip(v1, v2) )
magnitude1 = math.sqrt(sum(n ** 2 for n in v1))
magnitude2 = math.sqrt(sum(n ** 2 for n in v2))
return dot_product / (magnitude1 * magnitude2)
l1 = "Julie loves me more than Linda loves me".split()
l2 = "Jane likes me more than Julie loves me or".split()
v1, v2 = build_vector(l1, l2)
print(cosim(v1, v2))
en utilisant L'exemple de @Bill Bell, deux façons de le faire en [R]
a = c(2,1,0,2,0,1,1,1)
b = c(2,1,1,1,1,0,1,1)
d = (a %*% b) / (sqrt(sum(a^2)) * sqrt(sum(b^2)))
ou en profitant de la performance de la méthode crossprod ()...
e = crossprod(a, b) / (sqrt(crossprod(a, a)) * sqrt(crossprod(b, b)))
c'est un code simple Python
qui met en œuvre la similitude cosinus.
from scipy import linalg, mat, dot
import numpy as np
In [12]: matrix = mat( [[2, 1, 0, 2, 0, 1, 1, 1],[2, 1, 1, 1, 1, 0, 1, 1]] )
In [13]: matrix
Out[13]:
matrix([[2, 1, 0, 2, 0, 1, 1, 1],
[2, 1, 1, 1, 1, 0, 1, 1]])
In [14]: dot(matrix[0],matrix[1].T)/np.linalg.norm(matrix[0])/np.linalg.norm(matrix[1])
Out[14]: matrix([[ 0.82158384]])
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
*
* @author Xiao Ma
* mail : 409791952@qq.com
*
*/
public class SimilarityUtil {
public static double consineTextSimilarity(String[] left, String[] right) {
Map<String, Integer> leftWordCountMap = new HashMap<String, Integer>();
Map<String, Integer> rightWordCountMap = new HashMap<String, Integer>();
Set<String> uniqueSet = new HashSet<String>();
Integer temp = null;
for (String leftWord : left) {
temp = leftWordCountMap.get(leftWord);
if (temp == null) {
leftWordCountMap.put(leftWord, 1);
uniqueSet.add(leftWord);
} else {
leftWordCountMap.put(leftWord, temp + 1);
}
}
for (String rightWord : right) {
temp = rightWordCountMap.get(rightWord);
if (temp == null) {
rightWordCountMap.put(rightWord, 1);
uniqueSet.add(rightWord);
} else {
rightWordCountMap.put(rightWord, temp + 1);
}
}
int[] leftVector = new int[uniqueSet.size()];
int[] rightVector = new int[uniqueSet.size()];
int index = 0;
Integer tempCount = 0;
for (String uniqueWord : uniqueSet) {
tempCount = leftWordCountMap.get(uniqueWord);
leftVector[index] = tempCount == null ? 0 : tempCount;
tempCount = rightWordCountMap.get(uniqueWord);
rightVector[index] = tempCount == null ? 0 : tempCount;
index++;
}
return consineVectorSimilarity(leftVector, rightVector);
}
/**
* The resulting similarity ranges from −1 meaning exactly opposite, to 1
* meaning exactly the same, with 0 usually indicating independence, and
* in-between values indicating intermediate similarity or dissimilarity.
*
* For text matching, the attribute vectors A and B are usually the term
* frequency vectors of the documents. The cosine similarity can be seen as
* a method of normalizing document length during comparison.
*
* In the case of information retrieval, the cosine similarity of two
* documents will range from 0 to 1, since the term frequencies (tf-idf
* weights) cannot be negative. The angle between two term frequency vectors
* cannot be greater than 90°.
*
* @param leftVector
* @param rightVector
* @return
*/
private static double consineVectorSimilarity(int[] leftVector,
int[] rightVector) {
if (leftVector.length != rightVector.length)
return 1;
double dotProduct = 0;
double leftNorm = 0;
double rightNorm = 0;
for (int i = 0; i < leftVector.length; i++) {
dotProduct += leftVector[i] * rightVector[i];
leftNorm += leftVector[i] * leftVector[i];
rightNorm += rightVector[i] * rightVector[i];
}
double result = dotProduct
/ (Math.sqrt(leftNorm) * Math.sqrt(rightNorm));
return result;
}
public static void main(String[] args) {
String left[] = { "Julie", "loves", "me", "more", "than", "Linda",
"loves", "me" };
String right[] = { "Jane", "likes", "me", "more", "than", "Julie",
"loves", "me" };
System.out.println(consineTextSimilarity(left,right));
}
}
Simple code JAVA pour calculer la similarité cosinus
/**
* Method to calculate cosine similarity of vectors
* 1 - exactly similar (angle between them is 0)
* 0 - orthogonal vectors (angle between them is 90)
* @param vector1 - vector in the form [a1, a2, a3, ..... an]
* @param vector2 - vector in the form [b1, b2, b3, ..... bn]
* @return - the cosine similarity of vectors (ranges from 0 to 1)
*/
private double cosineSimilarity(List<Double> vector1, List<Double> vector2) {
double dotProduct = 0.0;
double normA = 0.0;
double normB = 0.0;
for (int i = 0; i < vector1.size(); i++) {
dotProduct += vector1.get(i) * vector2.get(i);
normA += Math.pow(vector1.get(i), 2);
normB += Math.pow(vector2.get(i), 2);
}
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}
deux vecteurs A et B existent dans un espace 2D ou 3D, l'angle entre ces vecteurs est cos similitude.
si l'angle est plus grand (peut atteindre 180 degrés maximum) qui est Cos 180=-1 et l'angle minimum est 0 degré. cos 0 =1 implique que les vecteurs sont alignés les uns par rapport aux autres et donc que les vecteurs sont similaires.
cos 90=0 (ce qui est suffisant pour conclure que les vecteurs A et B ne sont pas similaires du tout et puisque la distance ne peut pas être négative, la cosinus valeurs mensonge de 0 à 1. Par conséquent, plus d'angle implique une réduction de la similarité (visualiser aussi cela a du sens)