TG2 0

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 44

INSTITUTO TECNOLÓGICO DE AERONÁUTICA

Rafael Alencar de Lima

Uso de Machine Learning em análise de crédito

Trabalho de Graduação
2020

Curso de Engenharia Eletrônica

Número da CDU (tamanho 10)

Rafael Alencar de Lima


Uso de Machine Learning em análise de crédito

Orientador
Prof. Dr Paulo André Lima de Castro (ITA)

ENGENHARIA ELETRÔNICA

SÃO JOSÉ DOS CAMPOS


INSTITUTO TECNOLÓGICO DE AERONÁUTICA

2020

Dados Internacionais de Catalogação-na-Publicação (CIP)


Divisão de Informação e Documentação
Alencar, Rafael
Uso de machine learning em análise de crédito / Rafael Alencar de Lima.
São José dos Campos, 2020.
Número de folhas no formato 46f.

Trabalho de Graduação – Curso de Engenharia Eletrônica – Instituto Tecnológico de Aeronáutica,


2020. Orientador: Prof. Dr. Paulo André Lima de Castro.

1. Machine Learning. 2. credito. 3. matlab. I. Instituto Tecnológico de Aeronáutica. II. Uso de


Machine Learning em análise de crédito

REFERÊNCIA BIBLIOGRÁFICA

Alencar, Rafael. Uso de Machine Learning em análise de Crédito. 2020. 16f. Trabalho de
Conclusão de Curso. (Graduação em Engenharia Eletrônica) – Instituto Tecnológico de
Aeronáutica, São José dos Campos.
CESSAO DE DIREITOS

NOME DO AUTOR: Rafael Alecar de Lima


TfTULo Do TRABALHo: Uso de Machine Leaning em analise de Cr6dito
TIPO Do TRABALHO/ANO : Graduacao / 2020

i concedida ao Instituto Tecnol6gico de Aeroniutica permissao para reproduzir c6pias deste


trabalho de graduagao e para emprestar ou vender c6pias somente para prop6sitos academicos
e cientificos. 0 autor reserva outros direitos de publicag5o e nenhuma parte deste trabalho de
graduapao pode ser reproduzida sem a autorizaeao do autor.

Rua H8-A,141
12228460, Saojose dos Campos -SP
1V

Uso de Machine Learning em analise de cr6dito

Essa publicagao foi aceita como Relat6rio Final de Trabalho de Graduagfro

Gzed=ededAb/£~rfe
Prof. Dr Paulo Andr6 Lima de Castro (ITA)
Orientador

Prof. Dr. Marcelo da Silva Pinho


Coordenador do Curso de Engenharia Eletr6nica

Sao Jos6 dos Campos,18 de novenibro de 2020


v

Agradecimentos
Gostaria de agradecer a todas as pessosas incríveis que conheci no ITA, as
amizades que fiz para a vida toda e e obrigado a todo o suporte e ejuda que vocês me
deran nesses anos. Tenho certeza que não estaria hoje realizando esse sonho se não
fosse a ajuda de vocês.
Gostaria de agradecer a toda minha família, que sempre apoiou meu sonho de
cursar o ITA e que independente de quantos anos levei para passar e me formar,
sempre me apoiaram nessa caminhada. Gostaria de um agradecimento especial ao meu
pai, Francisco Euripedes (Xicão), aos meus Imaos, Thiago e Matheus, as minhas tias,
Selma e Ana, a minha avó, Selma, que sempre estiveram comigo em todas as
dificuldades. Agradeço também a minha noiva, Lisliane Medeiros, que trilhou esse
caminho junto de mim e sempre me deu o apoio necessário, principalmente nos
momentos de maior dificuldade, te amo nega.
Por fim gostaria de agradece a minha Mãe, Marcia Aires de Alencar Lima, que
tanto me ensinou e me moldou, infelizmente ela me foi tirada ainda cedo e não pode
me ver realizar esse sonho, mas tenho certeza que ela esta acompanhando meus passos
e sempre olhando por mim.
vi

Resumo

Esse trabalho tem por objetivo apresentar uma possível solução aos elevados juros
no Brasil. Através de técnicas de machine learning iremos desenvolver um modelo de
Scorecard para classificar os eventuais tomadores de empréstimo. Com isso temos por
objetivo reduzir o índice de inadimplência, o que resultaria em uma diminuição da
taxa de juros praticada pelos bancos para empréstimos pessoais. Outro benefício é a
automatização do processo, o que permitiria maior agilidade e transparência no
processo, permitindo que o requerente ao empréstimo fizesse a operação toda online.
vii

Abstract

This work has the objective of presenting a possible solution to the high interest
rates in Brasil. Through the tecniques of machine learning a scorecard model wil be
developed to classify the credit borrowers. With this tool we intend to lower the
default rates, and by doing this, lowering the interest rates on the Market. Other
benefit is the automation of the process, allowing greater speed and transparency in the
process, allowing credit approval to occour online and in real time.
viii

Sumário
1. Introdução ....................................................................................................................... 10
1.2. Motivação ................................................................................................................. 11
1.3. Objetivo .................................................................................................................... 12
2. Conceitos Teóricos .......................................................................................................... 13
2.2. Breve resumo sobre Machine Learning .................................................................... 13
2.3. Métodos de Machine Learning ................................................................................. 13
2.3.2. Aprendizagem supervisionada .................................................................................................. 13
2.3.3. Aprendizagem não-supervisionada .......................................................................................... 14
2.3.4. Aprendizagem por reforço ........................................................................................................ 15
2.4. Algoritmo a ser utilizado .......................................................................................... 15
2.4.2. Regressão logística .................................................................................................................... 15
2.5. Processamento de dados ........................................................................................... 16
2.5.2. Limpeza dos dados .................................................................................................................... 16
2.5.3. Característica selection ............................................................................................................. 17
2.5.4. Data Transformation ................................................................................................................. 17
2.5.5. Característica Engeneering ....................................................................................................... 17
2.6. Linguagem de programação utilizada....................................................................... 18
3. Predição de Score de crédito.......................................................................................... 19
3.2. Exploração preliminar e divisão dos dados .............................................................. 20
3.3. Identificando a variável alvo .................................................................................... 20
3.4. Divisão dos dados ..................................................................................................... 21
3.5. Limpeza dos dados ................................................................................................... 21
3.6. Seleção das Características ....................................................................................... 22
3.7. Codificação One-hot e atualização do dataset teste.................................................. 24
3.8. Agrupamento WoE e Característica Engeneering .................................................... 24
3.8.2. O que é WoE e IV ...................................................................................................................... 24
3.8.3. WoE ........................................................................................................................................... 25
3.8.4. IV ............................................................................................................................................... 26
3.8.5. Característica Engeneering com WoE e IV dos dados ............................................................... 26
3.9. Treinando o Modelo ................................................................................................. 28
3.10. Previsão .................................................................................................................... 29
3.11. Desenvolvimento do Scorecard ................................................................................ 29
3.12. Cálculo dos scores de crédito para dataset de teste .................................................. 30
3.13. Setando o limite para aprovação de crédito .............................................................. 31
4. Conclusão ........................................................................................................................ 32
4.2. Trabalhos Futuros ..................................................................................................... 32
ix

5. Apendices......................................................................................................................... 33
5.2. Apendice 1 ................................................................................................................ 33
5.3. Apendice 2 ................................................................................................................ 34
5.4. Apendice 3 ................................................................................................................ 35
5.5. Apendice 4 ................................................................................................................ 35
5.6. Apendice 5 ................................................................................................................ 40
5.7. Apendice 6 ................................................................................................................ 40
5.8. Apendice 7 ................................................................................................................ 41
10

1. Introdução
No Brasil, ao longo de sua história, o sistema financeiro sempre foi muito regulado
e restrito, o que culminou num oligopólio do mercado de crédito, especialmente para
pessoas físicas, no qual a quase totalidade do crédito legal seja concedido por apenas 5
bancos.
Devido a falta de concorrência e outros fatores, alguns relacionados a regulações
no mercado de crédito, os juros no Brasil, a muito, são motivo de grande reclamação
dos brasileiros. Para se ter uma idéia, de acordo com o site agenciabrasil.ebc a taxa
média de juros para pessoa física em março de 2020 ficou em 46.1% a.a.
Um dos motivos dessa taxa de juros tão alta é o chamado spread bancário, que
nada mais é do que a diferença entre as taxas pagas pelo banco quando a pessoa faz
um investimento financeiro e os juros cobrados pelo banco quando alguém toma um
empréstimo.
Segundo dados do Banco Mundial, em 2016 o Brasil tinha o segundo maior spread
bancário do mundo, como pode ser visto na figura 1.2.
Um dos motivos do spread bancário ser tão grande, no Brasil, é porque o país está
entre os piores em termos de recuperação judicial de crédito.
Segundo o Banco mundial, no Brasil apenas U$0.13 são recuperados de cada U$1
emprestado – a metodologia considera o valor recuperado quando há execução de
dívidas. A média mundial está em U$0.34 por U$1. Essa baixa recuperação explica,
em parte, porque o spread bancário no país é tão grande.
11

figura 1.1 - Mapa mundi do spread bancário em 2016, segundo o Banco Mundial

1.2. Motivação
Devido a recuperação judicial de crédito no Brasil ser tão baixa, as instituições
financeiras acabam aumentando os juros para que no geral não tenham prejuízo ao
conceder empréstimos. O que acontece no final das contas é que as pessoas que pagam
seus empréstimos corretamente acabam pagando juros maiores do que deveriam, para
compensar as pessoas inadimplentes.
As instituições financeiras não estão confortáveis nesse cenário, pois se elas
cobram juros muito altos, menos pessoas estarão dispostas a fazer um empréstimo, e
as que o fazem tem uma chance maior de não cumprirem com suas obrigações
comparado com o cenário de juros mais baixos.
Por esse motivo as instituições tentam diminuir a taxa de juros que irão cobrar.
Para isso elas fazem uma análise de crédito do requerente com base em diversos dados
que elas possuem dele, como histórico financeiro, quantidade de dinheiro que ele tem
na conta, quais as garantias que ele pode apresentar, tudo isso para tentar reduzir o
risco de elas perderem dinheiro no negócio.
Entretanto essa análise encontra alguns problemas e limitações, por exemplo se a
pessoa não for cliente de longa data do banco, não há histórico financeiro ou ele é
muito recente para gerar uma análise robusta que indique a chance de inadimplência
com elevado grau de certeza. Outro problema é que toda essa análise hoje em dia é
12

feita quase que manualmente, não existe uma automatização, o que acaba por tornar o
processo muito lento e uma experiência negativa para o cliente.
Vivemos hoje na era digital onde as pessoas tem acesso a praticamente qualquer
serviço e informação ao alcance de seus dedos de forma instantânea. Assim a
motivação para esse trabalho vem de modernizar e automatizar a forma como é feita a
anlise de crédito no brasil, para que ele possa ser feito de forma segura e online.
Outra motivação é que o banco central do brasil recentemente criou um banco de
dados, o SCR, em que ficam armazenadas as informações referentes as operações de
crédito por CPF ou CNPJ. Mediante a autorização do portador do CPF ou CNPJ, as
instituições financeiras podem fazer consultas a esse banco de dados, permitindo
assim, uma analise mais verossimil do crédito a ser concedido a uma pessoa, mesmo
ela não sendo um cliente de longa data da instituição.

1.3. Objetivo
Utilizar machine learnig para realizar análise de crédito, gerando um score que
possa ser interpretado de forma simples e intuitiva pelos funcionários da instituição
financeira e assim agilizar e tornar mais transparente o processo de concessão de
crédito.
13

2. Conceitos Teóricos
2.2. Breve resumo sobre Machine Learning
Tradicionalmente, os programadores sempre desenvolveram sistemas
especificando cada passo em código, de forma clara.
Machine Learning (ML) é um subcampo da inteligência artificial que visa resolver
problemas mais complexos, dos quais os programadores ainda não têm um
conhecimento tão amplo.
Também se aplica quando é inviável mapear todas as variáveis e possibilidades.
Para essa finalidade, os sistemas são estimulados a solucionar problemas de forma
autônoma, aprendendo sobre eles e propondo uma saída.
Nesse contexto, os algoritmos analisam dados de entrada, processam e preveem
saídas possíveis dentro de um intervalo definido. No processo, eles tentam diferentes
abordagens e otimizam sua capacidade de chegar ao resultado.
Os sistemas em machine learning passam por duas fases: treino e execução. Na
primeira, são alimentados por um conjunto de entrada para que sejam contextualizados
com a situação específica que envolve o problema. Então, na segunda fase, eles
começam a deduzir os caminhos a partir do que aprenderam na etapa anterior.

2.3. Métodos de Machine Learning


2.3.2. Aprendizagem supervisionada
A aprendizagem supervisionada é útil nos casos em que um rótulo está disponível
para o conjunto de treinamento. Todas as entradas e saídas são conhecidas, mas
precisam ser previstas para outras instâncias.
Então, esses dados são passados pelo o sistema de aprendizagem, que tem como
função descobrir caminhos e ajustar seu próprio modelo para chegar aos resultados
esperados.
Um exemplo prático seria ensinar uma máquina a reconhecer e categorizar e-mails,
separando os que são relevantes dos que são SPAM.
Na fase de treinamento, são transmitidas para o algoritmo amostras de ambos os
casos, visto que os dois blocos de informação são plenamente conhecidos. Já na fase
de execução, o sistema terá a capacidade de determinar se um e-mail novo é ou não
uma mensagem indesejada.
14

Ou seja, o software já sabe quais entradas estão associadas com quais saídas, mas
precisa aprender um meio de entender essa associação.
Nesse processo, ele tenta identificar padrões e estabelecer previsões que ajudam a
otimizar a abordagem. Esse modelo tem esse nome porque é como se o operador
humano estivesse sempre dando assistência ao sistema, ensinando-o de uma forma
direta.
Os resultados desse tipo de algoritmo são geralmente marcados como classificação
e regressão. O primeiro diz respeito a uma forma de mapear elementos iguais em
categorias específicas, como no exemplo acima, “spam” e “não spam”. Já o segundo
consiste em identificar uma tendência para os dados que permite, inclusive, predizer o
futuro com base em dados históricos.

2.3.3. Aprendizagem não-supervisionada


Já na aprendizagem não-supervisionada o desafio é descobrir relações implícitas
em um conjunto de dados não rotulados. Dessa forma, o algoritmo fica encarregado de
identificar padrões para rotular os dados.
Um exemplo muito comum é a empresa que fornece como base para um sistema de
Machine Learning um conjunto de dados sobre os clientes e espera que ele identifique
possíveis atributos comuns e padrões de comportamento para criar ofertas específicas
e segmentadas.
É como um aprendizado sem assistência humana, com o sistema ditando os
caminhos a seguir. Nesse modelo de algoritmo, as estratégias comuns são clustering e
redução de dimensão.
Abordagens como essas podem ser utilizadas em sistemas de recomendação, em
que, com base em informações colaborativas ou específicas, um software consegue
filtrar conteúdos ideais em meio a uma miríade deles.
É muito usado em lojas de e-commerce, para recomendar produtos que possam ser
interessantes para o cliente que visita o site. Similarmente, há serviços de streaming
que sugerem músicas ou vídeos que devem ser vistos por um usuário.
Tanto Netflix como Amazon utilizam essa abordagem para criar seus algoritmos
de recomendação.
15

2.3.4. Aprendizagem por reforço


Nesse método de aprendizagem, que segue o estilo utilizado no início dos estudos
sobre Inteligência Artificial, o computador é estimulado a aprender com base em
tentativas e erros, otimizando o processo na prática direta. Com essa abordagem, é
possível, por exemplo, ensinar um sistema a priorizar hábitos em detrimento de outros,
com recompensas proporcionais ao acerto.
A aprendizagem por reforço foi inspirada por psicólogos comportamentalistas, que
acreditavam na eficácia de recompensas e punições na educação dos seres humanos.
Também lembra o procedimento de adestração de animais domésticos.
É um método, portanto, baseado na construção de experiência. A partir disso, o
algoritmo sabe quais caminhos são melhores que outros e quais processos são mais
ágeis.
Exemplos de aplicação são os veículos autônomos e máquinas que jogam xadrez.
O sistema aprende com múltiplas tentativas, que envolvem erros como uma jogada
ruim ou um choque contra um obstáculo.

2.4. Algoritmo a ser utilizado


De modo a conseguir os melhores resultados, pretende-se utilizar o método da
Aprendizagem Supervisionada.Dentro do método da aprendizagem supervisionada se
escolheu utilizar o algoritmo da regressão logística pois ele é um algoritmo que
naturalmente já trabalha com o conceito de probabilidade de um determinado evento
ocorrer. A partir dessa probabilidade de inadimplência podemos, então, gerar o score
do cliente, onde clientes com menor probabilidade de inadimplência tem scores mais
altos e clientes com maior probabilidade de inadimplência tem scores mais baixos.

2.4.2. Regressão logística


Regressão logística é um algoritmo de classificação usado para problemas de
predição em variáveis discretas. Os exemplos mais conhecidos do uso deste algoritmo
são problemas de classificação de email, em spam e não-spam, classificação de tumor,
em maligno e benigno. A regressão logística gera como saída, usando a função
sigmoid, um valor de probabilidade de o evento ocorrer.
A hipótese da regressão logística tende a limitar a função custo entre 0 e 1.
Funções lineares costumam falhar na representação, dado que podem assumir valores
16

maiores que 1 e menores que 0, o que não é possível de acontecer na regressão


logística devido sua hipotese.

2.5. Processamento de dados


Treinar algoritmos de machine learnling e utiliza-los para predição de uma variável
alvo é, na verdade, uma tarefa relativamente fácil, graças a várias bibliotecas, voltadas
ao assunto, ja existentes em python. Então o maior gargalo fica sendo em como
preparar os dados de forma que ao alimentar o algoritmo com esses dados, se consiga
extrair informações uteis e corretas.
O processamento de dados transforma o dado cru em um dado que possa ser,
efetivamento usado em algoritmos de machine learning. Essa é uma atividade e vital
no processo de machine learning, e pode definir se o algoritmo vai de fato funcionar
ou não.

2.5.2. Limpeza dos dados


Apenas uma atividade do processamento de dados, que inclui também
característica selection, data transformation, característica engeneering.

Características com variância zero


São características que contém um único valor em todo o espectro de observações.
Logo são características que nada acrescentam ao algoritmo de previsão, já que a
variável alvo não é afetada por ela. Em alguns algoritmos elas podem ter papel
negativo, por isso devem ser excluídas.

Colunas com poucos valores únicos


Colunas com poucos valores únicos (baixa variância) devem ser analisados com
cautela. Essas colunas não devem ser descartadas automaticamente. Colunas
categóricas, não são esperadas ter um número alto de valores únicos.
Intuitivamente podemos achar que essas colunas devem ser excluídas, mas e se
elas contiverem informações úteis? Por exemplo, assuma que uma variável binaria em
um problema de classificação tem vários 0’s e pouquissimos 1’s (variância quase
zero). A variável alvo é sempre a mesma quando o dado inicial for 1, mas quando for
zero ela assume qualquer valor possível, logo nesse caso essa coluna não deveria ser
descartada.
17

Logo, em colunas com baixa variância se deve avaliar caso a caso as colunas e só
depois decidir pela exclusão.

Dados duplicados
Linhas duplicadas devem ser deletadas dos dados utilizados, dado que são
redundantes.

Imputar valores ausentes statisticamente


Não é raro a ocorrência campos ausentes nos dados. A maioria dos algoritmos de
machine learning não conseguem lidar com campos ausentes e dão erro durante o
treino do modelo. Então, esses campos ausentes devem ser preenchidos ou excluídos
(algo a ser evitado a todo custo dado a importância dos dados na sociedade atual).
O preenchimento desses dados deve ser feito lógicamente e um método bem
eficiente para o preenchimento desses dados é fazê-lo estatisticamente.
Os métodos mais comuns de preenchimento dos campos faltantes são:
• média da coluna
• mediana da coluna
• moda da coluna

2.5.3. Característica selection


É o processo de seleção de um subconjunto das características para uso no
modelo.
Característica selection é feita por vários motivos, entre eles simplificação do
modelo, diminuição do tempo de treinamento, aumento da generalização e redução da
possibilidade de ovefitting.

2.5.4. Data Transformation


É o processo de convesão dos dados de um formato em outro, tipicamente de um
formato de um sistema fonte no formato do sistema de destino.

2.5.5. Característica Engeneering


Característica engeneering é o processo de extrair e selecionear, a partir de dados
brutos, características que possam ser utilizadas de uma forma efetiva em modelos
preditivos.
18

Por exemplo: Discretizar uma variável contínua, como uma que expresse o salário
de um indivíduo, por faixa.

2.6. Linguagem de programação utilizada


Para a implementação desse trabalho foi escolhido trabalhar com a linguagem de
programação python devido as inúmeras bibliotecas existentes e validadas com foco em
machine learning, o que facilitou bastante o trabalho a feito.
19

3. Predição de Score de crédito


Nosso objetivo nesse trabalho é utilizar machine learning para gerar um score de
crédito dos aplicantes a um empréstimo e com base nisso definir se o empréstimo sera
concedido.
O score de crédito diz aos credores qual a chance de uma pessoa que tomou um
empréstimo ficar inadimplente baseada no histórico dela. Ele é calculado usando
informações dos estratos de crédito de uma pessoa. É geralmente um número que vai
de 300 a 850 e quanto maior esse número, menor a chance de inadimplência e maior a
confiança que aquele empréstimo será pago.
Os grandes benefícios de usar scores de crédito é que eles são de fácil interpretação
e não necessitam de qualquer conhecimento especializado para entendimento. Por esse
motivo, quase todas as instituições financeiras nos EUA adotaram alguma forma de
score de credito.
Existem diversas fórmulas de score de crédito no mercado, dentre elas a mais
famosa é a FICO Score. O score FICO é calculado com da seguinte forma: 30% são
dívidas, 35% histórico de pagamento, 10% mix de crédito, 15% historico de crédito,
10% crédito novo. Ao final dessa avaliação, um número entre 300 e 850 é gerado, com
valores acima de 800 sendo considerados excepcionais e abaixo de 580 são bem ruins,
como podemos ver na figura 3.1.

figura 3.1- Cálculo Scorecard


20

3.2. Exploração preliminar e divisão dos dados


Nós vamos utilizar o dataset disponibilizado na plataforma Kaggle dos
empréstimos concedidos pelo Lending Club, uma financeira P2P dos EUA.
Os dados brutos incluem informação de mais de 450000 empréstimos concedidos
entre 2007 e 2014 com quase 75 características, incluindo status atual do empréstimo e
vários outros atributos relacionados tanto aos tomadores do empréstimo quanto aos
pagamentos feitos.
A exploração inicial dos dados revelou:
• 18 características com mais de 80% dos dados faltantes. Dada a alta proporção
de valores faltantes, qualquer técnica para imputar esses dados resultaria em
resultados incorretos
• Algumas características não são relacionadas a risco de credito, como a id,
member_id, url, title
• Outras características dizem respeito a informações futuras, que só serão
preenchidas uma vez que ocorrer a inadimplência, como a recoveries e a
collection_recovery_fee.
Já que nosso objetivo é prever a probabilidade futura de inadimplência, manter
essas características no modelo não faz muito sentido, por isso iremos excluir todas
essas características

3.3. Identificando a variável alvo


Baseado na leitura da descrição das características, disponibilizado junto com o
conjunto de dados, vemos que a variável buscada é a loan_Status.
NA figura 3.2 vemos os valores únicos da loan_status e suas proporções.

figura 3.2- Avaliação ocorrencia valores campos loan_status


21

Nós classificamos os empréstimos com os seguintes valores de loan_status como


sendo inadimplente (ruim, ou 1):
• Charged off
• Default
• Late (31-120 days)
• Does not meet the credit policy. Status: Charged OFF
Todos os outros valores serão classificados como bom (ou 0).

3.4. Divisão dos dados


Nós vamos dividir os dados nos seguintes datasets: treinamento (80%) e teste
(20%). Vamos realisar o teste Repeated Stratified K Fold no dataset de treinamento
para avaliar o modelo enquanto que o dataset de teste permanecerá intocado até o final
da avaliação.
A figura 3.2 mostra que os dados são bem enviesados para bons empréstimos, dado
que a os emprenstimos inadimplentes representam menos de 3% do total. Devido isso,
nós iremos stratificar os datasets de teste/treino de forma a manter a distribuição de
empréstimos bons e ruins do dataset original.
Dividir os dados antes da limpeza, ou preenchimento dos campos faltantes evita
qualquer vazamento do grupo de treinamento para o grupo de teste, levando a
previsões mais verossimeis quando aplicarmos o modelo ao dataset de testeo.
O referente ao que foi proposto ate agora se encontra no apêndice 1

3.5. Limpeza dos dados


A seguir façamos uma limpeza nos dados:
• Remove o texto da coluna emp_length e converte os valores na coluna para
formato numérico
• Para todas as colunas com datas: converter para o formato de data do Python
• Remove o texto da coluna term e converte para formato numérico
Vamos definir funções para cada uma das tarefas acima e aplicaremos elas ao
dataset de treinamento. Ter essas funções prontas vai nos ajudar na hora em que
formos fazer o mesmo com o dataset de teste.
22

3.6. Seleção das Características


Agora vamos realizar a seleção das características para identificar aquelas que são
mais indicadas para nosso problema de classificação binaria. Para as características
categóricas utilizaremos o teste CHI-squared e para características numéricas
utilizaresmos o ANOVA F-statistics.
Os p-valores, em ordem crescente, para o teste CHI-squared nas características
categóricas:

figura 3.3- P_value para as características categoricas

O ANOVA F-statistic para as 34 características numéricas mostram uma grande


variedade de valores F, indo de 23513 ate 0.39. Nós manteremos as top 20
características.
Depois, iremos calcular as correlações cruzadas, duas a duas, das 20 características
numéricas escolhidas para detectar alguma possível multicolinearidade.
O heat-map das correlações cruzadas, duas a duas, identificam duas características
(out_prncp_inv e total_pymnt_inv) como altamente correlacionadas, logo iremos
excluir ambas do nosso modelo.
23

O heat-map das correlações cruzadas das variáveis pode ser visto na figura 3.4.

O código usado para seleção de características se encontra no apêndice 2.

figura 3.4- Heat map correlações cruzadas características duas a duas


24

3.7. Codificação One-hot e atualização do dataset teste


Agora vamos criar dummy variables, que é uma variável que assume valor 0 ou 1
para indicar a presença ou falta de alguma variável categórica, para nossas quatro
variáveis categóricas finais e atualizar nosso dataset de treino e teste.
A criação de dummy variables se faz necessária para podermos trabalhar
numericamente com variáveis categóricas e assim alimentar nosso modelo.
Após a criação das dummy variables temos que atualizar os datasets de treino e
teste e nesse ponto pode surgir o seguinte problema: por exemplo, temos a
característica grade, que pode assumir os valores A,B,C,D, entretanto, suponha que o
percentual de D seja muito baixo e ele não apareça no dataset de teste, logo a dummy
variable grade D não sera criada neste grupo de teste, então teremos uma diferença
entre as características no dataset de teste e de treino, o que pode acasionar um
problema no modelo. Então temos que inserir esse campo no dataset onde ele esteja
faltando e preencher com valores 0 em todos os campos dessa característica mostrando
assim que a grade D não aparece no dataset de teste, mas mesmo assim que existe a
característica criada.
O código referente ao que foi proposto nesta seção se encontra no apêndice 3

3.8. Agrupamento WoE e Característica Engeneering


Criar novas características categóricas a partir de todas as características numéricas
e variáveis categóricas baseadas em WoE é uma das partes mais importantes antes do
desenvolvimento de um modelo de risco de crédito.

3.8.2. O que é WoE e IV


Peso da evidência (WoE em inglês) e valor da informação (IV) são usadas para
característica engeneering e seleção, e são extensivamente usadas em problemas de
scoring de crédito.
WoE é uma medida do poder preditivo de uma variável independente em relação a
variável alvo. Ela mede a extensão que uma característica pode diferenciar entre
classes alvo, no nosso caso, entre bons e maus pagadores.
IV ajuda a ranquear as características baseado nas suas importâncias relativas.
Benefícios do WoE e do IV:
25

• Considera contribuição individual de cada variável para o resultado final


• Detecta ralações lineares e não-lineares
• Ranqueia as variáveis em termos de forca preditiva
• Compara a força das variáveis continuas e categóricas sem a criação de
dummy variables

3.8.3. WoE
A fórmula para calcular o WoE é a seguiente:

Passos para WoE característica engeneering


• Calcule o WoE para cada grupo das variáveis categóricas, por exemplo,
para cada valor de grade, grade=A, grade=B, grade=C, grade=D, etc
• Agrupe variáveis contínuas em grupos discretos, baseados em sua
distribuição e número de observações únicas, por exemplo, dividir os
clientes em grupos por faixa de renda anual
• Calcule WoE para cada grupo derivado das variáveis contínuas
• Uma vez que WoE esteja calculado para cada grupo tanto nas
características categóricas quanto numéricas, combine grupos de acordo
com as seguintes regras:
• Cada grupo deve possuir pelo menos 5% das observações
• Cada grupo ser não-zero para ambos bons e maus empréstimos
• O WoE deve ser distinto para cada categoria. Grupos similares
devem ser agrupados. Pois grupos com WoE similares tem
quase o mesmo poder preditivo
• Os agrupamentos devem ser monotônicos, significando que
devem crescer ou diminuir à medida que se passa de um grupo
para outro na mesma característica
• Valores faltantes devem ser agrupados juntos
26

3.8.4. IV
IV é calculado da seguinte maneira:

A convenção de interpretação dos valore de IV pode ser vista na figura 3.5

figura 3.5- Tabela convenção valores de IV

3.8.5. Característica Engeneering com WoE e IV dos


dados
Vamos calcular o WoE e IV para dados de treino e performar a devida
característica engeneering. Nos vamos definir as três funções seguintes:
• Calcule e printe valores WoE e IV para variáveis categóricas
• Calcule e printe valores WoE e IV para variáveis numéricas
• Plote os valores WoE por grupo para nos ajudar a visualizar o WoE e
combinar grupos com valores similares de WoE
AS figuras 3.6 e 3.7 mostra essas funções aplicadas a variável categórica grade.

figura 3.6- Valores WoE e IV para variáveis Grade


27

figura 3.7- Grafico valores de WoE para variáveis Grade

Uma vez calculada e visualizada o WoE, selecione quais grupos serão


combinados e quais características serão excluídas dado seu IV. As características
restantes até agora serão tratadas de uma das seguintes formas:
• Não existe necessidade de combinar agrupamentos WoE ou o criar
uma categoria separada dado o WoE já ser discreto e monotonico e
não ter valores vazios: grade, verification_status, term
• Combine agrupamentos WoE com pouquíssimas observações, com
agrupamentos vizinhos: home_ownership, purpose
• Combine agrupamentos WoE com valores similares: int_rate,
annual_inc, dti, inq_last, inq_last_6mths, revol_until, out_prncp,
total_rec_int, total_rev_hi_lim, mths_since_earliest_cr_line,
mths_since_issue_d, mths_since_last_credit_pull_d
• Ignore características com baixo ou altíssimo IV: emp_length,
total_acc, last_pymnt_amnt, tot_cur_bal,
mths_since_last_pymnt_d_factor

O código referente ao foi proposto nesta seção se encontra no apêndice 4


28

3.9. Treinando o Modelo


Finalmente, chegamos ao estágio onde machine learning será envolvido. Vamos
utilizar um modelo de logistic regression no nosso dataset de treinamento e observar
os resultados.
Nossa métrica de avaliação será a Area Under the Receiver Operating
Characteristic Curve (AUROC), uma métrica de uso comum e aceita em scoring de
credito
Após performar a validação K-folds no dataset de treinamentoe estando satisfeito
com o AUROC, retornamos um sumário com todas as características e os seus
respectivos coeficientes como pode ser visto na figura 3.7

figura 3.7- Grafico valores dos coeficientes para cada característica

O código referente ao que foi proposto nesta seção se encontra no apêndice 5


29

3.10. Previsão
Tudo se resume a isso: aplique o modelo de regressão logística treinado para
predizer a probabilidade de inadimplência no dataset de teste, que ainda não foi usado
até o momento, exceto para data cleaning and característica selection.
Então, iremos desenhar a curva ROC, curva PR, e calcular AUROC and GINI.
Nosso teste AUROC resulta em 0.866 com GINI de 0.732, ambos sendo considerados
bons scores de avaliação. AS curvas ROC e PR podem ser vistas na figura 3.9

figura 3.9- Curvas ROC e PR (respectivamente).

O cálculo da área sob a curva PR deu 0.97, o que é um ótimo resultado, quanto
mais próximo de 1 melhor.
O código para o que foi proposto nesta seção se encontra no apêndice 6

3.11. Desenvolvimento do Scorecard


A peça final do quebra-cabeça é a criação de um scorecard simples e de fácil
interpretação por leigos no assunto.
Então nós determinamos os valores máximo e mínimo possíves de scores que
nosso scorecard deve resultar. Como referência, vamos usar o padrão FICO: scores
vão de 300 ate 850.
Os coeficientes retornados pelo nosso modelo de regressão logística para cada
característica vão ser usados em escala para determinar qual a pontuação de cada
variável por aritimética básica. Uma tabela com os valores dos coeficientes e a
pontuação correspondente podem ser vistas na figura 3.10 para algumas características
30

figura 3.10- Tabela pontuações Scorecard de cada variavel

3.12. Cálculo dos scores de crédito para dataset de teste


Uma vez que tenhamos as pontuações para nosso scorecard final, estamos prontos
para calcular o score de crédito de todas as observações no nosso dataset de test.
Lembre-se que nosso dataset de teste é apenas uma coleção de dummy variables com
valores que podem ser 0 ou 1. Por exemplo na figura 3.11 temos a observação 395346
que tem grade: C, possui casa própria e seu status de verificação é source verified:

figura 3.11- Print variáveis para cada observação

Finalmente o score de credito é calculado como uma simples multiplicação de


matrizes, entre a matriz do dataset de teste e a matriz do scorecard. Considerando a
observação acima junto com a seguinte parte do scorecard final mostrado na figura
3.12 temos:
31

figura 3.12- Scorecard para variáveis grade

A observação 395346 receberá 598 pontos do intercept e depois somará mais 15


pontos por ser grade: C. Analogamente a observação 3766583 terá uma pontuação
inicial de 598 pontos e a isso será adicionado 24 pontos por ter grade: A. O score de
credito final é apenas a soma dos pontos dados por cada uma das variáveis
individualmente, que pode ser obtido por uma simples multiplicação de matriz entre a
matriz de scorecad e a matriz de variáveis da observação.

3.13. Setando o limite para aprovação de crédito


Agora, como decidimos quais pedidos de crédito serão aprovados e quais serão
recusados? Qual a pontuação ideal de corte? Essa linha de corte deve balancear da
melhor forma possível o fato que quanto mais empréstimos forem aprovados, mais
dinheiro vamos ganhar com os juros, mas maior o risco de inadimplência.
Para descobir a pontuação de corte ótima, nós precisamos voltar para a
probabilidade de threshold da curva ROC.
A Curva ROC plota o FPR e TPR para todos as probabilidades de treshold de 0 a
1. Já que gostaríamos de minimizar o FPR enquanto maximizamos o TPR, o que
buscamos é a ponta esquerda da curva. Esse treshold ideal pode ser calculado com
uma função simples em python que leva como argumento a diferença entre o TPR e o
FPR.
Esse valor de treshold sera o valor correspondente, na curva ROC, onde a
derivada fica em 45º, representando assim o ponto em que a partir dele o FPR começa
a aumentar mais rápido de o TPR.
32

Com isso chegamos ao valor ideal de treshold de 0,187, que ao converter para
uma pontuação, chegamos à pontuação de 488. Esses valores correspondem a uma
taxa de aprovação de 92,6% e uma taxa de rejeição de 7,4% dos pedidos de credito.
O código para as partes 3.10, 3.11, 3.12 e 3.13 se encontra no apêndice 7

4. Conclusão
Esse tabalho fez uma breve análise do problema dos juros altos e propôs o uso de
machine learning com o objetivo de tentar diminuir as incertezas relacionados a
concessão de crédito e assim tentar melhorar um pouco o problema.
Foi mostrado o passo a passo do desenvolvimento de um modelo de machine
learning para análise de crédito e o desenvolvimento de um scorecard para permitir a
fácil interpretação e uso dos resultados por qualquer pessoa.

4.2. Trabalhos Futuros


Para trabalhos futuros se propõe a realização desta mesma análise utilizando
diversos algoritmos diferentes a fim de comparar e observar qual gera o melhor
resultado.
Se propõe tambem fazer uma análise semelhante a essa, mas dessa vez, com dados
de empréstimos concedidos no Brasil, a fim de fazer um estudo nacional sobre o
assunto.
33

5. Apendices

5.2. Apendice 1

# importa as bibliotecas necessarias


import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split,
RepeatedStratifiedKFold, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, roc_auc_score, confusion_matrix,
precision_recall_curve, auc
from sklearn.característica_selection import f_classif
from sklearn.pipeline import Pipeline
from sklearn.base import BaseEstimator, TransformerMixin
from scipy.stats import chi2_contingency

# importa os dados
loan_data = pd.read_csv('C:/Users/rafae/Jupyter/loan_data_2007_2014.csv')

# deleta as colunas com mais de 80% de nulos


loan_data.dropna(thresh = loan_data.shape[0]*0.2, how = 'all', axis = 1,
inplace = True)

#deleta coluna redundantes ou que não fazem sentido


loan_data.drop(columns = ['id', 'member_id', 'sub_grade', 'emp_title',
'url', 'desc', 'title', 'zip_code', 'next_pymnt_d', 'recoveries',
'collection_recovery_fee', 'total_rec_prncp', 'total_rec_late_fee'],
inplace = True)

# explora os valores únicos na coluna loan_status


loan_data['loan_status'].value_counts(normalize = True)

# cria nova coluna baseado na loan_status que sera nossa variável alvo
loan_data['good_bad']= np.where(loan_data.loc[:,
'loan_status'].isin(['Charged Off', 'Default',
'Late (31-120 days)','Does not meet the credit policy. Status:Charged
Off']),
0, 1)

# Exclui a coluna loan_status original


loan_data.drop(columns = ['loan_status'], inplace = True)

# divide os dados em 80/20 enquanto mantem a distribuição original


X = loan_data.drop('good_bad', axis = 1)
y = loan_data['good_bad']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2,
random_state = 42,
stratify = y)

# copia dos dataset X_train e X_test


X_train, X_test = X_train.copy(), X_test.copy()
34

5.3. Apendice 2

# divide o dataset de traino em categórico e numerico


X_train_cat = X_train.select_dtypes(include = 'object').copy()
X_train_num = X_train.select_dtypes(include = 'number').copy()

# de fine um dicionário vazio para armazenar os resultados chi-squre


chi2_check = {}

# faz loop por cada coluna no dataset de treinamento para calcular o chi-
statico com a variável alvo
for column in X_train_cat:
chi, p, dof, ex = chi2_contingency(pd.crosstab(y_train,
X_train_cat[column]))
chi2_check.setdefault('Característica',[]).append(column)
chi2_check.setdefault('p-value',[]).append(round(p, 10))

# converte o dicionário para um dataframe


chi2_result = pd.DataFrame(data = chi2_check)
chi2_result.sort_values(by = ['p-value'], ascending = True, ignore_index =
True, inplace = True)

# substitui os valores faltantes de cada coluna com a media da coluna


X_train_num.fillna(X_train_num.mean(), inplace = True)

# calcula a F-static e os valores P


F_statistic, p_values = f_classif(X_train_num, y_train)

# converte para dataframe


ANOVA_F_table = pd.DataFrame(data = {'Numerical_Característica':
X_train_num.columns.values,'F-Score': F_statistic, 'p values':
p_values.round(decimals=10)})
ANOVA_F_table.sort_values(by = ['F-Score'], ascending = False,
ignore_index = True, inplace = True)

# salva as top 20 características numéricas em uma lista


top_num_características = ANOVA_F_table.iloc[:20,0].to_list()

# calcula a correlação, duas a duas, entre elas


corrmat = X_train_num[top_num_características].corr()
plt.figure(figsize=(10,10))
sns.heatmap(corrmat)

# salva os nomes das colunas que serão excluídas em uma lista


drop_columns_list = ANOVA_F_table.iloc[20:, 0].to_list()
drop_columns_list.extend(chi2_result.iloc[4:, 0].to_list())
drop_columns_list.extend(['out_prncp_inv', 'total_pymnt_inv'])

# função para excluir essas colunas


def col_to_drop(df, columns_list):
df.drop(columns = columns_list, inplace = True)

# aplica a função acima na X_train


col_to_drop(X_train, drop_columns_list)
35

5.4. Apendice 3

# função para criar dummy variables


def dummy_creation(df, columns_list):
df_dummies = []
for col in columns_list:
df_dummies.append(pd.get_dummies(df[col], prefix = col, prefix_sep
= ':'))
df_dummies = pd.concat(df_dummies, axis = 1)
df = pd.concat([df, df_dummies], axis = 1)
return df

# Aplique a função as quatro variáveis categoricas


X_train = dummy_creation(X_train, ['grade', 'home_ownership',
'verification_status', 'purpose'])

# Atualize o dataset de teste com todas as funções definidas ate agora


emp_length_converter(X_test, 'emp_length')
date_columns(X_test, 'earliest_cr_line')
date_columns(X_test, 'issue_d')
date_columns(X_test, 'last_pymnt_d')
date_columns(X_test, 'last_credit_pull_d')
loan_term_converter(X_test, 'term')
col_to_drop(X_test, drop_columns_list)
X_test = dummy_creation(X_test, ['grade', 'home_ownership',
'verification_status', 'purpose'])
X_test = X_test.reindex(labels=X_train.columns, axis=1, fill_value=0)

5.5. Apendice 4

# função para calcular o WoR e IV de características categoricas


# a função tem como entrada três argumentos: um dataframe (x_trai_prepr),
#uma string(column_name) e um dataframe (y_train_prepr)
def woe_discrete(df, cat_variabe_name, y_df):
df = pd.concat([df[cat_variabe_name], y_df], axis = 1)
df = pd.concat([df.groupby(df.columns.values[0], as_index =
False)[df.columns.values[1]].count(),
df.groupby(df.columns.values[0], as_index =
False)[df.columns.values[1]].mean()], axis = 1)
df = df.iloc[:, [0, 1, 3]]
df.columns = [df.columns.values[0], 'n_obs', 'prop_good']
df['prop_n_obs'] = df['n_obs'] / df['n_obs'].sum()
df['n_good'] = df['prop_good'] * df['n_obs']
df['n_bad'] = (1 - df['prop_good']) * df['n_obs']
df['prop_n_good'] = df['n_good'] / df['n_good'].sum()
df['prop_n_bad'] = df['n_bad'] / df['n_bad'].sum()
df['WoE'] = np.log(df['prop_n_good'] / df['prop_n_bad'])
df = df.sort_values(['WoE'])
df = df.reset_index(drop = True)
df['diff_prop_good'] = df['prop_good'].diff().abs()
df['diff_WoE'] = df['WoE'].diff().abs()
df['IV'] = (df['prop_n_good'] - df['prop_n_bad']) * df['WoE']
df['IV'] = df['IV'].sum()
return df
36

#Função para calcular o WoE e IV de variáveis continuas


def woe_ordered_continuous(df, continuous_variabe_name, y_df):
df = pd.concat([df[continuous_variabe_name], y_df], axis = 1)
df = pd.concat([df.groupby(df.columns.values[0], as_index =
False)[df.columns.values[1]].count(),
df.groupby(df.columns.values[0], as_index =
False)[df.columns.values[1]].mean()], axis = 1)
df = df.iloc[:, [0, 1, 3]]
df.columns = [df.columns.values[0], 'n_obs', 'prop_good']
df['prop_n_obs'] = df['n_obs'] / df['n_obs'].sum()
df['n_good'] = df['prop_good'] * df['n_obs']
df['n_bad'] = (1 - df['prop_good']) * df['n_obs']
df['prop_n_good'] = df['n_good'] / df['n_good'].sum()
df['prop_n_bad'] = df['n_bad'] / df['n_bad'].sum()
df['WoE'] = np.log(df['prop_n_good'] / df['prop_n_bad'])
#df = df.sort_values(['WoE'])
#df = df.reset_index(drop = True)
df['diff_prop_good'] = df['prop_good'].diff().abs()
df['diff_WoE'] = df['WoE'].diff().abs()
df['IV'] = (df['prop_n_good'] - df['prop_n_bad']) * df['WoE']
df['IV'] = df['IV'].sum()
return df

# seta como default o estilo de gráfico seaborn


sns.set()

# função para plotar WoE


def plot_by_woe(df_WoE, rotation_of_x_axis_labels = 0):
x = np.array(df_WoE.iloc[:, 0].apply(str))
y = df_WoE['WoE']
plt.figure(figsize=(18, 6))
plt.plot(x, y, marker = 'o', linestyle = '--', color = 'k')
plt.xlabel(df_WoE.columns[0])
plt.ylabel('Weight of Evidence')
plt.title(str('Weight of Evidence by ' + df_WoE.columns[0]))
plt.xticks(rotation = rotation_of_x_axis_labels)

#cria uma lista com todas as categorias de referencia


ref_categories = ['mths_since_last_credit_pull_d:>75',
'mths_since_issue_d:>122', 'mths_since_earliest_cr_line:>434',
'total_rev_hi_lim:>79,780',
'total_rec_int:>7,260', 'total_pymnt:>25,000',
'out_prncp:>15,437', 'revol_util:>1.0', 'inq_last_6mths:>4', 'dti:>35.191',
'annual_inc:>150K', 'int_rate:>20.281', 'term:60',
'purpose:major_purch__car__home_impr', 'verification_status:Not Verified',
'home_ownership:MORTGAGE', 'grade:G']

# transforma a classe para criar novas dummy variables categoricas


class WoE_Binning(BaseEstimator, TransformerMixin):
def __init__(self, X): # no *args or *kargs
self.X = X
def fit(self, X, y = None):
return self #nothing else to do
def transform(self, X):
X_new = X.loc[:, 'grade:A': 'grade:G']
X_new['home_ownership:OWN'] = X.loc[:,'home_ownership:OWN']
X_new['home_ownership:MORTGAGE'] =
X.loc[:,'home_ownership:MORTGAGE']
X_new['home_ownership:OTHER_NONE_RENT'] =
sum([X['home_ownership:OTHER'], X['home_ownership:NONE'],
X['home_ownership:RENT']])
37

X_new = pd.concat([X_new, X.loc[:, 'verification_status:Not


Verified':'verification_status:Verified']], axis = 1)
X_new['purpose:debt_consolidation'] =
X.loc[:,'purpose:debt_consolidation']
X_new['purpose:credit_card'] = X.loc[:,'purpose:credit_card']
X_new['purpose:major_purch__car__home_impr'] =
sum([X['purpose:major_purchase'], X['purpose:car'],
X['purpose:home_improvement']])
X_new['purpose:educ__ren_en__sm_b__mov'] =
sum([X['purpose:educational'], X['purpose:renewable_energy'],
X['purpose:small_business'],

X['purpose:moving']])
X_new['purpose:vacation__house__wedding__med__oth'] =
sum([X['purpose:vacation'], X['purpose:house'], X['purpose:wedding'],

X['purpose:medical'], X['purpose:other']])
X_new['term:36'] = np.where((X['term'] == 36), 1, 0)
X_new['term:60'] = np.where((X['term'] == 60), 1, 0)
X_new['int_rate:<7.071'] = np.where((X['int_rate'] <= 7.071), 1, 0)
X_new['int_rate:7.071-10.374'] = np.where((X['int_rate'] > 7.071) &
(X['int_rate'] <= 10.374), 1, 0)
X_new['int_rate:10.374-13.676'] = np.where((X['int_rate'] > 10.374)
& (X['int_rate'] <= 13.676), 1, 0)
X_new['int_rate:13.676-15.74'] = np.where((X['int_rate'] > 13.676)
& (X['int_rate'] <= 15.74), 1, 0)
X_new['int_rate:15.74-20.281'] = np.where((X['int_rate'] > 15.74) &
(X['int_rate'] <= 20.281), 1, 0)
X_new['int_rate:>20.281'] = np.where((X['int_rate'] > 20.281), 1,
0)
X_new['annual_inc:missing'] = np.where(X['annual_inc'].isnull(), 1,
0)
X_new['annual_inc:<28,555'] = np.where((X['annual_inc'] <= 28555),
1, 0)
X_new['annual_inc:28,555-37,440'] = np.where((X['annual_inc'] >
28555) & (X['annual_inc'] <= 37440), 1, 0)
X_new['annual_inc:37,440-61,137'] = np.where((X['annual_inc'] >
37440) & (X['annual_inc'] <= 61137), 1, 0)
X_new['annual_inc:61,137-81,872'] = np.where((X['annual_inc'] >
61137) & (X['annual_inc'] <= 81872), 1, 0)
X_new['annual_inc:81,872-102,606'] = np.where((X['annual_inc'] >
81872) & (X['annual_inc'] <= 102606), 1, 0)
X_new['annual_inc:102,606-120,379'] = np.where((X['annual_inc'] >
102606) & (X['annual_inc'] <= 120379), 1, 0)
X_new['annual_inc:120,379-150,000'] = np.where((X['annual_inc'] >
120379) & (X['annual_inc'] <= 150000), 1, 0)
X_new['annual_inc:>150K'] = np.where((X['annual_inc'] > 150000), 1,
0)
X_new['dti:<=1.6'] = np.where((X['dti'] <= 1.6), 1, 0)
X_new['dti:1.6-5.599'] = np.where((X['dti'] > 1.6) & (X['dti'] <=
5.599), 1, 0)
X_new['dti:5.599-10.397'] = np.where((X['dti'] > 5.599) & (X['dti']
<= 10.397), 1, 0)
X_new['dti:10.397-15.196'] = np.where((X['dti'] > 10.397) &
(X['dti'] <= 15.196), 1, 0)
X_new['dti:15.196-19.195'] = np.where((X['dti'] > 15.196) &
(X['dti'] <= 19.195), 1, 0)
X_new['dti:19.195-24.794'] = np.where((X['dti'] > 19.195) &
(X['dti'] <= 24.794), 1, 0)
X_new['dti:24.794-35.191'] = np.where((X['dti'] > 24.794) &
(X['dti'] <= 35.191), 1, 0)
38

X_new['dti:>35.191'] = np.where((X['dti'] > 35.191), 1, 0)


X_new['inq_last_6mths:missing'] =
np.where(X['inq_last_6mths'].isnull(), 1, 0)
X_new['inq_last_6mths:0'] = np.where((X['inq_last_6mths'] == 0), 1,
0)
X_new['inq_last_6mths:1-2'] = np.where((X['inq_last_6mths'] >= 1) &
(X['inq_last_6mths'] <= 2), 1, 0)
X_new['inq_last_6mths:3-4'] = np.where((X['inq_last_6mths'] >= 3) &
(X['inq_last_6mths'] <= 4), 1, 0)
X_new['inq_last_6mths:>4'] = np.where((X['inq_last_6mths'] > 4), 1,
0)
X_new['revol_util:missing'] = np.where(X['revol_util'].isnull(), 1,
0)
X_new['revol_util:<0.1'] = np.where((X['revol_util'] <= 0.1), 1, 0)
X_new['revol_util:0.1-0.2'] = np.where((X['revol_util'] > 0.1) &
(X['revol_util'] <= 0.2), 1, 0)
X_new['revol_util:0.2-0.3'] = np.where((X['revol_util'] > 0.2) &
(X['revol_util'] <= 0.3), 1, 0)
X_new['revol_util:0.3-0.4'] = np.where((X['revol_util'] > 0.3) &
(X['revol_util'] <= 0.4), 1, 0)
X_new['revol_util:0.4-0.5'] = np.where((X['revol_util'] > 0.4) &
(X['revol_util'] <= 0.5), 1, 0)
X_new['revol_util:0.5-0.6'] = np.where((X['revol_util'] > 0.5) &
(X['revol_util'] <= 0.6), 1, 0)
X_new['revol_util:0.6-0.7'] = np.where((X['revol_util'] > 0.6) &
(X['revol_util'] <= 0.7), 1, 0)
X_new['revol_util:0.7-0.8'] = np.where((X['revol_util'] > 0.7) &
(X['revol_util'] <= 0.8), 1, 0)
X_new['revol_util:0.8-0.9'] = np.where((X['revol_util'] > 0.8) &
(X['revol_util'] <= 0.9), 1, 0)
X_new['revol_util:0.9-1.0'] = np.where((X['revol_util'] > 0.9) &
(X['revol_util'] <= 1.0), 1, 0)
X_new['revol_util:>1.0'] = np.where((X['revol_util'] > 1.0), 1, 0)
X_new['out_prncp:<1,286'] = np.where((X['out_prncp'] <= 1286), 1,
0)
X_new['out_prncp:1,286-6,432'] = np.where((X['out_prncp'] > 1286) &
(X['out_prncp'] <= 6432), 1, 0)
X_new['out_prncp:6,432-9,005'] = np.where((X['out_prncp'] > 6432) &
(X['out_prncp'] <= 9005), 1, 0)
X_new['out_prncp:9,005-10,291'] = np.where((X['out_prncp'] > 9005)
& (X['out_prncp'] <= 10291), 1, 0)
X_new['out_prncp:10,291-15,437'] = np.where((X['out_prncp'] >
10291) & (X['out_prncp'] <= 15437), 1, 0)
X_new['out_prncp:>15,437'] = np.where((X['out_prncp'] > 15437), 1,
0)
X_new['total_pymnt:<10,000'] = np.where((X['total_pymnt'] <=
10000), 1, 0)
X_new['total_pymnt:10,000-15,000'] = np.where((X['total_pymnt'] >
10000) & (X['total_pymnt'] <= 15000), 1, 0)
X_new['total_pymnt:15,000-20,000'] = np.where((X['total_pymnt'] >
15000) & (X['total_pymnt'] <= 20000), 1, 0)
X_new['total_pymnt:20,000-25,000'] = np.where((X['total_pymnt'] >
20000) & (X['total_pymnt'] <= 25000), 1, 0)
X_new['total_pymnt:>25,000'] = np.where((X['total_pymnt'] > 25000),
1, 0)
X_new['total_rec_int:<1,089'] = np.where((X['total_rec_int'] <=
1089), 1, 0)
X_new['total_rec_int:1,089-2,541'] = np.where((X['total_rec_int'] >
1089) & (X['total_rec_int'] <= 2541), 1, 0)
X_new['total_rec_int:2,541-4,719'] = np.where((X['total_rec_int'] >
2541) & (X['total_rec_int'] <= 4719), 1, 0)
39

X_new['total_rec_int:4,719-7,260'] = np.where((X['total_rec_int'] >


4719) & (X['total_rec_int'] <= 7260), 1, 0)
X_new['total_rec_int:>7,260'] = np.where((X['total_rec_int'] >
7260), 1, 0)
X_new['total_rev_hi_lim:missing'] =
np.where(X['total_rev_hi_lim'].isnull(), 1, 0)
X_new['total_rev_hi_lim:<6,381'] = np.where((X['total_rev_hi_lim']
<= 6381), 1, 0)
X_new['total_rev_hi_lim:6,381-19,144'] =
np.where((X['total_rev_hi_lim'] > 6381) & (X['total_rev_hi_lim'] <= 19144),
1, 0)
X_new['total_rev_hi_lim:19,144-25,525'] =
np.where((X['total_rev_hi_lim'] > 19144) & (X['total_rev_hi_lim'] <=
25525), 1, 0)
X_new['total_rev_hi_lim:25,525-35,097'] =
np.where((X['total_rev_hi_lim'] > 25525) & (X['total_rev_hi_lim'] <=
35097), 1, 0)
X_new['total_rev_hi_lim:35,097-54,241'] =
np.where((X['total_rev_hi_lim'] > 35097) & (X['total_rev_hi_lim'] <=
54241), 1, 0)
X_new['total_rev_hi_lim:54,241-79,780'] =
np.where((X['total_rev_hi_lim'] > 54241) & (X['total_rev_hi_lim'] <=
79780), 1, 0)
X_new['total_rev_hi_lim:>79,780'] = np.where((X['total_rev_hi_lim']
> 79780), 1, 0)
X_new['mths_since_earliest_cr_line:missing'] =
np.where(X['mths_since_earliest_cr_line'].isnull(), 1, 0)
X_new['mths_since_earliest_cr_line:<125'] =
np.where((X['mths_since_earliest_cr_line'] <= 125), 1, 0)
X_new['mths_since_earliest_cr_line:125-167'] =
np.where((X['mths_since_earliest_cr_line'] > 125) &
(X['mths_since_earliest_cr_line'] <= 167), 1, 0)
X_new['mths_since_earliest_cr_line:167-249'] =
np.where((X['mths_since_earliest_cr_line'] > 167) &
(X['mths_since_earliest_cr_line'] <= 249), 1, 0)
X_new['mths_since_earliest_cr_line:249-331'] =
np.where((X['mths_since_earliest_cr_line'] > 249) &
(X['mths_since_earliest_cr_line'] <= 331), 1, 0)
X_new['mths_since_earliest_cr_line:331-434'] =
np.where((X['mths_since_earliest_cr_line'] > 331) &
(X['mths_since_earliest_cr_line'] <= 434), 1, 0)
X_new['mths_since_earliest_cr_line:>434'] =
np.where((X['mths_since_earliest_cr_line'] > 434), 1, 0)
X_new['mths_since_issue_d:<79'] = np.where((X['mths_since_issue_d']
<= 79), 1, 0)
X_new['mths_since_issue_d:79-89'] =
np.where((X['mths_since_issue_d'] > 79) & (X['mths_since_issue_d'] <= 89),
1, 0)
X_new['mths_since_issue_d:89-100'] =
np.where((X['mths_since_issue_d'] > 89) & (X['mths_since_issue_d'] <= 100),
1, 0)
X_new['mths_since_issue_d:100-122'] =
np.where((X['mths_since_issue_d'] > 100) & (X['mths_since_issue_d'] <=
122), 1, 0)
X_new['mths_since_issue_d:>122'] =
np.where((X['mths_since_issue_d'] > 122), 1, 0)
X_new['mths_since_last_credit_pull_d:missing'] =
np.where(X['mths_since_last_credit_pull_d'].isnull(), 1, 0)
X_new['mths_since_last_credit_pull_d:<56'] =
np.where((X['mths_since_last_credit_pull_d'] <= 56), 1, 0)
40

X_new['mths_since_last_credit_pull_d:56-61'] =
np.where((X['mths_since_last_credit_pull_d'] > 56) &
(X['mths_since_last_credit_pull_d'] <= 61), 1, 0)
X_new['mths_since_last_credit_pull_d:61-75'] =
np.where((X['mths_since_last_credit_pull_d'] > 61) &
(X['mths_since_last_credit_pull_d'] <= 75), 1, 0)
X_new['mths_since_last_credit_pull_d:>75'] =
np.where((X['mths_since_last_credit_pull_d'] > 75), 1, 0)
X_new.drop(columns = ref_categories, inplace = True)
return X_new

5.6. Apendice 5

# define o pipeline do modelo


reg = LogisticRegression(max_iter=1000, class_weight = 'balanced')
woe_transform = WoE_Binning(X)
pipeline = Pipeline(steps=[('woe', woe_transform), ('model', reg)])

# define o critério de cross_validation


cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=3, random_state=1)

# fit e avalia o modelo de logistic regression com a cross_validation


scores = cross_val_score(pipeline, X_train, y_train, scoring = 'roc_auc',
cv = cv)
AUROC = np.mean(scores)
GINI = AUROC * 2 - 1

# printa a media do score AUROC e Gini


print('Mean AUROC: %.4f' % (AUROC))
print('Gini: %.4f' % (GINI))

# fit a pipeline em todo o dataset de treino


pipeline.fit(X_train, y_train)

# cria tabela sumario


X_train_woe_transformed = woe_transform.fit_transform(X_train)
característica_name = X_train_woe_transformed.columns.values
summary_table = pd.DataFrame(columns = ['Característica name'], data =
característica_name)
summary_table['Coefficients'] = np.transpose(pipeline['model'].coef_)
summary_table.index = summary_table.index + 1
summary_table.loc[0] = ['Intercept', pipeline['model'].intercept_[0]]
summary_table.sort_index(inplace = True)

5.7. Apendice 6

# Faz previsão para nosso dataset de teste


y_hat_test = pipeline.predict(X_test)
# get the predicted probabilities
y_hat_test_proba = pipeline.predict_proba(X_test)
# select the probabilities of only the positive class (class 1 - default)
y_hat_test_proba = y_hat_test_proba[:][: , 1]

# vamos agora crear um novo dataframe com classes e as probabilidades


previstas
41

y_test_temp = y_test.copy()
y_test_temp.reset_index(drop = True, inplace = True)
y_test_proba = pd.concat([y_test_temp, pd.DataFrame(y_hat_test_proba)],
axis = 1)

# renomeia as colunas
y_test_proba.columns = ['y_test_class_actual', 'y_hat_test_proba']

# torna o index de um dataframe igual ao index do outro dataframe


y_test_proba.index = X_test.index

# pega os valores necessário para plotar a curva ROC


fpr, tpr, thresholds = roc_curve(y_test_proba['y_test_class_actual'],
y_test_proba['y_hat_test_proba'])
# Plota a curva ROC
plt.plot(fpr, tpr)
# plot a secondary diagonal line, with dashed line style and black color to
represent a no-skill classifier
plt.plot(fpr, fpr, linestyle = '--', color = 'k')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC curve');

# Calcula a are abaico da curva AUROC para o dataset de teste


AUROC = roc_auc_score(y_test_proba['y_test_class_actual'],
y_test_proba['y_hat_test_proba'])
# calculate Gini from AUROC
Gini = AUROC * 2 - 1
# print AUROC and Gini
print('AUROC: %.4f' % (AUROC))
print('Gini: %.4f' % (Gini))

# Plota a curva PR
no_skill = len(y_test[y_test == 1]) / len(y)
plt.plot([0, 1], [no_skill, no_skill], linestyle='--', label='No Skill')
precision, recall, thresholds =
precision_recall_curve(y_test_proba['y_test_class_actual'],
y_test_proba['y_hat_test_proba'])
plt.plot(recall, precision, marker='.', label='Logistic')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.legend()
plt.title('PR curve');

5.8. Apendice 7

# Cria um novo dataframe com uma coluna com on valores da lista de


categorias de referencia
df_ref_categories = pd.DataFrame(ref_categories, columns = ['Característica
name'])

# criamos uma segunda coluna, chamada ‘coeficientes’, que contem apenas


valores 0
df_ref_categories['Coefficients'] = 0

# concatena os dois data frames


df_scorecard = pd.concat([summary_table, df_ref_categories])
42

# reseta o index
df_scorecard.reset_index(inplace = True)

# cria uma nova coluna, chamada ‘nome original da características’, que


contem nome original das características
df_scorecard['Original característica name'] = df_scorecard['Característica
name'].str.split(':').str[0]

# define o intervalo em que o score deve ficar


min_score = 300
max_score = 850

# Calcula a soma mínima dos coeficientes de cada categoria


min_sum_coef = df_scorecard.groupby('Original característica
name')['Coefficients'].min().sum()

# calcula a soma máxima dos coeficientes de cada categoria


max_sum_coef = df_scorecard.groupby('Original característica
name')['Coefficients'].max().sum()

# cria uma coluna nova que com os score calculado nos coeficientes
df_scorecard['Score - Calculation'] = df_scorecard['Coefficients'] *
(max_score - min_score) / (
max_sum_coef - min_sum_coef)
df_scorecard.loc[0, 'Score - Calculation'] = (
(df_scorecard.loc[0,'Coefficients'] - min_sum_coef) /
(max_sum_coef - min_sum_coef
)) * (max_score - min_score) + min_score
df_scorecard['Score - Preliminary'] = df_scorecard['Score -
Calculation'].round()

# checa o mínimo e o máximo possível dos scores


min_sum_score_prel = df_scorecard.groupby('Original característica
name')['Score - Preliminary'].min().sum()
max_sum_score_prel = df_scorecard.groupby('Original característica
name')['Score - Preliminary'].max().sum()
print(min_sum_score_prel)
print(max_sum_score_prel)

# Ajusta para que mínimo emaximo scores esteja dentro da faixa desejada
pd.options.display.max_rows = 102
df_scorecard['Difference'] = df_scorecard['Score - Preliminary'] -
df_scorecard['Score - Calculation']
df_scorecard['Score - Final'] = df_scorecard['Score - Preliminary']
df_scorecard.loc[0, 'Score - Final'] = 598

# checa novamente o mínimo e máximo possível dos scores


print(df_scorecard.groupby('Original característica name')['Score -
Final'].min().sum())
print(df_scorecard.groupby('Original característica name')['Score -
Final'].max().sum())

# calcula os scores para o dataser de teste


X_test_woe_transformed = woe_transform.fit_transform(X_test)
X_test_woe_transformed.insert(0, 'Intercept', 1)

# gera lista final do scorecard


43

scorecard_scores = df_scorecard['Score - Final']


print(X_test_woe_transformed.shape)
print(scorecard_scores.shape)

#faz a multiplicação de matriz para gerar os scores finais


X_test_woe_transformed = pd.concat([X_test_woe_transformed,
pd.DataFrame(dict.fromkeys(ref_categories, [0]
*
len(X_test_woe_transformed)),
index =
X_test_woe_transformed.index)], axis = 1)
scorecard_scores = scorecard_scores.values.reshape(102, 1)
print(X_test_woe_transformed.shape)
print(scorecard_scores.shape)
y_scores = X_test_woe_transformed.dot(scorecard_scores)
J = tpr - fpr
ix = np.argmax(J)
best_thresh = thresholds[ix]
print('Best Threshold: %f' % (best_thresh))
df_cutoffs = pd.DataFrame(thresholds, columns = ['thresholds'])
df_cutoffs['Score'] = ((np.log(df_cutoffs['thresholds'] / (1 -
df_cutoffs['thresholds'])) - min_sum_coef) *
((max_score - min_score) / (max_sum_coef -
min_sum_coef)) + min_score).round()

def n_approved(p):
return np.where(y_test_proba['y_hat_test_proba'] >= p, 1, 0).sum()
df_cutoffs['N Rejected'] = y_test_proba['y_hat_test_proba'].shape[0] -
df_cutoffs['N Approved']
df_cutoffs['Approval Rate'] = df_cutoffs['N Approved'] /
y_test_proba['y_hat_test_proba'].shape[0]
df_cutoffs['Rejection Rate'] = 1 - df_cutoffs['Approval Rate']
df_cutoffs[df_cutoffs['thresholds'].between(0.18657, 0.18658)]
44

6. Referências
• Ng, Andrew. Coursera: Machine Learning, c2020. Curso online.
Disponível em: < >.
• Castro, Paulo André. Google classrom: CEMA-824 – inteligência artificial, c2020.
Curso online. Disponível em:
< https://classroom.google.com/u/2/c/NTY0NTA2MDg1NzNa>.
• HAN, Jiawei, KAMBER, Micheline. Data Mining: Concepts and Techniques. United
States of America: Morgan Kufmann, 2001.
• NORVIG, P. Inteligência Artificial: Uma abordagem moderna. 3ª. Ed. Rio de
janeiro: Elsevier Editora, 2009.

Você também pode gostar