Construye un sistema de recomendación con Surprise en Python

Share
Construye un sistema de recomendación con Surprise en Python

En el actual ecosistema digital, la personalización ya no es un lujo —es un requisito fundamental para la retención y la conversión. Tanto si se trata de optimizar tiendas online como plataformas de transmisión de contenido, la capacidad de predecir las preferencias del usuario con gran precisión es un factor diferenciador clave a nivel arquitectónico. Para las organizaciones que buscan servicios de ingeniería Servicios de ingeniería de IA para empresasde inteligencia artificial robustos para empresas

Este artículo proporciona una guía técnica sobre cómo implementar un sistema de recomendación utilizando Python y la biblioteca Scikit-Surprise. Analizaremos aspectos más avanzados, como las opciones arquitectónicas, la optimización de hiperparámetros y las técnicas de factorización de matrices adecuadas para entornos de producción.

Servicios de Ingeniería de LLM y IA

Ofrecemos una completa gama de soluciones impulsadas por la IA, que incluyen IA generativa, visión artificial, aprendizaje automático, procesamiento del lenguaje natural y automatización basada en IA.

Learn more

La base matemática: Factorización de matrices

Si bien los enfoques basados en memoria (como K-Nearest Neighbors) son intuitivos, a menudo sufren de problemas de escalabilidad en espacios dispersos y de alta dimensión. Los enfoques basados en modelos, específicamente la Factorización Matricial (SVD), generalmente ofrecen un rendimiento y una escalabilidad superiores.

En el contexto de la biblioteca Surprise, el algoritmo de Descomposición en Valores Singulares (SVD) minimiza el Error Cuadrático Regularizado. La calificación predicha $\hat{r}_{ui}$ para el usuario $u$ y el ítem $i$ se calcula como:

$$\hat{r}_{ui} = \mu + b_u + b_i + q_i^T p_u$$

¿Dónde?:

  • $\mu$ es la calificación promedio global.
  • $b_u$ y $b_i$ son términos de sesgo para el usuario y el elemento, respectivamente.
  • $q_i$ y $p_u$ son los vectores de características latentes.

Para estimar estos parámetros, minimizamos la siguiente función objetivo regularizada utilizando el descenso de gradiente estocástico (SGD):

$$\sum_{r_{ui} \in R_{train}} \left(r_{ui} - \hat{r}_{ui} \right)^2 + \lambda \left(b_i^2 + b_u^2 + ||q_i||^2 + ||p_u||^2 \right)$$

Configuración del entorno e importación de datos

La biblioteca Surprise es una biblioteca de scikit en Python diseñada específicamente para sistemas de recomendación. Se encarga de las tareas complejas como la manipulación de datos, la gestión de iteradores y el benchmarking de algoritmos.

Instalación

pip install scikit-surprise pandas

Cargando conjuntos de datos personalizados

A diferencia de los tutoriales estándar que se basan en conjuntos de datos MovieLens predefinidos, las aplicaciones empresariales suelen requerir la ingestión de datos desde bases de datos SQL o Data Lakes. A continuación, se presenta un patrón listo para su uso para cargar un conjunto de datos personalizado desde un PandasDataFrame

import pandas as pd
from surprise import Reader, Dataset

# Simulate loading data from a production DB or Data Lake
# Schema: [user_id, item_id, rating, timestamp]
data_payload = {
    'user_id': [101, 102, 101, 103, 104, 102, 103, 105],
    'item_id': ['PROD_A', 'PROD_A', 'PROD_B', 'PROD_B', 'PROD_C', 'PROD_C', 'PROD_A', 'PROD_B'],
    'rating': [5, 4, 3, 5, 2, 4, 3, 5]
}

df = pd.DataFrame(data_payload)

# Define the rating scale. This is crucial for normalization.
# If your implicit feedback is binary (0/1), use rating_scale=(0, 1)
reader = Reader(rating_scale=(1, 5))

# The columns must correspond to user id, item id and ratings (in that order)
data = Dataset.load_from_df(df[['user_id', 'item_id', 'rating']], reader)

print("Data ingestion complete. Building trainset...")
trainset = data.build_full_trainset()
print(f"Number of users: {trainset.n_users}")
print(f"Number of items: {trainset.n_items}")

Selección de Algoritmos y Validación Cruzada

Elegir el algoritmo adecuado implica un equilibrio entre el tiempo de entrenamiento, la precisión (RMSE) y la interpretabilidad. Para obtener servicios de ingeniería de inteligencia artificial robustos para empresas22, normalmente evaluamos a tres candidatos principales:

  1. Descomposición de Valores Singulares (SVD): Ideal para la precisión en escenarios de retroalimentación explícita.
  2. SVDpp (SVD++): Una extensión del SVD que tiene en cuenta las calificaciones implícitas. Más lenta, pero a menudo más precisa.
  3. Factorización Matricial No Negativa (NMF): Útil cuando los factores latentes deben ser no negativos (interpretación).

Aquí se explica cómo realizar pruebas de rendimiento con estas algoritmos utilizando la validación cruzada en 5 pliegues:

from surprise import SVD, NMF, KNNBasic
from surprise.model_selection import cross_validate

# Define algorithms to benchmark
algorithms = {
    'SVD': SVD(random_state=42),
    'NMF': NMF(random_state=42),
    'KNN_Baseline': KNNBasic(sim_options={'name': 'cosine', 'user_based': True})
}

benchmark_results = []

for name, algo in algorithms.items():
    print(f"Running cross-validation for {name}...")
    # cv=5 ensures robustness against overfitting on specific data splits
    results = cross_validate(algo, data, measures=['RMSE', 'MAE'], cv=5, verbose=False)
    
    mean_rmse = results['test_rmse'].mean()
    mean_mae = results['test_mae'].mean()
    fit_time = results['fit_time'].mean()
    
    benchmark_results.append({
        'Algorithm': name,
        'RMSE': mean_rmse,
        'MAE': mean_mae,
        'Fit Time (s)': fit_time
    })

# Convert to DataFrame for architectural review
results_df = pd.DataFrame(benchmark_results).sort_values(by='RMSE')
print(results_df)

Servicios de Ingeniería de LLM y IA

Ofrecemos una completa gama de soluciones impulsadas por la IA, que incluyen IA generativa, visión artificial, aprendizaje automático, procesamiento del lenguaje natural y automatización con IA.

Learn more

Ajuste de hiperparámetros con GridSearchCV

En un entorno de producción, los hiperparámetros predeterminados rara vez son óptimos. Por ejemplo, el algoritmo SVD es muy sensible a la tasa de aprendizaje (lr_alllr_all) y al término de regularización (reg_all

Utilizamos GridSearchCV para realizar una búsqueda exhaustiva sobre los valores de parámetros especificados.

from surprise.model_selection import GridSearchCV

# Define the parameter grid
# n_factors: The number of latent factors (dimensions of the matrix)
# n_epochs: The number of iterations of the SGD procedure
# lr_all: The learning rate for all parameters
# reg_all: The regularization term for all parameters
param_grid = {
    'n_factors': [20, 50, 100],
    'n_epochs': [20, 30],
    'lr_all': [0.002, 0.005, 0.01],
    'reg_all': [0.02, 0.1, 0.2]
}

print("Starting Grid Search. This may take some time depending on dataset size...")
gs = GridSearchCV(SVD, param_grid, measures=['rmse', 'mae'], cv=3, n_jobs=-1)

gs.fit(data)

# Extract best score and parameters
print(f"Best RMSE: {gs.best_score['rmse']}")
print(f"Best Parameters: {gs.best_params['rmse']}")

Implementar el modelo

Una vez que se hayan identificado los hiperparámetros óptimos, el modelo final debe entrenarse con todo el conjunto de datos y serializarse para su implementación. En una arquitectura de microservicios, este modelo normalmente estaría dentro de un contenedor dedicado a la inferencia.

Formación y Predicción

# Initialize SVD with best parameters found via GridSearch
best_params = gs.best_params['rmse']
algo = SVD(
    n_factors=best_params['n_factors'],
    n_epochs=best_params['n_epochs'],
    lr_all=best_params['lr_all'],
    reg_all=best_params['reg_all']
)

# Retrain on the whole dataset
trainset = data.build_full_trainset()
algo.fit(trainset)

# Predict a specific user-item pair
# user_id='101', item_id='PROD_C' (which user 101 has NOT seen yet)
prediction = algo.predict(uid=101, iid='PROD_C')

print(f"User 101 predicted rating for PROD_C: {prediction.est:.2f}")

Generación de recomendaciones principales (Top-N)

Para una aplicación en tiempo real, rara vez necesitamos una única predicción. Necesitamos los elementos "Top-N" para un usuario específico.

def get_top_n(predictions, n=10):
    """Return the top-N recommendation for each user from a set of predictions."""
    top_n = {}
    
    # Map the predictions to each user.
    for uid, iid, true_r, est, _ in predictions:
        if uid not in top_n:
            top_n[uid] = []
        top_n[uid].append((iid, est))

    # Sort the predictions for each user and retrieve the k highest ones.
    for uid, user_ratings in top_n.items():
        user_ratings.sort(key=lambda x: x[1], reverse=True)
        top_n[uid] = user_ratings[:n]

    return top_n

# To generate recommendations, we create a "test set" of all pairs NOT in the training set
testset = trainset.build_anti_testset()
predictions = algo.test(testset)

top_n_recommendations = get_top_n(predictions, n=5)

# Display recommendations for User 101
print(f"Recommendations for User 101: {top_n_recommendations.get(101, [])}")

Consideraciones arquitectónicas para clientes de 4Geeks

Cuando se asocie con 4Geeks para obtener servicios de ingeniería de inteligencia artificial para empresas3, enfatizamos que el algoritmo es solo uno de los componentes de la solución.Además, queremos destacar que el algoritmo es solo uno de los componentes de la solución.

  1. Problema de inicio en frío: Los nuevos usuarios o ítems con cero interacciones no pueden ser modelados únicamente por SVD. Se requieren arquitecturas híbridas que combinen el filtrado basado en contenido (utilizando metadatos del ítem) con el filtrado colaborativo para cerrar esta brecha.
  2. Escalabilidad: build_anti_testset(): crece exponencialmente ($N_{usuarios} \times N_{ítems}$). Para conjuntos de datos con millones de ítems, no se pueden calcular predicciones para todos pares faltantes en tiempo real. En cambio, debe utilizarse índices de vecinos más cercanos aproximados (ANN) como Faiss en los vectores de usuario/ítem ($p_u$ y $q_i$) generados por el modelo SVD.
  3. Deriva del modelo: Los preferencias de los usuarios cambian. Se necesitan pipelines automatizados de MLOps para retrenar el modelo periódicamente (por ejemplo, diariamente o semanalmente) para capturar las tendencias cambiantes.

Conclusión

Implementar un sistema de recomendación con Scikit-Surprise proporciona una base de alto rendimiento para experiencias personalizadas del usuario. Sin embargo, pasar de una Jupyter notebook a un sistema de producción escalable y tolerante a fallos requiere una profunda experiencia en ingeniería de datos y MLOps.

En 4Geeks... nos especializamos en convertir estas pruebas de concepto en soluciones de IA de nivel empresarial, gestionando todo, desde la gobernanza de datos hasta la optimización de la inferencia en tiempo real. Tanto si está optimizando para RMSE como para indicadores clave de rendimiento (KPI) específicos del negocio, como la tasa de clics (CTR), una sólida base de ingeniería es fundamental para el éxito.

Servicios de Ingeniería de LLM y IA

Ofrecemos una completa gama de soluciones impulsadas por la IA, que incluyen IA generativa, visión artificial, aprendizaje automático, procesamiento del lenguaje natural y automatización basada en IA.

Learn more

Preguntas frecuentes

¿Qué es la biblioteca Scikit-Surprise y por qué se prefiere para construir sistemas de recomendación?

Scikit-Surprise es una biblioteca especializada en Python dedicada a la creación y evaluación de sistemas de recomendación. Se utiliza ampliamente porque automatiza tareas complejas como el manejo de datos, la gestión de iteradores y la evaluación de algoritmos. Al centrarse específicamente en los datos de calificación explícitos, permite a los desarrolladores implementar y comparar de manera eficiente varios algoritmos de filtrado colaborativo, convirtiéndola en una herramienta robusta para desarrollar experiencias de usuario personalizadas.

¿Cómo mejora la descomposición de valores singulares (SVD) la precisión en las predicciones en el filtrado colaborativo?

Descomposición de Valores Singulares (SVD) es un algoritmo potente de factorización de matrices que predice las preferencias del usuario al descubrir características latentes (patrones ocultos) dentro de las interacciones usuario-elemento. A diferencia de los métodos básicos basados en memoria como K-Nearest Neighbors, SVD minimiza el error de predicción a través de Descenso de Gradiente Estocástico (SGD) e incorpora términos de sesgo tanto para usuarios como para elementos. Este enfoque mejora significativamente la escalabilidad y la precisión, especialmente cuando se trata de conjuntos de datos dispersos comunes en aplicaciones empresariales.

¿Cuáles son los pasos esenciales para implementar un modelo de recomendación en un entorno de producción?

Implementar con éxito un modelo de recomendación requiere pasar más allá del entrenamiento inicial para centrarse en la optimización y la escalabilidad. Los pasos clave incluyen realizar el ajuste de hiperparámetros (utilizando herramientas como GridSearchCV) para equilibrar la adaptación del modelo y su capacidad de generalización, así como reentrenar el modelo final con todo el conjunto de datos. Para un rendimiento en tiempo real, también es crucial abordar desafíos como el problema del "Inicio Frío" para nuevos usuarios y utilizar índices de vecinos más cercanos (ANN) para generar recomendaciones top-N de manera eficiente a gran escala.

Read more