nnet 패키지는 결과가 몇 가지 범주로 나뉘는 경우 더 좋은 방법이긴 하지만, 뉴럴넷 패키지와 대비해서 몇 가지 단점도 있습니다. 대표적인 단점은 시각화가 어렵다는 것이죠. 하지만 R의 특성상 많은 개발자들이 깃허브에 시각화 툴을 개발해 올려놨기 때문에 이를 활용하면 nnet 역시 시각화가 가능합니다. 앞서 예제에서 시각화를 진행해 보겠습니다.
require(nnet)
library(mlbench)
data(PimaIndiansDiabetes)
pima <- pimaindiansdiabetes="" span="">->
pima<-pima age="" c="" diabetes="" glucose="" mass="" pedigree="" pregnant="" pressure="" span="">-pima>
pima=subset(pima,glucose>0)
pima=subset(pima,pressure>0)
pima=subset(pima,mass>0)
set.seed(1234)
data1<-scale c="" pima="" span="">-scale>
data2<-pima c="" span="">-pima>
data=cbind(data1,data2)
data<-data .frame="" data="" span="">-data>
data$data2<-as .factor="" data2="" data="" span="">-as>
n = nrow(data)
train <- 600="" n="" sample="" span="">->
test <- data="" span="" train="">->
train <- data="" span="" train="">->
nn <- data2="" data="train," nnet="" size="3) </span">->
nn
data3<-predict nn="" span="" test="" type="class">-predict>
test=cbind(test,data3)
test
test$pred<-ifelse data2="=test$data3,1,0)</span" test="">-ifelse>
table(test$pred)
sum(test$pred)/124
시각화 툴을 다운 받기 위해선 devtool 패키지가 기본으로 있어야 합니다. 그리고 reshape 패키지도 필요합니다.
library(devtools)
source_url('https://gist.githubusercontent.com/fawda123/7471137/raw/466c1474d0a505ff044412703516c34f1a4684a5/nnet_plot_update.r')
library(reshape)
plot(nn)
여기서 알 수 있듯이 nnet 패키지는 한 층의 은닉층 (H1-3)을 지니고 있으며 편향은 두 단계에서 진행하게 됩니다. 이 시각화 툴은 가중치가 클수록 굵은 실선으로 표시하고 있어 신경망이 어떻게 작동하는지 좀 더 쉽게 이해할 수 있습니다. 은닉층의 수는 늘릴 수 없지만 nnet에서도 몇 가지 옵션은 가능합니다.
대표적인 파라미터는 은닉층 노드의 숫자인 size와 몇 번 반복해서 최적의 결과를 찾을 것인지 지정하는 maxit, 그리고 overfitting 이라는 문제를 막기 위해 사용하는 weigth decay parameter인 decay입니다. 아래처럼 옵션을 바꿔보겠습니다.
nn <- data2="" data="train," decay="5e-4," maxit="300) </span" nnet="" size="6,">->
> table(test$pred)
0 1
31 93
> sum(test$pred)/124
[1] 0.75
결과를 보니 75%에서 맞게 분류를 해 분류 정확도가 높아졌습니다.
그림을 보니 신경망의 복잡도가 더 높아지면서 예측 정확도도 높아진 것 같습니다. 여기서 보면 특히큰 영향을 주는 노드가 H4,H5라는 점을 알 수 있으며 이들에게 큰 영향을 주는 인자는 공복혈당, 연령 (H4), BMI, 혈당, 임신력 (H5)라는 점을 확인할 수 있습니다. 여러 번 반복 연산을 한 결과 이렇게 가중치와 편향을 주는 경우 가장 좋은 예측 결과를 보였다는 점을 알 수 있습니다.
신경망의 분류 정확도를 보다 전통적인 통계 방식으로 표현하기 위해서 민감도와 특이도를 구할 수도 있습니다. 민감도는 실제로 병이 있는 경우 있다고 판정하는 경우이고 특이도는 병이 없는 경우 없다고 판정하는 경우입니다. 목적에 따라 민감도가 중요한 부분도 있고 특이도가 중요한 부분도 있겠지만, 일반적으로 둘 다 높으면 좋을 것입니다. 패키지에 따라 기본으로 제공하는 경우도 있지만, nnet, neuralnet 모두 그런 기능이 없기 때문에 스스로 만들어야 합니다.
a<-subset data2="=2&test$data3==2)</span" test="">-subset>
b<-subset data2="=2&test$data3==1)</span" test="">-subset>
c<-subset data2="=1&test$data3==2)</span" test="">-subset>
d<-subset data2="=1&test$data3==1)</span" test="">-subset>
nrow(a)/(nrow(a)+nrow(b)) #sensitivity
nrow(d)/(nrow(c)+nrow(d)) #specificity
각각의 숫자로 보면 (바로 옆 창에 행의 갯수가 나타납니다) 26, 19, 12, 67입니다. a는 당뇨가 생긴 경우 생겼다고 예측한 그룹, b는 당뇨가 생겼는데 안생겼다고 예측한 그룹, c는 당뇨가 안생겼는데 생긴다고 예측한 그룹, d는 당뇨가 안생겼는데 안생겼다고 예측한 그룹입니다.
> nrow(a)/(nrow(a)+nrow(b)) #sensitivity
[1] 0.5777778
> nrow(d)/(nrow(c)+nrow(d)) #specificity
[1] 0.8481013
기본적으로 이 모형은 민감도(sensitivity) 가 높지 않고 특이도(sepcificity)가 높습니다. 이는 질병 발생율에서 생기는 쪽을 더 중시한다는 점을 생각하면 좋은 예측 모델이라고 할 순 없습니다. 신경망 모델을 평가하는 기준은 이렇게 여러 가지 부분을 같이 놓고 비교해서 평가해야 합니다.
댓글
댓글 쓰기