K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

One-Class SVM

02.8.4

One-Class SVM

最終更新 2026-03-03 読了時間 3 分
まとめ
One-Class SVM は、正常データだけを使って「正常な領域」を囲む境界を学び、その外側に落ちた点を異常と判定する手法です。RBF カーネルを使うと境界は円や楕円に限らずデータの形に沿って曲がるので、三日月型やドーナツ型の正常領域も表せます。scikit-learn の OneClassSVM では nu が「訓練データのうち境界の外に出してよい割合の上限」を決め、nu=0.05 なら正常データの最大 5% を異常側に置きます。読み終えると、decision_function の符号が境界の内外を表し、nu と gamma が境界の広さと滑らかさをどう変えるかが分かります。
  • SVM — カーネルトリックとマージンの概念を先に理解すると効果的です

直感 #

工場の正常な製品の測定データは何千件もあるのに、不良品のデータは数件しかない。こうした場面では 2 クラス分類が使えません。One-Class SVM は正常データだけから「正常はこの範囲」という境界を 1 本引き、新しい製品がその外に出たら異常と呼びます。Isolation Forest が「孤立させやすい点を探す」のに対して、One-Class SVM は「正常を定義して、そこから外れたものを検出する」という逆向きの発想です。nu=0.05 は「訓練に使った正常データのうち 5% までは境界の外にはみ出してよい」という許容度で、これを小さくすると境界は広がり、大きくすると境界は正常点を絞り込むように縮みます。

詳細な解説 #

ライブラリとデータ #

次のコードは、原点のまわりに標準偏差 0.5 で散らばる正常データ 300 点と、\([-4, 4]\) の正方形に一様に散らばる外れ値 20 点を作ります。学習に使うのは正常データだけで、外れ値はあとで「境界の外に出るか」を試すためのテスト用です。

1
2
3
4
5
6
7
8
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import OneClassSVM
from sklearn.datasets import make_blobs

np.random.seed(42)
X_train, _ = make_blobs(n_samples=300, centers=1, cluster_std=0.5, center_box=(0, 0))
X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2))

モデル学習と予測 #

正常データだけで fit し、正常データと外れ値それぞれに predict をかけて、-1(異常)と判定された割合を表示します。

1
2
3
4
5
6
7
8
model = OneClassSVM(kernel="rbf", gamma="scale", nu=0.05)
model.fit(X_train)

y_pred_train = model.predict(X_train)
y_pred_outliers = model.predict(X_outliers)

print(f"正常データの異常判定率: {(y_pred_train == -1).mean():.2%}")
print(f"外れ値の異常検出率: {(y_pred_outliers == -1).mean():.2%}")

決定境界の可視化 #

平面を 300 × 300 の格子に切り、各格子点で decision_function を計算して等高線にします。赤い線が境界(値 0)、青く塗られた部分が境界の外側(負の値)です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
xx, yy = np.meshgrid(np.linspace(-5, 5, 300), np.linspace(-5, 5, 300))
Z = model.decision_function(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap="Blues_r", alpha=0.5)
plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors="red")
plt.scatter(X_train[:, 0], X_train[:, 1], c="blue", s=10, label="Normal")
plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c="red", s=30, marker="x", label="Outlier")
plt.legend()
plt.title("One-Class SVM Decision Boundary")
plt.show()

実行結果の読み方 #

赤い境界線は正常データのかたまりを囲む、ほぼ円に近い閉曲線になります。nu=0.05 なので、境界のすぐ外に青い点が 300 点の 5% 程度はみ出し、これが誤検知にあたります。20 個の外れ値 × は大半が濃い青の領域にあります。そこは decision_function が大きく負になる、境界から遠い「はっきりした異常」の場所です。

主要パラメータ #

パラメータ意味推奨
nu異常の上限割合0.01–0.1(事前知識に基づく)
kernelカーネル関数“rbf”(非線形に強い)
gammaRBF カーネルの幅“scale” or “auto”

gamma を大きくするとカーネルの幅が狭くなり、境界は個々の正常点にぴったり張り付いて穴だらけになります(過学習)。小さくすると境界は大きな 1 つの円に近づき、正常領域の形の細部を無視します。nu は境界の「厳しさ」、gamma は境界の「滑らかさ」と覚えると調整しやすくなります。

Isolation Forest との比較 #

手法アプローチ高次元耐性計算速度パラメータ感度
One-Class SVM正常境界を学習○遅い(O(n²))高い
Isolation Forest異常を直接分離○速い(O(n log n))低い

データが数万点を超えるなら、カーネル行列の計算が \(O(n^2)\) になる One-Class SVM より Isolation Forest が先です。数千点以下で、正常領域が三日月型のように曲がっていて境界を細かく引きたいときは One-Class SVM が向きます。

まとめ #

One-Class SVM は正常データだけから境界を学ぶ手法です。RBF カーネルを使えば、その境界は円に限らず正常領域の形に沿って曲がります。nu=0.05 は正常データの最大 5% を境界の外に置く許容度、gamma は境界の滑らかさを決め、decision_function の符号がそのまま正常(正)と異常(負)の判定になります。不良品のデータが集まらない製造ラインや、新種の攻撃を検知したいセキュリティ監視のように、「正常は定義できるが異常は定義できない」場面で使います。

  • Isolation Forest — ツリーベースの異常検知
  • SVM — 二値分類版の SVM
  • DBSCAN — 密度ベースの外れ値検出