[{"content":" ","date":null,"permalink":"/es/","section":"¡Bienvenido a mi página web!","summary":" ","title":"¡Bienvenido a mi página web!"},{"content":" ","date":null,"permalink":"/es/blog/","section":"Blog","summary":" ","title":"Blog"},{"content":" ","date":null,"permalink":"/es/tags/","section":"Etiquetas","summary":" ","title":"Etiquetas"},{"content":"","date":null,"permalink":"/es/tags/gaming/","section":"Etiquetas","summary":"","title":"gaming"},{"content":"","date":null,"permalink":"/es/tags/python/","section":"Etiquetas","summary":"","title":"python"},{"content":" El Contexto: ¿Por Qué Hice Esto? #Llevo un mes jugando este nuevo juego (Path of Exile 2) y, para enfrentar el contenido más difícil, necesitas equipo de alta calidad. Para conseguirlo, necesitas una Superior cantidad de moneda dentro del juego. ¿El problema? La economía es caótica. Los jugadores descubren constantemente nuevas formas de obtener moneda, pero en cuanto un método se vuelve popular, deja de ser rentable.\nComo alguien apasionado por la programación y los datos (y tal vez que pasa demasiado tiempo pensando en hojas de cálculo), pensé:\n\u0026ldquo;¿Por qué no usar mis habilidades de programación para encontrar la mejor forma de hacer moneda?\u0026rdquo;\nAsí que me propuse simular estrategias de conversión de moneda en el juego, centrándome específicamente en la refundición de esencias para determinar si podía encontrar un patrón rentable. Por ejemplo, obtener esencias de nivel superior que se vendan por la mayor cantidad de moneda (Orbes Exaltados).\nEl Problema: Refundición de Esencias en PoE #En PoE, las \u0026ldquo;Esencias\u0026rdquo; son materiales de creación que pueden refundirse en versiones de nivel superior. ¿El truco? Las tasas de éxito son bajas y los resultados son aleatorios. Mi pregunta era simple:\nSi refundiera miles de esencias, ¿obtendría ganancias o me arruinaría?\nPara responder esto, construí un simulador en Python que modela el proceso, incorporando:\nProbabilidades de conversión: Una tasa de éxito del 2.26% para mejoras a un nivel superior (según datos de la comunidad). Precios de mercado: Valores en Orbes Exaltados para cada tipo de esencia (spoiler: Superior Esencia de Celeridad = $$$). Recursos protegidos: Algunas esencias de nivel bajo (como Electricidad) son demasiado valiosas para refundirlas. Construyendo el Simulador #1. Modelando la Economía #Limitaciones del Mundo Real\nLa refundición de esencias tiene restricciones que afectan la simulación:\nEspacio de Inventario: Los jugadores tienen un almacenamiento limitado en el inventario y el baúl. Volatilidad del Mercado: Las esencias baratas son escasas en grandes cantidades y los precios fluctúan rápidamente. Impuestos: Se aplica un impuesto en oro a las transacciones del mercado. Tiempo: La refundición consume tiempo, y los cambios en el mercado pueden borrar las ganancias. Diseño de la Simulación\nPara reflejar estos desafíos, el simulador:\nEjecuta 100,000 intentos de inversión independientes (sin refundiciones infinitas). Cada intento consiste en 1,000 refundiciones como mínimo. Esto representa una inversión asequible, un espacio de inventario razonable, impuestos en oro y tiempo consumido (25 minutos). Rastrea métricas como ganancia promedio, rachas de pérdidas y retornos ajustados al riesgo. Parámetros Clave\nInversión: 1,300 Orbes Exaltados (evita la ruina en el 95% de los escenarios). Entrada de Esencias: 3,000 esencias de nivel bajo (2.3 Exaltados cada una). Mecánica: Éxito (2.26%): Se obtiene una esencia de nivel superior aleatoria. Fracaso: Se recibe una esencia menor aleatoria (excluyendo Electricidad/Celeridad protegidas). # Simplified simulation loop while reforges_possible: consume_3_essences() if success(probability=0.0226): reward = random_greater_essence() else: refund = random_minor_essence() 2. Significancia Estadística #En PoE, la refundición es un juego de extremos. La mayoría de las refundiciones otorgan una esencia de nivel bajo, pero algunas pueden recompensarte con esencias de alto valor como Superior Esencia de Celeridad (vale 186 Exaltados) o Superior Esencia del Infinito (vale 96 Exaltados).\nAquí está el problema:\nCeleridad tiene una tasa de obtención del 0.1%. En promedio, necesitarías hacer 1,000 refundiciones solo para ver una Superior Esencia de Celeridad. Infinito tiene una tasa de obtención del 0.25%. Un poco mejor, pero sigue siendo rara. En mis primeras simulaciones, estos eventos raros distorsionaban los resultados. Una sola gota de Celeridad podía hacer que un intento pareciera increíblemente rentable, mientras que una racha de mala suerte podía acabar con todo mi capital. Esto hacía imposible obtener conclusiones significativas, incluso con 100,000 intentos.\nEl Punto de Inflexión: Escalando la Simulación #Para obtener resultados confiables, me di cuenta de que necesitaba simular muchas más refundiciones.\nLey de los Grandes Números:\nCuantos más ensayos realices, más cerca estarán tus resultados de las verdaderas probabilidades. Con 100,000 intentos (100 millones de refundiciones), podría ver ~100,000 gotas de Celeridad. Pero con 1 millón de intentos (1,000 millones de refundiciones), esperaría ~1,000,000 gotas de Celeridad, lo que daría una imagen mucho más clara de su impacto. Reducción de la Varianza:\nLas muestras pequeñas son ruidosas. Al aumentar la escala, pude suavizar la aleatoriedad y observar las tendencias subyacentes. Captura de Eventos Raros:\nEventos raros como las gotas de Celeridad dominan la distribución de ganancias. Sin suficientes pruebas, su impacto se sobrestima o se subestima. Así que amplié a 1 millón de simulaciones.\nResultados #Ganancia promedio por intento: 385 Exalted (IC 95%: 384–386)\n1. Desglose de ganancias por tipo de esencia #La Esencia Menor de Electricidad es el mayor contribuyente, representando el 30% de la ganancia total, seguida por la Esencia Mayor del Infinito y la Esencia Mayor de Celeridad, con un 18% y 15% respectivamente. A pesar de ser clasificada como una esencia menor, la Esencia Menor de Electricidad tiene un impacto mayor que varias esencias mayores.\nEsencia Contribución a la Ganancia 1 Esencia Menor de Electricidad 30% 2 Esencia Mayor del Infinito 18% 3 Esencia Mayor de Celeridad 15% 4 Esencia Mayor de la Mente 7% 5 Esencia Mayor de Electricidad 6% 6 Esencia Mayor de Hechicería 6% 7 Esencia Mayor del Tormento 4% 8 Esencia Menor de Celeridad 3% 9 Esencia Mayor de Mejora 2% 10 Esencia Mayor de Batalla 1% 2. Probabilidad de Pérdida # Fórmula: \\(\\text{Probabilidad de Pérdida} = \\frac{\\text{Intentos Perdidos}}{\\text{Intentos Totales}} \\)\n\\(\\text{Probabilidad de Pérdida} = 9.8\\% \\)\n3. Ratio de Ganancias/Pérdidas #Fórmula: \\( \\text{Ratio WL} = \\frac{\\text{Probabilidad de Ganancia}}{\\text{Probabilidad de Pérdida}} \\)\n\\( \\text{Ratio WL} = 9.20 \\)\n4. Valor en Riesgo (VaR) #Fórmula: \\( \\text{VaR} = \\text{Percentil de Pérdidas al Nivel de Confianza} \\)\n\\( \\text{VaR}_{95\\%}= 86.85 \\text{ Exalted Orbs} \\)\n5. Retorno Ajustado al Riesgo (Ratio de Sharpe) # Fórmula: \\(\\text{Ratio de Sharpe} = \\frac{\\text{Ganancia Promedio}}{\\text{Desviación Estándar de la Ganancia}} \\)\n\\(\\text{Ratio de Sharpe} = 1.24 \\)\n6. Valor Esperado (EV) por Intento # Fórmula: \\({EV} = (\\text{Ganancia Promedio} \\times \\text{Probabilidad de Ganancia}) - (\\text{Pérdida Promedio} \\times \\text{Probabilidad de Pérdida}) \\)\n\\({EV} = 358.68 \\text{ Exalted Orbs } \\)\nConclusión #Después de simular 1 millón de intentos de refundición (1 billón de refundiciones), los resultados son claros: refundir esencias en Path of Exile 2 es una estrategia de bajo riesgo y alta recompensa, pero solo si estás dispuesto a pasar 30 minutos repitiendo la misma tarea. Esto es lo que nos dicen los números:\nRentabilidad:\nGanancia Promedio: 385 Exalted por intento (IC 95%: 384–386). Ratio de Ganancia/Pérdida: 9.2 (90.2% tasa de ganancia vs. 9.8% tasa de pérdida). Valor Esperado: 358.68 Exalted por intento. Gestión del Riesgo:\nRatio de Sharpe: 1.24. Valor en Riesgo (VaR): El 95% de los intentos pierde \u0026lt;86.85 Exalted. Factores Clave:\nEsencias de Electricidad: Contribuyeron al 30% de las ganancias totales. Celeridad \u0026amp; Infinito: Representaron el 33 ¡Gracias por leer! Si tienes alguna pregunta o comentario, no dudes en contactarme. Aprecio mucho tu retroalimentación.\nKeywords: Python, Simulation, Path of Exile 2, Poe2\n","date":"17 enero 2025","permalink":"/es/blog/simulation-essence-poe2/","section":"Blog","summary":"El Contexto: ¿Por Qué Hice Esto?","title":"Simulaciones de Path of Exile 2: Esencia"},{"content":"","date":null,"permalink":"/es/tags/simulation/","section":"Etiquetas","summary":"","title":"simulation"},{"content":"","date":null,"permalink":"/es/tags/aws/","section":"Etiquetas","summary":"","title":"AWS"},{"content":" Introducción #Los datos son la base de la toma de decisiones en el mundo digital actual. Desde la detección de fraudes hasta la optimización de operaciones empresariales, las organizaciones dependen de pipelines de datos eficientes para ingerir, procesar y analizar grandes cantidades de información. Pero gestionar estos pipelines a gran escala requiere más que bases de datos tradicionales, se necesita una arquitectura robusta y escalable.\nEste proyecto nació de un curso que tomé durante mi maestría en Analítica de Datos, específicamente en Sistemas de Bases de Datos Avanzados, donde nos propusimos diseñar y desplegar un Data Lake en AWS. ¿El objetivo? Construir un sistema capaz de integrar datos de múltiples fuentes de manera fluida mientras garantizábamos eficiencia, automatización y escalabilidad. En lugar de solo configurar servicios, me enfoqué en estructurar un pipeline que pudiera manejar desafíos de datos del mundo real, como procesar datos estructurados y semiestructurados, automatizar la ingestión y optimizar los costos.\nEn este blog, te contaré mi experiencia y a lo largo del camino, resaltaré lecciones clave aprendidas, decisiones arquitectónicas tomadas y mejoras que haría en futuras iteraciones.\nContexto y Antecedentes #Para nuestro proyecto final, el instructor nos dio dos opciones:\n1️⃣ Opción A → Desarrollar un sistema de consultas avanzadas que interactúe con varias bases de datos en la nube.\n2️⃣ Opción B → Construir un Data Lake en AWS, siguiendo una arquitectura de extremo a extremo demostrada en un video de referencia.\nEl video, Building Data Lakes on AWS, proporcionaba una guía paso a paso para configurar un Data Lake utilizando servicios como AWS Glue, Athena y S3. Sin embargo, el instructor dejó claro que no era necesario replicar el video exactamente, dándonos la flexibilidad de modificar la implementación según fuera necesario.\nDecidimos optar por Opción B, pero queríamos evitar AWS Glue para eliminar costos durante el desarrollo. Esto requirió cambios adicionales, como reemplazar Glue por otros servicios de AWS y configurar un programador para automatizar el procesamiento de datos. Estas modificaciones introdujeron nuevos desafíos técnicos y aumentaron la complejidad del proceso de desarrollo.\nVisión General del Proyecto #En su núcleo, este proyecto consistió en construir un Data Lake en la nube utilizando AWS. Pero, ¿qué significa eso en la práctica? Aquí tienes un desglose a alto nivel:\nAlmacenamiento de Datos: Un bucket de AWS S3 sirve como el repositorio principal para los datos entrantes desde las bases de datos. Infraestructura de Base de Datos: Se implementan múltiples bases de datos (MySQL, SQL Server y PostgreSQL) utilizando Amazon RDS. Gestión de Costos con CloudFormation: Se utilizaron plantillas de CloudFormation para desplegar y eliminar bases de datos a diario durante el desarrollo. Este enfoque ayudó a minimizar los costos mientras el proyecto seguía evolucionando. Procesamiento ETL: Las funciones de AWS Lambda se encargan de los procesos de Extract, Transform, Load (ETL) para limpiar y mover los datos. Orquestación: Amazon EventBridge activa y programa las funciones Lambda para procesar los datos de manera eficiente. Seguridad: AWS Secrets Manager garantiza un manejo seguro de las credenciales de las bases de datos. Desafíos y Lecciones Aprendidas #Como en cualquier proyecto técnico, este vino con su parte de desafíos:\nConfiguración de conexiones seguras entre las instancias de RDS y las funciones Lambda. Optimización de costos aprovechando los recursos de la capa gratuita de AWS. Automatización de todo el flujo de trabajo mientras se mantenía la flexibilidad para futuros cambios. Al final, tuve una arquitectura funcional de Data Lake, capaz de ingerir datos desde múltiples fuentes y prepararlos para análisis. No es perfecta, pero es una base sólida.\nEl Viaje Personal #Cada proyecto tiene un lado técnico, pero siempre hay un viaje personal detrás del código. Este proyecto no fue la excepción.\nCómo Comenzó #Configurar un Data Lake en AWS fue una gran oportunidad para trabajar con múltiples servicios de AWS de manera estructurada. Ya estaba familiarizado con AWS, pero este proyecto requería integrar múltiples servicios mientras mantenía los costos bajos. Fue la oportunidad perfecta para aprender, romper cosas y descubrir cómo hacer que funcionen en un escenario del mundo real.\nLa documentación de AWS es útil, pero a menudo se enfoca en cómo configurar los servicios en lugar de por qué ciertas decisiones son importantes. En lugar de simplemente seguir guías, probamos diferentes configuraciones para encontrar el mejor enfoque para nuestro proyecto. Esta experimentación práctica nos ayudó a perfeccionar nuestra arquitectura, solucionar problemas y tomar decisiones informadas.\nDesafíos Clave y Cómo Los Superamos #Problemas de Conectividad de Base de Datos #Antes de lanzar AWS RDS, probamos la conectividad con nuestras bases de datos existentes en Azure y MongoDB. Estas pruebas tempranas nos ayudaron a verificar las interacciones entre las bases de datos, pero debido a las restricciones de tiempo, decidimos alojar todo en Amazon RDS para mantener la consistencia.\nEl siguiente desafío surgió al configurar la red de VPC. Ejecutar Lambda dentro de una VPC requería configurar grupos de seguridad, subredes y gateways NAT. Para depurar el acceso a la red, lanzamos una instancia EC2 dentro de la VPC y la usamos para probar las conexiones a RDS. Esto nos ayudó a identificar y ajustar rápidamente las reglas de seguridad, lo que permitió una comunicación fluida con la base de datos.\nSolución # Utilizamos una instancia EC2 dentro de la VPC para probar las conexiones antes de desplegar las funciones Lambda. Configuramos grupos de seguridad y enrutamiento de subredes para permitir que las funciones Lambda accedieran a RDS de manera segura. Aseguramos que los roles IAM y los puntos finales de VPC estuvieran configurados para una interacción eficiente con la base de datos. Automatización de la Infraestructura con CloudFormation #Tenía experiencia previa con CloudFormation, por lo que desplegar recursos a través de plantillas no fue un desafío. Sin embargo, el principal problema fue asegurarnos de que las configuraciones de bases de datos funcionaran con las instancias de bajo nivel de AWS. Algunos parámetros de RDS no eran compatibles con las instancias de bajo nivel, lo que causaba fallos en el despliegue.\nSolución # Ajustamos los grupos de parámetros de la base de datos para que coincidan con las limitaciones del nivel de instancia. Desplegamos iterativamente pilas de CloudFormation para identificar problemas de compatibilidad de recursos. Este enfoque nos permitió desplegar bases de datos rápidamente y eliminarlas después del desarrollo diario para mantener los costos bajos.\nProcesamiento ETL y Programación de Eventos #El principal desafío con AWS Lambda fue configurar capas personalizadas para manejar las consultas a la base de datos. Necesitábamos bibliotecas externas de Python, pero nos encontramos con limitaciones en la máquina local, límites de tamaño de capa y problemas de compatibilidad de bibliotecas.\nPara resolverlo, usamos nuestra instancia EC2 para construir la capa Lambda, asegurándonos de que todas las dependencias estuvieran correctamente empaquetadas. Luego, la capa se subió a S3 y se vinculó a las funciones Lambda.\nSolución # Construimos la capa Lambda en una instancia EC2 para manejar las dependencias de paquetes. Comprimimos y subimos la capa a S3 para su fácil reutilización. Ajustamos la memoria y el tiempo de espera de las funciones Lambda para mejorar el rendimiento. Una vez que las funciones Lambda estaban funcionando de manera eficiente, las programamos utilizando Amazon EventBridge para automatizar el pipeline ETL.\nLo que Mejoraría la Próxima Vez #🔹 Más automatización: Aunque CloudFormation ayudó, incorporar Terraform podría proporcionar una mayor flexibilidad en la gestión de infraestructura.\n🔹 Registro y monitoreo: Agregar alertas de AWS CloudWatch mejoraría la visibilidad de fallos y el rendimiento del sistema.\nProfundización Técnica #Ahora que hemos cubierto el recorrido, vamos a sumergirnos en los detalles de cómo se construyó este Data Lake. Esta sección desglosará cada componente principal, desde la ingestión de datos hasta el procesamiento y almacenamiento, destacando configuraciones clave y mejores prácticas a lo largo del camino.\nIngestión de Datos: Configuración de AWS S3 como el Data Lake #El primer paso para construir un Data Lake es definir dónde se almacenarán los datos. En este caso, Amazon S3 sirve como la base, actuando como una solución de almacenamiento escalable y rentable.\nCreación del Bucket de S3 #Para configurar el bucket de Data Lake, utilicé la consola de AWS y seguí las mejores prácticas:\nDeshabilité las ACLs → Asegura que todos los objetos sean propiedad de mi cuenta. Bloqueé el acceso público → Previene la exposición no deseada de datos. Activé la versión → Mantiene versiones históricas de los objetos en caso de errores. Encriptación por defecto (AES-256) → Protege los datos en reposo. aws s3api create-bucket --bucket utp-database-data-lake-project --region us-east-1 Una vez creado el bucket, se convirtió en el repositorio central para la ingestión de datos. Todos los datos sin procesar de varias bases de datos (MySQL, SQL Server y PostgreSQL) fueron almacenados aquí antes de ser procesados.\nInfraestructura como Código: AWS CloudFormation #Provisionar manualmente bases de datos y recursos de red es ineficiente, por lo que automatizé el proceso utilizando AWS CloudFormation. CloudFormation permite definir la infraestructura en una plantilla YAML, haciendo que los despliegues sean repetibles y escalables.\nStack de Base de Datos (Instancias RDS) #Modifiqué una plantilla de CloudFormation proporcionada por AWS para desplegar tres instancias Amazon RDS:\nMySQL (para transacciones de comercio electrónico) SQL Server (para datos CRM) PostgreSQL (para datos de gestión empresarial) Cada instancia de base de datos tenía la siguiente configuración:\nTipo de instancia: db.t3.micro Almacenamiento: 20GB Seguridad: Integración con el rol IAM y AWS Secrets Manager para el almacenamiento de credenciales Redes: Subred privada con grupos de seguridad VPC Resources: MySQLInstance: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: mysql-instance DBName: db_mysql DBInstanceClass: db.t3.micro AllocatedStorage: 20 Engine: MySQL EngineVersion: \u0026#34;8.0.39\u0026#34; MasterUsername: Fn::Sub: \u0026#34;{{resolve:secretsmanager:arn:aws:secretsmanager:us-east-1:123456789㊙️utp/database/rds-ASDAS:SecretString:MySQLDBUsername}}\u0026#34; Una vez desplegado, la sección de Outputs de CloudFormation proporcionó puntos finales para conectar a cada instancia de base de datos.\nProcesamiento de Datos con AWS Lambda (Pipelines ETL) #Extraer, transformar y cargar (ETL) datos de manera eficiente es crucial para un Data Lake bien funcionando. Se utilizó AWS Lambda para automatizar la extracción de datos, procesar los datos crudos y almacenar versiones refinadas en S3.\nFlujo de Trabajo ETL #Cada función Lambda era responsable de un paso diferente en el pipeline ETL:\nExtraer datos de RDS Transformar los registros crudos en formatos estructurados (Parquet, CSV) Cargar los datos procesados nuevamente en S3 import os import json import logging from io import BytesIO import pymysql import boto3 from botocore.exceptions import ClientError import pandas as pd # Configuración de logging logger = logging.getLogger() logger.setLevel(logging.INFO) # Inicialización de clientes de AWS secrets_client = boto3.client(\u0026#39;secretsmanager\u0026#39;, region_name=\u0026#39;us-east-1\u0026#39;) s3_client = boto3.client(\u0026#39;s3\u0026#39;) # Recuperación de configuración desde variables de entorno SECRET_ARN = os.environ.get(\u0026#39;SECRET_ARN\u0026#39;) def lambda_handler(event, context): try: # Recuperar las credenciales de la base de datos creds = get_db_credentials(SECRET_ARN) endpoint = creds[\u0026#39;MySQLODBEndpoint\u0026#39;] # Consultar la base de datos y obtener el resultado como un DataFrame de pandas df = query_database(endpoint, creds) ... Procesamiento Basado en Eventos # AWS EventBridge fue utilizado para activar las funciones Lambda cada 5 minutos, asegurando actualizaciones de datos casi en tiempo real. Cada función Lambda procesaba una tabla diferente, asegurando modularidad. Los datos procesados fueron almacenados en un bucket S3 \u0026ldquo;Refined\u0026rdquo;, listos para análisis. Seguridad y Gestión de Credenciales con AWS Secrets Manager #Almacenar las credenciales de base de datos en el código es riesgoso. Para mejorar la seguridad, se utilizó AWS Secrets Manager para almacenar de manera segura las credenciales de RDS.\nPasos Tomados:\nSe creó un secreto para cada instancia de base de datos. Se restringió el acceso mediante políticas IAM de AWS (solo las funciones Lambda podían recuperar las credenciales). Se habilitó la rotación automática de credenciales para mejorar la seguridad. { \u0026#34;SecretId\u0026#34;: \u0026#34;rds-secret\u0026#34;, \u0026#34;Database\u0026#34;: \u0026#34;MySQL\u0026#34;, \u0026#34;Username\u0026#34;: \u0026#34;admin\u0026#34;, \u0026#34;Password\u0026#34;: \u0026#34;securepassword\u0026#34; } Gobernanza de Datos: Monitoreo y Registro con CloudWatch #Hacer seguimiento de los fallos en los trabajos de ETL y la salud de la base de datos era esencial. AWS CloudWatch Logs ayudó a monitorear:\nTasas de éxito/fallo de ejecución de Lambda Tiempos de ejecución de consultas y posibles cuellos de botella Utilización de CPU y memoria de la base de datos Configuración de Alarmas en CloudWatch #Se configuró CloudWatch para enviar alertas por correo electrónico si: ✅ Una función Lambda fallaba más de 3 veces consecutivas ✅ Una instancia RDS superaba el 80% de uso de CPU durante más de 5 minutos\nResources: LambdaErrorAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: LambdaErrorCount MetricName: Errors Namespace: AWS/Lambda Statistic: Sum Period: 60 EvaluationPeriods: 3 Threshold: 3 AlarmActions: - !Ref SNSAlertTopic Consulta de Datos y Análisis: AWS Athena y Herramientas de Visualización #Una vez que los datos se almacenaron en el S3 Bucket Refinado, era necesario que fueran fácilmente accesibles para análisis. En lugar de configurar un almacén de datos tradicional, se utilizó AWS Athena para ejecutar consultas SQL directamente sobre los datos de S3.\nDefinición de la Tabla Athena #CREATE EXTERNAL TABLE IF NOT EXISTS tickit_sales ( salesid INT, listid INT, sellerid INT, buyerid INT, eventid INT, dateid SMALLINT, qtysold SMALLINT, pricepaid DOUBLE, commission DOUBLE, saletime STRING, refined_timestamp TIMESTAMP ) STORED AS PARQUET LOCATION \u0026#39;s3://utp-database-data-lake-project/tickit/refined/sales/\u0026#39;; Ahora, los datos podían ser consultados instantáneamente utilizando SQL estándar.\nConexión con Herramientas BI #El paso final fue integrar Athena con Power BI y Grafana para visualizaciones en tiempo real.\nResumen de la Arquitectura Tecnológica #Al final del proyecto, la arquitectura completa se veía así:\n1️⃣ AWS S3 → Almacena datos crudos y procesados.\n2️⃣ AWS RDS (MySQL, SQL Server, PostgreSQL) → Bases de datos que alimentan el Data Lake.\n3️⃣ AWS CloudFormation → Automatiza la configuración de bases de datos e infraestructura.\n4️⃣ AWS Lambda → Ejecuta trabajos de ETL para transformación de datos.\n5️⃣ AWS EventBridge → Automatiza la programación de ETL.\n6️⃣ AWS Secrets Manager → Gestiona credenciales de bases de datos de forma segura.\n7️⃣ AWS CloudWatch → Monitorea la salud del sistema y registra fallos.\n8️⃣ AWS Athena → Permite consultas SQL sobre datos de S3.\n9️⃣ Power BI / Grafana → Para informes y monitoreo.\nLecciones Aprendidas y Direcciones Futuras #Cada proyecto trae una mezcla de éxitos y desafíos. Algunas cosas funcionan exactamente como se planeó, pero ahí es donde ocurre el mejor aprendizaje. Esta sección profundiza en mis mayores aprendizajes al construir el Data Lake basado en AWS y lo que haría diferente la próxima vez.\nLecciones Claves Aprendidas #1. Gestionar los costos en AWS requiere una planificación cuidadosa #Me di cuenta de que una mala asignación de recursos puede disparar rápidamente los costos. Mantener instancias de RDS inactivas puede generar gastos innecesarios.\n✅ Aprendizaje:\nUtiliza AWS Cost Explorer para monitorear el gasto en tiempo real. Aprovecha las políticas de ciclo de vida de S3 para mover automáticamente los datos antiguos a Glacier. Considera instancias bajo demanda vs. reservadas para RDS si ejecutas proyectos a largo plazo. 2. Las canalizaciones ETL deberían ser más modulares #Inicialmente, cada función Lambda de AWS manejaba un proceso de extracción de datos diferente, pero a medida que añadí más bases de datos, gestionar múltiples funciones ETL se volvió complejo. Si una función fallaba, la depuración era una pesadilla.\n✅ Aprendizaje:\nEn lugar de múltiples funciones Lambda pequeñas, considera orquestar flujos de trabajo ETL con AWS Step Functions para un mejor manejo de errores. Utiliza Amazon Glue en lugar de Lambda para cargas de trabajo ETL a gran escala. 3. El registro y monitoreo son salvavidas #Los registros de AWS CloudWatch me ayudaron a depurar fallos en trabajos de ETL y problemas de conectividad con la base de datos.\n✅ Aprendizaje:\nConfigura Alarmas de CloudWatch para recibir notificaciones de fallos. Usa los registros de consultas de Athena para optimizar el rendimiento y evitar consultas lentas. Mejoras Futuras y Próximos Pasos #Este proyecto fue una excelente experiencia de aprendizaje, pero hay algunas cosas que mejoraría o expandiría en el futuro:\n1. Reemplazar ETL Lambda por AWS Glue #AWS Glue es sin servidor, escalable y más adecuado para tareas ETL complejas. Pasar de Lambda a Glue reduciría la complejidad y proporcionaría una mejor gestión de esquemas.\n2. Implementar permisos en el Data Lake con AWS Lake Formation #Actualmente, S3 almacena todos los datos, pero no hay un control de acceso detallado. AWS Lake Formation permitiría una mejor gestión de permisos mediante políticas de acceso basadas en roles en los conjuntos de datos almacenados.\n3. Automatizar más con Terraform #CloudFormation fue excelente, pero Terraform ofrece compatibilidad multicloud y más flexibilidad. Migrar la automatización de la infraestructura a Terraform haría los despliegues aún más sencillos.\n4. Expandir la visualización de datos con Amazon QuickSight #Usé Power BI y Grafana, pero Amazon QuickSight podría ser una mejor alternativa para integrarse directamente con AWS.\nConclusión #En este proyecto, he compartido nuestro enfoque para construir un Data Lake escalable en AWS y las lecciones que aprendí en el camino. Un agradecimiento especial a mis amigos Andy Sanjur, Harris Yearwood y Isaac Ávila por sus contribuciones y apoyo durante todo este proceso.\nA lo largo del camino, enfrentamos varios desafíos depurando problemas de red, optimizando la eficiencia de costos y mejorando las medidas de seguridad. Pero al superarlos, adquirimos valiosa experiencia práctica con los servicios de AWS y la infraestructura como código (IaC).\nReflexiones Finales y Lecciones Aprendidas #✅ La infraestructura en la nube requiere un equilibrio entre automatización y flexibilidad\nEl uso de CloudFormation simplificó el despliegue, pero ajustar las configuraciones requirió intervención manual. La próxima vez, exploraría Terraform para más flexibilidad.\n✅ Las canalizaciones ETL deben ser escalables y mantenibles\nLambda funcionó para ETL a pequeña escala, pero AWS Glue sería una mejor solución a largo plazo. Step Functions también podría mejorar el manejo de errores.\n✅ La optimización de costos es un proceso continuo\nIncluso dentro del nivel gratuito, los costos de AWS pueden dispararse si no se monitorean. Herramientas como Cost Explorer y políticas de ciclo de vida de S3 ayudan a controlar los gastos.\n✅ La seguridad debe ser una prioridad desde el principio\nAlmacenar credenciales en AWS Secrets Manager, implementar permisos basados en roles de IAM y bloquear el acceso público a S3 fueron medidas clave de seguridad.\nThank you for reading! If you have any questions or comments, please feel free to contact me. Your feedback is highly appreciated.\nKeywords: AWS, Data Lake, Cloud Computing, Database Systems, ETL, CloudFormation, S3, RDS, Lambda, Data Engineering\n","date":"20 diciembre 2024","permalink":"/es/portfolio/aws-database-data-lake/","section":"Portafolio","summary":"Introducción #Los datos son la base de la toma de decisiones en el mundo digital actual.","title":"Construcción de un Lago de Datos en AWS"},{"content":"","date":null,"permalink":"/es/tags/datalake/","section":"Etiquetas","summary":"","title":"Datalake"},{"content":" ","date":null,"permalink":"/es/portfolio/","section":"Portafolio","summary":" ","title":"Portafolio"},{"content":"","date":null,"permalink":"/es/tags/classification/","section":"Etiquetas","summary":"","title":"classification"},{"content":"","date":null,"permalink":"/es/tags/machine-leaning/","section":"Etiquetas","summary":"","title":"machine leaning"},{"content":" Predecir el churn de clientes no se trata solo de identificar quién es probable que se vaya; se trata de comprender las implicaciones financieras detrás de la salida de cada cliente. Además, una de las complejidades en la predicción del churn es lidiar con conjuntos de datos desbalanceados, donde el número de clientes que no se van supera ampliamente a los que se van.\nHoy, construiré un modelo de predicción de churn de clientes sensible al costo usando aprendizaje automático. Profundizaré en la exploración de datos, ingeniería de características, entrenamiento del modelo y evaluación, con el objetivo de minimizar las pérdidas financieras asociadas con el churn de clientes. Al mismo tiempo, analizaré el desempeño de un modelo de clasificación durante un escenario de conjunto de datos desbalanceado.\nIntroducción #El churn de clientes es una métrica crítica para las empresas, especialmente en industrias como telecomunicaciones, banca y servicios basados en suscripciones. Los modelos de predicción de churn ayudan a identificar a los clientes que probablemente dejen de usar los productos o servicios de una empresa. Al abordar proactivamente el churn, las empresas pueden implementar estrategias de retención dirigidas, ahorrando ingresos significativos.\nLos modelos tradicionales de predicción de churn a menudo se enfocan únicamente en la precisión, descuidando las ramificaciones financieras de los diferentes tipos de errores de predicción. Por ejemplo, el costo de predecir incorrectamente que un cliente leal se irá (falso positivo) es diferente de no identificar a un cliente que realmente se va (falso negativo). Para abordar esto, adopto un enfoque sensible al costo que incorpora los costos comerciales asociados con cada tipo de error directamente en el modelo.\nEn este post, construiré un modelo de predicción de churn que considere estos costos. Además, abordaré el problema del desbalanceo de clases, donde la mayoría de los datos son de clientes que no se van. Un desbalance de este tipo puede hacer que el modelo pase por alto a los verdaderos clientes que se van, lo cual no es útil para una empresa que busca mantener a sus clientes.\nEscenario Empresarial #Antes de sumergirnos en los datos y el código, es esencial enmarcar nuestro problema en un contexto empresarial del mundo real. Nuestro objetivo no es solo predecir el churn, sino minimizar el impacto financiero del churn en el negocio.\nLa Matriz de Costos #Definimos una matriz de costos que cuantifica las consecuencias financieras de los diferentes resultados de la predicción:\nPredicción Quedarse (0) Predicción Churn (1) Actual Stay (0) $0 -$200 Actual Churn (1) -$750 $550 Negativo Verdadero (TN): Predecir correctamente que un cliente se quedará. Costo: $0. Falso Positivo (FP): Predecir que un cliente se irá cuando en realidad no lo hará. Costo: -$200 (costo de esfuerzos de retención innecesarios). Falso Negativo (FN): No predecir que un cliente se irá. Costo: -$750 (pérdida debido a la salida del cliente). Positivo Verdadero (TP): Predecir correctamente que un cliente se irá y tomar acción. Ganancia: $550 (beneficio por retener al cliente). Nota: Los costos negativos representan gastos, mientras que los costos positivos representan ganancias.\nAl integrar esta matriz de costos en nuestro modelo, me aseguro de que nuestras predicciones se alineen con los objetivos comerciales, enfocándose en maximizar las ganancias en lugar de solo la precisión estadística.\nEntendiendo el Problema del Desbalanceo de Clases #El desbalanceo de clases ocurre cuando una clase en un problema de clasificación está representada mucho más que otras clases. En la predicción de churn, típicamente, la mayoría de los clientes no se van, lo que lleva a un conjunto de datos desbalanceado. Este desbalance puede sesgar los modelos hacia la clase mayoritaria, causando un mal rendimiento al predecir la clase minoritaria.\nExiste un debate continuo en la comunidad de ciencia de datos sobre el mejor enfoque para manejar el desbalanceo de clases:\nTécnicas de Resampling: Como sobremuestreo de la clase minoritaria o submuestreo de la clase mayoritaria. Pesado de Clases: Asignar pesos más altos a la clase minoritaria durante el entrenamiento del modelo. Ajustes Algorítmicos: Usar algoritmos que sean robustos al desbalanceo de clases. Dejar los Datos Tal Como Están: Algunos argumentan que alterar el conjunto de datos puede distorsionar la verdadera distribución, y los modelos deben aprender de los datos originales. En este proyecto, me enfocaré en aplicar el pesado de clases y lo compararé con los modelos entrenados con los datos desbalanceados originales.\nDescripción del Conjunto de Datos #El conjunto de datos utilizado en este proyecto proviene del Kaggle’s Bank Customer Churn Dataset por Radheshyam Kollipara.\nEl conjunto de datos incluye las siguientes características:\nRowNumber: Representa el número de fila. CustomerId: Identificador único para cada cliente. Surname: Apellido del cliente. CreditScore: Puntuación crediticia del cliente. Geography: País de residencia. Gender: Género del cliente. Age: Edad del cliente. Tenure: Número de años que el cliente ha estado con el banco. Balance: Balance de la cuenta del cliente. NumOfProducts: Número de productos bancarios que el cliente está utilizando. HasCrCard: Indica si el cliente tiene una tarjeta de crédito (1) o no (0). IsActiveMember: Indica si el cliente es un miembro activo (1) o no (0). EstimatedSalary: Ingreso anual estimado del cliente. Exited: Variable objetivo que muestra si el cliente se ha ido (1) o se ha quedado (0). Complain: Indica si el cliente ha presentado una queja (1) o no (0). Satisfaction Score: Puntuación de satisfacción del cliente (1-5). Card Type: Tipo de tarjeta que tiene el cliente (ej. Plata, Oro). Points Earned: Puntos de lealtad acumulados por el cliente. Vista previa del conjunto de datos:\ndataset.sample(5) RowNumber CustomerId Surname CreditScore Geography Gender Age Tenure Balance NumOfProducts HasCrCard IsActiveMember EstimatedSalary Exited Complain Satisfaction Score Card Type Point Earned 2503 2504 15583364 McGregor 476 France Female 32 6 111871.93 1 0 0 112132.86 0 0 3 GOLD 988 1362 1363 15683841 Hamilton 555 Germany Male 41 10 113270.20 2 1 1 185387.14 0 0 1 SILVER 398 842 843 15599433 Fanucci 660 Germany Male 35 8 58641.43 1 0 1 198674.08 0 0 5 PLATINUM 815 7919 7920 15634564 Aksyonov 593 Spain Male 31 8 112713.34 1 1 1 176868.89 0 0 2 GOLD 710 3512 3513 15657779 Boylan 806 Spain Male 18 3 0.00 2 1 1 86994.54 0 0 2 GOLD 768 Análisis Exploratorio de Datos (EDA) #Limpieza de Datos #Primero, revisemos los valores faltantes:\ndataset.isnull().sum() Resultado:\nCustomerId 0 CreditScore 0 Geography 0 Gender 0 Age 0 Tenure 0 Balance 0 NumOfProducts 0 HasCrCard 0 IsActiveMember 0 EstimatedSalary 0 Exited 0 Complain 0 Satisfaction Score 0 Card Type 0 Point Earned 0 dtype: int64 Todas las columnas tienen cero valores faltantes.\nA continuación, eliminemos las columnas irrelevantes que no contribuirán al objetivo de nuestro proyecto:\ndata.drop(columns=[\u0026#39;RowNumber\u0026#39;, \u0026#39;CustomerId\u0026#39;, \u0026#39;Surname\u0026#39;], inplace=True) Resumen Estadístico #Generamos un resumen estadístico para entender la distribución de las características numéricas:\ndata.describe() CustomerId CreditScore Age Tenure Balance NumOfProducts HasCrCard IsActiveMember EstimatedSalary Exited Complain Satisfaction Score Point Earned count 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 mean 1.56909e+07 650.529 38.9218 5.0128 76485.9 1.5302 0.7055 0.5151 100090 0.2038 0.2044 3.0138 606.515 std 71936.2 96.6533 10.4878 2.89217 62397.4 0.581654 0.45584 0.499797 57510.5 0.4028 0.4033 1.40592 225.925 min 1.55657e+07 350 18 0 0 1 0 0 11.58 0 0 1 119 25% 1.56285e+07 584 32 3 0 1 0 0 51002.1 0 0 2 410 50% 1.56907e+07 652 37 5 97198.5 1 1 1 100194 0 0 3 605 75% 1.57532e+07 718 44 7 127644 2 1 1 149388 0 0 4 801 max 1.58157e+07 850 92 10 250898 4 1 1 199992 1 1 5 1000 Perspectivas:\nEdad: La edad promedio es de aproximadamente 39 años, con una desviación estándar de 10.5 años. Balance: El balance promedio es de \\( \\$76,486 \\), pero la desviación estándar es alta $62,397, lo que indica una variabilidad significativa. Exited: Aproximadamente el 20% de los clientes han abandonado, mostrando un desbalance de clases. Manejo del Desbalance de Clases #El desbalance de clases puede sesgar el modelo hacia la clase mayoritaria (clientes no cancelados). Abordaré este problema durante el entrenamiento del modelo utilizando técnicas como el ajuste de pesos por clase y el ajuste del umbral.\nExploración y Ingeniería de Características #Comprender las relaciones entre las características y la variable objetivo es crucial.\nAnálisis de Correlación #Calcula la matriz de correlación para identificar relaciones lineales:\nHallazgos Clave:\nEdad tiene una correlación positiva débil con Exited (0.29), lo que sugiere que los clientes más viejos tienen más probabilidades de abandonar. Queja tiene una correlación positiva fuerte con Exited (0.99). Esto puede indicar que la existencia de una queja está presente solo en los clientes que abandonaron. Un análisis más profundo indica que la fuerte correlación entre quejas y abandono se debe al hecho de que casi todos los clientes que abandonan presentaron una queja antes de irse. En contraste, los clientes que no abandonaron rara vez presentaron quejas. Esto sugiere que las quejas son un indicador fuerte de insatisfacción, que a menudo conduce al abandono. Esta característica podría causar filtración de datos. Consideraré eliminarla.\ncomplain = dataset.groupby([\u0026#39;Complain\u0026#39;,\u0026#39;Exited\u0026#39;]).size().reset_index(name=\u0026#39;Count\u0026#39;) total = complain[\u0026#39;Count\u0026#39;].sum() complain[\u0026#39;Proportion\u0026#39;] = (complain[\u0026#39;Count\u0026#39;] / total ) Complain Exited Count Proportion 0 0 7952 0.7952 0 1 4 0.0004 1 0 10 0.001 1 1 2034 0.2034 Visualización de Características Clave #Distribución de Edad # Observación:\nLos clientes que abandonan tienden a ser más mayores. Distribución de Balance # Observación:\nLos clientes que abandonan generalmente tienen balances de cuenta más altos. Número de Productos # La muesca representa la media. Observación:\nLos clientes con un producto tienen más probabilidades de abandonar que aquellos con múltiples productos. Tenencia # Observación:\nLa distribución de tenencia es similar tanto para clientes que abandonan como para los que no, con ambos grupos teniendo una tenencia media de 5 años. Los clientes que abandonan muestran más variabilidad en su tenencia, lo que indica que pueden dejar el banco en diferentes etapas de su relación. Salario Estimado # Observación:\nLos clientes que abandonan y los que no tienen balances similares, alrededor de 100,000. Ambos grupos muestran una distribución similar en los balances sin valores atípicos. Puntuación de Satisfacción # Observación:\nLos clientes que abandonan y los que no tienen la misma distribución, con una mediana de 3 y rangos intercuartiles idénticos. Las cercas superior e inferior también son idénticas, sin valores atípicos para ninguno de los grupos. Geografía # Observación:\nFrancia: Tiene la mayor base de clientes, con una tasa de abandono del 16.2%. Alemania: Muestra una tasa de abandono significativamente más alta, con 32.4%, lo que sugiere que los clientes alemanes tienen más probabilidades de abandonar. España: Tiene una tasa de abandono similar a la de Francia, con un 16.7%. Estas diferencias indican que la geografía podría influir en el abandono, con los clientes alemanes mostrando una mayor probabilidad de abandonar en comparación con los de Francia y España.\nPuntuación de Satisfacción # Observación:\nTitulares de tarjeta Diamond: Tienen la tasa de abandono más alta con 21.8%. Titulares de tarjeta Gold: Muestran la tasa de abandono más baja con 19.3%. Titulares de tarjeta Platinum y Silver: Tienen tasas de abandono similares, alrededor del 20.3% y 20.1%, respectivamente. Estos resultados sugieren que los titulares de tarjeta Diamond tienen más probabilidades de abandonar, mientras que los titulares de tarjeta Gold tienen algo más de probabilidad de quedarse. Sin embargo, las diferencias en las tasas de abandono entre tipos de tarjeta son relativamente pequeñas.\nExtracción de Características #Eliminación de Características Potencialmente Problemáticas #Considero eliminar la característica Complain debido a su correlación casi perfecta con Exited, lo que podría causar filtración de datos:\ndata.drop(columns=[\u0026#39;CustomerId\u0026#39;,\u0026#39;Complain\u0026#39;], inplace=True) Preprocesamiento de Datos #División de Datos en Entrenamiento y Prueba #Dividimos los datos en conjuntos de entrenamiento, validación y prueba. Esto se hace antes de la escala de las características para evitar la filtración de datos.\nfrom sklearn.model_selection import train_test_split X = dataset.drop(columns=\u0026#39;Exited\u0026#39;) y = dataset[\u0026#39;Exited\u0026#39;] # División inicial para separar el conjunto de prueba X_train_val, X_test, y_train_val, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y) # Dividir los datos restantes en conjuntos de entrenamiento y validación X_train, X_val, y_train, y_val = train_test_split( X_train_val, y_train_val, test_size=0.25, random_state=42, stratify=y_train_val) Con base en estas divisiones, la distribución final es:\nConjunto Total de Registros Porcentaje del Total de Datos Entrenamiento 6,000 60% Validación 2,000 20% Prueba 2,000 20% Transformador de Columnas #from sklearn.compose import ColumnTransformer from sklearn.preprocessing import OneHotEncoder, StandardScaler num_cols = [\u0026#39;CreditScore\u0026#39;, \u0026#39;Age\u0026#39;, \u0026#39;Tenure\u0026#39;, \u0026#39;Balance\u0026#39;, \u0026#39;NumOfProducts\u0026#39;, \u0026#39;EstimatedSalary\u0026#39;, \u0026#39;Satisfaction Score\u0026#39;, \u0026#39;Point Earned\u0026#39;] cat_cols = [\u0026#39;Geography\u0026#39;, \u0026#39;Card Type\u0026#39;, \u0026#39;Gender\u0026#39;] bin_cols = [\u0026#39;HasCrCard\u0026#39;, \u0026#39;IsActiveMember\u0026#39;] preprocessor = ColumnTransformer( transformers=[ # Codificación One-hot para variables categóricas (\u0026#39;one_hot_encoder\u0026#39;, OneHotEncoder(drop=\u0026#39;first\u0026#39;, sparse_output=False), cat_cols), # Escalado estándar para características numéricas (\u0026#39;standard_scaler\u0026#39;, StandardScaler(), num_cols), ], # Deja pasar las características binarias remainder=\u0026#39;passthrough\u0026#39; ) preprocessor.fit(X_train) X_train = preprocessor.transform(X_train) X_val = preprocessor.transform(X_val) X_test = preprocessor.transform(X_test) feature_names = list(preprocessor.named_transformers_[\u0026#39;one_hot_encoder\u0026#39;] \\ .get_feature_names_out(input_features=cat_cols)) feature_names = feature_names + num_cols + bin_cols Definición de la Función de Costo #Definimos una función de costo personalizada para evaluar nuestros modelos según la matriz de costos del negocio:\nfrom sklearn.metrics import confusion_matrix, make_scorer def cost_function(y_true, y_pred, neg_label=0, pos_label=1): cm = confusion_matrix(y_true, y_pred, labels=[neg_label, pos_label]) cost_matrix = np.array([ [0, -200], # [Costo de TN, Costo de FP] [-750, 550] # [Costo de FN, Ganancia de TP] ]) total_gain = np.sum(cm * cost_matrix) return total_gain cost_scorer = make_scorer(cost_function, greater_is_better=True, neg_label=0, pos_label=1) Esta función calcula la ganancia (o pérdida) total para un conjunto de predicciones, considerando los costos asociados con cada tipo de resultado de la predicción.\nEntrenamiento de Modelos #Entrenaré tres modelos diferentes:\nRegresión Logística Clasificador Random Forest Clasificador XGBoost Validación Cruzada #Se utiliza validación cruzada con k-fold estratificado para garantizar que cada partición tenga una distribución de clases similar:\nfrom sklearn.model_selection import cross_val_score, StratifiedKFold skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) Modelos Base #Comenzamos entrenando modelos base sin manejar el desequilibrio de clases.\nRegresión Logística #from sklearn.linear_model import LogisticRegression lr_base = LogisticRegression(random_state=42) lr_base.fit(X_train, y_train) Random Forest #from sklearn.ensemble import RandomForestClassifier rf_base = RandomForestClassifier(random_state=42) rf_base.fit(X_train, y_train) XGBoost #from xgboost import XGBClassifier # La fracción de instancias positivas en el conjunto y_train_val pos_frac = y_train_val.mean() xgb_base = XGBClassifier(random_state=42, base_score=pos_frac) xgb_base.fit(X_train, y_train) Modelos con Pesos #Se aplicaron pesos de clase para abordar el desequilibrio de clases.\nRegresión Logística con Pesos de Clase #lr_balanced = LogisticRegression(random_state=42, class_weight=\u0026#39;balanced\u0026#39;) lr_balanced.fit(X_train, y_train) Random Forest con Pesos de Clase #rf_balanced = RandomForestClassifier(random_state=42, class_weight=\u0026#39;balanced\u0026#39;) rf_balanced.fit(X_train, y_train) XGBoost con Scale Pos Weight #Calculamos scale_pos_weight como la relación entre las clases negativas y positivas.\nfrom collections import Counter counter = Counter(y_train) neg_class = counter[0] pos_class = counter[1] scale_pos_weight = neg_class / pos_class xgb_balanced = XGBClassifier(random_state=42, scale_pos_weight=scale_pos_weight, base_score=pos_frac) xgb_balanced.fit(X_train, y_train) Evaluación de Modelos en Datos de Validación #Métricas de Evaluación #Evaluamos los modelos usando varias métricas:\nPrecisión: Exactitud general. Precisión: Predicciones positivas correctas sobre el total de predicciones positivas. Recuperación: Predicciones positivas correctas sobre los positivos reales. Puntuación F1: Promedio armónico de precisión y recuperación. ROC-AUC: Área bajo la curva ROC. MCC: Proporciona una evaluación balanceada considerando todos los elementos de la matriz de confusión. Brier Score: Evalúa la precisión de las predicciones probabilísticas midiendo la diferencia cuadrada media entre las probabilidades predichas y los resultados reales. Nombre del Modelo Exactitud Precisión Recall F1 Score ROC AUC MCC LR Base 0.8040 0.5564 0.1818 0.2741 0.7719 0.2339 LR Balanced 0.7045 0.3808 0.7224 0.4987 0.7743 0.3492 RF Base 0.8610 0.7452 0.4816 0.5851 0.8418 0.5236 RF Balanced 0.8575 0.7480 0.4521 0.5636 0.8500 0.5065 XGB Base 0.8535 0.6696 0.5528 0.6057 0.8362 0.5203 XGB Balanced 0.8270 0.5695 0.6143 0.5910 0.8364 0.4821 Observación:\nRF destaca con el MCC y ROC AUC más altos, lo que indica un rendimiento robusto a través de múltiples métricas. Aunque RF Balanced tiene el ROC AUC más alto, RF Base alcanza el MCC más alto. En términos de puntuación F1, XGB obtiene los mejores resultados. Puntuaciones ROC AUC Validación Cruzada # Modelo ROC AUC RF Balanced 0.8273 RF Base 0.8256 XGB Base 0.8143 XGB Balanced 0.8075 LR Balanced 0.7659 LR Base 0.7641 Calibración e Importancia de Características #Gráfico de Calibración #Los gráficos de calibración ayudan a evaluar qué tan bien las probabilidades predichas reflejan las probabilidades reales.\nPuntuaciones Brier (menor es mejor) # Modelo Puntuación Brier RF Balanced 0.1068 RF Base 0.1082 XGB Base 0.1111 XGB Balanced 0.1263 LR Base 0.1350 LR Balanced 0.1966 Observación:\nEl Balanced Random Forest tiene el mejor puntaje Brier, lo que lo convierte en el modelo más preciso para las predicciones de probabilidad. El balanceo mejora ligeramente el Random Forest, pero empeora el rendimiento de la Regresión Logística y un poco el de XGBoost. Importancia de las Características #Para determinar las características más importantes, utilizo SHAP (SHapley Additive exPlanations), que ayuda a entender cuánto contribuye cada característica a las predicciones del modelo.\nObservación:\nEdad, Número de Productos y ¿Es Miembro Activo? son consistentemente las características más importantes en los modelos de RF y XGB, lo que indica que la edad, el número de productos y el estado de membresía activa influyen significativamente en la rotación. El balanceo del conjunto de datos tiene poco efecto en la importancia de las características para cada modelo. Ajuste del Umbral de Decisión #Por defecto, los modelos clasifican las muestras como positivas si la probabilidad predicha es ≥ 0.5. Sin embargo, este umbral podría no ser óptimo para nuestro escenario sensible a costos.\nProceso de Ajuste del Umbral #Buscar un umbral que maximice nuestra función de costo personalizada con TunedThresholdClassifierCV de scikit-learn.\nfrom sklearn.model_selection import TunedThresholdClassifierCV tuned_model = TunedThresholdClassifierCV( model, scoring=cost_scorer, # Puntaje personalizado para el negocio store_cv_results=True, ) tuned_model.fit(X_train, y_train) Resultados Después del Ajuste del Umbral # Observación:\nEl modelo Balanced RF post-ajuste genera la mayor ganancia con $22,850, convirtiéndolo en el modelo de mejor rendimiento. Ambos modelos de Regresión Logística ajustados resultan en pérdidas negativas. Evaluación Final con Datos de Prueba #Se prueban los modelos en un conjunto de datos de prueba para evaluar su rendimiento final. Debido a su bajo rendimiento, la Regresión Logística fue excluida de estas evaluaciones.\nRentabilidad del Modelo # Observación:\nCon excepción de Balanced XGB, los modelos ajustados por umbral superan a todos los modelos no ajustados en términos de ganancia sobre datos no vistos. El modelo más rentable es el Random Forest base ajustado por umbral. Desempeño General del Modelo # Nombre del Modelo Exactitud Precisión Recall F1 Score ROC AUC MCC Base RF 0.8690 0.7897 0.4877 0.6030 0.8578 0.5518 Base RF post-ajuste 0.7125 0.4016 0.8358 0.5426 0.8578 0.4212 Balanced RF 0.8700 0.8217 0.4632 0.5925 0.8632 0.5526 Balanced RF post-ajuste 0.6480 0.3549 0.8873 0.5070 0.8632 0.3820 Base XGB 0.8470 0.6635 0.5074 0.5750 0.8403 0.4902 Base XGB post-ajuste 0.6585 0.3598 0.8652 0.5083 0.8403 0.3794 Balanced XGB 0.8400 0.5987 0.6544 0.6253 0.8439 0.5247 Balanced XGB post-ajuste 0.6980 0.3874 0.8260 0.5274 0.8439 0.3992 Mejor Modelo #Random Forest post-ajuste # Nombre del Modelo Exactitud Precisión Recall F1 Score ROC AUC MCC Base RF post-ajuste 0.7125 0.4016 0.8358 0.5426 0.8578 0.4212 Conclusión #Predecir la rotación de clientes no se trata solo de identificar quién tiene más probabilidades de irse, sino también de entender el impacto financiero de perder a un cliente. Al adoptar un enfoque sensible a los costos, este proyecto buscó alinear la modelización predictiva con los objetivos empresariales, asegurando que las estrategias de retención maximicen las ganancias financieras.\nEl análisis demostró que manejar el desbalance de clases es crucial para una predicción efectiva de la rotación. Mientras que los modelos tradicionales tienden a favorecer la clase mayoritaria, la aplicación de técnicas como el pesado de clases mejoró el recall, permitiendo que el modelo capturara mejor a los clientes en riesgo de rotación.\nEntre los modelos probados, el Random Forest post-ajuste balanceado surgió como la opción más rentable. Al ajustar los umbrales de decisión, este modelo optimizó el balance entre identificar correctamente a los clientes que se irán y minimizar los falsos positivos, lo que llevó a las mayores ganancias financieras sobre datos no vistos.\nAdemás, el análisis de la importancia de las características reveló que Edad, Número de Productos y Membresía Activa fueron los factores clave para predecir la rotación. Comprender estos factores permite a las empresas desarrollar intervenciones dirigidas para retener a los clientes de manera efectiva.\nPrincipales Conclusiones # El Enfoque Sensible a los Costos Mejora la Alineación con el Negocio\nIncorporar una matriz de costos en la evaluación del modelo aseguró que las predicciones estuvieran alineadas con los resultados financieros en lugar de la precisión estadística pura. Este enfoque ayudó a equilibrar la maximización de ganancias con la mitigación de costos innecesarios.\nEl Desbalance de Clases Afecta el Rendimiento del Modelo\nEl conjunto de datos exhibió un desbalance significativo de clases, que fue abordado usando pesado de clases y aprendizaje sensible a costos. Los modelos balanceados obtuvieron mejores resultados en términos de recall, asegurando que se identificara correctamente más casos de rotación.\nEl Modelo Random Forest Post-Ajuste Fue el Mejor\nDespués del ajuste de umbral, el Random Forest balanceado post-ajuste emergió como el modelo más rentable, alcanzando la mayor ganancia financiera sobre datos no vistos.\nLa Importancia de las Características Resalta los Patrones de Comportamiento del Cliente\nCaracterísticas como Edad, Número de Productos y Membresía Activa tuvieron el mayor impacto en las predicciones de rotación, lo que resalta la necesidad de estrategias de retención dirigidas a grupos específicos de clientes.\nPróximos Pasos # Integración del Valor de Vida del Cliente (CLV)\nModelos futuros podrían incorporar el Valor de Vida del Cliente (CLV) en la función de costos para priorizar a los clientes de alto valor y optimizar la asignación de recursos.\nModelo de Costo Dinámico\nLa matriz de costos fija asume costos y ganancias uniformes entre todos los clientes, lo cual puede no reflejar las variaciones del mundo real. Un enfoque dinámico y basado en datos para la estimación de costos podría mejorar la toma de decisiones financieras.\nConsideración de la Experiencia del Cliente\nSi bien la maximización de ganancias fue el objetivo principal, las empresas deben equilibrar las acciones predictivas con la experiencia del cliente para evitar que las estrategias de retención tengan efectos negativos.\nPreparación Operativa para el Despliegue\nAntes de desplegar el modelo, es crucial evaluar las limitaciones del mundo real, como latencia, escalabilidad e integración con los sistemas de gestión de clientes existentes.\nReferencias # Documentación de Scikit-learn Aprendizaje de datos desbalanceados - EuroSciPy 2023 ¿Qué está ocultando tu modelo? Un tutorial sobre evaluación de modelos ML ¡Gracias por leer! Si tienes alguna pregunta o comentario, no dudes en contactarme. Aprecio mucho tu retroalimentación.\nKeywords: Machine Learning, Cost-Sensitive Learning, Classification, Data Science, Business Analytics\n","date":"26 octubre 2024","permalink":"/es/portfolio/cost-sensitive-model/","section":"Portafolio","summary":"Predecir el churn de clientes no se trata solo de identificar quién es probable que se vaya; se trata de comprender las implicaciones financieras detrás de la salida de cada cliente.","title":"Predicción de Churn de Clientes Sensible al Costo"},{"content":"Antecedentes #Desde una edad temprana, he sido apasionado por la tecnología. Con el tiempo, mis intereses evolucionaron desde las redes informáticas y la ciberseguridad al análisis y ciencia de datos, donde encontré mi verdadera motivación. Durante la universidad, mis cursos favoritos incluyeron metodologías de investigación, estadística, sistemas expertos y análisis de datos, lo que solidificó aún más mi compromiso con este campo. Actualmente, programo en Python y C++, desarrollando herramientas para optimizar tareas personales y participando en proyectos que facilitan el aprendizaje continuo.\nExperiencia #Obtuve una licenciatura en Ingeniería de Sistemas y Computación en la Universidad Tecnológica de Panamá. Adquirí experiencia a través de proyectos colaborativos, lo que perfeccionó mis habilidades en análisis de datos y resolución de problemas. Durante los últimos años de la universidad, realicé algunos trabajos paralelos programando y enseñando a estudiantes universitarios.\nEntre 2022 y 2024, trabajé para Credicorp Bank como Analista de Seguridad Informática en las siguientes tareas:\nInvestigaciones de fraude, evaluaciones de vulnerabilidades, informes interactivos y dashboards utilizando Power BI Administrar y mantener las bases de datos del departamento Desarrollo e implementación de pipelines para analizar patrones de fraude en entornos locales y en la nube Automatización de tareas de seguridad e Infraestructura como Código (IaC) utilizando Python Configuración de políticas de seguridad, Gestión de Identidad y Acceso (IAM), detección y respuesta a incidentes, y seguridad de infraestructura en AWS y Azure Gracias a mis amigos en CCB 🎉 Actualmente, estoy cursando una maestría en Ciencias de Analítica de Datos en la Universidad Tecnológica de Panamá y preparándome para una certificación en la nube. Planeo enfocar mi carrera en ciencia de datos. Tengo la intención de participar en comunidades tecnológicas, asistir a hackathons y talleres para expandir mis conocimientos, y establecer redes de contacto con profesionales del campo.\nComunidad de Python en Pycon 2023 Hobbies #En mi tiempo libre, me encanta jugar videojuegos, estar al tanto de las últimas tecnologías y escribir pequeños scripts para hacer las tareas diarias más fáciles.\n","date":null,"permalink":"/es/about/","section":"¡Bienvenido a mi página web!","summary":"Antecedentes #Desde una edad temprana, he sido apasionado por la tecnología.","title":"Sobre Mi"},{"content":"","date":null,"permalink":"/es/tags/cybersecurity/","section":"Etiquetas","summary":"","title":"Cybersecurity"},{"content":"","date":null,"permalink":"/es/tags/flask/","section":"Etiquetas","summary":"","title":"Flask"},{"content":"","date":null,"permalink":"/es/tags/machine-learning/","section":"Etiquetas","summary":"","title":"Machine Learning"},{"content":" Introducción #Los ataques de phishing son una de las amenazas más comunes en ciberseguridad hoy en día, engañando a los usuarios para que proporcionen información sensible a través de sitios web maliciosos. Con las técnicas de phishing evolucionando, los sistemas de detección automatizados son cruciales para mantenerse a la vanguardia. Es por eso que construí un clasificador de URLs de phishing, una aplicación web impulsada por aprendizaje automático que predice si una URL dada es legítima o fraudulenta.\nEn este blog, recorreré cómo desarrollé este proyecto, desde la extracción de características hasta el entrenamiento del modelo y la construcción de la aplicación web utilizando Flask.\nCómo Funciona la Aplicación #La aplicación permite a los usuarios ingresar una URL. Luego, el sistema realiza los siguientes pasos:\nExtracción de Características: La aplicación analiza diversas características de la URL, como la longitud, la presencia de caracteres especiales, la antigüedad del dominio y el uso de HTTPS. Predicción del Modelo: Un clasificador Random Forest predice si la URL es phishing (-1) o legítima (1) en base a estas características. Mostrar Resultados: La aplicación devuelve el resultado de la clasificación junto con la puntuación de probabilidad. Este proceso automatizado permite una detección rápida de phishing sin necesidad de intervención manual.\nExtracción de Características: ¿Qué Hace Sospechosa a una URL? #Una parte clave de la detección de phishing es la ingeniería de características, que significa definir características medibles de las URLs que ayudan a determinar si pueden ser fraudulentas. Los atacantes a menudo utilizan técnicas engañosas para engañar a los usuarios, y al analizar diferentes aspectos de una URL, podemos detectar patrones sospechosos. Aquí están las características que considera nuestra aplicación:\nCaracterísticas Básicas de la URL # Longitud de la URL: Las URLs más largas tienden a ocultar contenido malicioso. Legítima (\u0026lt; 54 caracteres) Sospechosa (54-75 caracteres) Phishing (\u0026gt; 75 caracteres) Presencia del Símbolo \u0026ldquo;@\u0026rdquo;: Si una URL contiene un @, a menudo es un intento de phishing para engañar a los usuarios. Redirecciones (\u0026quot;//\u0026quot; en Uso): Si una URL contiene múltiples \u0026ldquo;//\u0026rdquo; fuera de su posición normal, puede estar tratando de disfrazar su destino real. Uso de Guiones en el Dominio: Un dominio con guiones (por ejemplo, \u0026ldquo;secure-bank-login.com\u0026rdquo;) a menudo es una señal de phishing. Cantidad de Subdominios: Legítima (0-1 subdominios) Sospechosa (2 subdominios) Phishing (3+ subdominios) URLs Acortadas: Los atacantes a menudo utilizan servicios como bit.ly o tinyurl.com para enmascarar los enlaces de phishing. Indicadores de Dominio y Seguridad # Uso de HTTPS y Validez del Certificado SSL: La falta de HTTPS o un certificado SSL inválido aumenta el riesgo de phishing. Antigüedad del Dominio: Los dominios nuevos (menos de 6 meses) suelen ser creados para phishing antes de ser marcados. Expiración del Dominio: Si un dominio expira en ≤ 1 año, es una señal de advertencia, ya que las empresas legítimas generalmente registran dominios por períodos más largos. Disponibilidad del Registro WHOIS: Si faltan los datos de WHOIS, podría indicar un sitio fraudulento. Estructura del Sitio Web y Contenido # Fuente del Favicon: Si el favicon del sitio web (ícono en la pestaña del navegador) se carga desde un dominio externo, podría ser un phishing. Puertos No Estándar: Los sitios de phishing pueden usar puertos no comunes en lugar de los estándar como 80 (HTTP) o 443 (HTTPS). \u0026ldquo;HTTPS\u0026rdquo; en el Nombre del Dominio: Si el dominio mismo contiene \u0026ldquo;https\u0026rdquo; (por ejemplo, \u0026ldquo;https-secure-login.com\u0026rdquo;), probablemente sea engañoso. Solicitudes Externas y Enlaces: Un porcentaje alto de solicitudes externas (imágenes, scripts) puede indicar un intento de phishing. Demasiados enlaces ancla externos (enlaces clicables) también sugieren que la página está redirigiendo a los usuarios a otro lugar. Si los enlaces externos están dentro de etiquetas \u0026lt;meta\u0026gt;, \u0026lt;script\u0026gt; o \u0026lt;link\u0026gt;, es otra señal sospechosa. Interacción del Usuario y Comportamiento # Manejador de Formularios del Servidor (SFH): Si los datos del formulario se envían a un dominio diferente o a un manejador vacío, el sitio puede estar robando credenciales. Envío de Información a Correo Electrónico: Si la página envía datos a través de mailto: o utiliza la función mail() de PHP, podría ser phishing. Formato Abnormal de la URL: El dominio de un sitio legítimo debe coincidir con el nombre del host real. Si no lo hace, algo está mal. Redirección del Sitio Web: Legítima: 0-1 redirecciones Sospechosa: 2-3 redirecciones Phishing: 4+ redirecciones Manipulación de la Barra de Estado: Si el sitio modifica la barra de estado (por ejemplo, usando trucos con JavaScript onMouseOver), probablemente sea phishing. Deshabilitación del Clic Derecho: Los sitios de phishing suelen deshabilitar el clic derecho para evitar que los usuarios inspeccionen los elementos o copien el texto. Ventanas Emergentes con Campos de Entrada: Si una ventana emergente contiene campos de formulario, podría estar intentando capturar credenciales de inicio de sesión. Uso de Iframes: Los sitios de phishing a menudo usan etiquetas \u0026lt;iframe\u0026gt; para incrustar contenido malicioso de otra fuente. Reputación y Popularidad # Tráfico del Sitio Web: Los sitios clasificados por debajo de 100,000 (según Tranco) suelen ser legítimos, mientras que los sitios de bajo tráfico son más sospechosos. Puntuación PageRank: Si el sitio tiene un bajo PageRank (\u0026lt; 0.2), es un posible riesgo de phishing. Indexación en Google: Si un sitio no está indexado por Google, podría ser inseguro. Backlinks (Enlaces Externos que Apuntan al Sitio): Legítimo: Más de 2 backlinks Sospechoso: 1-2 backlinks Phishing: 0 backlinks Análisis Basado en Informes Estadísticos: Si el dominio aparece en bases de datos de phishing (como PhishTank), casi con certeza es malicioso. Al extraer todas estas características, la aplicación construye un conjunto de datos que ayuda a identificar intentos de phishing con mayor precisión. Estas señales trabajan juntas para detectar patrones comúnmente encontrados en sitios fraudulentos, mejorando nuestra capacidad para marcar URLs sospechosas antes de que causen daño.\nEntrenando el Modelo de Aprendizaje Automático #Detectar sitios web de phishing requiere un modelo de clasificación sólido capaz de identificar patrones engañosos en las URLs. Elegí un clasificador Random Forest, un algoritmo de aprendizaje en conjunto poderoso que maneja eficazmente estructuras de datos complejas, a la vez que ofrece interpretabilidad. A continuación, se detalla el proceso que seguí:\n1. Análisis Exploratorio de Datos (EDA) #Antes de sumergirme en el entrenamiento del modelo, realicé un Análisis Exploratorio de Datos (EDA) para comprender mejor el conjunto de datos y sus características.\nResumen del Conjunto de Datos #El conjunto de datos se descargó de UCI Machine Learning Repository, donado por R. Mohammad y L. McCluskey en 2015. No se especifica cómo recopilaron los datos, pero las características están bien documentadas. El conjunto de datos contiene 11,055 URLs, de las cuales 6,157 están etiquetadas como phishing (1) y 4,898 como legítimas (-1). Este pequeño desequilibrio de clases significa que los sitios de phishing son ligeramente más prevalentes, pero aún lo suficientemente cerca como para no requerir técnicas drásticas de remuestreo.\nPara obtener una imagen más clara, analicé las características y correlaciones del conjunto de datos para identificar los indicadores más fuertes del comportamiento de phishing.\nhaving_IP_AddressURL_LengthShortining_Servicehaving_At_Symboldouble_slash_redirectingPrefix_Suffixhaving_Sub_DomainSSLfinal_StateDomain_registeration_lengthFaviconportHTTPS_tokenRequest_URLURL_of_AnchorLinks_in_tagsSFHSubmitting_to_emailAbnormal_URLRedirecton_mouseoverRightClickpopUpWidnowIframeage_of_domainDNSRecordweb_trafficPage_RankGoogle_IndexLinks_pointing_to_pageStatistical_reportResult0-1111-1-1-1-1-111-11-11-1-1-101111-1-1-1-111-1-1111111-101-111-110-1-11101111-1-10-1111-1210111-1-1-1-111-110-1-1-1-1011111-11-110-1-1310111-1-1-1111-1-100-11101111-1-11-11-11-1410-111-111-1111100-1110-11-11-1-10-11111 Correlaciones de Características # El análisis de mapa de calor muestra la correlación entre cada característica y la variable objetivo (phishing o legítima). Las observaciones clave incluyen:\nValidez del Certificado SSL: Una fuerte correlación positiva (0.71) indica que los sitios web con un certificado SSL válido son mucho más propensos a ser legítimos. Los sitios de phishing a menudo carecen de certificados adecuados. Etiquetas de Ancla Enlazando a Dominios Externos: Una alta correlación positiva (0.69) sugiere que los sitios de phishing tienden a tener un alto porcentaje de enlaces de ancla salientes que redirigen a los usuarios a diferentes dominios. Presencia de Subdominios: Una correlación positiva moderada (0.30) indica que la presencia de múltiples subdominios puede ser una señal de actividad de phishing. Prefijo/Sufijo en el Dominio: Una correlación positiva moderada (0.35) sugiere que la presencia de guiones u otros prefijos/sufijos en el nombre de dominio puede ser indicativa de phishing. Solicitudes de URLs de Fuentes Externas: Una correlación positiva (0.25) sugiere que una mayor proporción de recursos cargados externamente (imágenes, scripts) puede ser una señal de alerta. Duración del Registro del Dominio: Una correlación negativa (-0.23) sugiere que los sitios de phishing tienen más probabilidades de tener períodos de registro de dominio más cortos. Este mapa de calor visualiza eficazmente las relaciones entre las características y la probabilidad de que un sitio web sea de phishing, destacando los factores más influyentes.\nManejo de Datos Desbalanceados #Aunque el conjunto de datos no está severamente desbalanceado, los URLs de phishing superan ligeramente a los legítimos. Para asegurarme de que el modelo aprendiera de ambas clases de manera efectiva, apliqué ponderación de clases en lugar de sobremuestreo o submuestreo. Esto evita que el modelo se sesgue hacia la clase mayoritaria.\n2. Selección y Entrenamiento del Modelo #Para encontrar el mejor modelo para la detección de phishing, probé varios algoritmos utilizando LazyPredict, una herramienta de referencia automatizada. Los modelos con mejor rendimiento incluyeron:\nModelo Exactitud Exactitud Balanceada ROC AUC Puntuación F1 Clasificador Extra Trees 97.6% 97.6% 97.6% 97.6% Random Forest 97.4% 97.3% 97.3% 97.4% XGBoost 97.3% 97.2% 97.2% 97.3% 🔹 ¿Por qué Random Forest?\nAunque Extra Trees tuvo un rendimiento ligeramente mejor, Random Forest proporcionó una exactitud comparable y es más fácil de interpretar. Además, maneja bien el sobreajuste al promediar múltiples árboles de decisión, asegurando un rendimiento robusto en nuevos datos.\nValidación Cruzada #Para validar la estabilidad del modelo, realicé una validación cruzada de 5 pliegues, lo que confirmó una exactitud promedio del 97.1%. Esta consistencia en diferentes divisiones del conjunto de datos indicó que el modelo generaliza bien.\n3. Evaluación del Modelo #Una vez entrenado, evalué el clasificador Random Forest en el conjunto de prueba, que contenía 2,211 URLs. Los resultados fueron impresionantes:\n✔️ Exactitud: 98% – El modelo clasificó correctamente el 98% de las URLs de phishing y legítimas.\n✔️ Precisión: 98% – De todas las URLs clasificadas como phishing, el 98% eran realmente sitios de phishing.\n✔️ Recall: 98% – El modelo detectó correctamente el 98% de las URLs de phishing.\n✔️ Puntuación F1: 98% – Un buen equilibrio entre precisión y recall.\n✔️ Puntuación ROC-AUC: 98% – Indica un buen rendimiento para distinguir entre sitios de phishing y legítimos.\nAnálisis de la Matriz de Confusión #Una matriz de confusión ayuda a visualizar el rendimiento del modelo:\nPredicción Legítima (-1) Predicción Phishing (1) Legítima (-1) 951 (Verdaderos Negativos) 29 (Falsos Positivos) Phishing (1) 21 (Falsos Negativos) 1210 (Verdaderos Positivos) 🔹 Falsos Positivos (29 casos): Estos son URLs legítimas incorrectamente marcadas como phishing. Un menor número de falsos positivos reduce la frustración innecesaria de los usuarios.\n🔹 Falsos Negativos (21 casos): Estos son URLs de phishing incorrectamente clasificadas como legítimas. Minimizar los falsos negativos es crucial, ya que perder un intento de phishing puede generar brechas de seguridad.\nCompromiso entre Precisión y Recall # Una alta precisión significa que el modelo hace menos acusaciones erróneas (sitios legítimos mal clasificados como phishing). Un alto recall significa que el modelo detecta más sitios de phishing, pero puede marcar algunos legítimos por error. Con ambos al 98%, el modelo logra un excelente equilibrio. Creación de la Aplicación Web con Flask #Una vez entrenado el modelo, creé una aplicación web Flask para permitir que los usuarios interactúen con él. La aplicación consta de:\nFrontend (HTML, CSS): Una interfaz simple donde los usuarios ingresan una URL. Backend (API Flask): El endpoint /predict recibe la URL ingresada. La clase FeatureExtractor extrae las características relevantes. El modelo Random Forest predice si la URL es phishing. Los resultados se devuelven como una respuesta JSON. Ruta de Flask para predicción:\n@app.route(\u0026#34;/predict\u0026#34;, methods=[\u0026#34;POST\u0026#34;]) def predict(): try: data = request.get_json() if not data or \u0026#34;url\u0026#34; not in data: return jsonify({\u0026#34;success\u0026#34;: False, \u0026#34;message\u0026#34;: \u0026#34;No URL provided.\u0026#34;}), 400 url = data[\u0026#34;url\u0026#34;] # Preprocesar los datos de entrada extractor = FeatureExtractor(url) X_processed = extractor.extract_all_features() features = parse_features(X_processed) # Hacer la predicción prediction = model.predict(X_processed) probability = model.predict_proba(X_processed) probability = np.max(probability) return jsonify({ \u0026#34;success\u0026#34;: True, \u0026#34;prediction\u0026#34;: int(prediction[0]), \u0026#34;probability\u0026#34;: probability, \u0026#34;features\u0026#34;: features }) except Exception as e: logging.error(f\u0026#34;Error: {e}\u0026#34;) status_code = extract_status_code(str(e)) if status_code: return jsonify({\u0026#34;success\u0026#34;: False, \u0026#34;message\u0026#34;: status_code}), 500 else: return jsonify({\u0026#34;success\u0026#34;: False, \u0026#34;message\u0026#34;: \u0026#34;Invalid URL\u0026#34;}), 500 Esta API permite la clasificación en tiempo real de URLs, haciendo que la detección de phishing esté al alcance de los usuarios.\nDirectorios y Archivos Clave:\napp/: Contiene los archivos de la aplicación Flask. static/: Activos estáticos como CSS y JavaScript. templates/: Plantillas HTML. __init__.py: Inicializa la aplicación Flask y la caché. routes.py: Define las rutas de Flask y la lógica de predicción. data/: Almacenamiento de datos. raw/: Datos originales, no procesados. processed/: Datos limpiados y procesados. external/: Conjuntos de datos o recursos externos. notebooks/: Cuadernos de Jupyter para exploración y modelado. src/: Código fuente para pipelines de ML. feature_pipeline.py: Ingeniería y selección de características. model_pipeline.py: Entrenamiento y evaluación del modelo. inference_pipeline.py: Inferencia de datos para predicción directa en consola. config.py: Parámetros de configuración. utils.py: Funciones auxiliares. models/: Modelos y pipelines serializados. phishing_model.pkl: Modelo de machine learning entrenado. reports/: Documentación e informes. requirements.txt: Dependencias de Python. setup.py: Script de configuración del paquete. run_pipeline.py: Script para ejecutar pipelines de ML. run_app.py: Script para iniciar la aplicación Flask. Dockerfile: Configuración de Docker para contenedorización. .gitignore: Archivos y directorios que se deben ignorar en Git. README.md: Documentación del proyecto. Interfaz de la Aplicación #Así es como se ve la aplicación en acción:\n1. Ingreso de una URL #La interfaz principal proporciona un campo de entrada simple donde los usuarios pueden ingresar una URL para verificar amenazas de phishing.\n2. Escaneo de la URL #Una vez que la URL es enviada, la aplicación procesa la solicitud y devuelve una predicción. A continuación, la URL \u0026ldquo;randolphrogers.me\u0026rdquo; ha sido clasificada como segura con una probabilidad del 95.00%.\n3. Vista de Depuración #Para obtener más detalles, una versión de depuración muestra un desglose de todas las características extraídas y sus puntuaciones individuales, brindando transparencia al proceso de clasificación.\nResultados y Análisis #Después de construir con éxito la aplicación y la canalización de extracción de características, probé el modelo en datos completamente nuevos, incluidos sitios confirmados como phishing. Sin embargo, los resultados fueron decepcionantes. El modelo, que había tenido un desempeño casi perfecto durante la evaluación, luchó por clasificar correctamente los sitios de phishing en escenarios del mundo real.\nIdentificación del Problema: ¿Sobreajuste o Limitaciones del Conjunto de Datos? #Al principio, sospeché de un sobreajuste. Revisé mis procedimientos de entrenamiento y prueba, pero todas las métricas de rendimiento sugerían un modelo bien entrenado. Para investigar más a fondo, creé un nuevo conjunto de datos de retención, simulando condiciones del mundo real, y evalué el modelo nuevamente. ¿Los resultados? Excelente desempeño, al igual que en el entrenamiento.\nEsto planteó una pregunta crítica: ¿Por qué el modelo falló en sitios de phishing reales, pero funcionó bien con los datos de prueba?\nDepuración con Inspección de Características #Usando el modo de depuración de la aplicación, examiné manualmente los resultados de cada sitio de phishing incorrectamente clasificado, comparando sus valores de características con lo que el modelo había aprendido. Esto llevó a un descubrimiento clave:\nCada nuevo sitio de phishing seguía casi todas las características de detección de phishing más importantes de mi conjunto de datos.\nEl verdadero problema se hizo evidente. El conjunto de datos que utilicé para entrenar estaba obsoleto.\nLa Carrera Armamentista en Ciberseguridad: Por Qué los Datos Recientes Importan #En ciberseguridad, existe una carrera entre los atacantes (equipo rojo) y los defensores (equipo azul). Nuevas técnicas de phishing surgen a medida que las medidas de seguridad evolucionan, y los patrones de detección antiguos se vuelven ineficaces. Mi conjunto de datos estaba desactualizado, lo que significaba que el modelo había aprendido a detectar las tendencias de phishing pasadas en lugar de las amenazas más recientes.\nBuscando Datos Actualizados: Un Nuevo Conjunto de Datos, Nuevos Desafíos #Después de darme cuenta de esto, busqué un conjunto de datos más reciente. El mejor que encontré fue recolectado dos años después que mi conjunto original. Sin embargo, tenía solo 17 características en lugar de mis 30. Volví a entrenar y probar el modelo usando este conjunto de datos, y aunque los resultados fueron ligeramente más débiles, todavía fueron comparables.\nEsto confirmó que, si bien la frescura de los datos es crítica, la riqueza de las características también juega un papel importante en mantener un buen rendimiento del modelo.\nLimitaciones de la Recopilación de Datos Modernos #Uno de los mayores desafíos en el aprendizaje automático relacionado con la ciberseguridad es el acceso a datos actualizados. Muchas fuentes que anteriormente proporcionaban información útil ya no están disponibles.\nPor ejemplo:\nAlexa Internet, que proporcionaba clasificaciones de tráfico web para millones de sitios web, fue cerrada en 2022 Varias bases de datos clave de inteligencia de amenazas ahora restringen el acceso a través de APIs costosas o servicios de nivel empresarial Muchas características de mi conjunto original ahora son más difíciles de extraer debido a medidas de seguridad más estrictas en los sitios web Como proyecto secundario, estos costos son excesivamente altos, lo que dificulta actualizar y mejorar continuamente el modelo.\nReflexiones: Lo que Este Proyecto Me Enseñó #Aunque los resultados no fueron lo que esperaba, este proyecto resultó ser una valiosa experiencia de aprendizaje. Me obligó a\nReevaluar mi proceso de entrenamiento y probar mi modelo en condiciones más realistas Desarrollar métodos alternativos de evaluación para simular datos del mundo real Pensar críticamente sobre la validez de los datos, en lugar de solo sobre la precisión del modelo Esta experiencia reforzó una lección clave. En ciberseguridad, los modelos son tan buenos como los datos con los que se entrenan.\nAdemás, me di cuenta de que la puntuación de probabilidad que mostraba mi modelo podría no estar calibrada correctamente. Los usuarios podrían interpretarla de manera diferente a lo que el modelo realmente representa. Un paso de calibración de probabilidad podría mejorar la interpretabilidad.\nDesafíos y Lecciones Aprendidas #Cada proyecto presenta obstáculos, y este no fue diferente. Aquí hay algunos de los principales desafíos que enfrenté:\nDatos de entrenamiento desactualizados. El conjunto de datos que utilicé ya no era efectivo para identificar ataques de phishing modernos Datos limitados de WHOIS. Los registros de WHOIS a menudo estaban incompletos, lo que limitaba el análisis de la antigüedad de los dominios Equilibrar el rendimiento del modelo. Reducir los falsos positivos era crucial. Etiquetar incorrectamente sitios legítimos podría generar frustración en los usuarios Acceso a datos actualizados. Muchas fuentes útiles de datos ahora están restringidas detrás de servicios pagos, limitando las capacidades de extracción de características A pesar de estos desafíos, obtuve perspectivas invaluable sobre tanto el aprendizaje automático en ciberseguridad como sobre la importancia de los conjuntos de datos en evolución continua.\nMejoras Futuras #Siempre hay espacio para mejorar. Aquí hay algunas áreas que me gustaría explorar a continuación:\n✅ Usar Aprendizaje Profundo. Experimentar con redes neuronales para mejorar la precisión de la clasificación\n✅ Mejorar la Ingeniería de Características. Explorar nuevas técnicas de extracción de características, especialmente desde el análisis del contenido de las páginas web\n✅ Integrar Inteligencia de Amenazas. Verificar las URLs contra bases de datos de phishing en tiempo real para una mejor validación\n✅ Desplegar como una Extensión de Navegador. Permitir que los usuarios verifiquen URLs directamente desde sus navegadores, haciendo la herramienta más accesible\n✅ Calibrar las Puntuaciones de Probabilidad del Modelo. Asegurar que las probabilidades mostradas reflejen los niveles de confianza reales en lugar de engañar a los usuarios\nConclusión #Este proyecto fue una emocionante mezcla de ciberseguridad y aprendizaje automático, permitiéndome crear una herramienta práctica que puede ayudar a los usuarios a mantenerse seguros en línea. Al extraer características clave de las URLs y usar un modelo entrenado para la clasificación, la aplicación proporciona un sistema automatizado de detección de phishing.\nSin embargo, la lección más importante no se trató de la precisión del modelo. Se trató de la relevancia de los datos. No importa cuán avanzado sea un modelo de aprendizaje automático, si se entrena con información desactualizada, sus predicciones se volverán poco confiables con el tiempo.\nEn el futuro, planeo explorar métodos más dinámicos para actualizar y adaptar continuamente los modelos de detección de phishing.\nGracias por leer. Si estás interesado en proyectos similares o tienes sugerencias para mejoras, no dudes en ponerte en contacto.\nKeywords: Phishing Detection, Machine Learning, Flask, Cybersecurity, URL Classification\n","date":"26 septiembre 2024","permalink":"/es/portfolio/phishing-domain-classifier/","section":"Portafolio","summary":"Introducción #Los ataques de phishing son una de las amenazas más comunes en ciberseguridad hoy en día, engañando a los usuarios para que proporcionen información sensible a través de sitios web maliciosos.","title":"Modelo Clasificador de Dominios Phishing"},{"content":" Introducción #Las redes sociales se han convertido en una plataforma clave para discutir temas globales, y la pandemia de Covid-19 no fue la excepción. Millones de usuarios compartieron sus opiniones sobre las vacunas del Covid-19 en Twitter, que iban desde la aprobación absoluta hasta el escepticismo y la desinformación. Para comprender mejor estas opiniones, realicé un Análisis de Sentimiento sobre las vacunas del Covid-19 en Twitter utilizando Procesamiento de Lenguaje Natural (NLP) como parte de un trabajo durante mi licenciatura.\nEste proyecto tenía como objetivo explorar cómo reaccionó el público ante las vacunas del Covid-19 a lo largo del tiempo, qué vacunas fueron más favorecidas y cómo la desinformación jugó un papel importante en la formación de las discusiones. En este blog, te guiaré a través del proceso de recolección de datos, las técnicas de análisis de sentimiento y los conocimientos clave obtenidos a partir de más de 614,000 tweets relacionados con las vacunas del Covid-19.\nRecolección de Datos y Preprocesamiento #1. Fuente de los Datos #El conjunto de datos fue obtenido de Kaggle, que contenía tweets sobre las vacunas del Covid-19 recolectados por diferentes usuarios. El conjunto de datos consistió en dos fuentes principales:\nTweets sobre la Vacuna Covid Tweets sobre Todas las vacunas del Covid-19-19 Estos conjuntos de datos fueron fusionados, lo que resultó en un conjunto de datos final de 614,074 tweets que abarcan desde enero de 2020 hasta abril de 2022. El conjunto de datos proporcionó una visión amplia del sentimiento público a lo largo de diferentes etapas de la pandemia, incluyendo el desarrollo de vacunas, aprobaciones y distribuciones.\niduser_nameuser_locationuser_descriptionuser_createduser_followersuser_friendsuser_favouritesuser_verifieddatetexthashtagssourceretweetsfavoritesis_retweet01340539111971516416Rachel RohLa Crescenta-Montrose, CAAggregator of Asian American news; scanning diverse sources 24/7/365. RT's, Follows and 'Likes' will fuel me 👩‍💻2009-04-08 17:52:4640516923247False2020-12-20 06:06:44Same folks said daikon paste could treat a cytokine storm #PfizerBioNTech https://t.co/xeHhIMg1kF['PfizerBioNTech']Twitter for Android00False11338158543359250433Albert FongSan Francisco, CAMarketing dude, tech geek, heavy metal \u0026amp; '80s music junkie. Fascinated by meteorology and all things in the cloud. Opinions are my own.2009-09-21 15:27:30834666178False2020-12-13 16:27:13While the world has been on the wrong side of history this year, hopefully, the biggest vaccination effort we've ev… https://t.co/dlCHrZjkhmNaNTwitter Web App11False 2. Pasos de Preprocesamiento #Antes de aplicar el análisis de sentimiento, los datos pasaron por un extenso proceso de limpieza y transformación para eliminar el ruido y estandarizar el texto para su análisis. Los siguientes pasos fueron implementados:\nEliminación de tweets duplicados y contenido generado por bots: Para evitar sesgar los resultados. Eliminación de URLs, menciones y hashtags para centrarse solo en el contenido textual. Tokenización: Dividir las oraciones en palabras individuales. Lematización: Convertir las palabras a sus formas base (por ejemplo, \u0026ldquo;corriendo\u0026rdquo; → \u0026ldquo;correr\u0026rdquo;). Eliminación de palabras vacías: Filtrar palabras comunes como \u0026ldquo;el,\u0026rdquo; \u0026ldquo;y,\u0026rdquo; y \u0026ldquo;es\u0026rdquo; que no contribuyen al sentimiento. Manejo de caracteres especiales y emojis: Convertir los emojis en representaciones de texto para conservar el sentimiento. Para estas tareas, se utilizaron bibliotecas de Python como TextBlob, NLTK, pandas y NeatText. El objetivo era crear un conjunto de datos que reflejara con precisión el sentimiento humano sin que los puntos de datos irrelevantes afectaran los resultados. Después de limpiar los datos, el conjunto resultante consistió en 482,523 tweets.\nMetodología de Análisis de Sentimiento #1. Clasificación de Sentimiento #Cada tweet fue clasificado en una de tres categorías de sentimiento:\nPositivo: Opiniones favorables sobre las vacunas del Covid-19. Neutral: Tweets informativos o no opuestos. Negativo: Escepticismo, desinformación o desconfianza hacia las vacunas. Esta clasificación se realizó utilizando TextBlob, una biblioteca de Python que asigna puntajes de polaridad al texto:\nPolaridad varía de -1 (negativo) a +1 (positivo). Un puntaje de polaridad \u0026gt;0 se considera positivo, \u0026lt;0 negativo y 0 neutral. 2. Análisis de Subjetividad #También se midió la subjetividad, que determina cuán factual frente a opnativo es un tweet. Los puntajes de subjetividad ayudaron a distinguir entre reportes de noticias fácticos y opiniones personales, permitiendo ver cuánto del discurso sobre las vacunas se basó en emociones en lugar de hechos verificables.\nAnálisis de Sentimiento con TextBlob #Esta función de Python utiliza la biblioteca TextBlob para analizar el sentimiento de un texto dado. Retorna un diccionario que contiene la polaridad, subjetividad y la clasificación general del sentimiento del texto.\nfrom textblob import TextBlob def analyze_sentiment(text): analysis = TextBlob(text) polarity = analysis.sentiment.polarity subjectivity = analysis.sentiment.subjectivity if polarity \u0026gt; 0: sentiment = \u0026#39;Positive\u0026#39; elif polarity == 0: sentiment = \u0026#39;Neutral\u0026#39; else: sentiment = \u0026#39;Negative\u0026#39; result = { \u0026#39;polarity\u0026#39;: polarity, \u0026#39;subjectivity\u0026#39;: subjectivity, \u0026#39;sentiment\u0026#39;: sentiment } return result Hallazgos Clave #1. Distribución General del Sentimiento # El conjunto de datos mostró la siguiente distribución de sentimientos:\n42.6% Positivo 43.8% Neutral 13.6% Negativo Esto indica que, aunque la mayoría de los tweets fueron neutrales, el sentimiento positivo hacia las vacunas superó ligeramente al sentimiento negativo. Este es un hallazgo alentador, que muestra que, a pesar de la vacilación hacia las vacunas y la desinformación, los usuarios de las redes sociales fueron en su mayoría solidarios o al menos informativos sobre las vacunas.\n2. Sentimiento Específico por Vacuna #Los puntajes de sentimiento para diferentes vacunas fueron los siguientes:\nVacuna Polaridad Subjetividad Pfizer 0.1163 0.3176 AstraZeneca 0.114 0.2685 Sputnik 0.1082 0.3041 Covaxin 0.1080 0.2541 Moderna 0.1047 0.2954 Pfizer tuvo la mayor aceptación basada en la polaridad. Moderna tuvo la polaridad más baja, pero aún estaba por encima de 0, indicando un sentimiento positivo en general. Covaxin tuvo la subjetividad más baja, lo que significa que se hicieron más declaraciones objetivas sobre ella. Estos resultados reflejan cómo diferentes vacunas fueron recibidas por el público y proporcionan información sobre la confianza y percepción de la marca.\n3. Análisis de Series Temporales de Sentimiento # El análisis del sentimiento a lo largo del tiempo reveló tendencias clave:\nA principios de 2020 hubo baja actividad en los tuits sobre las vacunas debido a la falta de información disponible. El sentimiento aumentó en diciembre de 2020, coincidiendo con el lanzamiento de la vacuna de Pfizer bajo autorización de uso de emergencia (EUA). El mayor pico en el sentimiento ocurrió en agosto de 2021, coincidiendo con la aprobación de la tercera dosis en EE. UU. 4. Palabras Más Comunes en las Categorías de Sentimiento #Utilizando nubes de palabras, identificamos las palabras más frecuentemente utilizadas en diferentes categorías de sentimiento:\nPalabras Positivas: # Vacuna, Eficiente, Agradecido, Seguro, Increíble, Voluntario Palabras Negativas: # Peligroso, Asustado, Desinformación, Efectos secundarios, Arriesgado Palabras Neutras: # Vacuna, Dosis, Salud, Disponible, Anuncio Desafíos y Limitaciones #Aunque el análisis proporcionó perspectivas valiosas, también enfrentó algunas limitaciones:\nSesgo en los Datos de Twitter: El conjunto de datos puede no representar la opinión de la población global. Detección de Ironía y Sarcasmo: Algunos tuits con sarcasmo pueden haber sido mal clasificados. Tuits Generados por Bots: A pesar de la filtración, algunos tuits automatizados podrían haber influido en los resultados. Conclusión y Lecciones Aprendidas #Este proyecto proporcionó una perspectiva basada en datos sobre el sentimiento público hacia las vacunas contra el Covid, destacando tendencias clave y reacciones. Las principales lecciones aprendidas son:\nEl sentimiento público fue en su mayoría neutral a positivo. Pfizer tuvo la percepción más positiva entre las vacunas. El sentimiento aumentó durante los hitos clave de aprobación de las vacunas. Entender la opinión pública es crucial para campañas de salud pública, combatir la desinformación y mejorar las estrategias de distribución de vacunas. Las mejoras futuras podrían incluir modelos de sentimiento basados en deep learning y análisis en tiempo real de la percepción de las vacunas.\n¡Gracias por leer! Si tienes alguna pregunta o comentario, no dudes en contactarme. Aprecio mucho tu retroalimentación.\nKeywords: NLP, Sentiment Analysis, Covid, Machine Learning, Data Science\n","date":"5 agosto 2022","permalink":"/es/portfolio/twitter-covid-vaccines-sentiment/","section":"Portafolio","summary":"Introducción #Las redes sociales se han convertido en una plataforma clave para discutir temas globales, y la pandemia de Covid-19 no fue la excepción.","title":"Análisis de Sentimiento sobre la Vacuna del Covid-19 en Twitter"},{"content":"","date":null,"permalink":"/es/tags/covid-19/","section":"Etiquetas","summary":"","title":"Covid-19"},{"content":"","date":null,"permalink":"/es/tags/nlp/","section":"Etiquetas","summary":"","title":"NLP"},{"content":"","date":null,"permalink":"/es/tags/sentiment-analysis/","section":"Etiquetas","summary":"","title":"Sentiment Analysis"},{"content":"","date":null,"permalink":"/es/tags/twitter-data/","section":"Etiquetas","summary":"","title":"Twitter Data"}]