Ashay Pathak, Chatana Mandava, Ritesh Patel
El filtrado colaborativo es una técnica muy utilizada en los sistemas de recomendación y es un área de investigación que avanza rápidamente. Los dos métodos más utilizados son los basados en memoria y los basados en modelos.
En este post, sólo nos centraremos en (User-Based Collaborative Filtering) UB-CF que es un método basado en memoria. La idea principal detrás de UB-CF es que las personas con características similares comparten gustos similares. Por ejemplo, si estamos interesados en recomendar una película a nuestro amigo Bob, supongamos que Bob y yo hemos visto muchas películas juntos y las calificamos de forma casi idéntica. Tiene sentido pensar que en el futuro también nos seguirán gustando películas similares y utilizar esta métrica de similitud para recomendar películas.
Intentemos implementar UB-CF y generar una lista de películas que nuestro amigo Bob a.k.a usuario activo podría estar interesado en ver. La motivación para escribir este post es profundizar en el algoritmo y entender cómo funciona realmente UB-CF. La mayor parte del contenido de este post está inspirado en un Curso en Coursera.
Filtrado Colaborativo Usuario-Usuario
El método identifica a los usuarios que son similares al usuario consultado y estima que la calificación deseada es la media ponderada de las calificaciones de estos usuarios similares.
Estaremos haciendo las recomendaciones sobre el conjunto de datos MovieLens. El lenguaje de programación utilizado es python y el trabajo de análisis de datos se realiza principalmente utilizando la biblioteca pandas. IDE utilizado es jupyter notebook.
Así que antes de empezar me gustaría dar la lista de bibliotecas utilizadas :
- Pandas
- Numpy
- sklearn
Así que vamos a avanzar y entender los conceptos detrás de las recomendaciones. He adjuntado algunos fragmentos de código y salidas en el blog para una mejor comprensión. El archivo ipynb completo se adjunta al final del blog.
Función de puntuación
Es fácil idear una función para el filtrado colaborativo no personalizado (es decir, no tenemos en cuenta los gustos, disgustos y valoraciones del usuario activo en el pasado) que devuelva una puntuación tomando como parámetros de entrada el usuario u y el artículo i. La función devuelve una puntuación que cuantifica la intensidad con la que al usuario u le gusta/prefiere el artículo i.
Por lo tanto, esto se suele hacer utilizando las valoraciones de otras personas similares al usuario. Todo esto se discutiría en detalle más adelante. Por ahora la fórmula que he utilizado es,
Donde ‘s’ es la puntuación predicha, ‘u’ es el usuario, ‘i’ es el ítem, ‘r’ es la calificación dada por el usuario y ‘w’ es el peso.
En este caso nuestra puntuación es igual a la suma de las valoraciones que cada usuario dio a ese ítem restando la valoración media de ese usuario multiplicada por algún peso que es de lo mucho que este usuario es similar o se supone que contribuye a las predicciones de otro usuario. Este es el peso entre el usuario u y v. La puntuación oscila entre 0 y 1, donde 0 es bajo y 1 es alto. Todo parece perfecto, entonces ¿por qué restamos las valoraciones medias de cada usuario y por qué utilizamos la media ponderada en lugar de la media simple?
El problema está en los tipos de usuarios que estamos manejando. Comienza con el hecho de que la gente califica a menudo en escalas muy diferentes. Yo puedo ser un usuario positivo y optimista que valore la película que me ha gustado con un 4 sobre 5, pero otro usuario menos optimista o con un nivel de exigencia muy alto puede valorar su película favorita con un 2 sobre 5. Aquí su 2 es mi 4. En este caso, su 2 es mi 4. Para mejorarlo, podemos aumentar la eficacia de este algoritmo si normalizamos la puntuación del usuario. Una forma de hacerlo es decir que vamos a calcular s(u,i), es decir, la puntuación como la calificación media que el usuario da a cada elemento más una desviación y la desviación va a ser lo mucho que este elemento es mejor o peor que la media.
He utilizado la similitud coseno para calcular el peso dado en la fórmula anterior. También he utilizado la noción de vecindad que se discutiría en este blog a medida que avanzamos.
Para normalizar los datos de la manera anterior, se requiere algún análisis de datos en pandas. Usted puede obtener el código completo al final. Para el blog, me centraré en los conceptos importantes.
import pandas as pdmovies = pd.read_csv("movies.csv",encoding="Latin1")
Ratings = pd.read_csv("ratings.csv")
Tags = pd.read_csv("tags.csv",encoding="Latin1")Mean = Ratings.groupby(by="userId",as_index=False).mean()
Rating_avg = pd.merge(Ratings,Mean,on='userId')
Rating_avg=Rating_avg-Rating_avg
Rating_avg.head()