結論

SVM(サポートベクターマシン)とは、2つのクラスの間に「いちばん余白(マージン)が広くなる境界線」を引いて分類する機械学習の手法です。境界の位置は、境界にいちばん近い少数の点(サポートベクター)だけで決まり、カーネルを使うと曲がった境界も引けます。

この記事でわかること

  • マージン最大化とサポートベクターを8点の例で計算した数字
  • ヒンジ損失の勾配降下で自作した線形SVMと、SVC・LinearSVCの一致
  • C・gamma・カーネル・標準化・件数で精度と時間がどう変わるかの実測

2026年11月5日更新|scikit-learn 1.9.1・numpy 2.5.3・Python 3.13で実行確認

この記事で実際に動かしたもの:8点の手作りデータでのマージンの計算、numpyで書いた線形SVM(ヒンジ損失の勾配降下・約15行)とカーネルSVMの予測式、scikit-learn 1.9.1 の SVC・LinearSVC・SVR・SGDClassifier・Nystroem・CalibratedClassifierCV(同梱データ breast_cancer・wine・iris・digits・diabetes と make_moons・make_circles・make_classification)。

下の図は、SVMが学習して予測するまでの流れです。

flowchart TD
    A["訓練データ<br>特徴量とラベル"] --> B["標準化<br>StandardScaler"]
    B --> C{"カーネルを選ぶ"}
    C -->|線形| D["直線・平面の境界"]
    C -->|RBF・多項式| E["曲がった境界"]
    D --> F["マージン最大化<br>Cで誤分類をどこまで許すか"]
    E --> F
    F --> G["サポートベクターだけが残る"]
    G --> H["予測: 符号で分類<br>decision_function"]

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
SVMとは マージン(境界と最も近い点の距離)が最大になる境界で分類する手法。回帰(SVR)にも使える SVMとは
サポートベクターとは 境界に最も近く、境界の位置を決めている点。8点の例では3点だけだった マージン最大化の計算
svm python の書き方 make_pipeline(StandardScaler(), SVC()) を fit する 最初の5分
カーネル法・カーネルトリックとは 高い次元に写したときの内積を、写さずに元の空間の式で直接計算する方法 カーネル法とカーネルトリック
C と gamma の意味 C は誤分類への罰の重さ、gamma は1点の影響が届く範囲の狭さ。どちらも大きいほど過学習しやすい C と gamma
標準化は要るか 要る。wine では正解率が 0.66 から 0.98 に上がり、線形 SVC の学習は170倍速くなった 標準化しないと崩れる例
SVM が遅い SVC は件数の2乗以上で重くなる。件数2倍で学習4.5倍。数万件を超えたら LinearSVC・近似カーネル 件数と学習時間
確率を出したい scikit-learn 1.9 で probability=True は非推奨。CalibratedClassifierCV(SVC(), ensemble=False) を使う 確率が欲しいとき

確認環境:Ubuntu 24.04.5 LTS(CPU 2コア)で、Python 3.13.18、scikit-learn 1.9.1、numpy 2.5.3、scipy 1.18.1 を使いました。データは scikit-learn に同梱の load_breast_cancer・load_wine・load_iris・load_digits・load_diabetes と、make_moons・make_circles・make_classification で作ったもの、手作りの8点だけで、ネットからのデータ取得はしていません。線形SVMはヒンジ損失の(劣)勾配降下で numpy だけで書き、SVC(libsvm)・LinearSVC(liblinear)と目的関数の値・重みの向き・予測を照合しました。カーネルSVMは、学習済みの dual_coef_ と support_vectors_ から予測値を自分で計算して decision_function と比べています。計算はすべて OPENBLAS_NUM_THREADS=1 の1スレッド、時間はこの2コアのマシンでの値です。カーネルの式、gamma='scale' の式、計算量、LinearSVC の切片の扱い、確率推定(Platt scaling)と probability の非推奨は scikit-learn 1.9.1 の公式ドキュメントで確かめました。図は mermaid-cli で描画を確かめています(確認日 2026年11月5日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「SVM(サポートベクターマシン)とは|マージン・カーネル・Cとgammaを自作で実測」

SVM(サポートベクターマシン)とは:意味と用語

この節では、SVMの意味と、名前に出てくる「サポートベクター」「マージン」「カーネル」がふだんの意味とどう違うかが分かります。

SVM(Support Vector Machine、サポートベクターマシン)は、教師あり学習の分類手法で、クラスの間に引く境界を「最も近い点からの距離(マージン)が最大になる位置」に決めます。境界と平行に引いた2本の線の間(道幅)がいちばん広くなるように道を通す、と考えると分かりやすいです。数値を予測する回帰版は SVR(Support Vector Regression)と呼びます。

SVMの用語は、ふだんの言葉や他の IT 分野と同じ言葉が多く、検索すると意味が混ざります。最初に分けておきます。

言葉 ふだん・他分野での意味 SVMでの意味
マージン 利ざや・余白(印刷の余白、商品の粗利) 境界から最も近い点までの距離。道幅は両側を合わせた 2 ÷ ||w||
サポート 支援・問い合わせ窓口 境界を「支えている」点。サポートベクターだけで境界が決まる
ベクター(ベクトル) 画像形式の「ベクター画像」 1件のデータ(特徴量を並べた数の組)
カーネル OS の中核(Linux カーネル)、Jupyter の実行エンジン 2つのデータの「似ている度合い」を返す関数 K(x, z)
C プログラミング言語の C 誤分類への罰の重さ(正則化の強さの逆数)
gamma(γ) ガンマ線・ガンマ補正(画像の明るさ) RBF カーネルで1点の影響が届く範囲の狭さ

OS のカーネルについては別の記事(カーネルとは)で扱っており、この記事の「カーネル」はすべて SVM のカーネル関数の意味です。

1

境界は少数の点で決まる

マージンの外側にある点を消しても境界は動かない。予測に使うのはサポートベクターだけ。

3節で8点中3点

2

カーネルで曲げられる

RBF カーネルを使うと、同心円のように直線では分けられないデータも分けられる。

円のデータで0.54→1.00

3

尺度に敏感

点と点の距離や内積で計算するので、単位の大きい列が結果を支配する。標準化が前提。

8節で実測

4

件数が増えると重い

カーネル SVM は件数の2乗以上で時間が増える。数万件からは別の方法を考える。

9節で実測

機械学習の全体像の中では、SVM はロジスティック回帰と同じ「境界を引く」モデルの仲間です。深層学習が広まる前は、画像・文章の分類でも主力の手法でした。ニューラルネットワークとの違いは、関連記事「ニューラルネットワークとは|仕組み・学習・AttentionをNumPyで実演」で扱っています。

最初の5分:SVMをPythonで動かす(scikit-learn の SVC)

この節では、svm python の最小のコードと、学習した結果のどこを見ればよいかが分かります。

scikit-learn 同梱の乳がんデータ(569件・30列。腫瘍が悪性か良性か)で、標準化と SVC をひとまとめにして学習します。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=0, stratify=y)

model = make_pipeline(StandardScaler(), SVC())   # 既定は kernel="rbf", C=1.0, gamma="scale"
model.fit(X_train, y_train)

svc = model[-1]
print("テスト正解率", model.score(X_test, y_test))
print("サポートベクターの数", svc.n_support_, "合計", svc.n_support_.sum(), "/ 訓練", len(y_train))
print("decision_function", model.decision_function(X_test[:3]).round(3), "予測", model.predict(X_test[:3]))

実行結果です。

テスト正解率 0.9532163742690059
サポートベクターの数 [49 47] 合計 96 / 訓練 398
decision_function [-2.416  0.842 -1.092] 予測 [0 1 0]

訓練データ398件のうち、境界を決めているのは96件(24%)でした。decision_function は境界からの符号つきの距離に比例する値で、正なら classes_[1]、負なら classes_[0] と予測します。絶対値が1以上ならマージンの外側、1未満ならマージンの中です。

1

StandardScaler と SVC を Pipeline でつなぐ

公式ドキュメントも「SVM は尺度に対して不変ではないのでスケーリングを強く勧める。テストにも同じ変換を」と書き、例に make_pipeline を挙げている。

8節で実測

2

まず既定値(RBF・C=1・gamma="scale")で動かす

公式ドキュメントは C=1 を「妥当な既定値」とし、ノイズが多ければ下げるよう書いている。

基準を作る

3

C と gamma を対数の間隔で探す

0.01・0.1・1・10・100 のように10倍ずつ。GridSearchCV で交差検証する。

7節

4

件数が数万件を超えるなら LinearSVC か近似カーネル

SVC の学習時間は件数の2乗以上で増える。

9節

Jupyter や Colab で試す場合も、コードはそのまま動きます。Colab の始め方は関連記事「Google Colabとは|使い方・GPU・料金・制限とエラーの直し方」で扱っています。

マージン最大化とサポートベクターを2次元の例で計算する

この節では、マージンの計算方法と、どの点がサポートベクターになるかが、8点の数字で分かります。

2つのクラスに4点ずつの、手作りのデータです。

点 座標 (x1, x2) クラス decision_function 境界からの距離
A(1, 2)0−1.8003.182
B(2, 3)0−1.0001.768
C(2, 1)0−1.8003.182
D(3, 2)0−1.0001.768(サポートベクター)
E(5, 5)1+1.0001.768(サポートベクター)
F(6, 4)1+1.0001.768(サポートベクター)
G(6, 6)1+1.8003.182
H(7, 5)1+1.8003.182

誤分類をほぼ許さない設定(SVC(kernel="linear", C=1e6))で学習した結果です。

w [0.40009103 0.39986345] b -2.9999241389773936 margin width 3.535734931204915
SV idx [3 4 5] SV [[3.0, 2.0], [5.0, 5.0], [6.0, 4.0]] dual [[-0.1599909   0.07988166  0.08010924]]

境界の式は 0.4·x1 + 0.4·x2 − 3 = 0、つまり x1 + x2 = 7.5 の直線です。重み w = (0.4, 0.4) の長さは √(0.4² + 0.4²) = 0.5657 で、道幅は 2 ÷ 0.5657 = 3.536、片側のマージンは 1.768 です。表の「境界からの距離」は decision_function ÷ ||w|| で計算しました。

なぜこの直線なのか:他の境界との比較

8点を正しく分ける直線は無数にあります。いくつかの直線で「最も近い点までの距離」を計算しました。

境界の直線 8点を正しく分けるか 最も近い点までの距離(マージン)
x1 + x2 = 7.5(SVMの答え)分ける1.768
x1 = 4(縦の線)分ける1.000
x2 = 3.5(横の線)分ける0.500

どの線も訓練データの正解率は100%ですが、横の線は点B (2, 3) との距離が0.5しかなく、少しずれた新しいデータで間違えやすい境界です。SVMは、正しく分ける境界の中から、最も近い点までの距離が最大になるものを選びます。これがマージン最大化です。

サポートベクターは3点、点Bはマージン上でも係数0

サポートベクターとして返ったのは D・E・F の3点です。点B も decision_function が −1.000 でマージンの線の上にいますが、サポートベクターには入っていません。境界を決めるのに D・E・F の3点で足りたため、B の係数(dual_coef_)が0になったからです。

サポートベクター以外の点(A・C・G・H と B)を消して学習し直しても、境界は同じになります。逆に、サポートベクターを1点動かすと境界が動きます。「少数の点だけで境界が決まる」ことが、名前の由来です。

式で書くと(ハードマージン)

クラスを y = +1 / −1 とすると、SVMは次の問題を解いています。

最小化   (1/2) ||w||²
条件     すべての点 i で  y_i (w·x_i + b) ≥ 1

条件は「すべての点がマージンの外側(decision_function の絶対値が1以上)にいる」ことで、その中で ||w|| を小さくする=道幅 2/||w|| を広くする、という意味です。実際にはこの問題を双対問題(各点に係数 α を付けた形)に直して解き、α が0でない点がサポートベクターになります。dual_coef_ は α_i × y_i の値で、D が −0.160、E・F が +0.080 でした。符号つきの合計 −0.160 + 0.080 + 0.080 が0になっているのは、双対問題の条件 Σ α_i y_i = 0 そのものです。

ハードマージンとソフトマージン(C の意味)

この節では、外れ値が1つ入ったときに C の値で境界と道幅がどう変わるかが分かります。

上の8点に、クラス0の外れ値 (4.5, 4.5) を1点足しました。クラス1の E (5, 5)・F (6, 4) のすぐ近くです。全点を正しく分けようとすると道幅がとても狭くなります。

現実のデータは線形に分けきれないことが多いので、SVMは「マージンの内側に入る点・誤分類する点を、罰を払えば許す」形にします。これがソフトマージンで、罰の重さが C です。

最小化   (1/2) ||w||² + C × Σ max(0, 1 − y_i (w·x_i + b))
                          └─ ヒンジ損失:マージンの外なら0、内側に入った分だけ増える
C 境界(x1 + x2 =) 道幅 2/||w|| サポートベクター 訓練正解率(9点)
1,000,0009.50.70721.000
109.50.70721.000
18.02.82820.889(外れ値を誤分類)
0.1(傾きも変わる)4.65040.889
0.01(傾きも変わる)12.73980.667

C が大きいと、外れ値1点に合わせて境界が x1 + x2 = 9.5 へ動き、道幅は0.7まで狭まりました(ハードマージンに近い)。C=1 では外れ値を1点間違える代わりに道幅が4倍の2.83になり、境界は元の8点のちょうど中間に近い x1 + x2 = 8 に戻りました。C=0.01 まで下げると罰が軽すぎて、9点中3点を間違える境界になりました。

C を大きくする

訓練データの誤分類を強く嫌う

道幅が狭く、外れ値に引っ張られる

サポートベクターが少ない・過学習しやすい

C を小さくする

誤分類をある程度許す

道幅が広く、境界がなめらか

サポートベクターが多い・小さすぎると学習不足

公式ドキュメントも、C は「訓練データの誤分類と、境界の単純さのつり合いをとる」もので、「C が小さいと境界はなめらかになり、大きいと訓練データをすべて正しく分けようとする」と説明しています。C は「正則化の強さの逆数」なので、ロジスティック回帰の C と同じ向きです。過学習と正則化そのものは、同じ時期に書いた記事(過学習とは|原因と対策、交差検証・正則化・リークをPythonで実測)で扱っています。

ヒンジ損失と勾配降下法で線形SVMを自作する(LinearSVC・SVCとの比較)

この節では、線形SVMの中身を numpy で書き、scikit-learn の SVC・LinearSVC と同じ答えになるかを確かめた結果が分かります。

上のソフトマージンの式を、そのまま勾配降下で小さくします。ヒンジ損失 max(0, 1 − m) は m = 1 で折れ曲がっていて微分できないので、「マージンの内側にいる点(m < 1)だけが勾配に効く」という劣勾配を使います。

import numpy as np

def my_linear_svm(X, s, C, epochs=3000, lr0=0.5):
    """(1/2)||w||^2 + C * sum(max(0, 1 - s*(Xw+b))) を劣勾配降下で最小化。s は +1/-1"""
    n, d = X.shape
    w, b = np.zeros(d), 0.0
    best = (np.inf, None, None)
    for t in range(1, epochs + 1):
        m = s * (X @ w + b)
        act = m < 1                                   # ヒンジが効いている点(マージンの内側・誤分類)
        gw = w - C * (s[act, None] * X[act]).sum(0)    # ||w||^2/2 の勾配 + ヒンジの劣勾配
        gb = -C * s[act].sum()                          # 切片は正則化しない
        lr = lr0 / np.sqrt(t) / np.sqrt(C * n)          # だんだん小さくする学習率
        w -= lr * gw
        b -= lr * gb
        obj = 0.5 * w @ w + C * np.maximum(0, 1 - s * (X @ w + b)).sum()
        if obj < best[0]:
            best = (obj, w.copy(), b)                  # 劣勾配法は単調に減らないので最良を残す
    return best

乳がんデータを7:3に分け、訓練データで標準化して C=0.1 で学習しました。目的関数の値は次のように減りました。

反復      1: 58.7332
反復     10: 24.1773
反復    100:  4.0455
反復   1000:  2.8911
反復   3000:  2.8865   (0.103秒)

同じ C で scikit-learn の3つと比べた結果です。「向きの一致」は、SVC の重みとの cos 類似度(1.0 で完全に同じ向き)、「予測の一致」はテスト171件の予測が SVC と同じだった割合です。

実装 目的関数(同じ式で計算) 切片 b 向きの一致 テスト正解率/予測の一致
自作(劣勾配降下)2.88640.31950.999990.9591/100%
SVC(kernel="linear")2.88620.31981.000000.9591/100%
LinearSVC(loss="hinge")2.89200.25240.997880.9532/99.4%
LinearSVC(intercept_scaling=10)2.88600.31871.00000―
LinearSVC(既定 squared_hinge)3.5436(別の損失を解いている)0.06220.946460.9591/97.7%

15行ほどの自作が、SVC(libsvm の厳密な解法)と目的関数で小数第3位まで、テストの予測では171件すべてで一致しました。SVM の学習は「重みを小さく保ちながら、ヒンジ損失を減らす」ことだと確かめられます。速さは自作 103ミリ秒、SVC 1.8ミリ秒、LinearSVC 1.4ミリ秒で、業務では scikit-learn を使います。

LinearSVC の答えが少しずれる理由

LinearSVC(liblinear)は、既定で損失が二乗ヒンジ(squared_hinge)で、さらに切片 b も正則化します。公式ドキュメントにも「LinearSVC は squared_hinge 損失を使い、liblinear の実装のため切片も正則化する。intercept_scaling で影響を減らせる」とあります。手元でも loss="hinge" にしただけでは切片が 0.2524 と小さめにずれ、intercept_scaling=10 にすると SVC と同じ 0.319 に近づきました(100 では ConvergenceWarning: Liblinear failed to converge が出ました)。

サポートベクターの内訳

このときの SVC のサポートベクターは44個(訓練398件中)で、係数 α が上限の C に張り付いた点(マージンの内側か誤分類)が32個、ちょうどマージンの線の上が12個、訓練データで誤分類されたのは3個でした。ソフトマージンでは「マージンの内側に入った点」もサポートベクターになります。

勾配降下の学習率と収束の関係は、同じ時期に書いた記事(勾配降下法とは|学習率・SGD・Adamを自作して収束を比較)で扱っています。numpy の配列の書き方は関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」が参考になります。

カーネル法とカーネルトリック(線形・多項式・RBF)

この節では、カーネル法・カーネルトリックの意味と、カーネルの種類ごとの精度の違いが分かります。

直線で分けられないデータも、特徴量を増やして高い次元に写すと平面で分けられることがあります。たとえば (x1, x2) に x1²・x2²・x1·x2 を足すと、円の内側と外側を「平面」で分けられます。ところが特徴量を明示的に作ると、次元がすぐに膨らみます。

元の列数 2次までの組み合わせ 3次まで 5次まで
261021
30(breast_cancer)4965,456324,632
64(digits)2,14547,90511,238,513

SVM の双対問題と予測式には、データどうしの内積しか出てきません。そこで「高い次元に写してから内積をとる」代わりに、「元の空間で同じ値を直接返す関数」を使えば、写した先の特徴量を1つも作らずに済みます。これがカーネルトリックで、その関数がカーネルです。

多項式カーネルで、写像と同じ値になることを確かめる

2次の多項式カーネル K(x, z) = (x·z + 1)² は、2列のデータを6次元 φ(v) = (1, √2·v1, √2·v2, v1², v2², √2·v1·v2) に写したときの内積と同じです。x = (1, 2)、z = (3, −1) で計算しました。

カーネル  (x·z + 1)^2 = (1×3 + 2×(−1) + 1)^2 = 2^2 = 4.0
写像      φ(x) = [1. 1.414 2.828 1. 4. 2.828]
          φ(z) = [1. 4.243 −1.414 9. 1. −4.243]
          φ(x)·φ(z) = 3.999999999999998

カーネルは掛け算3回と足し算で済み、6次元の写像を作る必要がありません。RBF カーネル exp(−γ||x − z||²) は、写した先が無限次元に当たるため、明示的には作れず、カーネルトリックでしか計算できません。

カーネル SVM の予測式を自分で計算する

学習済みの SVC は、サポートベクターと係数だけで予測します。

decision_function(x) = Σ(サポートベクター i について) dual_coef_i × K(sv_i, x) + intercept_
from sklearn.metrics.pairwise import rbf_kernel
m = SVC(C=1, gamma=1).fit(X, y)                     # make_moons 400件
K = rbf_kernel(X[:5], m.support_vectors_, gamma=1)
mine = K @ m.dual_coef_[0] + m.intercept_[0]
print(mine.round(6)); print(m.decision_function(X[:5]).round(6))
[-1.303382  1.660012  1.180646 -1.423338  1.144428]
[-1.303382  1.660012  1.180646 -1.423338  1.144428]

小数第6位まで一致しました。自分で作ったカーネル行列を SVC(kernel="precomputed") に渡した場合も、サポートベクター116個・予測100%一致でした。予測にかかる時間はサポートベクターの数に比例するので、サポートベクターが多いモデルほど予測も遅くなります(9節)。

カーネルの種類と精度

scikit-learn 1.9.1 の公式ドキュメントにあるカーネルの式です。

kernel= 式 主なパラメータ 向いているデータ
"linear"⟨x, x'⟩C列が多い(文章の単語など)・直線で分かれる
"poly"(γ⟨x, x'⟩ + r)^ddegree(d)・coef0(r)・gamma列の掛け合わせが効く場合
"rbf"(既定)exp(−γ||x − x'||²)C・gammaまず試す。形の分からない境界
"sigmoid"tanh(γ⟨x, x'⟩ + r)gamma・coef0使う場面は少ない

4つのデータで、標準化+既定値のまま5分割交差検証した正解率です。

データ linear poly(3次) rbf sigmoid
make_moons(三日月2つ・400件)0.8480.8450.9000.690
make_circles(同心円・400件)0.5430.6331.0000.628
breast_cancer(30列)0.9720.9030.9740.953
digits(8×8画像・64列)0.9470.9170.9460.909

同心円は線形では0.54(ほぼあてずっぽう)ですが、RBF では1.00でした。一方、列の多い breast_cancer と digits では、線形と RBF がほぼ同じです。列が多いデータは高い次元の空間ですでに直線で分かれやすく、線形カーネルで足りることが多いので、線形でも試して比べます。

C と gamma で境界と精度がどう変わるか(RBFカーネル)

この節では、RBF カーネルの C と gamma を変えたときの訓練・テストの正解率とサポートベクターの数が、表で分かります。

gamma は「1点の影響がどこまで届くか」を決めます。RBF カーネル exp(−γ||x − z||²) は、γ が大きいほど少し離れただけで0に近づくので、各点の影響が狭い範囲に限られ、境界が点のまわりに細かく巻きつきます。既定の gamma="scale" は 1 / (列数 × X.var()) で、下の訓練データでは 0.833 でした。

ノイズの多い三日月(make_moons・400件・noise=0.3)を半分ずつ訓練とテストに分けました。各マスは「訓練/テスト/サポートベクター数(訓練200件中)」です。

C \ gamma 0.01 1 10 100
0.010.76/0.79/2000.84/0.89/2000.90/0.90/2000.98/0.80/200
0.10.76/0.79/2000.86/0.90/1300.90/0.91/1950.98/0.80/200
10.80/0.85/1500.91/0.92/720.90/0.91/1090.97/0.82/191
100.83/0.88/970.91/0.91/580.93/0.89/890.99/0.82/184
1000.84/0.88/840.90/0.91/570.95/0.84/701.00/0.81/183
10000.84/0.89/810.90/0.90/550.99/0.81/581.00/0.81/183

読み方は3つです。

  • gamma=100 の列は、C に関係なく訓練0.97〜1.00・テスト0.80〜0.82で、訓練データに巻きついた過学習です。サポートベクターも183〜200件とほぼ全件になり、「どの点も自分のまわりしか説明しない」状態です。
  • gamma=0.01 の列は境界がほぼ直線になり、C を1000にしてもテスト0.89止まりです。
  • 最良の C=1・gamma=1(既定値の 0.833 に近い)は、サポートベクターが72件と少ないのにテスト0.92でした。C と gamma は片方だけでなく組で見ます。gamma=10 でも C=0.1 なら 0.91 と保てますが、C=1000 では0.81に落ちました。

同じデータで C=1 に固定し、予測したクラスを文字で描きました(# がクラス1、横は x1 = −1.5〜2.5、縦は x2 = 1.5〜−1.0)。

--- C=1 gamma=0.1(ほぼ直線)
..........................................######
........................................########
......................................##########
....................................############
.................................###############
..............................##################
..........................######################
.....................###########################
................################################
...........#####################################
.......#########################################
...#############################################
################################################
################################################
--- C=1 gamma=100(点に巻きつく)
................................................
................................................
................................................
.....................................######.....
...................................##########...
................###................#############
..................##...#...........###########..
.................########.........############..
............#############....##...###########..#
.............###############.....###########....
................#######################..###....
...............####.##########..######..........
.......................####.#########...........
........................####...........###......

gamma=0.1 は1本のなめらかな線、gamma=100 は訓練データの点のまわりだけを囲む島がたくさんできる境界になりました。

0.92C=1・gamma=1 のテストサポートベクター72件
0.81C=100・gamma=100 のテスト訓練は1.00
183/200gamma=100 のサポートベクターほぼ全件

C と gamma の決め方(GridSearchCV)

公式ドキュメントは「C と gamma は指数的に離れた値で GridSearchCV を使って選ぶ」よう勧めています。乳がんデータで、C を 0.01〜1000、gamma を 0.0001〜10 の各6通り(36組×5分割=180回の学習)で探しました。

import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline

pipe = Pipeline([("sc", StandardScaler()), ("svc", SVC())])
grid = {"svc__C": np.logspace(-2, 3, 6), "svc__gamma": np.logspace(-4, 1, 6)}
g = GridSearchCV(pipe, grid, cv=5).fit(X_train, y_train)
print(g.best_params_, g.best_score_, g.score(X_test, y_test))
{'svc__C': np.float64(100.0), 'svc__gamma': np.float64(0.001)} 0.9849 0.9532   (3.4秒)

交差検証では0.985と既定値より高く見えますが、テストは既定値と同じ0.9532でした。交差検証の最良値は「たくさん試した中の最大」なので、少し楽観的に出ます。最後にテストデータで1回だけ確かめ、既定値より良くならなければ単純な方を使います。Pipeline に入れているので、標準化も各分割の訓練データだけで fit され、リークしません。

C と gamma の探し方

避けたい0.5・1・1.5・2 のように等間隔で細かく探す。テストデータの正解率を見ながら手で調整する
→
代わりに10倍ずつ(np.logspace)の粗い格子で当たりを付け、良い付近を細かくする。選ぶのは訓練データの交差検証で

C と gamma は10倍変えてやっと効き方が変わる。テストで選ぶとテストへの過学習になる

標準化しないとSVMが崩れる例

この節では、SVM に標準化(スケーリング)が要る理由と、しなかったときにどれだけ精度と時間が変わるかが分かります。

RBF カーネルは点と点の距離、線形カーネルは内積で計算します。どちらも、値の大きい列がほぼすべてを決めてしまいます。乳がんデータの列の標準偏差は、最小 0.0026(fractal dimension error)から最大 568.9(worst area)まで20万倍の差があります。

データ・カーネル そのまま StandardScaler MinMaxScaler 学習の時間(そのまま→標準化)
breast_cancer・rbf0.91220.97360.97540.12秒 → 0.06秒
breast_cancer・linear0.94550.97190.971915.35秒 → 0.09秒
wine・rbf0.66350.98330.97760.03秒 → 0.06秒
wine・linear0.96110.96060.96650.88秒 → 0.04秒

(5分割交差検証の平均。時間は5回分の合計)

wine(13列、プロリンの列だけ値が数百〜1,680)は、RBF のまま使うと正解率0.66で、ほぼプロリンの値だけで分類していました。標準化すると0.98です。線形カーネルの breast_cancer は、精度の差より学習時間が170倍になったことが目立ちます。値の幅が大きいと最適化の問題の形が悪くなり、解くまでの反復が増えるためです。

列を1つだけ1000倍した場合も確かめました(make_moons の x2 を1000倍)。

                   SVC そのまま   StandardScaler + SVC
make_moons            0.91             0.90
x2 を 1000 倍         0.81             0.90

単位を mm から µm に変えただけのような変更で、そのままの SVC は0.91から0.81に落ちました。標準化を入れると、どちらでも0.90で変わりません。スケーラーの種類ごとの違いや、決定木では標準化が要らない理由は、同じ時期に書いた記事(標準化と正規化の違い|スケーリングで精度が変わるモデルを8種で実測)で扱っています。

スケーリングの fit の仕方

避けたい全データで StandardScaler を fit してから訓練とテストに分ける。テストだけ別に fit する
→
代わりにmake_pipeline(StandardScaler(), SVC()) にして、訓練データだけで fit した変換をテストにも使う

公式ドキュメントも「テストには同じスケーリングを」と書き、Pipeline を例に挙げている

件数を増やしたときの学習時間(SVC が重くなる理由と代わりの方法)

この節では、SVC の学習と予測にかかる時間が件数でどう増えるかと、大きなデータでの代わりの方法が分かります。

make_classification(20列・ラベルの5%を反転させたノイズ入り)で、訓練の件数を変えて学習し、別の6,000件で予測しました。2コアのマシン・1スレッドでの値です。

訓練件数 SVC(rbf) 学習 SVC 予測6,000件 SVC テスト/SV数 LinearSVC 学習/テスト
1,0000.07秒0.59秒0.860/6430.01秒/0.681
2,0000.13秒0.67秒0.883/1,1010.01秒/0.689
5,0000.99秒1.70秒0.898/2,2100.01秒/0.685
10,0003.88秒2.63秒0.909/3,7780.03秒/0.686
20,00017.30秒6.32秒0.924/6,5870.09秒/0.687

10,000件から20,000件で学習は4.5倍、1,000件から20,000件(20倍)では約250倍になりました。公式ドキュメントは、SVC の学習時間は「件数に対して少なくとも2乗で増え、数万件を超えると実用的でなくなりうる」、計算量は libsvm のキャッシュの効き方により O(列数 × 件数²) から O(列数 × 件数³) の間、と書いています。手元の数字もその範囲でした。

予測も遅くなります。サポートベクターが件数の3分の1ほど(6,587件)残るため、1件の予測に6,587回のカーネル計算が要ります。このデータは境界が曲がっているため、LinearSVC は速いものの0.69止まりでした。

大きなデータでの代わり:カーネル近似(Nystroem)

公式ドキュメントは、大きなデータでは LinearSVC や SGDClassifier を、必要なら Nystroem などのカーネル近似の後に使うよう勧めています。Nystroem は、一部の点(ここでは500点)とのカーネルの値を特徴量にして、RBF カーネルを近似します。

方法(訓練20,000件) 学習 予測6,000件 テスト正解率
SVC(rbf)17.30秒6.32秒0.924
Nystroem(500) + LinearSVC17.41秒0.38秒0.912
Nystroem(500) + SGDClassifier(hinge)2.69秒(測っていない)0.895
SGDClassifier(hinge)(近似なし)0.36秒0.00秒0.673

Nystroem + SGD は SVC の6分の1の時間で、正解率は0.03低い0.895でした。件数が増えるほど差が開くので、数万件を超えるなら、まず近似カーネル+線形モデルで正解率の差を確かめ、許せる差なら乗り換えます。SVC を使い続ける場合は、公式ドキュメントにあるとおり cache_size(既定200MB)を500〜1000MB に上げると速くなることがあります。

  1. 1〜1万件 → SVC(rbf) をそのままこの環境で学習4秒以内。C と gamma を交差検証で
  2. 21万〜数万件 → SVC と近似を両方試す2万件で SVC 17秒。cache_size を上げる
  3. 3数万件〜 → Nystroem + SGDClassifier/LinearSVCn_components で精度と時間を調整
  4. 4列が多く直線で分かれる → LinearSVC文章の単語の列など。2万件で0.09秒

SVMで確率が欲しいとき(probability の非推奨と CalibratedClassifierCV)

この節では、SVM が確率をそのまま出さない理由と、scikit-learn 1.9 での確率の出し方が分かります。

SVM の出力 decision_function は境界からの距離で、確率ではありません。このデータでは −2.85〜3.07 の範囲でした。確率が要る場合(リスクの点数付け、しきい値を業務で決める場合)は、この値をロジスティック関数で 0〜1 に写す「Platt scaling」などで較正します。

scikit-learn 1.9 で probability=True は非推奨

これまで定番だった SVC(probability=True) を scikit-learn 1.9.1 で実行すると、次の警告が出ました。

FutureWarning: The `probability` parameter was deprecated in 1.9 and will be removed in version 1.11. Use `CalibratedClassifierCV(SVC(), ensemble=False)` instead of `SVC(probability=True)`

公式ドキュメントの SVC のページにも「deprecated 1.9」とあり、1.11 で削除予定です。以前の版のコードや解説をそのまま写すと、この警告が出ます。代わりの書き方は次のとおりです。

from sklearn.calibration import CalibratedClassifierCV
clf = CalibratedClassifierCV(SVC(), ensemble=False, cv=5)   # 以前の SVC(probability=True) 相当
clf.fit(X_train, y_train)
proba = clf.predict_proba(X_test)[:, 1]

make_classification(3,000件・ラベルの10%がノイズ)の半分で学習し、残り1,500件で比べました。

方法 学習時間 log loss Brier スコア predict と食い違った件数
SVC()(確率なし)0.184秒―――
SVC(probability=True)(非推奨)0.961秒0.38880.115821/1,500
CalibratedClassifierCV(ensemble=False)0.976秒0.38940.115825/1,500
CalibratedClassifierCV(sigmoid・既定)0.836秒0.39070.1174―
CalibratedClassifierCV(isotonic)0.812秒0.45760.1189―

確率を出すと学習は約5倍の時間になりました。内部で5分割の交差検証をして較正するためです。ensemble=False の書き方は、非推奨の probability=True と log loss・Brier スコアがほぼ同じでした。

predict と predict_proba が食い違う

1,500件中21件で、predict の答えと「predict_proba > 0.5」の答えが逆でした。

decision_function -0.0048  →  predict 0、 predict_proba 0.5335
decision_function -0.0523  →  predict 0、 predict_proba 0.5064

predict は decision_function の符号で決まり、確率は別に学習した較正のモデルから出るためです。公式ドキュメントも「確率は decision_function の値と食い違うことがある。2クラスでは predict_proba が0.5未満でも陽性と予測されることがある」と明記し、「確率でなくてもよい信頼度なら decision_function を使う」よう勧めています。また、非推奨の probability=True は random_state を 0・1・2 と変えるだけで、同じ1件の確率が 0.0292・0.0304・0.0327 と変わりました。

1順位だけ要る → decision_function

AUC の計算や上位N件の抽出は、確率に直さなくても decision_function の大小で足りる。学習も5倍速い。

2確率の値が要る → CalibratedClassifierCV

ensemble=False で以前の probability=True 相当。判定は predict_proba のしきい値に統一する。

3確率が主役 → 別のモデルも比べる

ロジスティック回帰は確率をそのまま出す。SVM にこだわる理由がなければ並べて比べる。

ROC曲線と AUC の読み方・しきい値の決め方は、同じ時期に書いた記事(ROC曲線とAUCとは|見方・しきい値の決め方と陽性がまれな時の落とし穴)で扱っています。

多クラス分類・クラスの偏り・回帰(SVR)

この節では、3クラス以上の分類の仕組み、陽性がまれなときの class_weight、数値を予測する SVR の使い方が分かります。

多クラス分類は「1対1」で学習している

SVM はもともと2クラスの手法です。scikit-learn の SVC は、クラスの2つずつの組すべてで SVM を学習し(one-vs-one)、多数決します。10クラスの digits なら 10×9÷2 = 45 個の SVM です。

iris   decision_function_shape="ovr" → 形 (1, 3)  [[ 2.2354  1.161  -0.2565]]
iris   decision_function_shape="ovo" → 形 (1, 3)  [[1.264  1.141  2.1978]]
digits decision_function_shape="ovo" → 形 (1, 45)

既定の "ovr" は、1対1の結果から「クラスごとの点数」の形(件数×クラス数)に組み直したもので、公式ドキュメントにも「内部の学習は常に one-vs-one で、ovr の行列は ovo から作るだけ」とあります。一方、LinearSVC は one-vs-rest(1クラス対残り全部)で学習します。

陽性がまれなとき:class_weight

陽性が5%(訓練1,000件中50件)のデータで比べました。

class_weight 正解率 再現率 適合率 バランス正解率
None(既定)0.9610.240.9230.620
"balanced"0.9630.800.5970.886
{0: 1, 1: 5}0.9730.740.7260.863

既定のままでは、陽性50件のうち12件しか見つけられませんでした(再現率0.24)。class_weight="balanced" は、クラスの件数に反比例した重みで C を掛け直す設定で(公式の式は n_samples / (n_classes × np.bincount(y)))、再現率は0.80に上がりました。正解率だけでは差が見えない点に注意します。

数値を予測する SVR

SVR は、予測と正解の差が epsilon 以内なら損失0、それを超えた分だけ罰する形で、「幅 2ε のチューブに多くの点が入る、なるべく平らな関数」を求めます。糖尿病データ(load_diabetes)でのテスト R² です。

SVR(rbf) 既定 C=1, epsilon=0.1     R² 0.1372   サポートベクター 309
SVR(rbf) C=100, epsilon=10         R² 0.2652   サポートベクター 265
SVR(linear) C=10                    R² 0.3832
LinearRegression                    R² 0.3929

目的変数が数十〜三百台の値なのに既定の epsilon=0.1・C=1 のままでは、罰が小さすぎてほとんど学習できていません。SVR は C と epsilon を目的変数の大きさに合わせる必要があります。このデータは直線的な関係が強いため、最小二乗法の線形回帰が最も良い結果でした。最小二乗法そのものは、関連記事「最小二乗法とは|公式・手計算の例とPythonでの求め方を実例で解説」で扱っています。

SVMのよくあるエラー・つまずき

この節では、SVM を scikit-learn で動かしたときに出たエラーの原文と直し方が分かります。すべて scikit-learn 1.9.1 で出た文面です。

症状・エラー原文 原因 直し方
ValueError: Unknown label type: continuous. Maybe you are trying to fit a classifier, which expects discrete classes on a regression target with continuous values.数値を当てたいのに SVC を使ったSVR にする
ValueError: Expected 2D array, got 1D array instead:1列の X を1次元で渡したX.reshape(-1, 1) か df[["列"]]
InvalidParameterError: The 'kernel' parameter of SVC must be a str among {'poly', 'linear', 'precomputed', 'rbf', 'sigmoid'} or a callable. Got 'gauss' instead.ガウスカーネルの名前を間違えた"rbf"(ガウスカーネルのこと)
InvalidParameterError: The 'C' parameter of SVC must be a float in the range (0.0, inf]. Got 0 instead.C=0 は指定できない0より大きい値
InvalidParameterError: The 'gamma' parameter of SVC must be a str among {'auto', 'scale'} or a float in the range [0.0, inf). Got -1 instead.gamma が負正の値か "scale"
ValueError: Input X contains NaN.(SVC does not accept missing values encoded as NaN natively.)欠損値があるSimpleImputer で埋める
ValueError: The number of classes has to be greater than one; got 1 classラベルが1種類だけ分割の層化(stratify)を確かめる
AttributeError: This 'SVC' has no attribute 'predict_proba'確率の設定なしで呼んだCalibratedClassifierCV で包む(10節)
FutureWarning: The `probability` parameter was deprecated in 1.9probability=True を使ったCalibratedClassifierCV(SVC(), ensemble=False)
ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.LinearSVC が反復の上限で止まった標準化・max_iter を増やす・C を下げる
ConvergenceWarning: Solver terminated early (max_iter=5). Consider pre-processing your data with StandardScaler or MinMaxScaler.SVC の max_iter が小さい既定(−1=上限なし)に戻し、標準化する
ValueError: Precomputed matrix must be a square matrix. Input is a 150x4 matrix.kernel="precomputed" に特徴量を渡した訓練どうしのカーネル行列(n×n)を渡す
ValueError: Unsupported set of arguments: The combination of penalty='l1' and loss='hinge' is not supportedLinearSVC の組み合わせL1 なら loss="squared_hinge", dual=False
学習が終わらない件数が多い・標準化していない9節・8節。まず数千件で時間を測る

SVMを使うか決める判断表

この節では、SVM を選ぶ場面と、他の手法に切り替える場面が分かります。

状況 向いている手法・設定 理由(この記事の実測・公式の記述)
件数が数千〜1万件・列が数十の表データSVC(rbf)+標準化+C・gamma の探索breast_cancer 0.97、学習は1秒未満
列が件数より多い(文章の単語・遺伝子)LinearSVC公式は「次元が件数より多くても有効」とする。digits では線形と RBF が同等
件数が数万件を超えるNystroem+SGD/LinearSVC、勾配ブースティングSVC は2万件で17秒、件数2倍で4.5倍
確率の値をそのまま使いたいロジスティック回帰、または CalibratedClassifierCV(SVC)SVC の確率は較正が別で、predict と21件食い違った
欠損値・単位がばらばらの列が多い決定木系(ランダムフォレスト・勾配ブースティング)SVC は NaN で止まり、標準化しないと wine で 0.66
なぜその判定かを列ごとに説明したい線形SVM(coef_ を読む)・決定木RBF の SVM は「どのサポートベクターに近いか」でしか説明できない
正常データしかなく、外れを見つけたいOneClassSVM・Isolation ForestSVM の考え方を1クラスに広げたもの
画像・音声・長い文章ニューラルネットワーク特徴量を自分で作る必要がない

表データで精度が最優先なら、SVM と並べてランダムフォレストや勾配ブースティングも比べます(同じ時期に書いた記事:ランダムフォレストとは|バギングを自作し特徴量重要度の偏りを実測)。高い次元のデータを、SVM の前に主成分分析で圧縮する方法もあり、関連記事「主成分分析(PCA)とは|手順・寄与率・負荷量の読み方をPythonで実演」で扱っています。

SVMのよくある質問

この節では、SVM について検索でよく調べられる疑問への答えが分かります。

Q. SVM は教師あり学習ですか。
はい。正解のラベル(分類)や値(回帰・SVR)が付いたデータから境界を学ぶ教師あり学習です。ラベルなしで外れ値を見つける OneClassSVM という派生もあります。

Q. サポートベクターマシンとサポートベクトルマシンは違うものですか。
同じものです。英語の vector を「ベクター」と書くか「ベクトル」と書くかの違いで、どちらも Support Vector Machine の訳です。

Q. カーネル法とカーネルトリックの違いは何ですか。
カーネル法は、カーネル関数(データどうしの似ている度合い)を使って非線形な問題を解く手法の総称です。カーネルトリックは、その中で「高い次元への写像を作らずに、写した先の内積をカーネルで直接計算する」計算上の工夫を指します。

Q. RBF カーネルとガウスカーネルは同じですか。
同じです。exp(−γ||x − z||²) の形で、scikit-learn では kernel="rbf" と指定します。"gauss" と書くとエラーになります。

Q. SVM はディープラーニングより劣っていますか。
得意な場面が違います。数千件程度の表データでは、SVM は学習が速く、少ない調整で高い精度が出ることが多いです。大量の画像や文章では、特徴量を自分で学べるニューラルネットワークが向きます。

Q. SVM は過学習しにくいと聞きました。
マージン最大化は過学習を抑える方向に働きますが、C と gamma が大きいと過学習します。この記事の例では gamma=100 で訓練1.00・テスト0.81でした。交差検証で確かめます。

Q. LinearSVC と SVC(kernel="linear") はどちらを使えばよいですか。
件数が多いなら LinearSVC(liblinear)が速いです。ただし既定の損失が二乗ヒンジで切片も正則化するため、答えは少し違います。SVC と同じ答えが要るなら loss="hinge" と intercept_scaling を調整します。

Q. 特徴量の重要度は出せますか。
線形カーネルなら coef_ の大きさ(標準化した上で)が目安になります。RBF などでは coef_ が無いので、permutation importance(列をかき混ぜて精度の落ち方を見る)を使います。

Q. SVM の予測が遅いのはなぜですか。
予測のたびに、すべてのサポートベクターとのカーネルを計算するからです。2万件で学習したモデルはサポートベクターが6,587件残り、6,000件の予測に6.3秒かかりました。

Q. gamma="scale" と "auto" の違いは何ですか。
"scale"(既定)は 1 / (列数 × X.var()) で、データのばらつきに合わせます。"auto" は 1 / 列数 で、ばらつきを見ません。scikit-learn 0.22 で既定が "auto" から "scale" に変わりました。

Q. E資格や G検定に SVM は出ますか。
機械学習の代表的な手法として学ぶ範囲に含まれることが多い分野です。試験の範囲は主催団体の公表するシラバスで確かめます。試験の全体像は関連記事「E資格とは|試験内容・合格率・G検定との違いとNumPyで解く要点」で扱っています。

SVM(サポートベクターマシン)のまとめ

この節では、記事の要点を5つで振り返ります。

  • SVMとは、境界と最も近い点の距離(マージン)が最大になる境界で分類する手法。8点の例では x1 + x2 = 7.5 が選ばれ、境界を決めたサポートベクターは3点だった。
  • ソフトマージンは (1/2)||w||² + C × ヒンジ損失の合計 の最小化。numpy の劣勾配降下で書いた15行が SVC と目的関数・予測で一致した。LinearSVC は二乗ヒンジと切片の正則化で少しずれる。
  • カーネルトリックは写像を作らずに内積を計算する工夫。同心円は線形 0.54 → RBF 1.00。列の多いデータでは線形でも同等。
  • C と gamma は組で、10倍ずつ交差検証で探す。gamma=100 は訓練1.00・テスト0.81の過学習。標準化は必須で、wine は0.66→0.98、線形の学習は170倍速くなった。
  • 件数が2倍で SVC の学習は4.5倍。数万件からは Nystroem+線形モデル。確率は scikit-learn 1.9 で probability=True が非推奨になり、CalibratedClassifierCV(SVC(), ensemble=False) を使う。

参考・出典

この節では、この記事で確かめた公式の資料が分かります(いずれも確認日 2026年11月5日)。

  • scikit-learn 1.9.1 documentation「1.4. Support Vector Machines」(長所と短所・カーネル関数の式・計算量・実用上の注意・確率推定・LinearSVC の切片):https://scikit-learn.org/stable/modules/svm.html
  • scikit-learn 1.9.1「SVC」(C・gamma='scale' の式・probability の非推奨・decision_function_shape・class_weight・学習時間の注意):https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html
  • scikit-learn 1.9.1「LinearSVC」:https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html
  • scikit-learn 1.9.1「CalibratedClassifierCV」:https://scikit-learn.org/stable/modules/generated/sklearn.calibration.CalibratedClassifierCV.html
  • scikit-learn 1.9.1「6.7. Kernel Approximation」(Nystroem):https://scikit-learn.org/stable/modules/kernel_approximation.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「SVM(サポートベクターマシン)とは|マージン・カーネル・Cとgammaを自作で実測」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー