Definições da sessão
#-----------------------------------------------------------------------
# Prof. Dr. Walmes M. Zeviani
# leg.ufpr.br/~walmes · github.com/walmes
# walmes@ufpr.br · @walmeszeviani
# Laboratory of Statistics and Geoinformation (LEG)
# Department of Statistics · Federal University of Paraná
# 2020-jun-14 · Curitiba/PR/Brazil
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Pacotes.
library(caret)
library(tidyverse)
library(readxl)
Importação e inspeção
#-----------------------------------------------------------------------
# Importação.
tb <- read_excel("./Fungo teca_W.xlsx")
str(tb)
## tibble [206 × 12] (S3: tbl_df/tbl/data.frame)
## $ Local : num [1:206] 1 1 2 2 3 3 4 4 5 5 ...
## $ Fungo : num [1:206] 1 1 1 1 1 1 1 1 1 1 ...
## $ Camada : chr [1:206] "0-0.1" "0,4-0.6" "0-0.1" "0,4-0.6" ...
## $ COS : num [1:206] NA NA 23.8 NA 23.6 ...
## $ MOS : num [1:206] NA NA 41 NA 40.6 ...
## $ Areia : num [1:206] NA 43.9 58.1 NA 53.7 ...
## $ Silte : num [1:206] NA 13.4 16.6 NA 25.1 ...
## $ Argila : num [1:206] NA 42.7 25.2 NA 21.1 ...
## $ Gradiente textura: num [1:206] NA NA NA NA NA ...
## $ pH : num [1:206] 7.27 7.38 6.7 NA 6.18 ...
## $ Umidade : num [1:206] NA 0.303 0.222 NA 0.321 ...
## $ Gradiente umidade: num [1:206] NA NA NA NA NA ...
names(tb) %>%
str_to_lower() %>%
dput()
## c("local", "fungo", "camada", "cos", "mos", "areia", "silte",
## "argila", "gradiente textura", "ph", "umidade", "gradiente umidade"
## )
names(tb) <- c("local", "fungo", "camada", "cos", "mos", "areia",
"silte", "argila", "gtextura", "ph", "umidade",
"gumidade")
#-----------------------------------------------------------------------
# Inpeção.
# Quantidade de camadas.
tb$camada %>%
unique()
## [1] "0-0.1" "0,4-0.6"
# Percentual de preenchimento das variáveis.
tb %>%
group_by(camada) %>%
summarise_all(~sum(!is.na(.))/length(.)) %>%
ungroup() %>%
gather("var", "val", cos:gumidade) %>%
ggplot(mapping = aes(x = var, y = val, fill = camada)) +
geom_col(position = "dodge") +
labs(x = "Variável", y = "Preenchimento", fill = "Camada") +
scale_fill_manual(values = c("navy", "purple"))

# Criar a tabela analítica de dados.
tb_a <- tb %>%
filter(camada == "0-0.1") %>%
select(-gtextura, -gumidade, -camada)
tb_a
## # A tibble: 103 x 9
## local fungo cos mos areia silte argila ph umidade
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 1 NA NA NA NA NA 7.27 NA
## 2 2 1 23.8 41.0 58.2 16.6 25.2 6.70 0.222
## 3 3 1 23.6 40.6 53.7 25.1 21.1 6.18 0.321
## 4 4 1 NA NA NA NA NA NA NA
## 5 5 1 22.6 38.9 19.9 47.3 32.8 6.52 0.434
## 6 6 1 23.6 40.6 52.1 24.6 23.3 4.94 0.303
## 7 7 1 NA NA 39.8 20.7 39.5 5.91 0.309
## 8 8 1 21.5 37.0 12.2 52.0 35.8 6.26 0.446
## 9 9 1 23.7 40.9 57.2 21.6 21.2 6.06 0.263
## 10 10 1 18.0 31.1 28.1 51.2 20.6 6.16 0.392
## # … with 93 more rows
tb_b <- tb %>%
filter(camada != "0-0.1") %>%
select(local, gtextura, gumidade)
tb_b
## # A tibble: 103 x 3
## local gtextura gumidade
## <dbl> <dbl> <dbl>
## 1 1 NA NA
## 2 2 NA NA
## 3 3 NA NA
## 4 4 NA NA
## 5 5 1.40 0.837
## 6 6 1.39 1.13
## 7 7 1.03 0.991
## 8 8 1.26 0.950
## 9 9 1.76 1.16
## 10 10 1.31 1.20
## # … with 93 more rows
tbu <- full_join(tb_a, tb_b) %>%
select(-local, -silte, -cos)
## Joining, by = "local"
str(tbu)
## tibble [103 × 8] (S3: tbl_df/tbl/data.frame)
## $ fungo : num [1:103] 1 1 1 1 1 1 1 1 1 1 ...
## $ mos : num [1:103] NA 41 40.6 NA 38.9 ...
## $ areia : num [1:103] NA 58.1 53.7 NA 19.9 ...
## $ argila : num [1:103] NA 25.2 21.1 NA 32.8 ...
## $ ph : num [1:103] 7.27 6.7 6.18 NA 6.52 ...
## $ umidade : num [1:103] NA 0.222 0.321 NA 0.434 ...
## $ gtextura: num [1:103] NA NA NA NA 1.4 ...
## $ gumidade: num [1:103] NA NA NA NA 0.837 ...
Análise exploratória
#-----------------------------------------------------------------------
# Análise exploratória.
tbu %>%
gather(key = "var", value = "val", -fungo) %>%
drop_na() %>%
ggplot(mapping = aes(x = val, y = fungo)) +
facet_wrap(facets = ~var, scale = "free_x") +
geom_point() +
geom_smooth(se = FALSE)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

# Percentual de preenchimento das variáveis.
tbu %>%
summarise_all(~sum(!is.na(.))/length(.)) %>%
ungroup() %>%
gather("var", "val", mos:gumidade) %>%
ggplot(mapping = aes(x = reorder(var, val), y = val)) +
geom_col() +
labs(x = "Variável", y = "Preenchimento")

lattice::splom(tbu)

# Versão sem valores ausentes.
tbuc <- drop_na(tbu)
# Diferença na distribuição com e sem casos completos.
list(dirty = tbu, clean = tbuc) %>%
bind_rows(.id = "condition") %>%
gather("var", "val", -condition) %>%
ggplot(mapping = aes(x = val, color = condition)) +
facet_wrap(facets = ~var, scale = "free") +
geom_density()

Regressão logística
#-----------------------------------------------------------------------
# Regressão logística.
# Ajuste do modelo.
m0 <- glm(fungo ~ ., data = tbuc, family = quasibinomial)
# Diagnóstico.
par(mfrow = c(2, 2))
plot(m0)

layout(1)
# Nada é significativo.
summary(m0)
##
## Call:
## glm(formula = fungo ~ ., family = quasibinomial, data = tbuc)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.7318 -1.1388 0.7280 0.8634 1.6500
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -5.042138 10.068446 -0.501 0.619
## mos 0.071744 0.047091 1.524 0.134
## areia -0.001934 0.059950 -0.032 0.974
## argila -0.068304 0.083765 -0.815 0.418
## ph 0.066258 0.460778 0.144 0.886
## umidade 3.626580 10.785997 0.336 0.738
## gtextura -0.003947 1.574043 -0.003 0.998
## gumidade 3.002416 2.561026 1.172 0.246
##
## (Dispersion parameter for quasibinomial family taken to be 1.080562)
##
## Null deviance: 80.837 on 60 degrees of freedom
## Residual deviance: 71.375 on 53 degrees of freedom
## AIC: NA
##
## Number of Fisher Scoring iterations: 6
summary(m0)$coefficients
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -5.042138248 10.06844551 -0.500786168 0.6185951
## mos 0.071743525 0.04709085 1.523513093 0.1335755
## areia -0.001933691 0.05995023 -0.032254944 0.9743899
## argila -0.068303537 0.08376452 -0.815423256 0.4184795
## ph 0.066258300 0.46077810 0.143796550 0.8862065
## umidade 3.626580107 10.78599676 0.336230409 0.7380247
## gtextura -0.003947107 1.57404267 -0.002507624 0.9980086
## gumidade 3.002415991 2.56102614 1.172348828 0.2462998
drop1(m0, test = "F")
## Single term deletions
##
## Model:
## fungo ~ mos + areia + argila + ph + umidade + gtextura + gumidade
## Df Deviance F value Pr(>F)
## <none> 71.375
## mos 1 74.094 2.0189 0.1612
## areia 1 71.376 0.0008 0.9771
## argila 1 72.112 0.5472 0.4627
## ph 1 71.397 0.0166 0.8981
## umidade 1 71.497 0.0906 0.7646
## gtextura 1 71.375 0.0000 0.9982
## gumidade 1 73.417 1.5159 0.2237
# Modelo nulo.
m00 <- update(m0, formula = . ~ 1, data = model.frame(m0))
# Razão entre modelos encaixados.
anova(m00, m0, test = "F")
## Analysis of Deviance Table
##
## Model 1: fungo ~ 1
## Model 2: fungo ~ mos + areia + argila + ph + umidade + gtextura + gumidade
## Resid. Df Resid. Dev Df Deviance F Pr(>F)
## 1 60 80.837
## 2 53 71.375 7 9.4622 1.251 0.2925
# COMMENT: regressão logística não identificou variáveis relevantes para
# explicar a resposta.
Florestas aleatórias
#-----------------------------------------------------------------------
# Randon forest.
# Cria fator.
tbuc$Fungo <- factor(tbuc$fungo)
# 10 repetições independentes de 5 dobras.
control <- trainControl(method = "repeatedcv",
number = 5,
repeats = 10,
search = "grid")
# Grid do hiperparâmetro.
tunegrid <- expand.grid(.mtry = (1:(ncol(tbu) - 1)))
# Ajusta todos os modelos para selecionar o melhor valor do mtry.
set.seed(2020)
rf_gridsearch <- train(Fungo ~ .,
data = tbuc[, -1],
method = "rf",
metric = "Accuracy",
tuneGrid = tunegrid,
trControl = control)
# Resultados.
print(rf_gridsearch)
## Random Forest
##
## 61 samples
## 7 predictor
## 2 classes: '0', '1'
##
## No pre-processing
## Resampling: Cross-Validated (5 fold, repeated 10 times)
## Summary of sample sizes: 49, 50, 48, 48, 49, 49, ...
## Resampling results across tuning parameters:
##
## mtry Accuracy Kappa
## 1 0.5076457 -0.14715218
## 2 0.5193124 -0.09621316
## 3 0.5159557 -0.09190607
## 4 0.5123893 -0.09813724
## 5 0.5140326 -0.08794582
## 6 0.5205944 -0.07684311
## 7 0.5153147 -0.08777485
##
## Accuracy was used to select the optimal model using the
## largest value.
## The final value used for the model was mtry = 6.
plot(rf_gridsearch)

# Incluindo o erro padrão.
rf_gridsearch$results %>%
ggplot(mapping = aes(x = mtry, y = Accuracy)) +
geom_point() +
geom_line() +
geom_errorbar(mapping = aes(ymin = Accuracy - AccuracySD,
ymax = Accuracy + AccuracySD),
width = 0.1)

# Usa a raíz do número de variáveis mesmo.
set.seed(3030)
tunegrid <- expand.grid(.mtry = round(sqrt(7), 0))
rf_final <- train(Fungo ~ .,
data = tbuc[, -1],
method = "rf",
metric = "Accuracy",
tuneGrid = tunegrid,
trControl = control)
rf_final
## Random Forest
##
## 61 samples
## 7 predictor
## 2 classes: '0', '1'
##
## No pre-processing
## Resampling: Cross-Validated (5 fold, repeated 10 times)
## Summary of sample sizes: 48, 49, 49, 49, 49, 48, ...
## Resampling results:
##
## Accuracy Kappa
## 0.4952331 -0.1470569
##
## Tuning parameter 'mtry' was held constant at a value of 3
# Gráfico de importância das variáveis.
# plot(varImp(rf_final, scale = TRUE))
plot(varImp(rf_final, scale = FALSE))

# Matriz de confução (média).
confusionMatrix(rf_final)
## Cross-Validated (5 fold, repeated 10 times) Confusion Matrix
##
## (entries are percentual average cell counts across resamples)
##
## Reference
## Prediction 0 1
## 0 5.7 18.5
## 1 32.0 43.8
##
## Accuracy (average) : 0.4951
# Lista com os indices de treino e teste.
out <- rf_final$control$indexOut
int <- rf_final$control$index
# NOTE: a predição aqui está sendo feita como modelo final que usa todos
# os dados e não uma particação. Dessa forma, a avaliação da performance
# é otimista.
results <-
map_dfr(out,
function(i) {
cm <- confusionMatrix(
data = predict(rf_final,
newdata = tbuc[i, ]),
reference = tbuc[i, ]$Fungo)
as.data.frame(as.list(cm$overall))
})
str(results)
## 'data.frame': 50 obs. of 7 variables:
## $ Accuracy : num 1 1 1 1 1 1 1 1 1 1 ...
## $ Kappa : num 1 1 1 1 1 1 1 1 1 1 ...
## $ AccuracyLower : num 0.753 0.735 0.735 0.735 0.735 ...
## $ AccuracyUpper : num 1 1 1 1 1 1 1 1 1 1 ...
## $ AccuracyNull : num 0.615 0.667 0.583 0.667 0.583 ...
## $ AccuracyPValue: num 0.00182 0.00771 0.00155 0.00771 0.00155 ...
## $ McnemarPValue : num NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
# Junta com a acurácia feita nos dados de teste.
results <- rf_final$resample %>%
rename_all(~paste0(., "_")) %>%
bind_cols(results) %>%
arrange(Accuracy_) %>%
mutate(index = seq_along(AccuracyNull))
# Acurácia do modelo final contra o modelo nulo.
ggplot(data = results,
mapping = aes(x = index,
xend = index,
y = AccuracyNull,
yend = Accuracy_)) +
geom_segment() +
geom_point(mapping = aes(shape = "Mod. Nulo")) +
geom_point(mapping = aes(y = Accuracy_, shape = "Mod. Ajustado")) +
labs(x = "Reamostragem", y = "Acurácia") +
scale_shape_manual(name = "Performance",
values = c(19, 1))

# Resultado médio.
rf_final$resample %>%
summarise_at("Accuracy", "mean")
## Accuracy
## 1 0.4952331
confusionMatrix(rf_final)
## Cross-Validated (5 fold, repeated 10 times) Confusion Matrix
##
## (entries are percentual average cell counts across resamples)
##
## Reference
## Prediction 0 1
## 0 5.7 18.5
## 1 32.0 43.8
##
## Accuracy (average) : 0.4951
#-----------------------------------------------------------------------