이번에 알아볼 machine learning 알고리즘은 K-nearest Neighbors라고 불리는 알고리즘입니다. 컨셉은 간단합니다. 새로운 데이터가 들어왔을 때, 기존에 우리가 가지고 있던 데이터를 기준으로 K개의 가장 가까운 점을 찾아서 그들의 평균값(regression의 경우)이나 majority votes(가장 빈번한 class로 분류하는 것. classification의 경우)로 새로운 데이터를 분류하는 방식입니다. 이름 그대로 K개의 가장 가까운 이웃인 것이죠 ^^

img

이 방법은 컨셉이 간단하고, 특별한 수학적인 모델이 없습니다. 따라서 해석이 거의 불가능하다는 단점은 있지만, 말 그대로 간단하고, 또한 굉장히 비선형적인 움직임이 강했을 때에 오히려 linear model보다 더 잘 데이터를 예측할 수 있기도 합니다.

이제 어떻게 동작하는지 원리를 파악해 봅시다. Logistic regression 시간에 사용했던 주식 시장 데이터를 다시 사용하겠습니다. 그리고 KNN을 사용하기 위해 class라이브러리를 추가로 불러줍니다. 여기서는 시각화를 위해서 Lag1과 Lag2의 두 가지 변수만 사용하겠습니다.

library(ISLR)
library(class)
attach(Smarket) #Smarket dataset을 사용할 것입니다.
## The following objects are masked from Smarket (pos = 4):
## 
##     Direction, Lag1, Lag2, Lag3, Lag4, Lag5, Today, Volume, Year
## 
## The following objects are masked from Smarket (pos = 7):
## 
##     Direction, Lag1, Lag2, Lag3, Lag4, Lag5, Today, Volume, Year
## 
## The following objects are masked from Smarket (pos = 9):
## 
##     Direction, Lag1, Lag2, Lag3, Lag4, Lag5, Today, Volume, Year
Xlag=cbind(Lag1,Lag2) #두 변수만 사용하여 새로운 x 데이터를 추출합니다.
train=Year<2005 #training set은 2005년 이전 데이터로 하겠습니다.
plot(Xlag[train,], col=Direction[train]) #일단 데이터가 어떻게 분포되어 있는지 확인해 보겠습니다.

center

역시 주식시장의 복잡성을 알 수 있듯이, 데이터가 굉장히 불규칙한 랜덤 형태를 보이네요. 그럼 이제 K=1인 1-NN model을 만들어 보겠습니다. 먼저 어느 영역에서 어떻게 분류가 되는지 눈으로 쉽게 보기 위해서 각 x축들의 최소 최대값들을 grid로 잘게 나눠서 확인해 보겠습니다.

grid = expand.grid(seq(min(Lag1[train]),max(Lag1[train]), by=0.1), seq(min(Lag2[train]), max(Lag2[train]), by=0.1)) #각 축의 최소 최대값을 0.1단위로 쪼개서 grid를 만듭니다.
grid.pred = knn(Xlag[train,], grid, Direction[train], k=1) #1-NN model을 만듭니다.
plot(grid, col=grid.pred, pch=20) #예측이 어떻게 되는지 영역 표시를 합니다.

center

예상대로 굉장히 불규칙하고 랜덤한 형태의 decision boundary가 형성이 되네요. 결국 데이터를 분류하는 데에 일정한 규칙이 없다는 얘기겠죠? 그럼 K=5으로 5-NN model을 만들어 보면 어떨까요?

grid.pred = knn(Xlag[train,], grid, Direction[train], k=5) #5-NN model을 만듭니다.
plot(grid, col=grid.pred, pch=20) #예측이 어떻게 되는지 영역 표시를 합니다.

center

여전히 굉장히 불안정하고 불규칙적인 영역이 나오죠? 그래도 이런 엄청나게 혼재되고 섞여 있는 데이터가 아니라면, 일반적으로 K의 값이 커질수록 더 완만한 모습의 decision boundary를 얻으실 수 있습니다. 그 이유는 많은 점을 포함할수록 평균을 냈을 때나 다수결로 했을 때 더 consistent한 결과를 가져오기 때문입니다.

그럼 이제 모델을 만들었으니 얼마나 잘 예측하는지 확인해 봅시다.

#1-NN모델의 성능과
knn.pred=knn(Xlag[train,],Xlag[!train,],Direction[train],k=1)
table(knn.pred,Direction[!train])
##         
## knn.pred Down Up
##     Down   43 58
##     Up     68 83
mean(knn.pred==Direction[!train])
## [1] 0.5
#5-NN모델의 성능을 각각 확인합니다.
knn.pred=knn(Xlag[train,],Xlag[!train,],Direction[train],k=5)
table(knn.pred,Direction[!train])
##         
## knn.pred Down Up
##     Down   40 59
##     Up     71 82
mean(knn.pred==Direction[!train])
## [1] 0.484127

둘 다 만족할만한 성능이 아니네요 ㅠㅠ 특히나 1-NN의 성능이 5-NN의 성능보다 나은걸 보니 data가 매우 복잡한 decision boundary를 가질 것이라는 예측을 해 봅니다. 하지만 비록 좋은 성능은 얻지 못했지만, KNN이 어떻게 동작하는지 살펴볼 수 있는 좋은 기회였습니다 ^^