2010-06-25 15 views
10

I'm trying to use TF-IDF para clasificar documentos en categorías. He calculado el tf_idf para algunos documentos, pero ahora cuando intento para calcular el coseno similitud entre dos de estos documentos que recibo un dicho rastreo:Coseno ¿Similitud de vectores de diferentes longitudes?

#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á rebanando el vector de modo que len (u) == len (v) el enfoque correcto? Yo pensaría que la similitud del coseno funcionaría con vectores de diferentes longitudes.

estoy usando 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))) 

También - es el orden de los valores tf_idf en los vectores importantes? ¿Deberían ordenarse, o no tiene importancia para este cálculo?

Respuesta

5

¿Está calculando la similitud del coseno de los vectores de términos? Los vectores de término deben tener la misma longitud. Si las palabras no están presentes en un documento, entonces debe tener un valor de 0 para ese término.

No estoy seguro exactamente de qué vectores está aplicando la similitud del coseno, pero al hacer la similitud del coseno, entonces sus vectores siempre deben tener la misma longitud y el orden importa mucho.

Ejemplo:

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

Aquí tienes dos vectores (.3,0,1) y (.7,8,1) y se puede calcular la similitud de coseno entre ellos. Si comparas (.3,1) y (.7,8) estarías comparando el puntaje de Doc1 de Baz con el puntaje de Bar de Doc2 que no tendría sentido.

+0

Los vectores que estoy pasando a la función cosine_distance son listas de Python de los valores tf_idf. v [5] == [,0060830126968545294, ,00048241996565891193, ,0020712248617478965, ,0110036199241575, ,0110036199241575] Usted dice que el orden importa - ¿cuál es la forma correcta de ordenar el contenido del vector (smallest-> grande, orden de palabras en el documento?) – erikcw

+0

Tiene que asignar un orden global a las palabras. Si la barra aparece antes de foo en doc2, entonces el valor tf_idf de la barra debe seguir siendo el primer elemento. – Pace

9

Es necesario multiplicar las entradas de las palabras correspondientes en el vector, por lo que debe haber un orden global para las palabras. Esto significa que, en teoría, tus vectores deberían tener la misma longitud.

En la práctica, si un documento se veía antes que el otro, las palabras en el segundo documento pueden haberse agregado al orden global después de verse el primer documento, por lo que aunque los vectores tengan el mismo orden, el primer documento puede ser más corto, ya que no tiene entradas para las palabras que no estaban en ese vector.

Documento 1: El zorro marrón rápido saltó sobre el perro perezoso.

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

Documento 2: El corredor fue rápido.

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 

En este caso, en teoría, debe rellenar el vector Documento 1 con ceros en el extremo. En la práctica, al calcular el producto escalar, solo necesita multiplicar elementos hasta el final del Vector 1 (ya que omitir los elementos adicionales del vector 2 y multiplicarlos por cero es exactamente igual, pero visitar los elementos extra es más lento).

Luego puede calcular la magnitud de cada vector por separado, y para eso los vectores no necesitan ser de la misma longitud.

+0

Al calcular la similitud de coseno, los ceros rellenos marcan la diferencia. La función que estoy usando para la similitud del coseno es: cosiness-similarity = dot-product (u, v)/sqrt (dot-product (u, u)) * sqrt (dot-product (v, v)) similitud de coseno ([1, 1, 1, 1, 1, 1, 1, 1, 0, 0,], [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1]) == 0.3333333333333333 coseno-similitud ([1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0 ]) == 0.4714045207910316 Parece que el problema es que el divisor de similitud de coseno realiza un producto de punto de sí mismo. Entonces el relleno tiene un efecto. ¿Sabes de todos modos alrededor de esto? – erikcw

+0

@erikcw: Cuando calcules los productos de puntos para 'Doc1 * Doc1', entonces necesitas ir a la longitud completa de' Doc1' pero no más. Para 'Doc2 * Doc2', entonces necesita ir a la longitud completa de' Doc2' pero no más. Para esa parte del producto escalar, no trunque el vector más largo, pero no es necesario rellenar el vector más corto. Sin embargo, al calcular 'Doc1 * Doc2', puede truncar con seguridad el vector más largo. Por lo tanto, su código debe diseñarse para que la función 'dot-product' tome decisiones sobre el relleno/truncamiento, en lugar de hacer que la función' cosine-similarity' tome esas decisiones. –

+0

@larsmans: las longitudes no coincidentes de los vectores en la segunda figura son intencionales. –

2

Intenta construir los vectores antes de alimentar a la función 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)) 
Cuestiones relacionadas