import pandas as pd from sklearn.ensemble import IsolationForest import joblib import pyodbc from datetime import datetime, timedelta print("--- INICIANDO SCRIPT DE ENTRENAMIENTO (DISTRIBUIDORES) ---") # --- 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_anomalias_dist.joblib' CONTAMINATION_RATE = 0.01 # Un 1% de contaminación # --- 2. Carga de Datos desde SQL Server --- 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) query = f""" SELECT Id_Distribuidor AS id_distribuidor, CAST(Fecha AS DATE) AS fecha, SUM(CASE WHEN TipoMovimiento = 'Salida' THEN Cantidad ELSE 0 END) as cantidad_enviada, SUM(CASE WHEN TipoMovimiento = 'Entrada' THEN Cantidad ELSE 0 END) as cantidad_devuelta FROM dist_EntradasSalidas WHERE Fecha >= '{fecha_limite.strftime('%Y-%m-%d')}' GROUP BY Id_Distribuidor, CAST(Fecha AS DATE) HAVING SUM(CASE WHEN TipoMovimiento = 'Salida' THEN Cantidad ELSE 0 END) > 0 """ print("Ejecutando consulta para obtener datos de entrenamiento de distribuidores...") df = pd.read_sql(query, cnxn) cnxn.close() except Exception as e: print(f"Error al conectar o consultar la base de datos: {e}") exit() if df.empty: print("No se encontraron datos de entrenamiento de distribuidores en el último año. Saliendo.") exit() # --- 3. Preparación de Datos --- print(f"Preparando {len(df)} registros para el entrenamiento del modelo de distribuidores...") # Se usa (df['cantidad_enviada'] + 0.001) para evitar división por cero df['porcentaje_devolucion'] = (df['cantidad_devuelta'] / (df['cantidad_enviada'] + 0.001)) * 100 df.fillna(0, inplace=True) df['porcentaje_devolucion'] = df['porcentaje_devolucion'].clip(0, 100) df['dia_semana'] = pd.to_datetime(df['fecha']).dt.dayofweek features = ['id_distribuidor', 'porcentaje_devolucion', 'dia_semana'] X = df[features] # --- 4. Entrenamiento y Guardado --- print(f"Entrenando el modelo 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 DISTRIBUIDORES COMPLETADO. Modelo guardado en '{MODEL_FILE}' ---")