cedro-blog

Keras AutoEncoder でクレジットカード詐欺を見破る

今回は、 AutoEncoderを使ってKaggle のクレジットカード取引データのどれが詐欺かを見破ってみたいと思います。

こんにちは cedro です。

皆さん、クレジットカードを使っていますか。私は小銭を扱うのが面倒だしポイントも付くので、金額に関わらずスーパーでもコンビニでも使えるところは全てクレジットカードを使っています。

ところで、クレジットカードをよく見ると、本来秘密にしなければならない重要な情報がカードに印字されていて、写真に撮られて情報を盗まれたり、落として見知らぬ人に使われてしまう心配がありますよね。

何だか気になって色々調べて見ると、クレジットカードを使う時の様々なデータを常に監視して、過去の実例から怪しいパターンを見つけると、直ぐ本人に問合せしたり、取引停止にして詐欺を未然防止する仕組みがあるようです。

そうした中、クレジットカード取引の異常検知に使うデータセットがあの有名なコンペティションサイト Kaggle にあることを知り、ぜひ試してみたくなりました。

ということで、今回は、 AutoEncoderを使ってKaggle のクレジットカード取引データのどれが詐欺かを見破ってみたいと思います。

 

データセットを入手する

今回使うデータセットは、2013年9月の欧州のクレジットカードの取引データです。2日間で284,807件の取引があり、その中に492件詐欺行為が含まれています。

kaggle のサイトにあるCredit Card Fraud Detection からデータセットをダウンロードし、適当なフォルダー(creditフォルダーとしておきます)の中に dataフォルダーを作り、そこに保存します。

 

データセットの内容を見るコードです。credit フォルダーの中でこのコードを実行します。

10行目で pandas でデータセットを読み込んだら、13行目の print( data.describe() ) だけで、全列の要約統計量(データ数、平均、標準偏差、最小値など)を一気に表示してくれます。pandas 便利!

項目は Time, V1〜V28, Amount, Class と全部で31項目あり、データ数は284807個です。Time は取引時間(秒)、Amountは取引金額(ドル)、Class は0が正常・1が異常を表しています。V1〜V28は、様々な取引状況のデータなのですが、どういう内容なのかは丸秘です。

 

異常(Classが1)の場合と正常(Classが0)の場合のAmount 列です。17−24行目で表示します。異常の場合は492件あって最大金額は2125ドル、正常の場合は284315件あって最大金額25691ドルということが分かります。

 

各列のヒストグラムです。27−28行目の data.hist( figsize = (20, 20) ) とplot.show() だけで表示できます。やっぱりpandas 凄い! 但し、表示順は実際の並びでなくアルファベット順です。

 

金額のヒストグラムです。33−45行目で表示します。異常(Fraud)の方が正常(Normal)より多額なのかと思いきや、むしろ少額ですね。一攫千金というよりは、目立たない様に少額で何回も使いたいということでしょうか。

 

時間帯と金額の関係です。48−58行目で表示させます。時間の単位は秒で2日分のデータですので、横軸の最大は60秒×60分×24時間×2日=172800です。異常(Fraud)と正常(Normal)で差は特に無い様ですね。

 

AutoEncoderに学習させます

17行目は学習をさせるかどうかのスイッチで、DO_TRANING = True で学習する、DO_TRANING = False で学習しないを選択します。

21−41行目で、学習データを作成します。細かな手順はコードのコメントを見て頂ければ分かると思います。最終的に、X_trainは以下の様なデータの集まりになります。

簡単に言うと、29列(31列からTimeとClassを除いた)のデータを1行づつ読み取り、29個の数字を学習データとして AutoEncoderの入力にします。そして、AutoEncoderはこれとできる限り同じ出力をだすことを学習します。

44−54行目はネットワークを構築部分。60−62行目はネットワークの最適化の部分で Optimiser = ‘adam’ ,  loss = ‘ mean_squared_error’ で行なっています。

64−66行目は学習した重みファイルを保存する部分、68−75行目は学習を実行する部分、78−84行目はロスの推移グラフを描く部分です。

では、早速実行してみましょう。mlpなのでノートパソコンで軽快に動きます。私のMacbookAir で20sec /epoch、100epochが約33分で完了します。

 

学習データは29個のデータの塊が227451 個あり、テストデータは29個のデータの塊が56962個あります。テストデータの中にある正常(0)の数は56864個、異常(1)の数は98個です。

 

ネットワークSummaryです。先程の29個のデータが Input_1に入力され、AutoEncoder はdense_4に出来るだけそれと同じ29個のデータを出力することを学習します。

 

ロス推移グラフです。train_lossも test_lossも順調に下がった様です。

異常検知をする

このコードを先程のコードの後に追加し、17行目の学習をさせるかどうかのスイッチは DO_TRANING =   False (学習しない)に変更します。

ポイントは、3−7行目の部分です。3行目はAutoEncoderが学習した重みファイルを読み込む部分、5行目はテストデータX_testをAutoEncoderに入力し、その出力をpredictions に入れる部分。

7行目はテストデータX_testと出力の平均2乗誤差(mse = mean squared error)を計算する部分です。入力するテストデータが学習した正常データの場合 mse は小さいですが、学習したことのない異常データの場合 mse は大きくなり、異常検知出来ることが期待できます。

13−28行目はROC曲線を描かせる部分、32−42行目はprecision曲線 とRecal曲線を描かせる部分、45−58は何処に閾値を設けるのかのイメージを描かせる部分、61−69行目はConfusion matrix を描かせる部分です。

まずは動かしてみましょう。学習はしませんので、あっと言うまに完了します。

 

分類性能を表すROC曲線です。左角に寄っている程性能が良い訳ですが、今回の様に異常データが極めて少ない場合は、これだけでは良く分かりません。

 

mse(テスト画像と再現画像の平均2乗誤差)Precision(適合率)Recall (再現率)の関係です。Precision は異常と予測した中に実際の異常が含まれる確率、Recallは異常と予測した中に実際の異常の何%が含まれるかを表します。

Precision を上げたいなら mse を上げ、明らかな異常だけ摑まえる様にすれば良い訳ですが、そうするとReacll は下がってしまいます。Recall を上げたいならmse を下げ、少しでも怪しいものは異常として捕まえれば良い訳ですが、そうするとPrecisionは下がってしまいます。つまり、Precision とRecall は相反する関係になります。

mse のどのあたりで Threshold(閾値)を設けるのかは、Precision とReacll をどうバランスさせたいかで決まります。今回は、非常に発生頻度の少ない異常を見付けたいので、Precisionの悪化には目をつぶりReacllを優先させる方針を取るべきでしょう。

 

これは、mse のどの値でTreshold(閾値)を引くと、異常がどれだけ捕まりそうかを可視化したグラフです。青色が正常取引、オレンジ色が異常取引を表しています。現在、mse =20 でTresholdを引いていますが、もう少しTreshold を下げないと異常の捕まりが少ない様です。

 

Confusion matrix です。正常データに比べて異常データがとても少ないので、かなりイビツな形になっています。いわゆる精度は Accuracy =(56796+29) / (56796+68+69+29) = 99.8%ですが、こういう場合はあまり意味がないですね。

現時点は、mse = 20で、Precision = 29 / (68+29) = 29.9% 、Recall = 29 / (69+29) =29.6% と丁度2つの指標が同じくらいですが、先程の方針通り、Precisionの悪化が容認出来る限りRacallを改善した方が良さそうです。

 

Treshold を調整してみます

先程のコードの45行目のTresholdの値を変更して実行すれば、色々な場合のConfusion Matrixが得られます。最終的に私が選んだのは、こんな設定です。

Treshold = 3で、Precision = 81 / (986+81) = 7.6% 、Recall = 81 / (81+17) =82.7% です。98件の異常取引のうち81件はその後の不正の未然防止が図れます。一方で、間違って取引停止にした 986人には「なぜ、使用停止になったかの説明とフォロー」をする必要がありますが、1000人未満なら何とか対応は出来るかと判断しました。

厳密に言えば、17人の不正の再発コストと986人への「なぜ使用停止になったかの説明とフォロー」のコストを比較して調整すべきですね。

最後に、学習+異常検知のコード全体を載せておきます。

では、また。