데이터분석/Machine Learning

R과 이진트리를 이용한 데이터의 분류분석 및 훈련

늘근이 2015. 11. 23. 22:41

데이터는 훈련과 예측이다.

머신러닝도 마찬가지이다.

 

무슨 이야기인고 하니, 어느 데이터가 있으면 그걸로 패턴을 분석하여 어떤식의 상관관계가 있는 지 알아볼수 있다는 것이다. 정형 데이터를 마이닝하는데 있어 제일 많이 쓰이는 분류분석(Classification)에서는 트리형식으로 데이터를 분류한다.

 

 

 

위와같은 그래프는 눈에 익지는 않겠지만 실제로 어떤 값을 가졌을때 구분이 어떻게 되어야 하는지 표현한 표와 같다. 예를들어 특정한값이 1.57 이하면 2번으로 가고 초과를 한다면 5번으로가서 최종적으로는 여러 인자를 통해 최종적인 노드를 결정하게 된다.

 

자 각설하고 한가지씩 따라해본다.

 

일단 HDclassif라는 라이브러리를 로딩해본다.

 

> library(HDclassif)

 

 

이 라이브러리에는 wine이라는 데이터가 있다..

 

> data(wine)
> head(wine)
  class    V1   V2   V3   V4  V5   V6   V7   V8   V9  V10
1     1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64
2     1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38
3     1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68
4     1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80
5     1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32
6     1 14.20 1.76 2.45 15.2 112 3.27 3.39 0.34 1.97 6.75
   V11  V12  V13
1 1.04 3.92 1065
2 1.05 3.40 1050
3 1.03 3.17 1185
4 0.86 3.45 1480
5 1.04 2.93  735
6 1.05 2.85 1450
> tail(wine)
    class    V1   V2   V3   V4  V5   V6   V7   V8   V9
173     3 14.16 2.51 2.48 20.0  91 1.68 0.70 0.44 1.24
174     3 13.71 5.65 2.45 20.5  95 1.68 0.61 0.52 1.06
175     3 13.40 3.91 2.48 23.0 102 1.80 0.75 0.43 1.41
176     3 13.27 4.28 2.26 20.0 120 1.59 0.69 0.43 1.35
177     3 13.17 2.59 2.37 20.0 120 1.65 0.68 0.53 1.46
178     3 14.13 4.10 2.74 24.5  96 2.05 0.76 0.56 1.35
     V10  V11  V12 V13
173  9.7 0.62 1.71 660
174  7.7 0.64 1.74 740
175  7.3 0.70 1.56 750
176 10.2 0.59 1.56 835
177  9.3 0.60 1.62 840
178  9.2 0.61 1.60 560

 

 

data()를 통해서 데이터를 로딩할수 있으며, head를 통해 상위 여섯개의 데이터를, tail을 통해 하위 여섯개의 데이터를 확인한다. 왜 굳이 이렇게 하냐면, 데이터를 다 까보면 너무 길어져서 귀찮을 수 있기 때문이다.

 

무슨 데이터인지는 잘 모르겠지만 뭐 알필요는 없다. 다만, 여기서는 class가 와인의 등급을 결정하는 것이며, V1~V13까지는 와인에 들어가있는 여러 성분의 농도를 표시한다고 보면 되겠다. 토양, 습도, 페놀, 알콜..등등

 

궁금하지 않은가? 와인마시는 사람들이 나름 소믈리에인지 고물리에인지 나와서 디캔딩을 하면서 온갖 전문용어를 언급하는데 사실은 그런가보다 하고 넘어가지 이렇게 통계치까지 확인해볼거라는건..

 

이제 등급별로 나눌것이므로, 이 등급을 나타내는 class를 범주(factor)로 바꾼다. 범주는 어떤 책에는 '요인'으로 해놨다. 요지는 그거다. 분류하고 싶은 등급.

 

> wine$class <- factor(wine$class)
> table(wine$class)

 1  2  3 
59 71 48 

 

 

이제, 테이블을 통해 wine안에 들어가있는 class라는 놈을 끌러보면 위와같이 심플하게 나온다. 총 178개나 되는 와인들중 1등급은 59개 2등급은 71개 3등급은 48개이다.

 

다음으로 중요한것이 데이터의 분리이다. 데이터를 보통 여러가지 비율로 나누기는 하지만 70%는 학습데이터로 쓰고 30%는 나중을 위해 따로 남겨두기 위해 다음과 같은 명령어를 쓸수있따.

 

> samples <- sample(2, nrow(wine), replace=TRUE, prob = c(0.7,0.3))
> table(samples)
samples
  1   2 
139  39 

 

위의 명렁어를 살펴보면 2가지로 샘플을 나누며, 0.7/0.3 비율로 잘 나눠준다는것을 알수있다.

 

이제 70%는 트레이닝 셋에 넣고 30%는 나중을 위해 남겨둬보자.

 

> trainingSet <- wine[samples == 1,]
> testSet <- wine[samples == 2,]

 

 

분류는 끝났다. 한번 이진트리를 만들어 보자.

 

> library(party)
> tree <- ctree(class ~ ., data = trainingSet)
> str(tree)

 

근데 이렇게 보면 지저분하게 보인다. 그저 간단하게

 

> tree@tree
1) V13 <= 880; criterion = 1, statistic = 102.559
  2) V12 <= 2.15; criterion = 1, statistic = 71.28
    3) V11 <= 0.82; criterion = 1, statistic = 17.869
      4)*  weights = 35 
    3) V11 > 0.82
      5)*  weights = 8 
  2) V12 > 2.15
    6) V1 <= 13.11; criterion = 1, statistic = 23.388
      7)*  weights = 46 
    6) V1 > 13.11
      8)*  weights = 8 
1) V13 > 880
  9) V4 <= 19.4; criterion = 1, statistic = 17.341
    10)*  weights = 35 
  9) V4 > 19.4
    11)*  weights = 7 

 

위와같이 확인할수도 있다. 이를 그래프로도 확인할수도 있는데,

 

> plot(tree)

 

 

이를 위와같은 명령어로, 처음봤던 이진트리로 나눠볼수도 있다. 이제 predict()함수로 아까 남겨두었던 30 %이 데이터를 검증할수 있다.

 

> predict(tree, newdata = testSet)
 [1] 1 1 1 1 2 2 1 1 1 1 1 1 1 2 2 2 2 2 1 1 2 2 2 2 2 1 2
[28] 2 2 3 2 2 3 3 3 3 2 2 3
Levels: 1 2 3

 

 

테스트를 해보기는 했는데 위쪽 그래프를 확인해보면, node 8 에 해당되는것들이 뭔가 구분이 잘 안된것처럼 보인다. 노드 9에 머물러 있는 놈들은 모두 1레벨, 그리고 6에 속한애들은 2등급, 3에 속한애들은 죄다 3등급이다.

 

최종적으로, 이제는 데이터에 대한 검증을 한번 해본다.

 

> table <- table(predict(tree), trainingSet$class)
> table
   
     1  2  3
  1 46  3  1
  2  0 49  5
  3  0  0 35
 
 
 

 

물론 대부분의 포도주것들은 다 잘 분류가 되었지만, 어떤것을 잘못 분류가 되어있다. 제대로 분류된것을 아래와 같은 명령어로 확인가능하다.

1등급으로 분류된 포도주 중 예측기로 예상되는 포도주는 3등급이 된 경우도 있다.

 

> diag(table)
 1  2  3 
46 49 35 

 

이제 이러한 명령어로 제대로 맞추는 확률을 한번 구해보자.

 

정밀도 (행을 기준으로 계산함)

 

> table[1,1] / sum(table[1,])
[1] 0.92
> table[2,2] / sum(table[2,])
[1] 0.9074074
> table[3,3] / sum(table[3,])
[1] 1

 

 

탐지율 (열을 기준으로 계산함)

 

> table[1,1] / sum(table[,1])
[1] 1
> table[2,2] / sum(table[,2])
[1] 0.9423077
> table[3,3] / sum(table[,3])
[1] 0.8536585

 

마찬가지로 귀찮아서 testSet으로는 별로 하기가 싫기 때문에 같은 방식으로 검증하면 된다.