viernes, 11 de marzo de 2016

[Spark MLlib] Filtrado Colaborativo (II): Recomendación por Usuario

Continuamos con este breve tutorial o introducción al filtrado colaborativo con Spark. Bien, la semana pasada en la entrada [Spark MLlib] Filtrado Colaborativo (I): Sistema de Recomendación construimos nuestro sistema de recomendación o más bien el generador de modelos. Esta semana tocará hacer uso de él y recomendar productos, en nuestro ejemplo películas, a nuestros usuarios a partir de sus votaciones.

Continuaremos también trabajando con la estructura de directorios y archivos ya definido, lo que vendría a ser nuestro proyecto dentro de nuestra herramienta IDE favorita. Antes de continuar, me gustaría matizar que este tutorial NO está orientado a la programación en scala ni a sus best practices a la hora de desarrollar. Todos los ejemplos son mejorables desde la primera línea. Por ejemplo, algo tan sencillo como recibir los parámetros con los que juego como argumentos de entrada, definir un único método principal, pues voy declarando funciones main por cada funcionalidad o algoritmo que trato de explicar, etc, pero lo dicho, no, no me voy a entretener ni por un instante en escribir el código correctamente, sólo pretendo dar unas pinceladas sobre cómo funcionan ciertos algoritmos o cómo alcanzar una determinada funcionalidad.

1) En esta ocasión creamos el archivo getRecommendationsByUserId.scala dentro de la misma carpeta donde creamos nuestro generador de modelos, es decir, en el directorio Carpeta_Proyecto/src/main/scala/mllib/collaborativeFiltering/

package mllib.collaborativeFiltering

import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.recommendation.{ALS, Rating, MatrixFactorizationModel}
import org.apache.spark.{SparkContext, SparkConf}

object getRecommendationsByUserId {
  def main (args: Array[String]): Unit = {

    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)

    val sparkConfig = new SparkConf().setMaster("local[2]").setAppName("getRecommendationsByUserId")
    val sc = new SparkContext(sparkConfig)

    val mlRatings = sc.textFile("data/movielens/ratings.csv")
    val ratings = mlRatings.map { line =>
      // userId,movieId,rating,timestamp
      val fields = line.split(",")
      Rating(fields(0).toInt, fields(1).toInt, fields(2).toDouble)
    }.cache()

    val mlMovies = sc.textFile("data/movielens/movies.csv")
    val movies = mlMovies.map { line =>
      // movieId,title,genres
      val fields = line.split(",")
      (fields(0).toInt, fields(1))
    }.collect.toMap

    val model = MatrixFactorizationModel.load(sc, "target/tmp/myCollaborativeFilter")    // Recuperando el modelo

    val userId = 25560     // Seleccionamos el usuario id. Interesante pasarlo al script como argumento ;)
    val moviesForUser = ratings.keyBy(_.user).lookup(userId)
    println("El usuario ha votado a " + moviesForUser.size + " peliculas:")
    moviesForUser.sortBy(-_.rating).take(10).map(rating => (movies(rating.product), rating.rating)).foreach(println)    // Observamos que tipo de películas le gustan al usuario

    val topKRecs = model.recommendProducts(userId,10)    // El método para obtener las recomendaciones ya viene implementado de serie en la librería. Obtenemos el top10 de productos, en nuestro caso películas, recomendados. También podríamos pasar el número de recomendaciones, topN  ;) ;)
    topKRecs.map(rating => (movies(rating.product), rating.rating)).foreach(println)

  }
}

2) Ejecutar la aplicación
sbt compile
...
[success] Total time: 1 s, completed 11-mar-2016 10:14:13

sbt run
...
Multiple main classes detected, select one to run:

 [1] mllib.DecisionTrees.classificationFlightsOnTime
 [2] mllib.collaborativeFiltering.getRecommendationsByUserId
 [3] mllib.collaborativeFiltering.recommendation

Enter number: 2
...
El usuario ha votado a 50 peliculas:
Star Wars: Episode IV - A New Hope (1977),5.0)
(Star Wars: Episode V - The Empire Strikes Back (1980),5.0)
("Princess Bride,5.0)
(Star Wars: Episode VI - Return of the Jedi (1983),5.0)
(Life Is Beautiful (La Vita è bella) (1997),5.0)
(X-Men (2000),5.0)
(Unbreakable (2000),5.0)
("Lord of the Rings: The Fellowship of the Ring,5.0)
(Spider-Man (2002),5.0)

("Lord of the Rings: The Two Towers,5.0)
...
("Roman Spring of Mrs. Stone,11.756657663464846)
(Babar The Movie (1989),11.171622844283377)
(Goodbye to Language 3D (2014),9.747998979226367)
(Garfield's Halloween Adventure (1985),9.736430143083723)
(Jimmy Carter Man from Plains (2007),9.72594699681999)
(Dangerous (1935),9.256450056766873)
(Bad Ronald (1974),9.089006045667578)
(End of the Line (2007),9.057430462126002)
(In the City of Sylvia (En la ciudad de Sylvia) (2007),8.963930587070152)
(Nine Dead Gay Guys (2003),8.895781428393946)
...
[success] Total time: 317 s, completed 11-mar-2016 10:41:22

Muy sencillo, ¿verdad?

Entradas relacionadas:

    [Spark MLlib] Filtrado Colaborativo (III): Recomendación por Ítem (pendiente)

6 comentarios:

  1. buenas, estoy esperando, me parece bueno los anteriores, Spark MLlib] Filtrado Colaborativo (III): Recomendación por Ítem

    ResponderEliminar
    Respuestas
    1. Gracias David! Se que ahí lo dejé como pendiente y casi ya puede decirse que olvidado XD. La verdad es que escasea demasiado el tiempo y no puedo dedicarle ni lo mínimo que pretendí inicialmente. Pero bueno, para no dejarlo ahí colgado a ver si pronto lo retomo.

      Eliminar
    2. jaja bueno si puedes hacerlo, por que la verda estoy muy interesado, me gusta lo que eh visto y eh podido hacer asta ahora

      Eliminar
  2. podrías hacer uno para recomendación de amigos? similar al de facebook? estoy interesado y necesito hacer uno, pero soy muy nuevo en esto de big data y apache spark y necesito algo de ayuda

    ResponderEliminar
    Respuestas
    1. Te dejo el siguiente link http://stevekrenzel.com/finding-friends-with-mapreduce en donde hay un ejemplo de cómo encontrar amigos. Con él aprendí el concepto de MapReduce más allá del típico ejemplo de contar palabras. Eso sí, es bastante antiguo y no se apoya en ningún algoritmo, Machine Learning, etc sino más bien en lógica tradicional. Espero que te sirva.

      Eliminar
  3. otra cosa, esto se podría llevar a un ambiente de producción?, y como se aria de manera para aplicar esto pero con Streaming? según he investigado, ha eso se le llama Sistemas de recomendación incrementales, pero no tengo idea aun

    ResponderEliminar