Abstracto
Los conjuntos de datos están extremadamente desequilibrados, con tasas positivas inferiores al 0,2%. Las redes neuronales estándar entrenadas con entropía cruzada binaria ponderada a menudo logran un ROC-AUC alto, pero tienen dificultades para identificar transacciones sospechosas bajo métricas sensibles a umbrales. Propongo un enfoque híbrido neurosimbólico (HNS) que incorpora conocimiento del dominio directamente en el objetivo de capacitación como una pérdida de regla diferenciable, fomentando que el modelo asigne una alta probabilidad de fraude a transacciones con cantidades inusualmente grandes y firmas PCA atípicas. En el conjunto de datos de Kaggle Credit Card Fraud, el híbrido logra un ROC-AUC de 0,970 ± 0,005 en 5 semillas aleatorias, en comparación con 0,967 ± 0,003 para la línea de base neuronal pura bajo evaluación simétrica. Un hallazgo práctico clave: en datos desequilibrados, la estrategia de selección de umbral afecta a F1 tanto como a la arquitectura del modelo; ambos modelos deben evaluarse con el mismo enfoque para que cualquier comparación sea significativa. Los materiales de código y reproducibilidad están disponibles en GitHub.
El problema: cuando la República de China y las AUC mienten
Tenía un conjunto de datos de fraude con una tasa positiva del 0,17%. Entrené una red BCE ponderada, obtuve un ROC-AUC de 0,96, alguien dijo “bien”. Luego analicé las distribuciones de puntuación y las métricas dependientes del umbral. El modelo había descubierto silenciosamente que predecir “no fraude” en cualquier cosa ambigua era el camino de menor resistencia, y nada en la función de pérdidas estaba en desacuerdo con esa decisión.
Lo que me molestó no fueron las matemáticas. Es que la modelo no tenía idea de cómo es el fraude. Un analista junior podría decirle desde el primer día: las transacciones grandes son sospechosas, las transacciones con firmas PCA inusuales son sospechosas y, cuando ambas suceden juntas, definitivamente debe prestar atención. Ese conocimiento simplemente… nunca llega al circuito de entrenamiento. Así que realicé un experimento. ¿Qué pasaría si codificara esa intuición del analista como una restricción suave directamente en la función de pérdida, algo que la red tiene que satisfacer y al mismo tiempo ajustarse a las etiquetas? El resultado fue una configuración híbrida neurosimbólica (HNS). Este artículo recorre el experimento completo: el modelo, la pérdida de reglas, el barrido lambda y, de manera crítica, lo que realmente muestra un análisis de varianza de múltiples semillas adecuado con evaluación de umbral simétrico.
La configuración
Utilicé el conjunto de datos sobre fraude con tarjetas de crédito de Kaggle: 284.807 transacciones, 492 de las cuales son fraude (0,172%). Las funciones V1–V28 son componentes PCA de un espacio de funciones original anónimo. La cantidad y el tiempo están sin procesar. El grave desequilibrio es el punto central; Aquí es donde los enfoques estándar comienzan a tener problemas.[1].
La división fue 70/15/15 tren/val/prueba, estratificada. Entrené cuatro cosas y las comparé cara a cara:
Bosque de aislamiento: contaminación = 0,001, se ajusta al conjunto de entrenamiento completo SVM de una clase: nu = 0,001, se ajusta solo a las muestras de entrenamiento sin fraude Neural puro: MLP de tres capas con ponderación de clase BCE +, sin conocimiento de dominio Neurosimbólico híbrido: el mismo MLP, con una penalización de regla diferenciable agregada a la pérdida
Isolation Forest y One-Class SVM sirven como prueba de instinto. Si una red supervisada con 199.000 muestras de entrenamiento no puede superar el listón establecido mediante un método no supervisado, vale la pena saberlo antes de escribir los resultados. Un modelo de aumento de gradiente sintonizado probablemente superaría a ambos enfoques neuronales; esta comparación tiene como objetivo aislar el efecto de la pérdida de reglas, no compararlos con todos los métodos posibles. El código completo de los cuatro está en GitHub.
El modelo
Nada exótico. Un MLP de tres capas con normalización por lotes después de cada capa oculta. La norma del lote importa más de lo que cabría esperar: bajo un fuerte desequilibrio de clases, las activaciones pueden variar mucho sin ella.[3].
clase MLP(nn.Module): def __init__(self, input_dim): super().__init__() self.net = nn.Sequential( nn.Linear(input_dim, 128), nn.ReLU(), nn.BatchNorm1d(128), nn.Linear(128, 64), nn.ReLU(), nn.BatchNorm1d(64), nn.Linear(64, 1) ) def adelante(self, x): devolver self.net(x)
Para la pérdida, BCEWithLogitsLoss con pos_weight, calculado como la proporción de recuentos de fraude y no fraude en el conjunto de capacitación. En este conjunto de datos eso es 577[4]. Una sola muestra fraudulenta en un lote genera 577 veces el gradiente de una muestra no fraudulenta.
pos_weight = contar(y=0) / contar(y=1) ≈ 577
Ese peso proporciona una señal direccional cuando aparece la etiqueta de fraude. Pero el modelo aún no tiene idea de qué aspecto tiene lo “sospechoso” en el espacio de características; sólo sabe que los ejemplos de fraude, cuando aparecen, deben tener una gran ponderación. Esto es diferente a saber dónde buscar lotes que no contienen ningún fraude etiquetado.
La pérdida de la regla
Aquí está la idea central. Los analistas de fraude saben empíricamente dos cosas: los montos de transacciones inusualmente altos son sospechosos y las transacciones que están lejos del comportamiento normal en el espacio de la PCA son sospechosas. Quiero que el modelo asigne altas probabilidades de fraude a las transacciones que coincidan con ambas señales, incluso cuando un lote no contenga ejemplos de fraude etiquetados.
El truco consiste en hacer que la regla sea diferenciable. Un umbral if/else (marcar cualquier transacción cuyo monto sea > 1000) es una función de paso difícil. Su gradiente es cero en todas partes excepto en el umbral mismo, donde no está definido. Eso significa que la retropropagación no tiene nada con qué funcionar; la regla no produce ninguna señal de gradiente útil y el optimizador la ignora. En su lugar, utilizo un sigmoide pronunciado centrado en la media del lote. Se aproxima al mismo comportamiento de umbral, pero se mantiene suave y diferenciable en todas partes: el gradiente es pequeño lejos del límite y alcanza un máximo cerca de él, que es exactamente donde desea que preste atención el optimizador. El resultado es una puntuación de sospecha suave entre 0 y 1:
def rule_loss(x, probs): # x[:, -1] = Monto (última columna en creditcard.csv después de eliminar Clase) # x[:, 1:29] = V1–V28 (componentes PCA, columnas 1–28) monto = x[:, -1] pca_norm = torch.norm(x[:, 1:29], dim=1) sospechoso = ( torch.sigmoid(5 * (cantidad – cantidad.media())) + torch.sigmoid(5 * (pca_norm – pca_norm.mean())) ) / 2.0 penalización = sospechoso * torch.relu(0.6 – probs.squeeze()) return penalización.mean()
Una nota sobre por qué la norma PCA específicamente: las características V1-V28 son el resultado de una transformación PCA aplicada a los datos de transacción anonimizados originales. Una transacción que se encuentra lejos del origen en este espacio comprimido tiene una variación inusual en múltiples características originales simultáneamente: es un valor atípico en la representación latente. La norma euclidiana del vector PCA captura esa distancia en un único escalar. Este no es un truco específico de Kaggle. En cualquier conjunto de datos donde los componentes del PCA representan una variación de comportamiento normal, la norma de esos componentes es un indicador razonable de la atipicidad. Si sus características no están transformadas por PCA, debe reemplazarlas con una señal apropiada para el dominio: distancia de Mahalanobis, puntuación de aislamiento o una puntuación z específica de la característica.
El término relu(0,6 – probs) es la restricción: se activa sólo cuando la probabilidad de fraude prevista por el modelo es inferior a 0,6 para una transacción sospechosa. Si el modelo ya tiene confianza (probabilidad > 0,6), la penalización es cero. Esto es intencional: no estoy penalizando al modelo por ser demasiado agresivo con las transacciones sospechosas, sólo por ser demasiado conservador. La asimetría significa que la regla nunca podrá luchar contra una predicción correcta de alta confianza.
Formalmente, el objetivo combinado es:
L_total = L_BCE + λ · L_regla
L_rule = E[ σ_susp(x) · ReLU(0.6 − p) ]
σ_susp(x) = ½ · [ σ(5·(cantidad − ā)) + σ(5·(‖V₁₋₂₈‖ − media‖V‖)) ]
El hiperparámetro λ controla con qué fuerza presiona la regla. En λ=0 se obtiene la línea de base neuronal pura. El circuito de entrenamiento completo:
para xb, yb en train_loader: xb, yb = xb.to(DISPOSITIVO), yb.to(DISPOSITIVO) logits = modelo(xb) bce = criterio(logits.squeeze(), yb) probs = torch.sigmoid(logits) rl = rule_loss(xb, probs) pérdida = bce + lambda_rule * rl optimizador.zero_grad() pérdida.retroceso() optimizador.paso()
Sintonización Lambda
Cinco valores probados: 0,0, 0,1, 0,5, 1,0, 2,0. Cada modelo entrenado para la mejor validación PR-AUC con parada temprana en paciencia=7, semilla=42:
Lambda 0.0 → Val PR-AUC: 0.7580 Lambda 0.1 → Val PR-AUC: 0.7595 Lambda 0.5 → Val PR-AUC: 0.7620 ← mejor Lambda 1.0 → Val PR-AUC: 0.7452 Lambda 2.0 → Val PR-AUC: 0.7504 Mejor Lambda: 0.5
λ=0,5 gana por poco en la validación PR-AUC. La brecha entre λ=0,0, 0,1 y 0,5 es pequeña, dentro del rango de varianza de las semillas, como muestra el análisis de múltiples semillas a continuación. La caída significativa en λ=1,0 y 2,0 sugiere que una ponderación agresiva de las reglas puede anular la señal del BCE en lugar de complementarla. En datos nuevos, trate λ=0 como valor predeterminado y verifique que se mantenga cualquier mejora en todas las semillas antes de confiar en ellos.
Una cosa con la que hay que tener cuidado con la selección del umbral: calculé el umbral F1 óptimo en el conjunto de validación y lo apliqué al conjunto de prueba, para ambos modelos de forma simétrica. En un conjunto de datos con una tasa positiva del 0,17%, el límite de decisión óptimo no está ni cerca de 0,5. Aplicar diferentes estrategias de umbral a diferentes modelos significa medir la brecha del umbral, no la brecha del modelo. Ambos deben utilizar el mismo enfoque:
def find_best_threshold(y_true, probs): precisión, recuperación, umbrales = precision_recall_curve(y_true, probs) f1_scores = 2*(precision*recall) / (precision+recall+1e-8) return umbrales[np.argmax(f1_scores)] # Aplicado simétricamente a AMBOS modelos: val solo establece hybrid_thresh, _ = find_best_threshold(y_val, hybrid_val_probs) pure_thresh, _ = find_best_threshold(y_val, pure_val_probs)
Resultados
En esta semilla, el híbrido y la línea de base pura son competitivos en F1 (0,767 frente a 0,776) e idénticos en Recall@1%FPR. El PR-AUC del híbrido es menor en esta semilla en particular (0,745 frente a 0,806). La señal más limpia es ROC-AUC: 0,970 para el híbrido frente a 0,969 para la línea base pura. ROC-AUC es independiente del umbral y mide la calidad de la clasificación en todos los límites posibles. Esa ventaja es donde la pérdida de reglas se muestra de manera más consistente.
Curva de recuperación de precisión
Lo que se desea en un sistema de fraude es una gran precisión temprana. La curva se mantiene razonablemente antes de caer, lo que significa que las transacciones mejor clasificadas del modelo son genuinamente fraudulentas, no solo un umbral de suerte. En producción, usted ajustaría el umbral a su relación de costos real: el costo de un fraude fallido versus el costo de una falsa alarma. El umbral F1 optimizado con valor utilizado aquí es un término medio razonable para la generación de informes, no la única opción válida.
Matriz de confusión
Distribuciones de puntuación
Este histograma es lo que miro primero después de entrenar cualquier clasificador con datos desequilibrados. La distribución no fraudulenta debería llegar a casi cero; la distribución del fraude debería extenderse hacia 1. La región de superposición en el medio es donde el modelo es genuinamente incierto: ahí es donde reside su umbral.
Análisis de varianza: 5 semillas aleatorias
Un resultado de una sola semilla en un conjunto de datos tan desequilibrado no es suficiente para confiar. Ejecuté ambos modelos en semillas [42, 0, 7, 123, 2024], aplicando umbrales optimizados para valores simétricamente a ambos en cada ejecución:
Semilla 42 | Híbrido F1: 0,767 PR-AUC: 0,745 | F1 pura: 0,776 PR-AUC: 0,806 Semilla 0 | Híbrido F1: 0,733 PR-AUC: 0,636 | F1 pura: 0,788 PR-AUC: 0,743 Semilla 7 | Híbrido F1: 0,809 PR-AUC: 0,817 | F1 pura: 0,767 PR-AUC: 0,755 Semilla 123 | Híbrido F1: 0,797 PR-AUC: 0,756 | F1 pura: 0,757 PR-AUC: 0,731 Semilla 2024 | Híbrido F1: 0,764 PR-AUC: 0,745 | F1 puro: 0,826 PR-AUC: 0,763
Tres observaciones de los datos de varianza. El híbrido gana en F1 en 2 de 5 semillas; la línea de base pura gana en 3 de 5. Ninguno de los dos domina en las métricas dependientes del umbral. La varianza PR-AUC del híbrido es notablemente mayor (±0,058 frente a ±0,026), lo que significa que la pérdida de reglas hace que algunas inicializaciones sean mejores y otras peores; es una sensibilidad, no una mejora garantizada. El único resultado que se cumple sin excepción: ROC-AUC es mayor para el híbrido en las 5 semillas. Esa es la señal más limpia de este experimento.
¿Por qué la pérdida de reglas ayuda a ROC-AUC?
ROC-AUC es independiente del umbral: mide qué tan bien el modelo clasifica el fraude por encima del no fraude en todos los límites posibles. Una mejora constante en 5 semillas es una señal real. Esto es lo que creo que está sucediendo.
Con una prevalencia de fraude del 0,172 %, la mayoría de los lotes de 2048 muestras contienen solo entre 3 y 4 ejemplos de fraude etiquetados. La pérdida del BCE casi no recibe ningún gradiente relevante para el fraude en la mayoría de los lotes. La pérdida de reglas se activa en cada transacción sospechosa independientemente de la etiqueta: genera señales de gradiente en lotes que de otro modo no le dirían al optimizador casi nada sobre el fraude. Esto le da al modelo una dirección consistente durante toda la capacitación, no solo en los raros lotes donde aparece un fraude etiquetado.
La penalización también es selectiva en función de las características. Al apuntar el modelo específicamente hacia la cantidad y la norma PCA, la regla reduce la posibilidad de que el modelo se aferre a correlaciones irrelevantes en las otras 28 dimensiones. Funciona como una regularización suave sobre el espacio de características, no solo sobre el espacio de salida.
El relu unilateral también importa. No estoy penalizando al modelo por ser demasiado agresivo con las transacciones sospechosas, sólo por ser demasiado conservador. La regla no puede luchar contra una predicción correcta y de alta confianza, sólo empuja hacia arriba las que tienen poca confianza. Esa asimetría es deliberada.
La lección no es que las reglas reemplacen el aprendizaje. Es que las reglas pueden guiarlo, especialmente cuando los ejemplos etiquetados son escasos y ya sabes algo sobre lo que estás buscando.
Sobre la evaluación de umbral en una clasificación desequilibrada
Un hallazgo de este experimento merece su propia sección porque se aplica a cualquier problema de clasificación desequilibrado, no sólo al fraude.
En un conjunto de datos con una tasa positiva del 0,17%, el umbral F1 óptimo no está ni cerca de 0,5. Un modelo puede clasificar el fraude casi a la perfección y aún así obtener una puntuación baja en F1 en un umbral predeterminado, simplemente porque el límite de decisión debe calibrarse según el desequilibrio de clases. Esto significa que si dos modelos se evalúan con diferentes estrategias de umbral (uno con un límite fijo y el otro con un límite optimizado para el valor), no se están comparando modelos. Estás midiendo la brecha del umbral.
La lista de verificación práctica para una comparación limpia de datos desequilibrados:
Ambos modelos se evaluaron con la misma estrategia de umbral. Umbral seleccionado según los datos de validación, nunca según los datos de prueba. PR-AUC y ROC-AUC informados junto con F1; ambos son independientes del umbral. Varianza entre múltiples semillas para separar las diferencias reales de la inicialización afortunada.
Cosas a tener en cuenta
Estadísticas relativas a lotes. La regla calcula la “cantidad alta” y la “norma de PCA alta” en relación con la media del lote, no una estadística de población fija. Durante el entrenamiento con lotes grandes (2048) y muestreo estratificado, las medias de los lotes son lo suficientemente estables. En la inferencia en línea que califica transacciones individuales, congele esas estadísticas en valores establecidos de entrenamiento. De lo contrario, el límite "sospechoso" cambia con cada llamada.
La varianza PR-AUC aumenta con la pérdida de la regla. El PR-AUC híbrido oscila entre 0,636 y 0,817 entre semillas, frente a 0,731 y 0,806 para la línea de base pura. Una regla que ayuda en algunas inicializaciones y perjudica en otras requiere una validación de múltiples semillas antes de sacar conclusiones. Los resultados de una sola semilla no son suficientes.
Un λ alto degrada el rendimiento. λ=1,0 y 2,0 muestran una caída significativa en la validación PR-AUC. Una ponderación agresiva de las reglas puede anular la señal del BCE en lugar de complementarla. Comience en λ=0,5 y verifique sus propios datos antes de subir.
Una extensión natural haría que los pesos de la regla se pudieran aprender en lugar de fijarlos en 0,5/0,5:
# Pesos de combinación que se pueden aprender self.rule_w = nn.Parameter(torch.tensor([0.5, 0.5])) w = torch.softmax(self.rule_w, dim=0) sospechoso = ( w[0]* antorcha.sigmoide(5 * (cantidad – cantidad.media())) + w[1]* antorcha.sigmoide(5 * (pca_norm – pca_norm.mean())) )
Esto permite que el modelo decida si la cantidad o la norma PCA es más predictiva para los datos específicos, en lugar de codificar ponderaciones iguales. Esta variante aún no se ha ejecutado; es la siguiente en la lista.
Pensamientos finales
La pérdida de la regla hace algo real: la mejora ROC-AUC es consistente e independiente del umbral en las 5 semillas. La mejora en métricas dependientes del umbral como F1 y PR-AUC está dentro del rango de ruido y depende de la inicialización. El resumen honesto: las reglas de dominio inyectadas en la función de pérdida pueden mejorar las distribuciones de puntuación subyacentes de un modelo en datos de eventos raros, pero la magnitud depende en gran medida de cómo se mide y de qué tan estable es la mejora entre semillas.
Si trabaja en la detección de fraudes, la detección de anomalías o cualquier dominio donde los positivos etiquetados son raros y el conocimiento del dominio es rico, vale la pena experimentar con este patrón. La implementación es simple: un puñado de líneas encima de un bucle de entrenamiento estándar. La disciplina más importante es la medición: utilice una evaluación de umbral simétrica, informe de métricas independientes del umbral y ejecute siempre varias semillas antes de confiar en un resultado.
El repositorio tiene el ciclo de entrenamiento completo, barrido lambda, análisis de varianza y código de evaluación. Descargue el CSV de Kaggle, colóquelo en el mismo directorio y ejecute app.py. Los números anteriores deberían reproducirse; si no se reproducen en su máquina, abra un problema y echaré un vistazo.
Referencias
[1]A. Dal Pozzolo, O. Caelen, RA Johnson y G. Bontempi, Calibración de probabilidad con submuestreo para clasificación desequilibrada (2015), IEEE SSCI. https://dalpozz.github.io/static/pdf/SSCI_calib_final_noCC.pdf
[2]Grupo de aprendizaje automático de ULB, conjunto de datos de detección de fraude con tarjetas de crédito (Kaggle). https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud (licencia de base de datos abierta)
[3]S. Ioffe y C. Szegedy, Normalización de lotes: aceleración del entrenamiento profundo de la red mediante la reducción del cambio de covariables interno (2015), arXiv:1502.03167. https://arxiv.org/abs/1502.03167
[4]Documentación de PyTorch: BCEWithLogitsLoss. https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html
[5]Código de experimento y materiales de reproducibilidad. https://github.com/Emmimal/neuro-symbolic-fraud-pytorch/
Divulgación
Este artículo se basa en experimentos independientes que utilizan datos disponibles públicamente (conjunto de datos sobre fraude con tarjetas de crédito de Kaggle) y herramientas de código abierto (PyTorch). No se utilizaron conjuntos de datos propietarios, recursos de la empresa ni información confidencial. Los resultados y el código son completamente reproducibles como se describe y el repositorio de GitHub contiene la implementación completa. Los puntos de vista y conclusiones expresados aquí son míos y no representan a ningún empleador u organización.