DEV Community

Jesus Oviedo Riquelme
Jesus Oviedo Riquelme

Posted on

MLZC25-15. Usando el Modelo: Del Laboratorio al Mundo Real

🎯 Objetivo del Post: Aprenderás a llevar tu modelo desde el notebook de desarrollo hasta un sistema en producción, incluyendo despliegue, monitoreo y mejores prácticas profesionales.

🚀 ¿Qué Significa "Usar el Modelo"?

Después de todo el trabajo de preparación de datos, entrenamiento y optimización, llega el momento más emocionante: usar nuestro modelo para hacer predicciones reales. Pero usar un modelo no es solo hacer model.predict(). Implica un proceso completo de despliegue, monitoreo y mantenimiento.

💡 Definición Profesional: Usar el modelo significa integrarlo en un sistema que pueda tomar decisiones basadas en predicciones automáticas, de manera confiable y escalable.

🔄 Del Notebook al Mundo Real

📝 En el Notebook (Desarrollo)

# Esto es lo que hemos estado haciendo (simple pero funcional)
modelo = Ridge(alpha=10)
modelo.fit(X_train, y_train)
prediccion = modelo.predict(X_nuevo)
print(f"Precio predicho: ${prediccion[0]:,.2f}")
Enter fullscreen mode Exit fullscreen mode

🌍 En Producción (Mundo Real)

# Esto es lo que necesitamos para usar el modelo realmente (robusto y escalable)
class PrediccionPreciosAutos:
    def __init__(self):
        self.modelo = None
        self.scaler = None
        self.columnas_esperadas = None

    def cargar_modelo(self, ruta_modelo, ruta_scaler):
        """Cargar modelo y preprocesador desde archivos"""
        import pickle

        with open(ruta_modelo, 'rb') as f:
            self.modelo = pickle.load(f)

        with open(ruta_scaler, 'rb') as f:
            self.scaler = pickle.load(f)

        # Cargar información de columnas
        with open('columnas_esperadas.pkl', 'rb') as f:
            self.columnas_esperadas = pickle.load(f)

    def predecir_precio(self, datos_auto):
        """Predecir precio de un auto específico"""
        # Validar entrada
        if not self._validar_entrada(datos_auto):
            return None

        # Preparar datos
        datos_procesados = self._procesar_entrada(datos_auto)

        # Hacer predicción
        prediccion = self.modelo.predict(datos_procesados)

        return {
            'precio_predicho': float(prediccion[0]),
            'confianza': self._calcular_confianza(datos_procesados),
            'fecha_prediccion': datetime.now().isoformat()
        }
Enter fullscreen mode Exit fullscreen mode

Tipos de Uso del Modelo

1. Predicción Individual (One-off)

Para predecir el precio de un auto específico:

# Datos de un auto específico
auto_ejemplo = {
    'marca': 'BMW',
    'modelo': '3 Series',
    'año': 2020,
    'kilometraje': 25000,
    'transmision': 'AUTOMATIC',
    'engine_hp': 255,
    'engine_cylinders': 4
}

# Usar el modelo
prediccion = modelo.predict(auto_ejemplo)
print(f"Precio estimado: ${prediccion:,.2f}")
Enter fullscreen mode Exit fullscreen mode

2. Predicción por Lotes (Batch)

Para procesar múltiples autos a la vez:

# Lista de autos
autos_lote = [
    {'marca': 'Toyota', 'modelo': 'Camry', 'año': 2019, 'kilometraje': 30000},
    {'marca': 'Honda', 'modelo': 'Civic', 'año': 2021, 'kilometraje': 15000},
    {'marca': 'BMW', 'modelo': 'X5', 'año': 2020, 'kilometraje': 20000}
]

# Procesar lote
predicciones = []
for auto in autos_lote:
    precio = modelo.predict(auto)
    predicciones.append({
        'auto': f"{auto['marca']} {auto['modelo']}",
        'precio_predicho': precio
    })

# Crear DataFrame con resultados
resultados = pd.DataFrame(predicciones)
print(resultados)
Enter fullscreen mode Exit fullscreen mode

3. API Web (Tiempo Real)

Crear una API para que otros sistemas puedan usar nuestro modelo:

from flask import Flask, request, jsonify
import pickle
import pandas as pd

app = Flask(__name__)

# Cargar modelo al iniciar la aplicación
with open('modelo_entrenado.pkl', 'rb') as f:
    modelo = pickle.load(f)

@app.route('/predict', methods=['POST'])
def predecir_precio():
    """Endpoint para predecir precio de auto"""
    try:
        # Obtener datos del request
        datos = request.json

        # Validar datos requeridos
        campos_requeridos = ['marca', 'modelo', 'año', 'kilometraje']
        for campo in campos_requeridos:
            if campo not in datos:
                return jsonify({'error': f'Campo {campo} es requerido'}), 400

        # Preparar datos para el modelo
        datos_modelo = pd.DataFrame([datos])

        # Hacer predicción
        precio_predicho = modelo.predict(datos_modelo)[0]

        # Devolver resultado
        return jsonify({
            'precio_predicho': float(precio_predicho),
            'status': 'success'
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

Guardando y Cargando el Modelo

Guardar el Modelo Entrenado

import pickle
import joblib

# Opción 1: Usando pickle
with open('modelo_precios_autos.pkl', 'wb') as f:
    pickle.dump(modelo, f)

# Opción 2: Usando joblib (más eficiente para modelos grandes)
joblib.dump(modelo, 'modelo_precios_autos.joblib')

# Guardar también el scaler y las columnas
joblib.dump(scaler, 'scaler.joblib')
joblib.dump(list(X.columns), 'columnas_esperadas.joblib')

print("Modelo guardado exitosamente")
Enter fullscreen mode Exit fullscreen mode

Cargar el Modelo

# Cargar modelo
modelo_cargado = joblib.load('modelo_precios_autos.joblib')
scaler_cargado = joblib.load('scaler.joblib')
columnas_esperadas = joblib.load('columnas_esperadas.joblib')

# Usar el modelo cargado
def predecir_con_modelo_cargado(datos_auto):
    # Convertir a DataFrame
    df_auto = pd.DataFrame([datos_auto])

    # Asegurar que tiene las columnas correctas
    for columna in columnas_esperadas:
        if columna not in df_auto.columns:
            df_auto[columna] = 0  # Valor por defecto

    # Reordenar columnas
    df_auto = df_auto[columnas_esperadas]

    # Normalizar
    df_auto_scaled = scaler_cargado.transform(df_auto)

    # Predecir
    precio = modelo_cargado.predict(df_auto_scaled)[0]

    return precio

# Ejemplo de uso
auto_nuevo = {
    'marca_BMW': 1,
    'marca_Toyota': 0,
    'año': 2020,
    'kilometraje': 25000,
    'engine_hp': 255
}

precio = predecir_con_modelo_cargado(auto_nuevo)
print(f"Precio predicho: ${precio:,.2f}")
Enter fullscreen mode Exit fullscreen mode

Validación de Entrada

Validar Datos Antes de Predecir

class ValidadorDatos:
    @staticmethod
    def validar_auto(datos_auto):
        """Validar que los datos del auto sean correctos"""
        errores = []

        # Validar año
        if 'año' in datos_auto:
            año = datos_auto['año']
            if not isinstance(año, (int, float)) or año < 1990 or año > 2024:
                errores.append("Año debe ser un número entre 1990 y 2024")

        # Validar kilometraje
        if 'kilometraje' in datos_auto:
            km = datos_auto['kilometraje']
            if not isinstance(km, (int, float)) or km < 0 or km > 500000:
                errores.append("Kilometraje debe ser un número positivo menor a 500,000")

        # Validar marca
        marcas_validas = ['BMW', 'Toyota', 'Honda', 'Audi', 'Mercedes-Benz']
        if 'marca' in datos_auto:
            if datos_auto['marca'] not in marcas_validas:
                errores.append(f"Marca debe ser una de: {', '.join(marcas_validas)}")

        return errores

# Usar validador
validador = ValidadorDatos()
datos_auto = {
    'marca': 'BMW',
    'año': 2020,
    'kilometraje': 25000
}

errores = validador.validar_auto(datos_auto)
if errores:
    print("Errores encontrados:")
    for error in errores:
        print(f"- {error}")
else:
    print("Datos válidos, procediendo con predicción")
    precio = predecir_con_modelo_cargado(datos_auto)
    print(f"Precio predicho: ${precio:,.2f}")
Enter fullscreen mode Exit fullscreen mode

Monitoreo del Modelo

Tracking de Predicciones

import logging
from datetime import datetime

# Configurar logging
logging.basicConfig(
    filename='predicciones.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class MonitorModelo:
    def __init__(self):
        self.predicciones_dia = 0
        self.predicciones_totales = 0

    def registrar_prediccion(self, datos_entrada, prediccion, confianza=None):
        """Registrar una predicción para monitoreo"""
        timestamp = datetime.now()

        # Incrementar contadores
        self.predicciones_totales += 1
        if timestamp.date() == datetime.now().date():
            self.predicciones_dia += 1

        # Log de la predicción
        log_info = {
            'timestamp': timestamp.isoformat(),
            'datos_entrada': datos_entrada,
            'prediccion': float(prediccion),
            'confianza': confianza
        }

        logging.info(f"Predicción realizada: {log_info}")

        return log_info

    def obtener_estadisticas(self):
        """Obtener estadísticas del modelo"""
        return {
            'predicciones_totales': self.predicciones_totales,
            'predicciones_hoy': self.predicciones_dia,
            'fecha_ultimo_uso': datetime.now().isoformat()
        }

# Usar monitor
monitor = MonitorModelo()

def predecir_con_monitoreo(datos_auto):
    # Hacer predicción
    precio = predecir_con_modelo_cargado(datos_auto)

    # Registrar en monitor
    monitor.registrar_prediccion(datos_auto, precio)

    return precio

# Ejemplo de uso
auto = {'marca': 'BMW', 'año': 2020, 'kilometraje': 25000}
precio = predecir_con_monitoreo(auto)
print(f"Precio: ${precio:,.2f}")
print(f"Estadísticas: {monitor.obtener_estadisticas()}")
Enter fullscreen mode Exit fullscreen mode

Interfaz de Usuario Simple

Aplicación Web Básica

import streamlit as st
import pandas as pd

# Configurar página
st.set_page_config(page_title="Predicción de Precios de Autos", page_icon="🚗")

st.title("🚗 Predicción de Precios de Autos")
st.markdown("Ingresa las características de tu auto para obtener una estimación de precio")

# Formulario de entrada
with st.form("form_prediccion"):
    col1, col2 = st.columns(2)

    with col1:
        marca = st.selectbox("Marca", ["BMW", "Toyota", "Honda", "Audi", "Mercedes-Benz"])
        año = st.number_input("Año", min_value=1990, max_value=2024, value=2020)
        kilometraje = st.number_input("Kilometraje", min_value=0, max_value=500000, value=25000)

    with col2:
        modelo = st.text_input("Modelo", value="3 Series")
        transmision = st.selectbox("Transmisión", ["MANUAL", "AUTOMATIC", "AUTOMATED_MANUAL"])
        engine_hp = st.number_input("Potencia del Motor (HP)", min_value=50, max_value=700, value=255)

    submitted = st.form_submit_button("Predecir Precio")

    if submitted:
        # Preparar datos
        datos_auto = {
            'marca': marca,
            'modelo': modelo,
            'año': año,
            'kilometraje': kilometraje,
            'transmision': transmision,
            'engine_hp': engine_hp
        }

        # Hacer predicción
        try:
            precio = predecir_con_modelo_cargado(datos_auto)

            # Mostrar resultado
            st.success(f"💰 Precio estimado: **${precio:,.2f}**")

            # Mostrar detalles
            with st.expander("Ver detalles de la predicción"):
                st.json(datos_auto)

        except Exception as e:
            st.error(f"Error al hacer predicción: {str(e)}")

# Estadísticas del modelo
st.sidebar.title("📊 Estadísticas del Modelo")
estadisticas = monitor.obtener_estadisticas()
st.sidebar.metric("Predicciones Totales", estadisticas['predicciones_totales'])
st.sidebar.metric("Predicciones Hoy", estadisticas['predicciones_hoy'])
Enter fullscreen mode Exit fullscreen mode

Mejores Prácticas para Usar el Modelo

1. Manejo de Errores Robusto

def predecir_seguro(datos_auto):
    try:
        # Validar entrada
        errores = ValidadorDatos.validar_auto(datos_auto)
        if errores:
            return {'error': 'Datos inválidos', 'detalles': errores}

        # Hacer predicción
        precio = predecir_con_modelo_cargado(datos_auto)

        return {'precio': precio, 'status': 'success'}

    except Exception as e:
        logging.error(f"Error en predicción: {str(e)}")
        return {'error': 'Error interno del servidor', 'status': 'error'}
Enter fullscreen mode Exit fullscreen mode

2. Versionado del Modelo

# Guardar modelo con versión
version = "v1.0"
joblib.dump(modelo, f'modelo_precios_autos_{version}.joblib')

# Cargar modelo específico
def cargar_modelo_version(version):
    return joblib.load(f'modelo_precios_autos_{version}.joblib')
Enter fullscreen mode Exit fullscreen mode

3. Configuración Flexible

# Archivo config.yaml
model_config = {
    'model_path': 'modelo_precios_autos_v1.0.joblib',
    'scaler_path': 'scaler_v1.0.joblib',
    'max_price': 200000,
    'min_price': 1000,
    'confidence_threshold': 0.7
}
Enter fullscreen mode Exit fullscreen mode

Errores Comunes al Usar el Modelo

1. Olvidar el Preprocesamiento

# MAL: Usar datos sin preprocesar
precio = modelo.predict(datos_sin_procesar)

# BIEN: Aplicar el mismo preprocesamiento del entrenamiento
datos_procesados = scaler.transform(datos_sin_procesar)
precio = modelo.predict(datos_procesados)
Enter fullscreen mode Exit fullscreen mode

2. No Validar Entrada

# MAL: Confiar en que los datos son correctos
precio = modelo.predict(datos_usuario)

# BIEN: Validar primero
if validar_datos(datos_usuario):
    precio = modelo.predict(datos_usuario)
else:
    return error
Enter fullscreen mode Exit fullscreen mode

3. Ignorar el Monitoreo

# MAL: No registrar predicciones
precio = modelo.predict(datos)

# BIEN: Registrar para monitoreo
precio = modelo.predict(datos)
monitor.registrar_prediccion(datos, precio)
Enter fullscreen mode Exit fullscreen mode

Conclusión

Usar el modelo en producción va mucho más allá de hacer predicciones. Requiere:

  • Preparación cuidadosa: Guardar y cargar modelos correctamente
  • Validación robusta: Verificar datos de entrada
  • Monitoreo continuo: Rastrear el rendimiento del modelo
  • Manejo de errores: Prepararse para situaciones inesperadas
  • Interfaces amigables: Hacer el modelo accesible a usuarios finales

Puntos clave:

  • El modelo debe ser fácil de usar pero seguro
  • Siempre validar datos de entrada
  • Monitorear el rendimiento continuamente
  • Preparar interfaces para diferentes tipos de usuarios
  • Documentar todo el proceso de uso

¡Has completado todo el ciclo de Machine Learning! Desde la preparación de datos hasta el despliegue del modelo en producción. Ahora tienes las herramientas para crear sistemas de ML que realmente funcionen en el mundo real.


¿Has desplegado algún modelo en producción? ¿Qué desafíos has encontrado al usar modelos en el mundo real?

Top comments (0)