import pandas as pd from sklearn.ensemble import IsolationForest import joblib import pyodbc from datetime import datetime, timedelta print("--- INICIANDO SCRIPT DE ENTRENAMIENTO (MONTOS CONTABLES) ---") # --- 1. Configuración --- DB_SERVER = 'TECNICA3' DB_DATABASE = 'SistemaGestion' CONNECTION_STRING = f'DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={DB_SERVER};DATABASE={DB_DATABASE};Trusted_Connection=yes;TrustServerCertificate=yes;' MODEL_FILE = 'modelo_montos.joblib' CONTAMINATION_RATE = 0.01 # Asumimos que el 1% de las transacciones podrían ser anómalas (ajustable) # --- 2. Carga de Datos de Múltiples Tablas --- try: print(f"Conectando a la base de datos '{DB_DATABASE}' en '{DB_SERVER}'...") cnxn = pyodbc.connect(CONNECTION_STRING) fecha_limite = datetime.now() - timedelta(days=730) # Usamos 2 años de datos para tener más contexto financiero # Query para Pagos a Distribuidores query_pagos = f""" SELECT 'Distribuidor' AS entidad, Id_Distribuidor AS id_entidad, Id_Empresa AS id_empresa, Fecha AS fecha, TipoMovimiento AS tipo_transaccion, Monto AS monto FROM cue_PagosDistribuidor WHERE Fecha >= '{fecha_limite.strftime('%Y-%m-%d')}' """ # Query para Notas de Crédito/Débito query_notas = f""" SELECT CASE WHEN Destino = 'Distribuidores' THEN 'Distribuidor' WHEN Destino = 'Canillas' THEN 'Canillita' ELSE 'Desconocido' END AS entidad, Id_Destino AS id_entidad, Id_Empresa AS id_empresa, Fecha AS fecha, Tipo AS tipo_transaccion, Monto AS monto FROM cue_CreditosDebitos WHERE Fecha >= '{fecha_limite.strftime('%Y-%m-%d')}' """ print("Ejecutando consultas para obtener datos de pagos y notas...") df_pagos = pd.read_sql(query_pagos, cnxn) df_notas = pd.read_sql(query_notas, cnxn) cnxn.close() except Exception as e: print(f"Error al conectar o consultar la base de datos: {e}") exit() # --- 3. Unificación y Preparación de Datos --- if df_pagos.empty and df_notas.empty: print("No se encontraron datos de entrenamiento en el período seleccionado. Saliendo.") exit() # Combinamos ambos dataframes df = pd.concat([df_pagos, df_notas], ignore_index=True) print(f"Preparando {len(df)} registros contables para el entrenamiento...") # Feature Engineering: Convertir textos a números categóricos # Esto ayuda al modelo a entender "Recibido", "Credito", etc., como categorías distintas. df['tipo_transaccion_cat'] = pd.Categorical(df['tipo_transaccion']).codes df['dia_semana'] = df['fecha'].dt.dayofweek # Las características para el modelo serán el contexto de la transacción y su monto features = ['id_entidad', 'id_empresa', 'tipo_transaccion_cat', 'dia_semana', 'monto'] X = df[features] # --- 4. Entrenamiento y Guardado --- print(f"Entrenando el modelo de montos contables con tasa de contaminación de {CONTAMINATION_RATE}...") model = IsolationForest(n_estimators=100, contamination=CONTAMINATION_RATE, random_state=42) model.fit(X) joblib.dump(model, MODEL_FILE) print(f"--- ENTRENAMIENTO DE MONTOS COMPLETADO. Modelo guardado en '{MODEL_FILE}' ---")