본문 바로가기

머신러닝, 딥러닝

[머신러닝] 8. 서포트 벡터 머신(feat. R Code)

장점

  • 범주, 수치 예측 문제에 사용
  • 오류 데이터 영향이 적음
  • 과적합 되는 경우가 적음
  • 신경망보다 사용하기 쉬움

단점

  • 여러 조합의 테스트가 필요
  • 학습 속도가 느림
  • 해석이 어렵고 복잡한 블랙박스

 


R Code

서포트 벡터 분류기

set.seed(1)
x=matrix(rnorm(20*2), ncol=2)
y=c(rep(-1, 10), rep(1, 10))
x[y==1,]=x[y==1,]+1
plot(x, col=(3-y))
  • 두 클래스에 속하는 관측치들을 생성한다.

library(e1071)

dat=data.frame(x=x, y=as.factor(y))
svmfit=svm(y~., data=dat, kernel='linear', cost=10, scale=FALSE)

plot(svmfit, dat)

  • svm()함수는 인자 kernel='linear'가 사용될 경우 서포트 벡터 분류기를 적합하는 데 사용될 수 있다.
  • cost 인자는 마진 위반에 대한 비용을 지정한다. cost인자가 작으면 마진이 넓을 것이고 많은 서포트 벡터들이 마진 상에 있거나 마진을 위반할 것이다.
svmfit$index
## [1]  1  2  5  7 14 16 17
summary(svmfit)
## Call:
## svm(formula = y ~ ., data = dat, kernel = "linear", cost = 10, 
##    scale = FALSE)
##
## Parameters:
##    SVM-Type:  C-classification 
##  SVM-Kernel:  linear 
##        cost:  10 
##
## Number of Support Vectors:  7
##  ( 4 3 )
##
## Number of Classes:  2 
## Levels: 
##  -1 1
  • 7개의 서포트 벡터가 있음을 볼 수 있다.
  • summary를 통해 선형 커널이 cost=10을 가지고 사용되었으며, 7개의 서포트 벡터가 있는데, 한 클래스에 4개 다른 클래스에 3개가 있음을 알 수 있다.
svmfit=svm(y~., data=dat, kernel='linear', cost=0.1, scale=FALSE)
plot(svmfit, dat)
svmfit$index
## [1]  1  2  3  4  5  7  9 10 12 13 14 15 16 17 18 20

  • 더 작은 값은 cost 파라미터를 사용하면, 마진이 넓어지기 때문에 더 많은 수의 서포트 벡터를 얻는다.
set.seed(1)
tune.out<-tune(svm, y~., data=dat, kernel='linear',
	ranges=list(cost=c(0.001, 0.01, 0.1, 1, 5, 10, 100)))
summary(tune.out)
## Parameter tuning of ‘svm’:
##
## - sampling method: 10-fold cross validation 
##
## - best parameters:
##  cost
##   0.1
##
## - best performance: 0.05 
##
## - Detailed performance results:
##    cost error dispersion
## 1 1e-03  0.55  0.4377975
## 2 1e-02  0.55  0.4377975
## 3 1e-01  0.05  0.1581139
## 4 1e+00  0.15  0.2415229
## 5 5e+00  0.15  0.2415229
## 6 1e+01  0.15  0.2415229
## 7 1e+02  0.15  0.2415229
  • e1071라이브러리는 교차검증을 수행하기 위해 내장 함수 tune()을 포함한다. 기본적으로 tune()은 관심있는 모델 셋(집합)에 대해 10-fold 교차검증을 수행한다.
  • cost=0.1인 경우 교차검증 오차율이 가장 낮다는 것을 알 수 있다.
bestmod=tune.out$best.model
summary(bestmod)
## Call:
## best.tune(method = svm, train.x = y ~ ., data = dat, ranges = list(cost = c(0.001, 
##     0.01, 0.1, 1, 5, 10, 100)), kernel = "linear")
##
## Parameters:
##    SVM-Type:  C-classification 
##  SVM-Kernel:  linear 
##       cost:  0.1 
##
## Number of Support Vectors:  16
##  ( 8 8 )
##
## Number of Classes:  2 
##
## Levels: 
##  -1 1
  • tune()함수는 얻어진 최고 모델을 저장하며, 이것은 다음과 같이 액세스 될 수 있다.
xtest=matrix(rnorm(20*2), ncol=2)
ytest=sample(c(-1, 1), 20, rep=TRUE)
xtest[ytest==1,]=xtest[ytest==1,]+1
testdat=data.frame(x=xtest, y=as.factor(ytest))

ypred=predict(bestmod, testdat)
table(predict=ypred, truth=testdat$y)
##        truth
## predict -1 1
##      -1  9 1
##      1   2 8
  • 예측에는 교차검증을 통해 얻은 최고의 모델을 사용한다.

 

서포트 벡터 머신

set.seed(1)
x=matrix(rnorm(200*2), ncol=2)
x[1:100,]=x[1:100,]+2
x[101:150,]=x[101:150,]-2
y=c(rep(1,150), rep(2,50))
dat=data.frame(x=x, y=as.factor(y))
plot(x, col=y)

train=sample(200, 100)
svmfit=svm(y~., data=dat[train,], kernel='radial', gamma=1, cost=1)
plot(svmfit, dat[train,])

  • 다항식 커널을 가지고 SVM을 적합하기 위해서는 kernel='polynomial'을 사용하고, 방사커널로 SVM을 적합하는 데는 kernel='radial'을 사용한다. 전자의 경우 degree 인자도 사용하여 다항식 커널에 대한 차수를 지정하고, 후자의 경우에는 gamma를 사용하여 방사기저커널에 대한 gamma값을 지정한다.
  • 데이터를 그래프로 나타내어 보면 클래스 경계가 비선형이라는 것을 명백히 알 수 있다.
svmfit=svm(y~., data=dat[train,], kernel='radial', gamma=1, cost=1e5)
plot(svmfit, dat[train,])

  • 그림을 보면 이 SVM적합에는 상당한 수의 훈련오차가 있음을 알 수 있다. cost값을 증가시키면 훈련오차의 수를 줄일 수 있지만, 이것은 데이터를 과대적합할 위험이 있는 더 불규칙한 결정경계를 초래한다.
set.seed(1)
tune.out=tune(svm, y~., data=dat[train,], kernel='radial',
	ranges=list(cost=c(0.1, 1, 10, 100, 1000),
	gamma=c(0.5, 1, 2, 3, 4)))
summary(tune.out)

table(true=dat[-train,'y'], pred=predict(tune.out$best.model, newdata=dat[-train,]))

 

 

ROC 곡선

library(ROCR)
rocplot<-function(pred, truth, ...){
	predob=prediction(pred, truth)
	perf=performance(predob, 'tpr', 'fpr')
	plot(perf, ...)}

svmfit.opt<-svm(y~., data=dat[train,], kernel='radial',
	gamma=2, cost=1, decision.values=T)
fitted<-attributes(predict(svmfit.opt, dat[train,], decision.values=TRUE))$decision.values
rocplot(fitted, dat[train,'y'], main='Training Data')

svmfit.flex<-svm(y~., data=dat[train,], kernel='radial',
	gamma=50, cost=1, decision.values=T)
fitted<-attributes(predict(svmfit.flex, dat[train,], decision.values=T))$decision.values
rocplot(fitted, dat[train,'y'], add=T, col='red')