¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Ordenar documentos con la similitud del coseno

Después de esta lección: Puedo ordenar documentos por el coseno del ángulo entre su vector y el de la consulta.

Lección de 60 min1 comandoLaboratorio JupyterLab de ciencia de datos: pandas, Matplotlib y scikit-learn en el navegador

Una consulta es un documento más corto

El modelo de espacio vectorial representa cada documento y cada consulta como una fila de números. Después ordena los documentos por lo parecida que es su fila a la de la consulta.

Con él, un buscador puede poner primero un texto que no contiene todas tus palabras pero que se parece mucho a lo que escribiste.

Al final de esta lección

Nota

Puedo ordenar documentos por el coseno del ángulo entre su vector y el de la consulta.

Palabras clave

PalabraQué significa
Vectoruna fila de números, uno por cada palabra del vocabulario
Vocabulariolas palabras que cuentan para comparar
Producto escalarla suma de multiplicar dos vectores posición a posición
Longitudla raíz de la suma de los cuadrados de un vector
Similitud del cosenoel producto escalar dividido entre las dos longitudes

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Cada texto se convierte en un vector

Se elige un vocabulario, por ejemplo cuatro palabras: biblioteca, facultad, marzo y plazo. Después se cuenta cuántas veces sale cada una en cada texto.

La fila de recuentos es el vector del texto. La consulta «plazo marzo» también es un texto, así que también tiene su vector, del mismo tamaño que los de los documentos.

Ejemplo resuelto: los vectores de los avisos

Textobibliotecafacultadmarzoplazo
consulta: plazo marzo0011
aviso 3: la beca de comedor tiene plazo en marzo0011
aviso 4: la biblioteca cierra tarde en marzo1010
aviso 6: plazo de pago en la facultad en marzo0111
aviso 5: bicicletas gratis en la facultad0100

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Convierte un texto en un vector

Código: python
# Cada aviso se convierte en una fila de cuatro recuentos.
vocab = ["biblioteca", "facultad", "marzo", "plazo"]

def make_vector(tokens):
    vector = []
    for word in vocab:
        vector.append(tokens.count(word))
    return vector

print(make_vector("plazo marzo".split()))
print(make_vector("plazo de pago en la facultad en marzo".split()))
# Cambia la consulta por "biblioteca" y ejecuta.

El coseno mide el ángulo entre dos vectores

El producto escalar multiplica dos vectores posición a posición y suma. Toma la consulta [0, 0, 1, 1] y el aviso 6, que es [0, 1, 1, 1]. La cuenta es 0, más 0, más 1, más 1: un total de 2.

La longitud de un vector es la raíz de la suma de sus cuadrados. La similitud del coseno es el producto escalar dividido entre las dos longitudes. Va de 0, sin palabras en común, a 1, la misma dirección.

Ejemplo resuelto: el coseno de cada aviso

AvisoProducto escalarLongitudesCoseno
32raíz de 2 por raíz de 2 = 21,0
62raíz de 2 por raíz de 3 = 2,4490,82
41raíz de 2 por raíz de 2 = 20,5
1, 2 y 50no se necesita0

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Calcula el coseno del aviso 6

Comando
docker exec jupyter python3 -c "print(round(2/((2**0.5)*(3**0.5)),2))"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

El orden de los resultados sale del coseno

Para ordenar, se calcula el coseno entre la consulta y cada documento. El de coseno más alto va primero. Los que valen 0 no comparten nada con la consulta y no se muestran.

Si dos empatan, hace falta una regla fija. Aquí gana el de número menor. Un truco simple: se guardan pares (menos el coseno, número) y se ordena la lista de pares.

Ordena los avisos para «plazo marzo»

Código: python
# Ordena los avisos por el coseno con la consulta "plazo marzo".
vectores = {
    1: [1, 0, 0, 0],
    2: [0, 1, 0, 0],
    3: [0, 0, 1, 1],
    4: [1, 0, 1, 0],
    5: [0, 1, 0, 0],
    6: [0, 1, 1, 1],
}
consulta = [0, 0, 1, 1]
def cosine(a, b):
    dot = 0
    la = 0
    lb = 0
    for n in range(len(a)):
        dot = dot + a[n] * b[n]
        la = la + a[n] * a[n]
        lb = lb + b[n] * b[n]
    if la == 0 or lb == 0:
        return 0.0
    return dot / ((la ** 0.5) * (lb ** 0.5))
pares = []
for numero in vectores:
    c = cosine(consulta, vectores[numero])
    pares.append((-round(c, 2), numero))
pares.sort()
for par in pares:
    print(par[1], -par[0])
# Cambia la consulta por [0, 1, 0, 0], que es "facultad", y mira el empate.

Un error muy común

Advertencia

Mucha gente cree que gana el documento que tiene más palabras de la consulta. El coseno también mira lo demás que dice el texto: uno centrado en el tema puede ganar a otro que habla de más cosas. Por eso el aviso 3 supera al 6, que además habla de la facultad.

Para ir más lejos: usa pesos tf-idf

Los vectores de la lección usan recuentos. Prueba a poner en cada posición el peso tf-idf de la lección anterior.

Calcula otra vez el orden de los seis avisos para «biblioteca marzo». ¿Cambia el orden? Escribe por qué crees que cambia o no.

Sobre este laboratorio y su código: Laboratorio JupyterLab de ciencia de datos: pandas, Matplotlib y scikit-learn en el navegador

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.