2015年9月17日木曜日

h2oでanomaly detectionを動かしてみる~追記~

データアナリティクス・グループの梅田です。


前回までの前編後編の記事で、R+h2oを用いてanomaly detectionのAPIを試しに動かしてみることを行いましたが、補足すべき事項ができましたので、以下2点を追記します。
  1. CRANにて、v3(v3.0.0.30以上)のh2oが配布されるようになりました。過去記事ではサンプルコードをv2ベースで記載していましたが、このコードをそのままv3環境で実行すると動かないので、変更点について補足します。
  2. オプション「variable_importances」について追記します。

1. h2o v3用のサンプルコード

h2o v3では、一部オプションの追加・廃止・表記変更が行われており、v2用に書いたコードは当該オプションの記述を書き換えないと動作しないことがあります。前編・後編の記事に関連する部分のみ抜粋すると、以下のような差分があります。
  • h2o.importFileの引数に「key」は指定できない。代わりに「destination_frame」で指定できる(ただし必須項目ではない)。
  • h2o.deeplearningなどでモデルを作成するとき、入力データを指定する引数名が「data」から「training_frame」へ変更。
  • h2o.deeplearningの引数で「classification」は廃止された。
    この引数はもともと、モデルを分類器とするか回帰モデルとするかを指定するオプションであるが、「y(目的変数)」が指定されている場合、目的変数の型から自動で推定されるようになった。
    当該変数列の値が文字列かつ取りうる値が数種類の場合は分類器と判定、数値の場合は回帰モデルと判定、という具合。
    例えば、異常があったか無かったかを「1」か「0」かで予測するモデル(分類器)を作成したいのに、回帰分析(数値予測)を行ってしまう場合は、入力データで「1」「0」を指定していた列の値を「T」「F」などの文字列に置き換えると分類器として判定される。(私も似たような状況に遭遇してデータをこのように加工しました)
  • h2o.deeplearningの引数で、「autoencoder=T」を指定した場合、「y」の値は指定できない。
  • h2o.anomalyの引数で、「model」は指定できない。「object」で指定する。

上記変更点を踏まえて、後編の中盤で記載したサンプルコードを修正すると以下のようになります。「variable_importances=T」というオプションも追記していますが、これについては、すぐ後で説明します。

datafile_path <- "accesslogdata.csv"
datafile <- h2o.importFile(localH2O, path = datafile_path)

dlmodel<-h2o.deeplearning(x=seq(1,4),
training_frame=datafile,
hidden=c(20,20),
activation="Rectifier",
autoencoder=T,
variable_importances=T,
ignore_const_cols=F)

anomaly_data <- h2o.anomaly(data=datafile,object=dlmodel)


2. オプション「variable_importances」について

h2o.deeplearningで「variable_importances=T」を与えて実行すると、作成したモデルの中で、それぞれの説明変数(要素)をどの程度重要視しているのかを出力させることができます。

上記のサンプルコードの場合、

dlmodel@model$variable_importances

の部分にその情報が格納されます(v2の場合は「dlmodel@model$varimp」)。
この情報は、以下のようなコードでcsvファイルに出力させることもできます。

write.csv(dlmodel@model$variable_importances,"varimp.csv")

出力例として、後編の記事で、擬似アクセスログの異常検知を試みたときのvariable_importanceを表にしたものを示します。
(ここではトップ10のみ抜粋しましたが、実際にはcsvファイルに書き出せば最終位まで漏れなく出力されます)

variablerelative_
importance
scaled_
importance
percentage
1useragent.Mozilla/5.0 (iPhone...110.000724
2useragent.Mozilla/5.0 (Windows NT 6.1...Chrome...0.9270.9270.000671
3useragent.Mozilla/5.0 (iPad...0.8680.8680.000628
4useragent.Mozilla/5.0 (Windows NT 6.1...0.850.850.000616
5useragent.Mozilla/5.0 (Windows NT 6.1...Firefox...0.6930.6930.000502
6id0.6560.6560.000475
7useragent.Mozilla/5.0 (Linux; Android 5.1...0.5330.5330.000386
8time.2015/4/1 1:57:140.2370.2370.000171
9ipaddress.40.61.82.1040.230.230.000167
10time.2015/4/1 0:39:040.2290.2290.000166

variableの列には「項目名.値」の様々なパターンが書き出されており、これが重要度順にソートされた項目値になります。6位の「id」のみ項目名のみの出力となっていますが、数値データについてはこのような扱いになるようです。
relative_importance列とscaled_importance列の値が重要度を表します。この例では2つの値が全て同値となっており、2種類の違いはわかりませんが、7位以上と8位以下とでは重要度の値に開きがあるので、7位以上がより重要視されていることがわかります。
percentage列は全行の値を合計すると1になっていました。重要度の全体を1としたときに当該要素がどの程度の割合を占めているかを表していると言えます。

上記の出力を後編の結果と照合すると、今回は正常パターンのUserAgentの値(6種類)とIDの値が重視された結果、「UserAgentとIDの値が正常パターンと一致するか否か」を重視した検知結果になったものと推測されます。正常パターンとは異なるUserAgentの値(Mac環境の値を使っていました)の重要度は1000位を下回っており、重要な決め手としては扱っていなかったようです。後編で説明した b. のパターンは、「正常なID+他とは違うUserAgent」の組み合わせだったので、結果として正常パターン寄りに判定されたようです。

「variable_importance」オプションは、有効にすると計算量が増え、処理時間が増えるケースがあることから、デフォルトでは無効になっていますが、予測結果/検知結果の説明の一助になるので、なるべく有効にしておくことをお勧めします。

0 件のコメント:

コメントを投稿