Cómo crear un detector de falsos positivos en Machine Learning
Este tutorial muestra cómo crear un detector de falsos positivos en Machine Learning para reducir alarmas excesivas en un sistema de clasificación. Saber identificar falsos positivos es útil para mejorar la eficiencia operacional y priorizar alertas reales.
Requisitos previos
- Python 3.8+ y pip instalados
- Bibliotecas: pandas, scikit-learn, numpy, matplotlib (instalación mostrada)
- Conocimientos básicos de clasificación y evaluación (precision, recall, ROC)
Paso 1: Entender el problema y preparar los datos
Un detector de falsos positivos aprende a predecir cuándo una predicción de clase positiva del modelo principal es probablemente incorrecta. Necesitamos un conjunto donde cada ejemplo tenga: features originales, la predicción del modelo primario (pred_label) y la etiqueta real (true_label). Vamos a crear un ejemplo sintético para seguir el flujo.
# instalar dependências (executar no terminal, se necessário) # pip install pandas scikit-learn numpy matplotlib import numpy as np import pandas as pd from sklearn.model_selection import train_test_split # exemplo sintético rng = np.random.RandomState(42) n = 2000 X = pd.DataFrame({'f1': rng.normal(size=n), 'f2': rng.uniform(size=n)}) # rótulo verdadeiro: evento raro dependente de f1 y = (X['f1'] + 0.5 * X['f2'] + rng.normal(scale=0.5, size=n) > 0.5).astype(int) # simulamos um modelo primário com algumas previsões (com erros) from sklearn.ensemble import RandomForestClassifier m_primary = RandomForestClassifier(n_estimators=50, random_state=1) X_train, X_rest, y_train, y_rest = train_test_split(X, y, test_size=0.5, random_state=1) m_primary.fit(X_train, y_train) pred_prob = m_primary.predict_proba(X_rest)[:, 1] pred_label = (pred_prob > 0.4).astype(int) # threshold do modelo primário
Paso 2: Construir el dataset del detector de falsos positivos
El detector es un segundo modelo que recibe como input: features originales, probabilidades o decisiones del modelo primario y pretende predecir si una predicción positiva es un falso positivo (pred_label=1 & true_label=0). Filtramos para casos en los que el primario predijo positivo.
# montar dataset para o detector X_det = X_rest.copy().reset_index(drop=True) y_det = ((pred_label == 1) & (y_rest.reset_index(drop=True) == 0)).astype(int) # 1 = falso positivo X_det['pred_prob'] = pred_prob X_det['pred_label'] = pred_label # consideramos só os exemplos em que o primário previu positivo (casos a decidir) mask = X_det['pred_label'] == 1 X_det_pos = X_det[mask].reset_index(drop=True) y_det_pos = y_det[mask].reset_index(drop=True) X_det_pos.shape, y_det_pos.value_counts().to_dict()
Paso 3: Entrenar un modelo detector simple
Usamos un clasificador ligero (ej.: LogisticRegression) para predecir falsos positivos. Esto permite estimar la probabilidad de ser falso positivo y aplicar un umbral para filtrar alarmas.
from sklearn.linear_model import LogisticRegression from sklearn.metrics import precision_score, recall_score, roc_auc_score X_train_d, X_test_d, y_train_d, y_test_d = train_test_split(X_det_pos, y_det_pos, test_size=0.3, random_state=2) features = ['f1', 'f2', 'pred_prob'] detector = LogisticRegression(max_iter=1000) detector.fit(X_train_d[features], y_train_d) y_pred_prob = detector.predict_proba(X_test_d[features])[:, 1] y_pred = (y_pred_prob > 0.5).astype(int) print('AUC detector:', round(roc_auc_score(y_test_d, y_pred_prob), 3)) print('Precision:', round(precision_score(y_test_d, y_pred), 3)) print('Recall:', round(recall_score(y_test_d, y_pred), 3))
Paso 4: Integrar el detector en la pipeline de inferencia
En producción, cuando el modelo primario hace una predicción positiva, llamamos al detector. Si el detector indica alto riesgo de falso positivo, marcamos la alerta como baja prioridad o la suprimimos. Ejemplo de aplicación en batch sobre X_rest.
# aplicar detector a todo el conjunto donde primário previu positivo all_df = X_rest.reset_index(drop=True).copy() all_df['pred_prob'] = pred_prob all_df['pred_label'] = pred_label mask_pos = all_df['pred_label'] == 1 probs_fp = np.zeros(len(all_df)) probs_fp[mask_pos] = detector.predict_proba(all_df[mask_pos][features])[:, 1] # decidir suprimir se probabilidade de falso positivo > 0.6 suppress = probs_fp > 0.6 all_df['suppress_alert'] = suppress.astype(int) all_df[['f1','f2','pred_prob','pred_label','suppress_alert']].head()
Verificar el resultado
Confirmar que el detector reduce falsos positivos sin eliminar muchos verdaderos positivos. Medimos métricas antes y después: tasa de falsos positivos (FPR) y recall del modelo primario sobre positivos reales.
from sklearn.metrics import confusion_matrix # métricas sem detector (considerando threshold primário) tp = ((all_df['pred_label']==1) & (y_rest.reset_index(drop=True)==1)).sum() fp = ((all_df['pred_label']==1) & (y_rest.reset_index(drop=True)==0)).sum() fn = ((all_df['pred_label']==0) & (y_rest.reset_index(drop=True)==1)).sum() print('Antes - TP, FP, FN:', tp, fp, fn) # aplicar supressão pred_after = all_df['pred_label'].copy() pred_after[all_df['suppress_alert']==1] = 0 # suprimido vira negativo tp_a = ((pred_after==1) & (y_rest.reset_index(drop=True)==1)).sum() fp_a = ((pred_after==1) & (y_rest.reset_index(drop=True)==0)).sum() fn_a = ((pred_after==0) & (y_rest.reset_index(drop=True)==1)).sum() print('Depois - TP, FP, FN:', tp_a, fp_a, fn_a) print('Redução de FP:', fp - fp_a)
Conclusión
Un detector de falsos positivos es un modelo complementario que reduce alertas innecesarias. Próximos pasos: calibrar thresholds, usar features del contexto (tiempo, usuario), probar modelos más robustos (XGBoost) y validar el impacto en producción. Consejo: empiece por medir el coste de cada falso positivo antes de definir el threshold.