Created
October 1, 2025 16:29
-
-
Save gabanox/0db12b3f7d1fe8cf078af8ae5474b3ed to your computer and use it in GitHub Desktop.
Generador de Transacciones de Tarjetas de Crédito - Script Python para generar datos sintéticos con indicadores de fraude
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| Generador de Transacciones de Tarjetas de Crédito | |
| Genera datos sintéticos de transacciones para proyectos de machine learning | |
| """ | |
| import random | |
| import pandas as pd | |
| from datetime import datetime, timedelta | |
| import json | |
| class GeneradorTransaccionesTarjetas: | |
| """Clase para generar transacciones sintéticas de tarjetas de crédito""" | |
| def __init__(self, num_registros=1000): | |
| self.num_registros = num_registros | |
| # Categorías de comercios | |
| self.categorias = [ | |
| 'Supermercado', 'Gasolina', 'Restaurante', 'Farmacia', | |
| 'Ropa', 'Electrónica', 'Entretenimiento', 'Viajes', | |
| 'Servicios', 'Telecomunicaciones', 'Educación', 'Salud' | |
| ] | |
| # Comercios por categoría | |
| self.comercios = { | |
| 'Supermercado': ['Walmart', 'Soriana', 'Chedraui', 'La Comer', 'Costco'], | |
| 'Gasolina': ['Pemex', 'BP', 'Shell', 'Mobil', 'Chevron'], | |
| 'Restaurante': ['Starbucks', 'McDonald\'s', 'Subway', 'Domino\'s', 'KFC', 'Italiannis'], | |
| 'Farmacia': ['Farmacias del Ahorro', 'Farmacia Guadalajara', 'Farmacias Similares', 'San Pablo'], | |
| 'Ropa': ['Zara', 'H&M', 'Liverpool', 'Palacio de Hierro', 'Coppel'], | |
| 'Electrónica': ['Best Buy', 'RadioShack', 'Office Depot', 'Amazon', 'Mercado Libre'], | |
| 'Entretenimiento': ['Cinépolis', 'Cinemex', 'Netflix', 'Spotify', 'Xbox Store'], | |
| 'Viajes': ['Volaris', 'Aeroméxico', 'Booking.com', 'Airbnb', 'Despegar'], | |
| 'Servicios': ['Uber', 'DiDi', 'Rappi', 'Cornershop', 'Izzi'], | |
| 'Telecomunicaciones': ['Telcel', 'AT&T', 'Movistar', 'Totalplay'], | |
| 'Educación': ['Udemy', 'Coursera', 'Amazon Web Services', 'LinkedIn Learning'], | |
| 'Salud': ['Hospital ABC', 'Laboratorio Chopo', 'Farmacias Similares', 'Dentegra'] | |
| } | |
| # Ciudades de México | |
| self.ciudades = [ | |
| 'Ciudad de México', 'Guadalajara', 'Monterrey', 'Puebla', | |
| 'Tijuana', 'León', 'Querétaro', 'Mérida', 'Cancún', 'Toluca' | |
| ] | |
| # Tipos de tarjeta | |
| self.tipos_tarjeta = ['Visa', 'Mastercard', 'American Express'] | |
| def generar_numero_tarjeta(self, tipo): | |
| """Genera un número de tarjeta enmascarado""" | |
| prefijos = { | |
| 'Visa': '4', | |
| 'Mastercard': '5', | |
| 'American Express': '37' | |
| } | |
| prefijo = prefijos[tipo] | |
| return f"{prefijo}{'*' * 12}{random.randint(1000, 9999)}" | |
| def generar_fecha_transaccion(self, fecha_inicio, fecha_fin): | |
| """Genera una fecha aleatoria entre dos fechas""" | |
| delta = fecha_fin - fecha_inicio | |
| random_days = random.randint(0, delta.days) | |
| random_seconds = random.randint(0, 86400) | |
| return fecha_inicio + timedelta(days=random_days, seconds=random_seconds) | |
| def es_transaccion_fraudulenta(self, probabilidad=0.05): | |
| """Determina si una transacción es fraudulenta (5% por defecto)""" | |
| return random.random() < probabilidad | |
| def generar_monto(self, categoria, es_fraude): | |
| """Genera un monto basado en la categoría y si es fraude""" | |
| # Rangos normales por categoría | |
| rangos_normales = { | |
| 'Supermercado': (100, 3000), | |
| 'Gasolina': (200, 1500), | |
| 'Restaurante': (150, 2000), | |
| 'Farmacia': (50, 800), | |
| 'Ropa': (300, 5000), | |
| 'Electrónica': (500, 15000), | |
| 'Entretenimiento': (100, 1500), | |
| 'Viajes': (1000, 20000), | |
| 'Servicios': (50, 1000), | |
| 'Telecomunicaciones': (200, 800), | |
| 'Educación': (300, 5000), | |
| 'Salud': (500, 10000) | |
| } | |
| rango = rangos_normales.get(categoria, (100, 1000)) | |
| if es_fraude: | |
| # Transacciones fraudulentas tienden a ser mayores | |
| monto = random.uniform(rango[1] * 0.8, rango[1] * 3) | |
| else: | |
| monto = random.uniform(rango[0], rango[1]) | |
| return round(monto, 2) | |
| def generar_transacciones(self): | |
| """Genera el conjunto de transacciones""" | |
| transacciones = [] | |
| # Fechas para las transacciones (últimos 90 días) | |
| fecha_fin = datetime.now() | |
| fecha_inicio = fecha_fin - timedelta(days=90) | |
| # Generar IDs de clientes (simular 200 clientes diferentes) | |
| num_clientes = 200 | |
| clientes = [f"CLI_{str(i).zfill(6)}" for i in range(1, num_clientes + 1)] | |
| for i in range(self.num_registros): | |
| # Datos básicos | |
| transaccion_id = f"TXN_{str(i+1).zfill(8)}" | |
| cliente_id = random.choice(clientes) | |
| tipo_tarjeta = random.choice(self.tipos_tarjeta) | |
| numero_tarjeta = self.generar_numero_tarjeta(tipo_tarjeta) | |
| # Categoría y comercio | |
| categoria = random.choice(self.categorias) | |
| comercio = random.choice(self.comercios[categoria]) | |
| # Fecha y hora | |
| fecha_transaccion = self.generar_fecha_transaccion(fecha_inicio, fecha_fin) | |
| # Determinar si es fraude | |
| es_fraude = self.es_transaccion_fraudulenta() | |
| # Monto | |
| monto = self.generar_monto(categoria, es_fraude) | |
| # Ubicación | |
| ciudad = random.choice(self.ciudades) | |
| # Hora del día (puede ser indicador de fraude) | |
| hora = fecha_transaccion.hour | |
| es_horario_inusual = hora < 6 or hora > 22 | |
| # Distancia desde la transacción anterior (simulada) | |
| distancia_km = random.uniform(0, 500) if es_fraude else random.uniform(0, 50) | |
| # Estado de la transacción | |
| estado = 'Rechazada' if es_fraude and random.random() > 0.3 else 'Aprobada' | |
| transaccion = { | |
| 'transaccion_id': transaccion_id, | |
| 'cliente_id': cliente_id, | |
| 'fecha': fecha_transaccion.strftime('%Y-%m-%d'), | |
| 'hora': fecha_transaccion.strftime('%H:%M:%S'), | |
| 'fecha_hora': fecha_transaccion.strftime('%Y-%m-%d %H:%M:%S'), | |
| 'tipo_tarjeta': tipo_tarjeta, | |
| 'numero_tarjeta': numero_tarjeta, | |
| 'comercio': comercio, | |
| 'categoria': categoria, | |
| 'monto': monto, | |
| 'ciudad': ciudad, | |
| 'distancia_km': round(distancia_km, 2), | |
| 'es_horario_inusual': es_horario_inusual, | |
| 'estado': estado, | |
| 'es_fraude': es_fraude | |
| } | |
| transacciones.append(transaccion) | |
| return transacciones | |
| def guardar_csv(self, transacciones, nombre_archivo='transacciones_tarjetas.csv'): | |
| """Guarda las transacciones en formato CSV""" | |
| df = pd.DataFrame(transacciones) | |
| df.to_csv(nombre_archivo, index=False, encoding='utf-8-sig') | |
| print(f"✓ Archivo CSV guardado: {nombre_archivo}") | |
| return df | |
| def guardar_json(self, transacciones, nombre_archivo='transacciones_tarjetas.json'): | |
| """Guarda las transacciones en formato JSON""" | |
| with open(nombre_archivo, 'w', encoding='utf-8') as f: | |
| json.dump(transacciones, f, ensure_ascii=False, indent=2) | |
| print(f"✓ Archivo JSON guardado: {nombre_archivo}") | |
| def generar_estadisticas(self, df): | |
| """Genera estadísticas del conjunto de datos""" | |
| print("\n" + "="*60) | |
| print("ESTADÍSTICAS DE TRANSACCIONES GENERADAS") | |
| print("="*60) | |
| print(f"\nTotal de transacciones: {len(df)}") | |
| print(f"Transacciones fraudulentas: {df['es_fraude'].sum()} ({df['es_fraude'].mean()*100:.2f}%)") | |
| print(f"Transacciones aprobadas: {(df['estado'] == 'Aprobada').sum()}") | |
| print(f"Transacciones rechazadas: {(df['estado'] == 'Rechazada').sum()}") | |
| print(f"\nMonto total: ${df['monto'].sum():,.2f}") | |
| print(f"Monto promedio: ${df['monto'].mean():,.2f}") | |
| print(f"Monto mínimo: ${df['monto'].min():,.2f}") | |
| print(f"Monto máximo: ${df['monto'].max():,.2f}") | |
| print(f"\nClientes únicos: {df['cliente_id'].nunique()}") | |
| print(f"Comercios únicos: {df['comercio'].nunique()}") | |
| print("\n" + "-"*60) | |
| print("TRANSACCIONES POR CATEGORÍA:") | |
| print("-"*60) | |
| print(df['categoria'].value_counts().to_string()) | |
| print("\n" + "-"*60) | |
| print("TRANSACCIONES POR TIPO DE TARJETA:") | |
| print("-"*60) | |
| print(df['tipo_tarjeta'].value_counts().to_string()) | |
| print("\n" + "-"*60) | |
| print("MONTO PROMEDIO POR CATEGORÍA:") | |
| print("-"*60) | |
| print(df.groupby('categoria')['monto'].mean().sort_values(ascending=False).apply(lambda x: f"${x:,.2f}").to_string()) | |
| print("\n" + "="*60 + "\n") | |
| def main(): | |
| """Función principal""" | |
| print("="*60) | |
| print("GENERADOR DE TRANSACCIONES DE TARJETAS DE CRÉDITO") | |
| print("="*60) | |
| print("\nGenerando 1000 transacciones sintéticas...\n") | |
| # Crear generador | |
| generador = GeneradorTransaccionesTarjetas(num_registros=1000) | |
| # Generar transacciones | |
| transacciones = generador.generar_transacciones() | |
| # Guardar en CSV y JSON | |
| df = generador.guardar_csv(transacciones) | |
| generador.guardar_json(transacciones) | |
| # Mostrar estadísticas | |
| generador.generar_estadisticas(df) | |
| # Mostrar muestra de datos | |
| print("MUESTRA DE DATOS (primeras 5 transacciones):") | |
| print("-"*60) | |
| print(df.head().to_string()) | |
| print("\n") | |
| if __name__ == "__main__": | |
| main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment