paint-brush
Deja de desplazarte y empieza a crear: crea tu propio recomendador de películas con inteligencia artificialpor@superlinked
Nueva Historia

Deja de desplazarte y empieza a crear: crea tu propio recomendador de películas con inteligencia artificial

por Superlinked11m2025/03/06
Read on Terminal Reader

Demasiado Largo; Para Leer

Aprenda a crear un sistema de recomendaciones personalizado basado en IA que prediga su próxima película favorita con precisión. En este tutorial, lo guiaremos a través del proceso de creación de un sistema de recomendaciones de películas utilizando bases de datos vectoriales. Aprenderá cómo funcionan los motores de recomendaciones de IA modernos y obtendrá experiencia práctica en la creación de su propio sistema con Superlinked.
featured image - Deja de desplazarte y empieza a crear: crea tu propio recomendador de películas con inteligencia artificial
Superlinked HackerNoon profile picture
0-item
1-item

“¡Dije que quería una película clase B, maldita sea!”

El fin del desplazamiento interminable (y de las discusiones sobre qué ver…)

¿Cansado de navegar sin parar por Netflix y sin saber qué ver a continuación? ¿Qué pasaría si pudieras crear tu propio sistema de recomendaciones personalizado, impulsado por IA, que prediga tu próxima película favorita con precisión?


En este tutorial, lo guiaremos a través del proceso de creación de un sistema de recomendación de películas utilizando bases de datos vectoriales (VectorDB) . Aprenderá cómo funcionan los motores de recomendación de IA modernos y obtendrá experiencia práctica en la creación de su propio sistema con Superlinked .


(¿Quieres ir directamente al código? Consulta nuestro repositorio en GitHub aquí . ¿Estás listo para probar los sistemas de recomendación para tu propio caso de uso? Obtén una demostración aquí ).

¡Empecemos a recomendar!

Seguiremos este cuaderno a lo largo del artículo. También puedes ejecutar el código directamente desde tu navegador usando Colab.


El algoritmo de recomendaciones de Netflix hace un buen trabajo al sugerir contenido relevante, dada la gran cantidad de opciones (~16.000 películas y programas de televisión en 2023) y la rapidez con la que tiene que proponer programas a los usuarios. ¿Cómo lo hace Netflix? En una palabra, mediante búsqueda semántica .


La búsqueda semántica comprende el significado y el contexto (tanto los atributos como los patrones de consumo) detrás de las consultas de los usuarios y las descripciones de películas y programas de televisión y, por lo tanto, puede proporcionar una mejor personalización en sus consultas y recomendaciones que los enfoques tradicionales basados en palabras clave.


Sin embargo, la búsqueda semántica plantea ciertos desafíos , entre los que destacan: 1) garantizar resultados de búsqueda precisos, 2) interpretabilidad y 3) escalabilidad, desafíos que cualquier estrategia de recomendación de contenido exitosa deberá abordar. Con la biblioteca de Superlinked, puede superar estas dificultades.


En este artículo, le mostraremos cómo usar la biblioteca Superlinked para configurar su propia búsqueda semántica y generar una lista de películas relevantes según sus preferencias.

Búsqueda semántica: desafíos

La búsqueda semántica aporta mucho valor a la búsqueda vectorial, pero plantea tres desafíos importantes en la integración de vectores para los desarrolladores:

  • Calidad y relevancia : para garantizar que sus incorporaciones capturen con precisión el significado semántico de sus datos, es necesario seleccionar cuidadosamente las técnicas de incorporación, los datos de entrenamiento y los hiperparámetros. Las incorporaciones de mala calidad pueden generar resultados de búsqueda inexactos y recomendaciones irrelevantes.


  • Interpretabilidad : los espacios vectoriales de alta dimensión son demasiado complicados para comprenderlos fácilmente. Para comprender mejor las relaciones y similitudes que contienen, los científicos de datos deben desarrollar métodos para visualizarlos y analizarlos.


  • Escalabilidad : la gestión y el procesamiento de incrustaciones de alta dimensión, especialmente en grandes conjuntos de datos, pueden agotar los recursos computacionales y aumentar la latencia. Los métodos eficientes de indexación, recuperación y cálculo de similitudes son esenciales para garantizar la escalabilidad y el rendimiento en tiempo real en entornos de producción.


La biblioteca Superlinked le permite abordar estos desafíos. A continuación, crearemos un recomendador de contenido (específicamente para películas), comenzando con la información que tenemos sobre una película determinada, integrando esta información como un vector multimodal, creando un índice de vector que se pueda buscar para todas nuestras películas y luego utilizando ponderaciones de consulta para ajustar nuestros resultados y llegar a buenas recomendaciones de películas. Vamos a ello.

Creando una experiencia de búsqueda rápida y confiable con Superlinked

A continuación, realizará una búsqueda semántica en el conjunto de datos de películas de Netflix utilizando los siguientes elementos de la biblioteca Superlinked:

  • Espacio de actualidad: para comprender la frescura (actualidad y relevancia) de sus datos, identificando películas más nuevas.
  • Espacio TextSimilarity: para interpretar los distintos metadatos que tiene sobre la película, como la descripción, el título y el género.
  • Ponderaciones de tiempo de consulta: le permiten elegir lo que es más importante en sus datos cuando ejecuta la consulta, optimizando así sin necesidad de volver a incrustar todo el conjunto de datos, realizar posprocesamiento o emplear un modelo de reclasificación personalizado (es decir, reduciendo la latencia).

El conjunto de datos de Netflix y lo que haremos con él

Recomendar películas con éxito es difícil, principalmente porque hay muchas opciones (más de 9000 títulos en 2023) y los usuarios quieren recomendaciones a pedido, de inmediato. Adoptemos un enfoque basado en datos para encontrar algo que queramos ver. En nuestro conjunto de datos de películas, sabemos lo siguiente:

  • descripción
  • género
  • título
  • año de lanzamiento


Podemos incrustar estas entradas y crear un índice vectorial sobre nuestras incrustaciones, creando un espacio en el que podemos buscar semánticamente.


Una vez que tengamos nuestro espacio vectorial indexado, haremos lo siguiente:

  • Primero, navega por las películas, filtradas por una idea (comedia romántica sincera)
  • A continuación, modifique los resultados, dando más importancia a las coincidencias en ciertos campos de entrada (es decir, ponderación).
  • Luego, busque en descripción, género y título con diferentes términos de búsqueda para cada uno.
  • y, después de encontrar una película que sea similar pero no exactamente igual, también busque usando esa película como referencia

Instalación y preparación del conjunto de datos

El primer paso es instalar la biblioteca e importar las clases necesarias.


(Nota: A continuación, cambie alt.renderers.enable(“mimetype”) a alt.renderers.enable('colab') si está ejecutando esto en Google Colab . Mantenga “mimetype” si está ejecutando esto en GitHub ).


 %pip install superlinked==5.3.0 from datetime import timedelta, datetime import altair as alt import os import pandas as pd from superlinked.evaluation.charts.recency_plotter import RecencyPlotter from superlinked.framework.common.dag.context import CONTEXT_COMMON, CONTEXT_COMMON_NOW from superlinked.framework.common.dag.period_time import PeriodTime from superlinked.framework.common.schema.schema import schema from superlinked.framework.common.schema.schema_object import String, Timestamp from superlinked.framework.common.schema.id_schema_object import IdField from superlinked.framework.common.parser.dataframe_parser import DataFrameParser from superlinked.framework.dsl.executor.in_memory.in_memory_executor import ( InMemoryExecutor, InMemoryApp, ) from superlinked.framework.dsl.index.index import Index from superlinked.framework.dsl.query.param import Param from superlinked.framework.dsl.query.query import Query from superlinked.framework.dsl.query.result import Result from superlinked.framework.dsl.source.in_memory_source import InMemorySource from superlinked.framework.dsl.space.text_similarity_space import TextSimilaritySpace from superlinked.framework.dsl.space.recency_space import RecencySpace alt.renderers.enable("mimetype") # NOTE: to render altair plots in colab, change 'mimetype' to 'colab' alt.data_transformers.disable_max_rows() pd.set_option("display.max_colwidth", 190)


También debemos preparar el conjunto de datos: definir constantes de tiempo, configurar la ubicación URL de los datos, crear un diccionario de almacenamiento de datos, leer el CSV en un DataFrame de pandas, limpiar el DataFrame y los datos para que se puedan buscar correctamente y hacer una verificación y una descripción general rápidas. (Consulte las celdas 3 y 4 para obtener más detalles).


Ahora que el conjunto de datos está preparado, puede optimizar su recuperación utilizando la biblioteca Superlinked.

Creación del índice para la búsqueda de vectores

La biblioteca de Superlinked contiene un conjunto de bloques de construcción básicos que utilizamos para construir un índice y gestionar la recuperación. Puede leer sobre estos bloques de construcción con más detalle aquí .


Primero, debes definir tu esquema para informar al sistema sobre tus datos.

 # accommodate our inputs in a typed schema @schema class MovieSchema: description: String title: String release_timestamp: Timestamp genres: String id: IdField movie = MovieSchema()


A continuación, utilice espacios para indicar cómo desea tratar cada parte de los datos al incrustarlos. Los espacios que se utilicen dependerán del tipo de datos. Cada espacio está optimizado para incrustar los datos de modo de devolver la mayor calidad posible de resultados de recuperación.


En las definiciones de espacio, describimos cómo se deben integrar las entradas para reflejar las relaciones semánticas en nuestros datos.


 # textual fields are embedded using a sentence-transformers model description_space = TextSimilaritySpace( text=movie.description, model="sentence-transformers/paraphrase-MiniLM-L3-v2" ) title_space = TextSimilaritySpace( text=movie.title, model="sentence-transformers/paraphrase-MiniLM-L3-v2" ) genre_space = TextSimilaritySpace( text=movie.genres, model="sentence-transformers/paraphrase-MiniLM-L3-v2" ) # release date are encoded using our recency space # periodtimes aim to reflect notable breaks in our scores recency_space = RecencySpace( timestamp=movie.release_timestamp, period_time_list=[ PeriodTime(timedelta(days=4 * YEAR_IN_DAYS)), PeriodTime(timedelta(days=10 * YEAR_IN_DAYS)), PeriodTime(timedelta(days=40 * YEAR_IN_DAYS)), ], negative_filter=-0.25, ) movie_index = Index(spaces=[description_space, title_space, genre_space, recency_space])


Una vez que haya configurado sus espacios y creado su índice, utilice las partes de origen y ejecutor de la biblioteca para configurar sus consultas. Consulte las celdas 10 a 13 en el cuaderno .


Ahora que las consultas están preparadas, pasemos a ejecutarlas y optimizar la recuperación ajustando los pesos.

Comprender la actualidad y cómo utilizarla en Superlinked

El espacio de actualidad le permite modificar los resultados de su consulta al incluir preferentemente publicaciones más antiguas o más nuevas de su conjunto de datos. Usamos 4, 10 y 40 años como períodos de tiempo para poder dar más importancia a los años con más títulos (consulte la celda 5 ).


Observe las interrupciones en la puntuación a los 4, 10 y 40 años. Los títulos con más de 40 años obtienen una puntuación negative_filter .

Puntuaciones de actualidad por período

Revisión y optimización de los resultados de búsqueda utilizando diferentes ponderaciones de tiempo de consulta

Definamos una función de utilidad rápida para presentar nuestros resultados en el cuaderno.


 def present_result( result: Result, cols_to_keep: list[str] = ["description", "title", "genres", "release_year", "id"], ) -> pd.DataFrame: # parse result to dataframe df: pd.DataFrame = result.to_pandas() # transform timestamp back to release year df["release_year"] = [ datetime.fromtimestamp(timestamp).year for timestamp in df["release_timestamp"] ] return df[cols_to_keep]


Consultas simples y avanzadas

La biblioteca Superlinked le permite realizar varios tipos de consultas; aquí definimos dos. Ambos tipos de consultas (simples y avanzadas) me permiten evaluar espacios individuales (descripción, título, género y, por supuesto, actualidad) según mis preferencias. La diferencia entre ellos es que con una consulta simple , establezco un texto de consulta y luego obtengo resultados similares en los espacios de descripción, título y género.


Con una consulta avanzada , tengo un control más preciso. Si quiero, puedo ingresar diferentes textos de consulta en cada uno de los espacios de descripción, título y género. Este es el código de consulta:


 query_text_param = Param("query_text") simple_query = ( Query( movie_index, weights={ description_space: Param("description_weight"), title_space: Param("title_weight"), genre_space: Param("genre_weight"), recency_space: Param("recency_weight"), }, ) .find(movie) .similar(description_space.text, query_text_param) .similar(title_space.text, query_text_param) .similar(genre_space.text, query_text_param) .limit(Param("limit")) ) advanced_query = ( Query( movie_index, weights={ description_space: Param("description_weight"), title_space: Param("title_weight"), genre_space: Param("genre_weight"), recency_space: Param("recency_weight"), }, ) .find(movie) .similar(description_space.text, Param("description_query_text")) .similar(title_space.text, Param("title_query_text")) .similar(genre_space.text, Param("genre_query_text")) .limit(Param("limit")) )


Consulta sencilla

En consultas simples, configuro el texto de mi consulta y aplico diferentes pesos según su importancia para mí.


 result: Result = app.query( simple_query, query_text="Heartfelt romantic comedy", description_weight=1, title_weight=1, genre_weight=1, recency_weight=0, limit=TOP_N, ) present_result(result) 


Resultados de consulta simple 1

Nuestros resultados contienen algunos títulos que ya he visto. Puedo solucionar esto ponderando la actualidad para sesgar mis resultados hacia los títulos recientes. Las ponderaciones se normalizan para tener una suma unitaria (es decir, todas las ponderaciones se ajustan para que siempre sumen un total de 1), por lo que no tiene que preocuparse por cómo las configura.


 result: Result = app.query( simple_query, query_text="Heartfelt romantic comedy", description_weight=1, title_weight=1, genre_weight=1, recency_weight=3, limit=TOP_N, ) present_result(result) 


Resultados de consulta simple 1

Mis resultados (arriba) ahora son todos posteriores a 2021.


Con la consulta simple, puedo ponderar cualquier espacio específico (descripción, título, género o actualidad) para que cuente más al devolver resultados. Experimentemos con esto. A continuación, le daremos más peso al género y le quitaremos peso al título: el texto de mi consulta es básicamente un género con un poco de contexto adicional. Mantengo la actualidad como está porque me gustaría que mis resultados estuvieran sesgados hacia las películas recientes.


 result = app.query( simple_query, query_text="Heartfelt romantic comedy", description_weight=1, title_weight=0.1, genre_weight=2, recency_weight=1, limit=TOP_N, ) present_result(result)


Esta consulta retrasa un poco el año de lanzamiento para brindarme resultados más ponderados por género (abajo).


Resultados de consulta simple 3

Consulta avanzada

La consulta avanzada me brinda un control aún más preciso. Mantengo el control sobre la actualidad, pero también puedo especificar el texto de búsqueda para la descripción, el título y el género, y asignar a cada uno un peso específico según mis preferencias, como se muestra a continuación (y en las celdas 19 a 21 ).

 result = app.query( advanced_query, description_query_text="Heartfelt lovely romantic comedy for a cold autumn evening.", title_query_text="love", genre_query_text="drama comedy romantic", description_weight=0.2, title_weight=3, genre_weight=1, recency_weight=5, limit=TOP_N, ) present_result(result)


Buscar usando una película específica

Digamos que en mis últimos resultados de películas encontré una película que ya vi y me gustaría ver algo similar. Supongamos que me gusta White Christmas, una comedia romántica de 1954 (id = tm16479) sobre cantantes y bailarines que se juntan para un espectáculo teatral para atraer invitados a una posada en dificultades de Vermont. Al agregar una cláusula with_vector adicional (con un parámetro movie_id ) a advanced_query, with_movie_query me permite buscar usando esta película (o cualquier película que me guste) y me brinda todo el control detallado de un texto de consulta de subbúsqueda independiente y ponderación.


Primero, agregamos nuestro parámetro movie_id:

 with_movie_query = advanced_query.with_vector(movie, Param("movie_id"))


Y luego puedo configurar mis otras consultas de subbúsqueda como vacías o como sea más relevante, junto con cualquier ponderación que tenga sentido. Digamos que mi primera consulta devuelve resultados que reflejan el aspecto de actuación/banda en el escenario de White Christmas (ver celda 24 ), pero quiero ver una película más orientada a la familia. Puedo ingresar un description_query_text para sesgar mis resultados en la dirección deseada.

 result = app.query( with_movie_query, description_query_text="family", title_query_text="", genre_query_text="", description_weight=1, title_weight=0, genre_weight=0, recency_weight=0, description_query_weight=1, movie_id="tm16479", limit=TOP_N, ) present_result(result) 


Resultados de la consulta avanzada 1

Pero ahora que veo los resultados, me doy cuenta de que en realidad tengo más ganas de algo más ligero y divertido. Ajustemos mi consulta en consecuencia:


 Result = app.query( with_movie_query, description_query_text="", title_query_text="", genre_query_text="comedy", description_weight=1, title_weight=0, genre_weight=2, recency_weight=0, description_query_weight=1, movie_id="tm16479", limit=TOP_N, ) present_result(result) 


Resultados de la consulta avanzada 2

Bueno, esos resultados son mejores. Elegiré uno de estos. ¡Pon las palomitas de maíz a hervir!

Conclusión

Superlinked facilita la realización de pruebas, iteraciones y mejoras en la calidad de la recuperación. Más arriba, le mostramos cómo utilizar la biblioteca Superlinked para realizar una búsqueda semántica en un espacio vectorial, como lo hace Netflix, y devolver resultados de películas precisos y relevantes. También vimos cómo ajustar nuestros resultados, modificando los pesos y los términos de búsqueda hasta obtener el resultado correcto.


¡Ahora prueba el cuaderno tú mismo y descubre lo que puedes lograr!

Pruébelo usted mismo: ¡obtenga el código y la demostración!

  • 💾 Obtén el código : consulta la implementación completa en nuestro repositorio de GitHub aquí . ¡Bifurca, modifícalo y hazlo tuyo!


  • 🚀 Míralo en acción : ¿Quieres ver cómo funciona en una configuración real? Reserva una demostración rápida y descubre cómo Superlinked puede potenciar tus recomendaciones. ¡Obtén una demostración ahora !


Los motores de recomendación están cambiando la forma en que descubrimos contenido. Ya sean películas, música o productos, la búsqueda vectorial es el futuro y ahora tienes las herramientas para crear la tuya.


Autor: Mór Kapronczay