Skip to content

Proyecto: Recomendador de Películas

En este proyecto daremos un paso más allá en el análisis de grafos y datos relacionales. No solo buscaremos conexiones directas, sino que calcularemos similitudes matemáticas entre elementos basándonos en el comportamiento de los usuarios.

Crearás un sistema de recomendación de películas utilizando una técnica conocida como Filtrado Colaborativo Basado en Ítems (Item-Based Collaborative Filtering).

Al finalizar esta práctica, serás capaz de:

  • Realizar Self-Joins (auto-cruces) en DataFrames para encontrar pares de elementos.
  • Aplicar funciones de agregación matemática avanzada.
  • Entender y aplicar la métrica de Similitud del Coseno (Cosine Similarity).
  • Optimizar cálculos distribuidos filtrando datos redundantes.

La idea base es sencilla: “A las personas que les gustó la película X, también les gustó la película Y”.

No necesitamos saber de qué trata la película (género, actores, año). Solo nos importa el patrón de votación de los usuarios.

graph LR
User1((Usuario 1)) -- Le gusta --> MovieA[Star Wars]
User1 -- Le gusta --> MovieB[Empire Strikes Back]
User2((Usuario 2)) -- Le gusta --> MovieA
User2 -- Le gusta --> MovieB
style MovieA fill:#bbf,stroke:#333
style MovieB fill:#bbf,stroke:#333
linkStyle 0,1,2,3 stroke-width:2px,fill:none,stroke:green;

Si muchos usuarios votan positivamente ambas películas, decimos que tienen una alta similitud.

Trabajaremos con un dataset estándar de la industria (similar a MovieLens).

  1. u.data: Calificaciones de usuarios.

    • Formato: UserID, MovieID, Rating, Timestamp
    • Ejemplo: 196 242 3 881250949
  2. u.item: Información de las películas.

    • Formato: MovieID, Title, ...
    • Ejemplo: 242|Kolya (1996)|...

Tu objetivo es encontrar, para cada película, cuáles son sus “gemelas” más cercanas basándote en las puntuaciones de los usuarios.

Carga los datos y asegúrate de tener un DataFrame (o RDD) con la estructura: userID, movieID, rating

Necesitamos encontrar todos los pares de películas que han sido vistas por el mismo usuario. Para esto, hacemos un join de la tabla de calificaciones consigo misma, usando el userID como clave.

  • Tabla A: User1 -> MovieA
  • Tabla B: User1 -> MovieB
  • Join (A+B): User1 -> (MovieA, MovieB)

⚠️ Importante: Esto generará muchas filas duplicadas (A-B y B-A) y pares de la misma película (A-A).

Para evitar cálculos innecesarios, filtra los resultados del join para mantener solo los pares donde MovieID_A < MovieID_B.

  • Esto elimina duplicados espejados (A,B es lo mismo que B,A).
  • Esto elimina auto-referencias (A,A).

Para cada par de películas (MovieA, MovieB), calcularemos su Similitud del Coseno.

La fórmula adaptada para Spark es:

$$ Similitud(A, B) = \frac{\sum (Rating_A \times Rating_B)}{\sqrt{\sum Rating_A^2} \times \sqrt{\sum Rating_B^2}} $$

O en términos computacionales, para cada par necesitamos acumular:

  1. XX: La suma de los cuadrados de los ratings de la película A.
  2. YY: La suma de los cuadrados de los ratings de la película B.
  3. XY: La suma del producto de ambos ratings (RatingA * RatingB).

Ordena los resultados por el valor de similitud (de mayor a menor) y muestra los 10 pares de películas más similares.

Reto: Cruza los IDs resultantes con u.item para mostrar los Títulos reales en lugar de números. “A quienes les gustó Star Wars, también les gustó Return of the Jedi”.


CriterioPuntos
Lógica de JoinRealiza correctamente el self-join por usuario para obtener pares de películas.
Métrica de SimilitudImplementa correctamente el cálculo matemático (ya sea Coseno o Correlación).
OptimizaciónFiltra duplicados (id1 < id2) antes de agrupar para reducir la carga.
PresentaciónMuestra los títulos de las películas en el resultado final, no solo IDs.
  • ¿Mi código maneja el caso de que un usuario haya visto solo una película? (El join lo eliminaría, lo cual es correcto).
  • ¿He filtrado los pares A-A?
  • ¿Los resultados tienen sentido? (ej. Las películas de una misma saga deberían salir juntas).
  • He incluido capturas o logs de la ejecución en mi entrega.