Limpeza e pré-processamento de dados:
Inadimplência em Cartões de Crédito

#eda #r #rshiny #kaggle

A inadimplência em operações de crédito representa um dos principais riscos enfrentados pelas instituições financeiras, com impactos diretos na rentabilidade, necessidade de capital regulatório e estabilidade do sistema financeiro como um todo. No contexto dos cartões de crédito, modalidade caracterizada pela ausência de garantias reais e pela concessão baseada principalmente na análise do perfil do cliente, a compreensão dos fatores que influenciam o comportamento de pagamento torna-se ainda mais crítica.

Neste artigo vou fazer uma Análise Exploratória de Dados (EDA) do conhecido dataset Default Credit Card Clients da UC Irvine Machine Learning Repository e estimar quais perfis de clientes possuem maior tendência a atrasarem o pagamento das faturas dos cartões de crédito. O dataset reúne informações de clientes de bancos em Taiwan no ano de 2005, constituído de 30.000 observações e 25 variáveis, representa um problema clássico na área de risco de crédito.

Objetivos da análise

Meu objetivo aqui é fazer uma análise exploratória de dados inicial baseada unicamente em modelos estatísticos para alcançar um primeiro entendimento dos dados do dataset. Dessa forma, ainda não entrarei na área de Machine Learning para previsão mais otimizada em si. Especificamente, busco responder às seguintes questões de pesquisa:

Questão principal: quais características demográficas, financeiras e comportamentais estão mais fortemente associadas à probabilidade de inadimplência em cartões de crédito?

Questões específicas:

  1. Como as variáveis demográficas (idade, sexo, educação, estado civil) se relacionam com o comportamento de pagamento?
  2. Existe relação entre o limite de crédito concedido e a taxa de inadimplência dos clientes?
  3. O histórico de pagamentos nos meses anteriores fornece sinais preditivos relevantes sobre inadimplência futura?
  4. Quais padrões podem ser identificados na utilização do cartão de crédito entre clientes adimplentes e inadimplentes?

Metodologia

A limpeza e o pré-processamento de dados, incluindo a harmonização de categorias não documentadas ou inconsistentes, são etapas que podem consumir uma porção significativa do tempo de um projeto, mas são essenciais para a validade e robustez dos modelos subsequentes (James et al., 2021).

Para fazer a manipulação dos dados optei por usar Linguagem R devido à sua ampla gama de pacotes para análise estatística. Além disso, o R oferece sintaxe clara e recursos que facilitam o entendimento dos resultados. Para visualização gráfica utilizei a biblioteca RShiny pois permite explorar os dados de forma dinâmica e intuitiva.

Execução

Optei por não incluir todo o código aqui, para não deixar a análise desnecessariamente extensa. A definição de cada variável bem como outras informações que podem ser importantes para verificar a consistência da análise podem ser encontradas neste link. As bibliotecas utilizadas e o código completo estão disponíveis no repositório do projeto no GitHub, que pode ser acessado neste link.

O trabalho será constituído em 4 etapas:

  1. Limpeza e pré-processamento dos dados: fundamental para garantir que as informações estejam corretas e prontas para análise;
  2. Análise descritiva e visualização dos dados: para entender padrões e tendências iniciais;
  3. Modelagem estatística: univariada e multivariada, para identificar fatores associados à inadimplência;
  4. Visualização e discussão dos resultados: gráficos interativos e implicações práticas.

Abaixo estão os detalhes de cada etapa, com o código necessário para reproduzir a análise.

1. Limpeza e pré-processamento

Para realizar uma inspeção inicial dos dados:


# Exbie a estrutura do dataframe para entender os tipos de dados de cada coluna
glimpse(credit_card_df)
    
Mostrar resultado

        Rows: 30,000
Columns: 25
$ ID                          1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28…
$ LIMIT_BAL                   20000, 120000, 90000, 50000, 50000, 50000, 500000, 100000, 140000, 20000, 200000, 260000, 630000, 700…
$ SEX                         2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 2,…
$ EDUCATION                   2, 2, 2, 2, 2, 1, 1, 2, 3, 3, 3, 1, 2, 2, 1, 3, 1, 1, 1, 1, 3, 2, 2, 1, 1, 3, 1, 3, 3, 1, 1, 2, 1, 2,…
$ MARRIAGE                    1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1,…
$ AGE                         24, 26, 34, 37, 57, 37, 29, 23, 28, 35, 34, 51, 41, 30, 29, 23, 24, 49, 49, 29, 39, 39, 26, 40, 23, 2…
$ PAY_0                       2, -1, 0, 0, -1, 0, 0, 0, 0, -2, 0, -1, -1, 1, 0, 1, 0, 0, 1, 1, 0, -1, 2, -2, 0, 0, 1, 0, -1, 0, -1,…
$ PAY_2                       2, 2, 0, 0, 0, 0, 0, -1, 0, -2, 0, -1, 0, 2, 0, 2, 0, 0, -2, -2, 0, -1, 0, -2, 0, 0, -2, 0, -1, 0, -1…
$ PAY_3                       -1, 0, 0, 0, -1, 0, 0, -1, 2, -2, 2, -1, -1, 2, 0, 0, 2, 0, -2, -2, 0, -1, 0, -2, 0, 0, -1, 0, -1, 0,…
$ PAY_4                       -1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, -1, 0, 0, 0, 2, -1, -2, -2, 0, -1, 2, -2, -1, 0, -1, 0, -1, 0,…
$ PAY_5                       -2, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, -1, 0, 0, 0, 2, -1, -2, -2, 0, -1, 2, -2, 0, 0, -1, 0, -1, 0, …
$ PAY_6                       -2, 2, 0, 0, 0, 0, 0, -1, 0, -1, -1, 2, -1, 2, 0, 0, 2, -1, -2, -2, -1, -1, 2, -2, 0, 0, -1, 0, -1, 0…
$ BILL_AMT1                   3913, 2682, 29239, 46990, 8617, 64400, 367965, 11876, 11285, 0, 11073, 12261, 12137, 65802, 70887, 50…
$ BILL_AMT2                   3102, 1725, 14027, 48233, 5670, 57069, 412023, 380, 14096, 0, 9787, 21670, 6500, 67369, 67060, 29173,…
$ BILL_AMT3                   689, 2682, 13559, 49291, 35835, 57608, 445007, 601, 12108, 0, 5535, 9966, 6500, 65701, 63561, 28116, …
$ BILL_AMT4                   0, 3272, 14331, 28314, 20940, 19394, 542653, 221, 12211, 0, 2513, 8517, 6500, 66782, 59696, 28771, 18…
$ BILL_AMT5                   0, 3455, 14948, 28959, 19146, 19619, 483003, -159, 11793, 13007, 1828, 22287, 6500, 36137, 56875, 295…
$ BILL_AMT6                   0, 3261, 15549, 29547, 19131, 20024, 473944, 567, 3719, 13912, 3731, 13668, 2870, 36894, 55512, 30211…
$ PAY_AMT1                    0, 0, 1518, 2000, 2000, 2500, 55000, 380, 3329, 0, 2306, 21818, 1000, 3200, 3000, 0, 3200, 10358, 0, …
$ PAY_AMT2                    689, 1000, 1500, 2019, 36681, 1815, 40000, 601, 0, 0, 12, 9966, 6500, 0, 3000, 1500, 0, 10000, 0, 0, …
$ PAY_AMT3                    0, 1000, 1000, 1200, 10000, 657, 38000, 0, 432, 0, 50, 8583, 6500, 3000, 3000, 1100, 1500, 75940, 0, …
$ PAY_AMT4                    0, 1000, 1000, 1100, 9000, 1000, 20239, 581, 1000, 13007, 300, 22301, 6500, 3000, 3000, 1200, 0, 2000…
$ PAY_AMT5                    0, 0, 1000, 1069, 689, 1000, 13750, 1687, 1000, 1122, 3738, 0, 2870, 1500, 3000, 1300, 1650, 195599, …
$ PAY_AMT6                    0, 2000, 5000, 1000, 679, 800, 13770, 1542, 1000, 0, 66, 3640, 0, 0, 3000, 1100, 0, 50000, 0, 0, 3376…
$ default.payment.next.month  1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,…
      

Aqui é possível observar que as variáveis estão em formatos adequados, com exceçãão de sex, education e marriage, que estão como numéricas, mas representam variáveis categóricas. Para corrigir isso, podemos usar a função mutate() do pacote dplyr para converter essas colunas em factor:


# Seleciona as colunas categóricas e as converte para o tipo 'factor'
factor_vars <- c("SEX", "EDUCATION", "MARRIAGE", "default.payment.next.month")
credit_card_df <- credit_card_df %>%
  mutate(across(all_of(factor_vars), as.factor))
    

Além disso, é essencial verificar a presença de valores ausentes. O tratamento desses dados é um problema central em ciência de dados. A decisão de como lidar com eles (e.g., remoção de casos, imputação) pode introduzir viés e afetar significativamente o desempenho e a validade do modelo final.


# Conta a quantidade de valores ausentes (NA) em cada coluna
missing_values <- colSums(is.na(credit_card_df))

# Exibe apenas as colunas que contêm valores ausentes
print(missing_values[missing_values > 0])
    
Mostrar resultado

named numeric(0)
      

A partir do resultado, podemos observar que não há valores ausentes no dataset, o que é um bom sinal para a análise. No entanto, é sempre importante estar atento a possíveis inconsistências nos dados, como categorias não documentadas ou erros de digitação. Para tanto, é recomendável realizar uma verificação das categorias presentes nas variáveis.

Por exemplo, para as variáveis categóricas, optei utilizar a função summary() para obter uma visão geral da distribuição das categorias:


  # Resumo das variáveis categóricas
summary(credit_card_df[c("SEX", "EDUCATION", "MARRIAGE")])
    
Mostrar resultado

      SEX          EDUCATION        MARRIAGE    
 Min.   :1.000   Min.   :0.000   Min.   :0.000  
 1st Qu.:1.000   1st Qu.:1.000   1st Qu.:1.000  
 Median :2.000   Median :2.000   Median :2.000  
 Mean   :1.604   Mean   :1.853   Mean   :1.552  
 3rd Qu.:2.000   3rd Qu.:2.000   3rd Qu.:2.000  
 Max.   :2.000   Max.   :6.000   Max.   :3.000
      

Aqui, pude perceber que as colunas EDUCATION e MARRIAGE apresentam um valor (0) que não está informado nas definições das variáveis do dataset.

Segundo as definições:

Ou seja, não temos uma definição para o valor (0) que apresenta 14 observações em EDUCATION e 54 em MARRIAGE. Decidi agrupar esse valor na categoria Unknown na primeira e em Others na segunda para facilitar a análise.

Além disso, seguindo o exposto por (James et al., 2021), para melhorar a interpretabilidade das variáveis categóricas, decidi recodificá-las (incluindo a variável default.payment.next.month) para evitar a consulta contínua à descrição de cada uma.


# Recodificando os níveis dos fatores para torná-los descritivos
credit_card_df <- credit_card_df %>%
  mutate(
    SEX = recode_factor(SEX, `1` = "Male", `2` = "Female"),
    EDUCATION = recode_factor(EDUCATION,
                              `0` = "Unknown",
                              `1` = "Graduate School",
                              `2` = "University",
                              `3` = "High School",
                              `4` = "Others",
                              `5` = "Unknown",
                              `6` = "Unknown"),
    MARRIAGE = recode_factor(MARRIAGE, `0` = "Other", `1` = "Married", `2` = "Single", `3` = "Other"),
    # Renomeia a variável alvo para maior clareza
    default.payment.next.month = recode_factor(default.payment.next.month, `0` = "No", `1` = "Yes")
  ) %>%
  # Renomeia a variável alvo
  rename(DEFAULT = default.payment.next.month)

# Verificando as colunas modificadas para ver os novos rótulos e suas contagens
summary(credit_card_df[c("SEX", "EDUCATION", "MARRIAGE", "DEFAULT")])
      
Mostrar resultado

    SEX                  EDUCATION        MARRIAGE     DEFAULT    
 Male  :11888   Unknown        :  345   Other  :  377   No :23364  
 Female:18112   Graduate School:10585   Married:13659   Yes: 6636  
                University     :14030   Single :15964              
                High School    : 4917                              
                Others         :  123
      

Agora, as variáveis categóricas estão mais claras e fáceis de interpretar, mas é necessário explicar como podemos interpretar os valores Unknown e Others.

Um exemplo mais comum acontece quando em um formulário, na categoria Sexualidade as opções selecionáveis podem ser: "heteressexual", "homossexual", "bissexual", "outro (especificar)" e "Prefiro não responder".

Dessa forma o dado existe, e a importância dele está no seu padrão. Se os clientes escolhem "Outros" ou "Prefiro não responder" o fazem por algum motivo que pode se correlacionar com a inadimplência. Então, dado todo o conjunto do dataset esses valores em si são uma informações valiosas. Apagá-las sem algum critério apenas para simplificar os dados causaria viés e possivelmente colocaria toda a análise em xeque.

A variável alvo DEFAULT foi renomeada para refletir melhor seu significado, e as categorias foram ajustadas para evitar confusões.

Por fim, é importante verificar se há duplicatas no dataset. A presença de duplicatas pode distorcer os resultados da análise e levar a conclusões erradas. Para verificar isso, podemos usar a função duplicated() do R:


# Verifica se há linhas duplicadas no dataframe
duplicated_rows <- credit_card_df[duplicated(credit_card_df), ]
# Exibe as linhas duplicadas, se houver
if (nrow(duplicated_rows) > 0) {
  print("Linhas duplicadas encontradas:")
  print(duplicated_rows)
} else {
  print("Nenhuma linha duplicada encontrada.")
}
    
Mostrar resultado

"Nenhuma linha duplicada encontrada."
      

Como esperado, não há duplicatas no dataset, o que é um bom sinal para a análise. Agora podemos prosseguir para a próxima etapa, que é a análise descritiva e visualização dos dados.