Detecção de Anomalias em Transações Financeiras

Biblioteca

library(tidyverse)
library(dplyr)
library(solitude)
library(ggplot2)
library(readr)

Carregar Datasets

DadosHistoricos <- read_csv("DadosHistoricos.csv")
NovosDados <- read.csv("NovosDados.csv")

Criando e treinando o modelo de Machine Learning com algoritmo isolationForest

modelo_ml = isolationForest$new() 
modelo_ml$fit(DadosHistoricos)
## INFO  [16:49:17.898] Building Isolation Forest ...
## INFO  [16:49:20.551] done
## INFO  [16:49:20.570] Computing depth of terminal nodes ...
## INFO  [16:49:22.014] done
## INFO  [16:49:22.083] Completed growing isolation forest

Fazendo as previsões com o modelo usando os dados históricos

PrevisoesHistorico = DadosHistoricos %>%
  modelo_ml$predict() %>%
  arrange(desc(anomaly_score))
#Density plot
plot(density(PrevisoesHistorico$anomaly_score))

Quanto maior o anomaly score maior a chance do registro ser uma anomalia, para isso foi definido como regra que anomaly score acima de 0.62 é uma anomalia.

Craindo regra e filtro

IndicesHistorico = PrevisoesHistorico[which(PrevisoesHistorico$anomaly_score > 0.62)]
AnomaliasHistorico = DadosHistoricos[IndicesHistorico$id, ]
NormaisHistorico = DadosHistoricos[-IndicesHistorico$id, ]

Plotando resultado

ggplot() + 
  geom_point(data = NormaisHistorico, 
             mapping = aes(transacao1,transacao2), 
             col = "skyblue3", 
             alpha = 0.5) + 
  geom_point(data = AnomaliasHistorico,
             mapping = aes(transacao1,transacao2), 
             col = "red2", 
             alpha = 0.8)

Previsões com o modelo que foi treinado

PrevisoesNovosDados = modelo_ml$predict(NovosDados)
# Se o anomaly score é maior que 0.62 consideramos como anomalia
IndicesNovosDados = PrevisoesNovosDados[which(PrevisoesNovosDados$anomaly_score > 0.62)]

Filtro

AnomaliasNovosDados = NovosDados[IndicesNovosDados$id, ]
NormaisNovosDados = NovosDados[-IndicesNovosDados$id, ]

Plotando resultado

ggplot() + 
  geom_point(data = NormaisNovosDados, 
             mapping = aes(transacao1,transacao2), 
             col = "turquoise3", 
             alpha = 0.5) + 
  geom_point(data = AnomaliasNovosDados, 
             mapping = aes(transacao1,transacao2), 
             col = "tomato3", 
             alpha = 0.8)

Arredondando a coluna ‘anomaly_score’ para 2 casas decimais

PrevisoesNovosDados <- PrevisoesNovosDados %>%
  mutate(anomaly_score = round(anomaly_score, 2))

Criando uma nova coluna com base na condição

PrevisoesNovosDados <- PrevisoesNovosDados %>%
  mutate(status = ifelse(anomaly_score > 0.62, "anomalia", "normal"))

Criando o box plot

ggplot(PrevisoesNovosDados, aes(x = status, y = anomaly_score, fill = status)) +
  geom_boxplot() +
  labs(title = "Box Plot de Anomalias e Normais",
       x = "Status",
       y = "Anomaly Score") +
  theme_minimal() +
  scale_fill_manual(values = c("anomalia" = "red", "normal" = "blue")) +
  theme(legend.position = "none")