# SVM(サポートベクターマシン)とは？特徴とRによる実装！

> 当サイト【スタビジ】の本記事では、機械学習手法の中でもアルゴリズムが分かりやすい上に汎化能力が高い優秀な手法SVM（サポートベクターマシン）についてまとめていきます！理論とRでの実装を合わせて見ていきますよー！

- URL: https://toukei-lab.com/svm
- 公開: 2022.11.29 / 更新: 2024.12.08
- サイト: スタビジ（https://toukei-lab.com）

:::talk{who="umatan"}
当サイト【スタビジ】の本記事では、機械学習手法の中でもアルゴリズムが分かりやすい上に汎化能力が高い優秀な手法SVM（サポートベクターマシン）についてまとめていきます！理論とRでの実装を合わせて見ていきますよー！
:::

こんにちは！

データサイエンティストのウマたん([@statistics1012](https://twitter.com/statistics1012?lang=ja))です！

機械学習手法の中でも<mark>汎化能力が高いとされ使われることの多いSVM（サポートベクターマシン）</mark>

この記事では、そんなSVM（サポートベクターマシン）について見ていきます！

:::talk{who="umatan"}
SVMは実装が容易でそれなりに高い精度をたたき出す優秀な手法だよ！
:::

:::box{title="読み飛ばしガイド"}
・[SVM（サポートベクターマシン）とは](/svm#SVM)\
・[SVMのメリット](/svm#SVM-2)\
・[SVMをRで実装してみよう！](/svm#SVMR)
:::

以下の動画でも簡単に解説していますよ！

::youtube{#v5Ed_DJenNQ}

他の手法についてはこちらも合わせてチェック！

<https://toukei-lab.com/pattern-recognition>

<https://toukei-lab.com/ai-term>

## SVM（サポートベクターマシン）とは

![](/wp-content/uploads/2019/04/52ceff2ccf51b6465679ab4c976fc8b0_s.jpg)

SVMとは、<mark>機械学習の中でも有名な手法の1つ。</mark>

SVMの特徴は、「**マージン最大化**」と「**カーネルトリック**」。

順番に見ていきましょう！

### マージン最大化

SVMは「<mark>マージン最大化</mark>」というアイデアで分類データにおいて非常に高い精度をほこります。

以下の図を見てみてください。

![](/wp-content/uploads/2019/06/svm.jpg)

〇と△で分類したいのですが左のような識別境界線を引いてしまうと、<mark>新たな未知の〇データに関して上手く分類することができません。</mark>

なるべく、右の図のように〇と△の中間地点に識別境界線を引くべきです。

そして、この場合見なくちゃいけないのは境界に近い〇と△のデータ。

これら<mark>境界に近いデータのことをサポートベクトルと呼びます。</mark>

これらのサポートベクトルのマージンが最大になるように境界線を引く方法が「**マージン最大化**」であり、SVMの肝になる手法です。

マージン最大化については視覚的に分かりやすいので大丈夫だと思います。

### カーネルトリック

**カーネルトリック**は<mark>少々難易度高</mark>です。

正直僕自身も完璧に理解しているとは言い難い・・笑

先ほどの例では、線形直線を引いて分類を行いました。

しかしデータの構造的に<mark>線形直線で分類出来ることばかりではありません。</mark>

データが真ん中に内側と外側に集まっている以下の図のようなパターンもあります。

![](/wp-content/uploads/2019/06/svm2.jpg)

そんな時、左図のように直線では分類できません。

右図のような<mark>非線形の識別境界線が必要になってくるのです。</mark>

非線形な識別境界線を引くには、データを**非線形変換**する必要があります。

データ構造が複雑になればなるほど、非線形変換は大変です。

そこで登場するのがカーネルトリック。

カーネルトリックでは、<mark>そのような複雑な非線形変換をせずとも非線形識別境界線を引くことが可能なのです。</mark>

## SVMのメリット

![](/wp-content/uploads/2019/03/a94310ed4de4a08528a026f0badfdb2f_s-e1556972696222.jpg)

SVMについてなんとなく理解いただけたでしょうか？

さて、そんなSVMですが数ある<mark>機械学習手法と比べた時にどんなメリットがあるのでしょうか？</mark>

SVMの特徴である「**マージン最大化**」は、学習データを完璧に分類できれば良い！という考え方とは少し違います。

実は、ある程度分類ができなくても良いというマージンを**ソフトマージン**、なるべく完璧に分類するようなマージンを**ハードマージン**と呼んでいます。

SVMの場合は、ソフト・ハードあれど、マージン最大化を行うことが目的であるので、<mark>無理やり全ての学習データを分類するようなモデルは作りません。</mark>

一方、他の機械学習手法は学習データに対して過度にフィッティングし完璧に分類しようとします。

そうすると起きるのが[過学習](/over-fitting)と呼ばれる現象。過適合などとも言ったりしますね。

過学習とは、<mark>学習モデルにフィッテングし過ぎて、あらたなデータに対する予測精度が悪化してしまうこと。</mark>

これは、機械学習手法で結構起こり得る問題なんです。

SVMは、「**マージン最大化**」というアルゴリズムから過学習が起こりにくくなっているんです。

## SVMをRで実装してみよう！

![](/wp-content/uploads/2018/09/S_8608589564326.jpg)

それでは、最後にSVMをRで実装してみます。

**有名なタイタニックのデータ**を用います。[Kaggleの公式サイト](https://www.kaggle.com/c/titanic/data)からデータをダウンロードできます。

まず、データのクレンジングを行い、欠損値は削除、不要と考えられる項目は削除しました。

**項目8つ**

:::box
Survived：生死　pclass：客室のクラス　sex：性別　age：年齢　sibsp：兄弟・配偶者の数　parch：親・子供の数　fare：乗船料金　embarked：乗船した港
:::

**サンプル数714**

この時、生死を目的変数としそれ以外を説明変数とします。

サンプル数714のうちランダムに400個のデータを取り出し学習データとし、残りの314を予測データとします。

学習データで予測モデルを作り、予測データにあてはめ真値と予測値の判別率を精度として比較します。

シミュレーション回数は1000回とし、上記の手順を1000回繰り返し、結果を平均したものを最終アウトプットとします。そのため、結果はばらつきがなく確からしい結果になっているはずです。

SVM(サポートベクターマシン)を[ランダムフォレスト](/%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%83%95%E3%82%A9%E3%83%AC%E3%82%B9%E3%83%88)、[ナイーブベイズ](/naivebaise)、[ニューラルネットワーク](/nn)、[XGboost](/xgboost)、[k近傍法](/%ef%bd%8b%e8%bf%91%e5%82%8d%e6%b3%95)の5手法と比較します！

基本的に引数は全部デフォルトで！果たして結果はどうなるでしょうか！

```r title="knn-comparison.R"
##様々な手法で予測精度の比較を行う##
##randomForest,SVM,ナイーブベイズ，ニューラルネット
library(xgboost)
library(caret)
library(Matrix)
library(kernlab)
library(randomForest)
library(e1071)
library(nnet)
library(ggplot2)
library(class)
titanic<-read.csv("タイタニック乗船者リスト.csv")##データの読み込み
titanic<-na.omit(titanic)##欠損値削除
titanic$Survived<-as.factor(titanic$Survived)##質的変数に変換
sim<-10##シミュレーション回数
result<-matrix(0,sim,6)##結果の箱
titanic[,4]<-as.numeric(titanic[,4])
titanic[,9]<-as.numeric(titanic[,9])

for(i in 1:sim){
  ####学習データとテストデータに分ける####
  train.id<-sample(nrow(titanic),400)
  train.data<-titanic[train.id,-1]
  test.data<-titanic[-train.id,-1]
  
  
  ##randomForest##
  rf<-randomForest(Survived~.,train.data)
  test.data.rf<-cbind(test.data,"predict"=predict(rf,test.data))
  result[i,1]<-sum(test.data.rf$predict==test.data.rf$Survived)/nrow(test.data.rf)
  
  
  ##SVM##
  svm<-ksvm(Survived~.,train.data)
  test.data.svm<-cbind(test.data,"predict"=predict(svm,test.data))
  result[i,2]<-sum(test.data.svm$predict==test.data.svm$Survived)/nrow(test.data.svm)
  
  ##ナイーブベイズ##
  nb<-naiveBayes(Survived~.,train.data)
  test.data.nb<-cbind(test.data,"predict"=predict(nb,test.data))
  result[i,3]<-sum(test.data.nb$predict==test.data.nb$Survived)/nrow(test.data.nb)
  
  ##ニューラルネット##
  nn<-nnet(Survived~.,train.data,size=5)
  test.data.nn<-cbind(test.data,"predict"=round(predict(nn,test.data),0))
  result[i,4]<-sum(test.data.nn$predict==test.data.nn$Survived)/nrow(test.data.nn)
  
  ##XGboost##
  label.data.train<-as.integer(train.data$Survived)-1##目的変数を01に
  label.data.predict<-as.integer(test.data$Survived)-1
  
  train.data.xg<-train.data[,-1]##目的変数取り除く
  test.data.xg<-test.data[,-1]
  
  xgb.data<-xgb.DMatrix(data.matrix(train.data.xg),label=label.data.train)##Xgb型へ成型
  xgb.data.predict<-xgb.DMatrix(data.matrix(test.data.xg))
  
  param <- list(
    "objective" = "binary:logistic"
    ,"eta" = 0.01
    # ,"max_depth" = 10
    ,"min_child_weight" = 5
    # ,"subsample" = 1
    # ,"colsample_bytree" = 1
  )##パラメータ適当
  
  model <- xgboost(
    param=param
    ,data=xgb.data
    ,nrounds=1000
  )##実際の学習
  
  predict_xgb<-predict(model,xgb.data.predict)
  
  a<-c()
  m<-length(predict_xgb)#行数
  
  for(l in 1:m){
    if(predict_xgb[l]>0.5){a[l]<-1}
    else{a[l]<-0}
  }
  result[i,5]<-sum(a==label.data.predict)/length(a)
  
  #k-nn
  knn<-knn(train.data,test.data,train.data[,"Survived"] ,prob=T,k=3)
  test.data.knn<-cbind(test.data,"predict"=knn)
  result[i,6]<-sum(test.data.knn$predict==test.data.knn$Survived)/nrow(test.data.knn)
  
}

result.c<-apply(result,2,mean)##simの平均値
result.c<-t(as.matrix(result.c))
result.c<-rbind(result.c,result.c)
result.c<-round(result.c,3)
##グラフ描画
colnames(result.c) <- c("RF","SVM","Bayes","NN","xgb","knn")
df<-data.frame(method=colnames(result.c),result=colMeans(result.c))
gp<-ggplot(df,aes(x=method,y=result,fill=method))
gp<-gp+geom_bar(width=0.8,stat="identity")
gp<-gp+ylab("result")
gp<-gp+geom_text(label=colMeans(result.c),vjust=1)
plot(gp)
```

kernlabというパッケージに入っているksvmという関数を用いて解析を行っていきます。

> \##SVM##\
> svm<-ksvm(Survived\~.,train.data)\
> test.data.svm<-cbind(test.data,”predict”=predict(svm,test.data))\
> result\[i,2]<-sum(test.data.svm\$predict==test.data.svm\$Survived)/nrow(test.data.svm)

データ加工は描画でいくつかコードを書いていますが、実際にSVMを行っているのはこの数行！

Survived\~.はSurvivedを目的変数としてそれ以外を説明変数にするよーということです。

結果は以下のようになりました！

![](/wp-content/uploads/2018/02/ml-comparison.png) それぞれBayes（ナイーブベイズ）、knn（k近傍法）、NN（ニューラルネットワーク）、RF（ランダムフォレスト）、SVM（サポートベクターマシン）、xgb（XGboost）と表示しています。

見事SVMの勝利！やはりランダムフォレスト・SVM・XGboostあたりが強いですね！

SVMが若干ランダムフォレストよりも精度が良いという結果になっています。

ちなみに計算速度はランダムフォレストの方が速く、SVMは若干遅めです。

## SVM（サポートベクターマシン）　まとめ

本記事では、**SVMの特徴と実装方法**について見てきました。

最後にまとめておきましょう！

:::point
**・マージン最大化により過学習しにくい**\
**・カーネルトリックにより非線形データでも計算負荷を抑えられている**\
**・実装が簡単**
:::

SVMは非常に優秀な手法ですが、実装が簡単なので是非試してみてください！

:::talk{who="umatan"}
もっと踏み込んで知りたい人はカーネルトリックについて調べてみるとよいよ！
:::

SVMに関してもっと詳しく知りたいかたは以下の書籍を参考にしてみてください！

::product[はじめてのパターン認識]{url="https://www.amazon.co.jp/dp/4627849710?tag=statistic08-22&linkCode=ogi&th=1&psc=1" image="https://m.media-amazon.com/images/I/51YFB3Y0EYL._SL160_.jpg" amazon="https://www.amazon.co.jp/dp/4627849710?tag=statistic08-22&linkCode=ogi&th=1&psc=1" rakuten="https://af.moshimo.com/af/c/click?a_id=858168&p_id=54&pc_id=54&pl_id=616&url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2F%25E3%2581%25AF%25E3%2581%2598%25E3%2582%2581%25E3%2581%25A6%25E3%2581%25AE%25E3%2583%2591%25E3%2582%25BF%25E3%2583%25BC%25E3%2583%25B3%2F%3Ff%3D1%26grp%3Dproduct"}

::product[入門パターン認識と機械学習]{url="https://www.amazon.co.jp/dp/4339024791?tag=statistic08-22&linkCode=ogi&th=1&psc=1" image="https://m.media-amazon.com/images/I/514HpqIAd2L._SL160_.jpg" amazon="https://www.amazon.co.jp/dp/4339024791?tag=statistic08-22&linkCode=ogi&th=1&psc=1" rakuten="https://af.moshimo.com/af/c/click?a_id=858168&p_id=54&pc_id=54&pl_id=616&url=https%3A%2F%2Fsearch.rakuten.co.jp%2Fsearch%2Fmall%2F%25E5%2585%25A5%25E9%2596%2580%25E3%2583%2591%25E3%2582%25BF%25E3%2583%25BC%25E3%2583%25B3%25E8%25AA%258D%25E8%25AD%2598%2F%3Ff%3D1%26grp%3Dproduct"}

ちなみにランダムフォレストをはじめとした機械学習に関して深く勉強したい方は以下の記事を見てみてください！

<https://toukei-lab.com/machine-learning-study>

データサイエンス全般について知りたい方は以下の記事をご覧ください。

<https://toukei-lab.com/data-scientist>

また、今回はRを使ってきましたが機械学習の文脈ではPythonの方がよく使われていたりします。Pythonを勉強したい方は以下をチェックしてみてください！

<https://toukei-lab.com/python-learn>

またこれらの知識を総合的に学べる「**[スタビジアカデミー（スタアカ）](https://toukei-lab.com/achademy/)**」というスクールを当メディアで運営しておりますので興味のある方は是非チェックしてみてください！

:::box
[**業界最安級のAIデータサイエンス特化スクール「スタビジアカデミー」**](https://toukei-lab.com/achademy/)
:::