2. 지도학습 알고리즘 (2)

2.1 의사결정나무 (Decision Tree)

  • 구조 : 뿌리마디 + 자식마디 + 부모마디 + 끝마디
  • 의사 결정나무의 학습은 학습에 사용되는 데이터 집합을 적절한 분할 기준 또는 분할 테스트에 따라 나누는 과정
  • 순활 분할 방식으로서 더 이상 순수도를 높일 수 없거나, 말단 노드에 포함된 개체의 수가 사전에 정한 최솟값에 도달하였거나, 노드의 깊이가 사전에 정해놓은 한계에 이를 때까지 재귀적으로 분할이 반복된다.
  • 이러한 방식을 하향식 결정트리 귀납버이라 한다.
  • 가지치기의 기준은 순수도를 가장 높여줄 수 있는 변수를 먼저 선택해 진행한다.
  • 순수도를 측정하는 척도로는 지니 척도, 정보이익=엔트로피이 많이 사용된다.

지니척도

  • 두 번을 복원 추출 했을 때, 동일 범주 개체가 선택될 확률이다.
  • 순수도가 높을수록 1에, 균등할수록 0.5에 가까워 진다.
  • 순수도가 높은 변수(불순도가 낮은 변수)로 가지치기를 한다.
  • 순수도 = 1- 불순도

엔트로피

  • 두 범주의 확률이 모두 0.5면 엔트로피는 1이 된다
  • 만약 한 범주만 있는 완전히 순수한 상태라면 엔트로피는 0이 된다.
  • 정보 이익은 분리 전과 분리 후의 엔트로피 차이를 계산해 얻는다.
  • 에프터 엔트로피가 작아져야 (더 순수한 상태) 정보 이익이 커진다.

2.1.1 데이터 준비

autoparts=read.csv("data/autoparts.csv",header = TRUE)
autoparts1=autoparts[autoparts$prod_no=="90784-76001",c(2:11)]
autoparts2=autoparts1[autoparts1$c_thickness<1000,]

autoparts2$y_faulty=ifelse((autoparts2$c_thickness<20)|(autoparts2$c_thickness>32),1,0)

t_index=sample(1:nrow(autoparts2),size=nrow(autoparts2)*0.7) # 행 인덱스 추출 (70%)
train=autoparts2[t_index,]
test=autoparts2[-t_index,]

2.1.2 모델 생성

m=tree(factor(y_faulty)~fix_time+a_speed+b_speed+separation+s_separation+rate_terms+mpa
  +load_time+highpressure_time,data=train)

plot(m)
text(m)

2.1.3 가지치기

  • 가지가 많을수록 정답률은 높아지나, 모델은 복잡해진다.
prune.m=prune.tree(m,method = "misclass") 
# 잘못된 분류를 기준으로 가지치기한다. 
# 기본값으로 두어도 큰 차이는 없다. 

plot(prune.m)

  1. 가지 9개
prune.m=prune.tree(m,best=9)
plot(prune.m)
text(prune.m)

  1. 가지 3개
prune.m2=prune.tree(m,best=3)
plot(prune.m2)
text(prune.m2)

2.1.4 검증 데이터 예측하기

yhat_test=predict(prune.m,test,type="class")
yhat_test2=predict(prune.m2,test,type="class")
  1. 가지 9개
confusionMatrix(yhat_test,as.factor(test$y_faulty))
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    0    1
##          0 5387  258
##          1  315  571
##                                          
##                Accuracy : 0.9123         
##                  95% CI : (0.9051, 0.919)
##     No Information Rate : 0.8731         
##     P-Value [Acc > NIR] : < 2e-16        
##                                          
##                   Kappa : 0.6155         
##  Mcnemar's Test P-Value : 0.01931        
##                                          
##             Sensitivity : 0.9448         
##             Specificity : 0.6888         
##          Pos Pred Value : 0.9543         
##          Neg Pred Value : 0.6445         
##              Prevalence : 0.8731         
##          Detection Rate : 0.8248         
##    Detection Prevalence : 0.8643         
##       Balanced Accuracy : 0.8168         
##                                          
##        'Positive' Class : 0              
## 
  1. 가지 3개
confusionMatrix(yhat_test2,as.factor(test$y_faulty))
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    0    1
##          0 5574  675
##          1  128  154
##                                           
##                Accuracy : 0.877           
##                  95% CI : (0.8688, 0.8849)
##     No Information Rate : 0.8731          
##     P-Value [Acc > NIR] : 0.1717          
##                                           
##                   Kappa : 0.2274          
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.9776          
##             Specificity : 0.1858          
##          Pos Pred Value : 0.8920          
##          Neg Pred Value : 0.5461          
##              Prevalence : 0.8731          
##          Detection Rate : 0.8535          
##    Detection Prevalence : 0.9568          
##       Balanced Accuracy : 0.5817          
##                                           
##        'Positive' Class : 0               
## 

2.1.5 ROC, AUC

  1. 가지 9개
ROC(test=yhat_test,stat=test$y_faulty,plot="ROC",AUC=T,main="Tree")

  1. 가지 3개
ROC(test=yhat_test2,stat=test$y_faulty,plot="ROC",AUC=T,main="Tree")

2.1.6 예측 (1) 한개의 데이터 예측

new.data=data.frame(fix_time=87,a_speed=0.609,b_speed=1.715,separation=242.7,s_separation=657.5,rate_terms=95,mpa=78,load_time=18.1,highpressure_time=82)
predict(prune.m,newdata = new.data,type="class")
## [1] 0
## Levels: 0 1
predict(prune.m2,newdata = new.data,type="class")
## [1] 0
## Levels: 0 1

2.1.7 예측 (2) 여러개의 데이터 예측

  1. 벡터
new.data=data.frame(fix_time=c(87,85.6),a_speed=c(0.609,0.472),b_speed=c(1.715,1.685),separation=c(242.7,243.4),s_separation=c(657.5,657.9),rate_terms=c(95,95),mpa=c(78,28.8),load_time=c(18.1,18.2),highpressure_time=c(82,60))
predict(prune.m,newdata = new.data,type="class")
## [1] 0 1
## Levels: 0 1
predict(prune.m2,newdata = new.data,type="class")
## [1] 0 1
## Levels: 0 1
  1. 데이터 프레임
new.data=data.frame(fix_time=test$fix_time,a_speed=test$a_speed,b_speed=test$b_speed,separation=test$separation,s_separation=test$s_separation,rate_terms=test$rate_terms,mpa=test$mpa,load_time=test$load_time,highpressure_time=test$highpressure_time)
head(predict(prune.m,newdata = new.data,type="class"))
## [1] 0 0 0 0 0 1
## Levels: 0 1
head(predict(prune.m,newdata = new.data,type="class"))
## [1] 0 0 0 0 0 1
## Levels: 0 1

2.1.8 다항 종속변수에 대하여 의사결정나무 모형 만들기

  1. 데이터 준비
autoparts2$g_class=as.factor(ifelse(autoparts2$c_thickness<20,1,ifelse(autoparts2$c_thickness<32,2,3)))
t_index=sample(1:nrow(autoparts2),size=nrow(autoparts2)*0.7) # 행 인덱스 추출 (70%)
train=autoparts2[t_index,]
test=autoparts2[-t_index,]
  1. 모델 생성
m=tree(g_class~fix_time+a_speed+b_speed+separation+s_separation+rate_terms+mpa
  +load_time+highpressure_time,data=train)
plot(m)
text(m)

  1. 검증데이터 예측하기
yhat_test=predict(m,test,type="class")
confusionMatrix(yhat_test,as.factor(test$g_class))
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    1    2    3
##          1  427  138    0
##          2  211 5393    8
##          3    3  125  226
## 
## Overall Statistics
##                                          
##                Accuracy : 0.9257         
##                  95% CI : (0.9191, 0.932)
##     No Information Rate : 0.866          
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.6974         
##  Mcnemar's Test P-Value : < 2.2e-16      
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity           0.66615   0.9535  0.96581
## Specificity           0.97657   0.7497  0.97967
## Pos Pred Value        0.75575   0.9610  0.63842
## Neg Pred Value        0.96413   0.7138  0.99870
## Prevalence            0.09815   0.8660  0.03583
## Detection Rate        0.06538   0.8258  0.03460
## Detection Prevalence  0.08651   0.8593  0.05420
## Balanced Accuracy     0.82136   0.8516  0.97274

2.1.9 연속형 종속변수에 대하여 의사결정나무 모형 만들기

  • 종속변수가 연속형이므로 type=“class” 사용하지 않음
  • 또한 table함수 사용 불가능
  1. 모델 생성
m=tree(c_thickness~fix_time+a_speed+b_speed+separation+s_separation+rate_terms+mpa
  +load_time+highpressure_time,data=train)
plot(m)
text(m)

  1. 검증데이터 예측
yhat_test=predict(m,test)
head(yhat_test)
##        5        6        9       12       19       22 
## 22.52917 22.52917 22.52917 22.52917 22.52917 33.13450
head(test$c_thickness)
## [1] 24.5 22.9 22.2 23.1 25.4 34.1
  1. 예측
new.data=data.frame(fix_time=c(87,85.6),a_speed=c(0.609,0.472),b_speed=c(1.715,1.685),separation=c(242.7,243.4),s_separation=c(657.5,657.9),rate_terms=c(95,95),mpa=c(78,28.8),load_time=c(18.1,18.2),highpressure_time=c(82,60))
predict(prune.m,newdata = new.data)
##        [,1]       [,2]
## 0 0.9337106 0.06628941
## 1 0.4170854 0.58291457

2.1.10 연습문제

  • rpart 패키지
rpart=rpart(as.factor(y_faulty)~fix_time+a_speed+b_speed+separation+s_separation+rate_terms+mpa
  +load_time+highpressure_time,data=train)
plot(rpart)
text(rpart)

printcp(rpart)
## 
## Classification tree:
## rpart(formula = as.factor(y_faulty) ~ fix_time + a_speed + b_speed + 
##     separation + s_separation + rate_terms + mpa + load_time + 
##     highpressure_time, data = train)
## 
## Variables actually used in tree construction:
## [1] b_speed      load_time    mpa          rate_terms   s_separation
## [6] separation  
## 
## Root node error: 1973/15236 = 0.1295
## 
## n= 15236 
## 
##          CP nsplit rel error  xerror     xstd
## 1  0.122656      0   1.00000 1.00000 0.021005
## 2  0.045109      2   0.75469 0.76128 0.018650
## 3  0.030917      3   0.70958 0.71566 0.018141
## 4  0.024835      4   0.67866 0.69285 0.017879
## 5  0.017739      7   0.60416 0.63153 0.017144
## 6  0.013431      8   0.58642 0.58642 0.016573
## 7  0.012924     13   0.51647 0.52965 0.015813
## 8  0.012164     20   0.42220 0.51597 0.015622
## 9  0.011151     21   0.41004 0.47846 0.015082
## 10 0.010644     23   0.38773 0.44247 0.014540
## 11 0.010000     24   0.37709 0.44146 0.014524
plotcp(rpart)

rpart.prune=rpart(as.factor(y_faulty)~fix_time+a_speed+b_speed+separation+s_separation+rate_terms+mpa
  +load_time+highpressure_time,data=train,control=rpart.control(cp=0.02))
plot(rpart.prune)
text(rpart.prune,pretty = 2)

2.2 KNN (K-Nearest Neighbors classfier)

  • 새로운 점이 주어졌을 때, 그 점으로부터 가까운 점 K개를 이용하여 분류하는 머신러닝 기법
  • 너무 작은 K를 선정하면 주변 소수의 데이터에 너무 큰 영향을 받는다.
  • 너무 큰 K를 선정하면 관련이 없는 먼 곳의 데이터까지 분류에 영향을 끼치고, 정작 중요한 주변의 데이터 영향력은 작아진다.
  • Cross Validation(교차검증)을 통해 오분류율이 낮은 K를 선정한다.
  • K값은 일반적으로 홀 수를 취한다.
  • 범주형 자료, 연속형 데이터 모두 사용 가능하다.

2.2.1 자료 준비

데이터 준비

autoparts=read.csv("data/autoparts.csv",header = TRUE)
autoparts1=autoparts[autoparts$prod_no=="90784-76001",c(2:11)]
autoparts2=autoparts1[autoparts1$c_thickness<1000,]
autoparts2$y_faulty=ifelse((autoparts2$c_thickness<20)|(autoparts2$c_thickness>32),1,0)

Train / Test set 나누기

t_index=sample(1:nrow(autoparts2),size=nrow(autoparts2)*0.7) # 행 인덱스 추출 (70%)
train=autoparts2[t_index,]
test=autoparts2[-t_index,]

2.2.2 Argument 준비

훈련 데이터 행렬과 종속변수

xmat.train=as.matrix(train[1:9])
y_faulty.train=train$y_faulty
head(xmat.train)
##       fix_time a_speed b_speed separation s_separation rate_terms  mpa
## 2009      85.2   0.551   1.630      260.3        641.4         80 78.3
## 9183      86.0   0.612   1.655      244.0        651.8         81 77.6
## 15264     81.3   0.640   1.589      184.7        715.9         87 75.0
## 8147      89.9   0.606   1.697      252.3        649.8         80 78.4
## 4334      85.1   0.601   1.658      249.9        651.5         79 78.3
## 2272      85.3   0.553   1.609      261.8        635.8         79 79.4
##       load_time highpressure_time
## 2009       18.1                59
## 9183       18.2                59
## 15264      19.2                66
## 8147       18.1                76
## 4334       18.1                57
## 2272       18.2                61

검증 데이터 행렬

xmat.test=as.matrix(test[1:9])
head(xmat.test)
##    fix_time a_speed b_speed separation s_separation rate_terms  mpa
## 3      86.0   0.609   1.715      242.7        657.5         95 78.0
## 5      86.1   0.603   1.704      242.5        657.3         95 77.9
## 6      86.3   0.606   1.707      244.5        656.9         95 77.9
## 7      86.5   0.606   1.701      243.1        656.9         95 78.2
## 10     86.0   0.608   1.696      248.0        657.3         95 77.5
## 12     86.5   0.606   1.692      243.8        657.4         95 77.8
##    load_time highpressure_time
## 3       18.1                82
## 5       18.2                56
## 6       18.0                78
## 7       18.1                55
## 10      18.1                60
## 12      18.1                51

2.2.3 예측 값 생성

library(class)
yhat_test=knn(xmat.train,xmat.test,as.factor(y_faulty.train),k=3)
head(yhat_test,100)
##   [1] 0 0 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1
##  [36] 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
##  [71] 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 1 1 1 1 1 1 1 1 1 1
## Levels: 0 1
table=table(real=test$y_faulty,predict=yhat_test)
table
##     predict
## real    0    1
##    0 5576  103
##    1  212  640
confusionMatrix(yhat_test,as.factor(test$y_faulty))
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    0    1
##          0 5576  212
##          1  103  640
##                                           
##                Accuracy : 0.9518          
##                  95% CI : (0.9463, 0.9568)
##     No Information Rate : 0.8695          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.7752          
##  Mcnemar's Test P-Value : 1.164e-09       
##                                           
##             Sensitivity : 0.9819          
##             Specificity : 0.7512          
##          Pos Pred Value : 0.9634          
##          Neg Pred Value : 0.8614          
##              Prevalence : 0.8695          
##          Detection Rate : 0.8538          
##    Detection Prevalence : 0.8862          
##       Balanced Accuracy : 0.8665          
##                                           
##        'Positive' Class : 0               
## 

2.2.4 최적 k값 찾기

library(e1071)
tune.out=tune.knn(x=xmat.train,y=as.factor(y_faulty.train),k=1:10)
tune.out
## 
## Parameter tuning of 'knn.wrapper':
## 
## - sampling method: 10-fold cross validation 
## 
## - best parameters:
##  k
##  5
## 
## - best performance: 0.0450254
plot(tune.out)

최적 k=5로 knn 재수행

library(class)
yhat_test=knn(xmat.train,xmat.test,as.factor(y_faulty.train),k=5)
head(yhat_test,100)
##   [1] 0 0 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
##  [36] 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
##  [71] 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 1 1 1 1 1 1 1 1 1 1
## Levels: 0 1
confusionMatrix(yhat_test,as.factor(test$y_faulty))
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    0    1
##          0 5584  201
##          1   95  651
##                                           
##                Accuracy : 0.9547          
##                  95% CI : (0.9493, 0.9596)
##     No Information Rate : 0.8695          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.7891          
##  Mcnemar's Test P-Value : 1.041e-09       
##                                           
##             Sensitivity : 0.9833          
##             Specificity : 0.7641          
##          Pos Pred Value : 0.9653          
##          Neg Pred Value : 0.8727          
##              Prevalence : 0.8695          
##          Detection Rate : 0.8550          
##    Detection Prevalence : 0.8858          
##       Balanced Accuracy : 0.8737          
##                                           
##        'Positive' Class : 0               
## 

2.2.5 ROC,AUC

library(Epi)
ROC(test=yhat_test,stat=test$y_faulty,plot="ROC",AUC=T,main="KNN")

2.2.6 데이터 예측

new.data=data.frame(fix_time=c(87,85.6),a_speed=c(0.609,0.472),b_speed=c(1.715,1.685),separation=c(242.7,243.4),s_separation=c(657.5,657.9),rate_terms=c(95,95),mpa=c(78,28.8),load_time=c(18.1,18.2),highpressure_time=c(82,60))
knn(xmat.train,new.data,y_faulty.train,k=5)
## [1] 0 1
## Levels: 0 1

2.2.7 종속변수가 다항인 경우

  • 이항인 경우와 같음.

2.2.8 종속변수가 연속형인 경우 FNN::knn.reg()

autoparts=read.csv("data/autoparts.csv",header = TRUE)
autoparts1=autoparts[autoparts$prod_no=="90784-76001",c(2:11)]
autoparts2=autoparts1[autoparts1$c_thickness<1000,]
t_index=sample(1:nrow(autoparts2),size=nrow(autoparts2)*0.7) # 행 인덱스 추출 (70%)
train=autoparts2[t_index,]
test=autoparts2[-t_index,]
xmat.train=as.matrix(train[1:9])
c_thickness.train=train$c_thickness
xmat.test=as.matrix(test[1:9])
library(FNN)
## 
## Attaching package: 'FNN'
## The following objects are masked from 'package:class':
## 
##     knn, knn.cv
yhat_test=knn.reg(xmat.train,xmat.test,c_thickness.train,k=3)
mse=mean((yhat_test$pred-test$c_thickness)^2)
mse
## [1] 1.625529

2.3 신경망(Neural Network)

  • 인간의 뇌를 모방하여 만든 모델
  • 입력층 / 은닉층 / 출력층으로 구성
  • 입력 - 반응을 결정하는 대표적인 함수는 sigmoid 함수이다.
  • 은닉층에서 정보의 조합이 어떻게 이루어지는지 실행 중에 파악하기가 어려워 결과 도출 과정을 설명하기 어렵고 모델 수정도 어렵다.
  • 변수 선택에 매우 민감.
  • 인공 신경망에서의 학습이란 노드와 노드 사이의 링크에 부여된 가중치를 조절하는 과정이다.
  • 가중치를 계속 조절해가며 오차를 줄여 나가도록 한다.
  • 가중치의 조정은 출력 노드로 부터 역방향으로 이루어지므로 역전파 알고리즘이라고 부른다.
  • 입력 변수가 많아지면 입력 노드가 많아지고, 노드가 많아지면 추정해야하는 가중치의 수가 늘어나게 된다. 추정해야 할 가중치의 수가 늘어나게 되면 과적합이 발생할 가능성이 높아져 train 데이터의 예측력은 높더라도 test 데이터의 예측력이 떨어지게 된다.
  • 따라서 종속변수와의 관계가 깊은 주요 변수를 최소한으로 선택하는 것이 필요하다.

2.3.1 자료 준비

autoparts=read.csv("data/autoparts.csv",header = TRUE)
autoparts1=autoparts[autoparts$prod_no=="90784-76001",c(2:11)]
autoparts2=autoparts1[autoparts1$c_thickness<1000,]
autoparts2$g_class=as.factor(ifelse(autoparts2$c_thickness<20,1,ifelse(autoparts2$c_thickness<32,2,3)))
t_index=sample(1:nrow(autoparts2),size=nrow(autoparts2)*0.7) # 행 인덱스 추출 (70%)
train=autoparts2[t_index,]
test=autoparts2[-t_index,]

2.3.2 모델 생성

library(nnet)
m=nnet(g_class~fix_time+a_speed+b_speed+separation+s_separation+rate_terms+mpa
  +load_time+highpressure_time,data=train,size=10)
## # weights:  133
## initial  value 19970.351493 
## iter  10 value 7036.254440
## final  value 7035.997379 
## converged

2.3.3 성능 평가

yhat_test=predict(m,test,type="class")
table=table(real=test$g_class,predict=yhat_test)
table
##     predict
## real    2    3
##    1  638    0
##    2 5678    1
##    3  213    1

2.3.4 시각화

library(reshape2)
library(devtools)
source_url("https://gist.githubusercontent.com/fawda123/7471137/raw/466c1474d0a505ff044412703516c34f1a4684a5/nnet_plot_updata.r")
## SHA-1 hash of file is 74c80bd5ddbc17ab3ae5ece9c0ed9beb612e87ef
plot(m)
## Loading required package: scales
## Loading required package: reshape
## 
## Attaching package: 'reshape'
## The following objects are masked from 'package:reshape2':
## 
##     colsplit, melt, recast
## The following object is masked from 'package:class':
## 
##     condense