Recomendador de Canciones de Spotify usando KNN ( K-Nearest Neighbors)

Jesus Pesqueira
LCC-Unison
Published in
7 min readDec 5, 2022

Jesus Ernesto Pesqueira Vasquez, Universidad de Sonora, Licenciatura en ciencias de la computación, Hermosillo, Sonora

Introducción

A quien no le gusta escuchar musica en estos tiempos, especialmente ahora que existen muchas plataformas donde escucharlas y lo mejor de todo es que estas apps cuentan con un motor de recomendacion que te lanzan canciones de acuerdo a tus preferencias y de manera regular. En este articulo hablaremos un poco sobre Machine Learning en particular el algoritmo KNN, ademas de las herramientas utilizadas para la elaboracion de la app y una aplicacion en la que tu tambien podras experimentar con el motor de recomedacion que se ha desarrollado.

Antes que nada

Antes de entrar a detalle, tenemos que saber un poco sobre que es un sistema de recomendación y tener una nocion de como funcionan estos.

Practicamente son algoritmos que intentas “predecir” los productos, canciones, etc que el usuario querra en particular.

Lo que tratan de lograr estos sistemas es ofrecer una mayor y mejor experiencia al usuario al estar recabando informacion acerca sus gustos y estar lanzadole resultados mas perzonalizado de acuerdo a sus busquedas ya sean productos, videos o canciones.

El sistema recomendador basa sus recomendaciones de las siguentes maneras:

  • Popularity: Aconseja por la “popularidad” de los productos. Por ejemplo, “los más vendidos” globalmente, se ofrecerán a todos los usuarios por igual sin aprovechar la personalización. Es fácil de implementar y en algunos casos es efectiva.
  • Content-based: A partir de productos visitados por el usuario, se intenta “adivinar” qué busca el usuario y ofrecer mercancías similares.
  • Colaborative: Es el más novedoso, pues utiliza la información de “masas” para identificar perfiles similares y aprender de los datos para recomendar productos de manera individual.

Mas a detalle sobre sistemas recomendaciones pueden consultar esta fuente https://www.aprendemachinelearning.com/sistemas-de-recomendacion/

Herramientas utilizadas para el desarrollo del sistema recomendador

Streamlit : Es un framework de Python de código abierto que permite de manera sencilla e integrada desarrollar aplicaciones gracias a la interacción con otras librerías para su empleo en campos de la teledetección, ciencia de datos, etc.

Lenguaje utilizado: Python para el desarrollo de la app web y aplicaciones de modelos de machine learning

Kaggle: Utilizamos la libreta de jupyter que nos ofrece esta plataforma para el preprocesamiento del dataset utilizado ademas de proporcionarnos el dataset

Algoritmo KNN (K-Nearest Neighbors): Es un clasificador de aprendizaje supervisado no paramétrico, que utiliza la proximidad para hacer clasificaciones o predicciones sobre la agrupación de un punto de datos individual.

Para mas detalles acerca del algoritmo KNN puede visitar la siguiente fuente https://www.ibm.com/mx-es/topics/knn

Desarrollo del sistema

La libreta para el preprocesamiento, el dataset y el codigo de la app se encuentran en el siguiente repositorio https://github.com/StarVeteran/Spotify-Recommender aqui pueden checar el codigo si lo desean.

El primer paso para el desarrollo de sistema recomendador es encontrar un dataset adecuado para esta situacion y kaggle nos ofrece justo eso. Sacamos el dataset llamado Spotify and Genius Track Dataset de kaggle que contiene justo lo que necesitamos para nuestro sistema recomendador

https://www.kaggle.com/datasets/saurabhshahane/spotgen-music-dataset

Para poder utilizar este dataset es necesario utlilizar una libreta de jupyter y cargar el dataset en kaggle para hacer un preprocesamiento para sacarle un mayor provecho.

La libreta se encuentra en el repositorio de github

Una vez que obtengamos el dataset preprocesador es hora de empezar a utilizarlos, primero que nada lo que ocuparemos es tener instalado los siguientes requerimientos para poder hacer funcionar la aplicacion que se encuentran en un archivo requirements.txt que se encuentra en el proyecto.

streamlit==1.0.0
pandas==1.3.3
plotly==5.3.1
scikit-learn==0.23.2

Una vez instalados los requerimientos podremos utilizar la app y analizar el codigo que contiene.

Empezamos con lo principal que se encuentra en app.py y estas son las librerias necesarias que utlizaremos.

import streamlit as st
st.set_page_config(page_title="Song Recommendation", layout="wide")

import pandas as pd
from sklearn.neighbors import NearestNeighbors
import plotly.express as px
import streamlit.components.v1 as components

Cargaremos el dataset para su uso

@st.cache(allow_output_mutation=True)
def load_data():
df = pd.read_csv("data/filtered_track_df.csv")
df['genres'] = df.genres.apply(lambda x: [i[1:-1] for i in str(x)[1:-1].split(", ")])
exploded_track_df = df.explode("genres")
return exploded_track_df

genre_names = ['Dance Pop', 'Electronic', 'Electropop', 'Hip Hop', 'Jazz', 'K-pop', 'Latin', 'Pop', 'Pop Rap', 'R&B', 'Rock']
audio_feats = ["acousticness", "danceability", "energy", "instrumentalness", "valence", "tempo"]

exploded_track_df = load_data()

Una vez que se cargan los datos, podemos comenzar a construir un modelo de aprendizaje automático para recomendar canciones, hay muchas formas de implementar diferentes modelos, pero una simple es usar un modelo de k-vecino más cercano para obtener las mejores canciones que están más cerca del conjunto de parámetros seleccionados por el usuario. Estos parámetros incluyen el género de interés, el rango de años de lanzamiento (comienzo y final del año) y un conjunto de características de audio (acústica, bailabilidad, energía, instrumentación, valencia y tempo).

def n_neighbors_uri_audio(genre, start_year, end_year, test_feat):
genre = genre.lower()
genre_data = exploded_track_df[(exploded_track_df["genres"]==genre) & (exploded_track_df["release_year"]>=start_year) & (exploded_track_df["release_year"]<=end_year)]
genre_data = genre_data.sort_values(by='popularity', ascending=False)[:500]

neigh = NearestNeighbors()
neigh.fit(genre_data[audio_feats].to_numpy())

n_neighbors = neigh.kneighbors([test_feat], n_neighbors=len(genre_data), return_distance=False)[0]

uris = genre_data.iloc[n_neighbors]["uri"].tolist()
audios = genre_data.iloc[n_neighbors][audio_feats].to_numpy()
return uris, audios

Se utiliza Sklearn para armar el modelo KNN y devolver los top-k resultados dado un punto de prueba. Se escribe una funcion llamada n_neighbors_uri_audio que devuelve los URIs de Spotify y las caracteristicas de audio de los valores del top neighbors en orden ascendente.

Ya lo unico que faltaria es implementar la vista de la app para hacer funcionar el modelo.

title = "Song Recommendation Engine"
st.title(title)

st.write("First of all, welcome! This is the place where you can customize what you want to listen to based on genre and several key audio features. Try playing around with different settings and listen to the songs recommended by our system!")
st.markdown("##")

with st.container():
col1, col2,col3,col4 = st.columns((2,0.5,0.5,0.5))
with col3:
st.markdown("***Choose your genre:***")
genre = st.radio(
"",
genre_names, index=genre_names.index("Pop"))
with col1:
st.markdown("***Choose features to customize:***")
start_year, end_year = st.slider(
'Select the year range',
1990, 2019, (2015, 2019)
)
acousticness = st.slider(
'Acousticness',
0.0, 1.0, 0.5)
danceability = st.slider(
'Danceability',
0.0, 1.0, 0.5)
energy = st.slider(
'Energy',
0.0, 1.0, 0.5)
instrumentalness = st.slider(
'Instrumentalness',
0.0, 1.0, 0.0)
valence = st.slider(
'Valence',
0.0, 1.0, 0.45)
tempo = st.slider(
'Tempo',
0.0, 244.0, 118.0)

tracks_per_page = 6
test_feat = [acousticness, danceability, energy, instrumentalness, valence, tempo]
uris, audios = n_neighbors_uri_audio(genre, start_year, end_year, test_feat)

tracks = []
for uri in uris:
track = """<iframe src="https://open.spotify.com/embed/track/{}" width="260" height="380" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>""".format(uri)
tracks.append(track)

if 'previous_inputs' not in st.session_state:
st.session_state['previous_inputs'] = [genre, start_year, end_year] + test_feat

current_inputs = [genre, start_year, end_year] + test_feat
if current_inputs != st.session_state['previous_inputs']:
if 'start_track_i' in st.session_state:
st.session_state['start_track_i'] = 0
st.session_state['previous_inputs'] = current_inputs

if 'start_track_i' not in st.session_state:
st.session_state['start_track_i'] = 0

with st.container():
col1, col2, col3 = st.columns([2,1,2])
if st.button("Recommend More Songs"):
if st.session_state['start_track_i'] < len(tracks):
st.session_state['start_track_i'] += tracks_per_page

current_tracks = tracks[st.session_state['start_track_i']: st.session_state['start_track_i'] + tracks_per_page]
current_audios = audios[st.session_state['start_track_i']: st.session_state['start_track_i'] + tracks_per_page]
if st.session_state['start_track_i'] < len(tracks):
for i, (track, audio) in enumerate(zip(current_tracks, current_audios)):
if i%2==0:
with col1:
components.html(
track,
height=400,
)
with st.expander("See more details"):
df = pd.DataFrame(dict(
r=audio[:5],
theta=audio_feats[:5]))
fig = px.line_polar(df, r='r', theta='theta', line_close=True)
fig.update_layout(height=400, width=340)
st.plotly_chart(fig)

else:
with col3:
components.html(
track,
height=400,
)
with st.expander("See more details"):
df = pd.DataFrame(dict(
r=audio[:5],
theta=audio_feats[:5]))
fig = px.line_polar(df, r='r', theta='theta', line_close=True)
fig.update_layout(height=400, width=340)
st.plotly_chart(fig)

else:
st.write("No songs left to recommend")

Por lo cual nos arroja lo siguiente

Ya lo que quedaria es simplemente probarlo ya sea localmente con el comando streamlit run app.py o puedes hacerlo aqui https://starveteran-spotify-recommender-app-h5m1oy.streamlit.app/

La aplicacion fue desplegada de igual manera en streamlit, desarrollada en python y el procesamiento de datos fue hecha en una libreta de kaggle.

De antemano muchas gracias por tomarte tu tiempo en leer este articulo c:

Si deseas leer otro de mis articulos puedes consultarlo aqui:

https://medium.com/lcc-unison/entrenamiento-de-ms-pacman-de-atari-con-una-red-neuronal-c9bd55c7b691

Aqui se encuentra el repositorio de github si deseas consultarlo

Referencias

https://streamlit.io

--

--