背景
課題: サンプルの中にある外れ値を抽出したい
環境: MATLAB R2017a
Toolbox: Statistics and Machine Learning Toolbox
データの作成
多変量正規分布の乱数を mvnrnd を使用して作成します.5% のサンプルだけ別の分布から生成されたサンプルにしています.
この例は2次元データなので,描画することで目視で外れ値を見つけることが可能ですが,多次元になると描画&判別することが難しくなります.
X = [mvnrnd([0;0],[1 .95;.95 1],95); mvnrnd([2;-2],[1 .1;.1 1],5)];
Y = categorical([ones(95,1); zeros(5,1)]);
h = scatter(X(:,1), X(:,2),'.b');
h.SizeData = 150;
1クラスSVM によるモデルの学習(学習フェーズ)
このサンプルの中に5%の異常値サンプルが混じっていると仮定します.コード内では,fitcsvm の OutlierFraction プロパティで,サンプル内に混じっている異常値の割合を指定します.
サポートベクタマシン (SVM) は通常2クラス(あるいは複数使用して多クラス)の分類を行う手法です.1クラスSVMは,サンプルが1クラスに属しておりそれ以外は外れ値であるという仮定を置きます.そのため,通常 SVM のモデル学習の関数 fitcsvm の第二入力引数はターゲット(ラベル情報)になりますが,1クラスSVM の場合は1クラスであるという仮定のもと,ones 関数を使用して全て1を入れておきます.
W = ones(size(X, 1), 1);
d = fitcsvm(X, W, 'KernelScale', 'auto', 'Standardize', true, 'OutlierFraction', 0.05);
One Class SVMによる外れ値検出(予測フェーズ)
predict 関数でクラスの分類スコアを計算します.confusionmat 関数を使用すると,実際の観測値と予測値の混合行列を表示することができます.
[~, score] = predict(d, X);
idx = score > 0;
Y_hat = categorical(idx, [0 1]);
confusionmat(Y, Y_hat)
ans =
4 1
1 94
結果の描画 (2/3次元の場合のみ)
gca (get current axes) 関数を使って,現在の軸からXYの座標軸の範囲を取得します.
XLim = get(gca, 'XLim');
YLim = get(gca, 'YLim');
取得した座標軸の範囲を100等分するようなグリッドを生成します.
X1 = linspace(XLim(1), XLim(2), 100);
X2 = linspace(YLim(1), YLim(2), 100);
[X1Grid, X2Grid] = meshgrid(X1, X2);
前例と同様に,predict 関数を使用してグリッドごとにSVMの分類スコアを計算します.
[~, scoreGrid] = predict(d, [X1Grid(:), X2Grid(:)]);
scoreGrid = reshape(scoreGrid, size(X1Grid, 1), size(X2Grid, 2));
スコアを等高線で描画します.
figure;
h = scatter(X(:, 1), X(:, 2), '.b');
h.SizeData = 150;
hold on
contour(X1Grid, X2Grid, scoreGrid, 10)
hold off
右下のサンプルは、他のサンプルと明らかに異なる等高線上にあることが分かり、これらが外れ値となります。