Modelo preditivo de classificação de empresas baixadas por porte - 2014 a 2024 - Dados Receita Federal do Brasil

Carregando o banco de dados

dados_parquet_BRF = arrow::read_parquet("BRF_FINAL 1 (1).parquet")
dados_parquet_BRF_filtrado = dados_parquet_BRF %>%  select ( MATRIZ,
                            NOME_F,
                            SIT_CAD,
                            DATA_SIT_CAD,
                            MOT_SIT_CAD,
                            DATA_INICIO_ATV,
                            CNAE_PRINC,
                            CNAE_SEC,
                            MUNIC,
                            SIT_ESP,
                            DATA_SIT_ESP,
                            CNPJ,
                            RAZAO_SOCIAL,
                            NATUREZA_JURIDICA,
                            CAPITAL_SOCIAL,
                            PORTE,
                            OP_SIMPLES,
                            DT_OP_SIMPLES,
                            OP_MEI,
                            DT_OP_MEI,
                            DT_EX_SIMPLES,
                            DT_EX_MEI,
                            code_muni,
                            PUBLICO_SEBRAE
                            )

#dados_parquet_SOCIOS_filtrado = dados_parquet_SOCIOS %>% select( CNPJ_BAS,
                                                              #IDENTIFICADOR_DE_SÓCIO,
                                                           #DATA_DE_ENTRADA_SOCIEDADE)

#transformando o campo CNPJ de 8 dígitos
dados_parquet_BRF_filtrado$CNPJ_BAS = str_sub(dados_parquet_BRF_filtrado$CNPJ,1,8) 

Transformação das variáveis de data e rótulos

dados_parquet_BRF_filtrado$ANO_DATA_INICIO_ATV = Year(dados_parquet_BRF_filtrado$DATA_INICIO_ATV)

dados_parquet_BRF_filtrado$MES_DATA_INICIO_ATV = Month(dados_parquet_BRF_filtrado$DATA_INICIO_ATV)

dados_parquet_BRF_filtrado$DIA_DATA_INICIO_ATV = day(dados_parquet_BRF_filtrado$DATA_INICIO_ATV)

dados_parquet_BRF_filtrado = dados_parquet_BRF_filtrado %>% mutate(SIT_CAD_ROTULADA = case_when( 
  
     SIT_CAD == 1 ~ "Nula",
                                                                    SIT_CAD == 2 ~ "Ativa",
                                                                    SIT_CAD == 3 ~ "Suspensa",
                                                                    SIT_CAD == 4 ~ "Inapta",
                                                                    SIT_CAD == 8 ~ "Baixada"
))

dados_parquet_BRF_filtrado = dados_parquet_BRF_filtrado %>% mutate(MATRIZ_ROTULADA = case_when( 
  
     MATRIZ == 1 ~ "Matriz",
                                                                           MATRIZ == 2 ~ "Filial"
                                                                  
))

dados_parquet_BRF_filtrado = dados_parquet_BRF_filtrado %>% mutate(OP_SIMPLES_ROTULADA = case_when( 
  
     OP_SIMPLES == 0 ~ "Não",
                                                                         OP_SIMPLES == 1 ~ "Sim"
     
                                                                  
))

dados_parquet_BRF_filtrado = dados_parquet_BRF_filtrado %>% mutate(OP_MEI_ROTULADA = case_when( 
  
     OP_MEI == 0 ~ "Não",
                                                                                   OP_MEI == 1 ~ "Sim"
     
                                                                  
))

dados_parquet_BRF_filtrado = dados_parquet_BRF_filtrado %>% mutate(PUBLICO_SEBRAE_ROTULADA = case_when( 
  
     PUBLICO_SEBRAE == 0 ~ "Não",
                                                                                   PUBLICO_SEBRAE == 1 ~ "Sim"
     
                                                                  
))

dados_parquet_BRF_filtrado = dados_parquet_BRF_filtrado %>% mutate(PORTE_ROTULADA = case_when( 
  
     PORTE == 1 ~ "MEI",
                                                                           
     PORTE == 2 ~ "ME",
     
     PORTE == 3 ~ "EPP",
     
     PORTE == 4 ~ "Demais"
     
                                                                  
))


dados_parquet_BRF_filtrado$CAPITAL_SOCIAL_NUMERO = as.numeric(gsub(",",".",dados_parquet_BRF_filtrado$CAPITAL_SOCIAL))

#PEGAR AS CNAES PRINCIPAIS E CLASSIFICAR 

dados_parquet_BRF_filtrado$CNAE_PRINC_2DIGITOS = as.numeric(str_sub(dados_parquet_BRF_filtrado$CNAE_PRINC,1,2)) 

dados_parquet_BRF_filtrado = dados_parquet_BRF_filtrado %>% mutate(CNAE_PRINC_2DIGITOS_ROTULADA = case_when( 
  
     (CNAE_PRINC_2DIGITOS >= 1 & CNAE_PRINC_2DIGITOS <= 3) ~ "Agricultura, pecuária, produção florestal, pesca e aqüicultura",
                                                                           
     (CNAE_PRINC_2DIGITOS >= 5 & CNAE_PRINC_2DIGITOS <= 9) ~ "Indústrias extrativas",
     
     (CNAE_PRINC_2DIGITOS >= 10 & CNAE_PRINC_2DIGITOS <= 33) ~ "Indústrias de transformação",
     
     CNAE_PRINC_2DIGITOS == 35 ~ "Eletricidade e gás",
      
     (CNAE_PRINC_2DIGITOS >= 36 & CNAE_PRINC_2DIGITOS <= 39) ~ "Água, esgoto, atividades de gestão de resíduos e descontaminação",
      
     (CNAE_PRINC_2DIGITOS >= 41 & CNAE_PRINC_2DIGITOS <= 43) ~ "Construção",
     
     (CNAE_PRINC_2DIGITOS >= 45 & CNAE_PRINC_2DIGITOS <= 47) ~ "Comércio, reparação de veículos automotores e motocicletas",
     
     (CNAE_PRINC_2DIGITOS >= 49 & CNAE_PRINC_2DIGITOS <= 53) ~ "Transporte, armazenagem e correio",
     
     (CNAE_PRINC_2DIGITOS >= 55 & CNAE_PRINC_2DIGITOS <= 56) ~ "Alojamento e alimentação",
     
     (CNAE_PRINC_2DIGITOS >= 58 & CNAE_PRINC_2DIGITOS <= 63) ~ "Informação e comunicação",
     
     (CNAE_PRINC_2DIGITOS >= 64 & CNAE_PRINC_2DIGITOS <= 66) ~ "Atividades financeiras, de seguros e serviços relacionados",
     
     CNAE_PRINC_2DIGITOS == 68  ~ "Atividades imobiliárias",
     
     (CNAE_PRINC_2DIGITOS >= 69 & CNAE_PRINC_2DIGITOS <= 75) ~  "Atividades profissionais, científicas e técnicas",
     
     (CNAE_PRINC_2DIGITOS >= 77 & CNAE_PRINC_2DIGITOS <= 82) ~  "Atividades administrativas e serviços complementares",
       
      CNAE_PRINC_2DIGITOS == 84 ~ "Administração pública, defesa e seguridade social",
      
      CNAE_PRINC_2DIGITOS == 85 ~ "Educação",
      
     (CNAE_PRINC_2DIGITOS >= 86 & CNAE_PRINC_2DIGITOS <= 88) ~ "Saúde humana e serviços sociais",
      
     (CNAE_PRINC_2DIGITOS >= 90 & CNAE_PRINC_2DIGITOS <= 93) ~ "Artes, cultura, esporte e recreação",
      
     (CNAE_PRINC_2DIGITOS >= 94 & CNAE_PRINC_2DIGITOS <= 96) ~ "Outras atividades de serviços",
      
     CNAE_PRINC_2DIGITOS == 97 ~ "Serviços domésticos", 
     
     CNAE_PRINC_2DIGITOS == 99 ~ "Organismos internacionais e outras instituições extraterritoriais"  
))


#natureza juridica

#CÓDIGO DA NATUREZA JURÍDICA
#2011: Empresa Pública
#2232: Sociedade Simples Pura
#2240: Sociedade Simples Limitada
#2305: Empresa Individual de Responsabilidade Limitada (EIRELI)
#3034: Serviço Notarial e Registral (Cartório)
#4014: Empresa Individual Imobiliária

Transformando para classe dicotômica

dados_parquet_BRF_filtrado_modelo = dados_parquet_BRF_filtrado %>% filter(MATRIZ==1 & 
         DATA_INICIO_ATV > "2014-01-01" &
         DATA_INICIO_ATV < "2024-08-10" & 
         PORTE_ROTULADA == "ME" ) %>% mutate(SIT_CAD_SIM_NAO = case_when( 
  
     SIT_CAD == 8  ~ "Sim",
                                                                                  TRUE ~ "Não"
                                                                  
), NATUREZA_JURIDICA = factor(NATUREZA_JURIDICA)
)

Separando em treino e teste

#selectionando treino e teste 80%,20%
data_split <- initial_split(dados_parquet_BRF_filtrado_modelo, 
                            prop = 0.8
                            )

train_data <- training(data_split)
test_data <- testing(data_split)

Contando os exemplos da classe no treino e teste

#Quantos exemplos de cada classe na variável resposta no treino?
round(prop.table(table(train_data$SIT_CAD_SIM_NAO)),4)*100
## 
##  Não  Sim 
## 48.2 51.8
#Quantos exemplos de cada classe na variável no teste?
round(prop.table(table(test_data$SIT_CAD_SIM_NAO)),4)*100
## 
##   Não   Sim 
## 48.15 51.85
  • Podemos ver que a nossa variável target não sofre de um problema de desbalanceamento muito grande, o que pode facilitar a nossa abordagem de modelagem de classificação;

  • Para desenvolver o modelo, utlizaremos 3 variáveis explicativas, quais sejam:

    • O capital social da empresa (Valor investido ao abrir a empresa);

    • Os Cnaes principais de dois dígitos (Indicam a principal atividade principal da empresa);

    • Natureza jurídica da empresa (Suas diferentes classificações, por exemplo se é uma empresa pública, um serviço notarial, empresa individual de responsabilidade limitada (EIRELLI), etc…);

Criando o classificador da árvore de decisão

dt_model = decision_tree(tree_depth = 30) %>%
  set_engine("rpart") %>%
  set_mode("classification") #%>%
#translate()

Selecionando variáveis para compor o modelo

train_data_filter = train_data %>%  select(#MATRIZ,
                                #MOT_SIT_CAD,
                                CNAE_PRINC_2DIGITOS,
                                NATUREZA_JURIDICA,
                                #PORTE,
                                #PUBLICO_SEBRAE,
                                CAPITAL_SOCIAL_NUMERO,
                                SIT_CAD_SIM_NAO
                                )

Criando o modelo na base de treino

dt_fit <- dt_model %>% 
  fit(factor(SIT_CAD_SIM_NAO) ~ . -SIT_CAD_SIM_NAO,
      data = train_data_filter)

Resumo do modelo

dt_fit 
## parsnip model object
## 
## n= 161247 
## 
## node), split, n, loss, yval, (yprob)
##       * denotes terminal node
## 
##  1) root 161247 77727 Sim (0.4820369 0.5179631)  
##    2) NATUREZA_JURIDICA=2062,2070,2232,2240,2321,2348 43044  4855 Não (0.8872084 0.1127916) *
##    3) NATUREZA_JURIDICA=2135,2305,2313 118203 39538 Sim (0.3344924 0.6655076)  
##      6) CAPITAL_SOCIAL_NUMERO>=9999.995 42899 19121 Não (0.5542787 0.4457213)  
##       12) NATUREZA_JURIDICA=2135 42042 18264 Não (0.5655773 0.4344227)  
##         24) CAPITAL_SOCIAL_NUMERO>=19934.45 25290  9319 Não (0.6315144 0.3684856) *
##         25) CAPITAL_SOCIAL_NUMERO< 19934.45 16752  7807 Sim (0.4660339 0.5339661) *
##       13) NATUREZA_JURIDICA=2305,2313 857     0 Sim (0.0000000 1.0000000) *
##      7) CAPITAL_SOCIAL_NUMERO< 9999.995 75304 15760 Sim (0.2092850 0.7907150) *
#%>% tidy()

Desenho da árvore

#plot(as.party(dt_fit$fit),
#     main = "Decision Tree Model",
#     cex = 0.8,  # Adjust font size
#     col = "blue")
fancyRpartPlot(dt_fit$fit,main = "Árvore de decisão")

Importância das variáveis

vip(dt_fit, type = "importance")

test_data_filter = test_data %>%  select(#MATRIZ,
                                #MOT_SIT_CAD,
                                CNAE_PRINC_2DIGITOS,
                                NATUREZA_JURIDICA,
                                #PORTE,
                                #PUBLICO_SEBRAE,
                                CAPITAL_SOCIAL_NUMERO,
                                SIT_CAD_SIM_NAO
                                )

Predizer categorias da target

class_preds <- predict(dt_fit, new_data = test_data_filter,
                       type = 'class')

Predizer probabilidades da target

prob_preds <- predict(dt_fit, new_data = test_data_filter, 
                      type = 'prob')

Juntando teste e resultados

model_results <- test_data %>% 
  select(SIT_CAD_SIM_NAO) %>% 
  bind_cols(class_preds, prob_preds)

Visualizando resultados em uma tabela

model_results %>%
  head()
## # A tibble: 6 × 4
##   SIT_CAD_SIM_NAO .pred_class .pred_Não .pred_Sim
##   <chr>           <fct>           <dbl>     <dbl>
## 1 Sim             Não             0.632     0.368
## 2 Sim             Não             0.887     0.113
## 3 Não             Não             0.887     0.113
## 4 Não             Não             0.632     0.368
## 5 Não             Não             0.632     0.368
## 6 Não             Sim             0.209     0.791

transformando em fator a classe

model_results$SIT_CAD_SIM_NAO = factor(model_results$SIT_CAD_SIM_NAO)

Criando a matriz de confusão

conf_mat(model_results, truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class)
##           Truth
## Prediction   Não   Sim
##        Não 13551  3580
##        Sim  5859 17322

calculando a acurácia

yardstick::accuracy(model_results, truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class)
## # A tibble: 1 × 3
##   .metric  .estimator .estimate
##   <chr>    <chr>          <dbl>
## 1 accuracy binary         0.766

calculando a sensibilidade

yardstick::sens(model_results, truth = SIT_CAD_SIM_NAO,
     estimate = .pred_class)
## # A tibble: 1 × 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 sens    binary         0.698

Calculando a especificidade

yardstick::spec(model_results, truth = SIT_CAD_SIM_NAO,
     estimate = .pred_class)
## # A tibble: 1 × 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 spec    binary         0.829

Customizando as métricas

resultados_metricas <- yardstick::metric_set(yardstick::accuracy, yardstick::sens, yardstick::spec)

Calculando metricas de forma customizada

resultados_metricas(model_results, 
                    truth = SIT_CAD_SIM_NAO,
                    estimate = .pred_class)
## # A tibble: 3 × 3
##   .metric  .estimator .estimate
##   <chr>    <chr>          <dbl>
## 1 accuracy binary         0.766
## 2 sens     binary         0.698
## 3 spec     binary         0.829

Criando a Matriz de confusão

conf_mat(model_results,
         truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class) %>% 
  summary()
## # A tibble: 13 × 3
##    .metric              .estimator .estimate
##    <chr>                <chr>          <dbl>
##  1 accuracy             binary         0.766
##  2 kap                  binary         0.529
##  3 sens                 binary         0.698
##  4 spec                 binary         0.829
##  5 ppv                  binary         0.791
##  6 npv                  binary         0.747
##  7 mcc                  binary         0.533
##  8 j_index              binary         0.527
##  9 bal_accuracy         binary         0.763
## 10 detection_prevalence binary         0.425
## 11 precision            binary         0.791
## 12 recall               binary         0.698
## 13 f_meas               binary         0.742

Plotando a matriz de confusão

conf_mat(model_results,
         truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class)  %>% 
  # criando o heat map
  autoplot(type = "heatmap")

Calculando métricas usando os limiares

threshold_df <- model_results %>% 
  roc_curve(truth = SIT_CAD_SIM_NAO, .pred_Não )

Visualizando os limiares

threshold_df %>%
  head()
## # A tibble: 6 × 3
##   .threshold specificity sensitivity
##        <dbl>       <dbl>       <dbl>
## 1   -Inf          0            1    
## 2      0          0            1    
## 3      0.209      0.0114       1    
## 4      0.466      0.718        0.797
## 5      0.632      0.829        0.698
## 6      0.887      0.941        0.489

Plotando a curva ROC

threshold_df %>% 
  autoplot()

Calculando a área embaixo da curva

roc_auc(model_results, truth = SIT_CAD_SIM_NAO, .pred_Não)
## # A tibble: 1 × 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 roc_auc binary         0.810

Criando o classificador dos Gradient boosting

gb_model = boost_tree(mode = "classification", trees = 100) %>%
  set_engine("xgboost") %>% #,seed = 63233 
  set_mode("classification") #%>%

Selecionando variáveis para compor o modelo

train_data_filter = train_data %>%  select(#MATRIZ,
                                #MOT_SIT_CAD,
                                CNAE_PRINC_2DIGITOS,
                                NATUREZA_JURIDICA,
                                #PORTE,
                                #PUBLICO_SEBRAE,
                                CAPITAL_SOCIAL_NUMERO,
                                SIT_CAD_SIM_NAO
                                )

Criando o modelo na base de treino

gb_fit <- gb_model %>% 
  fit(factor(SIT_CAD_SIM_NAO) ~ . -SIT_CAD_SIM_NAO,
      data = train_data_filter)

Resumo do modelo

#gb_fit %>% tidy()

Desenho das árvores

#

Importância das variáveis

vip(gb_fit, type = "gain")

test_data_filter = test_data %>%  select(#MATRIZ,
                                #MOT_SIT_CAD,
                                CNAE_PRINC_2DIGITOS,
                                NATUREZA_JURIDICA,
                                #PORTE,
                                #PUBLICO_SEBRAE,
                                CAPITAL_SOCIAL_NUMERO,
                                SIT_CAD_SIM_NAO
                                )

Predizer categorias da target

class_preds <- predict(gb_fit, new_data = test_data_filter,
                       type = 'class')

Predizer probabilidades da target

prob_preds <- predict(gb_fit, new_data = test_data_filter, 
                      type = 'prob')

Juntando teste e resultados

model_results <- test_data %>% 
  select(SIT_CAD_SIM_NAO) %>% 
  bind_cols(class_preds, prob_preds)

Visualizando resultados em uma tabela

model_results %>%
  head()
## # A tibble: 6 × 4
##   SIT_CAD_SIM_NAO .pred_class .pred_Não .pred_Sim
##   <chr>           <fct>           <dbl>     <dbl>
## 1 Sim             Não             0.736    0.264 
## 2 Sim             Não             0.904    0.0956
## 3 Não             Não             0.935    0.0649
## 4 Não             Não             0.659    0.341 
## 5 Não             Não             0.651    0.349 
## 6 Não             Sim             0.236    0.764

transformando em fator a classe

model_results$SIT_CAD_SIM_NAO = factor(model_results$SIT_CAD_SIM_NAO)

Criando a matriz de confusão

conf_mat(model_results, truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class)
##           Truth
## Prediction   Não   Sim
##        Não 15104  3855
##        Sim  4306 17047

calculando a acurácia

yardstick::accuracy(model_results, truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class)
## # A tibble: 1 × 3
##   .metric  .estimator .estimate
##   <chr>    <chr>          <dbl>
## 1 accuracy binary         0.798

calculando a sensibilidade

yardstick::sens(model_results, truth = SIT_CAD_SIM_NAO,
     estimate = .pred_class)
## # A tibble: 1 × 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 sens    binary         0.778

Calculando a especificidade

yardstick::spec(model_results, truth = SIT_CAD_SIM_NAO,
     estimate = .pred_class)
## # A tibble: 1 × 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 spec    binary         0.816

Customizando as métricas

resultados_metricas <- yardstick::metric_set(yardstick::accuracy, yardstick::sens, yardstick::spec)

Calculando metricas de forma customizada

resultados_metricas(model_results, 
                    truth = SIT_CAD_SIM_NAO,
                    estimate = .pred_class)
## # A tibble: 3 × 3
##   .metric  .estimator .estimate
##   <chr>    <chr>          <dbl>
## 1 accuracy binary         0.798
## 2 sens     binary         0.778
## 3 spec     binary         0.816

Criando a Matriz de confusão

conf_mat(model_results,
         truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class) %>% 
  summary()
## # A tibble: 13 × 3
##    .metric              .estimator .estimate
##    <chr>                <chr>          <dbl>
##  1 accuracy             binary         0.798
##  2 kap                  binary         0.594
##  3 sens                 binary         0.778
##  4 spec                 binary         0.816
##  5 ppv                  binary         0.797
##  6 npv                  binary         0.798
##  7 mcc                  binary         0.594
##  8 j_index              binary         0.594
##  9 bal_accuracy         binary         0.797
## 10 detection_prevalence binary         0.470
## 11 precision            binary         0.797
## 12 recall               binary         0.778
## 13 f_meas               binary         0.787

Plotando a matriz de confusão

conf_mat(model_results,
         truth = SIT_CAD_SIM_NAO,
         estimate = .pred_class)  %>% 
  # criando o heat map
  autoplot(type = "heatmap")

Calculando métricas usando os limiares

threshold_df <- model_results %>% 
  roc_curve(truth = SIT_CAD_SIM_NAO, .pred_Não )

Visualizando os limiares

threshold_df %>%
  head()
## # A tibble: 6 × 3
##    .threshold specificity sensitivity
##         <dbl>       <dbl>       <dbl>
## 1 -Inf          0                   1
## 2    0.000293   0                   1
## 3    0.000425   0.0000478           1
## 4    0.000432   0.0000957           1
## 5    0.000472   0.000144            1
## 6    0.000563   0.000191            1

Plotando a curva ROC

threshold_df %>% 
  autoplot()

Calculando a área embaixo da curva

roc_auc(model_results, truth = SIT_CAD_SIM_NAO, .pred_Não)
## # A tibble: 1 × 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 roc_auc binary         0.864

Tabela de comparação de métricas dos modelos de classificação

tabela_metricas = data.frame( Modelo= c("Árvore de decisão","Gradient boosting"),
Acuracia = c("0,766","0,800"), F1=c("0,740","0,789"),Precisão =c("0,795","0,802"),Revocação=c("0,693","0,776"),Espeficidade=c("0,833","0,822"),Roc_Auc=c("0,812","0,866"))

kableExtra::kable(tabela_metricas,align = "lccrr",caption = "Tabela de comparação de métricas dos modelos de classificação")
Tabela de comparação de métricas dos modelos de classificação
Modelo Acuracia F1 Precisão Revocação Espeficidade Roc_Auc
Árvore de decisão 0,766 0,740 0,795 0,693 0,833 0,812
Gradient boosting 0,800 0,789 0,802 0,776 0,822 0,866
  • Analisando os modelos e suas respectivas métricas, cabe destacar que o modelo que obteve a melhor perfomance geral foi o Gradient Boosting (GB), sendo superior em todas as métricas, exceto na especificidade:

    • F1 Score GB(78,9%);

    • Acurácia GB (80,0%);

    • Roc AUC GB (86,6%);

  • F1-Score : É a média harmônica da precisão e do recall. É útil quando se deseja um bom equilíbrio entre precisão e recall.

  • Interpretação: Um F1-score de 78,9% indica um bom equilíbrio entre precisão e recall, sugerindo que o modelo tem um bom desempenho geral.

  • Acurácia : Indica a proporção total de previsões corretas. Em outras palavras, o modelo acertou 80,0% das vezes.

  • Interpretação: É um bom indicador geral de desempenho, mas pode ser enganoso em casos de desbalanceamento de classes, que não é o caso da análise.

  • Roc: A curva ROC pode fornecer uma visão mais completa do desempenho do modelo, especialmente em cenários com diferentes limiares de classificação. Ela plota a taxa de verdadeiros positivos (sensibilidade) contra a taxa de falsos positivos (1 - especificidade) em vários pontos de corte.

  • Área Sob a Curva ROC: A área sob a curva ROC é um único valor que resume o desempenho global do modelo. Um AUC de 1 indica um classificador perfeito, enquanto um AUC de 0.5 indica um classificador aleatório, o nosso foi 0,866, indicando um desempenho bom do modelo.

Observações: O modelo perdeu nos seguintes quesitos:

  • Especificidade (0,822) (Perdeu para Árvore de decisão (0,833) )

    • Especificidade: Indica a proporção de exemplos negativos que foram corretamente identificados, ou seja quantas empresas que de fato não foram baixadas e o modelo previu como não baixadas e estava correto em 82,2% das vezes.

Considerações finais

  • Desenvolvemos um modelo de classificação com alta precisão para prever quais empresas encerrariam suas atividades que contempla 3 variáveis explicativas, quais sejam: O capital social da empresa (Valor investido ao abrir a empresa), os Cnaes principais de dois dígitos (Indicam a principal atividade principal da empresa) e a natureza jurídica da empresa (Suas diferentes classificações, por exemplo se é uma empresa pública, um serviço notarial, empresa individual de responsabilidade limitada (EIRELLI), etc…). Os resultados indicam que o modelo proposto é capaz de identificar corretamente 80,0% dos casos, com um F1-score de 78,9% e uma AUC de 86,6%.