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 *