2010-06-25 27 views
10

I'm trying to use TF-IDF pour trier les documents en catégories. J'ai calculé le tf_idf pour certains documents, mais maintenant quand j'essaie de calculer la similarité Cosinus entre deux de ces documents que je reçois un retraçage dit:Cosinus Similarité des vecteurs de différentes longueurs?

#len(u)==201, len(v)==246 

cosine_distance(u, v) 
ValueError: objects are not aligned 

#this works though: 
cosine_distance(u[:200], v[:200]) 
>> 0.52230249969265641 

est-tranchage le vecteur de telle sorte que len (u) == len (v) la bonne approche? Je penserais que la similarité de cosinus fonctionnerait avec des vecteurs de différentes longueurs.

J'utilise this function:

def cosine_distance(u, v): 
    """ 
    Returns the cosine of the angle between vectors v and u. This is equal to 
    u.v/|u||v|. 
    """ 
    return numpy.dot(u, v)/(math.sqrt(numpy.dot(u, u)) * math.sqrt(numpy.dot(v, v))) 

également - est l'ordre des valeurs tf_idf dans les vecteurs importants? Devraient-ils être triés - ou cela n'a-t-il pas d'importance pour ce calcul?

Répondre

5

Calculez-vous la similitude cosinus des vecteurs de terme? Les vecteurs de terme doivent avoir la même longueur. Si les mots ne sont pas présents dans un document alors il devrait avoir une valeur de 0 pour ce terme. Je ne suis pas exactement sûr de ce que les vecteurs que vous appliquez la similitude de cosinus mais en faisant la similitude de cosinus alors vos vecteurs devraient toujours avoir la même longueur et l'ordre importe beaucoup.

Exemple:

Term | Doc1 | Doc2 
Foo  .3  .7 
Bar | 0 | 8 
Baz | 1 | 1 

Ici vous avez deux vecteurs (.3,0,1) et (.7,8,1) et peut calculer la similarité cosinus entre eux. Si vous comparez (.3,1) et (.7,8), vous comparerez le score Doc1 de Baz au score Doc2 de Bar, ce qui n'aurait aucun sens.

+0

Les vecteurs que je passe à la fonction cosine_distance sont des listes Python des valeurs tf_idf. v [5] == [,0060830126968545294, 0,00048241996565891193, ,0020712248617478965, ,0110036199241575, ,0110036199241575] Vous dites que les questions d'ordre - quelle est la bonne façon de trier le contenu du vecteur (smallest-> plus grand, de l'ordre de mots dans le document?) – erikcw

+0

Vous devez affecter un ordre global aux mots. Si la barre apparaît avant foo dans doc2 alors la valeur tf_idf de la barre devrait toujours être le premier élément. – Pace

9

Vous devez multiplier les entrées pour les mots correspondants dans le vecteur, donc il devrait y avoir un ordre global pour les mots. Cela signifie qu'en théorie vos vecteurs doivent avoir la même longueur. En pratique, si un document a été vu avant l'autre, les mots du second document peuvent avoir été ajoutés à l'ordre global après la visualisation du premier document, donc même si les vecteurs ont le même ordre, le premier document peut être plus court, car il n'a pas d'entrées pour les mots qui n'étaient pas dans ce vecteur.

Document 1: Le renard brun rapide a sauté par-dessus le chien paresseux.

Global order:  The quick brown fox jumped over the lazy dog 
Vector for Doc 1: 1 1  1 1  1  1 1 1 1 

Document 2: Le coureur a été rapide.

Global order:  The quick brown fox jumped over the lazy dog runner was 
Vector for Doc 1: 1 1  1 1  1  1 1 1 1 
Vector for Doc 2: 1 1  0 0  0  0 0 0 0 1  1 

Dans ce cas, en théorie, vous devez pad le vecteur document 1 avec des zéros sur la fin. En pratique, lors du calcul du produit scalaire, il suffit de multiplier les éléments jusqu'à la fin du vecteur 1 (puisque omettre les éléments supplémentaires du vecteur 2 et les multiplier par zéro sont exactement les mêmes, mais visiter les éléments supplémentaires est plus lent).

Ensuite, vous pouvez calculer l'amplitude de chaque vecteur séparément, et pour cela les vecteurs n'ont pas besoin d'être de la même longueur.

+0

Lors du calcul de la similarité cosinus, les zéros remplis font une différence. La fonction que j'utilise pour la similarité de cosinus est: cosinus-similitude = produit scalaire (u, v)/sqrt (produit scalaire (u, u)) * sqrt (produit scalaire (v, v)) cosinus-similitude ([1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,], [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1]) == 0.3333333333333333 similitude de cosinus ([1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0 ]) == 0.4714045207910316 On dirait que le problème est que le diviseur de la similitude cosinus effectue un produit scalaire de lui-même. Donc, le rembourrage a un effet. Savez-vous de toute façon autour de cela? – erikcw

+0

@erikcw: Lorsque vous calculez les produits de points pour 'Doc1 * Doc1', vous devez aller sur toute la longueur de' Doc1' mais pas plus loin. Pour 'Doc2 * Doc2', vous devez aller sur toute la longueur de' Doc2' mais pas plus loin. Pour cette partie du produit scalaire, ne tronquez pas le vecteur le plus long, mais il n'est pas nécessaire de remplir le vecteur le plus court. Cependant, lors du calcul de Doc1 * Doc2, vous pouvez tronquer en toute sécurité le vecteur le plus long. Votre code doit donc être conçu pour que la fonction 'dot-product' prenne des décisions sur le remplissage/la troncature, plutôt que d'avoir la fonction' cosine-similarity' pour prendre ces décisions. –

+0

@larsmans: Les longueurs non concordantes des vecteurs de la deuxième figure sont intentionnelles. –

2

Essayez de construire les vecteurs avant de les nourrir à la fonction cosine_distance:

import math 
from collections import Counter 
from nltk import cluster 

def buildVector(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 


l1 = "Julie loves me more than Linda loves me".split() 
l2 = "Jane likes me more than Julie loves me or".split() 


v1,v2= buildVector(l1, l2) 
print(cluster.util.cosine_distance(v1,v2))