Nessa aula veremos com mais detalhes como usar as medidas de desempenho. Suponha que a base de dados está dividida em treino e teste e que a base de treino foi usada para ajustar o modelo.
Para os problemas de regressão a variável resposta \(Y\) é quantitativa contínua. Suponha que um modelo de regressão \(k\) realizou a previsão \(\hat{y}_i^k\) para a i-ésima observação da variável \(Y\). Suponha que \(y_i\) seja o real valor observado para a i-ésima observação da variável \(Y\). Para comparar os diferentes modelos vamos seguir os seguintes passos.
Primeiro calculamos a previsão da variável resposta \(Y\) para cada unidade amostral com cada um dos modelos ajustados. A tabela abaixo representa os valores calculados.
i | Valor observado | Previsão para o Modelo 1 | Previsão para o Modelo 2 | Previsão para o Modelo 3 |
---|---|---|---|---|
1 | \(y_1\) | \(\hat y_1^1\) | \(\hat y_1^2\) | \(\hat y_1^3\) |
2 | \(y_2\) | \(\hat y_2^1\) | \(\hat y_2^2\) | \(\hat y_2^3\) |
3 | \(y_3\) | \(\hat y_3^1\) | \(\hat y_3^2\) | \(\hat y_3^3\) |
… | … | … | … | … |
N | \(y_N\) | \(\hat y_N^1\) | \(\hat y_N^2\) | \(\hat y_N^3\) |
Uma vez conhecidas as previsões para a variável resposta considerando todos os modelos ajusatados, podemos calcular o SSE (soma dos erros ao quadrado) ou MSE (média dos erros ao quadrado) para cada um deles.
Soma dos erros ao quadrado: \[ SSE^k = \sum_{i=1}^N (\hat{y}_i ^k - y_i)^2 \]
Erro médio quadrático: \[ MSE^k = \dfrac{1}{N} \sum_{i=1}^N (\hat{y}_i^k - y_i)^2 \]
Vamos supor que a medida escolhida para comparação doi o MSE. Veja que a conta acima pode ser feita considerando tanto a base de treino quanto a base de teste. Em geral vamos medir o MSE (ou SSE) para as duas bases. Nesse caso podemos criar a seguinte tabela, que vai nos ajudar a decidir qual dos modelos é aquele mais adequado.
Modelo | MSE na base de treino | MSE na base de teste |
---|---|---|
1 | \(MSE^1_{treino}\) | \(MSE^1_{teste}\) |
2 | \(MSE^2_{treino}\) | \(MSE^2_{teste}\) |
3 | \(MSE^3_{treino}\) | \(MSE^3_{teste}\) |
O modelo com menor MSE na base de teste será aquele que parece ter melhor desempenho. Porpém observar o valor do MSE na base de treino pode nos trazer informações importantes. Por exemplo, se um modelo apresenta MSE na base de treino bem menor que o MSE na base de teste, principalmente quando comparado com os outros modelos, percebemos que para este modelo em questão está ocorrendo o sobreajuste (overfiting).
Outras informações que podemos extrair da comparação entre os valores do MSE é sober a importancia de uma covariável ou a inclusão de uma nova camada na rede. Se a diferença entre dois modelos é algo pontual, onde um indica a simplificação do outro, a comparação dos valores do MSE tanto na base de treino quanto na base de teste indica o quanto esse complicador pontual acrescentado no modelo mais complexo contribuiu na previsão da variável resposta.
Vamos usar o exemplo da aula prática. Considere a base de dados
composta pelas variáveis: age
, sex
,
bmi
, children
, smoker
,
region
, charges
. Vamos ajustar diferentes
modelos de redes neurais perceptron camada única para prever o custo de
um cliente. A difereça entre os diferentes modelos é apenas as
covariáveis usadas como entrada.
library(caret)
library(tidyverse)
library(neuralnet)
base = read.csv2("insurance.csv",sep = ",",dec=".")
base = tibble::as_tibble(base)
set.seed(123456789)
N = dim(base)[1]
indices_treino = createDataPartition(1:N,p=0.7)[[1]]
base_treino = base[indices_treino,]
base_teste = base[-indices_treino,]
scale = scale(base_treino$age)
age_ = scale[,1]
media_age = attr(scale,"scaled:center")
dp_age = attr(scale,"scaled:scale")
scale = scale(base_treino$bmi)
bmi_ = scale[,1]
media_bmi = attr(scale,"scaled:center")
dp_bmi = attr(scale,"scaled:scale")
scale = scale(base_treino$children)
children_ = scale[,1]
media_children = attr(scale,"scaled:center")
dp_children = attr(scale,"scaled:scale")
scale = scale(base_treino$charges)
charges_ = scale[,1]
media_charges = attr(scale,"scaled:center")
dp_charges = attr(scale,"scaled:scale")
#completar como ficam as variaveis quantitativas depos da base modificada
base_treino_ = base_treino |> mutate(age = age_,
bmi = bmi_,
children = children_,
charges = charges_)
matriz_treino_ <- model.matrix( ~ age + sex + bmi + children + smoker + region + charges, data = base_treino_)
#modelo completo
modelo_1 = neuralnet(charges ~ age + sexmale + bmi + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem idade
modelo_2 = neuralnet(charges ~ sexmale + bmi + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem sexo
modelo_3 = neuralnet(charges ~ age + bmi + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem bmi
modelo_4 = neuralnet(charges ~ age + sexmale + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem children
modelo_5 = neuralnet(charges ~ age + sexmale + bmi + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem smoker
modelo_6 = neuralnet(charges ~ age + sexmale + bmi + children + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem region
modelo_7 = neuralnet(charges ~ age + sexmale + bmi + children + smokeryes , data = matriz_treino_, hidden = 0,linear.output = TRUE)
prev_treino_1_ = modelo_1$net.result[[1]][,1]
prev_treino_1 = prev_treino_1_*dp_charges + media_charges
prev_treino_2_ = modelo_2$net.result[[1]][,1]
prev_treino_2 = prev_treino_2_*dp_charges + media_charges
prev_treino_3_ = modelo_3$net.result[[1]][,1]
prev_treino_3 = prev_treino_3_*dp_charges + media_charges
prev_treino_4_ = modelo_4$net.result[[1]][,1]
prev_treino_4 = prev_treino_4_*dp_charges + media_charges
prev_treino_5_ = modelo_5$net.result[[1]][,1]
prev_treino_5 = prev_treino_5_*dp_charges + media_charges
prev_treino_6_ = modelo_6$net.result[[1]][,1]
prev_treino_6 = prev_treino_6_*dp_charges + media_charges
prev_treino_7_ = modelo_7$net.result[[1]][,1]
prev_treino_7 = prev_treino_7_*dp_charges + media_charges
charges_treino = base_treino$charges
n = length(charges_treino)
MSE_treino_1 = (1/n)*sum((prev_treino_1 - charges_treino)^2)
MSE_treino_2 = (1/n)*sum((prev_treino_2 - charges_treino)^2)
MSE_treino_3 = (1/n)*sum((prev_treino_3 - charges_treino)^2)
MSE_treino_4 = (1/n)*sum((prev_treino_4 - charges_treino)^2)
MSE_treino_5 = (1/n)*sum((prev_treino_5 - charges_treino)^2)
MSE_treino_6 = (1/n)*sum((prev_treino_6 - charges_treino)^2)
MSE_treino_7 = (1/n)*sum((prev_treino_7 - charges_treino)^2)
base_teste_ = base_teste |> mutate(age = (age - media_age)/dp_age ,
bmi = (bmi - media_bmi)/dp_bmi,
children = (children - media_children)/dp_children,
charges = (charges - media_charges)/dp_charges)
matriz_teste_ <- model.matrix( ~ age + sex + bmi + children + smoker + region + charges, data = base_teste_)
prev_teste_1_ = (modelo_1 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_1 = prev_teste_1_*dp_charges + media_charges
prev_teste_2_ = (modelo_2 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_2 = prev_teste_2_*dp_charges + media_charges
prev_teste_3_ = (modelo_3 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_3 = prev_teste_3_*dp_charges + media_charges
prev_teste_4_ = (modelo_4 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_4 = prev_teste_4_*dp_charges + media_charges
prev_teste_5_ = (modelo_5 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_5 = prev_teste_5_*dp_charges + media_charges
prev_teste_6_ = (modelo_6 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_6 = prev_teste_6_*dp_charges + media_charges
prev_teste_7_ = (modelo_7 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_7 = prev_teste_7_*dp_charges + media_charges
charges_teste = base_teste$charges
n = length(charges_teste)
MSE_teste_1 = (1/n)*sum((prev_teste_1 - charges_teste)^2)
MSE_teste_2 = (1/n)*sum((prev_teste_2 - charges_teste)^2)
MSE_teste_3 = (1/n)*sum((prev_teste_3 - charges_teste)^2)
MSE_teste_4 = (1/n)*sum((prev_teste_4 - charges_teste)^2)
MSE_teste_5 = (1/n)*sum((prev_teste_5 - charges_teste)^2)
MSE_teste_6 = (1/n)*sum((prev_teste_6 - charges_teste)^2)
MSE_teste_7 = (1/n)*sum((prev_teste_7 - charges_teste)^2)
Modelo | MSE na base de treino | MSE na base de teste | Observações |
---|---|---|---|
1 | 37921827 | 33551260 | completo |
2 | 50125221 | 47900202 | sem idade |
3 | 37922627 | 33535116 | sem sexo |
4 | 41369965 | 38334393 | sem bmi |
5 | 38229334 | 33939101 | sem nº filhos |
6 | 127356957 | 130684270 | sem smoker |
7 | 38077180 | 33724508 | sem região |
Quais interpretações podemos tirar da Tabela 1 e da Figura 1 ?
Qual entre os modelos apresentados acima você prefere?
Você tentaria ajustar algum outro modelo após a observação da Tabela 1 e da Figura 1 ?
A variável smoker
traz muita informação para o
modelo.
A variável sex
parece trazer pouca informação para o
modelo.
A variável age
parece que também contribui para o
melhor ajuste do modelo.
Podemos ajustar outros modelos, todos contendo
smoker
e age
e não contendo sex
.
A diferença entre os modelos será nas demais variáveis.
#modelo sem sex e bmi
modelo_8 = neuralnet(charges ~ age + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem sex e children
modelo_9 = neuralnet(charges ~ age + bmi + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest, data = matriz_treino_, hidden = 0,linear.output = TRUE)
#modelo sem sex e regiao
modelo_10 = neuralnet(charges ~ age + bmi + children + smokeryes, data = matriz_treino_, hidden = 0,linear.output = TRUE)
prev_treino_8_ = modelo_8$net.result[[1]][,1]
prev_treino_8 = prev_treino_8_*dp_charges + media_charges
prev_treino_9_ = modelo_9$net.result[[1]][,1]
prev_treino_9 = prev_treino_9_*dp_charges + media_charges
prev_treino_10_ = modelo_10$net.result[[1]][,1]
prev_treino_10 = prev_treino_10_*dp_charges + media_charges
n = length(charges_treino)
MSE_treino_8 = (1/n)*sum((prev_treino_8 - charges_treino)^2)
MSE_treino_9 = (1/n)*sum((prev_treino_9 - charges_treino)^2)
MSE_treino_10 = (1/n)*sum((prev_treino_10 - charges_treino)^2)
prev_teste_8_ = (modelo_8 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_8 = prev_teste_8_*dp_charges + media_charges
prev_teste_9_ = (modelo_9 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_9 = prev_teste_9_*dp_charges + media_charges
prev_teste_10_ = (modelo_10 |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste_10 = prev_teste_10_*dp_charges + media_charges
n = length(charges_teste)
MSE_teste_8 = (1/n)*sum((prev_teste_8 - charges_teste)^2)
MSE_teste_9 = (1/n)*sum((prev_teste_9 - charges_teste)^2)
MSE_teste_10 = (1/n)*sum((prev_teste_10 - charges_teste)^2)
Modelo | MSE na base de treino | MSE na base de teste | Observações |
---|---|---|---|
1 | 37921827 | 33551260 | completo |
3 | 37922627 | 33535116 | sem sex |
8 | 41382393 | 38286177 | sem sex e bmi |
9 | 38230533 | 33920085 | sem sex e nº filhos |
10 | 38078022 | 33707882 | sem sex e região |
Entre todas as comparações parece que o Modelo 3 tem uma bom configuração.
A validação cruzada (k-fold cross-validation) é um outro processo de análise do ajuste do modelo. Neste processo a base de dados é dividido aleatoriamente em \(k\) pedaços de (aproximadamente) mesmo tamanho. Uma vez a base dividida, considera-se um dos \(k\) pedaços a base de teste e os outros \(k-1\) pedaços a base de treino. O modelo é ajustado na base de treino e é calculado o erro na base de teste. Esse processo é feito \(k\) vezes, sendo que em cada uma das vezes uma das partes é utilizada como base de teste e as outras \(k-1\) como base de treino. Ao final do processo, em vez de o valor do MSE na base de treino, teremos \(k\) valores do MSE na base de treino para cada modelo.
Divide o dataset em \(k\) partes;
Faz \(i=1\);
Considere a parte \(i\) como base de teste e o restante da base de dados como base de treino.
Ajuste cada modelo para a base de treino.
Calcule o MSE na base de teste para cada modelo ajustado na base de treino.
Faz \(i = i + 1\) e se \(i \le k\), volte para o passo 3.
Vamos realizar a validação cruzada considerando \(k=10\). Neste caso chamamos este processo de 10-fold cross-validation.
K = 10
N = dim(base)[1]
folds = createFolds(1:N, k = K, list = TRUE, returnTrain = FALSE)
MSE_treino = matrix(NA,ncol=10,nrow = K)
MSE_teste = matrix(NA,ncol=10,nrow = K)
for(k in 1:K){
base_treino = base[-folds[[k]],]
scale = scale(base_treino$age)
age_ = scale[,1]
media_age = attr(scale,"scaled:center")
dp_age = attr(scale,"scaled:scale")
scale = scale(base_treino$bmi)
bmi_ = scale[,1]
media_bmi = attr(scale,"scaled:center")
dp_bmi = attr(scale,"scaled:scale")
scale = scale(base_treino$children)
children_ = scale[,1]
media_children = attr(scale,"scaled:center")
dp_children = attr(scale,"scaled:scale")
scale = scale(base_treino$charges)
charges_ = scale[,1]
media_charges = attr(scale,"scaled:center")
dp_charges = attr(scale,"scaled:scale")
base_treino_ = base_treino |> mutate(age = age_,
bmi = bmi_,
children = children_,
charges = charges_)
matriz_treino_ = model.matrix( ~ age + sex + bmi + children + smoker + region + charges,
data = base_treino_)
modelos = list()
#modelo completo
modelos[[1]] = neuralnet(charges ~ age + sexmale + bmi + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem idade
modelos[[2]] = neuralnet(charges ~ sexmale + bmi + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem sexo
modelos[[3]] = neuralnet(charges ~ age + bmi + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem bmi
modelos[[4]] = neuralnet(charges ~ age + sexmale + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem children
modelos[[5]] = neuralnet(charges ~ age + sexmale + bmi + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem smoker
modelos[[6]] = neuralnet(charges ~ age + sexmale + bmi + children + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem region
modelos[[7]] = neuralnet(charges ~ age + sexmale + bmi + children + smokeryes ,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem sex e bmi
modelos[[8]] = neuralnet(charges ~ age + children + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem sex e children
modelos[[9]] = neuralnet(charges ~ age + bmi + smokeryes + regionnorthwest + regionsoutheast + regionsouthwest,
data = matriz_treino_,
hidden = 0,
linear.output = TRUE)
#modelo sem sex e regiao
modelos[[10]] = neuralnet(charges ~ age + bmi + children + smokeryes,
data = matriz_treino_,
hidden = 0,linear.output = TRUE)
base_teste = base[folds[[k]],]
base_teste_ = base_teste |> mutate(age = (age - media_age)/dp_age,
bmi = (bmi - media_bmi)/dp_bmi,
children = (children - media_children)/dp_children,
charges = (charges - media_charges)/dp_charges)
matriz_teste_ = model.matrix( ~ age + sex + bmi + children + smoker + region + charges,
data = base_teste_)
charges_treino = base_treino$charges
charges_teste = base_teste$charges
n = length(charges_treino)
for(i in 1:10){
prev_treino_ = modelos[[i]]$net.result[[1]][,1]
prev_treino = prev_treino_*dp_charges + media_charges
MSE_treino[k,i] = (1/n)*sum((prev_treino - charges_treino)^2)
prev_teste_ = (modelos[[i]] |> neuralnet::compute(matriz_teste_))$net.result[,1]
prev_teste = prev_teste_*dp_charges + media_charges
MSE_teste[k,i] = (1/(N-n))*sum((prev_teste - charges_teste)^2)
}
}
media_mse_treino = apply(MSE_treino,2,mean)
media_mse_teste = apply(MSE_teste,2,mean)
max_mse_treino = apply(MSE_treino,2,max)
max_mse_teste = apply(MSE_teste,2,max)
min_mse_treino = apply(MSE_treino,2,min)
min_mse_teste = apply(MSE_teste,2,min)
Modelo | Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. | obs |
---|---|---|---|---|---|---|---|
1 | 35052383 | 35859299 | 36362589 | 36462926 | 37149119 | 37828746 | completo |
2 | 48167648 | 48583527 | 48874624 | 49255779 | 49886897 | 50825434 | sem idade |
3 | 35080895 | 35859759 | 36367902 | 36471857 | 37154393 | 37847439 | sem sexo |
4 | 39353102 | 39561328 | 40023264 | 40320867 | 41079033 | 41624153 | sem bmi |
5 | 35387781 | 36222173 | 36684736 | 36792364 | 37493957 | 38218945 | sem nº filhos |
6 | 124297319 | 125784996 | 128227520 | 127927198 | 130082360 | 130994366 | sem smoker |
7 | 35293910 | 36047431 | 36540830 | 36648811 | 37361346 | 37945907 | sem região |
8 | 39354352 | 39568702 | 40042337 | 40327416 | 41080815 | 41624343 | sem sex e bmi |
9 | 35411030 | 36222400 | 36690789 | 36800334 | 37500644 | 38235650 | sem sex e nº filhos |
10 | 35323610 | 36047679 | 36546258 | 36657980 | 37370452 | 37965074 | sem sex e região |
Modelo | Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. | obs |
---|---|---|---|---|---|---|---|
1 | 25043589 | 30909894 | 38383064 | 37261278 | 42514234 | 50069096 | completo |
2 | 35665740 | 44503005 | 53762260 | 50166572 | 56504750 | 59835798 | sem idade |
3 | 24870982 | 30902541 | 38259841 | 37175013 | 42534000 | 49746972 | sem sexo |
4 | 29451005 | 34159790 | 44207911 | 41229772 | 47876783 | 49924468 | sem bmi |
5 | 24783705 | 31010821 | 38749435 | 37541574 | 42523241 | 50277693 | sem nº filhos |
6 | 101478352 | 110121862 | 126610967 | 129699208 | 149584506 | 162707852 | sem smoker |
7 | 25575475 | 30574566 | 38321676 | 37214522 | 42440986 | 49562596 | sem região |
8 | 29438603 | 34110740 | 43897482 | 41117489 | 47783057 | 49918550 | sem sex e bmi |
9 | 24613161 | 30975390 | 38598393 | 37450594 | 42535417 | 50004567 | sem sex e nº filhos |
10 | 25392315 | 30522216 | 38193623 | 37121399 | 42456642 | 49213230 | sem sex e região |
A partir da validação cruzada o modelo mais interessante é aquele que
não considera sex
e nem region
.