Detecção de Fraude na Enron usando Machine Learning

Márcio Ozório de Jesus
marciojesus
Published in
15 min readJul 31, 2018

Machine Learning

1. Introdução

Este projeto faz parte do Nanodegree Analista de Dados da Udacity.

A Enron foi uma empresa de distribuição de energia e gás e chegou a ser a sétima maior empresa do Estados Unidos, empregando cerca de 21.000 pessoas. Com uma divida de US$ 13 bilhões, o grupo pediu concordata em 2001 e arrastou consigo a empresa de auditoria Arthur Andersen. O governo americano abriu dezenas de investigações e identificou que a empresa havia manipulado os seus balanços, caracterizando assim fraude contábil. Este caso foi considerado um dos maiores escândalos financeiros já ocorridos, onde foi criado inclusive um documentário chamado “Enron — Os mais espertos da sala

Diversas pessoas foram invetisgadas e presas, incluindo funcionários, membros do conselho, diretor financeiro, diretor presidente, entre outros.

Muitos dados que normalmente são confidenciais, tornaram-se públicos. Dentre eles um relatório com dados financeiros de funcionários e membros do conselho e também milhares de arquivos de e-mails.

No conjunto de dados disponibilizado, existe um campo chamado “POI (Person of interest — Pessoa de interesse)”. Se for indicado sim, significa que a pessoa teve algum tipo de envolvimento com o escândalo ocorrido.

O objetivo deste estudo é utilizar técnicas de ciência de dados para investigar e desenvolver um modelo usando um algorítimo de aprendizado de máquina (machine learning) que consiga aprender com os dados disponibilizados e realizar predições indicando se o funcionário é ou não um POI.

Obs.:

Clique aqui e acesse os códigos desse estudo no github

2. Limpeza de dados (Data cleaning)

Carregando os dados

Informações da base de dados:

2.1. Analisando os dados ausentes

Podemos notar que exitem muitos valores que estão com o conteúdo “NaN”. Isso indica que são dados nulos ou ausentes.

Vamos analisar a quantidade de valores ausentes por coluna:

Vamos ver um gráfico para analisarmos melhor a quantidade. As lacunas em branco significa locais onde não há valores, ou seja, estão nulos

O gráfico abaixo exibe a proporção de valores nulos:

Como podemos ver acima, os dados com maior número de informações ausentes realmente são dados específicos para poucas pessoas, como empréstimos, valores para membros do conselho não funcionários, etc. Note também que a característica POI não contém nenhum valor ausente.

  • loan_advances (Adiantamentos de Empréstimos)- Empéstimos realizados pelos funcionários
  • director_fees (Taxas de Diretor) — Pagamento em dinheiro ou valor em ações pagos a conselheiros não funcionários
  • restricted_stock_deferred (Estoque restrito diferido) — Reflete o valor das ações restritas voluntariamente diferidas antes da liberação sob um acordo de compensação diferido.
  • deferral_payments (Pagamentos diferidos) — Reflete distribuições de um acordo de compensação diferido devido a rescisão do contrato de trabalho ou devido a saques em serviço, conforme disposições do plano.
  • deferred_income (Renda Diferida) — Reflete adiamentos voluntários de salário, incentivos anuais em dinheiro e incentivos em dinheiro de longo prazo, bem como taxas em dinheiro diferidas por conselheiros não empregados sob um acordo de compensação diferido. Também pode refletir adiamentos sob uma opção de ações ou unidade de estoque fantasma em vez de um acordo de caixa.

Sendo assim, iremos prosseguir com o estudo

2.2. Análise e remoção de Outliers (Exceções)

Vamos gerar um gráfico boxplot para tentar identificar possíveis outliers

Note que existe um valor muito acima do normal para a feature exercised_stock_options. Vamos analisar as informações para os dados acima de U$ 300.000.000

Veja que não trata-se da informação de um funcionário, e sim de uma linha contendo o valor total de todas as colunas. Portanto, iremos excluí-lo. Irei excluir também a coluna email_address, pois não será útil para o nosso estudo.

Irei criar uma nova feature com a soma de todos os valores para continuar a análise de outliers

Analisando os valores menores:

Podemos observar que de todos os registros acima, as informações do funcionário “LOCKHART EUGENE E” são as únicas que estão todas zeradas. Portanto, também irei considerá-lo como um outlier.

Analisando os valores maiores:

Não identifiquei nada de anormal para os registros acima. Nota-se que das cinco pessoas com maiores valores, três são pessoas de interesse (POI). Talvez possa ser alguma tendência. Vamos continuar a investigação.

2.3. Verificação dos valores

Como pudemos ver com a linha com os valores totais identificada nesta base de dados, pode-se constatar que essa base é uma cópia fiel do relatório com as informações financeiras que foi disponibilizado. Vamos conferir se pode haver mais alguma informação incorreta somando as colunas e verificando se bate com os campos de totais

Verificando se existem valores divergentes:

Corrigindo os valores:

3. Análise exploratória (Data analysis)

Analisando os valores após a remoção de outliers e correções:

Mapa de calor com a correlação entre as features

Analisando o gráfico mapa de calor acima, podos ver uma forte correlação entre os campos loan_advances e exercised_stock_options com o total_general.

Apesar disso, não há nenhuma outra correlação que nos dê alguma pista.

Média dos valores de pagamento por POI / não-POI

Vamos tentar identificar se existem algum padrão diferente entre os valores para pessoas que são e pessoas que não são de interesse e ver se os dados nos fornece alguma pista

Veja que a média dos valores de pagamentos para as pessoas que são POI é muito acima das pessoas que não são POI.

Média dos valores com ações por POI / não-POI

Média dos valores totais por POI / não-POI

Agora vamos analisar as médias das mensagens de e-mail de pessoas consideradas como não-POIS com pessoas consideradas POIs

Média de quantidade de mensagens POI / não-POI

Novamente vemos uma diferença bem grande. Fica claro esta diferença entre as classes (POI e não-POI) pode ser um padrão que pode ser explorado para facilitar a identificação através dos algoritios de aprendizado de máquina

Note que com cerca de 11 caracteristicas, conseguimos obter o mesmo resultado utilizando 19 caracteristicas.

Execução dos algoritmos de Aprendizado de Máquina (Machine Learning)

Realizaremos a execução dos algoritimos em três partes ou sequências:

Sequência 1 - Execução dos algorítimos COM os dados após a limpeza, mas SEM qualquer feature adicional e SEM qualquer otimização de parâmetrosSequência 2 - Execução dos algorítimos COM os dados após a limpeza e COM features adicionais e SEM otimização de parâmetrosSequência 3 - Execução dos algorítimos COM os dados após a limpeza, COM features adicionais e COM otimização de parâmetros

A ideia é realizar uma comparação para saber a diferença que tivemos no decorrer da execução das sequências acima.

A pontuação minima definida para este estudo é de 0.3 para as métricas de avaliação precision e recall

Será realizado a dividão do conjunto de dados utilizaremos uma divisão através de validação cruzada estratificada com 10 divisões, onde 80% dos dados serão utilizados para treinamento e 20% para testes. No entanto, a realização dos testes ficará a cargo do programa tester.py que foi disponibilizado pela Udacity e será responsável por realizar os testes e nos retornar as métricas de acruácia, precision, recall e f1.

4. Sequencia 1 — Execução dos algorítimos COM os dados após a limpeza, mas SEM qualquer feature adicional e SEM qualquer otimização de parâmetro

A maior acurácia obtida foi para o algorítimo Extratrees. Seguido por Randonforest e Adaboost. Todos com acurácia entre 0.84 e 0.87

5. Adicionando novas características

Foram adicionados seis novos recursos/características:

  1. total_general: soma total de todos os valores da pessoa (total_payments + total_stock_value).
  2. perc_from_poi: percentual de mensagens recebidas de um POI em relação a quantidade total
  3. perc_shared_poi: : percentual de mensagens em compartilhadas com um POI em relação a quantidade total
  4. perc_to_poi: percentual de mensagens enviadas a um POI em relação a quantidade total
  5. perc_total_payments: percentual do total de pagamentos em relação à soma total
  6. perc_total_stock_value: percentual de valores com ações em relação à soma total

Obs.: Como o código para criação das novas características é um pouco grande, caso queira consultar, por favor consulte o código no Githubconforme indicado no incio deste post.

6. Seleção de características (Feature selection)

Esse é um passo bastante importante, onde a ideia principal é manter somente as características essenciais para a execução do modelo de machine learning. Segue abaixo alguns métodos utilizamos para selecionarmos as características/features:

6.1. Importância da característica

Utilizaremos uma árvore de decisão para estimar a importância das características

Com um teste simples usando o algorítimo DecisionTree identificou-se que conseguimos a melhor acurácia utilizando as 4 melhores features:

6.2. RFECV (Recursive Feature Elimination with Cross-Validation)

Esta função nos permite obter uma classificação de por característica e também qual é a quantidade ideal de número de características a serem utilizadas em nosso modelo

Analisando a “melhor quantidade de features” a serem utilizadas para conseguimos a melhor acurácia:

6.3. Seleção Univaridada — SelectkBest (CHI2, ANOVA)

Este método realiza testes estatísticos para selecionar os recursos que tem a relação mais forte com a variável de saída. Será utilizados o teste estatístico CHI2 e ANOVA:

A criação das novas características tiveram um impacto bastante positivo. Como podemos ver nas tabelas acima, das 10 principais features, 4 são novas features criadas (tanto para o método estatístico CHI2 quanto para o ANOVA) :

Agora irei realizar a execução do SelectKBest para analisarmos a acurácia de alguns algorítimos de aprendizado de máquina:

Como pudemos ver, houveram diferenças consideráveis na escolha das características utilizando os três métodos de seleção de características.

Nos testes realizdos com SelectKBest conforme o gráfico acima, alguns algoritimos tiveram acurácia semelhante como Extratrees e RandonForest, no entanto, alguns algoritmos tiveram grande divergência, como AdaBoost e DecisionTree. Ao final, escolhi utilizar o método de Seleção Univariada (SelectKBest) com escolha automática de melhor número de características (k) através da biblioteca GridSearchCV que é uma biblioteca para realização de uma busca exaustiva identificando o melhor parâmetro.

7. Sequencia 2 — Execução dos algorítimos COM os dados após a limpeza e COM features adicionais e SEM otimização de parâmetros

Resultado:

Com exceção do algorítimo GaussianNaiveBayes, Não houveram mudanças significativas de acurácia com as novas features. Iremos realizar a execução da Sequencia 3 com a otimização dos parâmetros e ao final iremos analisar cada detalhe.

8. Sequencia 3 — Execução dos algorítimos COM os dados após a limpeza, COM features adicionais e COM otimização de parâmetros (Tunning)

Para agruparmos os principais passos em Machine Learning, iremios utilizar PipeLines. Assim conseguiremos automatizar os processos de forma segura e escalável. Realizamoos a otimização (tunning) dos parâmetor utilizando a biblioteca GridSearchCV que é uma biblioteca para realização de uma busca exaustiva identificando o melhor parâmetro.

Verifiquei na documentação dos algoritmos, e informei alguns valores possíveis como parâmetro, e a partir daí o próprio GridSearchCV realiza a identificação e utilização dos melhores parâmetros.

- Algoritimo DecisionTree

Resultado:

- Algoritimo Naive Bayes (Gaussian)

Resultado:

- Algorítimo ExtraTrees

Resultado:

- Algorítimo LogisticRegression

Resultado:

- Algorítimo AdaBoost

Resultado:

- Algorítimo RandonForest

Resultado:

9. Avaliação

Uma etapa essencial no processo é a avaliação dos resultados gerados pelo algoritmo. É através da avaliação que poderemos quantificar a qualidade das predições e sabermos se estamos atingindo ou não os objetivos do projeto.

Segue a pontuação de todos os algorítimos:

A melhor acurácia foi atingida através do algoritmo Extratrees (0,87), no entanto, esta métrica não o foco principal de nossa avaliação.

Para isto, iremos analisar as métricas de avaliação chamadas precision e recall, e foi por esse motivo que o algoritmo escolhido foi o DecisionTree. Lembrando que a pontuação exigida para este estudo foi de 0,30 para precision e recall.

PRECISION

Ter uma alta taxa para a precision, não significa que o algoritmo identificou a maioria dos POIs corretamente, mas sim que quando o algoritmo prediz que trata-se de um “1 — POI”, é porque há uma grande probabilidade de realmente ele seja um “1 — POI”. No nosso caso a métrica precision teve uma taxa de acerto de 0,36.

RECALL

Uma alta taxa para recall, indica que não faço predições desta classe para outras classes. Focando na pontuação da classe “1 — POI” significaria dizer que se a pessoa for um “1 — POI”, dificilmente o algoritmo iria predizer que trata-se de um “0 — não-POI”. A pontuação média para a métrica recall foi de 0.76

A execução do GridSearchCV na busca pelos melhores parâmetros, foi executado com parâmetro scoring = F1, que é uma média harmônica entre as métricas precision e recall.

Média de acurácia por modelo

Como podemos ver acima, com relação a acurácia os passos realizados não tiveram tanto impacto sobre alguns algoritimos, como AdaBoost, DecisionTree e RandomForest. Já para Naive Bayes houve um ganho considerável, enquanto que para ExtraTrees e Regressão Logistica, a acurácia caiu bastante. Mas como o nosso foco principal é em relação a Precision e Recall, iremos analisar o gráfico abaixo com a média da métrica F1 por modelo.

Média da métrica F1 por modelo

Pode-se notar no gráfico acima a importância da otimização de parâmetros para melhoria da métrica (Consequentemente Precision e Recall)

Modelos com as melhores pontuações

Os quatro modelos abaixo foram os que obtiveram pontuações de Precision e Recall acima de 0.30, que é um dos requisitos deste projeto.

O único algoritimo que atingiu as pontuações minimas antes mesmo da criação de novas características (Sequencia 1) e com inserção de novas características, mas sem otimização de parâmetros foi o AdaBoost. No entanto, na Sequencia 3 os algoritimos DecisionTree e ExtraTrees obtiveram melhores pontuações para a métrica Recall e isto esta indo de encontro com a conclusão do projeto que está descrita no próximo tópico.

10. Conclusão

Seria ótimo se as duas métricas (tanto precision quanto recall) tivessem pontuações altas, mas tudo dependerá muito do assunto, do problema e do objetivo do estudo.

Dado a natureza do problema e a quantidade de casos que estamos trabalhando, acredito que duas estratégias poderiam ser utilizadas:

1) Trabalhar para obter uma taxa alta de recall para a classe “1 — POI” e se possível uma taxa média para precision. Isso indica que quando o algoritmo está analisando uma pessoa que não está envolvida no caso de fraude, geralmente ele o algoritmo não prediz que ela está envolvida. Ao final, teríamos uma lista de possíveis pessoas que estão envolvidas no caso, e a partir daí, iniciaria uma investigação a procura de provas apurando quem realmente está ou não envolvida. A ideia principal é separar um grupo de pessoas, e por mais que saibamos da possibilidade de ter pessoas neste grupo que não estão envolvidas no escândalo, sabemos que a grande maioria das pessoas envolvidas (os chamados POIs) estão contidos neste grupo. O trabalho então é levantar provas para identificá-las.

2) Outra estratégia que poderia ser escolhida é ter uma alta taxa para precision para a classe 1-POI. Desta maneira podemos até estar deixando muitas pessoas envolvidas com o escândalo passarem, no entanto, as que o algoritmo identificar que são POI, é porque a chance é realmente muito grande. E a partir daí traçar uma estratégia e fazer uma investigação nestas pessoas para conseguir chegar às demais pessoas envolvidas (Ex.: estratégias como delação premiada). Pode ser uma boa estratégia em casos onde o custo de investigação é alto.

Entre as duas estratégias acima, eu escolheria a primeira (recall), pois a partir de um número de pessoas identificadas, realizaria uma investigação neste conjunto selecionado para encontrar evidências se a pessoa teve ou não envolvimento na fraude. Neste sentido, o algoritmo obteve uma boa pontuação para a métrica Recall.

O conjunto de dados que trabalhamos é muito pequeno e há um desequilíbrio muito grande entre as classes (0 — não-POI e 1 — POI), contudo com a aplicação de técnicas para limpeza de dados, seleção e criação de características, validação cruzada, otimização de parâmetros dos algoritmos e testes com utilização de várias métricas para avaliação, acredito que os resultados encontrados foram bons.

Algo que pode ser realizado para melhorar ainda mais os resultados, é a continuação da exploração por algorítimos e otimização de parâmetros e com mais tempo, seria interessante também a utilização de machine learning para análise do conteúdo dos e-mails dos funcionários.

Observações:

A realização deste trabalho deixou claro a importância dos passos abaixo, onde cada um teve grande importância para atingir os resultados:

  • Conhecimento do assunto que está sendo estudado, possibilitando a utilização de estratégias mais adequadas
  • É de extrema importância a verificação das informações realizando a limpeza dos dados, seja corrigindo dados incorretos ou removendo outliers fazendo com que os algoritimos trabalhem de forma adequada.
  • Criação de novas caracteristicas (features) que relacine uma informação com outra, indicando assim uma relação de força que pode ser de grande importância para os algoritimos de aprendizado de máquina
  • Seleção das características/features juntamente com o processo de escalonamento.
  • Utilização de algoritimos adequados juntamente com a otimização dos parâmetros

No diretório raiz (github) deste projeto contém:

--

--