library(readxl)
dados <- read_excel("dados_pinus.xlsx")4 Regressão Ridge
A regressão de Cume, Cumeeira, em Crista ou chamada Ridge Regression, proposta por Hoerl e Kennard (1970a), é um dos vários métodos propostos para remediar os problemas de multicolinearidade, alterando o método de mínimos quadrados para permitir estimadores viesados dos coeficientes de regressão.
Quando um estimador tem um viés pequeno e é substancialmente mais preciso que o estimador não viesado, este pode ser escolhido desde que tenha grande probabilidade de estar próximo do valor verdadeiro (Hoerl; Kennard 1970b). Assim a probabilidade do estimador de cumeeira estar próximo do valor verdadeiro é muito maior que para o estimador não viesado de mínimos quadrados ordinais (NETER et al., 1996).
Uma medida da combinação do efeito do viés e da variação amostral é o valor esperado do quadrado do desvio do estimador e do valor verdadeiro. Esta medida é chamada de Erro Médio Quadrático (EMQ), e pode ser escrita como,
\[ E(\hat{\beta}-\beta)^{2} = V(\hat{\beta}) + [E(\hat{\beta})-\beta]^{2}\]
Dessa maneira, o EMQ é igual à variância do estimador mais o viés ao quadrado. Note que se o estimador for não viesado, o erro médio quadrático é igual ao estimador da variância. Pelo método de mínimos quadrados, o coeficiente \(\beta\) pode ser estimado como,
\[ \hat{\beta} = (X^{'}X)^{-1}X^{'}Y \]
e as estimativas e suas variâncias poderão ser incertas na presença de multicolinearidade. A regressão de cume consiste na adição de coeficientes a diagonal principal da matriz de correlações \((X^{'}X)^{-1}\) , causando um decréscimo na variância das estimativas. Desta maneira, o estimador de cume de \(\beta\) é obtido por,
\[\hat{\beta} = (X^{'}X + k)^{-1}X^{'}Y\] Sendo \(k= diagonal(k_{1},k_{2},...,k_{p}), k_{i} \geq 0\), onde um procedimento bastante usado é \(k=kI\), \(k_{i} \geq 0\) . O estimador em cume é na verdade uma família de estimadores, onde \(k\) é um valor pequeno que deve ser escolhido a critério do pesquisador. Em geral, aumenta-se gradativamente o valor de \(k\) até que os estimadores dos coeficientes tornam-se estáveis, não variam. Se a escolha for \(k_{i} = 0\), para todo \(i\), tem-se o estimador de Mínimos Quadrados (NETER; WASSERMAN, 1974), (DRAPER; SMITH, 1981) e (ELIAN, 1998).
Quando os dados possuem traços de multicolinearidade sempre existe um valor para o parâmetro \(k\) no qual os estimadores de Regressão em Crista produzem um Quadrado Médio do Erro (QME) menor do que o QME produzido pelos Estimadores de mínimos quadrados ordinários (HOERL; KENNARD, 1970a), (NETER; WASSERMAN, 1974), (DRAPER; SMITH, 1981), (ELIAN, 1998),
A função estimada pela Regressão em Crista produz predições com novas observações que tendem a serem mais precisas do que as feitas pela função estimada pelo método de mínimos quadrados ordinários, quando as variáveis independentes são correlacionadas e a nova observação segue o mesmo padrão de multicolinearidade, esta precisão na predição de novas observações é favorecida pela Regressão de Cume, especialmente quando a multicolinearidade é forte (NETER; WASSERMAN, 1974), (DRAPER; SMITH, 1981), (ELIAN, 1998).
4.1 Métodos pra Determinar \(k\)
Um valor ideal para o parâmetro \(K\), o qual resulta em um menor QME que o obtido pelo Método de Mínimos Quadrados Ordinários (MQO) depende do vetor de parâmetro desconhecido e da variância do erro também desconhecido (HOERL; KENNARD, 1970a). Conseqüentemente, K precisa ser determinado empiricamente ou obtido dos dados, e não é possível determinar o valor ideal do parâmetro de cume K. Muitos métodos têm sido propostos para obter os valores apropriados, mas não existe um consenso de qual método é o mais adequado. Assim, o parâmetro de ridge \(K\) será estimado a partir de dois métodos: Gráfico do Traço de Cume (Ridge Trace Plot) e Gráfico do Fator de Inflação da Variância (Variance Inflation Factor Plot).
Um dos obstáculos principais em utilizar a regressão de cume está em escolher um valor de k. O traço de cume é um esboço dos valores de (p-1) coeficientes estimados de regressão de cume padronizados para diferentes valores de \(K\), usualmente entre 0 e 1. Feito o traço, pode-se examinar um valor de \(K\) onde as estimativas se estabilizam. Hoerl e Kennard (1970b) desenvolveram um gráfico bidimensional do valor de cada coeficiente versus \(k\), mostrando como os valores de \(\hat{\beta}\) variam em função dos valores de k, ou seja, a partir do gráfico o analista escolhe um valor para K que os coeficientes da regressão tendem a ser mais precisos, que o MQO, quando os dados estão sob o efeito da multicolinearidade.
Segundo Chagas et al. (2009), o objetivo é escolher um valor de k a partir do qual as estimativas dos parâmetros sejam relativamente estáveis gerando uma série de coeficientes com menor soma dos quadrados do resíduo do que a solução clássica. Assim, na medida em que se aumenta o valor de k, a soma de quadrados dos resíduos também aumentará, sugerindo iniciar com valores pequenos de k e ir aumentando gradativamente até que os coeficientes se estabilizem.
Para Hoerl e Kennard (1970a), o Fator de Inflação da Variância, mostra a variabilidade em função do valor de K, ou seja, à medida que se atribui valores para K que estabilizam os coeficientes de regressão de cume, a variabilidade diminui, removendo a multicolinearidade. O traço do cume pode também ser usado para sugerir variável(s) que pode(m) ser retiradas do modelo. Algumas variáveis cuja estimativa do parâmetro é instável a cada mudança do valor de K ou que decresce para zero são candidatos para anulação.
Atualmente na literatura, existem várias medidas corretivas para suavizar os efeitos provocados pela multicolinearidade, outros métodos são propostos desde simples as mais complexas, tais como, Ampliação do Tamanho da Amostra e Remoção das Variáveis (HAIR et al., 2005), utilização de Modelo de Regressão por Componente Principais (SILVA et al., 2009), Modelo de Regressão por Análise Fatorial (VALENTE et al., 2011), Regressão com Variáveis Latentes (MALHOTRA, 2011) e Regressão via Redes Neurais (RODRIGUES et al., 2010) e (LEAL et al., 2015).
Para rodar a regressão Ridge na linguagem R, usaremos o pacote glmnet.
4.2 Carregar Dataset2
Segundo Passo é carregar a base de dados, chamada de Volume de Pinus. Para isso é necessário instalar o pacote para leitura de arquivo com extensão do tipo excel(.xlsx) por meio do comando install.packages(“readxl”).
Posteriormente, ativar o pacote no R com o comando library(readxl). Tendo um detalhe fundamental, que se instala somente um vez o pacote, e se ativa toda vez que for usar.
4.2.1 Variáveis
Para ilustrar a regressão ridge, vamos começar com um exemplo em que queremos estudar a relação entre DAP (variável preditora \(X_{1}\)) e Volume (variável dependente Y) com uma amostra de 250 arvores.
- Local: Empresa Duratex Florestal SP
- Amostra: 20 arvores
- IAF : Indice Aerea Foliar
- DAF : Distribuição Angular da Folha
- GAP :
- IDADE : Idade em Meses da arvore
- DAP : Diâmetro a Altura do Peito (1.30 metros do solo)
- ALTURA : Altura da arvore
- ÁEREA BASAL : Area Basal da arvore
4.3 Matriz de Correlação
library(corrplot)
correl <- cor(dados[, -1])
corrplot(correl,
method = "color", # circle, number, shade
type = "upper", # lower, full
#order = "hclust",
addCoef.col = "black",
tl.srt = 90,
diag = TRUE)
4.4 Matriz de Dispersão
library(psych)
library(GGally)
pairs.panels(dados,
method = "pearson",
density = TRUE,
ellipses = TRUE,
smoother = TRUE)
4.5 Regressão Linear
Uma das tarefas mais corriqueiras dos analista de dados é a produção de tabelas. Seja para apresentar frequências, estatísticas descritivas (media, mediana, moda, etc), seja para apresentar resultados de modelos de regressão.
Tabela de resultados referente ao modelo de regressão linear multiplo com n =250.
Modelo_mlm <- lm(VOLUME ~ ., data = dados)
summary(Modelo_mlm)
Call:
lm(formula = VOLUME ~ ., data = dados)
Residuals:
Min 1Q Median 3Q Max
-35.500 -6.329 -0.319 7.374 27.916
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -124.6245 22.3169 -5.584 6.29e-08 ***
IDADE 8.5913 0.6628 12.962 < 2e-16 ***
DAP -4.0900 1.1241 -3.638 0.000335 ***
ALTURA 13.4301 0.2229 60.259 < 2e-16 ***
IAF 0.6560 1.6718 0.392 0.695108
DAF 2.7282 1.3959 1.954 0.051810 .
GAP 0.4299 1.5373 0.280 0.779992
AREA_BASAL -227.5270 286.3350 -0.795 0.427614
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 10.41 on 242 degrees of freedom
Multiple R-squared: 0.9588, Adjusted R-squared: 0.9576
F-statistic: 803.9 on 7 and 242 DF, p-value: < 2.2e-16
4.5.1 Fator de Inflanção da Variância (vIF)
library(car)
vif(Modelo_mlm) IDADE DAP ALTURA IAF DAF GAP AREA_BASAL
1.044845 65.625225 1.026564 6.652028 1.040344 6.694949 65.782421
4.6 Modelo de Regressão Ridge Geral
#------------------ Pacotes ------------------------------------------#
library(caret)
library(glmnet)
#------------------ Modelo Ridge Completo ----------------------------#
set.seed(123)
train_index <- createDataPartition(dados$VOLUME, p = 0.9, list = FALSE)
dados_treino <- dados[train_index, ]
dados_teste <- dados[-train_index, ]
x_train <- model.matrix(VOLUME ~ ., dados_treino)[, -1]
y_train <- dados_treino$VOLUME
x_test <- model.matrix(VOLUME ~ ., dados_teste)[, -1]
y_test <- dados_teste$VOLUME
# Regressão Ridge (Ridge:alpha = 0; LASSO:alpha = 1)
cv_ridge <- cv.glmnet(x_train,
y_train,
alpha = 0,
standardize = TRUE
)
# Melhor lambda
best_lambda_ridge <- cv_ridge$lambda.min
cat("Melhor lambda (Ridge):", best_lambda_ridge, "\n")Melhor lambda (Ridge): 4.345508
modelo_ridge <- glmnet(x_train,
y_train,
alpha = 0,
lambda = best_lambda_ridge,
standardize = TRUE)
# Coeficientes do modelo final
coef_ridge <- coef(modelo_ridge)
print(coef_ridge)8 x 1 sparse Matrix of class "dgCMatrix"
s0
(Intercept) -112.9141563
IDADE 7.7791185
DAP -2.5523709
ALTURA 12.2855577
IAF 0.3903256
DAF 2.3744578
GAP -0.0264784
AREA_BASAL -601.6109904
# Predição no conjunto de teste
y_pred_ridge <- as.numeric(predict(modelo_ridge,
newx = x_test)
)
#------------------------------------------------------------------------------#
# Medidas Performance
R2_ridge <- cor(y_test, y_pred_ridge)^2
rmse_ridge <- sqrt(mean((y_test - y_pred_ridge)^2))
mae_ridge <- mean(abs(y_test - y_pred_ridge))
mape_ridge <- mean(abs((y_test - y_pred_ridge) / y_test)) * 100
# Predição nos dados de treino para obter o RSS
y_pred_train_ridge <- predict(modelo_ridge,
s = best_lambda_ridge,
newx = x_train)
RSS <- sum((y_train - y_pred_train_ridge)^2)
n <- length(y_train)
df_ridge <- modelo_ridge$df
AIC_ridge <- n * log(RSS / n) + 2 * (df_ridge + 1)
BIC_ridge <- n * log(RSS / n) + log(n) * (df_ridge + 1)
cat(
"\n--- Performance Ridge Geral ---\n",
"R² =", round(R2_ridge, 4), "\n",
"RMSE =", round(rmse_ridge, 4), "\n",
"MAE =", round(mae_ridge, 4), "\n",
"MAPE =", round(mape_ridge, 2), "%\n",
"AIC =", round(AIC_ridge, 2), "\n",
"BIC =", round(BIC_ridge, 2), "\n"
)
--- Performance Ridge Geral ---
R² = 0.9127
RMSE = 13.252
MAE = 11.5346
MAPE = 26.4 %
AIC = 1082.22
BIC = 1109.59
#------------------------------------------------------------------------------#4.6.1 Ridge Trace Plot Geral
library(caret)
library(glmnet)
library(reshape2)
library(ggplot2)
modelo_ridge_seq <- glmnet(
x_train,
y_train,
alpha = 0,
standardize = TRUE
)
coefs <- as.matrix(modelo_ridge_seq$beta)
df_coef <- as.data.frame(t(coefs))
df_coef$lambda <- log(modelo_ridge_seq$lambda)
df_long <- melt(
df_coef,
id.vars = "lambda",
variable.name = "Variavel",
value.name = "Coeficiente"
)
ggplot(df_long, aes(lambda, Coeficiente, color = Variavel)) +
geom_line(linewidth = 2, alpha = 0.85) +
geom_vline(
xintercept = log(best_lambda_ridge),
linetype = "dashed",
color = "red"
) +
labs(
title = "Ridge Trace Plot",
subtitle = "Modelo Ridge Geral",
x = expression(log(lambda)),
y = "Coeficientes"
) +
theme_minimal(base_size = 14) +
theme(
legend.position = "right",
legend.title = element_blank()
)
4.6.2 VIF Trace Plot (Geral)
library(ggplot2)
library(reshape2)
# ---------------- MATRIZ DE PREDITORES ---------------- #
X <- scale(x_train)
# ---------------- SEQUÊNCIA DE k ---------------- #
k_values <- exp(seq(
log(1e-4),
log(10),
length.out = 100
))
# ---------------- FUNÇÃO VIF RIDGE ---------------- #
ridge_vif <- function(X, k) {
XtX <- crossprod(X)
A <- solve(XtX + diag(k, ncol(X)))
diag(A %*% XtX %*% A)
}
# ---------------- CÁLCULO DOS VIFS ---------------- #
vif_matrix <- sapply(k_values, function(k) ridge_vif(X, k))
# ---------------- ORGANIZAÇÃO DOS DADOS ---------------- #
vif_df <- as.data.frame(t(vif_matrix))
colnames(vif_df) <- colnames(X)
vif_df$k <- k_values
vif_long <- melt(
vif_df,
id.vars = "k",
variable.name = "Variavel",
value.name = "VIF"
)
# Remove problemas numéricos
vif_long <- vif_long[
is.finite(vif_long$VIF) & vif_long$VIF > 0,
]
# ---------------- GRÁFICO FINAL (NORMAL) ---------------- #
ggplot(vif_long,
aes(x = log(k),
y = VIF,
color = Variavel)) +
geom_line(linewidth = 1.2, alpha = 0.9) +
geom_hline(yintercept = 10,
linetype = "dashed",
color = "gray40") +
geom_vline(xintercept = log(best_lambda_ridge),
linetype = "dashed",
color = "red") +
scale_y_log10() +
labs(
title = "VIF Trace Plot",
subtitle = "Modelo Ridge Completo",
x = expression(log(k)),
y = "VIF",
color = "Variáveis"
) +
theme_minimal(base_size = 14) +
theme(
legend.position = "right",
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 12, color = "gray40")
)
4.7 Modelo de Regressão Ridge (Sem Area Basal)
library(readxl)
library(dplyr)
library(caret)
library(glmnet)
library(car)
library(corrplot)
library(ggcorrplot)
library(ggplot2)
library(reshape2)
## Modelo de Regressão Ridge (Sem Área Basal)
dados_sem_area <- dados %>% select(-AREA_BASAL)
#---------------------------------------------------------------#
# Modelo Linear Múltiplo (baseline)
modelo2_mlm <- lm(VOLUME ~ ., data = dados_sem_area)
summary(modelo2_mlm)
Call:
lm(formula = VOLUME ~ ., data = dados_sem_area)
Residuals:
Min 1Q Median 3Q Max
-35.687 -6.355 0.048 7.512 28.158
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -113.7672 17.6318 -6.452 5.91e-10 ***
IDADE 8.5571 0.6609 12.948 < 2e-16 ***
DAP -4.9760 0.1431 -34.769 < 2e-16 ***
ALTURA 13.4382 0.2225 60.403 < 2e-16 ***
IAF 0.6504 1.6706 0.389 0.6974
DAF 2.7371 1.3948 1.962 0.0509 .
GAP 0.4282 1.5362 0.279 0.7807
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 10.4 on 243 degrees of freedom
Multiple R-squared: 0.9587, Adjusted R-squared: 0.9576
F-statistic: 939.3 on 6 and 243 DF, p-value: < 2.2e-16
vif(modelo2_mlm) IDADE DAP ALTURA IAF DAF GAP
1.040444 1.065338 1.024446 6.651911 1.040277 6.694936
#---------------------------------------------------------------#
# Partição treino / teste
set.seed(123)
train_index2 <- createDataPartition(
dados_sem_area$VOLUME,
p = 0.9,
list = FALSE
)
dados_treino2 <- dados_sem_area[train_index2, ]
dados_teste2 <- dados_sem_area[-train_index2, ]
#---------------------------------------------------------------#
# Matrizes de preditores
x_train2 <- model.matrix(VOLUME ~ ., dados_treino2)[, -1]
y_train2 <- dados_treino2$VOLUME
x_test2 <- model.matrix(VOLUME ~ ., dados_teste2)[, -1]
y_test2 <- dados_teste2$VOLUME
#---------------------------------------------------------------#
# Ridge com validação cruzada
cv_ridge2 <- cv.glmnet(
x_train2,
y_train2,
alpha = 0,
standardize = TRUE
)
best_lambda_ridge2 <- cv_ridge2$lambda.min
modelo_ridge2 <- glmnet(
x_train2,
y_train2,
alpha = 0,
lambda = best_lambda_ridge2,
standardize = TRUE
)
#---------------------------------------------------------------#
# Predição no conjunto de teste
y_pred_ridge2 <- as.numeric(
predict(modelo_ridge2, newx = x_test2)
)
#---------------------------------------------------------------#
# Métricas de desempenho
R2_ridge2 <- cor(y_test2, y_pred_ridge2)^2
rmse_ridge2 <- sqrt(mean((y_test2 - y_pred_ridge2)^2))
mae_ridge2 <- mean(abs(y_test2 - y_pred_ridge2))
mape_ridge2 <- mean(abs((y_test2 - y_pred_ridge2) / y_test2)) * 100
#---------------------------------------------------------------#
# AIC e BIC (via RSS + df efetivos)
y_pred_train_ridge2 <- as.numeric(
predict(modelo_ridge2, newx = x_train2)
)
RSS2 <- sum((y_train2 - y_pred_train_ridge2)^2)
n2 <- length(y_train2)
df2 <- modelo_ridge2$df
AIC_ridge2 <- n2 * log(RSS2 / n2) + 2 * (df2 + 1)
BIC_ridge2 <- n2 * log(RSS2 / n2) + log(n2) * (df2 + 1)
#---------------------------------------------------------------#
# Resultado final
cat(
"\n--- Performance do Modelo Ridge (Sem Área Basal) ---\n",
"R² =", round(R2_ridge2, 4), "\n",
"RMSE =", round(rmse_ridge2, 4), "\n",
"MAE =", round(mae_ridge2, 4), "\n",
"MAPE =", round(mape_ridge2, 2), "%\n",
"AIC =", round(AIC_ridge2, 2), "\n",
"BIC =", round(BIC_ridge2, 2), "\n"
)
--- Performance do Modelo Ridge (Sem Área Basal) ---
R² = 0.9215
RMSE = 12.7064
MAE = 10.9662
MAPE = 25.4 %
AIC = 1085.05
BIC = 1109
4.7.1 Ridge Trace Plot (Sem Area Basal)
library(caret)
library(glmnet)
library(ggplot2)
library(reshape2)
### Ridge Trace Plot (Sem Área Basal)
modelo_ridge2_seq <- glmnet(
x_train2,
y_train2,
alpha = 0,
standardize = TRUE
)
#---------------------------------------------------------------#
# Extração dos coeficientes
coefs2 <- as.matrix(modelo_ridge2_seq$beta)
lambdas2 <- modelo_ridge2_seq$lambda
df_coef2 <- as.data.frame(t(coefs2))
df_coef2$lambda <- log(lambdas2)
#---------------------------------------------------------------#
# Formato longo
df_long2 <- melt(
df_coef2,
id.vars = "lambda",
variable.name = "Variavel",
value.name = "Coeficiente"
)
#---------------------------------------------------------------#
# Ridge Trace Plot
ggplot(df_long2,
aes(x = lambda,
y = Coeficiente,
color = Variavel)) +
geom_line(linewidth = 1.2, alpha = 0.9) +
geom_vline(
xintercept = log(best_lambda_ridge2),
linetype = "dashed",
color = "red",
linewidth = 1
) +
labs(
title = "Ridge Trace Plot",
subtitle = "Modelo Ridge (Sem Área Basal)",
x = expression(log(lambda)),
y = "Coeficientes dos preditores"
) +
scale_color_brewer(palette = "Dark2") +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 13, color = "gray40"),
legend.title = element_blank(),
legend.text = element_text(size = 11),
legend.position = "right",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85")
)
4.8 Modelo de Regressão Ridge (Sem DAP)
library(readxl)
library(dplyr)
library(caret)
library(glmnet)
library(car)
library(corrplot)
library(ggcorrplot)
library(ggplot2)
library(reshape2)
## Modelo de Regressão Ridge (Sem DAP)
#---------------------------------------------------------------#
# Base sem DAP
dados_sem_dap <- dados %>% select(-DAP)
# Modelo linear auxiliar (diagnóstico)
modelo3_mlm <- lm(VOLUME ~ ., data = dados_sem_dap)
summary(modelo3_mlm)
Call:
lm(formula = VOLUME ~ ., data = dados_sem_dap)
Residuals:
Min 1Q Median 3Q Max
-36.457 -6.181 -0.254 7.513 26.999
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -176.1803 17.6702 -9.970 <2e-16 ***
IDADE 8.7213 0.6783 12.858 <2e-16 ***
ALTURA 13.4068 0.2283 58.718 <2e-16 ***
IAF 0.7247 1.7133 0.423 0.6727
DAF 2.8075 1.4305 1.963 0.0508 .
GAP 0.4863 1.5755 0.309 0.7578
AREA_BASAL -1260.8588 37.3898 -33.722 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 10.67 on 243 degrees of freedom
Multiple R-squared: 0.9565, Adjusted R-squared: 0.9554
F-statistic: 890.9 on 6 and 243 DF, p-value: < 2.2e-16
vif(modelo3_mlm) IDADE ALTURA IAF DAF GAP AREA_BASAL
1.041809 1.025712 6.651179 1.040091 6.694267 1.067890
#---------------------------------------------------------------#
# Divisão treino / teste
set.seed(123)
train_idx_dap <- createDataPartition(
dados_sem_dap$VOLUME,
p = 0.9,
list = FALSE
)
dados_treino_dap <- dados_sem_dap[train_idx_dap, ]
dados_teste_dap <- dados_sem_dap[-train_idx_dap, ]
#---------------------------------------------------------------#
# Matrizes para o glmnet
x_train_dap <- model.matrix(VOLUME ~ ., dados_treino_dap)[, -1]
y_train_dap <- dados_treino_dap$VOLUME
x_test_dap <- model.matrix(VOLUME ~ ., dados_teste_dap)[, -1]
y_test_dap <- dados_teste_dap$VOLUME
#---------------------------------------------------------------#
# Ridge com validação cruzada
cv_ridge_dap <- cv.glmnet(
x_train_dap,
y_train_dap,
alpha = 0,
standardize = TRUE
)
best_lambda_dap <- cv_ridge_dap$lambda.min
cat("Melhor lambda (sem DAP):", best_lambda_dap, "\n")Melhor lambda (sem DAP): 4.345508
#---------------------------------------------------------------#
# Modelo Ridge final
modelo_ridge_dap <- glmnet(
x_train_dap,
y_train_dap,
alpha = 0,
lambda = best_lambda_dap,
standardize = TRUE
)
coef(modelo_ridge_dap)7 x 1 sparse Matrix of class "dgCMatrix"
s0
(Intercept) -1.495238e+02
IDADE 7.847080e+00
ALTURA 1.231958e+01
IAF 4.641568e-01
DAF 2.827680e+00
GAP 4.234242e-02
AREA_BASAL -1.190645e+03
#---------------------------------------------------------------#
# Predição no conjunto de teste
y_pred_dap <- predict(
modelo_ridge_dap,
s = best_lambda_dap,
newx = x_test_dap
)
#---------------------------------------------------------------#
# Métricas de desempenho
R2_dap <- cor(y_test_dap, y_pred_dap)^2
rmse_dap <- sqrt(mean((y_test_dap - y_pred_dap)^2))
mae_dap <- mean(abs(y_test_dap - y_pred_dap))
mape_dap <- mean(abs((y_test_dap - y_pred_dap) / y_test_dap)) * 100
#---------------------------------------------------------------#
# AIC e BIC (versão adequada para Ridge)
y_pred_train_dap <- predict(
modelo_ridge_dap,
s = best_lambda_dap,
newx = x_train_dap
)
RSS_dap <- sum((y_train_dap - y_pred_train_dap)^2)
# Graus de liberdade efetivos
df_dap <- modelo_ridge_dap$df[
which(modelo_ridge_dap$lambda == best_lambda_dap)
]
n_dap <- nrow(dados_treino_dap)
AIC_dap <- n_dap * log(RSS_dap / n_dap) + 2 * (df_dap + 1)
BIC_dap <- n_dap * log(RSS_dap / n_dap) + log(n_dap) * (df_dap + 1)
#---------------------------------------------------------------#
# Resultados
cat("\n--- Performance do Modelo Ridge (Sem DAP) ---\n")
--- Performance do Modelo Ridge (Sem DAP) ---
cat(
"R² =", R2_dap,
"\nRMSE =", rmse_dap,
"\nMAE =", mae_dap,
"\nMAPE =", mape_dap,
"\nAIC =", AIC_dap,
"\nBIC =", BIC_dap
)R² = 0.9087487
RMSE = 13.63578
MAE = 11.86191
MAPE = 26.8178
AIC = 1091.824
BIC = 1115.768
4.8.1 Ridge Trace Plot (Sem DAP)
### Ridge Trace Plot (Sem DAP)
library(glmnet)
library(reshape2)
library(ggplot2)
#---------------------------------------------------------------#
# Ajuste do caminho completo do Ridge (sem fixar lambda)
modelo_ridge_path_dap <- glmnet(
x_train_dap,
y_train_dap,
alpha = 0,
standardize = TRUE
)
#---------------------------------------------------------------#
# Extração dos coeficientes
coefs_dap <- as.matrix(modelo_ridge_path_dap$beta)
lambdas_dap <- modelo_ridge_path_dap$lambda
df_coef_dap <- as.data.frame(t(coefs_dap))
df_coef_dap$log_lambda <- log(lambdas_dap)
#---------------------------------------------------------------#
# Formato longo
df_long_dap <- melt(
df_coef_dap,
id.vars = "log_lambda",
variable.name = "Variavel",
value.name = "Coeficiente"
)
#---------------------------------------------------------------#
# Ridge Trace Plot
ggplot(df_long_dap,
aes(x = log_lambda,
y = Coeficiente,
color = Variavel)) +
geom_line(linewidth = 1.2, alpha = 0.9) +
geom_vline(
xintercept = log(best_lambda_dap),
linetype = "dashed",
linewidth = 1,
color = "red"
) +
labs(
title = "Ridge Trace Plot",
subtitle = "Modelo Ridge (Sem DAP)",
x = expression(log(lambda)),
y = "Coeficientes dos preditores",
color = "Variáveis"
) +
scale_color_brewer(palette = "Dark2") +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 13, color = "gray40"),
legend.title = element_text(size = 11),
legend.text = element_text(size = 10),
legend.position = "right",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85")
)
4.8.2 VIF Trace Plot (Sem DAP)
### VIF Trace Plot (Sem DAP)
library(ggplot2)
library(reshape2)
#---------------------------------------------------------------#
# MATRIZ DE PREDITORES (SEM DAP)
X_dap <- scale(x_train_dap)
#---------------------------------------------------------------#
# SEQUÊNCIA DE k (penalização)
k_values <- exp(seq(
log(1e-4),
log(10),
length.out = 100
))
#---------------------------------------------------------------#
# FUNÇÃO PARA CÁLCULO DO VIF RIDGE
ridge_vif <- function(X, k) {
XtX <- crossprod(X)
A <- solve(XtX + diag(k, ncol(X)))
diag(A %*% XtX %*% A)
}
#---------------------------------------------------------------#
# CÁLCULO DOS VIFS AO LONGO DE k
vif_matrix_dap <- sapply(
k_values,
function(k) ridge_vif(X_dap, k)
)
#---------------------------------------------------------------#
# ORGANIZAÇÃO DOS DADOS
vif_df_dap <- as.data.frame(t(vif_matrix_dap))
colnames(vif_df_dap) <- colnames(X_dap)
vif_df_dap$k <- k_values
vif_long_dap <- melt(
vif_df_dap,
id.vars = "k",
variable.name = "Variavel",
value.name = "VIF"
)
# Remove problemas numéricos
vif_long_dap <- vif_long_dap[
is.finite(vif_long_dap$VIF) & vif_long_dap$VIF > 0,
]
#---------------------------------------------------------------#
# GRÁFICO VIF TRACE PLOT
ggplot(vif_long_dap,
aes(x = log(k),
y = VIF,
color = Variavel)) +
geom_line(linewidth = 1.2, alpha = 0.9) +
geom_hline(
yintercept = 10,
linetype = "dashed",
color = "gray40"
) +
geom_vline(
xintercept = log(best_lambda_dap),
linetype = "dashed",
color = "red",
linewidth = 1
) +
scale_y_log10() +
labs(
title = "VIF Trace Plot",
subtitle = "Modelo Ridge (Sem DAP)",
x = expression(log(k)),
y = "VIF",
color = "Variáveis"
) +
theme_minimal(base_size = 14) +
theme(
legend.position = "right",
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 12, color = "gray40"),
legend.title = element_text(size = 11),
legend.text = element_text(size = 10)
)
4.9 Modelo de Regressão Ridge (Sem DAP + Area Basal)
## Modelo de Regressão Ridge (Sem DAP + Área Basal)
library(dplyr)
library(caret)
library(glmnet)
#---------------------------------------------------------------#
# REMOÇÃO DAS VARIÁVEIS
dados_sem_dap_ab <- dados %>%
select(-DAP, -AREA_BASAL)
#---------------------------------------------------------------#
# DIVISÃO TREINO / TESTE
set.seed(123)
train_idx_dap_ab <- createDataPartition(
dados_sem_dap_ab$VOLUME,
p = 0.9,
list = FALSE
)
dados_treino_dap_ab <- dados_sem_dap_ab[train_idx_dap_ab, ]
dados_teste_dap_ab <- dados_sem_dap_ab[-train_idx_dap_ab, ]
#---------------------------------------------------------------#
# MATRIZES DE PROJETO
x_train_dap_ab <- model.matrix(
VOLUME ~ .,
dados_treino_dap_ab
)[, -1]
y_train_dap_ab <- dados_treino_dap_ab$VOLUME
x_test_dap_ab <- model.matrix(
VOLUME ~ .,
dados_teste_dap_ab
)[, -1]
y_test_dap_ab <- dados_teste_dap_ab$VOLUME
#---------------------------------------------------------------#
# RIDGE COM VALIDAÇÃO CRUZADA
cv_ridge_dap_ab <- cv.glmnet(
x_train_dap_ab,
y_train_dap_ab,
alpha = 0,
standardize = TRUE
)
best_lambda_dap_ab <- cv_ridge_dap_ab$lambda.min
cat(
"Melhor lambda (sem DAP e Área Basal):",
best_lambda_dap_ab, "\n"
)Melhor lambda (sem DAP e Área Basal): 4.345508
#---------------------------------------------------------------#
# MODELO FINAL
modelo_ridge_dap_ab <- glmnet(
x_train_dap_ab,
y_train_dap_ab,
alpha = 0,
lambda = best_lambda_dap_ab,
standardize = TRUE
)
#---------------------------------------------------------------#
# PREDIÇÃO (TESTE)
y_pred_dap_ab <- predict(
modelo_ridge_dap_ab,
s = best_lambda_dap_ab,
newx = x_test_dap_ab
)
#---------------------------------------------------------------#
# MÉTRICAS DE DESEMPENHO
R2_dap_ab <- cor(y_test_dap_ab, y_pred_dap_ab)^2
rmse_dap_ab <- sqrt(mean((y_test_dap_ab - y_pred_dap_ab)^2))
mae_dap_ab <- mean(abs(y_test_dap_ab - y_pred_dap_ab))
mape_dap_ab <- mean(
abs((y_test_dap_ab - y_pred_dap_ab) / y_test_dap_ab)
) * 100
#---------------------------------------------------------------#
# AIC e BIC (APROXIMADOS)
y_pred_train_dap_ab <- predict(
modelo_ridge_dap_ab,
s = best_lambda_dap_ab,
newx = x_train_dap_ab
)
RSS_dap_ab <- sum(
(y_train_dap_ab - y_pred_train_dap_ab)^2
)
df_dap_ab <- modelo_ridge_dap_ab$df[
which.min(
abs(modelo_ridge_dap_ab$lambda - best_lambda_dap_ab)
)
]
n_dap_ab <- nrow(dados_treino_dap_ab)
AIC_dap_ab <- n_dap_ab * log(RSS_dap_ab / n_dap_ab) +
2 * (df_dap_ab + 1)
BIC_dap_ab <- n_dap_ab * log(RSS_dap_ab / n_dap_ab) +
log(n_dap_ab) * (df_dap_ab + 1)
#---------------------------------------------------------------#
# RESULTADOS
cat("\n--- Modelo Ridge SEM DAP e SEM Área Basal ---\n")
--- Modelo Ridge SEM DAP e SEM Área Basal ---
cat(
"R² =", R2_dap_ab,
"\nRMSE =", rmse_dap_ab,
"\nMAE =", mae_dap_ab,
"\nMAPE =", mape_dap_ab,
"\nAIC =", AIC_dap_ab,
"\nBIC =", BIC_dap_ab
)R² = 0.713538
RMSE = 22.66082
MAE = 16.85935
MAPE = 31.39215
AIC = 1476.926
BIC = 1497.45
4.9.1 Ridge Trace Plot (Sem DAP + Area Basal)
library(glmnet)
library(reshape2)
library(ggplot2)
# Ajuste do caminho completo do Ridge
modelo_ridge_dap_ab <- glmnet(
x_train_dap_ab,
y_train_dap_ab,
alpha = 0,
standardize = TRUE
)
# Extração dos coeficientes
coefs_dap_ab <- as.matrix(modelo_ridge_dap_ab$beta)
lambdas_dap_ab <- modelo_ridge_dap_ab$lambda
# Organização dos dados
df_coef_dap_ab <- as.data.frame(t(coefs_dap_ab))
df_coef_dap_ab$log_lambda <- log(lambdas_dap_ab)
df_long_dap_ab <- melt(
df_coef_dap_ab,
id.vars = "log_lambda",
variable.name = "Variavel",
value.name = "Coeficiente"
)
# Gráfico Ridge Trace Plot
ggplot(df_long_dap_ab,
aes(x = log_lambda, y = Coeficiente, color = Variavel)) +
geom_line(linewidth = 1.2, alpha = 0.9) +
geom_vline(
xintercept = log(best_lambda_dap_ab),
linetype = "dashed",
linewidth = 1,
color = "red"
) +
labs(
title = "Ridge Trace Plot",
subtitle = "Modelo Ridge (Sem DAP e Área Basal)",
x = expression(log(lambda)),
y = "Coeficientes dos preditores"
) +
scale_color_brewer(palette = "Dark2") +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 13, color = "gray40"),
legend.position = "right",
legend.title = element_blank(),
legend.text = element_text(size = 11),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85")
)
4.9.2 VIF Trace Plot (Sem DAP + Area Basal)
library(ggplot2)
library(reshape2)
# ---------------- MATRIZ DE PREDITORES ---------------- #
X <- scale(x_train_dap_ab)
# ---------------- SEQUÊNCIA LOGARÍTMICA DE k ---------------- #
k_values <- exp(seq(
log(1e-4),
log(10),
length.out = 100
))
# ---------------- FUNÇÃO VIF RIDGE ---------------- #
ridge_vif <- function(X, k) {
XtX <- crossprod(X)
A <- solve(XtX + diag(k, ncol(X)))
diag(A %*% XtX %*% A)
}
# ---------------- CÁLCULO DOS VIFS ---------------- #
vif_matrix <- sapply(k_values, function(k) ridge_vif(X, k))
# ---------------- ORGANIZAÇÃO DOS DADOS ---------------- #
vif_df <- as.data.frame(t(vif_matrix))
colnames(vif_df) <- colnames(X)
vif_df$log_k <- log(k_values)
vif_long <- melt(
vif_df,
id.vars = "log_k",
variable.name = "Variavel",
value.name = "VIF"
)
# Remoção de problemas numéricos
vif_long <- vif_long[
is.finite(vif_long$VIF) & vif_long$VIF > 0,
]
# ---------------- GRÁFICO FINAL ---------------- #
ggplot(
vif_long,
aes(x = log_k, y = VIF, color = Variavel, group = Variavel)
) +
geom_line(linewidth = 1.5, alpha = 0.9) +
scale_y_log10() +
geom_hline(
yintercept = 10,
linetype = "dashed",
color = "gray40"
) +
geom_vline(
xintercept = log(best_lambda_dap_ab),
linetype = "dashed",
linewidth = 1,
color = "red"
) +
labs(
title = "VIF Trace Plot",
subtitle = "Modelo Ridge (Sem DAP e Área Basal)",
x = expression(log(k)),
y = "VIF Ridge"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 13, color = "gray40"),
legend.position = "right",
legend.title = element_blank(),
panel.grid.minor = element_blank()
)
4.9.3 Modelo Elastic Net (Geral)
## =========================================================
## Elastic Net – Modelo Geral (Ridge + LASSO)
## =========================================================
library(caret)
library(glmnet)
library(dplyr)
library(ggplot2)
set.seed(123)
#--------------------------------------------
# Dados de treino e teste (mesmo padrão)
#--------------------------------------------
train_index_enet <- createDataPartition(dados$VOLUME, p = 0.9, list = FALSE)
dados_treino_enet <- dados[train_index_enet, ]
dados_teste_enet <- dados[-train_index_enet, ]
x_train_enet <- model.matrix(VOLUME ~ ., dados_treino_enet)[, -1]
y_train_enet <- dados_treino_enet$VOLUME
x_test_enet <- model.matrix(VOLUME ~ ., dados_teste_enet)[, -1]
y_test_enet <- dados_teste_enet$VOLUME
#--------------------------------------------
# Grid PODEROSO de alpha e lambda
#--------------------------------------------
alpha_grid <- seq(0.1, 0.9, by = 0.1)
set.seed(123)
cv_results <- lapply(alpha_grid, function(a) {
cv <- cv.glmnet(
x_train_enet,
y_train_enet,
alpha = a,
standardize = TRUE,
nfolds = 10
)
data.frame(
alpha = a,
lambda = cv$lambda.min,
cvm = min(cv$cvm)
)
})
cv_df <- do.call(rbind, cv_results)
best_row <- cv_df[which.min(cv_df$cvm), ]
best_alpha_enet <- best_row$alpha
best_lambda_enet <- best_row$lambda
cat("Alpha ótimo:", best_alpha_enet, "\n")Alpha ótimo: 0.5
cat("Lambda ótimo:", best_lambda_enet, "\n")Lambda ótimo: 0.2475232
modelo_enet <- glmnet(
x_train_enet,
y_train_enet,
alpha = best_alpha_enet,
lambda = best_lambda_enet,
standardize = TRUE
)
y_pred_enet <- predict(modelo_enet, newx = x_test_enet)
R2_enet <- cor(y_test_enet, y_pred_enet)^2
rmse_enet <- sqrt(mean((y_test_enet - y_pred_enet)^2))
mae_enet <- mean(abs(y_test_enet - y_pred_enet))
mape_enet <- mean(abs((y_test_enet - y_pred_enet) / y_test_enet)) * 100
coef_enet <- coef(modelo_enet)
variaveis_enet <- rownames(coef_enet)[
coef_enet[, 1] != 0 & rownames(coef_enet) != "(Intercept)"
]
n <- length(y_train_enet)
y_fitted_enet <- predict(modelo_enet, newx = x_train_enet)
rss_enet <- sum((y_train_enet - y_fitted_enet)^2)
sigma2_enet <- rss_enet / n
logLik_enet <- -n/2 * (log(2 * pi) + log(sigma2_enet) + 1)
df_enet <- modelo_enet$df
AIC_enet <- -2 * logLik_enet + 2 * df_enet
BIC_enet <- -2 * logLik_enet + log(n) * df_enet
cat("\n==============================\n")
==============================
cat("ELASTIC NET — MODELO FINAL\n")ELASTIC NET — MODELO FINAL
cat("==============================\n")==============================
cat("Alpha ótimo:", best_alpha_enet,
"\nLambda ótimo:", best_lambda_enet,
"\nR²:", R2_enet,
"\nRMSE:", rmse_enet,
"\nMAE:", mae_enet,
"\nMAPE:", mape_enet,
"\nAIC:", AIC_enet,
"\nBIC:", BIC_enet,
"\n\nVariáveis selecionadas:\n",
paste(variaveis_enet, collapse = ", "),
"\n")Alpha ótimo: 0.5
Lambda ótimo: 0.2475232
R²: 0.9188018
RMSE: 12.29131
MAE: 10.54561
MAPE: 23.6061
AIC: 1695.341
BIC: 1715.864
Variáveis selecionadas:
IDADE, DAP, ALTURA, DAF, GAP, AREA_BASAL
4.9.4 Comparação dos Modelos
library(dplyr)
library(knitr)
library(kableExtra)
tabela_ridge <- tibble(
Modelo = c(
"Ridge Completo",
"Ridge sem Área Basal",
"Ridge sem DAP",
"Ridge sem DAP e Área Basal",
"Elastic Net"
),
Lambda_Otimo = c(
best_lambda_ridge,
best_lambda_ridge2,
best_lambda_dap,
best_lambda_dap_ab,
best_lambda_enet
),
R2 = c(
R2_ridge,
R2_ridge2,
R2_dap,
R2_dap_ab,
R2_enet
),
RMSE = c(
rmse_ridge,
rmse_ridge2,
rmse_dap,
rmse_dap_ab,
rmse_enet
),
MAE = c(
mae_ridge,
mae_ridge2,
mae_dap,
mae_dap_ab,
mae_enet
),
MAPE = c(
mape_ridge,
mape_ridge2,
mape_dap,
mape_dap_ab,
mape_enet
),
AIC = c(
AIC_ridge,
AIC_ridge2,
AIC_dap,
AIC_dap_ab,
AIC_enet
),
BIC = c(
BIC_ridge,
BIC_ridge2,
BIC_dap,
BIC_dap_ab,
BIC_enet
)
) %>%
mutate(
Lambda_Otimo = round(Lambda_Otimo, 5),
R2 = round(R2, 4),
RMSE = round(RMSE, 3),
MAE = round(MAE, 3),
MAPE = round(MAPE, 2),
AIC = round(AIC, 2),
BIC = round(BIC, 2)
)
kable(
tabela_ridge,
caption = "Comparação dos modelos Ridge",
align = "c"
) %>%
kable_styling(
full_width = FALSE,
position = "center",
bootstrap_options = c("striped", "hover", "condensed")
)| Modelo | Lambda_Otimo | R2 | RMSE | MAE | MAPE | AIC | BIC |
|---|---|---|---|---|---|---|---|
| Ridge Completo | 4.34551 | 0.9127 | 13.252 | 11.535 | 26.40 | 1082.22 | 1109.59 |
| Ridge sem Área Basal | 4.34551 | 0.9215 | 12.706 | 10.966 | 25.40 | 1085.05 | 1109.00 |
| Ridge sem DAP | 4.34551 | 0.9087 | 13.636 | 11.862 | 26.82 | 1091.82 | 1115.77 |
| Ridge sem DAP e Área Basal | 4.34551 | 0.7135 | 22.661 | 16.859 | 31.39 | 1476.93 | 1497.45 |
| Elastic Net | 0.24752 | 0.9188 | 12.291 | 10.546 | 23.61 | 1695.34 | 1715.86 |
library(ggplot2)
library(ggrepel)
df_comp <- data.frame(
Modelo = c(
"Geral",
"Sem Área Basal",
"Sem DAP",
"Sem DAP/Área Basal",
"Elastic Net"
),
RMSE = c(
rmse_ridge,
rmse_ridge2,
rmse_dap,
rmse_dap_ab,
rmse_enet
),
AIC = c(
AIC_ridge,
AIC_ridge2,
AIC_dap,
AIC_dap_ab,
AIC_enet
)
)
ggplot(df_comp, aes(x = AIC, y = RMSE, label = Modelo)) +
geom_point(size = 4, color = "firebrick") +
geom_text_repel(size = 4, box.padding = 0.4) +
labs(
title = "",
subtitle = "",
x = "AIC",
y = "RMSE"
) +
theme_minimal(base_size = 14)