Modul 6: Neurale netværk - EKSEMPEL
library(magrittr)
library(neuralnet)
##
## Vedhæfter pakke: 'neuralnet'
## Det følgende objekt er maskeret fra 'package:ROCR':
##
## prediction
## Det følgende objekt er maskeret fra 'package:dplyr':
##
## compute
library(openxlsx)
library(recipes)
library(rsample)
library(shapr)
##
## Vedhæfter pakke: 'shapr'
## Det følgende objekt er maskeret fra 'package:dplyr':
##
## explain
Aktiveringsfunktion
# definition af sigmoid aktiveringsfunktion
<- function(x){1/(1+exp(-x))}
sigmoid # plot af logistisk/sigmoid aktiveringsfunktion
plot(x <- seq(-10,10,length=100), sigmoid(.5*x+3), type="l")
# plot af tanh aktiveringsfunktion
plot(x <- seq(-10,10,length=100), tanh(.5*x+3), type="l")
Klargøring af datasæt
# klargøring (standardisering) af datasæt [på samme måde som i modul 4]
set.seed(4321)
<- initial_split(bolig, 2/3)
split <- training(split)
train <- testing(split)
test <- recipe(Salgspris ~ ., data = train) %>%
rec step_date(Salgsdato, features = "decimal") %>%
step_integer(Tidligere.solgt) %>%
step_range(all_numeric(), min=0, max=1) %>%
step_rm(c("Vejnavn","Husnummer","Salgsdato"))
<- bake(prep(rec), train)
train.std <- bake(prep(rec), test)
test.std View(train.std)
Indledning
Vi ser her på det simplest tænkelige neurale netværk, som har 1 input og 0 skjulte lag.
Estimation
<- neuralnet(Salgspris ~ Boligareal, data=train.std, hidden = 0, linear.output=TRUE)
nn # plot af estimeret model
dev.off(2)
## null device
## 1
plot(nn,col.entry="green",col.out="red", show.weights = T)
# modellens SSE
$result.matrix[c("error"),]
nn## error
## 222.1333
Kontrolberegning
# input
<- train.std$Boligareal
input # bias
<- nn$weights[[1]][[1]][1]
output.bias # vægt
<- nn$weights[[1]][[1]][2]
output.wgt # prædiktion
<- output.wgt*input+output.bias*1
output.result 1:5]
output.result[## [1] 0.3468929 0.3103663 0.1300162 0.2784055 0.2784055
# modellens prædiktion (for observation 1-5)
predict(nn,train.std)[1:5]
## [1] 0.3468929 0.3103663 0.1300162 0.2784055 0.2784055
Sammenligning med lineær regression
# estimation af lineær regressionsmodel
<- lm(Salgspris ~ Boligareal, data = train.std)
lm_fit # koefficienter i lineær regressionsmodel
coef(lm_fit)
## (Intercept) Boligareal
## 0.05236006 2.25580758
# vægte i neuralt netværk
setNames(c(output.bias, output.wgt), names(coef(lm_fit)))
## (Intercept) Boligareal
## 0.0523972 2.2555172
# vægte i neuralt netværk, når estimationspræcisionen øges
<- neuralnet(Salgspris ~ Boligareal, data=train.std, hidden = 0, linear.output = TRUE, threshold = 0.0000001)
nn_accurate setNames(nn_accurate$weights[[1]][[1]][,1], names(coef(lm_fit)))
## (Intercept) Boligareal
## 0.05236006 2.25580759
Arkitektur
Neuralt netværk: 1 input, 1 skjult lag med 1 knude
# ~~~ Estimation ~~~
<- neuralnet(Salgspris ~ Boligareal, data=train.std, hidden = 1, linear.output=TRUE)
nn # plot af estimeret model
dev.off(2)
## null device
## 1
plot(nn,col.entry="green",col.out="red", show.weights = T)
# ~~~ Kontrolberegning (skjult lag) ~~~
# input
<- train.std$Boligareal
input # bias
<- nn$weights[[1]][[1]][1]
hidden.bias # vægt
<- nn$weights[[1]][[1]][2]
hidden.wgt # prædiktion
<- sigmoid(hidden.wgt*input+hidden.bias*1) hidden.result
# ~~~ Kontrolberegning (output lag) ~~~
# bias
<- nn$weights[[1]][[2]][1]
output.bias # vægt
<- nn$weights[[1]][[2]][2]
output.wgt # prædiktion
<- output.wgt*hidden.result+output.bias*1
output.result 1:5]
output.result[## [1] 0.3528739 0.2916392 0.1263348 0.2448110 0.2448110
# modellens prædiktion (for observation 1-5)
predict(nn,train.std)[1:5]
## [1] 0.3528739 0.2916392 0.1263348 0.2448110 0.2448110
# ~~~ modellens fejl (= SSE/2) ~~~
$result.matrix[c("error"),]
nn## error
## 208.1507
# kontrolberegning af SSE/2
sum((train.std$Salgspris - predict(nn,train.std))^2)/2
## [1] 208.1507
Neuralt netværk: 1 input, 1 skjult lag med 2 knuder
# ~~~ Estimation ~~~
<- neuralnet(Salgspris ~ Boligareal, data=train.std, hidden = 2, linear.output=TRUE)
nn # plot af estimeret model
dev.off(2)
## null device
## 1
plot(nn,col.entry="green",col.out="red", show.weights = T)
# modellens SSE
$result.matrix[c("error"),]
nn## error
## 208.1418
# ~~~ Kontrolberegning (skjult lag) ~~~
# input
<- train.std$Boligareal
input # bias
<- nn$weights[[1]][[1]][1,]
hidden.bias # vægt
<- nn$weights[[1]][[1]][2,]
hidden.wgt # prædiktion
<- cbind( sigmoid(hidden.wgt[1]*input+hidden.bias[1]*1),
hidden.result sigmoid(hidden.wgt[2]*input+hidden.bias[2]*1) )
# ~~~ Kontrolberegning (output lag) ~~~
# bias
<- nn$weights[[1]][[2]][1]
output.bias # vægte
<- nn$weights[[1]][[2]][2:3]
output.wgt # prædiktion
<- output.wgt[1]*hidden.result[,1]+output.wgt[2]*hidden.result[,2]+output.bias*1
output.result 1:5]
output.result[## [1] 0.3529968 0.2921931 0.1252427 0.2454095 0.2454095
# modellens prædiktion (for observation 1-5)
predict(nn,train.std)[1:5]
## [1] 0.3529968 0.2921931 0.1252427 0.2454095 0.2454095
Betydning af netværksarkitektur
<- neuralnet(Salgspris ~ ., data=train.std, hidden = c(5), linear.output=TRUE, threshold=0.1)
nn.model1 dev.off(2)
## null device
## 1
plot(nn.model1)
::RMSE(x=predict(nn.model1,test.std), ref=test.std$Salgspris)
DescTools## [1] 0.1288629
<- neuralnet(Salgspris ~ ., data=train.std, hidden = c(5,5), linear.output=TRUE, threshold=0.1)
nn.model2 dev.off(2)
## null device
## 1
plot(nn.model2)
::RMSE(x=predict(nn.model2,test.std), ref=test.std$Salgspris)
DescTools## [1] 0.1316482
<- neuralnet(Salgspris ~ ., data=train.std, hidden = c(5,10), linear.output=TRUE, threshold=0.1)
nn.model3 dev.off(2)
## null device
## 1
plot(nn.model3)
::RMSE(x=predict(nn.model3,test.std), ref=test.std$Salgspris)
DescTools## [1] 0.12941
Fortolkning af input til neuralt netværk (= forklarende variable)
# funktion til brug for beregning af Shapley-værdier
<- function(x, newdata) {
predict_model.nn predict(x, newdata = newdata)
}# beregning af Shapley-værdier for neuralt netværk nn.model3 (se ovenfor) for observation 1-5
<- shapr(train.std, nn.model3)
nn_explainer ## get_model_specs is not available for your custom model. All feature consistency checking between model and data is disabled.
## See the 'Advanced usage' section of the vignette:
## vignette('understanding_shapr', package = 'shapr')
## for more information.
## The specified model provides feature labels that are NA. The labels of data are taken as the truth.
# NB: "as.data.frame" er nødvendig her fordi test.std ikke er en data frame
<- explain(as.data.frame(test.std[1:5, ]),
nn_shap
nn_explainer,approach = 'empirical',
prediction_zero = mean(train.std$Salgspris))
1:5,]
test.std[## # A tibble: 5 x 8
## Postnummer Opførselsår Antal.værelser Grundareal Boligareal Tidligere.solgt Salgspris Salgsdato_decimal
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0 0.861 0.211 0.00338 0.175 1 0.230 0.742
## 2 0 0.863 0.211 0.00236 0.0678 0 0.239 0.189
## 3 0.00501 0.782 0.474 0.00131 0.162 1 0.526 0.547
## 4 0.00501 0.779 0.263 0.00138 0.119 0 0.441 0.718
## 5 0.00501 0.811 0.263 0.000829 0.156 0 0.315 0.267
plot(nn_shap, index_x_test = 1:5)
# Shapley opdeler den fittede værdi i bidrag hørende til hver enkelt forklarende variabel
$dt
nn_shap## none Postnummer Opførselsår Antal.værelser Grundareal Boligareal Tidligere.solgt Salgspris
## 1: 0.3429702 0.118376434 -0.01204577 -0.01543997 -0.013310413 0.12553281 -0.014074836 -0.060379961
## 2: 0.3429702 0.064611623 -0.01417070 0.00183910 -0.012268266 -0.08654693 0.012874969 0.003790434
## 3: 0.3429702 -0.030308357 0.04975918 0.05217729 0.007896912 -0.02801878 -0.016759477 0.038854821
## 4: 0.3429702 -0.005485522 0.05330641 0.02762469 0.008356331 -0.02801115 0.011139276 0.034800571
## 5: 0.3429702 0.060719901 0.04967514 0.03180738 0.010494847 0.07595848 0.007333047 -0.013457145
## Salgsdato_decimal
## 1: 0.04943960
## 2: -0.03835143
## 3: -0.03463261
## 4: 0.01240790
## 5: -0.03452730
# kontrolberegning: sum af Shapley-bidrag = fittet værdi
predict(nn.model3, test.std[1:5, ])
## [,1]
## [1,] 0.5210681
## [2,] 0.2747490
## [3,] 0.3819392
## [4,] 0.4571087
## [5,] 0.5309745
rowSums(nn_shap$dt)
## [1] 0.5210681 0.2747490 0.3819392 0.4571087 0.5309745