LoginSignup
5
10

More than 3 years have passed since last update.

異常検知入門1 基礎編

Posted at

Aidemy 2020/11/10

はじめに

 こんにちは、んがょぺです!バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます!
 今回は、以上検知入門の一つ目の投稿になります。どうぞよろしくお願いします。

*本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・異常検知について
・ホテリング法、マハラノビス距離について
・単純ベイズ法について

異常検知について

異常検知とは

異常検知とは、その名の通り異常なデータを捉えるというものである。具体的には、医療現場の患者の異変を検知することや、システムの故障を検知することなど、幅広く使われている。
・この単元では
「異常検知の理論の理解」「簡単な異常検知システムの実装」_を目指す。

異常パターン

・検知すべき「異常」のパターンについて見ていく。

外れ値

・1つ目が「外れ値」である。これまでも何度か出てきたものだが、外れ値とは「値がほかの集合と比べて大きく離れているもの」を指す。図示するとわかりやすい。

・図スクリーンショット 2020-11-02 17.27.04.png

・外れ値を検出する問題を、そのまま「外れ値検出」という。詳しくはChapter2で扱う。

変化点

・2つ目が「変化点」である。変化点とは「値がほかと異なった振る舞いをするもの」を指す。以下の図のように、ある点から値が急上昇している場合、その点が変化点である。

・図
スクリーンショット 2020-11-02 17.31.12.png

・変化点を検出する問題を「変化(点)検知」あるいは「異常部位検知」という。詳しくはChapter3で扱う。

異常検知における指標

値がどれだけ異常かを定量的に示したものが「異常度」である。基本的には異常度が高いほどその値は異常であるといえる。
・また、異常か正常かの境目となる点のことを「閾値」という。
・以降の異常検知で行うことは全て「異常度の定義→閾値の決定」という流れになる。この閾値の決定の際に「どの確率で異常とみなすか」を定義することが多く、この確率のことを「誤報率」という。

「(実際に正常であるもののうち、正常であると判定できた数)/(実際に正常である標本の数)」で算出されるものを「正答率(正常標本精度)」といい、「1-正常率」で表されるものが誤報率となる。つまり、誤報率は「実際に正常であるもののうち、異常と判定してしまったものの割合」である。
・これらの値は検出器の精度評価にも使われる

・誤報率を計算するコード
スクリーンショット 2020-11-02 18.29.37.png

ホテリング法

ホテリング法とは

ホテリング法とは、外れ値検知の手法の一つである。先述の通り、異常度と閾値を定義する。
・扱うデータについて「単一の正規分布から発生している」「異常な値をほとんど含まない」という条件を満たす時のみ有効に適用される。

・ホテリング法の流れは以下のようになる。
 ①.誤報率を自分で設定し、それに従って閾値を求める。
 ②.正常と言える値の平均値共分散行列を計算する。
 ③.テストデータの異常度を計算し、閾値を超えていたら異常と判断する

・以上が流れとなるが、データはほとんど正常とみなされる。また、ホテリング方は教師なし学習であると言える。

マハラノビス距離

・ホテリング法の流れ③では異常度を計算するが、このとき使われる指標が「マハラノビス距離」というものになる。この距離は「あるデータとデータ全体の平均との距離」である。
・普通距離を計算するときには「ユークリッド距離」を使用するが、異常度には「分散(スケール)の大きさによって値が大きく変わる」「変数同士の相関を反映できない」という理由で使用できない
・これに対しマハラノビス距離は、逆共分散行列正規化することで分散を考慮することを可能としている。具体的には、分散の小さいものの影響を強くし、大きいものの影響を弱くすることで分散を考慮する。
・また、正規化によって各特徴量間の相関を補正することもできる

・コードは以下の通りである(②で同様のことを行うため詳細は後述)。

スクリーンショット 2020-11-02 21.01.39.png

①.誤報率を自分で設定し、それに従って閾値を求める

・ここからは、実際にホテリング法を実装していく。ホテリング法で外れ値の検出をすること「T二乗法」という。
・最初は閾値を求めていくのだが、求める上で必要な「誤報率」は自分で設定する必要がある。誤報率は高く設定すればより多くの異常を検知でき、低く設定すれば正常なデータをより残すことができる。このように異常なデータの排除と正常なデータを残すことはトレードオフの関係にあるので、場合に即した値を設定をすることが大切である。一般的には0.05や0.01などの値が使われる。

・誤情報を設定し、データの量も十分にあるとき、閾値は「χ(カイ)二乗検定」という手法を用いて設定する。
・この検定は、具体的に言うと、誤報率を0.05に設定した場合、「正常時には0.05%未満でしか起こらないぐらい稀な値だから異常である」と検定している。

・実装は「st.chi2.ppf()」で行う。第一引数には「1-誤報率」、第二引数には次元数(変数の個数)を渡す。

・コード(異常度aはマハラノビス距離で求めるが、今回は省略)
スクリーンショット 2020-11-02 21.35.27.png

②.正常と言える値の平均値と共分散行列を計算する

・③で異常値を計算するには、先述したマハラノビス距離を求める必要があるので、この算出に必要な「平均値」「共分散行列」を求める。
・平均はnp.mean(data,axis=0)で求める。(axis=0で列ごとに求めている)
・データの共分散行列はnp.cov(data.T)で求める。

・コードスクリーンショット 2020-11-02 21.51.42.png

③.テストデータの異常度を計算し、閾値を超えていたら異常と判断する

・最後にdistance.mahalanobis()データ(x)と平均(mean)と逆共分散行列np.linalg.pinv(cov))を渡すことで計算できる。
・この結果と、①で算出した閾値(threshold)を比較して、異常を検知する。

・コードスクリーンショット 2020-11-02 22.07.29.png

ホテリング法の実践

・以上の①〜③までを併せて行う。コードは以下の通り。
・(補足)各データの異常値を計算するときはfor文でX_testの要素を抽出する必要がある。また、前項で行わなかった「閾値と異常値の比較」は、異常値が閾値より大なら「異常」、閾値以下なら「正常」とする。

スクリーンショット 2020-11-02 23.20.46.png

・結果(赤が外れ値(異常)、青が正常値)
スクリーンショット 2020-11-02 23.21.25.png

単純ベイズ法

単純ベイズ法とは

・ホテリング法を含む異常検知の手法は、「変数が多くなる(次元が増える)と計算量が増え、複雑になりすぎる」と言う欠点を持つ。これを解消するために、多変数の問題を1変数(1次元)の問題とする手法である「単純ベイズ法」が使われる。
・単純ベイズ法の基本的な考え方として、「変数同士の相関がないため、複数の事象が起こる確率が、それぞれの確率の積で表される」と言うものがある。例えば、コインを2回投げる問題で、2回とも表が出る確率は「1/2 * 1/2」で表される。これを応用して、データが異常か正常かの確率は、各変数の異常である確率(に重み付けをしたもの)の積で求めることができる。
・すなわち単純ベイズ法では、異常度はデータと重みの内積で(次元を1にしつつ)求めることができる。また、閾値はホテリング法のようには求められず、検証用データを使って最適化することで求められる
・単純ベイズ方が使える条件は「データの変数が0以上の整数であること」である。
・流れは以下の通りである。
 ①ベイズ法で訓練データから重みを計算する
 ②評価用データから閾値を最適化する
 ③異常度を計算し、閾値と比較する

・以上の流れについて、Chapter2以降では、単純ベイズ法が使われる問題である「文書の異常値検知」で見ていく。

単純ベイズ法の事前知識

・異常検知に限らず、データ処理においては「データをベクトルとして考えたとき、適切なベクトルとの内積を取ると、そのデータの特徴を表す数値が得られる」と言う考え方がある。この時の「適切なベクトル」のことを「重みベクトル」と言う。
・単純ベイズ法でも、③で異常値を求めるときは、重みベクトルさえわかれば、あとはそれとデータの内積を取れば簡単に異常値を求めることができると言える。そのため、①ではこの重みベクトルを算出する

・今回行う「文書の異常値検知」について、メールのスパム判定のようなものを考えると、メール(文書)を形態素解析し、名詞など識別に使えそうなデータの出現個数を調べ、これとスパムかどうかのラベルを渡して重みを作成する、ということを行う。(つまり教師あり学習
・あとは、新しく渡された文書を同じように形態素解析し、その出現回数と作成した重みを掛け合わせて異常値を算出する。

・また、文書の異常値検知のデータは、「単語袋詰め表現」として出現頻度を表す。具体的には以下のコードを参照。これは、"hoge"と"foo"は出現せず、"bar","po","do"はそれぞれ3,4,1回出現したことを表している。

スクリーンショット 2020-11-03 14.19.17.png

①ベイズ法で訓練データから重みを計算する

重みの算出は、訓練データ「X_train」のうち、正常なデータ(X0)の重みを「w0」、異常なデータ(X1)の重みを「w1」としたとき、「np.log(w1/w0)」で求めることができる。
・よって、w0とw1をそれぞれ求める必要がある。「(全正常データの各単語の出現総数) ÷ (全正常データの総出現単語数)」で求めることができるが、np.logで対数を取るときに重みが0にならないように、「alpha=1」をたす。これを「ゲタを履かせる」と言う。
・各単語の出現総数は(正常データなら)「np.sum(X0, axis=0)」で求められる。総単語数は「np.sum(X0)」で求められる。

・コードスクリーンショット 2020-11-03 15.00.37.png

・結果(一部のみ)スクリーンショット 2020-11-03 15.01.02.png

②評価用データから閾値を最適化する

・①の重み算出は訓練データ(X_train)で行ったが、閾値の最適化は評価用データ「X_valid」で行う。
・閾値の最適化は、「metrics.roc_curve()」で行う。第一引数には評価用データのラベル「y_valid」を渡し、第二引数には評価用データの異常度を渡せば良い。
・評価用データの異常度については次の項でも行うが、先述の通りデータと重みの内積を取れば良いので、「np.dot()」で算出できる。
・また、「metrics.roc_curve()」は「偽陽性率」「真陽性率」「閾値候補」の3つを返すので、それぞれ変数「fpr」「tpr」「thr_arr」に格納する。
・この3つの変数について、「thr_arr[(tpr-fpr).argmax()]」とすることで閾値(threshold)を算出できる。

・コードスクリーンショット 2020-11-03 16.14.13.png

③異常度を計算し、閾値と比較する

・最後に、前項でも触れた通り、異常度を「np.dot()」で算出し、閾値と比較する。(コードは省略)

まとめ

・異常パターンには「外れ値」「変化点」がある。これを検出することが異常検知である。
・外れ値検出の手法の一つに、「ホテリング法」と言うものがある。ホテリング法では、まず「異常か正常か」の境目である閾値を決定し、次にデータの平均と(逆)共分散行列から異常度を算出する。この閾値と異常度を比べることで、異常か正常かを決定する。
・また、データが多次元であるときはこの手法が使えないので、「単純ベイズ法」を使って一次元のデータとして扱うことで異常検知を可能にする。
・単純ベイズ法では、重みベクトルを算出し、これとデータの内積を計算することで異常度を算出し、また閾値を決定してこの2つを比べることで異常か正常かを決定する。

今回は以上です。最後まで読んでいただき、ありがとうございました。

5
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
10