Creación de un sistema de recomendación sencillo en Python con Pandas

    Introducción

    ¿Alguna vez te has preguntado cómo Netflix te sugiere películas basadas en las películas que ya has visto? ¿O cómo muestran los sitios web de comercio electrónico opciones como «Comprados juntos con frecuencia»? Pueden parecer opciones relativamente simples, pero detrás de escena, se ejecuta un algoritmo estadístico complejo para predecir estas recomendaciones. Estos sistemas se denominan sistemas de recomendación, sistemas de recomendación o motores de recomendación. Un sistema de recomendación es una de las aplicaciones más famosas de la ciencia de datos y el aprendizaje automático.

    Un sistema de recomendación emplea un algoritmo estadístico que busca predecir las calificaciones de los usuarios para una entidad en particular, basándose en la similitud entre las entidades o entre los usuarios que calificaron previamente esas entidades. La intuición es que es probable que tipos similares de usuarios tengan calificaciones similares para un conjunto de entidades.

    Actualmente, muchas de las grandes empresas de tecnología utilizan un sistema de recomendación de una forma u otra. Puede encontrarlos en cualquier lugar, desde Amazon (recomendaciones de productos) hasta YouTube (recomendaciones de videos) hasta Facebook (recomendaciones de amigos). La capacidad de recomendar productos o servicios relevantes a los usuarios puede ser un gran impulso para una empresa, por lo que es tan común encontrar esta técnica empleada en tantos sitios.

    En este artículo, veremos cómo podemos construir un sistema de recomendación simple en Python.

    Tipos de sistemas de recomendación

    Hay dos enfoques principales para crear sistemas de recomendación: filtrado basado en contenido y filtrado colaborativo:

    Filtrado basado en contenido

    En el filtrado basado en contenido, la similitud entre diferentes productos se calcula sobre la base de los atributos de los productos. Por ejemplo, en un sistema de recomendación de películas basado en contenido, la similitud entre las películas se calcula en función de los géneros, los actores de la película, el director de la película, etc.

    Filtración colaborativa

    El filtrado colaborativo aprovecha el poder de la multitud. La intuición detrás del filtrado colaborativo es que si a un usuario A le gustan los productos X e Y, y si a otro usuario B le gusta el producto X, hay muchas posibilidades de que también le guste el producto Y.

    Tomemos el ejemplo de un sistema de recomendación de películas. Suponga que un gran número de usuarios ha asignado las mismas calificaciones a las películas X e Y. Llega un nuevo usuario que ha asignado la misma calificación a la película X pero que aún no ha visto la película Y. El sistema de filtrado colaborativo le recomendará la película Y.

    Implementación del sistema de recomendación de películas en Python

    En esta sección, desarrollaremos un sistema de recomendación de películas muy simple en Python que usa la correlación entre las calificaciones asignadas a diferentes películas, para encontrar la similitud entre las películas.

    El conjunto de datos que vamos a utilizar para este problema es MovieLens Dataset. Para descargar el conjunto de datos, vaya a la página de inicio del conjunto de datos y descargue el archivo «ml-latest-small.zip», que contiene un subconjunto del conjunto de datos de películas real y contiene 100000 clasificaciones para 9000 películas de 700 usuarios.

    Una vez que descomprima el archivo descargado, verá los archivos «links.csv», «movies.csv», «ratings.csv» y «tags.csv», junto con el documento «README». En este artículo, usaremos los archivos «movies.csv» y «ratings.csv».

    Para los scripts de este artículo, la carpeta «ml-latest-small» descomprimida se ha colocado dentro de la carpeta «Conjuntos de datos» en la unidad «E».

    Visualización y preprocesamiento de datos

    El primer paso en cada problema de ciencia de datos es visualizar y preprocesar los datos. Haremos lo mismo, así que primero importemos el archivo «ratings.csv» y veamos qué contiene. Ejecute el siguiente script:

    import numpy as np
    import pandas as pd
    
    ratings_data = pd.read_csv("E:Datasetsml-latest-small\ratings.csv")
    ratings_data.head()
    

    En el script anterior usamos el read_csv()método de la biblioteca Pandas para leer el archivo «ratings.csv». A continuación, llamamos al head()método desde el objeto de marco de datos devuelto por la read_csv()función, que mostrará las primeras cinco filas del conjunto de datos.

    La salida se ve así:

    userId
    movieId
    calificación
    marca de tiempo

    01312.51260759144
    1110293.01260759179
    2110613.01260759182
    3111292.01260759185
    4111724.01260759205

    Puede ver en el resultado que el archivo «ratings.csv» contiene los atributos userId, movieId, ratings y timestamp. Cada fila del conjunto de datos corresponde a una calificación. La columna userId contiene el ID del usuario que dejó la calificación. La columna movieId contiene el Id de la película, la columna de calificación contiene la calificación dejada por el usuario. Las calificaciones pueden tener valores entre 1 y 5. Y finalmente, la marca de tiempo se refiere al momento en que el usuario dejó la calificación.

    Hay un problema con este conjunto de datos. Contiene los ID de las películas pero no sus títulos. Necesitaremos nombres de películas para las películas que recomendamos. Los nombres de las películas se almacenan en el archivo «movies.csv». Importemos el archivo y veamos los datos que contiene. Ejecute el siguiente script:

    movie_names = pd.read_csv("E:Datasetsml-latest-small\movies.csv")
    movie_names.head()
    

    La salida se ve así:

    géneros de
    títulos de movieId

    01Toy Story (1995)Aventura | Animación | Infantil | Comedia | Fantasía
    12Jumanji (1995)Aventura | Niños | Fantasía
    23Viejos gruñones (1995)Comedia | Romance
    34Esperando para exhalar (1995)Comedia | Drama | Romance
    45Padre de la novia Parte II (1995)Comedia

    Como puede ver, este conjunto de datos contiene movieId, el título de la película y su género. Necesitamos un conjunto de datos que contenga el ID de usuario, el título de la película y sus calificaciones. Tenemos esta información en dos objetos de marco de datos diferentes: «ratings_data» y «movie_names». Para obtener nuestra información deseada en un solo marco de datos, podemos fusionar los dos objetos de marcos de datos en la columna movieId ya que es común entre los dos marcos de datos.

    Podemos hacer esto usando la merge()función de la biblioteca Pandas, como se muestra a continuación:

    movie_data = pd.merge(ratings_data, movie_names, on='movieId')
    

    Ahora veamos nuestro nuevo marco de datos:

    movie_data.head()
    

    La salida se ve así:

    userId
    movieId
    clasificación
    marca de tiempo géneros de
    título

    01312.51260759144Mentes peligrosas (1995)Drama
    17313.0851868750Mentes peligrosas (1995)Drama
    231314.012703541953Mentes peligrosas (1995)Drama
    332314.0834828440Mentes peligrosas (1995)Drama
    436313.0847057202Mentes peligrosas (1995)Drama

    Puede ver que nuestro marco de datos recién creado contiene userId, título y calificación de la película según sea necesario.

    Ahora echemos un vistazo a la calificación promedio de cada película. Para hacerlo, podemos agrupar el conjunto de datos por el título de la película y luego calcular la media de la calificación de cada película. Luego, mostraremos las primeras cinco películas junto con su calificación promedio usando el head()método. Mira el siguiente guión:

    movie_data.groupby('title')['rating'].mean().head()
    

    La salida se ve así:

    title
    "Great Performances" Cats (1998)           1.750000
    $9.99 (2008)                               3.833333
    'Hellboy': The Seeds of Creation (2004)    2.000000
    'Neath the Arizona Skies (1934)            0.500000
    'Round Midnight (1986)                     2.250000
    Name: rating, dtype: float64
    

    Puede ver que las calificaciones promedio no están ordenadas. Ordenemos las calificaciones en orden descendente de sus calificaciones promedio:

    movie_data.groupby('title')['rating'].mean().sort_values(ascending=False).head()
    

    Si ejecuta el script anterior, la salida se verá así:

    title
    Burn Up! (1991)                                     5.0
    Absolute Giganten (1999)                            5.0
    Gentlemen of Fortune (Dzhentlmeny udachi) (1972)    5.0
    Erik the Viking (1989)                              5.0
    Reality (2014)                                      5.0
    Name: rating, dtype: float64
    

    Las películas ahora se han ordenado según el orden ascendente de sus calificaciones. Sin embargo, existe un problema. Una película puede llegar a la parte superior de la lista anterior incluso si solo un usuario le ha dado cinco estrellas. Por lo tanto, las estadísticas anteriores pueden ser engañosas. Normalmente, una película que es realmente buena obtiene una calificación más alta por parte de un gran número de usuarios.

    Tracemos ahora la cantidad total de calificaciones de una película:

    movie_data.groupby('title')['rating'].count().sort_values(ascending=False).head()
    

    La ejecución del script anterior devuelve el siguiente resultado:

    title
    Forrest Gump (1994)                          341
    Pulp Fiction (1994)                          324
    Shawshank Redemption, The (1994)             311
    Silence of the Lambs, The (1991)             304
    Star Wars: Episode IV - A New Hope (1977)    291
    Name: rating, dtype: int64
    

    Ahora puedes ver algunas películas realmente buenas en la parte superior. La lista anterior respalda nuestro punto de que las buenas películas normalmente reciben calificaciones más altas. Ahora sabemos que tanto la calificación promedio por película como el número de calificaciones por película son atributos importantes. Creemos un nuevo marco de datos que contenga ambos atributos.

    Ejecute el siguiente script para crear un ratings_mean_countmarco de datos y primero agregue la calificación promedio de cada película a este marco de datos:

    ratings_mean_count = pd.DataFrame(movie_data.groupby('title')['rating'].mean())
    

    A continuación, debemos agregar la cantidad de calificaciones de una película al ratings_mean_countmarco de datos. Ejecute el siguiente script para hacerlo:

    ratings_mean_count['rating_counts'] = pd.DataFrame(movie_data.groupby('title')['rating'].count())
    

    Ahora echemos un vistazo a nuestro marco de datos recién creado.

    ratings_mean_count.head()
    

    La salida se ve así:

    titleratingrating_counts

    Gatos «Grandes actuaciones» (1998)1.7500002
    $9.99 (2008)3.8333333
    ‘Hellboy’: Las semillas de la creación (2004)2.0000001
    Bajo los cielos de Arizona (1934)0.5000001
    ‘Ronda de medianoche (1986)2.2500002

    Puede ver el título de la película, junto con la calificación promedio y el número de calificaciones de la película.

    Tracemos un histograma para el número de calificaciones representadas por la columna «rating_counts» en el marco de datos anterior. Ejecute el siguiente script:

    import matplotlib.pyplot as plt
    import seaborn as sns
    sns.set_style('dark')
    %matplotlib inline
    
    plt.figure(figsize=(8,6))
    plt.rcParams['patch.force_edgecolor'] = True
    ratings_mean_count['rating_counts'].hist(bins=50)
    

    Aquí está el resultado del script anterior:

    En la salida, puede ver que la mayoría de las películas han recibido menos de 50 calificaciones. Mientras que la cantidad de películas que tienen más de 100 calificaciones es muy baja.

    Ahora trazaremos un histograma para calificaciones promedio. Aquí está el código para hacerlo:

    plt.figure(figsize=(8,6))
    plt.rcParams['patch.force_edgecolor'] = True
    ratings_mean_count['rating'].hist(bins=50)
    

    La salida se ve así:

    Puede ver que los valores enteros tienen barras más altas que los valores flotantes ya que la mayoría de los usuarios asignan calificación como valor entero, es decir, 1, 2, 3, 4 o 5. Además, es evidente que los datos tienen una distribución normal débil con el media de alrededor de 3,5. Hay algunos valores atípicos en los datos.

    Anteriormente, dijimos que las películas con un mayor número de calificaciones generalmente también tienen una calificación promedio alta, ya que una buena película normalmente es conocida y una película conocida es vista por una gran cantidad de personas y, por lo tanto, generalmente tiene una calificación más alta. clasificación. Veamos si este también es el caso de las películas en nuestro conjunto de datos. Trazaremos las calificaciones promedio contra el número de calificaciones:

    plt.figure(figsize=(8,6))
    plt.rcParams['patch.force_edgecolor'] = True
    sns.jointplot(x='rating', y='rating_counts', data=ratings_mean_count, alpha=0.4)
    

    La salida se ve así:

    El gráfico muestra que, en general, las películas con calificaciones promedio más altas en realidad tienen un mayor número de calificaciones, en comparación con las películas que tienen calificaciones promedio más bajas.

    Encontrar similitudes entre películas

    Dedicamos bastante tiempo a visualizar y preprocesar nuestros datos. Ahora es el momento de encontrar la similitud entre películas.

    Usaremos la correlación entre las calificaciones de una película como métrica de similitud. Para encontrar la correlación entre las calificaciones de la película, necesitamos crear una matriz donde cada columna es un nombre de película y cada fila contiene la calificación asignada por un usuario específico a esa película. Tenga en cuenta que esta matriz tendrá muchos valores nulos ya que cada película no es calificada por todos los usuarios.

    Para crear la matriz de títulos de películas y las calificaciones de usuarios correspondientes, ejecute el siguiente script:

    user_movie_rating = movie_data.pivot_table(index='userId', columns="title", values="rating")
    
    user_movie_rating.head()
    

    título «Great Performances» Cats (1998) $ 9.99 (1998) ‘Hellboy’: The Seeds of Creation (2008) ‘Neath the Arizona Skies (1934)’ Round Midnight (1986) ‘Salem’s Lot (2004)’ Til There Was You ( 1997) ‘burbs, The (1989)’ night Mother (1986) (500) Days of Summer (2009) … Zulu (1964) Zulu (2013) userId

    1YayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYaya
    2YayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYaya
    3YayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYaya
    4YayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYaya
    5YayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYayaYaya

    Sabemos que cada columna contiene todas las calificaciones de los usuarios para una película en particular. Busquemos todas las calificaciones de los usuarios de la película «Forrest Gump (1994)» y busquemos películas similares. Elegimos esta película porque tiene el mayor número de calificaciones y queremos encontrar la correlación entre las películas que tienen un mayor número de calificaciones.

    Para encontrar las calificaciones de los usuarios de «Forrest Gump (1994)», ejecute el siguiente script:

    forrest_gump_ratings = user_movie_rating['Forrest Gump (1994)']
    

    El script anterior devolverá una serie de Pandas. Veamos cómo se ve.

    forrest_gump_ratings.head()
    
    userId
    1    NaN
    2    3.0
    3    5.0
    4    5.0
    5    4.0
    Name: Forrest Gump (1994), dtype: float64
    

    Ahora recuperemos todas las películas que son similares a «Forrest Gump (1994)». Podemos encontrar la correlación entre las calificaciones de los usuarios de «Forest Gump (1994)» y todas las demás películas que utilizan la corrwith()función que se muestra a continuación:

    movies_like_forest_gump = user_movie_rating.corrwith(forrest_gump_ratings)
    
    corr_forrest_gump = pd.DataFrame(movies_like_forest_gump, columns=['Correlation'])
    corr_forrest_gump.dropna(inplace=True)
    corr_forrest_gump.head()
    

    En el guión anterior, primero recuperamos la lista de todas las películas relacionadas con «Forrest Gump (1994)» junto con su valor de correlación, usando la corrwith()función. A continuación, creamos un marco de datos que contiene el título de la película y las columnas de correlación. Luego eliminamos todos los valores de NA del marco de datos y mostramos sus primeras 5 filas usando la headfunción.

    La salida se ve así:

    titleCorrelation

    $9.99 (2008)1.000000
    ‘burbs, El (1989)0.044946
    (500) Días de verano (2009)0.624458
    * pilas no incluidas (1987)0.603023
    … Y justicia para todos (1979)0.173422

    Ordenemos las películas en orden descendente de correlación para ver películas altamente correlacionadas en la parte superior. Ejecute el siguiente script:

    corr_forrest_gump.sort_values('Correlation', ascending=False).head(10)
    

    Aquí está el resultado del script anterior:

    titleCorrelation

    $9.99 (2008)1.0
    Di que no es así (2001)1.0
    Metrópolis (2001)1.0
    No ver el mal, no escuchar el mal (1989)1.0
    Hombres intermedios (2009)1.0
    Agua para elefantes (2011)1.0
    Watch, The (2012)1.0
    La próxima película de Cheech & Chong (1980)1.0
    Forrest Gump (1994)1.0
    Guerrero (2011)1.0

    De la salida se puede ver que las películas que tienen alta correlación con «Forrest Gump (1994)» no son muy conocidas. Esto muestra que la correlación por sí sola no es una buena métrica para la similitud porque puede haber un usuario que vio ‘»Forest Gump (1994)» y solo una película más y calificó ambas como 5.

    Una solución a este problema es recuperar solo aquellas películas correlacionadas que tengan al menos más de 50 calificaciones. Para hacerlo, agregará la rating_countscolumna del rating_mean_countmarco de datos a nuestro corr_forrest_gumpmarco de datos. Ejecute el siguiente script para hacerlo:

    corr_forrest_gump = corr_forrest_gump.join(ratings_mean_count['rating_counts'])
    corr_forrest_gump.head()
    

    La salida se ve así:

    titleCorrelationrating_counts

    $9.99 (2008)1.0000003
    ‘burbs, El (1989)0.04494619
    (500) Días de verano (2009)0.62445845
    * pilas no incluidas (1987)0.6030237
    … Y justicia para todos (1979)0.17342213

    Puede ver que la película «$ 9.99», que tiene la correlación más alta, tiene solo tres calificaciones. Esto significa que sólo tres usuarios dieron las mismas calificaciones a «Forest Gump (1994)», «$ 9,99». Sin embargo, podemos deducir que una película no se puede declarar similar a otra película basándonos en solo 3 calificaciones. Es por eso que agregamos la columna «rating_counts». Filtremos ahora películas correlacionadas con «Forest Gump (1994)», que tienen más de 50 ratings. El siguiente código hará eso:

    corr_forrest_gump[corr_forrest_gump ['rating_counts']>50].sort_values('Correlation', ascending=False).head()
    

    La salida del script se ve así:

    titleCorrelationrating_counts

    Forrest Gump (1994)1.000000341
    Mi gran boda griega (2002)0.62624051
    Mente hermosa, A (2001)0.575922114
    Pocos hombres buenos, A (1992)0.55520676
    Million Dollar Baby (2004)0.54563865

    Ahora puede ver en la salida las películas que están altamente correlacionadas con «Forrest Gump (1994)». Las películas de la lista son algunas de las películas más famosas de Hollywood, y dado que «Forest Gump (1994)» también es una película muy famosa, existe una alta probabilidad de que estas películas estén correlacionadas.

    Conclusión

    En este artículo, estudiamos qué es un sistema de recomendación y cómo podemos crearlo en Python usando solo la biblioteca Pandas. Es importante mencionar que el sistema de recomendación que creamos es muy simple. Los sistemas de recomendación de la vida real utilizan algoritmos muy complejos y se discutirán en un artículo posterior.

    Si desea obtener más información sobre los sistemas de recomendación, le sugiero que consulte los libros Sistemas prácticos de recomendación y Sistemas de recomendación: el libro de texto . Ellos profundizan mucho más en este tema y cubren métodos más complejos y precisos que los que hicimos en este artículo.

     

    Etiquetas:

    Deja una respuesta

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