サポートベクターマシン(SVM, Support Vector Machine)を確実に使いこなすための関連キーワードを難易度別に整理しました。
🍰 まずはやさしく
データを分ける境界線を引く道具です。
2つのグループをきれいに分けるために使います。
スマホのアプリで写真の種類を分けるような仕組みです。
この章では、境界線の引き方の基本を学びます。
この用語は、 統計データ解析・データサイエンスの世界で重要な概念の1つです。 ジャストインタイム型学習では、 必要なときに参照し、 関連概念と合わせて学ぶことで定着を図ります。
この用語の基本的な意味、 数学的定義、 直感的理解について、 上記の3つの概念マップを通じて、 関連する用語と一緒に把握しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd import numpy as np from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.model_selection import cross_val_score # SSDSE-B-2026 を読み込み(2 行目の日本語見出し行は skiprows で除外) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() # 直近 2023 年度の 47 都道府県 # 2 値ラベル: 65 歳以上人口比率が全国中央値以上なら 1(高齢県) ratio = d['A1303'].astype(float) / d['A1101'].astype(float) # A1303=65歳以上, A1101=総人口 y = (ratio >= ratio.median()).astype(int) # 特徴量: 総人口・出生数・年平均気温(すべて実在列コード) X = d[['A1101', 'A4101', 'B4101']].astype(float) # A4101=出生数, B4101=年平均気温 # 標準化 + RBF カーネル SVM(マージン最大化で分類) clf = make_pipeline(StandardScaler(), SVC(C=1.0, kernel='rbf', gamma='scale')) print('5-fold CV 正答率:', cross_val_score(clf, X, y, cv=5).mean().round(3)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 線形 SVM と RBF SVM を比較し、境界を決めるサポートベクターを取り出す from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.model_selection import cross_val_score # 線形カーネル: 決定境界は超平面 w・x + b = 0 lin = make_pipeline(StandardScaler(), SVC(kernel='linear', C=1.0)) print('線形 SVM CV:', cross_val_score(lin, X, y, cv=5).mean().round(3)) # RBF カーネル: カーネルトリックで非線形境界も表現 rbf = make_pipeline(StandardScaler(), SVC(kernel='rbf', C=1.0, gamma='scale')) rbf.fit(X, y) print('RBF SVM CV:', cross_val_score(rbf, X, y, cv=5).mean().round(3)) # サポートベクター = 境界近傍の少数の点だけが分類器を決める svc = rbf.named_steps['svc'] print('サポートベクター数:', svc.n_support_, '/ 全', len(X), '件') |
このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 関連手法を辿って学習を進めましょう。
統計データ活用コンペティションのSSDSE-B-2026データは、 47都道府県の社会経済データ。 この概念を使って以下のような分析ができます:
| 機能 | Python (pandas) | Python (scipy) |
|---|---|---|
| 要約統計 | df.describe() | stats.describe() |
| 平均 | df.mean() | np.mean() |
| 標準偏差 | df.std() | np.std() |
| 相関 | df.corr() | stats.pearsonr() |
| t検定 | — | stats.ttest_ind() |
| 回帰 | — | stats.linregress() |
| 分布フィッティング | — | stats.norm.fit() |
この概念は、 他の多くの統計概念と密接に関連しています。 ジャストインタイム型学習では、 必要に応じて関連用語へジャンプしながら全体像を構築します。
| グループ | 主要概念 |
|---|---|
| 記述統計 | 平均、 中央値、 最頻値、 分散、 標準偏差、 共分散、 相関係数 |
| 可視化 | ヒストグラム、 散布図、 箱ひげ図、 ヒートマップ |
| 推測統計 | 標本平均、 標準誤差、 信頼区間、 p値、 有意水準 |
| 確率分布 | 正規分布、 t分布、 χ²分布、 F分布、 二項分布 |
| 仮説検定 | t検定、 F検定、 χ²検定、 ノンパラ検定 |
| 回帰 | 単回帰、 重回帰、 OLS、 Ridge、 LASSO |
| 分類 | ロジスティック回帰、 決定木、 SVM、 k-NN |
| 教師なし学習 | クラスタリング、 PCA、 因子分析 |
| 時系列 | ARIMA、 VAR、 指数平滑法、 自己相関 |
| 因果推論 | DiD、 IV、 傾向スコア、 交絡変数 |
| 前処理 | 標準化、 正規化、 欠損値処理、 多重共線性対策 |
| 評価 | R²、 残差、 CV、 RMSE、 効果量 |
🍰 まずはやさしく
データを分けるための計算手法です。
正しく分類できるルールを作るために使います。
部活のメンバーを2つのチームに分けるイメージです。
ここでは、この手法の詳しい使い方を読みます。
論文中に 「サポートベクトルマシン」として登場する用語。
サポートベクトルマシン とは:クラス間のマージンを最大化するように分類境界を引く手法。カーネルで非線形にも対応。
本ページでは「svm」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
サポートベクターマシン (SVM) は 2 クラス間のマージン (境界に最も近いサンプルとの距離) を最大化する分類器で、 カーネル法によって非線形境界も扱える。 ハードマージン / ソフトマージン (C パラメータ)、 RBF・多項式カーネル、 双対問題と KKT 条件、 サポートベクター、 SVR (回帰拡張) を本ページで扱う。
🍰 まずはやさしく
2つのグループの間に広い道を作るイメージです。
どちらのグループか迷わないようにするために使います。
買い物で、安い店と高い店をはっきり分ける感じです。
ここでは、図を使って仕組みを直感的に理解します。
SVM は「2 クラスを最も広いマージンで分ける直線(または曲面)」を引く分類器。 SSDSE-B-2026 で「人口 100 万人以上 vs 未満」を「出生率・65歳以上人口比率・婚姻件数」から分類すると、 SVM は境界に近いサポートベクターだけを使って最適な超平面を引く。 線形で分けにくいときはカーネルで非線形化。
SVMは「マージンを最大化する超平面」を引く。 サポートベクトルだけが境界を決め、 カーネル関数で非線形にも拡張できる。
→ 太線が境界、 破線が±1マージン。 オレンジ枠の点がサポートベクトル。
→ カーネル関数で高次元空間に写像すると線形分離が可能になる。
→ C が小さいほど誤分類を許してマージンを広げ、 過学習を抑制する。
サポートベクターマシン (SVM) について、 ここまでの内容が「自分で説明できるか」を 5 問で確かめてみよう。 答えに自信が持てなかったら、 該当する章へ戻ってもう一度読み直すこと。 暗記ではなく、 「なぜそうなるか」を 1-2 文で言語化できることが目標。
Q1. マージン最大化は何を最大化しているのか
SVM の目的関数は「マージン (境界平面と最も近いサンプルとの距離) を最大化する」と説明される。 では、 マージンが大きいほど何が良いのかを、 汎化性能の観点から 2 文で書け。 ヒント: マージン = 境界の「余裕」であり、 余裕があるほど未知データへの誤分類耐性が高い。
答えの方向: マージンが大きい境界は、 訓練データと境界の距離に余裕があるため、 未知サンプルが境界の反対側に多少ずれても誤分類されにくい。 これは VC 次元的にも汎化誤差の上界が小さくなることに対応し、 過学習を抑える効果がある。
Q2. サポートベクトルとは何で、 なぜ重要か
SVM では「境界面に最も近いサンプル」だけが境界を決め、 他のサンプルは境界の式に直接寄与しない。 これがサポートベクトル。 サポートベクトル以外のデータ点を除いて学習しても、 境界はほぼ同じになる理由を 1-2 文で説明せよ。
答えの方向: SVM の最適化はラグランジュ乗数 αi が 0 でない点 (= サポートベクトル) のみが境界の式 (w = Σ αi yi xi) に寄与する形になる。 つまり αi = 0 となる遠方のサンプルは数式上、 境界を 1 mm も動かさない。 だからサポートベクトル以外を除外しても結論が変わらない。
Q3. C パラメータの意味
ソフトマージン SVM の C を「大きく」する/「小さく」すると、 境界はそれぞれどう変化するか。 過学習・未学習の観点で違いを述べよ。
答えの方向: C を大きくする = 誤分類への罰則が大きい = マージンが狭くてもよいから訓練誤差を限界まで下げに行く → 過学習リスク増。 C を小さくする = 誤分類を許す代わりにマージンを広げる → 未学習に近づくが汎化に強い。 グリッドサーチで CV により最適 C を選ぶのが定石。
Q4. カーネル関数を使う理由
線形分離できないデータに対して SVM ではカーネル関数 (RBF、 多項式など) を用いる。 「特徴量を高次元に写像してから線形 SVM を解く」とどう違うのか、 計算量の観点で説明せよ。
答えの方向: 高次元への写像 φ(x) を陽に計算すると次元が爆発するが、 SVM の双対形式は内積 <φ(xi), φ(xj)> しか現れない。 カーネル関数 K(xi, xj) = <φ(xi), φ(xj)> を使えば、 φ を一度も計算せずに内積だけ算出できる (= カーネルトリック)。 これにより無限次元の RBF 空間でも計算できる。
Q5. SVM を使う前にスケーリングが必要な理由
SVM (特に RBF カーネル) を SSDSE-B-2026 のような実データに適用する前には、 必ず StandardScaler などで標準化することが推奨される。 なぜか。
答えの方向: RBF カーネル K(x,y) = exp(-γ||x-y||²) は特徴量間のユークリッド距離に直接依存する。 もし「人口 (単位: 万人)」と「平均年収 (単位: 万円)」のようにスケールが大きく違うと、 大きい値の特徴量だけが距離を支配し、 他の特徴量が無視される。 これを防ぐため、 平均 0・分散 1 にそろえる標準化が必要。
→ 5 問とも自分の言葉で 2 文で説明できれば、 SVM の核心は理解できている。 詰まった項目は「マージン最大化」「双対問題」「カーネル」のセクションに戻って読み直そう。
SVM は線形分離が難しい問題で強力だが、 万能ではない。 適用前に押さえておくべき前提条件・限界・よくある誤解を 1 つずつ整理しておく。
RBF・多項式カーネルはユークリッド距離に依存するため、 特徴量のスケール差が大きいと「スケールの大きい変数だけが効く」モデルになる。 例えば SSDSE-B-2026 の都道府県データで「人口 (百万人単位)」「年収 (万円単位)」「ジニ係数 (0-1)」を混ぜると、 ジニ係数は事実上無視される。 必ず StandardScaler や RobustScaler で 0 平均・1 分散にそろえる。 線形カーネルでも標準化は推奨。
SVM の双対問題は O(n²) 〜 O(n³) で計算量がスケールする。 n が数万を超えると訓練時間が現実的でなくなる。 大規模データには SGDClassifier (loss='hinge') や LinearSVC、 あるいは LightGBM などの勾配ブースティングへの切り替えを検討する。
SVM は本来「境界からの距離」を返すモデルで、 確率は直接出ない。 確率が必要なら sklearn の probability=True オプション (内部で Platt scaling を実行) を使う。 ただし計算コストが上がり、 確率の校正度合いも完全ではない。 ロジスティック回帰と比較し、 用途に応じて選ぶ。
文章分類のような高次元スパース行列では、 線形 SVM (LinearSVC) はロジスティック回帰や Naive Bayes と性能差が小さく、 学習が速いそれらに軍配が上がることが多い。 RBF カーネルの利点は「特徴量数 < サンプル数」かつ「非線形性が明確」な場面で最も大きい。
原型の SVM は線形分離器だが、 カーネルトリックを使えば任意の非線形境界も表現できる。 RBF カーネルは理論的に「任意の関数を近似できる」ユニバーサル近似器に近い。 「SVM は線形にしか効かない」というのは誤解。
確かに予測時に必要な情報はサポートベクトルだけだが、 「最初からサポートベクトルだけ拾えばよい」というわけではない。 どのサンプルがサポートベクトルになるかは最適化を解いて初めて分かるので、 訓練時には全データを使う必要がある。 また、 サポートベクトルが多すぎる場合は過学習や C が小さすぎる兆候であり、 ハイパーパラメータの見直しが必要。
カーネルは「内積を一般化する関数」であって、 任意の非線形を等しく扱えるわけではない。 RBF カーネルは局所的な構造を捉えるのに強いが、 周期的なパターンや方向依存性のあるデータには弱い。 データの構造を見て (散布図・主成分プロットなど)、 カーネルを選ぶことが重要。
→ SVM の強みは「マージン最大化」と「カーネル」の 2 本柱だが、 適用条件 (標準化、 計算量) を満たさないと真価を発揮できない。 ベンチマークではランダムフォレストや勾配ブースティングとの比較を必ず行うこと。
下の平面には 青クラス (+1) と 赤クラス (-1) の点が並んでいます。 何もない場所をクリック(タップ)すると選択中のクラスの点を追加、 既存の点をクリックするとクラスが反転します。 SVM がリアルタイムで最大マージン境界を再計算し、 決定境界(濃い線)・マージン境界(薄い破線)・サポートベクター(黄色い枠の点)を描画します。 スライダーやカーネル切替で挙動の変化を体感してください。
この平面遊びを実データの分類に置き換えると、 例えば SSDSE-B-2026(2023 年度・47 都道府県)で「65 歳以上人口比率 = A1303 ÷ A1101」を計算し、 全国中央値以上を 高齢県 (-1)、 未満を 非高齢県 (+1) とラベル付けするイメージです。 実測値(cp932 / skiprows=[1] で読み込み)では:
| 都道府県 | 総人口 A1101 | 65歳以上 A1303 | 高齢化率 |
|---|---|---|---|
| 東京都 | 14,086,000 | 3,205,000 | 22.8% |
| 大阪府 | 8,763,000 | 2,424,000 | 27.7% |
| 鳥取県 | 537,000 | 179,000 | 33.3% |
| 島根県 | 650,000 | 227,000 | 34.9% |
| 秋田県 | 914,000 | 357,000 | 39.1% |
→ 東京・大阪のような大都市は低め、 秋田・島根・鳥取は高めと、 高齢化率は都市規模とゆるく相関します。 標準化した「人口」「高齢化率」を軸に取ると、 境界近傍の少数県(中央値付近の県)だけがサポートベクターになり分類境界を決めます。 上の widget で青=低齢・赤=高齢に見立てて追体験してみてください。(出典: 統計センター SSDSE-B-2026 実測値)
同じ二値分類でも ロジスティック回帰 と SVM は「何を損失にするか」が違います。 両者を並べると SVM の個性が際立ちます。
| 観点 | SVM(ヒンジ損失) | ロジスティック回帰(対数損失) |
|---|---|---|
| 損失関数 | $\max(0,1-y_if(x_i))$ — マージン内だけ罰する | $\log(1+e^{-y_if(x_i)})$ — 全点が滑らかに寄与 |
| 境界を決める点 | サポートベクター(近傍の一部)のみ | 全データが少しずつ影響 |
| 確率出力 | 直接は出ない(Platt 補正が必要) | $\sigma(f(x))$ で自然に確率が出る |
| 非線形化 | カーネルで容易(RBF 等) | 特徴量を明示的に増やす必要 |
| 外れ値への強さ | マージン外の外れ値は無視され頑健 | 遠い点も損失に効きやや敏感 |
🍰 まずはやさしく
境界線を決めるための数学的なルールです。
計算で一番いい分け方を見つけるために使います。
テストの点数で合格と不合格を分ける基準のようなものです。
ここでは、計算式を使って定義を詳しく読み解きます。
直感で全体像を掴んだら、 次は厳密な定義を見ます。 数式は短いものでも、 「何を入力にして、 何を出力するのか」を意識して読むと早く慣れます。
上の数式に出てくる各記号が何を表すかを、 言葉で翻訳します。 1 つずつ自分の言葉で言い換えられるようになると、 論文や教科書のスピードが一気に上がります。
| 記号 | 意味(言葉での説明) |
|---|---|
| $w, b$ | 超平面 $w^\top x + b = 0$ のパラメータ |
| $y_i \in \{-1, +1\}$ | クラスラベル |
| $\xi_i$ | スラック変数(誤分類を許容) |
| $C$ | マージンと誤分類のトレードオフ |
| カーネル | $K(x_i, x_j)$ で非線形分離 |
合成データではなく、 SSDSE-B-2026 を念頭に 47 都道府県を「都市圏 / 地方圏」に分類する SVM の手順を具体的に示します。
# 目的変数 Y
都市圏(9 県、 +1):東京・神奈川・千葉・埼玉・愛知・大阪・京都・兵庫・福岡
地方圏(38 県、 -1):その他
# 説明変数 X(2 次元で可視化用)
x₁ = 標準化された人口密度(z スコア)
x₂ = 標準化された第 3 次産業就業者割合(z スコア)
例(標準化後):
東京:(x₁, x₂) = (+4.42, +2.15) → 完全な都市圏
神奈川:(+2.43, +1.78)
大阪:(+3.06, +1.92)
鳥取:(-0.82, -0.94) → 地方圏
青森:(-0.71, -0.85)# 線形 SVM、 C=1 で学習
# 学習結果(仮想的だが現実的)
w = (0.62, 0.48)
b = -0.31
# 分離面の方程式
0.62·x₁ + 0.48·x₂ - 0.31 = 0
# 各点でのスコア f(x) = w·x + b
東京:0.62·4.42 + 0.48·2.15 - 0.31 = 2.74 + 1.03 - 0.31 = +3.46(強く都市側)
神奈川:0.62·2.43 + 0.48·1.78 - 0.31 = 1.51 + 0.85 - 0.31 = +2.05
鳥取:0.62·(-0.82) + 0.48·(-0.94) - 0.31 = -0.51 - 0.45 - 0.31 = -1.27(強く地方側)
# 分類:sign(f(x))
東京:+1 ✓(都市圏)、 鳥取:-1 ✓(地方圏)# マージン上の点(αᵢ > 0 かつ < C):「真のサポートベクター」
# 例:千葉、 滋賀、 宮城、 広島 などが境界近傍
# 想定される結果(仮想)
都市圏側 SV:千葉(f≈+1.02)、 滋賀(f≈+1.05、 誤分類)
地方圏側 SV:宮城(f≈-1.01)、 広島(f≈-0.95)
→ 計 4 件のサポートベクターで境界が決まる
→ 47 県中 43 件は分類に直接寄与しない(マージンの外側)
# RBF SVM、 C=1、 γ=0.5 で学習
# 各点間の RBF カーネル
K(東京, 大阪) = exp(-0.5·||(4.42-3.06)² + (2.15-1.92)²||)
= exp(-0.5·(1.85+0.053))
= exp(-0.95)
≈ 0.387
K(東京, 鳥取) = exp(-0.5·((4.42+0.82)² + (2.15+0.94)²))
= exp(-0.5·(27.46+9.55))
= exp(-18.5)
≈ 9.2×10⁻⁹
→ 東京と大阪は「類似」、 東京と鳥取は「全く別」# C と γ を変えた精度(5-fold CV、 仮想)
C=0.1, γ=0.1 → 精度 0.81(過小学習)
C=1.0, γ=0.5 → 精度 0.96(バランス良)
C=10.0, γ=2.0 → 精度 0.91(過学習傾向)
C=100, γ=10 → 精度 0.85(強い過学習)
# 最適:C=1.0, γ=0.5
# GridSearchCV で系統的に探索
数式だけでは「分かった気になる」だけで終わりがち。 ここで SSDSE-B-2026(教育用標準データセット — 47 都道府県 × 100+ 指標、 2018-2023 年度)の実値を当てはめて、 サポートベクターマシン の挙動を電卓的に追体験します。
SSDSE-B-2026 は 統計センターの SSDSE 配布ページ から CSV を直接ダウンロードできます。 本サイトでは data/raw/SSDSE-B-2026.csv に配置している前提でコードを書いています。
合成 2 点間で分離超平面のマージンを計算する。
1 2 3 4 5 6 7 8 9 | import numpy as np w = np.array([1, 1]) b = -5 x1 = np.array([3, 4]) x2 = np.array([1, 2]) norm_w = np.linalg.norm(w) print(f"x1 距離: {abs(w @ x1 + b)/norm_w:.3f}") print(f"x2 距離: {abs(w @ x2 + b)/norm_w:.3f}") print(f"マージン: {2/norm_w:.3f}") |
💬 手計算 (Step 2) と Python 出力が完全一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import pandas as pd import numpy as np from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.model_selection import train_test_split # SSDSE-B-2026 を読み込み(2 行目の日本語見出しは skiprows=[1] で除外) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023].copy() # 2 値ラベル: 大都市圏の 9 都府県を 1、その他を 0 urban = ['東京都','神奈川県','千葉県','埼玉県','愛知県','大阪府','京都府','兵庫県','福岡県'] d['urban'] = d['Prefecture'].isin(urban).astype(int) # 特徴量: 総人口・出生数・年平均気温(すべて実在列コード) X = d[['A1101', 'A4101', 'B4101']].astype(float) y = d['urban'] X_tr, X_te, y_tr, y_te = train_test_split( X, y, test_size=0.3, random_state=0, stratify=y) clf = make_pipeline( StandardScaler(), SVC(C=1.0, kernel='rbf', gamma='scale') ) clf.fit(X_tr, y_tr) print('テスト精度:', clf.score(X_te, y_te)) |
1 2 3 4 5 6 7 8 9 10 11 | from sklearn.svm import LinearSVC clf_lin = make_pipeline( StandardScaler(), LinearSVC(C=1.0, max_iter=10000, dual=False) ) clf_lin.fit(X_tr, y_tr) print('線形 SVM 精度:', clf_lin.score(X_te, y_te)) # 係数を取り出す print('係数:', clf_lin.named_steps['linearsvc'].coef_) |
1 2 3 4 5 6 7 8 9 10 11 12 13 | from sklearn.model_selection import GridSearchCV param_grid = { 'svc__C': [0.01, 0.1, 1, 10, 100], 'svc__gamma': [0.001, 0.01, 0.1, 1, 10], 'svc__kernel': ['rbf'] } pipe = make_pipeline(StandardScaler(), SVC()) grid = GridSearchCV(pipe, param_grid, cv=5, scoring='f1', n_jobs=-1) grid.fit(X_tr, y_tr) print('最適パラメータ:', grid.best_params_) print('最適スコア:', grid.best_score_) |
1 2 3 4 5 6 7 8 9 10 | clf_bal = make_pipeline( StandardScaler(), SVC(C=1.0, kernel='rbf', class_weight='balanced') ) clf_bal.fit(X_tr, y_tr) # F1 で評価 from sklearn.metrics import classification_report y_pred = clf_bal.predict(X_te) print(classification_report(y_te, y_pred)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import matplotlib.pyplot as plt import numpy as np import pandas as pd from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline # 決定境界は平面にしか描けないので、この抜粋では特徴量 2 つのモデルを作り直す # (前のブロックの clf は 総人口・出生数・年平均気温 の 3 特徴量) _d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _d = _d[_d['SSDSE-B-2026'] == 2023].copy() urban = ['東京都','神奈川県','千葉県','埼玉県','愛知県','大阪府','京都府','兵庫県','福岡県'] _d['urban'] = _d['Prefecture'].isin(urban).astype(int) X2 = _d[['A1101', 'A4101']].astype(float) # 総人口・出生数 y2 = _d['urban'] clf2 = make_pipeline(StandardScaler(), SVC(C=1.0, kernel='rbf', gamma='scale')) clf2.fit(X2, y2) svc = clf2.named_steps['svc'] sv = svc.support_vectors_ print(f'サポートベクター数: {len(sv)}') # 標準化した空間で格子を作り、決定関数を評価する Xz = clf2.named_steps['standardscaler'].transform(X2) xx, yy = np.meshgrid(np.linspace(Xz[:, 0].min() - 1, Xz[:, 0].max() + 1, 100), np.linspace(Xz[:, 1].min() - 1, Xz[:, 1].max() + 1, 100)) Z = svc.decision_function(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape) plt.contourf(xx, yy, Z, alpha=0.4, levels=[-1, 0, 1]) plt.scatter(Xz[:, 0], Xz[:, 1], c=y2, edgecolor='k') plt.scatter(sv[:, 0], sv[:, 1], s=200, facecolors='none', edgecolors='red', label='SV') plt.xlabel('総人口 (標準化)'); plt.ylabel('出生数 (標準化)') plt.legend() plt.savefig('svm_boundary.png', dpi=150) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from sklearn.svm import SVR from sklearn.compose import TransformedTargetRegressor # 連続目的変数:出生数 A4101(実在列) y_reg = d['A4101'].astype(float) X_reg = d[['A1101','A1303','B4101']].astype(float) # 総人口・65歳以上・気温 # SVR は「目的変数のスケール」にも敏感。出生数は数万のオーダーなので、 # 既定の C=1.0・epsilon=0.1 のままだと何も学習できず R² が負になる。 # y も標準化して学習し、予測時に元のスケールへ戻す。 svr = TransformedTargetRegressor( regressor=make_pipeline(StandardScaler(), SVR(C=10.0, kernel='rbf', epsilon=0.1)), transformer=StandardScaler()) svr.fit(X_reg, y_reg) print('R² =', round(svr.score(X_reg, y_reg), 4)) |
1 2 3 4 5 6 7 8 9 10 11 12 | from sklearn.svm import OneClassSVM # 全データから「正常」の輪郭を学習 oc = make_pipeline( StandardScaler(), OneClassSVM(nu=0.1, kernel='rbf', gamma='scale') ) oc.fit(X) # -1 = 異常、 1 = 正常 labels = oc.predict(X) print(d.loc[X.index][labels==-1][['Prefecture','A1101']]) # 異常=外れ値県 |
まず環境をそろえます。 必要なライブラリを入れ、 matplotlib の日本語フォント(Hiragino Sans)を設定し、 SSDSE を encoding='cp932' で読み込んで shape・head()・describe() を確認します。 SVM も距離(内積)で境界を決めるので、 k 近傍法と同じくスケールの違いに弱く、 StandardScaler が実質的に必須です。 この後の節では 47 都道府県を 2 群に分ける境界を引き、 カーネルを変えると境界の形がどう変わるかを見ます。 エンコーディングを指定し忘れると UnicodeDecodeError で止まるのが最初の関門なので、 ここだけは丸暗記して構いません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # サポートベクターマシン を SSDSE-B-2026 で確かめる最小コード import pandas as pd import numpy as np # 1) SSDSE-B-2026(教育用標準データセット)を読み込み df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) print('shape:', df.shape) # (564, 112) — 47 都道府県 × 12 年度 print('cols head:', list(df.columns[:8])) # 2) 直近年度(2023 年度)に絞る df23 = df[df['年度'] == 2023].copy() print('rows in 2023:', len(df23)) # 3) サポートベクターマシン を動かすために必要な列だけ取り出す y = df23['合計特殊出生率'].astype(float) x = df23['総人口'].astype(float) print('y stats:', y.describe().round(3).to_dict()) print('x stats:', x.describe().round(0).to_dict()) # 4) サポートベクターマシン の本処理(このページの主題) # — 具体実装は同カテゴリの個別ページにも掲載 print('---- サポートベクターマシン 結果 ----') print('mean y:', y.mean().round(3), '/ std y:', round(y.std(), 3)) print('mean x:', x.mean().round(0), '/ std x:', round(x.std(), 0)) print('corr(x, y):', y.corr(x).round(3)) |
うまく動かないときは ①data/raw/SSDSE-B-2026.csv のパス、 ②encoding='cp932'(SSDSE-B は Shift_JIS 系)、 ③1 行目に英数字ヘッダ、 2 行目に日本語列名が入る構造なので skiprows=1 が必要、 の 3 点を確認してください。
SVM は特徴量のスケールに非常に敏感です。 「人口(万人単位、 数十〜千)」と「進学率(%、 35〜70)」を同じデータに混ぜると、 人口のスケールが大きいため距離計算を支配し、 進学率は無視されます。 必ず StandardScaler や MinMaxScaler でスケールを揃えてから学習させてください。 これを忘れると精度が大きく劣化します。
RBF SVM では C(正則化)と γ(カーネル幅)の相互作用が大きく、 片方ずつ調整しても最適に到達しません。 必ず GridSearchCV や RandomizedSearchCV で同時に探索。 推奨範囲:C ∈ [0.01, 100](対数刻み)、 γ ∈ [0.001, 10] または γ='scale'/'auto'。 デフォルト設定で使うと最良ではないことが多いです。
SVM の学習計算量は概ね O(n² ~ n³)。 n > 数万件では現実的に動きません。 対策は (i) `LinearSVC`(線形限定だが O(n))、 (ii) Nystroem 法など特徴近似、 (iii) SGDClassifier with hinge loss、 (iv) サンプリングして縮小。 Random Forest や勾配ブースティングの方が大規模データには現実的です。
SVM は本質的に確率モデルではなく、 sklearn の `probability=True` オプションは Platt スケーリングで事後的に補正しているだけです。 また `probability=True` にすると学習が数倍遅くなります。 確率出力が必要なら、 学習後に `CalibratedClassifierCV` で別途キャリブレーションする方が柔軟。 確率の信頼性が重要ならロジスティック回帰の方が直接的です。
陽性 5%、 陰性 95% のデータで SVM をデフォルトで使うと、 全部陰性と予測するモデルが学習されます(精度 95%)。 `class_weight='balanced'` で逆頻度重み付け、 もしくは個別に `class_weight={0:1, 1:20}` のように指定。 評価指標も accuracy ではなく F1、 AUC、 recall を用いるべきです。
RBF は確かに万能ですが、 データ構造によっては線形 SVM の方が安定で高速、 特に高次元疎データ(テキスト、 ゲノム)では線形が標準です。 多項式カーネルは特定の幾何構造を持つデータに有効。 カーネル選択も交差検証で系統的に比較し、 単純な線形で十分な場合は線形を選ぶのが堅実です。
RBF SVM は本質的にブラックボックスです。 「どの特徴量が重要か」が直接見えません。 線形 SVM なら係数 w で重要度が出ますが、 RBF では SHAP、 permutation importance、 部分依存プロット等の事後分析が必要。 解釈性が最重要なら、 ロジスティック回帰、 決定木、 GAM などを最初から検討してください。
この用語を実務で使うときにつまずきやすい点を、 失敗パターン別に整理しました。 1 度経験すれば回避できるものばかりですが、 先に知っておくと事故が大幅に減ります。
p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:
| 統計量 | 効果量 | 小 | 中 | 大 |
|---|---|---|---|---|
| 2群平均差 | Cohen's d | 0.2 | 0.5 | 0.8 |
| 相関 | r | 0.1 | 0.3 | 0.5 |
| 線形回帰 | R² | 0.02 | 0.13 | 0.26 |
| ANOVA | η² (eta²) | 0.01 | 0.06 | 0.14 |
| χ² | Cramér's V | 0.1 | 0.3 | 0.5 |
| ロジスティック | Odds Ratio | 1.5 | 2.5 | 4.0 |
サポートベクトルマシン がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 機械学習 › 教師あり学習 › サポートベクトルマシン
中心に サポートベクトルマシン を置き、 そこから k近傍法・k-means・分類 計 3 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「サポートベクトルマシン」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「サポートベクトルマシン」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは サポートベクトルマシン の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → 教師あり学習 → サポートベクトルマシン という入れ子の位置を示します。 「教師あり学習には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。
SVM (サポートベクトルマシン) はマージン最大化原理に基づく分類器。 SSDSE-B-2026 の 47 都道府県を「大都市圏 (東京・大阪等 11 県) vs 地方 (36 県)」の 2 クラスに分け、 総人口 A1101 + 65歳以上人口 A1303 + 出生数 A4101 + 年平均気温 B4101 (いずれも SSDSE-B-2026 の実在列コード) を特徴量として SVM で分類するワークフローが典型。 RBF カーネルで非線形境界を捉えられ、 小サンプル (n=47) でも安定する。
Platt scaling で補正する。SVM は「サポートベクトル (境界近傍の少数サンプル) のみで分類面が決まる」スパース性が長所。 SSDSE-B-2026 のような n=47 でも、 サポートベクトルが 10 前後で安定モデルが組める。
SVM は高次元・小〜中規模データの分類で強い手法だが、 データ規模・特徴量タイプ・解釈性要件で線形 SVM、 RBF SVM、 他手法のいずれを選ぶかが変わる。 以下に典型シナリオと推奨手法を示す。
| シナリオ | 重視する観点 | 推奨手法 |
|---|---|---|
| 特徴量 >> サンプル (テキスト・遺伝子) | 高次元疎データ・線形可分 | 線形 SVM (LinearSVC) / LogisticRegression |
| 中規模 (n < 数万)・非線形境界 | カーネルトリック・マージン最大化 | RBF カーネル SVM (γ=scale) |
| 大規模 (n > 10 万) | 学習時間・スケーラビリティ | SGD-SVM / LightGBM / XGBoost |
| 解釈性を重視 / 分野知識統合 | 係数・ルールの読みやすさ | 線形 SVM + L1 / 決定木 |
| クラス不均衡 (1:100 以上) | 少数クラスの recall | class_weight="balanced" / SMOTE 併用 |
| 確率出力が必要 (ROC・キャリブレーション) | SVM は本来確率非対応 | CalibratedClassifierCV + SVM / LogisticRegression |
上の「直感で掴む」節を、 3 つのキーワードに分けてもう一段掘り下げます。 この 3 つが腑に落ちれば SVM の 8 割は理解できたと言えます。
下表は SSDSE-B-2026(cp932, skiprows=[1], 2023 年 47 都道府県)の実測値です。 特徴量は総人口 A1101・出生数 A4101・年平均気温 B4101(いずれも実在列コード)、 ラベルは 65 歳以上人口比率(A1303/A1101)が全国中央値以上なら 1。 StandardScaler + SVC を 5-fold 交差検証した正答率で、 いずれも本ページで再現可能な数値です(架空値ではありません)。
| 設定 | C | γ | CV 正答率 |
|---|---|---|---|
| 線形カーネル | 0.1 | — | 0.724 |
| 線形カーネル | 1 | — | 0.727 |
| 線形カーネル | 10 | — | 0.682 |
| RBF カーネル | 0.1 | scale | 0.642 |
| RBF カーネル | 1 | scale | 0.709 |
| RBF カーネル | 1 | 1.0 | 0.771 |
| RBF カーネル | 10 | scale | 0.749 |
| RBF カーネル(最良) | 10 | 1.0 | 0.813 |
読み取り:(1) C も γ も上げれば良いわけではない。 線形は C=1 が最良で C=10 では 0.682 に低下(過学習気味)。 RBF は (C=10, γ=1.0) が 0.813 で最良だが、 γ を上げすぎると境界が個々の点に張り付き汎化が落ちる。 (2) デフォルト(RBF, C=1, γ=scale=0.709)を鵜呑みにせず、 ハイパーパラメータを GridSearchCV で同時探索する意義が数字で見える。
| C | サポートベクター数 / 全 47 | マージンの性格 |
|---|---|---|
| 0.1 | 47(全点) | 非常にソフト(誤分類を大きく許容) |
| 1 | 34 | 中庸 |
| 10 | 25 | ややハード |
| 100 | 21 | ハードに近い(マージン狭) |
C を上げるほどサポートベクターが減るのがはっきり見えます。 C が小さいとマージン違反を許容するので多くの点が SV になり(=広く緩い境界)、 C が大きいと誤分類ペナルティが重く少数の点で境界を厳しく決めます。 SV 数が n/2(=約 24)を大きく下回る C=100 は過学習を疑う目安になります。
上の「落とし穴 7 選」を踏まえ、 特に結論そのものを歪めやすいポイントを補足します。
decision_function の符号付き距離はそのままでは確率ではありません。 ROC 曲線や閾値調整に確率が要るなら CalibratedClassifierCV で Platt/isotonic 較正を。 確率の素直さが最優先なら ロジスティック回帰が第一候補です。SVC は既定で OvO(クラス対ごとに分類器を作る)、 LinearSVC は OvR。 クラス数が多いと OvO は分類器数が O(k²) に増え計算が重くなります。 不均衡なら評価はマクロ F1で。ハードマージンは「1 点の誤分類も許さない」前提で、 完全に線形分離可能なデータでしか解が存在しません。 現実にはノイズや重なりがあるため、 ソフトマージンがスラック変数 ξᵢ ≥ 0 を導入し、 マージン違反を許しつつ ΣξᵢをコストCで罰します。 最小化する目的関数は「½‖w‖² + C·Σξᵢ」。 C が大きいほど違反に厳しく(ハード寄り)、 小さいほど寛容(ソフト寄り)です。
カーネルが有効なのは、 対応する高次元写像 φ が存在する(Mercer 条件を満たす)ため、 K(x, z) = φ(x)·φ(z) を φ を計算せずに求められるから。 これがカーネル法全体の基礎です。
SVM の主問題は制約付き 2 次計画で、 ラグランジュ双対に変形するとデータが内積 xᵢ·xⱼ の形でしか現れないためカーネル化が自然にできます。 双対変数 αᵢ が非ゼロの点がサポートベクター。 一方、 制約なしの等価な見方がヒンジ損失 max(0, 1 − yᵢ f(xᵢ)) の最小化+L2 正則化で、 これは ロジスティック回帰のロジスティック損失と対比されます(ヒンジは「正しく十分な余裕で分類できた点」の損失を厳密に 0 にする)。
SVM を回帰に拡張したのが SVR。 誤差が ε 以内なら罰しないε-不感帯を設け、 帯の外だけを罰します。 「大多数の点を帯の中に収めつつ、 モデルを平滑(‖w‖ 小)に保つ」発想で、 外れ値に頑健な回帰が得られます。
| 観点 | SVM | ロジスティック回帰 |
|---|---|---|
| 損失 | ヒンジ損失 | ロジスティック損失 |
| 確率出力 | 本来なし(要較正) | 直接得られる |
| 非線形 | カーネルで容易 | 特徴量を明示的に拡張 |
| 境界の決まり方 | サポートベクターのみ | 全データが寄与 |
| 解釈性 | 線形なら係数, RBF は低い | 係数・オッズ比で高い |
関連ページ:分類の全体像、 パーセプトロン(線形分離器の原型)、 カーネル法、 標準化、 ハイパーパラメータ。 なお SVR・One-Class SVM・双対の詳細は本ページ内で扱い、 個別ページは未整備のためテキストで補足しています。