Pipeline de Machine Learning para Clasificación de Tickets
Resumen
¿Cómo implementar un pipeline para la clasificación de tickets?
Desarrollar un pipeline de machine learning robusto es esencial para manejar procesos automatizados de análisis de datos. En este contexto, vamos a implementar un pipeline enfocado en la clasificación de tickets, integrando procesos de procesamiento de datos y entrenamiento del modelo en un flujo eficaz utilizando herramientas como Visual Studio Code y bibliotecas relevantes.
¿Cómo configurar el entorno de trabajo?
Antes de comenzar a desarrollar nuestro pipeline, es fundamental preparar el entorno de trabajo. Se proporcionan dos archivos importantes:
config.py:
Aloja variables cruciales para el flujo de trabajo, incluyendo rutas de almacenamiento de datos y configuraciones de parámetros del modelo.
Permite versatilidad al incluir una versión configurable, ayudando a identificar ejecuciones específicas del pipeline.
# Ejemplo básico de estructura
config ={"data_path":"ruta_datos_procesados","version":2,"language":"inglés","filename_input":"nombre_entrada","model_params":{"param1":"value1","param2":"value2"},}
utils.py:
Incluye funciones auxiliares no definidas como tareas, pero útiles para el flujo de trabajo general, como la decodificación de etiquetas o el almacenamiento y carga de objetos con picle.
¿Cómo integrar las tareas en el flow?
Iniciando con el desarrollo del flow, se importa una serie de librerías:
Scikit-learn para entrenamiento y métricas de modelo.
Prefect para orquestar el pipeline.
Módulos personalizados para procesamiento de texto y extracción de características.
¿Cómo se define una tarea de procesamiento de texto?
Crear una tarea que gestione el procesamiento de texto es esencial para preparar datos para el modelo.
¿Cómo se ejecuta la extracción de características?
La extracción de características permite estructurar los datos de manera más efectiva para el modelo.
@task(retries=3, retry_delay_seconds=60, name="featureExtractionTask", tags=["feature_engineering"])def feature_extraction(data_path: str,version: int): feature_processor =FeatureExtractionProcessor() features = feature_processor.run(data_path, version)return features
¿Cómo se ejecuta todo el pipeline?
Una vez definidas las tareas, se integran dentro de un flow:
from prefect importFlow# Definición del flow
withFlow("Ticket Classification Pipeline")asflow: processed_data =text_processing(config['language'], config['filename_input'], config['version']) features =feature_extraction(config['data_path'], config['version'])flow.run()
Este flujo ejecuta primero el procesamiento de texto y luego la extracción de características, asegurando que los datos estén adecuadamente preparados para el modelo.
¿Cuáles son los siguientes pasos?
Con el pipeline en marcha, el siguiente paso será integrar nuevas tareas para completar la ejecución de los procesos necesarios para el entrenamiento y evaluación del modelo. Esto incluye tareas para aplicar transformaciones a los datos, manejar hiperparámetros y evaluar la precisión del modelo. Continuar explorando y mejorando la robustez de tu pipeline asegurará no solo resultados precisos, sino también eficientes, lo cual es fundamental para cualquier proyecto de machine learning.
Quiero hacer un aporte constructivo para complementar lo aprendido, pensando en lo que los DS se encontrarán en entornos productivos reales. Aunque mencionas la importancia de las buenas prácticas, he notado algunas oportunidades de mejora técnica en el código para alinearlo con los estándares actuales de la industria:
Persistencia de Modelos (joblib vs pickle): En los ejemplos se usa pickle. Si bien funciona, para modelos de Machine Learning y arrays grandes, el estándar de facto es joblib. Es mucho más eficiente en manejo de memoria y rendimiento que pickle puro.
Portabilidad (Rutas): El uso de rutas absolutas suele romper los pipelines de CI/CD. Lo ideal es promover siempre rutas relativas o el uso de pathlib.
Orden de Imports: Para mantener el código limpio, es vital seguir el orden estricto de PEP 8 (Nativas > Terceros > Locales). Además, dentro de cada sección, la convención es colocar primero los import puros y luego los from ... import ..., manteniendo todo estrictamente alfabético. También es crucial evitar los wildcard imports (import *) que ocultan dependencias.
Formateo Automático y Mantenibilidad (Black/Ruff): En la función completa que muestras en la imagen, utilizas una “Alineación Visual” tanto en la definición como en la llamada:
Aunque esto es sintácticamente válido, es frágil y difícil de mantener. Si en el futuro cambiaras el nombre de la función feature_extraction_task o la variable feature_extraction_processor, tendrías que reajustar manualmente todos los espacios de las líneas inferiores para que coincidan.
Hoy en día, se recomienda usar formateadores automáticos como Black o Ruff. Estas herramientas automatizan el estándar PEP 8 y convierten esa estructura en un “Hanging Indent”, que es mucho más robusto:
Creo que mencionar estas herramientas (linters y formatters) aportaría muchísimo valor a los estudiantes para que su código sea profesional desde el día uno.
Eficiencia en Logs (Lazy Logging): He notado el uso de f-strings dentro de los logs (ej. logger.info(f"Data {version}")). Pylint suele advertir sobre esto (regla logging-fstring-interpolation). La razón es que la f-string se evalúa siempre, incluso si el log está desactivado, desperdiciando recursos. La buena práctica es usar la interpolación nativa del logger:
logger.info("Data %s", version)
para aprovechar la evaluación perezosa (lazy evaluation).
Creo que mencionar estas herramientas (linters y formatters) aportaría muchísimo valor a los estudiantes para que su código sea profesional y eficiente desde el día uno.
muchas gracias por tu aporte! no sabia lo del joblib en vez del pickle, ni de la alineacion
Si en lugar de tener un archivo de datos, deseo extraer los datos directamente de una base de datos, data_path deberia deberia ser algo parecido al metodo create_engine() de sqlalchemy ???
Para extraer datos directamente de una base de datos, se utiliza la conexión configurada, como el método create_engine() de SQLModel o SQLAlchemy, el cual utiliza la URL de la base de datos definida en las variables de entorno.