Como criar um detector de falsos positivos em Machine Learning
Este tutorial mostra como criar um detector de falsos positivos em Machine Learning para reduzir alarmes excessivos num sistema de classificação. Saber identificar falsos positivos é útil para melhorar a eficiência operacional e priorizar alertas reais.
Pré-requisitos
- Python 3.8+ e pip instalados
- Bibliotecas: pandas, scikit-learn, numpy, matplotlib (instalação mostrada)
- Conhecimentos básicos de classificação e avaliação (precision, recall, ROC)
Passo 1: Entender o problema e preparar os dados
Um detector de falsos positivos aprende a prever quando uma previsão de classe positiva do modelo principal é provavelmente incorreta. Precisamos de um conjunto onde cada exemplo tem: features originais, a previsão do modelo primário (pred_label) e o rótulo real (true_label). Vamos criar um exemplo sintético para seguir o fluxo.
# 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
Passo 2: Construir o dataset do detector de falsos positivos
O detector é um segundo modelo que recebe como input: features originais, probabilidades ou decisões do modelo primário e pretende prever se uma previsão positiva é um falso positivo (pred_label=1 & true_label=0). Filtramos para casos em que o primário previu 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()
Passo 3: Treinar um modelo detector simples
Usamos um classificador leve (ex.: LogisticRegression) para prever falsos positivos. Isto permite estimar a probabilidade de ser falso positivo e aplicar um threshold para filtrar alarmes.
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))
Passo 4: Integrar o detector na pipeline de inferência
Em produção, quando o modelo primário faz uma previsão positiva, chamamos o detector. Se o detector indicar alto risco de falso positivo, marcamos o alerta como baixa prioridade ou suprimimos. Exemplo de aplicação em batch sobre X_rest.
# aplicar detector a todo o conjunto onde 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 o resultado
Confirmar que o detector reduz falsos positivos sem eliminar muitos verdadeiros positivos. Medimos métricas antes e depois: taxa de falsos positivos (FPR) e recall do modelo primário sobre positivos reais.
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)
Conclusão
Um detector de falsos positivos é um modelo complementar que reduz alarmes desnecessários. Próximos passos: calibrar thresholds, usar features do contexto (tempo, utilizador), experimentar modelos mais robustos (XGBoost) e validar o impacto em produção. Dica: comece por medir o custo de cada falso positivo antes de definir o threshold.