Skip to content

Latest commit

 

History

History
543 lines (415 loc) · 20.9 KB

File metadata and controls

543 lines (415 loc) · 20.9 KB

Documentación: Sistema de Recomendación Híbrido con Random Forest

1. Introducción

Este script implementa un sistema de recomendación de ciudades basado en Random Forest Regressor, un algoritmo de aprendizaje supervisado. A diferencia de los enfoques basados en similitud (como KNN), este sistema utiliza datos históricos de usuarios con ratings reales para aprender patrones complejos entre las características de los usuarios, las características de las ciudades y los ratings que los usuarios asignaron.

Propósito

El recomendador híbrido permite:

  • Entrenar un modelo supervisado con historial de usuarios y sus ratings
  • Aprender patrones complejos entre características de usuario y ciudad
  • Predecir qué rating daría un usuario a cada ciudad disponible
  • Generar recomendaciones basadas en ratings predichos (mayor rating = mejor recomendación)

Algoritmo

El script utiliza Random Forest Regressor con:

  • Algoritmo: Ensemble de árboles de decisión (100 árboles por defecto)
  • Enfoque: Aprendizaje supervisado (requiere datos históricos con ratings)
  • Modelo híbrido: Combina características del usuario con características de la ciudad
  • Ventajas: Robusto a outliers, captura interacciones no lineales, no requiere normalización estricta

Diferencia con KNN-recomendation.py

Característica KNN Random Forest
Enfoque No supervisado (similitud) Supervisado (aprendizaje)
Datos requeridos Solo CSV de ciudades CSV de ciudades + CSV de historial con ratings
Output Score de similitud (0-1) Rating predicho (valor numérico)
Aprendizaje No aprende de datos históricos Aprende patrones de ratings históricos
Uso recomendado Cuando no hay datos históricos Cuando hay historial de usuarios con ratings

2. Arquitectura y Funcionamiento

Clase Principal: HybridRecommender

La clase HybridRecommender encapsula toda la lógica del sistema de recomendación híbrido.

Componentes Principales

  1. Modelo Random Forest (self.model)

    • Instancia de RandomForestRegressor de scikit-learn
    • Configurado con 100 estimadores (árboles) y random_state=42 para reproducibilidad
    • Se entrena con datos combinados: [User_Features] + [City_Features] → Rating
  2. Base de Datos de Ciudades (self.cities_df)

    • DataFrame de pandas que contiene toda la información de las ciudades
    • Incluye nombres de ciudades y todas sus características numéricas
    • Se guarda junto con el modelo para permitir predicciones futuras
  3. Orden de Features (feature_order)

    • Se guarda el orden exacto de las columnas usadas en el entrenamiento
    • Crítico para asegurar que las predicciones usen el mismo orden de features

Flujo de Trabajo

Entrenamiento:
CSV Ciudades + CSV Historial → JOIN por nombre → Combinar features → Entrenar Random Forest → Guardar modelo

Predicción:
Cargar modelo → Replicar features usuario → Combinar con features ciudades → Predecir ratings → Ordenar por rating

3. Métodos Principales

train(cities_path: str, history_path: str, model_out: str)

Entrena el modelo Random Forest combinando el historial de usuarios con las características de las ciudades.

Proceso:

  1. Carga de datos:

    • Lee el CSV de ciudades (cities_path)
    • Lee el CSV de historial (history_path)
  2. Feature Engineering - JOIN:

    • Realiza un JOIN entre df_history y df_cities usando City_Name (historial) y City (ciudades)
    • El resultado contiene: [User_F1..F10] + [City_F1..F10] + [Rating]
  3. Preparación de datos:

    • Excluye columnas no numéricas: City_Name, City, Rating
    • Todas las demás columnas se usan como features (X)
    • Rating es el target (y)
  4. Entrenamiento:

    • Entrena el Random Forest con los datos combinados
    • El modelo aprende: [User_Features + City_Features] → Rating
  5. Persistencia:

    • Guarda un diccionario con:
      • model: Modelo Random Forest entrenado
      • cities_df: Base de datos completa de ciudades
      • feature_order: Orden exacto de las columnas usadas

Parámetros:

  • cities_path: Ruta al archivo CSV con los datos de ciudades
  • history_path: Ruta al archivo CSV con el historial de usuarios y ratings
  • model_out: Ruta donde guardar el modelo entrenado (.pkl)

Salida:

  • Mensaje indicando cuántos registros históricos se usaron para entrenar
  • Mensaje confirmando dónde se guardó el modelo

predict(model_path: str, user_features: list)

Predice qué rating daría un usuario a cada ciudad disponible.

Proceso:

  1. Carga del modelo:

    • Valida que el archivo del modelo exista
    • Carga el diccionario con el modelo, ciudades y orden de features
  2. Preparación de datos de predicción:

    • Replica las 10 features del usuario tantas veces como ciudades hay
    • Crea un DataFrame con las features del usuario (User_F1 a User_F10)
    • Obtiene las features numéricas de todas las ciudades
    • Concatena horizontalmente: [User_Features] + [City_Features] para cada ciudad
  3. Predicción:

    • El modelo predice un rating para cada combinación usuario-ciudad
    • Cada predicción representa qué rating daría ese usuario a esa ciudad
  4. Formateo de resultados:

    • Añade la columna Predicted_Rating al DataFrame de ciudades
    • Ordena las ciudades por rating predicho descendente (mejores primero)

Parámetros:

  • model_path: Ruta al archivo .pkl del modelo entrenado
  • user_features: Lista de 10 valores numéricos representando las características del usuario

Retorna:

  • DataFrame con todas las ciudades ordenadas por Predicted_Rating descendente
  • Incluye todas las columnas originales de las ciudades más la columna Predicted_Rating

Excepciones:

  • FileNotFoundError: Si el archivo del modelo no existe

4. Requisitos de Datos

Formato del CSV de Ciudades

El archivo CSV de ciudades debe cumplir con la siguiente estructura:

  1. Columna City: Nombre de la ciudad (texto) - REQUERIDA para el JOIN
  2. Siguientes columnas: Características numéricas de la ciudad (pueden ser 10 o más)

Estructura esperada:

City,Caracteristica1,Caracteristica2,Caracteristica3,Caracteristica4,Caracteristica5,Caracteristica6,Caracteristica7,Caracteristica8,Caracteristica9,Caracteristica10
Barcelona,8.5,7.2,9.0,6.5,8.0,7.8,9.2,6.0,8.5,7.5
Madrid,7.8,8.0,8.5,7.2,7.5,8.2,8.0,7.8,7.0,8.5
Tokyo,9.0,9.5,8.5,9.2,6.0,8.8,9.0,8.5,9.0,8.7

Requisitos:

  • Debe tener encabezados (nombres de columnas)
  • La columna City debe existir y contener los nombres de las ciudades
  • Las características deben ser valores numéricos (int o float)
  • No deben existir valores faltantes (NaN) en las columnas numéricas

Formato del CSV de Historial

El archivo CSV de historial es crítico para el entrenamiento. Debe contener:

  1. 10 columnas de características del usuario: F1, F2, F3, ..., F10
  2. Columna City_Name: Nombre de la ciudad visitada (debe coincidir con City del CSV de ciudades)
  3. Columna Rating: Rating que el usuario dio a esa ciudad (target para el modelo)

Estructura esperada:

F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,City_Name,Rating
6,3,10,7,4,6,9,2,6,10,Bali,8.4
10,7,4,3,7,7,2,5,4,1,Oslo,7.2
7,5,1,4,0,9,5,8,0,10,Tokyo,6.5

Ejemplo completo con datos sintéticos:

F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,City_Name,Rating
6,3,10,7,4,6,9,2,6,10,Bali,8.4
10,7,4,3,7,7,2,5,4,1,Oslo,7.2
7,5,1,4,0,9,5,8,0,10,Tokyo,6.5
10,9,2,6,3,8,2,4,2,6,Dubai,7.7
4,8,6,1,3,8,1,9,8,9,Medellin,7.4
4,1,3,6,7,2,0,3,1,7,Berlin,6.3
3,1,5,5,9,3,5,1,9,1,New York,5.6
9,3,7,6,8,7,4,1,4,7,Berlin,6.9
9,8,8,0,8,6,8,7,0,7,Buenos Aires,6.9
7,10,2,0,7,2,2,0,10,4,Madrid,6.3
9,6,9,8,6,8,7,1,0,6,Medellin,8.6
6,7,4,2,7,5,10,2,0,2,Buenos Aires,6.0
4,2,0,4,9,6,6,10,8,9,Tokyo,7.6
9,2,6,0,3,3,4,6,6,10,New York,6.4
3,6,10,2,5,1,9,8,4,5,Oslo,8.1
3,10,9,6,8,6,0,0,8,10,Medellin,6.3
8,3,8,2,6,5,7,10,8,4,Medellin,7.5
0,2,9,7,10,5,7,8,3,0,Madrid,7.4
0,9,3,6,1,2,0,4,0,7,Sydney,5.1
0,10,0,1,1,5,6,4,0,0,Medellin,5.1

Requisitos críticos:

  • Orden de columnas: F1, F2, ..., F10, City_Name, Rating (en ese orden)
  • City_Name debe coincidir: Los nombres en City_Name deben existir en la columna City del CSV de ciudades
  • Rating numérico: Debe ser un valor numérico (float o int), típicamente en escala 0-10
  • Múltiples usuarios: Puede contener historial de múltiples usuarios (el modelo aprende patrones generales)
  • Múltiples ratings por ciudad: Una misma ciudad puede aparecer múltiples veces con diferentes usuarios/ratings

Interpretación de Ratings:

  • 0-2: Muy bajo / No le gustó
  • 3-4: Bajo / Poco satisfactorio
  • 5-6: Medio / Aceptable
  • 7-8: Alto / Muy satisfactorio
  • 9-10: Muy alto / Excelente

Características del Usuario para Predicción

Para realizar predicciones, se requieren 10 valores numéricos que representan las características del usuario.

Formato:

  • 10 valores numéricos (float) separados por espacios
  • Cada valor representa una característica del usuario
  • El orden debe ser: F1, F2, F3, ..., F10

Ejemplo:

8.5 7.2 9.0 6.5 8.0 7.8 9.2 6.0 8.5 7.5

Importante: Las características del usuario deben representar los mismos aspectos que las características F1-F10 en el CSV de historial. El orden es crítico.

5. Uso del Script

El script se ejecuta desde la línea de comandos y soporta dos subcomandos principales.

Comando: train

Entrena el modelo con archivos CSV de ciudades e historial, y lo guarda en disco.

Sintaxis:

python Random-Forest-Predictivo.py train --cities <ruta_csv_ciudades> --history <ruta_csv_historial> [--out <archivo_modelo>]

Parámetros:

  • --cities (requerido): Ruta al archivo CSV con los datos de ciudades
  • --history (requerido): Ruta al archivo CSV con el historial de usuarios y ratings
  • --out (opcional): Nombre del archivo donde guardar el modelo. Por defecto: hybrid_model.pkl

Ejemplo:

python Random-Forest-Predictivo.py train --cities ciudades.csv --history historial.csv --out mi_modelo.pkl

Salida esperada:

Entrenando con 20 registros históricos...
Modelo híbrido guardado en: mi_modelo.pkl

Comando: predict

Carga un modelo pre-entrenado y predice ratings para todas las ciudades basándose en las características del usuario.

Sintaxis:

python Random-Forest-Predictivo.py predict [--model <archivo_modelo>] <característica1> <característica2> ... <característica10>

Parámetros:

  • --model (opcional): Ruta al archivo del modelo entrenado. Por defecto: hybrid_model.pkl
  • features (requerido): 10 valores numéricos separados por espacios, representando las características del usuario (F1 a F10)

Ejemplo:

python Random-Forest-Predictivo.py predict --model mi_modelo.pkl 8.5 7.2 9.0 6.5 8.0 7.8 9.2 6.0 8.5 7.5

Salida esperada:

                City  Predicted_Rating
          Barcelona              8.45
             Madrid              8.12
            Tokyo               7.89
            Oslo                7.65
         Medellin               7.43

6. Salidas del Script

Formato del Archivo .pkl

El modelo se guarda en formato .pkl usando la librería joblib, que es más eficiente que pickle para objetos de NumPy y scikit-learn.

Contenido del Diccionario Guardado

El archivo .pkl contiene un diccionario con tres claves:

{
    'model': RandomForestRegressor,      # Modelo Random Forest entrenado
    'cities_df': DataFrame,              # Base de datos completa de ciudades
    'feature_order': list                 # Orden exacto de columnas usadas en entrenamiento
}

Importancia de la Persistencia

Es crítico guardar los tres componentes juntos porque:

  • El modelo Random Forest contiene los árboles entrenados que aprendieron los patrones
  • La base de datos de ciudades contiene los nombres y características para generar predicciones
  • El orden de features asegura que las predicciones usen el mismo orden que el entrenamiento

Salida de Predicción

El método predict() retorna un DataFrame con:

  • Todas las ciudades de la base de datos
  • Todas las columnas originales del CSV de ciudades
  • Columna Predicted_Rating: Rating predicho (valor numérico, típicamente 0-10)
  • Ordenadas por Predicted_Rating descendente (mejores recomendaciones primero)

Interpretación de Ratings Predichos:

  • Rating >= 8.0: Muy alta satisfacción esperada, excelente recomendación
  • Rating >= 7.0: Alta satisfacción esperada, buena recomendación
  • Rating >= 6.0: Satisfacción media esperada, opción aceptable
  • Rating >= 5.0: Satisfacción baja esperada, considerar otras opciones
  • Rating < 5.0: Baja satisfacción esperada, no recomendado

7. Dependencias

El script requiere las siguientes librerías de Python:

Librerías Estándar

  • argparse: Manejo de argumentos de línea de comandos
  • sys: Funciones del sistema
  • os: Operaciones del sistema de archivos

Librerías Externas

Instalar con pip:

pip install pandas numpy scikit-learn joblib

Dependencias:

  • pandas: Manipulación y análisis de datos (lectura de CSV, DataFrames, JOINs)
  • numpy: Operaciones numéricas y arrays (replicación de features)
  • scikit-learn: Algoritmos de machine learning (RandomForestRegressor)
  • joblib: Serialización eficiente de objetos Python (guardado/carga de modelos)

Versiones Recomendadas

  • Python 3.7 o superior
  • pandas >= 1.0.0
  • numpy >= 1.18.0
  • scikit-learn >= 0.22.0
  • joblib >= 0.14.0

8. Ejemplo Completo de Uso

Paso 1: Preparar los Datos

Archivo ciudades.csv:

City,Seguridad,Transporte,Cultura,Gastronomia,Naturaleza,Entretenimiento,Educacion,Salud,Economia,CalidadVida
Barcelona,8.5,9.0,9.5,9.2,7.0,8.8,8.5,8.0,7.5,8.7
Madrid,8.0,9.2,9.0,8.8,6.5,9.0,9.2,8.5,8.0,8.5
Tokyo,9.0,9.5,8.5,9.2,6.0,8.8,9.0,8.5,9.0,8.7
Oslo,9.5,8.5,7.5,7.0,9.5,7.0,8.0,9.0,8.5,9.2
Dubai,8.0,8.0,6.5,7.5,5.0,8.5,7.0,8.0,9.5,8.0
Medellin,7.5,7.0,8.0,8.5,8.5,7.5,7.5,7.5,6.5,8.0
Berlin,8.5,8.5,9.0,8.0,7.0,8.5,8.5,8.5,7.5,8.5
New York,7.5,8.0,9.5,9.0,6.0,9.5,9.0,8.0,9.0,8.0
Buenos Aires,7.0,7.5,8.5,9.0,7.0,8.0,7.5,7.0,6.0,7.5
Sydney,9.0,8.0,8.0,8.5,8.0,8.0,8.5,9.0,8.0,9.0
Bali,8.0,6.0,7.0,7.5,9.5,7.5,6.0,7.0,5.5,8.5

Archivo historial.csv:

F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,City_Name,Rating
6,3,10,7,4,6,9,2,6,10,Bali,8.4
10,7,4,3,7,7,2,5,4,1,Oslo,7.2
7,5,1,4,0,9,5,8,0,10,Tokyo,6.5
10,9,2,6,3,8,2,4,2,6,Dubai,7.7
4,8,6,1,3,8,1,9,8,9,Medellin,7.4
4,1,3,6,7,2,0,3,1,7,Berlin,6.3
3,1,5,5,9,3,5,1,9,1,New York,5.6
9,3,7,6,8,7,4,1,4,7,Berlin,6.9
9,8,8,0,8,6,8,7,0,7,Buenos Aires,6.9
7,10,2,0,7,2,2,0,10,4,Madrid,6.3
9,6,9,8,6,8,7,1,0,6,Medellin,8.6
6,7,4,2,7,5,10,2,0,2,Buenos Aires,6.0
4,2,0,4,9,6,6,10,8,9,Tokyo,7.6
9,2,6,0,3,3,4,6,6,10,New York,6.4
3,6,10,2,5,1,9,8,4,5,Oslo,8.1
3,10,9,6,8,6,0,0,8,10,Medellin,6.3
8,3,8,2,6,5,7,10,8,4,Medellin,7.5
0,2,9,7,10,5,7,8,3,0,Madrid,7.4
0,9,3,6,1,2,0,4,0,7,Sydney,5.1
0,10,0,1,1,5,6,4,0,0,Medellin,5.1

Paso 2: Entrenar el Modelo

python Random-Forest-Predictivo.py train --cities ciudades.csv --history historial.csv --out hybrid_model.pkl

Salida:

Entrenando con 20 registros históricos...
Modelo híbrido guardado en: hybrid_model.pkl

Paso 3: Generar Predicciones

Supongamos que un usuario tiene las siguientes características (F1 a F10):

  • F1: 8.5 (Seguridad)
  • F2: 7.2 (Transporte)
  • F3: 9.0 (Cultura)
  • F4: 6.5 (Gastronomía)
  • F5: 8.0 (Naturaleza)
  • F6: 7.8 (Entretenimiento)
  • F7: 9.2 (Educación)
  • F8: 6.0 (Salud)
  • F9: 8.5 (Economía)
  • F10: 7.5 (Calidad de Vida)
python Random-Forest-Predictivo.py predict --model hybrid_model.pkl 8.5 7.2 9.0 6.5 8.0 7.8 9.2 6.0 8.5 7.5

Salida esperada:

                City  Predicted_Rating
          Barcelona              8.45
             Madrid              8.12
            Tokyo               7.89
            Oslo                7.65
         Medellin               7.43

Interpretación de Resultados

  1. Barcelona (8.45): El modelo predice que este usuario le daría un rating de 8.45 a Barcelona, lo que indica muy alta satisfacción esperada. Es la mejor recomendación.

  2. Madrid (8.12): También predice alta satisfacción. Buena opción alternativa.

  3. Tokyo (7.89): Satisfacción alta esperada, pero ligeramente menor que las anteriores.

  4. Oslo (7.65): Satisfacción alta, opción viable.

  5. Medellin (7.43): Satisfacción alta pero menor que las opciones anteriores.

9. Consideraciones Importantes

Validación de Datos

Coincidencia de nombres de ciudades:

  • Los nombres en City_Name (historial) deben coincidir exactamente con los nombres en City (ciudades)
  • El JOIN es case-sensitive y debe coincidir exactamente (incluyendo espacios, acentos, etc.)
  • Si una ciudad en el historial no existe en el CSV de ciudades, esa fila se excluirá del entrenamiento

Orden de características:

  • El orden de las características F1-F10 en el historial debe ser consistente
  • El orden de las características del usuario en la predicción debe ser el mismo
  • El script actual no valida explícitamente el orden por nombre de columna (asume orden numérico)

Limitaciones Actuales

  1. Nombres de columnas asumidos:

    • El script asume que las features del usuario se llaman F1-F10 en el historial
    • En predicción, crea columnas User_F1-User_F10, pero no valida que coincidan con el entrenamiento
    • Recomendación para producción: Validar que los nombres de columnas coincidan exactamente
  2. Orden de features:

    • El script asume que el orden numérico se mantiene
    • No valida explícitamente que el orden de features de ciudad sea el mismo
    • Recomendación para producción: Usar feature_order guardado para validar y reordenar columnas
  3. Escalabilidad:

    • Con muchas ciudades (1000+), la predicción replica las features del usuario muchas veces
    • Random Forest es eficiente, pero el proceso de preparación de datos puede ser lento
    • Recomendación: Para bases de datos muy grandes, considerar pre-filtrar ciudades o usar batch processing

Mejores Prácticas

  1. Datos de entrenamiento:

    • Mientras más datos históricos, mejor será el modelo
    • Idealmente, tener ratings de múltiples usuarios para cada ciudad
    • Evitar datos desbalanceados (todas las ciudades con ratings similares)
  2. Calidad de datos:

    • Validar que no haya valores faltantes (NaN) en los CSVs
    • Asegurar que los ratings estén en un rango consistente (ej: 0-10)
    • Revisar outliers en ratings que puedan afectar el modelo
  3. Reentrenamiento:

    • Si se añaden nuevas ciudades o se actualiza el historial, reentrenar el modelo
    • Guardar versiones del modelo para comparar performance
    • Considerar validación cruzada para evaluar la calidad del modelo
  4. Validación del modelo:

    • El script actual no incluye métricas de evaluación (R², MAE, RMSE)
    • Recomendación: Añadir evaluación del modelo en producción usando un conjunto de prueba

Comparación: ¿Cuándo usar Random Forest vs KNN?

Usa Random Forest cuando:

  • Tienes datos históricos de usuarios con ratings reales
  • Quieres predecir ratings numéricos específicos
  • Necesitas capturar interacciones complejas entre usuario y ciudad
  • Tienes suficientes datos históricos (mínimo 20-30 registros, idealmente 100+)

Usa KNN cuando:

  • No tienes datos históricos con ratings
  • Solo quieres encontrar ciudades similares a las preferencias del usuario
  • Necesitas un sistema más simple y rápido de implementar
  • Tienes solo el CSV de ciudades sin historial de usuarios

Notas de Producción

  1. Versionado del modelo:

    • Guardar modelos con timestamps o versiones
    • Documentar qué datos se usaron para entrenar cada modelo
  2. Manejo de errores:

    • El script valida que el modelo exista antes de predecir
    • No valida exhaustivamente el formato de los CSVs
    • Recomendación: Añadir validaciones más robustas en producción
  3. Performance:

    • Random Forest con 100 árboles es rápido para entrenar (< 1 minuto con 1000 registros)
    • Predicción es muy rápida (< 1 segundo para 100 ciudades)
    • Para bases de datos muy grandes, considerar reducir n_estimators o usar modelos más ligeros
  4. Reproducibilidad:

    • El modelo usa random_state=42 para reproducibilidad
    • Mismo conjunto de datos siempre produce el mismo modelo
    • Cambios en los datos o parámetros producirán modelos diferentes