• João Ataide

Avaliação de risco de crédito


 

Dia ensolarado em pleno semi-árido brasileiro, um representante de uma instituição financeira mais especificamente a Fintech λλ entrou em contato comigo por e-mail, solicitando um serviço para execução de uma solução para melhora de seu modelo de avaliação de risco de crédito dos clientes.


Sabendo que das áreas que constituem essas empresas, uma das que causam mais problemas e desconfortos são as taxas de inadimplência por parte das carteiras dos clientes. Tornando essas atividades de avaliação destas carteiras obrigatórias e de extrema importância, podendo chegar causar déficit gigantescos na balança comercial.


Fui então investigar e descobrir que, para essas instituições, cada cliente faz parte de uma carteira de crédito, na qual indica as possibilidade nas quais os clientes são capazes financeiramente para o pagamento da dívida (empréstimos, cartão de crédito e outros), tal avaliação de carteira é informada como ranking.


Devido a isso, essas estão investindo cada vez mais em novas tecnologias, com o intuito de desenvolver e aprimorando seus sistemas de avaliação, visando sempre minimizar os riscos de default (inadimplência) ou não cumprimento das obrigações e/ou condições de um empréstimo. Sempre apostado cada vez mais em modelos de Machine Learning.


Inúmeras soluções podem ser feitas para solucionar esses problemas. Neste projeto em questão irei realizar a criação de um algorítimo para identificar a probabilidade de um cliente não cumprir com suas obrigações financeiras, observo que toda essa história faz parte de um ficção criada por mim, sendo o presente trabalho uma das práticas do curso do Data Science na Prática do Carlos Melo. 


Para iniciar o trabalho foi preciso avaliar o banco de dados fornecido pela instituição. Valendo ressaltar que, geralmente as avaliações são feitas no momento em que o cliente solicita o cartão (normalmente no primeiro contato com a instituição), entretanto, usaremos um banco de dados já estabelecidos (Dataset), tal dataset possuí 45.000 entradas e 43 colunas e constitui basicamente como um csv.



No caso desse projeto é de extrema importância a identificação do significado de cada umas das variáveis que serão utilizadas no trabalho, as quais podem ser vistas abaixo:

  • id - identificação anônima, representa um valor único do cliente por cliente.

  • target_default - é a variável alvo, que utilizaremos para analisar o risco de default (inadimplência).

  • As colunas score_3, score_4 e score_5 são numéricas, já score_1 e score_2' estão codificadas de alguma maneira. Teremos que verificar a frente se existe uma quantidade de classes que possam ser convertidas em informações úteis.

  • Existem outras variáveis que apresentam algum tipo de codificação, como reason, state, zip, channel, job_name e real_state que estão codificadas e também precisarão de alguma análise mais aprofundada para saber se é possível extrair alguma informação das mesmas.

  • profile_tags - contém um dicionário um rótulo atribuído a cada cliente.

  • target_fraud - seria a variável alvo para outro modelo, onde o objetivo seria a detecção de fraude.

  • lat_lon - está em formato string, contendo uma tupla com as coordenadas.

Como primeira fase de todo projeto, iniciarei a análise exploratória dos dados, seguindo esta ordem: valores ausentes, tipos de dados, valores únicos, balanceamento dos dados e Estatística Descritiva.


Ao realizar esse cálculo podemos ver que algumas colunas como: target_fraud, last_amount_borrowed',last_borrowed_in_months,ok_since,external_data_provider_credit_checks_last_2_year apresentam mais da metade dos dados ausentes. Já as camadas external_data_provider_credit_checks_last_year, credit_limit , n_issues possuem entre 25 - 34% do seus valores ausentes. No entanto a contagem de valores únicos mostra que as colunas external_data_provider_credit_checks_last_2_year e channel apresentam um único valor possível, deste modo, se tornando camadas que não possibilitariam a contribuição para o modelo, podendo então ser descartadas.


Seguindo os passos, quando analisei o balanceamento de nossa variável alvo target_default, proporção entre os inadimplentes False 77.95% e True 14.80%, sendo necessário efetuar o balanceamento mais a frente.



Por último, os cálculos das principais informações estatísticas apresentadas, podemos destacar algumas observações:

  • A coluna external_data_provider_credit_checks_last_2_year possui valores mínimos, máximos e desvio-padrão iguais a zero.

  • A coluna reported_income apresenta valores inf, que irão interferir na análise e modelo. Substituiremos valores do tipo np.inf por np.nan para trabalhar com os dados.

  • A coluna external_data_provider_email_seen_before apresenta o valor mínimo de -999, o que é estranho ao se considerar as outras informações. Após verificar de maneira mais aprofundada, chegou-se a conclusão que esses dados são outliers ou foram tratados inadequadamente. Substituiremos os valores iguais a -999 por np.nan.


Feita a maioria das análises exploratórias, o próximo passo é realizar as manipulações necessárias para construir o melhor modelo, onde, podemos dar início então ao pré-processamento dos dados.


Para isso, realizei as seguintes manipulações para limpeza:

  • Substituir inf por NaN, na camada reported_income;

  • Descartar as colunas ids, target_fraud,external_data_provider_credit_checks_last_2_year, channel e profile_phone_number;

  • substituir -999 em external_data_provider_email_seen_before por NaN;

  • Eliminar colunas sem informação aparente ou que demandam mais pesquisa;

  • Eliminar as entradas onde target_default é igual a NaN.

Com esse primeiro pre-processamento feito analisando as variáveis, pude então iniciar os pré-processamentos da entrada. Esse dataset possui diversos dados ausentes e nulos, no entanto, não temos muitas informações sobre os motivos desses problemas. Então, para solucionar isso irei substituir os valores ausentes (Nan) por zero para as variáveis que não possuem referenciais, como: 'last_amount_borrowed', 'last_borrowed_in_months' e 'n_issues'. Já as demais, substituirei pela mediana quando for numérica e pela moda quando for categórica.


Com todos esses pré-processamentos efetuados, ficou seguinte dataset:

Ficando com 41.741 entradas: e 25 camadas. Note que a maioria das camadas está criptografadas, as qual utilizarei o algorítimo LabelEncoder e GetDummies para transformar os dados categóricos em dados numéricos, separando aqueles que tenham mais de um binário de categorias.


Chegando ao resultado, de um dataset assim:


Como vimos anteriormente, os dados de alvo estão completamente desbalanceados, assim será necessário realizar algumas manipulações, chegando ao resultado boleano de Falso 35.080 e verdadeiro 35.025.



Com todas as manipulações feitas, busquei na literatura e em outros cientistas de dados, qual melhor modelo se adapta a esse tipo de problema. Fazendo uma pesquisa sistemática identifiquei que o melhor modelo para esse problema, no caso o mais utilizado é o RandomForestt (RF). Então, para identificar o melhor modelo de RF, criei uma função de validação que se utiliza do estimador Recall, criando uma base line geral de quanto o modelo poderia errar e assim contatando que seria o melhor modelo de aprendizagem a ser usado.


#Função de validação

def valid(X, y, model, quite = False):

  X = np.array(X)
  y = np.array(y)
  pipeline = make_pipeline(StandardScaler(), model)
  scores = cross_val_score(pipeline, X, y, scoring="recall")

  if quite == False:
     print("Recall: {:.3f} (+/- {:.3f})".format(scores.mean(), scores.std()))

  return scores.mean()
rfc = RandomForestClassifier()
score_baseline = valid(X_treino_balanceado, y_treino_balanceado, rfc)

Chegando a um resultado de Recall: 0.967 (+/- 0.003), podendo dar continuidade com o algorítimo de RF, iniciando então os testes usando o GridSearchCV, identificando então quais melhores critérios a serem usados, chegando ao seguinte modelo final.


forest = RandomForestClassifier(criterion='entropy', n_estimators=100)
forest.fit(X_treino_balanceado, y_treino_balanceado)

Com o modelo pronto, pude então realizar as predições e então compará-los com o resultado

da base de teste, obtendo um resultado ótimo, como você pode ver abaixo:


Com uma matriz de confusão apresentando 96% de Verdadeiros Positivos e 99% de Verdadeiros Negativos.


Neste projeto, realizei diversos procedimentos para a construção de um modelo de predição de risco de crédito, no qual necessitou a realização de diversas manipulações, desde a exclusão de camadas, balanceamento e padronização. Chegando a um resultado extremamente satisfatório para o cliente, podendo ser colocado em produção. Entretanto, fica o gap, de utilização de outros modelos de aprendizagem para efetuar esse trabalho, identificando se de fato o RandomForest é o melhor para esse problema, você pode ver o projeto completo no notebook.


Considerando o caso da Fintech λλ, o resultado foi de fato muito satisfatório, vendo que estes poderiam melhorar seu serviço de avaliação. Podemos notar isso com um simples exemplo de um cliente com uma carteira de crédito de 1 milhão de reais, o meu modelo poderia garantir que a empresa receberia pelos empréstimos 990 mil, errando apenas 1% dos casos, esse resultado se torna o risco financeiro da empresa aceitável, pois consideraria que ela manteria sua carteira de crédito em uma situação muito saudável, e a taxa de inadimplência bem abaixo das médias nacionais.


Gostou mais desse tipo de estrutura para os artigos do blog? Manda teu feedback nas minhas redes sociais e e-mail, caso tenha gostado, compartilha para fortalecer o trabalho. :)