Introdução

Neste notebook, comparamos diferentes modelos de regressão utilizando dados reais. O objetivo é analisar a performance preditiva de cada modelo, utilizando métricas como RMSE e \(R^2\). Considerando os dados reais de imóveis anunciados para venda na cidade de João Pessoa - PB, com mais de 27 mil observações obtidas via web scraping de sites de anúncios imobiliários e referem-se à anúncios do primeiro semestre de 2023.A partir dele realiza-se uma análise preditiva do valor dos imóveis, baseada em suas características, considerando uma abordagem clara e completa para a análise de dados e modelagem preditiva. Utilizaremos uma variedade de modelos de regressão e uma análise detalhada para comparar o desempenho de cada modelo.

library(tidymodels)
library(vetiver)
library(iml)
library(cowplot)
library(ggplot2)
library(randomForest)
library(workflowsets)
library(glmnet)
library(parallelly)
library(parallel)
library(recipes)
library(imager)
library(kknn)
library(GGally)

Carregando os Dados

dados <- read.csv("C:/Users/gleyc/Downloads/joao_pessoa_gleyce.csv")
view(dados)

Análise Exploratória dos Dados

str(dados)
## 'data.frame':    27038 obs. of  30 variables:
##  $ id               : num  2.62e+09 2.63e+09 2.63e+09 2.63e+09 2.44e+09 ...
##  $ endereco         : chr  "Rua Professora Nair Paiva dos Santos" "Altiplano Cabo Branco" "Rua Doutor Pedro Narciso Castanheira" "Rua Elisio Lopes de Oliveira" ...
##  $ valor            : int  1450000 1950000 350000 360000 650000 699600 740000 1450000 1599000 700000 ...
##  $ area             : int  221 295 525 191 300 200 130 228 228 200 ...
##  $ quarto           : int  4 5 2 3 5 4 3 5 4 4 ...
##  $ vaga             : int  3 2 NA 3 2 2 3 4 4 2 ...
##  $ banheiro         : int  4 7 1 3 5 5 3 5 4 4 ...
##  $ url              : chr  "https://www.zapimoveis.com.br/venda/casas/pb+joao-pessoa++altiplano-cabo-branco/?pagina=1" "https://www.zapimoveis.com.br/venda/casas/pb+joao-pessoa++altiplano-cabo-branco/?pagina=1" "https://www.zapimoveis.com.br/venda/casas/pb+joao-pessoa++altiplano-cabo-branco/?pagina=1" "https://www.zapimoveis.com.br/venda/casas/pb+joao-pessoa++altiplano-cabo-branco/?pagina=1" ...
##  $ bairro           : chr  "altiplano_cabo_branco" "altiplano_cabo_branco" "altiplano_cabo_branco" "altiplano_cabo_branco" ...
##  $ zona             : chr  "leste" "leste" "leste" "leste" ...
##  $ tipo             : chr  "casas" "casas" "casas" "casas" ...
##  $ comercio         : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ area_servico     : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ espaco_gourmet   : logi  TRUE TRUE FALSE FALSE FALSE FALSE ...
##  $ piscina          : logi  TRUE TRUE FALSE TRUE FALSE FALSE ...
##  $ elevador         : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ salao_de_festa   : logi  TRUE FALSE FALSE FALSE FALSE FALSE ...
##  $ academia         : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ playground       : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ quadra_de_esporte: logi  TRUE FALSE FALSE FALSE FALSE FALSE ...
##  $ portaria_24_horas: logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ varanda_gourmet  : logi  TRUE FALSE FALSE FALSE FALSE FALSE ...
##  $ sauna            : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ spa              : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ iptu             : int  700 NA NA 900 NA NA NA NA 1 NA ...
##  $ condominio       : int  680 NA NA NA NA NA NA NA 1 NA ...
##  $ latitude         : num  -7.14 -7.13 -7.14 -7.13 -7.14 ...
##  $ longitude        : num  -34.8 -34.8 -34.8 -34.8 -34.8 ...
##  $ z_lat            : num  -0.03221 -0.00477 -0.02302 -0.01207 -0.01603 ...
##  $ z_lon            : num  0.1164 0.1127 0.0974 0.1006 0.0996 ...

Pré- Processamento dos Dados

# Verificar os nomes das colunas
colnames(dados)
##  [1] "id"                "endereco"          "valor"            
##  [4] "area"              "quarto"            "vaga"             
##  [7] "banheiro"          "url"               "bairro"           
## [10] "zona"              "tipo"              "comercio"         
## [13] "area_servico"      "espaco_gourmet"    "piscina"          
## [16] "elevador"          "salao_de_festa"    "academia"         
## [19] "playground"        "quadra_de_esporte" "portaria_24_horas"
## [22] "varanda_gourmet"   "sauna"             "spa"              
## [25] "iptu"              "condominio"        "latitude"         
## [28] "longitude"         "z_lat"             "z_lon"
# Remover colunas desnecessárias apenas se existirem
cols_to_remove <- c("endereco", "bairro", "iptu","id", "condominio")
dados <- dados %>%
  select(-one_of(cols_to_remove))


# Transformar a variável tipo em variáveis dummy
dados <- dados %>%
  mutate(
    tipo_casa = ifelse(grepl("casa", tipo, ignore.case = TRUE), 1, 0),
    tipo_apartamento = ifelse(grepl("apartamento", tipo, ignore.case = TRUE), 1, 0),
    tipo_terreno = ifelse(grepl("terreno", tipo, ignore.case = TRUE), 1, 0)
  )


# Criar receita para imputação de dados faltantes
recipe_dados <- recipe(~ ., data = dados) %>%
  step_impute_knn(all_predictors(), neighbors = 5)

# Ajustar a receita aos dados
dados_imputados <- prep(recipe_dados, training = dados) %>%
  bake(new_data = NULL)

# Remover a coluna tipo original
dados_imputados <- dados_imputados %>%
  select(-tipo)

# Verificar se há mais valores faltantes
sum(is.na(dados_imputados))
## [1] 0

Análise de Correlção

# Calcular a matriz de correlação
cor_matrix <- cor(dados_imputados %>% select_if(is.numeric))

# Visualizar a matriz de correlação
library(reshape2)
## 
## Anexando pacote: 'reshape2'
## O seguinte objeto é mascarado por 'package:tidyr':
## 
##     smiths
library(ggplot2)

cor_matrix_melted <- melt(cor_matrix)
ggplot(cor_matrix_melted, aes(Var1, Var2, fill = value)) +
  geom_tile() +
  scale_fill_gradient2(low = "red", high = "blue", mid = "white", midpoint = 0, limit = c(-1, 1), space = "Lab", name="Correlação") +
  theme_minimal() +
  labs(title = "Matriz de Correlação")

# Modelo de regressão linear
modelo_lm <- lm(valor ~ area + quarto + banheiro + tipo_casa + tipo_apartamento + tipo_terreno, data = dados_imputados)

# Resumo do modelo
summary(modelo_lm)
## 
## Call:
## lm(formula = valor ~ area + quarto + banheiro + tipo_casa + tipo_apartamento + 
##     tipo_terreno, data = dados_imputados)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
##  -3881952   -271388   -103294    111890 149727357 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      -5.371e+04  5.314e+04  -1.011 0.312166    
## area             -6.873e-03  1.872e-02  -0.367 0.713515    
## quarto            1.832e+05  1.744e+04  10.500  < 2e-16 ***
## banheiro          1.987e+05  1.190e+04  16.698  < 2e-16 ***
## tipo_casa        -2.470e+05  6.938e+04  -3.559 0.000373 ***
## tipo_apartamento -2.387e+05  5.610e+04  -4.255  2.1e-05 ***
## tipo_terreno      1.612e+06  9.550e+04  16.883  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1893000 on 27031 degrees of freedom
## Multiple R-squared:  0.04024,    Adjusted R-squared:  0.04003 
## F-statistic: 188.9 on 6 and 27031 DF,  p-value: < 2.2e-16
# Previsões e cálculo do erro quadrático médio (RMSE)
dados_imputados$predicoes_lm <- predict(modelo_lm, newdata = dados_imputados)
rmse_lm <- sqrt(mean((dados_imputados$valor - dados_imputados$predicoes_lm)^2))
# Preparar os dados para a regressão Ridge
x <- model.matrix(valor ~ area + quarto + banheiro + tipo_casa + tipo_apartamento + tipo_terreno, data = dados_imputados)[, -1]
y <- dados_imputados$valor

# Ajustar o modelo de regressão Ridge
modelo_ridge <- cv.glmnet(x, y, alpha = 0)

# Previsões e cálculo do RMSE
predicoes_ridge <- predict(modelo_ridge, newx = x)
rmse_ridge <- sqrt(mean((y - predicoes_ridge)^2))
# Ajustar o modelo de regressão Lasso
modelo_lasso <- cv.glmnet(x, y, alpha = 1)

# Previsões e cálculo do RMSE
predicoes_lasso <- predict(modelo_lasso, newx = x)
rmse_lasso <- sqrt(mean((y - predicoes_lasso)^2))
# Ajustar o modelo de Elastic Net
modelo_elastic_net <- cv.glmnet(x, y, alpha = 0.5)

# Previsões e cálculo do RMSE
predicoes_elastic_net <- predict(modelo_elastic_net, newx = x)
rmse_elastic_net <- sqrt(mean((y - predicoes_elastic_net)^2))

# Exibir RMSE do modelo Elastic Net
cat("RMSE do modelo Elastic Net:", rmse_elastic_net, "\n")
## RMSE do modelo Elastic Net: 1931771
# Comparar e classificar a performance dos modelos
resultados <- data.frame(
  Modelo = c("Linear", "Ridge", "Lasso", "Elastic Net"),
  RMSE = c(rmse_lm, rmse_ridge, rmse_lasso, rmse_elastic_net)
)

resultados <- resultados %>%
  arrange(RMSE)

print(resultados)
##        Modelo    RMSE
## 1      Linear 1892506
## 2       Ridge 1931771
## 3       Lasso 1931771
## 4 Elastic Net 1931771

Fazendo as análises e comparando os quatro modelos de regressão — Linear, Ridge, Lasso e Elastic Net — para prever o valor de venda de imóveis em João Pessoa. O desempenho foi avaliado usando o RMSE, com a regressão linear simples obtendo o melhor resultado (RMSE = 1892506). Os modelos Ridge, Lasso e Elastic Net apresentaram RMSEs muito semelhantes (1931771), indicando que a regularização não trouxe uma melhoria significativa. Isso sugere que as features não se beneficiaram muito da regularização, ou que os parâmetros de regularização poderiam ser otimizados. A regressão linear simples mostrou-se eficaz, possivelmente porque as variáveis explicativas têm uma relação linear direta com o valor dos imóveis.