Quiet Time

▣ R 를 활용한 기계학습 7장. 블랙박스 기법 : 신경망과 서포트 벡터 머신 신경망 (p286)

■  서포트 벡터 머신이란(Support Vector Machine: SVM)?
서포트 벡터 머신이란 간단히 말해 이진 분류기이다. 
 SVM 목적은 초평면(hyperplane) 기준으로 한쪽 면으로 동일한 데이터가 놓이게 평평한 경계를 만드는 것이다.



 
  • 초평면 (hyperplane)?
SVM 보통 범주 값을 유사한 데이터들로 그룹짓기 위해 초평면(hyperplane )이라는 경계를 사용하는데

hyperplane은 n-1차원의 subspace를 의미하는 것이며, 3차원의 경우 hyperplane은 2차원의 면이 되고, 2차원의 경우는 hyperplane은 1차원의 선이된다








 ■  Kernel Tricks 기법: 선형분리가 불가능한 데이터나
비선형 data들을 차원 높여서 분리하는 방법

이렇게 1차원 데이터를 2차원으로 높이게 되면 분리가 가능하다.

그림을 보면 왼쪽 평면에 있는 sample들이 오른쪽과 같이 변형되었는데, 이것은 sample들이 있는 공간을 kernel 함수를 이용하여 공간을 3차원 공간으로 변형시켜주었기 때문이다. 그런 다음 3차원 공간에서 hyperplane을 이용하면 cancer와 normal 샘플들을 좀 더 쉽게 구별할 수 있게 된다.
 



 
왼쪽 그림에서는 대각선 방향의 직선이 최대 여백 초평면(Maximum Margin Hyperplane) 해당한다. 그리고 직선과 가장 가까운 분류에 속한 점들을 서포트 벡터 라고한다.























■  실습1 : 붓꽃 데이터 분류--- 1. Data set : 기본제공(iris)
data(iris)
install.packages("ggplot2")
library(ggplot2)
gplot(Petal.Length, Petal.Width, data=iris, color = Species) #실제 데이터를 확인
library(e1071)
s<-sample(150,100)       # 1 ~ 150 까지 중복되지 않는 랜덤수를 100개 생성
col<- c("Petal.Length", "Petal.Width", "Species")    # 컬럼명 지정 꽃잎 길이 , 꽃잎 폭, 종류
iris_train <- iris[s,col]      # 랜덤으로 뽑은 100개의 트레이닝 셋
iris_test <- iris[-s,col]       # 나머지 테스트 셋

# 리니어 커널방식으로 트레이닝 셋을 종류별로 모델링한다.
iris_svm <- svm(Species ~. , data=iris_train, cost=1,kernel ="linear")
plot(iris_svm, iris_train[,col])

# svm로 훈련된 모델과 테스트데이터로 결과예측
p<- predict(iris_svm,iris_test[,col],type="class")
plot(p)
table(p, iris_test[,3])
mean( p == iris_test[,3])







■  실습2 : 광학식 문자 인식 ---- 1. Data set : letterdata.csv
# 각 글자모양의 속성들을 수치화 한 데이터
# 데이터 읽기와 구조
letters <- read.csv("letterdata.csv")
str(letters)

# 훈련 데이터와 테스터 데이터 구분
letters_train <- letters[1:16000, ]
letters_test  <- letters[16001:20000, ]
## 3단계 : 데이터로 모델 훈련 ----
# 단순 선형 SVM을 훈련으로 시작
install.packages(“kernlab”)
library(kernlab)
letter_classifier <- ksvm(letter ~ ., data = letters_train, kernel = "vanilladot")
# 모델에 대한 기본 정보 확인
letter_classifier


## 4단계 : 모델 성능 평가 ----
# 테스트 데이터셋에 대한 예측
letter_predictions <- predict(letter_classifier, letters_test)

head(letter_predictions)

table(letter_predictions, letters_test$letter)

# 일치/불일치 예측을 표시하는 TRUE/FALSE 벡터 생성
agreement <- letter_predictions == letters_test$letter
table(agreement)
prop.table(table(agreement))

## 5단계 : 커널을 바꿔서 모델 성능을 향상시켜보자 ----
## 가우시안 RBF 커널을 사용
##  RBF ? 링크 -> [Radial Basis Function(방사 기저 함수)]
letter_classifier_rbf <- ksvm(letter ~ ., data = letters_train, kernel = "rbfdot")
letter_predictions_rbf <- predict(letter_classifier_rbf, letters_test)

agreement_rbf <- letter_predictions_rbf == letters_test$letter
table(agreement_rbf)
prop.table(table(agreement_rbf))
prop.table(table(agreement))


향상 됐음!

■  실습3 : 산불데이터 forestfires.csv
install.packages("dplyr")
install.packages("kernlab")
install.packages("ROCR")
install.packages("caret")
install.packages("e1071")
library(dplyr)
library(kernlab)
library(ROCR)
library(caret)
library(e1071)

mydata <- read.csv('forestfires.csv',header =T)
hist(mydata$area)
rug(mydata$area)

# area값들을 분석하기 쉽게 변경 log값을 씌워서 y컬럼으로 추가한다.
mydata <- mutate(mydata, y = log(area + 1))

normalise <- function(x) {  #정규화함수
  return((x - min(x)) / (max(x) - min(x))) }
 
#분석할 값들을 정규화한다.
mydata$temp <- normalise(mydata$temp)
mydata$rain <- normalise(mydata$rain)
mydata$RH <- normalise(mydata$RH)
mydata$wind <- normalise(mydata$wind)

#산불 넓이가 5헥타르 이상인 것을 large 아니면 small로 놓고 분석한다.
mydata$size <- factor(ifelse(mydata$y< 2, 1, 0),
                       labels = c("large", "small"))
#tail(mydata[, c("size", "area")]) 
train <- sample(x = nrow(mydata), size = 400, replace = FALSE)
# 각 커널 방식 비교
# polydot커널 방식으로 svm
m.poly <- ksvm(size ~ temp + RH + wind + rain,
          data = mydata[train, ],
          kernel = "polydot", C = 1)

pred <- predict(m.poly, newdata = mydata[-train, ], type = "response")
 
table(pred, mydata[-train, "size"])
mean(pred == mydata[-train, "size"])


# tanhdot 커널 방식으로 svm
m.tan <- ksvm(size ~ temp + RH + wind + rain,
          data = mydata[train, ],
          kernel = "tanhdot", C = 1)

pred <- predict(m.tan, newdata = mydata[-train, ], type = "response")
 
table(pred, mydata[-train, "size"])
mean(pred == mydata[-train, "size"])


# rbfdot 커널 방식으로 svm
m.rad <- ksvm(size ~ temp + RH + wind + rain,
          data = mydata[train, ],
          kernel = "rbfdot", C = 1)
pred <- predict(m.rad, newdata = mydata[-train, ], type = "response")
 
table(pred, mydata[-train, "size"])
mean(pred == mydata[-train, "size"])