Machine Learning para Avaliação de Risco de Crédito

Prevendo casos de inadimplência

Otávio Simões Silveira
Data Hackers
8 min readAug 14, 2020

--

Photo by Sharon McCutcheon on Unsplash

Cada vez mais instituições financeiras têm utilizado técnicas de análise de dados e aprendizado de máquina em suas operações. Alguns exemplos de situações onde tais técnicas podem ser de grande importância para o sucesso da instituição são detecção de fraudes em cartões de crédito e identificação de risco de crédito. Neste artigo, abordaremos o segundo exemplo.

Risco de crédito é a possibilidade de ocorrência de perdas financeiras devido ao não cumprimento das obrigações por parte do tomador. Em outras palavras, é o risco de inadimplência por parte do tomador do crédito. Com isso em mente, este artigo apresenta um projeto desenvolvido com objetivo de treinar, testar e avaliar um modelo de machine learning capaz de prever com alto índice de acerto se uma operação de crédito resultará ou não em inadimplência.

Para tanto, foi utilizado um dataset onde cada linha representa uma aplicação para crédito, com diversas variáveis contendo os dados da aplicação e uma variável alvo, informando se houve ou não inadimplência em cada uma delas. Este dataset pode ser encontrado aqui.

Para cumprir o objetivo proposto, o projeto passou pelas seguintes etapas:

  • Exploração e limpeza dos dados;
  • Feature engineering;
  • Preparação dos dados;
  • Seleção de um modelo de machine learning;
  • Ajuste, treinamento, teste e avaliação do modelo selecionado.

Neste artigo serão expostas apenas as principais partes do que foi feito. Para acompanhar todo o passo a passo mais detalhadamente, veja o notebook completo no GitHub.

Análise Exploratória e Limpeza dos Dados

O DataFrame é composto por 45 mil linhas e 43 colunas, representando variáveis contínuas e categóricas, das quais várias apresentam valores ausentes. Vejamos então o percentual de valores ausentes por coluna.

target_fraud                                        96.617778
last_amount_borrowed 66.568889
last_borrowed_in_months 66.568889
ok_since 58.988889
external_data_provider_credit_checks_last_2_year 50.284444
external_data_provider_credit_checks_last_year 33.608889
credit_limit 30.666667
n_issues 25.653333
facebook_profile 9.906667
marketing_channel 7.951111
job_name 7.413333
target_default 7.242222
external_data_provider_email_seen_before 4.962222
lat_lon 3.028889
user_agent 1.604444
n_bankruptcies 1.548889
n_defaulted_loans 1.275556
reason 1.257778
income 1.248889
real_state 1.248889
state 1.248889
zip 1.248889
channel 1.248889
score_3 1.248889
score_2 1.248889
score_1 1.248889
n_accounts 1.248889
risk_rate 1.248889
shipping_zip_code 0.000000
score_4 0.000000
score_5 0.000000
profile_tags 0.000000
score_6 0.000000
application_time_in_funnel 0.000000
shipping_state 0.000000
reported_income 0.000000
application_time_applied 0.000000
profile_phone_number 0.000000
external_data_provider_fraud_score 0.000000
external_data_provider_first_name 0.000000
external_data_provider_credit_checks_last_month 0.000000
email 0.000000
ids 0.000000

Também pôde-se verificar a quantidade de valores únicos em cada coluna:

external_data_provider_credit_checks_last_2_year        1
channel 1
target_fraud 2
target_default 2
external_data_provider_credit_checks_last_year 2
facebook_profile 2
last_borrowed_in_months 2
external_data_provider_credit_checks_last_month 4
n_defaulted_loans 5
real_state 5
email 6
n_bankruptcies 6
score_1 7
marketing_channel 9
shipping_state 25
score_2 35
n_issues 44
n_accounts 44
state 50
external_data_provider_email_seen_before 62
risk_rate 82
score_3 88
ok_since 100
user_agent 297
application_time_in_funnel 501
zip 823
external_data_provider_fraud_score 1001
last_amount_borrowed 14325
reason 14874
credit_limit 20928
lat_lon 22412
profile_tags 26131
shipping_zip_code 28263
job_name 32265
external_data_provider_first_name 32886
application_time_applied 35543
reported_income 40025
income 41211
score_4 45000
score_5 45000
score_6 45000
profile_phone_number 45000
ids 45000

Existem duas colunas com o mesmo valor em todas as linhas. Temos também variáveis categóricas com quantidades muito altas de valores únicos, algumas até com um valor único por linha como, por exemplo, as colunas ids, profile_phone_number, shipping_zip_code.

No que se refere a valores ausentes, cinco colunas possuem mais da metade de suas linhas com valores nulos. No entanto, a grande maioria possue menos de 2% de valores ausentes. Pouco mais de 7% das linhas possuem valores nulos na variável alvo. Tais linha serão, portanto, descartadas.

Limpeza

Além de tratar menores inconsistências, a etapa de limpeza dos dados foi composta das seguintes etapas:

  • Descartar variáveis com apenas um valor único e variáveis categóricas com quantidades muito altas de valores únicos;
  • Descartar variáveis com mais de 50% dos valores ausentes;
  • Preencher os valores nulos na coluna facebook_profile com False, considerando assim que são pessoas sem perfil nessa rede social.
  • Substituir valores @hotmaill.com e @gmaill.com na coluna email por @hotmail.com e @gmail.com, respectivamente.
  • Remover a string BR- da coluna shipping_state, deixando apenas a sigla do estado. A coluna apresenta dados no formato BR-MG, BR-SP, etc.
  • Descartar linhas onde a variável alvo está ausente e transformar os valores desta variável para 0 e 1.

Valores Ausentes

Os valores ausentes nas colunas numéricas foram preenchidos com a mediana da coluna. Já as colunas categóricas tiveram os valores ausentes substituídos pelos valores presentes na mesma proporção em que estes aparacem na coluna através da função abaixo.

Após essa etapa, não restaram valores ausentes no conjunto de dados.

Análises e Feature Engineering

A coluna profile_tags contém tags atribuídas a cada solicitante no formato {'tags': ['n19', 'n8']}. Cada tag única na coluna foi então transformada em uma variável dummie. O coluna original foi descartada.

A coluna application_time_applied representa algo como a hora da aplicação. Em sua forma original seria difícil retirar qualquer insight, por isso os valores dos minutos e segundos foram excluídos, possibilitando a análise do impacto de cada hora de aplicação sobre a variável alvo.

Percebeu-se que aplicações realizadas antes das sete horas da manhã têm maior probabilidade de inadimplência. Para melhor utilizar essa informação, foi criada a coluna overnight com valores 0 e 1, sendo 1 para aplicações feitas de madrugada e 0 para demais horários.

Também foi possível fazer uma análise semelhante para os estados, onde nota-se que dois estados se destacam, exercendo maior influência sobre a variável alvo.

Como o dataset contém informações sobre latitude e longitude, foi possível ver a distrbuição de casos de inadimplência pelo país utilizando o Basemap.

Podemos notar pelo mapa que existe uma maior concentração de casos nas regiões sudeste e nordeste.

Ainda, podemos perceber a baixa quantidade de casos em Roraima, o que pode indicar que a influência do estado na inadimplência, que foi destacada no gráfico anterior, pode se dar pelo baixo número de ocorrências, tanto da classe positiva como da classe negativa da variável alvo.

A mesma análise realizada com os horários de aplicação e com os estados foi expandida para outras variáveis categóricas.

A partir dos gráficso, notamos que:

  • E-mails @outlook.com tem maior probabilidade de inadimplência;
  • Aplicações com perfil no Facebook têm maior chance de inadimplência;
  • Não se pode afirmar muito sobre a coluna marketing_channel.

Análises semelhantes foram realizadas para algumas das colunas numéricas. Para tanto, foram usados gráficos de dispersão.

Podemos destacar que:

  • Valores mais altos na coluna n_bankruptcies implicam em maior chance de inadimplência. Isso faz sentido, uma vez que esta coluna representa algo como “número de falências”;
  • Valores mais altos na coluna external_data_provider_email_seen_before implicam em menor chance de inadimplência;
  • Não é possível afirma muito a respeito dos outros gráficos.

Machine Learning

Preparação dos Dados

Como podemos verificar no gráfico ao lado, trata-se de um dataset desbalanceado.
Existem em torno de seis vezes mais representações da classe 0 (sem inadimplência) do que da classe 1 (inadimplência). Sendo assim, foi gerado um novo dataset balanceado utilizando a função resample para possibilitar que modelos fossem treinados com dados balanceados e não balanceados. O processo de balanceamento e divisão dos datasets em treino e teste encontra-se abaixo.

Escolha do Modelo e Métricas

Foram utilizados quatro algoritmos diferentes para treinar os modelos:

Usando a técnica de validação cruzada, foi possível verificar o desempenho desses quatro algoritmos tanto com os dados balanceados, como com os dados desbalanceados e, portando, temos oito modelos. As seguintes métricas foram utilizadas para avaliar esses modelos:

  • Acurácia;
  • Precisão;
  • Recall;
  • Área sob a curva ROC.

Foram obtidos os seguintes resultados:

De uma forma geral, os dados balanceados apresentaram melhores resultados considerando as quatro métricas utilizadas. Dentre os algoritmos, Random Forest apresentou os melhores resultados e, portanto, a combinação desse algoritmo com os dados balanceados foi a escolhida para o projeto.

Tunning de Hiperparâmetros e Avaliação com Dados de Teste

Para realizar ajustes mais precisos no modelo, foi utilizada a técnica de Grid Search para escolher o melhor valor para os seguintes hiperparâmetros:

  • criterion;
  • n_estimators;
  • max_depth;
  • min_samples_split;
  • min_samples_leaf.

Os resultados foram:

Melhor resultado: 0.9861359409206981 para {'criterion': 'gini'}
Melhor resultado: 0.9874987742559391 para {'n_estimators': 400}
Melhor resultado: 0.7652671250910943 para {'max_depth': 9}*
Melhor resultado: 0.9876456384401593 para {'min_samples_split': 2}
Melhor resultado: 0.9875772351859455 para {'min_samples_leaf': 1}
* max_depth foi então mantida com o padrão None

Com os hiperparâmetros ajustados, o próximo passo foi avaliar o modelo com os dados de teste.

Conclusão

Neste projeto, trabalhamos com um problema de identificação de risco de crédito com objetivo de construir um modelo de machine learning capaz de identificar possíveis inadimplentes. Para isso, passo pelas seguintes etapas:

  • Exploração e limpeza dos dados;
  • Análise dos dados e feature engineering;
  • Preparação dos dados para machine learning;
  • Seleção do algoritmo;
  • Ajuste, treinamento e avaliação de um modelo de machine learning.

Como resultado, além de alguns insights relevantes sobre o impacto de algumas características na variável alvo, foi construído um modelo preditivo que demonstrou acurácia de 98%, sendo considerado um resultado satisfatório e, portando, cumprindo o objetivo inicialmente proposto.

Outra abordagem para o mesmo problema seria utilizar predict_proba ao invés de predict para prever a probabilidade de inadimplência e não apenas um rótulo 0 ou 1. Desta forma, em uma situação real, a instuição cedente do crédito seria capaz de estipular os juros com base na probabilidade de cada aplicação, diferenciando de maneira mais eficiente a sua base de clientes. Essa abordagem no entanto, está fora do escopo o artigo.

Caso tenha alguma dúvida, sugestão ou feedback, sinta-se à vontade para entrar em contato via GitHub, Linkedin ou Twitter.

--

--