Breve introducción a los Sistemas de Recomendación

amazon
netflix

En este pequeño tutorial, vamos a hablar sobre Sistemas de Recomendación.
Es posible que no sepas que son, sin embargo interactúas constantemente con ellos en Internet.
Cada vez que Amazon te sugiere productos relacionados…
O cuando Netflix o Youtube te recomiendan contenido que te puede interesar…
La finalidad de un sistema de recommendación es predecir la valoración que un usuario va a hacer de un ítem que todavía no ha evaluado.
Esta valoración se genera al analizar una de dos cosas, o las características de cada item, o las valoraciones de cada usuario a cada item, y se usa para recomendar contenido personalizado a los usuarios.
Hay dos tipos principales de sistemas de recomendación:

  • Filtrado de Contenido. Las recomendaciones están basadas en las características de cada item.
  • Filtrado Colaborativo. Las recomendaciones están basadas en las valoraciones existentes de los usuarios.

En este tutorial vamos a trabajar con el dataset de MovieLens. Este dataset contiene valoraciones de películas sacadas de la página web MovieLens (https://movielens.org/).
El dataset consiste en múltiples archivos, pero los que vamos a usar en este artículo son movies.dat y ratings.dat.
Primero nos descargamos el dataset:

Filtrado de Contenido

Aquí están las primeras líneas del archivo movies.dat. El archivo tiene el formato:
movie_id::movie_title::movie genre(s)

Los géneros de cada película están separados por un pipe |.
Cargamos el archivo movies.dat:

Out[]:

 movie_idmovie_titlemovie_genre
01Toy Story (1995)Animation|Children’s|Comedy
12Jumanji (1995)Adventure|Children’s|Fantasy
23Grumpier Old Men (1995)Comedy|Romance
34Waiting to Exhale (1995)Comedy|Drama

Para poder usar la columna movie_genre, tenemos que convertirla en un grupo de campos llamados dummy_variables.
Esta función convierte una variable categórica (por ejemplo, el genéro de la película puede ser Animation, Comedy, Romance…), en múltiples columnas (una columna para Animation, una columna para Comedy, etc).
Para cada película, éstas columnas dummy tendrán un valor de 0 excepto para aquellos géneros que tenga la película.

Out[]:

 movie_idmovie_titlemovie_genreActionAdventureAnimationChildren’sComedyCrimeDocumentary
01Toy Story (1995)Animation|Children’s|Comedy0011100
12Jumanji (1995)Adventure|Children’s|Fantasy0101000
23Grumpier Old Men (1995)Comedy|Romance0000100
34Waiting to Exhale (1995)Comedy|Drama0000100
45Father of the Bride Part II (1995)Comedy0000100

Por ejemplo, la película con una id de 1, Toy Story, pertenece a los géneros Animation, Children’s y Comedy, y por lo tanto las columnas Animation, Children’s y Comedy tienen un valor de 1 para Toy Story.

Out[]:

El filtrado de contenidos es una manera bastante simple de construir un sistema de recomendación. En este método, los items (en éste ejemplo las películas), se asocian a un grupo de características (en este caso los géneros cinematográficos).
Para recomendar items a un usuario, primero dicho usuario tiene que especificar sus preferencias en cuanto a las características.
En el ejemplo de Movielens, el usuario tiene que especificar qué generos le gustan y cuánto le gustan.
Por el momento tenemos todas las columnas categorizadas por géneros.
Vamos a crear un usuario de ejemplo, con unos gustos cinematográficos enfocados a películas de acción, aventura y ficción:

Ahora que tenemos las preferencias del usuario, para calcular la puntuación que dicho usuario daría a cada película sólo tenemos que hacer el producto vectorial de las preferencias del usuario con las características de cada película.

Ahora podemos computar la puntuación de la película Toy Story, una película de animación infantil, para el usuario del ejemplo.

Out[]:

Para este usuario, Toy Story tiene una puntuación de 5. Lo cual no significa mucho por sí mismo, sólo si comparamos dicha puntuación con la puntuación de las otras películas.
Por ejemplo,, calculamos la puntuación de Die Hard (La Jungla de Cristal), una película de acción.

 movie_idmovie_titlemovie_genreActionAdventureAnimationChildren’sComedyCrimeDocumentary
163165Die Hard: With a Vengeance (1995)Action|Thriller1000000
10231036Die Hard (1988)Action|Thriller1000000
13491370Die Hard 2 (1990)Action|Thriller1000000

Out[]:

 1023
Action1
Adventure0
Animation0
Children’s0
Comedy0
Crime0
Documentary0
Drama0
Fantasy0
Film-Noir0
Horror0
Musical0
Mystery0
Romance0
Sci-Fi0
Thriller1
War0
Western0
  • Nota, 1023 es el índice interno del dataframe, no el índice de la película Die Hard en Movielens*

Vemos que Die Hard tiene una puntuación de 8 y Toy Story de 5, asi que Die Hard sería recomendada al usuario antes que Toy Story. Lo cual tiene sentido teniendo en cuenta que a nuestro usuario de ejemplo le encantan las películas de acción.
Una vez sabemos como calcular la puntuación para una película, recomendar nuevas películas es tan fácil como calcular las puntuaciones de cada película, y luego escoger aquellas con una puntuación más alta.

Asi que vemos que el sistema de recomendación recomienda películas de acción y de ciencia ficción.
El filtrado de contenidos hace que recomendar nuevas películas a un usuario sea muy fácil, ya que los usuarios simplemente tienen que indicar sus preferencias una vez. Sin embargo, este sistema tiene algunos problemas:

  • Hay que categorizar cada item nuevo manualmente en funcion a las características existentes.
  • Las recomendaciones son limitadas, ya que por ejemplo, los items existentes no se pueden clasificar en función de una nueva categoría.

Hemos visto que el filtrado de contenidos es quizás una manera demasiado simple de hacer recomendaciones, lo que nos lleva a…

Filtrado Colaborativo

El filtrado colaborativo es otro método distinto de predecir puntuaciones de usuarios a items. Sin embrago, en este método usamos las puntuaciones existentes de usuarios a items para predecir los items que no han sido valorados por el usuario al que queremos recomendar.
Para ello asumimos que las recomendaciones que le hagamos a un usuario serán mejores si las basamos en usuarios con gustos similares.
Para este ejemplo usaremos el archivo ratings.dat, que tiene el siguiente formato:
user_id::movie_id::rating::timestamp

El dataset de Movielens contiene un archivo con más de un millón de valoraciones de películas hechas por usuarios.

Out[]:

 user_idmovie_titlemovie_idrating
01One Flew Over the Cuckoo’s Nest (1975)11935
12One Flew Over the Cuckoo’s Nest (1975)11935
212One Flew Over the Cuckoo’s Nest (1975)11934
315One Flew Over the Cuckoo’s Nest (1975)11934
417One Flew Over the Cuckoo’s Nest (1975)11935

De momento tenemos una matriz de usuarios y películas, vamos a convertir ratings_df a una matriz con un usuario por fila y una película por columna.

Out[]:

movie_title$1,000,000 Duck (1971)‘Night Mother (1986)‘Til There Was You (1997)
user_id    
1000
2000
3050
4001
5000

Nos queda una matriz de 6064 usuarios y 3706 películas.
Para computar la similaridad entre películas, una manera de hacerlo es calcular la correlación entre ellas en función de la puntuación que dan los usuarios.
Una manera fácil de calcular la similaridad en python es usando la función numpy.corrcoef, que calcula el coeficiente de correlación de Pearson(PMCC)](https://es.wikipedia.org/wiki/Coeficiente_de_correlaci%C3%B3n_de_Pearson) entre cada pareja de items.
El PMCC tiene un valor entre -1 y 1 que mide cuán relacionadas están un par de variables cuantitativas.
La matriz de correlación es una matriz de tamaño m x m, donde el elemento Mij representa la correlación entre el item i y el item j.

Out[]:

*Nota: Usamos la matriz traspuesta de ratings_mtx_df para que la función np.corrcoef nos devuelva la correlación entre películas. En caso de no hacerlo nos devolvería la correlación entre usuarios.
Una vez tenemos la matriz, si queremos encontrar películas similares a una concreta, solo tenemos que encontrar las películas con una correlación alta con ésta.

Out[]:

Vemos que los resultados son bastante buenos.
Ahora, si queremos recomendar películas a un usuario, solo tenemos que conseguir la lista de películas que dicho usuario ha visto. Ahora, con dicha lista, podemos sumar las correlaciones de dichas películas con todas las demás y devolver las películas con una mayor correlación total.

Por ejemplo, vamos a seleccionar un usuario con preferencia por las películas infantiles y algunas películas de acción.

Out[]:

 user_idmovie_titlemovie_idrating
58330421Titan A.E. (2000)37455
70730721Princess Mononoke, The (Mononoke Hime) (1997)30005
7074221Star Wars: Episode VI – Return of the Jedi (1983)12105
23964421South Park: Bigger, Longer and Uncut (1999)27005
48753021Mad Max Beyond Thunderdome (1985)37044
70765221Little Nemo: Adventures in Slumberland (1992)28004
70801521Stop! Or My Mom Will Shoot (1992)32683
70688921Brady Bunch Movie, The (1995)5853
62394721Iron Giant, The (1999)27613
61978421Wild Wild West (1999)27013
421121Bug’s Life, A (1998)23553
36805621Akira (1988)12743
22612621Who Framed Roger Rabbit? (1988)29873
4163321Toy Story (1995)13
3497821Aladdin (1992)5883
3343221Antz (1998)22943
1891721Bambi (1942)20181
61221521Devil’s Advocate, The (1997)16451
61765621Prince of Egypt, The (1998)23941
44098321Pinocchio (1940)5961
70767421Messenger: The Story of Joan of Arc, The (1999)30531
70819421House Party 2 (1991)37741

Ahora podemos proporcionar nuevas recomendaciones para dicho usuario teniendo en cuenta las películas que ha visto como input.

Out[]:

Vemos que el sistema recomienda mayoritariamente películas infantiles y algunas películas de acción.
El ejemplo que he puesto sobre filtrado colaborativo es un ejemplo muy simple, y no tiene en cuenta las valoraciones que cada usuario ha hecho a cada película (solo si las ha visto).
Una manera más eficaz de hacer filtrado colaborativo es vía Descomposición en valores singulares (SVD). Es un tópico que da para otro artículo pero este artículo lo explica con bastante claridad.
El filtrado colaborativo se usa con frecuencia en la actualidad. Es capaz de recomendar nuevos items sin tener que clasificarlos manualmente en función de sus características. Además, es capaz de proporcionar recomendaciones basadas en características ocultas que no serían obvias a primera vista (por ejemplo, combinaciones de géneros o de actores).
Sin embargo, el filtrado colaborativo tiene un problema importante, y es que no puede recomendar items a un usuario a menos que dicho usuario haya valorado items, este problema se llama problema de Arranque en frío.
Una manera de solucionar ésto es usar un sistema híbrido de filtrado de contenido + filtrado colaborativo, usando el filtrado de contenidos para nuevos usuarios y filtrado colaborativo para usuarios de los que se tiene suficiente información.

Lista de lecturas

Aquí hay una lista de lecturas sobre sisetmas de recomendación (en inglés)

2 pensamientos sobre “Breve introducción a los Sistemas de Recomendación”

  1. Pingback: Una breve introducción a los Sistemas de Recomendación

  2. Muy chulo, se ve bien como usar pandas.
    nota: donde dices producto vectorial, realmente no es producto vectorial, es producto escalar, producto punto (dot_product) o producto interno. El producto vectorial te devolvería un vector.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

79 − seventy five =