Previsão em R
com o pacote nnet para redes neurais
As redes neurais são muito importantes e são amplamente utilizadas no aprendizado de máquina. Eles têm a capacidade de aprender automaticamente os recursos dos dados de entrada nos quais executam tarefas.
As redes neurais também são chamadas de redes neurais artificiais .
Tenho alguns dados de reservas que quero analisar usando uma rede neural, mas achei que seria apropriado esclarecer algumas frases que costumam ser usadas antes de entrar no lado R das coisas.
Como funcionam as redes neurais:
As redes neurais funcionam usando um grande número de neurônios interconectados. (neurônios artificiais) para processar e transformar dados de entrada , usando funções de ativação e pesos aprendidos durante o processo de treinamento do modelo. A intenção é produzir saídas que minimizem uma função perda/custo.
As etapas incluem:
- Camada de entrada: dados de entrada
- Camadas ocultas: podem ser variadas para controlar a complexidade da rede.
- Funções de ativação: função sigmoide , função tangente hiperbólica e função da unidade linear retificada (ReLU) .
- Termos de ponderação e viés
- Propagação: propagação direta.
- Treinamento: inicializado aleatoriamente
- Avaliação: avaliado em um conjunto de teste
Eu adicionei algumas definições abaixo antes de começarmos.
- Propagação direta — o processo de passar dados de entrada através de uma rede neural para produzir uma saída.
- Backpropagation — um algoritmo usado para treinar os pesos e vieses do modelo para que as previsões sejam as mais precisas possíveis. O objetivo é minimizar uma função de perda que mede a diferença entre a saída prevista e a saída real.
- Convergência — o processo pelo qual os parâmetros de um modelo se aproximam de um conjunto de valores ótimos que minimizam uma função de perda, com o objetivo de encontrar pesos e vieses que produzam a menor função de perda possível.
- Nó — uma unidade matemática que representa um neurônio.
- Funções de ativação — funções matemáticas usadas para introduzir não linearidade no modelo. Eles são aplicados à soma ponderada das entradas em cada nó da rede, e a saída da função de ativação determina a saída do nó .
- Pesos — referem-se aos valores atribuídos às conexões entre neurônios/nós que representam a força das conexões.
- Função de perda — também conhecida como função de custo, uma função matemática usada para medir a diferença entre a saída prevista e a saída real do modelo.
library(knitr)
library(tidyverse)
opts_chunk$set(fig.width=9, fig.height=7)
opts_chunk$set(comment="", fig.align="center", tidy=TRUE, fig.retina=2, cache = TRUE)
library(broom)
library(yardstick)
library(parsnip)
library(nnet)
library(patchwork)
library(rsample)
library(recipes)
data <- read_csv("https://raw.githubusercontent.com/NicJC/Hotel-reservations/main/Hotel_Reservations.csv")
data %>% names()
booking <- data.frame(
No_Adults = data$no_of_adults,
arrival_day = data$arrival_date,
arrival_month = data$arrival_month ,
year = data$arrival_year,
Qty_weekNights = data$no_of_week_nights,
Qty_weekendNights = data$no_of_weekend_nights,
room_type = data$room_type_reserved,
AvgPricePerRoom = data$avg_price_per_room
)
booking %>% head(n=8)
skimr::skim(booking)
Eu quero dar uma olhada nos dados:
booking %>% ggplot() +
geom_point(mapping = aes(
y= Qty_weekendNights ,
x = No_Adults ,
col = as.factor(arrival_month),
size = as.factor(year))) +
labs(title = "Weekend Nights booked by quantity of adults per month",
color = "Arrival Month",
x = "Number of Adults",
y = "Weekens Nights booked",
size = "year"
)
Vou criar 5 modelos para avaliar os dados das reservas. Estou interessado na variável “Qty_weekendNights” que farei a variável de destino ou a resposta.
Também preciso dividir os dados em um conjunto de treinamento e teste. Vou usar uma divisão de 25/75%:
set.seed(1784)
split <- initial_split(booking, prop=3/4)
train <- training(split)
test <- testing(split)
Eu defino a semente para fins de repetibilidade. Se eu quiser fazer o mesmo experimento, posso usar a mesma semente.
Agora o primeiro modelo:
set.seed(2982)
model1<- nnet(Qty_weekendNights ~ ., data = train, linout=TRUE, size=11)
Tamanho refere-se ao número de unidades na camada oculta. 11 é demais.
set.seed(7365)
model2<- nnet(Qty_weekendNights ~ ., data = train,
linout=TRUE,
size=6,
decay=0.01,
maxit=1000
)
O número ideal (tamanho) de unidades na camada oculta deve ser o número de preditores efetivos (7) dividido por 2, arredondado para cima. 4 deve ser um bom número.
set.seed(8)
model3<- nnet(Qty_weekendNights ~ ., data = train, linout=FALSE, size=4)
set.seed(168)
model4<- nnet(Qty_weekendNights ~ ., data = train,
linout=TRUE,
size=4,
decay = 0.01 ,
maxit = 1000,
Hess = TRUE)
Os mínimos locais podem ser problemáticos porque o modelo encontrará um conjunto de pesos que produz um erro baixo nos dados de treinamento, mas esse erro pode não ser o menor possível. Idealmente, queremos o mínimo global.
Se Hess = TRUE, esperamos retornar o melhor conjunto de pesos.
Outra maneira de ajustar uma rede neural e obter métricas. Esta forma de encaixe dos modelos requer a embalagem da pastinaca .
set.seed(814)
model5 <- mlp(mode="regression", engine="nnet", hidden_units=4, penalty=0.01,
epochs = 1000)
fit1 <- model5 %>% fit(Qty_weekendNights ~ ., data=train)
fit1 %>% extract_fit_engine() %>% pluck("convergence")
pred1 <- fit1 %>% augment(new_data=test)
pred1 %>% metrics(truth=Qty_weekendNights, estimate=.pred)
O 0 acima refere-se a pluck(“convergência”) que produzirá um 0 se o modelo convergiu ou um “1” se o máximo de iterações foi atingido.
Verificarei as métricas do modelo para os modelos 1–4:
modelo 4
pred <- test %>%
bind_cols(pred = predict(model4, newdata=test) %>% as.numeric())
pred %>%
metrics(truth=Qty_weekendNights, estimate=pred)
pred2 <- test %>%
bind_cols(pred = predict(model3, newdata=test) %>% as.numeric())
pred2 %>%
metrics(truth=Qty_weekendNights, estimate=pred)
pred3 <- test %>%
bind_cols(pred = predict(model2, newdata=test) %>% as.numeric())
pred3 %>%
metrics(truth=Qty_weekendNights, estimate=pred)
pred4 <- test %>%
bind_cols(pred = predict(model1, newdata=test) %>% as.numeric())
pred4 %>%
metrics(truth=Qty_weekendNights, estimate=pred)
pred1 <- fit1 %>% augment(new_data=test)
pred1
Conclusão
Eu ajustei algumas redes neurais e usei vários parâmetros para tentar obter um ajuste melhor.
a decadência é muito importante, pois afetará sua função de custo/perda. O decaimento do peso refere-se a uma técnica que visa evitar o overfitting adicionando um termo de penalidade à função de custo. O overfitting ocorre quando um modelo se torna muito complexo e se ajusta muito bem aos dados de treinamento. 0,01 para o parâmetro de decaimento geralmente é um bom número a ser usado.
Vale a pena brincar com os parâmetros e criar vários modelos que você compara entre si por meio de métricas de modelo.
Eu usei muito o operador pipe %>% em meu código. Se você quiser saber mais sobre tubulação, confira meu artigo abaixo:
Tubulação com REspero que você tenha gostado do artigo e tenha achado útil.
Siga-me para mais artigos sobre R, Julia, Python e estatística aplicada!





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)