'Dummy'에 해당되는 글 1건

  1. 2016.12.20 제5장 신경망모형 - 분류 5
반응형

독일 신용평가 데이터를 활용한 신경망 모형. 목표변수 y는 good / bad의 범주형 데이터로 모든 변수를 수치화 한 후 신경망 모형을 


1) 
데이터 입력

> set.seed(1000)

> library(neuralnet)

> library(dummy)

> setwd('c:/Rwork')

> german = read.table('germandata.txt',header = T)

 

추가 공부: dummy화란?

 

2) 데이터 및 타입 변경

> dvar=c(4,9,10,15,17) #명목변수 지정 purpose(a43,a40..), personal,  debtors, housing, job

> german2 = dummy(x=german[,dvar]) #명목변수를 더미변수화

> head(german2,1)

purpose_A40 purpose_A41 purpose_A410 purpose_A42 purpose_A43 purpose_A44 purpose_A45

1           0           0            0           0           1           0           0

purpose_A46 purpose_A48 purpose_A49 personal_A91 personal_A92 personal_A93 personal_A94

1           0           0           0            0            0            1            0

debtors_A101 debtors_A102 debtors_A103 housing_A151 housing_A152 housing_A153 job_A171

1            1            0            0            0            1            0        0

job_A172 job_A173 job_A174

1        0        1        0

> german2 = german2[,-c(10,14,17,20,24)] #더미변수생성

> head(german,1)

check  duration  history  purpose  credit  savings  employment  installment  personal  debtors

1   A11        6     A34      A43    1169      A65        A75           4      A93    A101

Residence  property  age  others  housing  numcredits  job  residpeople  telephone  foreign    y

1        4     A121  67   A143    A152          2 A173           1      A192    A201   good

> german2 = cbind(german[,-dvar],german2) #변수 결함

> str(german2)
'data.frame':   1000 obs. of  40 variables:
 $ check       : Factor w/ 4 levels "A11","A12","A13",..: 1 2 4 1 1 4 4 2 4 2 ...
 $ duration    : int  6 48 12 42 24 36 24 36 12 30 ...
 $ history     : Factor w/ 5 levels "A30","A31","A32",..: 5 3 5 3 4 3 3 3 3 5 ...
 $ credit      : int  1169 5951 2096 7882 4870 9055 2835 6948 3059 5234 ...
 $ savings     : Factor w/ 5 levels "A61","A62","A63",..: 5 1 1 1 1 5 3 1 4 1 ...
 $ employment  : Factor w/ 5 levels "A71","A72","A73",..: 5 3 4 4 3 3 5 3 4 1 ...
 $ installment : int  4 2 2 2 3 2 3 2 2 4 ...
 $ residence   : int  4 2 3 4 4 4 4 2 4 2 ...
 $ property    : Factor w/ 4 levels "A121","A122",..: 1 1 1 2 4 4 2 3 1 3 ...
 $ age         : int  67 22 49 45 53 35 53 35 61 28 ...
 $ others      : Factor w/ 3 levels "A141","A142",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ numcredits  : int  2 1 1 1 2 1 1 1 1 2 ...
 $ residpeople : int  1 1 2 2 2 2 1 1 1 1 ...
 $ telephone   : Factor w/ 2 levels "A191","A192": 2 1 1 1 1 2 1 2 1 1 ...
 $ foreign     : Factor w/ 2 levels "A201","A202": 1 1 1 1 1 1 1 1 1 1 ...
 $ y           : Factor w/ 2 levels "bad","good": 2 1 2 2 1 2 2 2 2 1 ...
 $ purpose_A40 : Factor w/ 2 levels "0","1": 1 1 1 1 2 1 1 1 1 2 ...
 $ purpose_A41 : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 2 1 1 ...
 $ purpose_A410: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ purpose_A42 : Factor w/ 2 levels "0","1": 1 1 1 2 1 1 2 1 1 1 ...
 $ purpose_A43 : Factor w/ 2 levels "0","1": 2 2 1 1 1 1 1 1 2 1 ...
 $ purpose_A44 : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ purpose_A45 : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ purpose_A46 : Factor w/ 2 levels "0","1": 1 1 2 1 1 2 1 1 1 1 ...
 $ purpose_A48 : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ purpose_A49 : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ personal_A91: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 2 1 ...
 $ personal_A92: Factor w/ 2 levels "0","1": 1 2 1 1 1 1 1 1 1 1 ...
 $ personal_A93: Factor w/ 2 levels "0","1": 2 1 2 2 2 2 2 2 1 1 ...
 $ personal_A94: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 2 ...
 $ debtors_A101: Factor w/ 2 levels "0","1": 2 2 2 1 2 2 2 2 2 2 ...
 $ debtors_A102: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ debtors_A103: Factor w/ 2 levels "0","1": 1 1 1 2 1 1 1 1 1 1 ...
 $ housing_A151: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 2 1 1 ...
 $ housing_A152: Factor w/ 2 levels "0","1": 2 2 2 1 1 1 2 1 2 2 ...
 $ housing_A153: Factor w/ 2 levels "0","1": 1 1 1 2 2 2 1 1 1 1 ...
 $ job_A171    : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ job_A172    : Factor w/ 2 levels "0","1": 1 1 2 1 1 2 1 1 2 1 ...
 $ job_A173    : Factor w/ 2 levels "0","1": 2 2 1 2 2 1 2 1 1 1 ...
 $ job_A174    : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 2 1 2 ...

> nrow(german2);ncol(german2)
[1] 1000
[1] 40

> for(i in 1:ncol(german2)) if(!is.numeric(german2[,i])) german2[,i] = as.numeric(german2[,i])#여타 순서가 있는 범주형 변수의 수치형 변수화

> german2$y = ifelse(german$y == 'good',1,0) #목표변수 변환

> head(german$y)

[1] good bad  good good bad  good

Levels: bad good

> head(german2$y)

[1] 1 0 1 1 0 1

 ## 중요 : 신경망에서는 범주형 데이터를 수치화하여 적용한다. ##

 

3) 75% 랜덤 추출

> i = sample(1:nrow(german2),round(0.75*nrow(german2))) #75%랜덤 추출

> length(i)
[1] 750

 

4) 변수의 표준화 과정

> max2 = apply(german2, 2, max)

> min2 = apply(german2, 2, min)

> gdat = scale(german2, center = min2, scale = max2 - min2) # 변수조정(0,1,dummy variable은 변화 없음)

> gdat = as.data.frame(gdat) #데이터 프레임 형태로 변경, 데이터 준비 끝!

> str(gdat)

'data.frame':     1000 obs. of  35 variables:

$ check       : num  0 0.333 1 0 0 ...

$ duration    : num  0.0294 0.6471 0.1176 0.5588 0.2941 ...

$ history     : num  1 0.5 1 0.5 0.75 0.5 0.5 0.5 0.5 1 ...

$ credit      : num  0.0506 0.3137 0.1016 0.4199 0.2542 ...

$ savings     : num  1 0 0 0 0 1 0.5 0 0.75 0 ...

$ employment  : num  1 0.5 0.75 0.75 0.5 0.5 1 0.5 0.75 0 ...

$ installment : num  1 0.333 0.333 0.333 0.667 ...

$ residence   : num  1 0.333 0.667 1 1 ...

$ property    : num  0 0 0 0.333 1 ...

$ age         : num  0.8571 0.0536 0.5357 0.4643 0.6071 ...

$ others      : num  1 1 1 1 1 1 1 1 1 1 ...

$ numcredits  : num  0.333 0 0 0 0.333 ...

$ residpeople : num  0 0 1 1 1 1 0 0 0 0 ...

$ telephone   : num  1 0 0 0 0 1 0 1 0 0 ...

$ foreign     : num  0 0 0 0 0 0 0 0 0 0 ...

$ y           : num  1 0 1 1 0 1 1 1 1 0 ...

$ purpose_A40 : num  0 0 0 0 1 0 0 0 0 1 ...

$ purpose_A41 : num  0 0 0 0 0 0 0 1 0 0 ...

$ purpose_A410: num  0 0 0 0 0 0 0 0 0 0 ...

$ purpose_A42 : num  0 0 0 1 0 0 1 0 0 0 ...

$ purpose_A43 : num  1 1 0 0 0 0 0 0 1 0 ...

$ purpose_A44 : num  0 0 0 0 0 0 0 0 0 0 ...

$ purpose_A45 : num  0 0 0 0 0 0 0 0 0 0 ...

$ purpose_A46 : num  0 0 1 0 0 1 0 0 0 0 ...

$ purpose_A48 : num  0 0 0 0 0 0 0 0 0 0 ...

$ personal_A91: num  0 0 0 0 0 0 0 0 1 0 ...

$ personal_A92: num  0 1 0 0 0 0 0 0 0 0 ...

$ personal_A93: num  1 0 1 1 1 1 1 1 0 0 ...

$ debtors_A101: num  1 1 1 0 1 1 1 1 1 1 ...

$ debtors_A102: num  0 0 0 0 0 0 0 0 0 0 ...

$ housing_A151: num  0 0 0 0 0 0 0 1 0 0 ...

$ housing_A152: num  1 1 1 0 0 0 1 0 1 1 ...

$ job_A171    : num  0 0 0 0 0 0 0 0 0 0 ...

$ job_A172    : num  0 0 1 0 0 1 0 0 1 0 ...

$ job_A173    : num  1 1 0 1 1 0 1 0 0 0 ...


5)
신경망 모델 구축 및 신경망 그래프 그리기

> train = gdat[i,] #학습샘플과 테스트 샘플 추출

> test = gdat[-i,]

> gn = names(german2)

> gn

[1] "check"        "duration"     "history"      "credit"       "savings"      "employment" 

[7] "installment"  "residence"    "property"     "age"          "others"       "numcredits" 

[13] "residpeople"  "telephone"    "foreign"      "y"            "purpose_A40"  "purpose_A41"

[19] "purpose_A410" "purpose_A42"  "purpose_A43"  "purpose_A44"  "purpose_A45"  "purpose_A46"

[25] "purpose_A48"  "personal_A91" "personal_A92" "personal_A93" "debtors_A101" "debtors_A102"

[31] "housing_A151" "housing_A152" "job_A171"     "job_A172"     "job_A173"   

> f = as.formula(paste('y~',paste(gn[!gn %in% 'y'],collapse = '+')))

> f

y ~ check + duration + history + credit + savings + employment +

 installment + residence + property + age + others + numcredits +

   residpeople + telephone + foreign + purpose_A40 + purpose_A41 +

   purpose_A410 + purpose_A42 + purpose_A43 + purpose_A44 +

 purpose_A45 + purpose_A46 + purpose_A48 + personal_A91 +

   personal_A92 + personal_A93 + debtors_A101 + debtors_A102 +

   housing_A151 + housing_A152 + job_A171 + job_A172 + job_A173

> nn1 = neuralnet(f,data=train,hidden=c(3,2),linear.output=F) #은닉층은 2, 첫번째 노드는 3, 두번째 노드는 2. 분류의 경우 linear.output = F

> summary(nn1)

Length Class      Mode   

call                   5  -none-     call   

response            750  -none-     numeric

covariate          25500  -none-     numeric

model.list              2  -none-     list   

err.fct                 1  -none-     function

act.fct                 1  -none-     function

linear.output           1  -none-     logical

data                  35  data.frame list   

net.result              1  -none-     list   

weights                1  -none-     list   

startweights            1  -none-     list   

generalized.weights     1  -none-     list   

result.matrix         119  -none-     numeric

> plot(nn1)


은닉층이 2개인 신경망 모형의 그래프가 완성된다. 이 그래프에 대한 해석을 좀 더 공부하고 싶은데 아직은 잘 모르겠음.

 

6) 모형 추정:

> dim(german2)[1]
[1] 1000

> dim(german2)[2]
[1] 35

> colnames(test)[16]
[1] "y"

> pred.nn0 = compute(nn1,train[,c(1:15,17:dim(german2)[2])]) #학습데이터의 실제값과 예측값 비교, 16번째 열의 값은 y

 

함수 설명:

> pred.nn0 = compute(nn1,train[,c(1:15,17:dim(german2)[2])]) 16번째 변수가 y 목표변수. compute 작성된 신경망모형을 이용하여 새로운 예에 적용하여 결과를 도출. nn1 새롭게 예측에 적용할 자료, train[,c(1:15,17:dim(german2)[2])]는 신경망모형으로적합한 결과 오브젝트

 

7) 학습샘플의 실제값과 예측값을 비교해보자.

> head(cbind(german2[1,16],round(pred.nn0$net.result,10)))

[,1]         [,2]

931    1 0.7786470581

546    1 0.0000005387

56     1 0.8208161458

883    1 0.9999999722

11     1 0.0000004232

354    1 0.0000046419

#왼쪽이 실제값, 오른쪽이 예측값. 분류의 문제이므로 값은 0 1사이. 0.5 cut off값을 둘 수 있다. 또는 0.3미만 폐기, 0.7이하 보류, 0.7 초과만 사용한느 cutoff도 가능. 왼쪽이 실제 값, 오른쪽이 학습된 데이터. 4번째 행은 실제 1의 값을 1에 가깝게 예측하였고, 5번째 행은 실제 1이지만 0에 가깝게 예측한 사례. german2[,16] 16번째 열 즉 y값임을 알겠는데 german2[1,16]은 뭘까궁금

 

8) 예측 정확도 평가

> pred.nn1 = compute(nn1,test[,c(1:15,17:dim(german2)[2])]) #test data를 바탕으로 판단해보자

> pred.nn2 = ifelse(pred.nn1$net.result>0.5,1,0) #0.5를 경계로 1 0 분류

> head(cbind(german2[-i,16],pred.nn2)) #테스트 샘플의 실제값과 예측값

[,1]  [,2]

3     1    1

12    1    0

13    1    1

14    1    0

15    0    1

26    1    1

> sum(german2[-i,16]!=pred.nn2) / length(german2[-i,16])

[1] 0.404

> sum(german2[-i,16]!=pred.nn2)

[1] 101

> length(german2[-i,16])

[1] 250

#테스트 샘플의 오분류율, 16번째 값은 목표변수, sum(german2[-i,16]!=pred.nn2) pred.nn2와 같지 않은  값을 전체길이 length(german2[-i,16])로 나눔. i를 빼고 16번째 컬럼을 사용

 

> library(nnet)

> nnet1 =nnet(f,data=train,size = 3, linout = F)

# weights:  109

initial  value 181.570914

iter  10 value 113.679457

iter  20 value 96.943318

iter  30 value 82.803121

iter  40 value 73.239858

iter  50 value 70.807278

iter  60 value 69.865795

iter  70 value 69.476434

iter  80 value 69.158350

iter  90 value 69.039026

iter 100 value 68.929899

final  value 68.929899

stopped after 100 iterations

> pred.nnet1 = predict(nnet1,test[,c(1:15,17:dim(german2)[2])])

> pred.nnet2 = ifelse(pred.nnet1>0.5,1,0)

> head(cbind(german2[-i,16],pred.nnet2)) #테스트 샘플의 실제값과 예측값

[,1] [,2]

3     1    1

12    1    0

13    1    1

14    1    1

15    0    0

26    1    1

> sum(german2[-i,16]!=pred.nnet2) / length(german2[-i,16]) #테스트 샘플 예측의 오분류율

[1] 0.408

이 부분은 교재에 별도 설명이 없어서 추가 공부가 필요함.

 

소감: 알파고 딥마이닝으로 인해 관심을 가지게 된 신경망 모형. 이론 공부도 해보고 R도 따라해보니 약 50%정도 이해된 상태. 궁금한 점은 아래와 같음.

1. 명복 변수 중 더미화 하지 않은 것들도 있음.

-> 교수님 답변: 해당 신경망 모형에서는 숫자로 입력되어 있는 범주형 변수들은 수치변수로 그대로 사용하고 표준화만 하였습니다. 순서가 있는 범주형 변수라고 판단한 변수였습니다. 해당 변수들을 제외하고 나머지 변수들은 변환이 필요하여 dummy 함수를 사용하였습니다.

 

2. 위 신경망 plot 그래프가 무엇을 의미하는지 더 자세히 해석할 능력이 필요함.

-> 교수님 답변: 신경망 모형의 해석은 그림을 보고 해석하기가 상당히 힘듭니다. 워낙 복잡한 함수의 결합이기 때문입니다. 다만, 화살표 위의 수치(절대값)를 보고 연결강도가 강한지 여부를 판단할 수 있습니다. 신경망 모형의 태생적인 한계점인 것 같습니다.

참고로 교재에서 사용하였던 neuralnet 패키지는 plot을 제공합니다. 과거 강의에서 사용했던 다른 패키지는 직접적으로 plot을 산출할 수는 없었습니다.

 

3. 위 신경망 모형을 통해서 오분류율은 40.4%로 나왔는데 너무 높은건 아닌지 생각됨.

 -> 교수님 답변: 오분율은 상대적인 것이긴 하지만 높은 수준으로 보입니다. 교재에서는 예측 판별 기준으로 0.5라는 값을 사용했는데 실제 실무에서는 이 값을 적절하게 변경시키면서 오분류율을 낮추어주는 것이 좋을 것입니다. 예를 들어 원 데이터가 1 0에 비해 많이 분포되어 있다면, 0.5보다 큰 값을 기준치로 삼는 편이 좋습니다.

 

4. 은닉층의 개수는 어떻게 설정하면 좋을지?

 

5. 가장 궁금한 것은 이 모델을 어떻게 실무에 적용할지 잘 모르겠음. 위 독일 신용평가 데이터로 신경망 모형을 만들고 오분류율도 체크하고, 실제값과 예측값도 비교하였는데, 이것이 의미하는 것들. 가령, 변수의 중요성, 그래서 신용도가 좋은 경우는 어느 경우이고, 또 다른 고객 데이터 셋이 있는데 이 새로운 셋에서 어떤 고객, 변수, 값들을 추출해야 우리가 원하는 우수한 고객을 알아낼 수 있는지, 실제 비즈니스 적용 포인트가 가장 궁금함.

 -> 교수님 답변: 실무에서 신경망 모형을 잘 해석하여 활용하기는 어려운 것이 사실입니다. 다만, 상대적으로 예측력이 높다는 점을 살려 새로운 데이터의 모든 변수들을 활용하여 1이나 0값을 예측하거나 목표변수의 값 자체를 산출하는 목적으로는 유용성이 높다고 봅니다. 변수의 해석이나 변수의 선택보다는 예측이나 분류 자체의 목적으로 사용하기에 적합하다고 보시면 좋습니다.

 

6. 전반적으로 의사결정나무, 앙상블 모형에 이어 데이터 마이닝 분야에 깊은 관심을 가지게 되는 좋은 계기.

 

출처: 데이터마이닝(장영재, 김현중, 조형준 공저)

반응형
Posted by 마르띤
,