O pacote ensinado pelo livro do Lantz, o neuralnet
está desatualizado e algumas funções importantes não estão funcionando mais. Aproveitando isso, resolvi fazer tudo usando o nnet
mas dentro do tidymodels
, para aprender a fazer já algo mais organizado e seriado.
setwd('/home/heitor/Área de Trabalho/R Projects/Análise Macro/Lab 9')
library(tidyverse)
library(tidymodels)
library(nnet)
library(NeuralNetTools)
<- read_csv("concrete.csv")
dds <- initial_split(dds)
slice_1 <- training(slice_1)
train <- testing(slice_1) test
Vamos criar a estrutura geral do nosso modelo, deixando espaços livres com tune()
por serem os parâmetros a serem testados com vários números, reiteragas vezes.
<- mlp(
nnet_1 hidden_units = integer(tune()),
penalty = double(tune()),
activation = 'linear') %>%
set_mode("regression") %>%
set_engine("nnet", verbose = 0)
# traduzir para pô-lo em termos de nnet:
%>% translate() nnet_1
## Single Layer Neural Network Specification (regression)
##
## Main Arguments:
## hidden_units = integer(tune())
## penalty = double(tune())
## activation = linear
##
## Engine-Specific Arguments:
## verbose = 0
##
## Computational engine: nnet
##
## Model fit template:
## nnet::nnet(formula = missing_arg(), data = missing_arg(), weights = missing_arg(),
## size = integer(tune()), decay = double(tune()), verbose = 0,
## trace = FALSE, linout = TRUE)
Defino como os dados alimentarão o modelo já descrito acima e aplico um tratamento de normalização nos dados, usando desvio da média e desvio-padrão.
<- recipe(strength~.,
recipe_1 data = train) %>%
step_normalize(all_numeric_predictors()) %>%
prep()
%>% bake(new_data=NULL) recipe_1
## # A tibble: 772 × 9
## cement slag ash water superplastic coarseagg fineagg age strength
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.488 -0.866 -0.861 0.469 -1.04 0.667 0.597 -0.599 17.4
## 2 1.39 -0.609 1.20 -0.628 0.443 -1.87 -0.288 0.157 74.4
## 3 0.444 -0.866 1.29 0.789 0.760 -2.13 0.242 -0.275 38.6
## 4 -1.11 -0.866 1.69 -0.240 -0.290 1.09 0.0870 -0.661 10.8
## 5 -0.273 -0.866 0.681 -1.62 1.33 0.202 1.45 0.835 61.0
## 6 0.0557 1.48 -0.861 -1.69 0.826 0.412 0.381 -0.599 38
## 7 0.507 -0.662 1.68 -0.674 1.94 0.305 -1.51 -0.275 47.3
## 8 0.662 -0.866 -0.861 0.469 -1.04 1.05 0.447 0.681 40.7
## 9 -0.273 -0.866 0.681 -1.62 1.33 0.202 1.45 -0.491 42.3
## 10 0.729 -0.866 1.35 0.529 0.793 -2.13 0.0658 -0.275 40.9
## # … with 762 more rows
Junto o modelo descrito e os dados tratados, formando um workflow:
<- workflow() %>%
nnet_1_wrkflw add_model(nnet_1) %>%
add_recipe(recipe_1)
Defino a validação cruzada em grupos de cinco, ou seja, a amostra de treino será \(\frac{4}{5}\) passando por várias reamostragens.
<- vfold_cv(train, v = 5) valid_1
Treinaremos o modelo com vários parâmetros e selecionaremos de acordo com ccc
: coeficiente de concordância de correlação. Mostraremos um gráfico com os parâmetros testados.
<- nnet_1_wrkflw %>%
nnet_1_trained tune_grid(valid_1,
grid = 15,
control = control_grid(save_pred = T),
metrics = metric_set(ccc, mae))
%>% show_best(n=15) nnet_1_trained
## # A tibble: 15 × 8
## hidden_units penalty .metric .estimator mean n std_err .config
## <int> <dbl> <chr> <chr> <dbl> <int> <dbl> <chr>
## 1 8 5.14e- 3 ccc standard 0.914 5 0.0119 Preprocessor1_M…
## 2 10 1.44e- 5 ccc standard 0.907 5 0.0103 Preprocessor1_M…
## 3 6 1.07e- 6 ccc standard 0.907 5 0.00735 Preprocessor1_M…
## 4 9 1.18e- 8 ccc standard 0.905 5 0.0158 Preprocessor1_M…
## 5 9 2.70e- 2 ccc standard 0.905 5 0.00910 Preprocessor1_M…
## 6 7 4.88e-10 ccc standard 0.903 5 0.0166 Preprocessor1_M…
## 7 5 1.93e- 1 ccc standard 0.902 5 0.00796 Preprocessor1_M…
## 8 7 8.53e- 5 ccc standard 0.899 5 0.00750 Preprocessor1_M…
## 9 4 8.57e- 7 ccc standard 0.898 5 0.0114 Preprocessor1_M…
## 10 4 2.53e- 4 ccc standard 0.898 5 0.00978 Preprocessor1_M…
## 11 6 2.18e-10 ccc standard 0.894 5 0.0129 Preprocessor1_M…
## 12 3 4.71e- 8 ccc standard 0.886 5 0.0128 Preprocessor1_M…
## 13 2 2.38e- 1 ccc standard 0.878 5 0.0113 Preprocessor1_M…
## 14 2 5.39e- 4 ccc standard 0.857 5 0.0161 Preprocessor1_M…
## 15 1 4.14e- 9 ccc standard 0.595 5 0.151 Preprocessor1_M…
# (6.1) Auto-plot ---
::autoplot(nnet_1_trained) ggplot2
Selecionaremos o melhor modelo, usando o ccc
.
<- select_best(nnet_1_trained, 'ccc')
best_tune <- nnet_1 %>%
nnet_final finalize_model(best_tune)
Aplicaremos esse modelo, nnet_final
na partição feita em slice_1
e com a organização dos dados de acordo com recipe_1
. Vemos que conseguimos aumentar para 92.37% a correlação entre previsto e verdadeiro.
<- workflow() %>%
nnet_final_wrkflw add_recipe(recipe_1) %>%
add_model(nnet_final) %>%
last_fit(slice_1) %>%
collect_predictions()
nnet_final_wrkflw
## # A tibble: 258 × 5
## id .pred .row strength .config
## <chr> <dbl> <int> <dbl> <chr>
## 1 train/test split 23.9 1 29.9 Preprocessor1_Model1
## 2 train/test split 27.8 18 44.9 Preprocessor1_Model1
## 3 train/test split 22.6 22 21.9 Preprocessor1_Model1
## 4 train/test split 24.6 25 31.7 Preprocessor1_Model1
## 5 train/test split 45.3 27 49.2 Preprocessor1_Model1
## 6 train/test split 32.7 30 33.8 Preprocessor1_Model1
## 7 train/test split 38.4 32 39.3 Preprocessor1_Model1
## 8 train/test split 59.8 34 44.5 Preprocessor1_Model1
## 9 train/test split 21.3 39 17.5 Preprocessor1_Model1
## 10 train/test split 39.0 43 37.4 Preprocessor1_Model1
## # … with 248 more rows
cor(nnet_final_wrkflw$.pred, nnet_final_wrkflw$strength)
## [1] 0.9282894
Por fim, faço duas ilustrações: um plot dos dados originais contra os previstos, com a estimação perfeita sendo a linha vermelha; e a representação da rede neural.
%>%
nnet_final_wrkflw select(.row, .pred, strength) %>%
ggplot() +
aes(x = strength,
y = .pred) +
geom_point() +
geom_abline(intercept = 0,
slope = 1,
color ='red',
size = .8)
Para fazer a representação da rede neural, precisamos traduzir o que foi feito em mlp()
para colocar como um objeto nnet
e fazer o gráfico.
%>% translate() nnet_final
## Single Layer Neural Network Specification (regression)
##
## Main Arguments:
## hidden_units = 8
## penalty = 0.00514168063170647
## activation = linear
##
## Engine-Specific Arguments:
## verbose = 0
##
## Computational engine: nnet
##
## Model fit template:
## nnet::nnet(formula = missing_arg(), data = missing_arg(), weights = missing_arg(),
## size = 8L, decay = 0.00514168063170647, verbose = 0, trace = FALSE,
## linout = TRUE)
<-nnet(strength ~ cement+slag+ash+water+superplastic+coarseagg+fineagg+age,
nnet3 size = 8, # as penalty
data = recipe(strength~., data = train) %>%
step_normalize(all_numeric_predictors()) %>%
prep() %>% bake(new_data=NULL),
decay = 0.0218099079606513,
verbose = 0, trace = FALSE,
linout = TRUE)
%>% plotnet() nnet3