#はじめに
以前に不均衡データにおいて少数派データの識別精度の劣化を抑制する方法として、オーバーサンプリング・アンダーサンプリング・コスト関数のウェイト調整の実装方法とその効果について報告しました。
https://qiita.com/ryouta0506/items/619d9ac0d80f8c0aed92
今回はその続きということで、kaggleの「Credit Card Fraud Detection」について教師付き異常値検知問題としてアプローチした結果を報告したいと思います。
#異常値検出アプローチ概略
教師付き異常値検知は、クラス1とクラス2の確率密度関数を決定することで学習を終わらせることができます。この確率密度関数に必要なパラメータは、ロジスティック回帰やSVMのように探索的アプローチと異なり、解析的アプローチによって得ることができます。そのため、ロジスティック回帰やSVMのようなコスト関数が必要とされません。つまり、クラス間の件数の割合と無関係にパラメータが決定できることになります。
今回の場合、特徴量にV1~V28と多変量を扱うため、多変量確率密度関数を取り扱うことになります。したがって、計算の対象は平均値ベクトルと共分散行列です。平均値ベクトルは、確率密度関数の算出する期待値が最大になる変量の組み合わせのようなものです。最も単純な多変量確率密度関数である2次元の場合、その関数の形状は立体の山のようになります。平均値ベクトルはこの山の頂上の位置ということになります。共分散行列は2つの情報が含まれた行列です。ひとつは、変量の分散です。先の山のたとえでいうと裾野の広がりにあたります。ふたつめは、変数間の相関です。X軸方向の分散が2、Y軸方向の分散が1、のような場合、上から見た裾野は楕円形になります。その際、楕円が右上がりなのか左上がりなのか、さらにはX軸に対して並行なのかを決定するためにこの相関があります。
クラス1とクラス2の確率密度関数が定義できたら、未知のデータに対して各クラスに属する期待度を計算し、結果を比較することで識別を行います。単純に比較すると両者の大小で実現できますが、教科書通りにいうと、以下の数式で計算した結果を閾値と比較して識別します。
log(クラス1の期待値 ÷ クラス0の期待値) = log(クラス1の期待値) - log(クラス0の期待値)
実装
実装のコードを以下に示します。
from sklearn.model_selection import train_test_split
from scipy.stats import norm
import scipy.stats as sc
from sklearn import metrics
nega_train , nega_test = train_test_split(dat01_nega)
posi_train , posi_test = train_test_split(dat01_posi)
test = pd.concat([nega_test,posi_test])
collist = list(test.columns.values)
collist.remove('Time')
collist.remove('Amount')
collist.remove('Class')
# 平均ベクトルの算出
mean_posi = posi_train[collist].mean()
mean_nega = nega_train[collist].mean()
# 共分散行列の算出
cov_posi = np.cov(posi_train[collist].as_matrix().T)
cov_nega = np.cov(nega_train[collist].as_matrix().T)
# クラス1とクラス2の期待値の算出
tmp = test[collist].as_matrix()
pdf_posi = sc.multivariate_normal.pdf(tmp, mean=mean_posi , cov=cov_posi)
pdf_nega = sc.multivariate_normal.pdf(tmp, mean=mean_nega , cov=cov_nega)
# 識別
C1 = 0.0000000001 # 結果がゼロになった場合に備えた補正値
C2 = 0.0000000001
result_list1 = np.log2(pdf_posi + C1) - np.log2(pdf_nega + C2)
result_list2 = [1 if x>=0 else 0 for x in result_list1]
なお、期待値が極小の場合、ゼロ扱いとなるためlog2の結果がinfとなってしまいます。そこで、補正をすることにしました。補正には乗算と加算がありますが、確実に結果が得られるように加算にしています。この値によって識別結果に影響することが予想されるので、問題に応じて調整することが求められます。
識別の閾値は無難にゼロとしました。この値も問題に応じて調整すべきものでしょう。
結果
識別結果は、以下のようになりました。
Predict | 0 | 1 | All |
---|---|---|---|
Class | |||
0 | 67633 | 3446 | 71079 |
1 | 12 | 111 | 123 |
All | 67645 | 3557 | 71202 |
全体の識別率は95.14%とまずまずです。また、クラス1の識別率も90.24%(111÷123)と相応の結果となりました。前回のオーバーサンプリング時のものとおおよそ同等の性能となりそうです。
まとめ
あえて複雑なモデルベースの手法を用いなくともシンプルなものでもそれなりの成果が得られることが確認できました。本問題の場合、V1~V28の特徴量がうまく正規分布に近かったことが影響しているのかもしれません。この結果からするとベイズ識別器を使えばさらにいい精度が得られることも期待できるのではないでしょうか。