Introdução

Declaração do Problema

A expansão dos produtos e serviços financeiros nas últimas décadas como cartões de crédito, hipotecas, empréstimos pessoais e produtos de crédito alternativo tem facilitado o acesso ao crédito, mas também provocado um aumento no volume de reclamações por parte dos consumidores. Com a popularização dos serviços financeiros digitais e o aumento da complexidade dos produtos ofertados, muitos consumidores têm enfrentado dificuldades para compreender taxas, condições contratuais e processos de resolução de problemas, o que se reflete diretamente nas reclamações registradas por canais oficiais, como o banco de dados mantido pelo Consumer Financial Protection Bureau (CFPB). Além disso, pesquisas demonstram que a divulgação pública dessas reclamações pode exercer um papel disciplinador sobre os bancos e influenciar diretamente suas práticas de mercado (Jou et al. 2024).

Pesquisas conduzidas por Bastani, Namavari, and Shaffer (2019) apontam que determinadas categorias de produtos, como hipotecas, serviços de cobrança e relatórios de crédito, concentram a maior parte das reclamações. Os autores aplicaram técnicas de modelagem de tópicos em textos de reclamações e identificaram que, mesmo dentro de uma mesma categoria de produto, as insatisfações dos consumidores se distribuem em subtemas específicos, o que revela a complexidade dos problemas enfrentados pelos usuários desses serviços.

Outros estudos, como o de Vaishnav et al. (2023), utilizaram abordagens baseadas em Big Data para analisar os dados do CFPB em larga escala, revelando variações significativas nos produtos mais reclamados ao longo do tempo e entre diferentes regiões dos Estados Unidos. Apesar do uso de técnicas computacionais mais sofisticadas, esses trabalhos reforçam o papel essencial da análise descritiva e exploratória como ponto de partida para compreender padrões estruturais de insatisfação no setor financeiro.

Diante disso, este relatório tem como objetivo realizar uma análise exploratória dos produtos financeiros mais reclamados com base no banco de dados do CFPB, utilizando contagens, rankings, comparações temporais e visualizações para destacar padrões relevantes. A expectativa é que os resultados obtidos possam gerar insights valiosos tanto para os consumidores quanto para instituições financeiras e órgãos reguladores, ao identificar os produtos que mais concentram desafios de atendimento, clareza e transparência no mercado financeiro.

Método

O diagrama abaixo detalha nossa metodologia de análise de dados em cinco etapas sequenciais. O processo abrange desde a coleta e limpeza dos dados, passando pela criação de gráficos e variáveis, até a análise e interpretação final dos resultados. Este é um ciclo iterativo, permitindo o refinamento contínuo da investigação.

Conjunto de Dados

Este conjunto de dados contém reclamações de consumidores enviadas ao CFPB (Consumer Financial Protection Bureau) sobre produtos e serviços financeiros nos Estados Unidos. As informações incluem data de recebimento, tipo de produto, problema relatado, entre outros campos relevantes. O conjunto está disponível em formato CSV e foi extraído da fonte oficial: Consumer Complaint Database - CFPB. A tabela abaixo apresenta o dicionário de dados com a descrição e o tipo de cada campo presente no dataset.

Campo Descrição Tipo dos dados
Date received A data em que o CFPB recebeu a reclamação datetime
Product O tipo de produto identificado pelo consumidor na reclamação string
Sub-product O tipo de subproduto identificado pelo consumidor na reclamação string
Issue O problema identificado pelo consumidor na reclamação string
Sub-issue O subproblema identificado pelo consumidor na reclamação string
Consumer complaint narrative Descrição submetida pelo consumidor sobre o que ocorreu string
Company public response Resposta pública opcional da empresa à reclamação string
Company Empresa mencionada na reclamação string
State Estado informado no endereço do consumidor string
ZIP code CEP informado pelo consumidor string
Tags Dados que facilitam busca e filtragem das reclamações string
Consumer consent provided? Indica se o consumidor consentiu com a publicação da narrativa string
Submitted via Meio pelo qual a reclamação foi enviada ao CFPB string
Date sent to company Data em que o CFPB enviou a reclamação à empresa datetime
Company response to consumer Como a empresa respondeu à reclamação string
Timely response? Se a empresa respondeu em tempo hábil boolean
Consumer disputed? Se o consumidor contestou a resposta da empresa boolean | null
Complaint ID Número de identificação único da reclamação integer

Pacotes Requeridos

Nesta análise, os seguintes pacotes são utilizados para nos auxiliar desde a importação até a visualização dos dados.

library(tidyverse) 
library(lubridate) 
library(janitor)   
library(knitr)     
library(scales)    
library(glue)      
library(DT)
library(plotly)
Pacotes Utilizados na Análise
Pacote Finalidade
tidyverse Ecossistema principal para manipulação (dplyr), visualização (ggplot2) e outras tarefas de dados.
lubridate Ferramentas para facilitar o trabalho com datas e extrair componentes como ano e mês.
janitor Funções para limpar nomes de colunas e criar tabelas de frequência.
knitr Ferramentas para criar tabelas bem formatadas e renderizar o relatório.
scales Utilitários para formatar eixos e números em gráficos (ex: separador de milhar).
glue Facilita a formatação e concatenação de textos com variáveis (usado no subtítulo dinâmico).
DT Cria tabelas de dados interativas com paginação e busca.
plotly Converte gráficos estáticos do ggplot2 em visualizações interativas com tooltips e zoom.

Preparação dos Dados

Nesta seção, realizamos a importação, limpeza e transformação do conjunto de dados de reclamações do CFPB. O objetivo é preparar os dados para a análise exploratória, garantindo que eles estejam consistentes, livres de informações irrelevantes e em um formato adequado para manipulação e visualização.

Importação e Limpeza Inicial

Importando o dataset:

Iniciamos carregando os dados e aplicando limpezas essenciais: padronizamos os nomes das colunas para facilitar o uso, filtramos o período para os últimos 2 anos para focar em tendências recentes e removemos colunas e registros desnecessários ou incompletos para nossa análise.

# Carregar, limpar nomes, converter datas e filtrar período de 2 anos
dados <- read_csv("complaints.csv") %>%
  janitor::clean_names() %>%
  mutate(date_received = ymd(date_received)) %>%
  filter(date_received >= as.Date("2023-01-01"))

Verificando a quantidade inicial de linhas e colunas:

Antes de iniciar a limpeza dos dados, é importante entender o tamanho original do conjunto de dados. Isso inclui o número total de linhas (reclamações) e o número de variáveis disponíveis.

cat("O dataset original contém", nrow(dados), "linhas e", ncol(dados), "colunas.\n")
## O dataset original contém 6091463 linhas e 18 colunas.

Essa informação nos dá uma noção da dimensão inicial do dataset antes de aplicar filtros ou exclusões.

Verificando quantidade de valores ausentes (NAs) por variável:

Outro passo essencial é verificar a quantidade de valores ausentes em cada variável. Isso ajuda a decidir quais colunas podemos utilizar ou se precisamos aplicar alguma técnica de imputação ou exclusão.

dados %>%
  summarise(across(everything(), ~ sum(is.na(.)))) %>%
  pivot_longer(cols = everything(), names_to = "Variável", values_to = "Qtd_Ausentes") %>%
  mutate(
    Total_Registros = nrow(dados),
    Percentual_Ausente = round((Qtd_Ausentes / Total_Registros) * 100, 2)
  ) %>%
  arrange(desc(Qtd_Ausentes)) %>%
  kable(
    col.names = c("Variável", "Qtd. Ausentes", "Total de Registros", "% Ausente"),
    caption = "Quantidade de valores ausentes por variável antes da limpeza"
  )
Quantidade de valores ausentes por variável antes da limpeza
Variável Qtd. Ausentes Total de Registros % Ausente
tags 5832232 6091463 95.74
consumer_complaint_narrative 4387819 6091463 72.03
company_public_response 2874326 6091463 47.19
consumer_consent_provided 798375 6091463 13.11
sub_issue 151687 6091463 2.49
state 13749 6091463 0.23
zip_code 115 6091463 0.00
company_response_to_consumer 18 6091463 0.00
issue 6 6091463 0.00
sub_product 5 6091463 0.00
date_received 0 6091463 0.00
product 0 6091463 0.00
company 0 6091463 0.00
submitted_via 0 6091463 0.00
date_sent_to_company 0 6091463 0.00
timely_response 0 6091463 0.00
consumer_disputed 0 6091463 0.00
complaint_id 0 6091463 0.00

Analisando a tabela, podemos ver quais variáveis têm altos níveis de ausência de dados. Variáveis com muitos NAs, como consumer_complaint_narrative, podem ser descartadas caso não sejam essenciais para a análise.

Visualizando os produtos únicos antes da transformação:

Como o foco deste projeto é a análise por produto, é fundamental visualizar os valores únicos que existem na coluna product antes de qualquer transformação ou categorização.

dados %>%
  distinct(product) %>%
  arrange(product) %>%
  head(20) %>%
  kable(caption = "Exemplo de Produtos Únicos Antes da Padronização (Top 20)")
Exemplo de Produtos Únicos Antes da Padronização (Top 20)
product
Checking or savings account
Credit card
Credit card or prepaid card
Credit reporting or other personal consumer reports
Credit reporting, credit repair services, or other personal consumer reports
Debt collection
Debt or credit management
Money transfer, virtual currency, or money service
Mortgage
Payday loan, title loan, or personal loan
Payday loan, title loan, personal loan, or advance loan
Prepaid card
Student loan
Vehicle loan or lease

Essa listagem ajuda a entender a diversidade e a granularidade das categorias originais de produtos. Observa-se, por exemplo, que algumas categorias têm nomes muito longos ou semelhantes, o que justifica a criação de categorias agrupadas posteriormente.

Visualizando as respostas da empresa ao consumidor:

dados %>%
  distinct(company_response_to_consumer) %>%
  arrange(company_response_to_consumer) %>%
  kable(caption = "Valores únicos da variável 'company_response_to_consumer'")
Valores únicos da variável ‘company_response_to_consumer’
company_response_to_consumer
Closed with explanation
Closed with monetary relief
Closed with non-monetary relief
In progress
Untimely response
NA

Limpeza básica: Removendo colunas irrelevantes e NAs em produto

Agora removemos colunas que não são úteis para nossa análise exploratória de produtos, como códigos postais ou consentimentos, e também eliminamos registros que não têm informação de produto.

dados_limpos <- dados %>%
  select(
    date_received, product, sub_product, issue, company,
    company_response_to_consumer, timely_response, consumer_disputed
  ) %>%
  filter(!is.na(product) & product != "") %>%
  mutate(date_received = ymd(date_received))

Com essa etapa, garantimos que o dataset final só contenha informações relevantes ao nosso objetivo e que todos os registros tenham pelo menos o campo de produto preenchido.

Criação de Novas Variáveis

Para permitir análises temporais, criamos novas variáveis a partir da data, como ano, mês e dia da semana. Isso nos permitirá investigar padrões sazonais.

dados_limpos <- dados_limpos %>%
  mutate(
    ano_reclamacao = year(date_received),
    mes_reclamacao = month(date_received, label = TRUE, abbr = FALSE),
    dia_semana_reclamacao = wday(date_received, label = TRUE, abbr = FALSE)
  )

# Mostra a estrutura final do dataset de forma condensada
glimpse(dados_limpos)
## Rows: 6,091,463
## Columns: 11
## $ date_received                <date> 2025-05-31, 2025-05-31, 2025-05-31, 2025…
## $ product                      <chr> "Credit reporting or other personal consu…
## $ sub_product                  <chr> "Credit reporting", "Credit reporting", "…
## $ issue                        <chr> "Improper use of your report", "Incorrect…
## $ company                      <chr> "TRANSUNION INTERMEDIATE HOLDINGS, INC.",…
## $ company_response_to_consumer <chr> "In progress", "In progress", "In progres…
## $ timely_response              <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Yes",…
## $ consumer_disputed            <chr> "N/A", "N/A", "N/A", "N/A", "N/A", "N/A",…
## $ ano_reclamacao               <dbl> 2025, 2025, 2025, 2025, 2025, 2025, 2025,…
## $ mes_reclamacao               <ord> maio, maio, maio, maio, maio, maio, maio,…
## $ dia_semana_reclamacao        <ord> sábado, sábado, sábado, sábado, domingo, …

Com essas novas variáveis, podemos analisar a distribuição das reclamações por períodos temporais, como tendência mensal ou sazonalidade semanal.

Criação da coluna de categoria agrupada de produtos (Categoria_Produto):

Como algumas categorias de produto no dataset original são muito específicas ou têm nomes longos, criamos uma nova coluna chamada categoria_produto, que agrupa os produtos em categorias macro, mantendo a coluna original intacta.

dados_limpos <- dados_limpos %>%
  mutate(categoria_produto = case_when(
    str_detect(product, regex("credit card|prepaid card", ignore_case = TRUE)) ~ "Cartões",
    str_detect(product, regex("mortgage|home equity|reverse mortgage", ignore_case = TRUE)) ~ "Empréstimos Imobiliários",
    str_detect(product, regex("student loan", ignore_case = TRUE)) ~ "Empréstimos Estudantis",
    str_detect(product, regex("vehicle loan|lease", ignore_case = TRUE)) ~ "Financiamento de Veículos",
    str_detect(product, regex("payday loan|title loan|advance loan|personal loan", ignore_case = TRUE)) ~ "Empréstimos Pessoais",
    str_detect(product, regex("checking|savings account", ignore_case = TRUE)) ~ "Contas Bancárias",
    str_detect(product, regex("money transfer|virtual currency|money service", ignore_case = TRUE)) ~ "Transferências e Serviços Financeiros",
    str_detect(product, regex("credit reporting|credit repair|consumer reports", ignore_case = TRUE)) ~ "Relatórios de Crédito",
    str_detect(product, regex("debt collection", ignore_case = TRUE)) ~ "Cobrança de Dívidas",
    str_detect(product, regex("debt or credit management", ignore_case = TRUE)) ~ "Gerenciamento de Dívidas",
    TRUE ~ "Outros"
  ))

Com essa nova variável, será possível criar visualizações mais simples e focadas, agrupando reclamações por grandes grupos de produtos, sem perder o detalhamento da variável original product.

Verificando a distribuição das categorias agrupadas:

dados_limpos %>%
  count(categoria_produto, sort = TRUE) %>%
  kable(
    col.names = c("Categoria de Produto", "Número de Reclamações"),
    caption = "Distribuição de Reclamações por Categoria Agrupada de Produto"
  )
Distribuição de Reclamações por Categoria Agrupada de Produto
Categoria de Produto Número de Reclamações
Relatórios de Crédito 5207394
Cobrança de Dívidas 323521
Cartões 178774
Contas Bancárias 140183
Transferências e Serviços Financeiros 93765
Empréstimos Imobiliários 53096
Empréstimos Estudantis 36200
Financiamento de Veículos 33220
Empréstimos Pessoais 20467
Gerenciamento de Dívidas 4843

Essa tabela confirma que a maior parte das reclamações se concentra em algumas poucas categorias-chave, o que será explorado nas análises posteriores.

Criando a coluna Reposta da empresa:

dados_limpos <- dados_limpos %>%
  mutate(tipo_resposta_empresa = case_when(
    company_response_to_consumer == "Closed with explanation" ~ "Fechado com explicação",
    company_response_to_consumer == "Closed with monetary relief" ~ "Fechado com compensação monetária",
    company_response_to_consumer == "Closed with non-monetary relief" ~ "Fechado com compensação não monetária",
    company_response_to_consumer == "In progress" ~ "Em andamento",
    company_response_to_consumer == "Untimely response" ~ "Resposta fora do prazo",
    TRUE ~ "Não informado"
  ))

Criação da variável com as 5 categorias com mais reclamações:

top_5_categorias <- dados_limpos %>%
  count(categoria_produto) %>%
  slice_max(n, n = 5) %>%
  pull(categoria_produto)

Estrutura Final do Dataset:

Por fim, verificamos a estrutura do dataset final, para garantir que todas as variáveis necessárias estão presentes e prontas para análise.

glimpse(dados_limpos)
## Rows: 6,091,463
## Columns: 13
## $ date_received                <date> 2025-05-31, 2025-05-31, 2025-05-31, 2025…
## $ product                      <chr> "Credit reporting or other personal consu…
## $ sub_product                  <chr> "Credit reporting", "Credit reporting", "…
## $ issue                        <chr> "Improper use of your report", "Incorrect…
## $ company                      <chr> "TRANSUNION INTERMEDIATE HOLDINGS, INC.",…
## $ company_response_to_consumer <chr> "In progress", "In progress", "In progres…
## $ timely_response              <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Yes",…
## $ consumer_disputed            <chr> "N/A", "N/A", "N/A", "N/A", "N/A", "N/A",…
## $ ano_reclamacao               <dbl> 2025, 2025, 2025, 2025, 2025, 2025, 2025,…
## $ mes_reclamacao               <ord> maio, maio, maio, maio, maio, maio, maio,…
## $ dia_semana_reclamacao        <ord> sábado, sábado, sábado, sábado, domingo, …
## $ categoria_produto            <chr> "Relatórios de Crédito", "Relatórios de C…
## $ tipo_resposta_empresa        <chr> "Em andamento", "Em andamento", "Em andam…

Com isso, concluímos a etapa de limpeza e preparação dos dados, assegurando que o dataset está devidamente tratado para a análise exploratória focada nos produtos.

# Comando para verificar a data mais recente no dataset
cat("A data mais recente na base de dados é:", 
    format(max(dados_limpos$date_received), "%d/%m/%Y"), 
    "\n")
## A data mais recente na base de dados é: 02/06/2025

Análise Exploratória dos Dados

Com os dados preparados, investigamos os padrões das reclamações com foco no Produto.

Dataframe

Além das visualizações gráficas, a tabela abaixo permite a exploração interativa das reclamações filtrando por produto, empresa e tipo de problema relatado.

dados_limpos %>%
  slice_head(n = 500) %>%
  select(date_received, product, categoria_produto, company, issue, company_response_to_consumer) %>%
  datatable(
    options = list(pageLength = 10, autoWidth = TRUE),
    caption = "Tabela Interativa: Reclamações por Produto (Limite de 500 linhas)"
  )

Quais produtos lideram as queixas?

Como ponto de partida da análise, buscamos identificar quais categorias de produtos financeiros concentram o maior volume absoluto de reclamações por parte dos consumidores. Esse mapeamento inicial é fundamental para revelar os principais focos de insatisfação no setor e orientar as etapas seguintes da investigação.

data_fim <- max(dados_limpos$date_received)
subtitulo_texto <- glue::glue("Período: 01/01/2023 a {format(data_fim, '%d/%m/%Y')}")

top_10_produtos <- dados_limpos %>%
  count(categoria_produto, sort = TRUE) %>%
  slice_max(n, n = 10)

grafico_interativo <- ggplot(top_10_produtos, aes(
    x = fct_reorder(categoria_produto, n), 
    y = n,
    text = paste("Produto:", categoria_produto, "<br>Reclamações:", comma(n, big.mark = "."))
  )) +
  geom_col(fill = "#1f77b4", width = 0.5) +
  coord_flip() +
  scale_y_continuous(
    expand = expansion(mult = c(0, 0.35)),
    labels = comma_format(big.mark = ".", decimal.mark = ",")
  ) +
  labs(
    title = "Top 10 Produtos com Mais Reclamações",
    subtitle = subtitulo_texto,
    x = "Categoria de Produto",
    y = "Número de Reclamações"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    plot.subtitle = element_text(size = 11, hjust = 0.5),
    plot.margin = margin(t = 20, r = 30, b = 30, l = 20),
    axis.text.y = element_text(size = 10)
  )

ggplotly(grafico_interativo, tooltip = "text") %>%
  layout(
    title = list(
      text = paste0("Top 10 Produtos com Mais Reclamações",
                    "<br>", # Isso cria uma quebra de linha
                    "<sup>", # Tag HTML para deixar o texto um pouco menor
                    subtitulo_texto,
                    "</sup>" # Fecha a tag
      ),
      x = 0.5 # Centraliza o título
    )
  )

A análise do ranking de reclamações por produtos financeiros revela um cenário de profunda desigualdade na distribuição das queixas, direcionando o foco central de toda a investigação. Como evidencia o gráfico, a categoria ‘Relatórios de Crédito’ lidera com um volume impressionante de aproximadamente 5,2 milhões de reclamações, número mais de quinze vezes superior ao registrado pela segunda categoria mais reclamada. Essa concentração extrema de insatisfação indica que o problema não está disperso entre os diferentes produtos financeiros, mas sim fortemente concentrado e de grande magnitude. Diante desse quadro, a análise se aprofunda para compreender as causas estruturais e a dinâmica que sustentam esse fenômeno.

Evolução Temporal dos Principais Produtos

Após identificar “Relatórios de Crédito” como o principal problema, a próxima etapa foi analisar sua tendência temporal. O objetivo era entender se este é um problema crônico e estável ou uma crise recente e crescente.

top_3_produtos_nomes <- top_10_produtos %>% head(3) %>% pull(categoria_produto)

ano_mais_recente <- year(max(dados_limpos$date_received))
n_meses_ultimo_ano <- month(max(dados_limpos$date_received))

evolucao_media_mensal <- dados_limpos %>%
  filter(categoria_produto %in% top_3_produtos_nomes) %>%
  count(ano_reclamacao, categoria_produto) %>%
  mutate(
    n_meses = if_else(ano_reclamacao == ano_mais_recente, 
                      n_meses_ultimo_ano, 
                      12),
    media_mensal = n / n_meses
  )

grafico_evolucao_base <- ggplot(evolucao_media_mensal, 
  aes(
    x = ano_reclamacao, 
    y = media_mensal,
    color = categoria_produto, 
    group = categoria_produto,
    text = paste0(
      "<b>", categoria_produto, "</b><br>",
      "Ano: ", ano_reclamacao, "<br>",
      "Média Mensal de Reclamações: ", round(media_mensal, 1)
    )
  )) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 3) +
  scale_y_continuous(labels = label_comma(big.mark = ".")) +
  scale_x_continuous(breaks = unique(evolucao_media_mensal$ano_reclamacao)) +
  labs(
    title = "Média Mensal de Reclamações - Top 3 Produtos",
    subtitle = "Análise normalizada para uma comparação justa entre os anos",
    x = "Ano",
    y = "Média Mensal de Reclamações",
    color = "Categoria de Produto"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    plot.subtitle = element_text(size = 11, hjust = 0.5),
    legend.position = "bottom"
  )

ggplotly(grafico_evolucao_base, tooltip = "text")

A análise da evolução temporal, agora normalizada pela média mensal de reclamações para uma comparação justa, revela um cenário alarmante. Longe de ser um problema estável, a taxa de queixas para ‘Relatórios de Crédito’ demonstra uma forte e contínua aceleração ano após ano.

A média mensal de reclamações saltou de aproximadamente 87.241/mês para 187.386/mês, e atingiu um novo pico de aproximadamente 298.664/mês. Isso indica que o problema não é apenas crônico e de grande volume, mas também está piorando em frequência, tornando-se uma questão cada vez mais crítica para consumidores e reguladores no período analisado.

Problemas mais frequentes em Relatórios de Crédito

Com a confirmação de que o problema com ‘Relatórios de Crédito’ é grande e persistente, partimos para entender as causas principais. Este gráfico mostra quais são os problemas específicos mais citados pelos consumidores dentro dessa categoria.

top_issues <- dados_limpos %>%
  filter(product == "Credit reporting, credit repair services, or other personal consumer reports") %>%
  count(issue, sort = TRUE) %>%
  head(5) %>%
  mutate(issue_pt = case_when(
    issue == "Incorrect information on your report" ~ "Informação incorreta no relatório",
    issue == "Problem with a credit reporting company's investigation into an existing problem" ~ "Problema com investigação de disputa",
    issue == "Improper use of your report" ~ "Uso indevido do relatório",
    issue == "Unable to get your credit report or credit score" ~ "Não conseguiu obter relatório ou score",
    issue == "Problem with fraud alerts or security freezes" ~ "Problema com alertas de fraude ou bloqueios",
    TRUE ~ issue
  ))

cores <- c("#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd")
grafico_vertical_base <- ggplot(top_issues, 
  aes(
    x = fct_reorder(issue_pt, n, .desc=T), 
    y = n,
    text = paste0(
      "<b>", issue_pt, "</b><br>",
      "Nº de Reclamações: ", comma(n, big.mark = ".")
    )
  )) +
  geom_col(fill = cores, width = 0.7) +
  scale_x_discrete(labels = label_wrap(20)) + 
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(
    title = "Top 5 Problemas em Relatórios de Crédito",
    x = "Tipo de Problema",
    y = "Número de Reclamações"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    axis.text.x = element_text(size = 10, lineheight = 1.1),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.y = element_blank()
  )

grafico_interativo_final <- ggplotly(grafico_vertical_base, tooltip = "text") %>%
  config(
    displaylogo = FALSE,
    modeBarButtonsToRemove = c('select2d', 'lasso2d', 'autoScale2d', 'toggleSpikelines')
  )

grafico_interativo_final

Ao aprofundar a análise no produto mais reclamado, o gráfico revela que a insatisfação dos consumidores se concentra em um trio de problemas principais com volumes de queixa muito próximos.

O problema de ‘Informação incorreta no relatório’ lidera com 242.156 reclamações, mas é seguido de perto por ‘Uso indevido do relatório’ com 215.052 e ‘Problema com investigação de disputa’ com 179.080.

Essa distribuição demonstra que a crise na categoria de relatórios de crédito se expandiu, abrangendo não apenas a qualidade dos dados (informação incorreta), mas também a segurança e privacidade das informações (uso indevido) e a eficiência dos processos de correção (problemas na investigação).

Distribuição de Tipos de Resposta por Produto

Depois de identificar os principais problemas, o próximo passo foi entender como as empresas estão respondendo a essas reclamações. Este gráfico mostra os tipos de resposta mais comuns nas principais categorias de produtos, ajudando a revelar os padrões de atendimento e resolução.

grafico_resposta_produto <- dados_limpos %>%
  filter(!is.na(tipo_resposta_empresa)) %>%
  filter(categoria_produto %in% top_5_categorias) %>%
  count(categoria_produto, tipo_resposta_empresa) %>%
  ggplot(aes(x = fct_reorder(categoria_produto, n, sum), y = n, fill = tipo_resposta_empresa)) +
  geom_col(position = position_dodge(width = 0.6), width = 0.5) +
  coord_flip() +
  scale_y_continuous(
    expand = expansion(mult = c(0, 0.1)),
    labels = label_comma(big.mark = ".")
  ) +
  labs(
    title = "Tipos de Resposta das Empresas - Top 5 Categorias",
    x = "Categoria de Produto",
    y = "Número de Reclamações",
    fill = "Resposta da Empresa"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
    legend.position = "bottom",
    legend.box = "vertical",
    legend.text = element_text(size = 9, lineheight = 1.1),
    legend.title = element_text(size = 10, face = "bold"),
    axis.text.y = element_text(size = 9),
    plot.margin = margin(t = 10, r = 20, b = 10, l = 10)
  ) +
  guides(fill = guide_legend(ncol = 2))

ggplotly(grafico_resposta_produto, width = 950, height = 500)

Ao observar os tipos de resposta para “Relatórios de Crédito”, o gráfico mostra que a conclusão mais frequente para as reclamações é o status “Fechado com explicação”. Em segundo lugar, aparece a resposta “Fechado com compensação não monetária” e, em seguida, “Fechado com compensação monetária”.

Visão mais detalhada:

Para obter a visão mais detalhada possível, nossa análise final cruza os problemas mais críticos com os tipos de resposta específicos para cada um. O objetivo é descobrir se a forma como as empresas respondem varia dependendo da natureza exata da queixa.

top_issues_nomes <- top_issues$issue  

cruzamento_issue_resposta <- dados_limpos %>%
  filter(product == "Credit reporting, credit repair services, or other personal consumer reports") %>%
  filter(issue %in% top_issues_nomes) %>%
  mutate(issue_pt = case_when(
    issue == "Incorrect information on your report" ~ "Informação incorreta no relatório",
    issue == "Problem with a credit reporting company's investigation into an existing problem" ~ "Problema com investigação de disputa",
    issue == "Improper use of your report" ~ "Uso indevido do relatório",
    issue == "Unable to get your credit report or credit score" ~ "Não conseguiu obter relatório ou score",
    issue == "Problem with fraud alerts or security freezes" ~ "Problema com alertas de fraude ou bloqueios",
    TRUE ~ issue
  )) %>%
  count(issue_pt, tipo_resposta_empresa, sort = TRUE)

grafico_cruzamento_issue_resposta <- ggplot(cruzamento_issue_resposta, aes(x = fct_reorder(issue_pt, n, sum), y = n, fill = tipo_resposta_empresa)) +
  geom_col(position = "dodge", width = 0.7) +
  coord_flip() +
  labs(
    title = "Respostas das Empresas por Problema - Relatórios de Crédito",
    subtitle = "Cruzamento dos 5 principais problemas x tipos de resposta",
    x = "Problema Específico",
    y = "Número de Reclamações",
    fill = "Resposta da Empresa"
  ) +
  scale_y_continuous(labels = label_comma(big.mark = ".", decimal.mark = ",")) +
  theme_minimal(base_size = 12) +
  theme(
    legend.position = "bottom",
    legend.title = element_text(face = "bold", size = 11),
    legend.text = element_text(size = 10, lineheight = 1.2),
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    plot.subtitle = element_text(size = 11, hjust = 0.5),
    plot.margin = margin(t = 30, r = 40, b = 30, l = 20),
    axis.text.y = element_text(size = 10, lineheight = 1.2)
  )

ggplotly(grafico_cruzamento_issue_resposta, width = 900)

Uma análise mais detalhada deste gráfico revela uma descoberta importante. Para as queixas mais graves, como “Informação incorreta”, a resolução mais comum não é apenas uma “explicação”, mas sim uma “compensação não monetária”, que provavelmente significa que os dados no relatório foram corrigidos. Isso sugere que o problema principal da crise não é a recusa em corrigir os erros, mas sim uma falha no processo de comunicação e na eficiência da investigação. Essa falha continua causando frustração e um grande número de reclamações.

Conclusões

Este projeto teve como objetivo analisar os padrões de reclamações dos consumidores no setor financeiro. A análise dos dados do CFPB mostrou que a maior parte das reclamações está concentrada na categoria “Relatórios de Crédito”. Essa categoria tem mais de 15 vezes o número de queixas das outras e cresceu muito em 2024, mantendo um nível alto nos dados parciais de 2025. As causas principais apontam para problemas na qualidade dos dados, na eficiência das investigações e na segurança da informação. Mesmo que algumas correções sejam feitas, os consumidores ainda acham o processo insatisfatório.

Esses resultados são importantes para várias pessoas. Para os consumidores, é um alerta para que fiquem atentos aos seus relatórios de crédito. Para as empresas, mostra que é preciso melhorar os processos de disputa e o cuidado com os dados. Para os órgãos reguladores, indica que pode ser necessário aumentar a fiscalização sobre as agências de crédito para proteger os consumidores.

Embora essa análise seja apenas uma descrição dos dados, ela abre caminho para estudos futuros. Sugere-se acompanhar os dados mês a mês para entender melhor a crise, investigar empresas específicas para ver se o problema está concentrado em algumas delas e usar técnicas de Processamento de Linguagem Natural nas reclamações para entender melhor o que os consumidores estão dizendo.

Referências

Bastani, Kaveh, Hamed Namavari, and Jeffrey Shaffer. 2019. “Latent Dirichlet Allocation (LDA) for Topic Modeling of the CFPB Consumer Complaints.” Expert Systems with Applications 127: 256–71.
Jou, Jeffrey, Anya Kleymenova, Andrea Passalacqua, László Sándor, and Rajesh Vijayaraghavan. 2024. “Disciplining Banks Through Disclosure: Evidence from CFPB Consumer Complaints.” Available at SSRN.
Vaishnav, Dhwani, Manimozhi Neethinayagam, Akanksha S Khaire, Mansi Vivekanand Dhoke, and Jongwook Woo. 2023. “CFPB Consumer Complaints Analysis Using Hadoop.” arXiv Preprint arXiv:2310.06076.