【Pythonで異常検知】Chapter 1. 1変数正規分布に基づく異常検知 | USHITORA Lab.
スポンサーリンク

【Pythonで異常検知】Chapter 1. 1変数正規分布に基づく異常検知

Python

概要

この章では、以下の手順にしたがって1変数データの異常検知をPythonで実践することを目標とする。

  1. 訓練用データを正規分布にフィッティングする
  2. 得られた正規分布からテスト用データの異常度を求める
  3. 異常度の閾値を設定し、それを上回るデータを異常と判定する

データの準備

異常検知を実践するために、今回はScikit-learnのbrest_cancerのデータセットを用いる。このデータセットは、乳房にできた腫瘍の様々な特徴量の値と、その腫瘍が悪性・良性のいずれであったかを記載したラベルから成る。

変数dataにデータセットを読み込むと、data[“data”]に特徴量の値、data[“target”]に特徴量と関連付けられたラベルが格納される。ラベルは0が悪性、1が良性を意味し、特徴量の値からこれらのラベルを予測することが課題となる。

このデータセットは30の特徴量を持つため、今回はその中からworst areaの特徴量だけを用いる。また、このデータセットを訓練用とテスト用に分割することになるが、訓練用には良性(正常)のデータのみを用いるため、良性212例を訓練用としてモデルを作成し、残りの良性145例と悪性212例に対するラベルの予測を行うこととする。

正規分布へのフィッティング

訓練用データの特徴量のばらつきを、ヒストグラムで表示すると以下のようになる。

最尤推定法による正規分布へのフィッティング
観測された複数のデータがとある分布に基づいていると仮定して、その分布の形状を決定するパラメータを求める際、最尤推定法という手法がよく用いられる。この記事では、観測された結果が正規分布に従うと仮定した際に、最尤推定法を用いて平均 \(...

特徴量の分布は500付近で多く、そこから遠ざかるにつれて数が少なくなる山型の分布を取っている。今回の異常検知では、この特徴量の確率分布が正規分布にしたがうと考えて、この山型が最も適合する正規分布の形へフィッティングする。このとき、得られるのはフィッティングした正規分布の平均\(\mu\)と標準偏差\(\sigma\)である。なお、正規分布の導出とその性質についての解説は以下の記事を参照のこと。

エントロピーの最大化による正規分布の導出
この記事では、エントロピーを最大化する確率分布を求めることで、正規分布$$\mathcal{N}(x|\mu,\sigma)=\frac{1}{\sqrt{2\pi\sigma^2}}\exp\{-\frac{1}{2\si...

ここでは、Scipyに実装されているnorm.fitを用いてフィッティングを行う。

上図のオレンジ色の曲線が得られた正規分布である。なお、上図では特徴量の分布も確率密度として表示し直している。フィッティングの結果\(\mu\simeq 549, \sigma\simeq 158\)が得られ、このことから、特徴量の値が500程度になることはよくあることだが、100や1,000になることはほとんどあり得ないことが読み取れる。

確率変数と確率密度関数
この記事では、確率論で用いられる「確率変数」や「確率密度関数」などの用語について解説する。確率変数定義確率変数とは、確率論において、起こり得る事柄(事象)に割り当てられている数(通常、整数や実数など)を値として取る変数の...

異常度の計算

この、特徴量の値の起こりやすさを数値的に表現したものが「異常度」である。1変数正規分布では、特徴量が値\(x\)を取ることについての異常度\(a(x)\)は次のように表される。

$$a(x)=(\frac{x-\mu}{\sigma})^2$$

異常検知における異常度の定義
作成中。詳細は井手剛「入門 機械学習による異常検知――Rによる実践ガイド――」(2015)コロナ社を参照。

この値は\(x\)が\(\mu\)に近いときに小さく、\(\mu\)から遠いときに大きい。すなわち、名前の通り異常さの度合いを表している。また、データ数(今回は症例数)が非常に大きい時は、この異常度\(a(x)\)自身が自由度1、スケール因子1の\(\chi^2\)分布に従う。

$$a(x)\sim \chi^2(1,1)$$

異常検知における異常度が、カイ二乗分布に従うことの証明
作成中。詳細は井手剛「入門 機械学習による異常検知――Rによる実践ガイド――」(2015)コロナ社を参照。

この\(\chi^2\)分布を表示したのが下図である。

閾値の設定

上図に表示した\(\chi^2\)分布は確率密度関数であるため、これを\((0,\infty)\)の区間で積分すると1になる。また、図によると異常度が0~4程度の範囲が大部分の面積を占めているため、異常度が4以上となる確率はほとんどないことがわかる。異常検知の最終ステップでは、「異常度が〇以上になることは、△%程度の確率でしか起こり得ない(すなわち、ほとんど起こり得ない=異常である)」という異常度の閾値を設定し、それを超える異常度を持つデータ(症例)を異常(悪性)であると判断する。

たとえば、起こり得る確率が5%未満となる異常度の値は次のように求められる。

\(th_5\simeq 3.84\)より、異常度が3.84を超える確率は5%程度である。正常例の5%程度しか取り得ない値の特徴量であればそれはもう異常であると判断してもよく、ここでは上図の赤色で塗りつぶした範囲の異常度をもつデータはすべて異常とするモデルを作成する。

予測結果
悪性良性
真の状態悪性17735
良性7138

predict関数はデータ、パラメータ(\(\mu\)と\(\sigma\))、閾値を引数に与えることで、ラベルの予測結果を返す。また、sklearn.metrics.confusion_matrixは予測結果と真の状態の混同行列を返す。

混同行列の見方とその指標
混同行列(confusion matrix)とは、機械学習モデルや検査等の性能を示すための方法である。2×2の表に、実際のラベル(病気である・病気でない、など)と機械学習や検査による予測結果(陽性である・陰性である、など)の組み合わ...

今回は悪性例212例のうち177例が正しく悪性と判断され、35例の悪性は見落とされた。

ここで、閾値を変えることによって結果を改善することができる場合がある。次の実行例では、異常度の閾値を10%未満と、異常の範囲を広く取っている。

予測結果
悪性良性
真の状態悪性18626
良性19126

その結果、正しく悪性と判定される割合が増加したが、今度は先程よりも多くの良性例が間違って悪性と判断されていることがわかる。

次は逆に、異常度の閾値を1%未満とし、異常の範囲を狭めてみる。

予測結果
悪性良性
真の状態悪性16151
良性1144

今度は間違って悪性と判定される割合が非常に少なくなったが、かなり多くの悪性例を見落としている。

閾値をどのように定めるかによって予測性能は大きく変化しうるが、どの閾値が最適であるかの評価は難しい。最終的には異常検知を行う理由こそが閾値を決定するものとなり、たとえば今回の乳癌の判定のように異常(悪性)を見落とすと大きな不利益を被る場合には、多少偽陽性が増加しても異常の範囲は広く取った方がよいと考えられる。

コメント