サポートベクターマシン(SVM)を実装してみよう!わかりやすく解説
【スマホからでも実行可能】サポートベクターマシン(SVM)の実装方法を初心者にもわかりやすく解説。Pythonコード付きで、実際に手を動かしながらSVMの仕組みと使い方を学べます。機械学習の基礎を固めたい方、SVMを実践で使ってみたい方におすすめです。
サポートベクターマシン(SVM)実践編へようこそ!
この「実践編」では、前回までの「入門編」や「活用例編」で学んだサポートベクターマシン(SVM)の知識を活かして、実際にコンピュータ上でSVMを動かしてみましょう。
SVMは、データとデータの間にある「境界線」を見つけ出し、それを使って新しいデータがどちらのグループに属するかを判断する手法でしたね。特に、その境界線の引き方が賢く、できるだけそれぞれのグループから離れた位置に引こうとするのが特徴でした。
今回は、プログラミング言語Pythonと、機械学習でよく使われるライブラリ「scikit-learn(サイキット・ラーン)」を使って、SVMを体験していきます。難しい理論は一旦置いておいて、まずは手を動かしてSVMがどのようにデータを分類するのかを見ていきましょう。
記事の最後に、環境構築なしでスマホからでも即実行可能なGoogle Colabノートブックをご用意しています。
準備するもの
SVMを動かすためには、まずお使いのコンピュータにPythonといくつかのライブラリがインストールされている必要があります。
-
Pythonのインストール: もしPythonがまだ入っていない場合は、公式サイトなどからダウンロードしてインストールしてください。バージョンは3系がおすすめです。
-
ライブラリのインストール: SVMの実装には、主に以下のライブラリを使用します。
- scikit-learn: 機械学習のための便利なツールがたくさん詰まったライブラリです。SVMもこの中に含まれています。
- NumPy: 数値計算を効率的に行うためのライブラリです。scikit-learnも内部でNumPyを利用しています。
- Matplotlib: データをグラフで表示するためのライブラリです。今回は、SVMがどのようにデータを分類したかを視覚的に確認するのに役立ちます(必須ではありませんが、あると理解が深まります)。
これらのライブラリは、Pythonのパッケージ管理システムであるpipを使って簡単にインストールできます。コマンドプロンプトやターミナルを開いて、以下のコマンドを一行ずつ実行してください。
pip install scikit-learn numpy matplotlib
これで準備は完了です。早速SVMを動かしてみましょう。
データを準備しよう
機械学習モデルを訓練するには、まずデータが必要です。今回は、scikit-learnライブラリに用意されている簡単なサンプルデータセットの一つである「アヤメ (iris) データセット」を使ってみましょう。
アヤメデータセットには、3種類のアヤメ(Setosa、Versicolor、Virginica)のがく片の長さ・幅、花びらの長さ・幅という4つの特徴量と、どのアヤメの種類かという情報が含まれています。今回は、このデータを使って、SVMがアヤメの種類を分類できるか試してみます。
まずは、必要なライブラリをPythonスクリプトに読み込み、データセットを準備するコードを見ていきましょう。
# 必要なライブラリを読み込みます
from sklearn.datasets import load_iris # アヤメデータセットを読み込むため
from sklearn.model_selection import train_test_split # データを訓練用とテスト用に分けるため
from sklearn.svm import SVC # SVMの分類器を使うため
from sklearn.metrics import accuracy_score # モデルの正解率を計算するため
import numpy as np # 数値計算のため
# アヤメデータセットを読み込みます
iris = load_iris()
# 今回は簡単にするために、4つの特徴量のうち最初の2つ(がく片の長さと幅)だけを使い、
# アヤメの種類も最初の2種類(SetosaとVersicolor)だけに絞ります。
# これにより、2次元のデータで視覚的に分かりやすくなります。
X = iris.data[:100, :2] # 最初の100サンプルの、最初の2つの特徴量
y = iris.target[:100] # 最初の100サンプルの、アヤメの種類
# データを訓練用とテスト用に分けます
# test_size=0.3 は、全体の30%をテストデータとして使うという意味です。
# random_state は、毎回同じように分割するための「種」のようなものです。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
print("訓練データの特徴量の形:", X_train.shape)
print("訓練データのラベルの形:", y_train.shape)
print("テストデータの特徴量の形:", X_test.shape)
print("テストデータのラベルの形:", y_test.shape)
上記のコードでは、まず必要なライブラリを import
しています。
次に load_iris()
でアヤメデータセットを読み込み、扱いやすいように特徴量とアヤメの種類を絞り込んでいます。X
が特徴量(がく片の長さと幅)、y
がアヤメの種類(0か1で表されます)です。
そして、train_test_split
という関数を使って、持っているデータを「訓練用データ」と「テスト用データ」に分けています。
- 訓練用データ (X_train, y_train): SVMモデルに「こういうデータが来たら、この種類ですよ」と学習させるために使います。
- テスト用データ (X_test, y_test): 学習が終わったSVMモデルが、未知のデータに対してどれくらい正しく分類できるかを評価するために使います。
なぜデータを分けるのでしょうか? それは、モデルが学習に使ったデータだけを完璧に覚えてしまい、新しいデータに対しては全く役に立たない「過学習(かしがくしゅう)」という状態になるのを避けるためです。テストデータを使うことで、モデルが未知のデータに対してもちゃんと機能するかどうかを客観的に評価できます。
SVMモデルを作って学習させよう
データが準備できたので、いよいよSVMモデルを作り、訓練データを使って学習させてみましょう。scikit-learnでは、数行のコードで簡単にSVMモデルを扱うことができます。
# SVMモデル(分類器)を作成します
# kernel='linear' は、線形の境界線で分類するという意味です。
# C=1.0 は、どれくらい誤分類を許容するかのパラメータです(詳細は後述)。
svm_model = SVC(kernel='linear', C=1.0, random_state=42)
# 訓練データを使ってSVMモデルを学習させます
svm_model.fit(X_train, y_train)
print("SVMモデルの学習が完了しました。")
たったこれだけです!詳しく見ていきましょう。
-
SVC(kernel='linear', C=1.0, random_state=42)
SVC
は Support Vector Classifier の略で、分類問題のためのSVMモデルです。kernel='linear'
を指定することで、「線形カーネル」という種類のSVMを使うことを指示しています。これは、データを直線(あるいは高次元空間では平面)で分割しようとする、最も基本的なタイプのSVMです。C=1.0
は「コストパラメータ」や「正則化パラメータ」と呼ばれるもので、モデルの複雑さと誤分類の許容度を調整します。C
の値が大きいほど、訓練データに対して誤分類を厳しく罰し、より複雑な境界線を引こうとします。小さいほど、ある程度の誤分類を許容し、より単純な境界線を引こうとします。最初はデフォルト値(1.0
)で試してみるのが良いでしょう。random_state
は、計算の再現性を保つために設定します。
-
svm_model.fit(X_train, y_train)
fit
メソッドは、モデルに訓練データ(X_train
)とそれに対応する正解ラベル(y_train
)を与えて学習させるための命令です。- この処理によって、SVMモデルは
X_train
のデータ点(アヤメのがく片の長さと幅)とy_train
のラベル(アヤメの種類)の関係性を学び、2つの種類を最もよく分ける境界線(専門的には「決定境界」や「超平面」と呼びます)を見つけ出そうとします。 - 具体的には、各クラス(アヤメの種類)に最も近いデータ点(これらを「サポートベクター」と呼びます)を見つけ出し、これらのサポートベクターから等距離にある、かつ最もマージン(境界線とサポートベクターとの距離)が大きくなるような境界線を引きます。
これで、svm_model
という名前の変数に、学習済みのSVMモデルが格納されました。
学習済みモデルで予測してみよう
モデルの学習が終わったら、次はそのモデルがどれくらいの性能を持っているかを確認します。ここで使うのが、先ほど分けておいた「テスト用データ(X_test
, y_test
)」です。
学習済みのSVMモデルにテストデータの特徴量(X_test
)を入力し、アヤメの種類を予測させてみましょう。
# テストデータを使って、アヤメの種類を予測します
y_pred = svm_model.predict(X_test)
print("テストデータに対する予測結果:", y_pred)
print("実際のテストデータの種類:", y_test)
svm_model.predict(X_test)
を実行すると、X_test
の各サンプル(アヤメ)に対して、学習済みモデルがどちらの種類に属すると判断したかの予測結果が y_pred
に格納されます。
y_pred
と、実際の答えである y_test
を見比べてみましょう。どれくらい一致しているでしょうか?
モデルの性能を評価しよう
予測結果と実際の答えを一つ一つ見比べるのは大変なので、もっと客観的にモデルの性能を評価する指標を使います。分類問題で最も基本的な評価指標の一つが「正解率(Accuracy)」です。正解率とは、全てのテストデータのうち、モデルが正しく分類できたデータの割合のことです。
scikit-learnには、この正解率を簡単に計算してくれる関数 accuracy_score
が用意されています。
# モデルの正解率を計算します
accuracy = accuracy_score(y_test, y_pred)
print(f"モデルの正解率: {accuracy * 100:.2f}%")
このコードを実行すると、学習したSVMモデルがテストデータに対してどれくらいの割合で正しくアヤメの種類を分類できたかがパーセンテージで表示されます。
例えば、「モデルの正解率: 100.00%」と表示されたら、今回用意したテストデータに関しては全て完璧に分類できたということになります。データや問題の複雑さによっては、100%にならないことももちろんあります。
どのように分類されたか見てみよう (任意)
もし matplotlib
ライブラリをインストールしていれば、SVMがどのようにデータを分類したのかをグラフで視覚的に確認することができます。これは、SVMの動作を理解する上で非常に役立ちます。
以下は、2次元のデータ(がく片の長さと幅)を使い、線形SVMが引いた境界線をプロットするコードの例です。
# Matplotlibをインポート (もしインストールしていなければ、このセクションはスキップしてください)
import matplotlib.pyplot as plt
# 決定境界をプロットする関数 (やや複雑なので、コピペでOKです)
def plot_decision_boundary(X, y, model, title):
x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
np.arange(y_min, y_max, 0.02))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', marker='o', s=100, linewidth=1)
plt.xlabel('Sepal length (がく片の長さ)')
plt.ylabel('Sepal width (がく片の幅)')
plt.title(title)
plt.show()
# 訓練データと決定境界をプロット
plot_decision_boundary(X_train, y_train, svm_model, 'SVM Decision Boundary on Training Data (Linear Kernel)')
# テストデータと決定境界をプロット
plot_decision_boundary(X_test, y_test, svm_model, 'SVM Decision Boundary on Test Data (Linear Kernel)')
# サポートベクターをプロット (もしあれば)
sv = svm_model.support_vectors_
if sv is not None and len(sv) > 0:
plt.scatter(sv[:, 0], sv[:, 1], s=200, facecolors='none', edgecolors='k', linewidths=2, label='Support Vectors')
plt.legend()
plot_decision_boundary(X, y, svm_model, 'SVM Decision Boundary with Support Vectors')
このコードを実行すると、データ点がプロットされ、その間にSVMが引いた境界線が表示されます。また、境界線を決定するのに重要だった「サポートベクター」も表示されることがあります(円で囲まれた点など)。
plot_decision_boundary
関数は、グラフ上に背景色としてモデルの予測領域を描画し、その上に実際のデータ点をプロットします。- 点が色分けされて表示され、境界線がそれらを分けている様子が確認できるはずです。
svm_model.support_vectors_
でサポートベクターの座標を取得し、それらを強調表示することもできます。
この視覚化を通じて、「なるほど、SVMはこんな風に線を引いてデータを分けているんだな」という直感的な理解が得られるでしょう。
SVMのパラメータを調整してみよう
先ほど SVC(kernel='linear', C=1.0)
とモデルを作成しましたが、ここには調整可能な「パラメータ」が含まれています。これらのパラメータを変えることで、SVMの性能が向上したり、逆に悪化したりすることがあります。
主要なパラメータをいくつか見てみましょう。
-
カーネル (kernel)
'linear'
: 線形カーネル。データが直線(または平面)で分けられる場合に有効です。'poly'
: 多項式カーネル。より複雑な曲線でデータを分けたい場合に使います。次数(degree
)や係数(gamma
,coef0
)といった追加のパラメータがあります。'rbf'
: RBF(Radial Basis Function)カーネル。非常に柔軟性が高く、複雑な境界線も描けます。こちらもgamma
という重要なパラメータがあります。デフォルトでよく使われます。'sigmoid'
: シグモイドカーネル。ニューラルネットワークに似た振る舞いをします。
例えば、RBFカーネルを試す場合は以下のようにします。
svm_rbf_model = SVC(kernel='rbf', C=1.0, gamma='scale', random_state=42) # gamma='scale' は推奨設定の一つ svm_rbf_model.fit(X_train, y_train) y_pred_rbf = svm_rbf_model.predict(X_test) accuracy_rbf = accuracy_score(y_test, y_pred_rbf) print(f"RBFカーネルSVMの正解率: {accuracy_rbf * 100:.2f}%") # RBFカーネルでの決定境界もプロットしてみましょう # plot_decision_boundary(X_train, y_train, svm_rbf_model, 'SVM Decision Boundary (RBF Kernel)')
線形カーネルではうまく分類できなかったデータも、RBFカーネルのような非線形カーネルを使うことで、よりうまく分類できるようになることがあります。
-
コストパラメータ C
- 前述の通り、
C
は誤分類に対するペナルティの大きさを調整します。 C
が大きい: 誤分類を許さず、訓練データにフィットさせようとします。マージンは狭くなる傾向があります。過学習のリスクが高まることがあります。C
が小さい: ある程度の誤分類を許容し、より汎用的な(滑らかな)境界線を引こうとします。マージンは広くなる傾向があります。学習不足になるリスクがあります。
C
の値を例えば0.1
や10
に変えてみて、正解率や決定境界がどう変わるか試してみるのも良いでしょう。svm_c_high_model = SVC(kernel='linear', C=100.0, random_state=42) # Cを大きくする svm_c_high_model.fit(X_train, y_train) # ... (評価) svm_c_low_model = SVC(kernel='linear', C=0.01, random_state=42) # Cを小さくする svm_c_low_model.fit(X_train, y_train) # ... (評価)
- 前述の通り、
-
ガンマ (gamma) (RBFカーネル、多項式カーネル、シグモイドカーネルで使われます)
gamma
は、一つの訓練サンプルが影響を及ぼす範囲を決定します。gamma
が小さい: 影響範囲が広く、境界線はより滑らかになります。gamma
が大きい: 影響範囲が狭く、境界線はより複雑になり、訓練データに細かくフィットしようとします。過学習のリスクが高まります。'scale'
(デフォルト):1 / (n_features * X.var())
として計算されます。'auto'
:1 / n_features
として計算されます。
gamma
の値も変えて実験してみると、モデルの振る舞いが大きく変わることが分かります。
これらのパラメータを適切に設定することは「ハイパーパラメータ調整」と呼ばれ、モデルの性能を最大限に引き出すために非常に重要です。手動で一つ一つ試すのは大変なので、「グリッドサーチ」や「ランダムサーチ」といった自動で最適なパラメータの組み合わせを見つける手法も存在します。これらは少し発展的な内容になりますが、興味があれば調べてみてください。
まとめ
今回は、Pythonとscikit-learnを使って、サポートベクターマシン(SVM)を実際に動かしてみました。
- データの準備(読み込み、特徴量の選択、訓練データとテストデータへの分割)
- SVMモデルの作成(カーネルの選択、パラメータCの設定)
- モデルの学習 (
fit
メソッド) - 学習済みモデルによる予測 (
predict
メソッド) - モデルの性能評価(正解率の計算)
- (任意)決定境界の視覚化
- 主要なパラメータ(カーネル、C、gamma)の簡単な紹介
これらのステップを通して、SVMがどのようにデータを分類するのか、そしてその使い方について具体的なイメージが湧いたのではないでしょうか。
SVMは非常に強力な分類手法であり、さまざまな分野で活用されています。線形分離可能なデータだけでなく、カーネルトリックという工夫によって非線形なデータにも対応できるのが大きな強みです。
今回の実践編でSVMの基本的な使い方をマスターしたら、次はより複雑なデータセットに挑戦したり、異なるカーネルやパラメータ設定を試したりして、SVMのさらなる可能性を探求してみてください。また、グリッドサーチなどのハイパーパラメータ最適化手法についても学んでみると、より高性能なモデルを構築できるようになるでしょう。
これで、サポートベクターマシンの実践編は終わりです。実際に手を動かして学ぶことで、理論だけでは得られない深い理解が得られたことと思います。
図解即戦力 機械学習&ディープラーニングのしくみと技術がこれ1冊でしっかりわかる教科書
エンジニア1年生、機械学習関連企業への就職・転職を考えている人が、機械学習・ディープラーニングの基本と関連する技術、しくみ、開発の基礎知識などを一通り学ぶことのできる、最初の1冊目にふさわしい入門書を目指します。
▶ Amazonで見る環境構築なしで
実行できるファイルはこちら!
このボタンからGoogle Colabを開き、すぐにコードをお試しいただけます。
関連する記事
ランダムフォレストを実装してみよう!わかりやすく解説
【スマホからでも実行可能】ランダムフォレストの実装方法をPythonコード付きで丁寧に解説。機械学習のアンサンブル学習を実際に動かして理解を深めましょう。初心者にもわかりやすい実践ガイドです。
勾配ブースティング木(Gradient Boosted Trees)を実装してみよう!わかりやすく解説
【スマホからでも実行可能】勾配ブースティング木は、機械学習の分野で非常に強力な予測モデルの一つです。この記事では、その仕組みとPythonによる具体的な実装方法を、初心者にも分かりやすく解説します。実際にコードを動かしながら、この強力なアルゴリズムを体験してみましょう。
決定木(Decision Tree)を実装してみよう!わかりやすく解説
【スマホからでも実行可能】決定木の実装方法をPythonコード付きでステップバイステップ解説。データの準備からモデル構築、可視化、評価、チューニングまで、実践的なスキルが身につきます。機械学習の基本である決定木をマスターしましょう。
粒子群最適化(PSO)を実装してみよう!わかりやすく解説
【スマホからでも実行可能】粒子群最適化(PSO)のアルゴリズムをPythonで実装し、その仕組みを初心者にもわかりやすく解説します。最適化問題や機械学習に興味がある方におすすめです。パラメータ設定のコツや応用例も紹介し、実践的な理解を深めます。
k近傍法(k-NN)を実装してみよう!わかりやすく解説
【スマホからでも実行可能】k近傍法(k-NN)アルゴリズムについて、Pythonでの具体的な実装方法をステップバイステップで丁寧に解説します。機械学習の基本的な手法を実際に手を動かして理解したい方、データ分類タスクに挑戦したい方におすすめです。