Anomaly チュートリアル (Ruby)¶
ここではRuby版のAnomalyサンプルプログラムの解説をします。
ソースコード¶
このサンプルプログラムでは、学習の設定をするconfig.jsonと外れ値検知を行うanomaly.rbを利用します。以下にソースコードを記載します。
config.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | {
"method" : "lof",
"parameter" : {
"nearest_neighbor_num" : 10,
"reverse_nearest_neighbor_num" : 30,
"method" : "euclid_lsh",
"parameter" : {
"hash_num" : 8,
"table_num" : 16,
"probe_num" : 64,
"bin_width" : 10,
"seed" : 1234
}
},
"converter" : {
"string_filter_types": {},
"string_filter_rules": [],
"num_filter_types": {},
"num_filter_rules": [],
"string_types": {},
"string_rules": [{"key":"*", "type":"str", "global_weight" : "bin", "sample_weight" : "bin"}],
"num_types": {},
"num_rules": [{"key" : "*", "type" : "num"}]
}
}
|
anomaly.rb
このクライアントは Jubatus 0.5.x 以降で動作します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #!/usr/bin/env ruby
# -*- coding: utf-8 -*-
$host = "127.0.0.1"
$port = 9199
$name = "test"
require 'json'
require 'jubatus/anomaly/client'
# 0. set keyboard interruption handler"
Signal.trap(:INT) {
print "You pressed Ctrl+C."
print "Stop running the job."
exit(0)
}
# 1. Configuration to connect Jubatus Server
client = Jubatus::Anomaly::Client::Anomaly.new($host, $port, $name)
# 2. prepare training dataset
open("../kddcup.data_10_percent.txt") { |f|
f.each { |line|
duration, protocol_type, service, flag, src_bytes, dst_bytes, land, wrong_fragment, urgent, hot, num_failed_logins, logged_in, num_compromised, root_shell, su_attempted, num_root, num_file_creations, num_shells, num_access_files, num_outbound_cmds, is_host_login, is_guest_login, count, srv_count, serror_rate, srv_serror_rate, rerror_rate, srv_rerror_rate, same_srv_rate, diff_srv_rate, srv_diff_host_rate, dst_host_count, dst_host_srv_count, dst_host_same_srv_rate, dst_host_diff_srv_rate, dst_host_same_src_port_rate, dst_host_srv_diff_host_rate, dst_host_serror_rate, dst_host_srv_serror_rate, dst_host_rerror_rate, dst_host_srv_rerror_rate, label = line.split(",")
data = Jubatus::Common::Datum.new(
"protocol_type" => protocol_type,
"service" => service,
"flag" => flag,
"land" => land,
"logged_in" => logged_in,
"is_host_login" => is_host_login,
"is_guest_login" => is_guest_login,
"duration" => duration.to_f,
"src_bytes" => src_bytes.to_f,
"dst_bytes" => dst_bytes.to_f,
"wrong_fragment" => wrong_fragment.to_f,
"urgent" => urgent.to_f,
"hot" => hot.to_f,
"num_failed_logins" => num_failed_logins.to_f,
"num_compromised" => num_compromised.to_f,
"root_shell" => root_shell.to_f,
"su_attempted" => su_attempted.to_f,
"num_root" => num_root.to_f,
"num_file_creations" => num_file_creations.to_f,
"num_shells" => num_shells.to_f,
"num_access_files" => num_access_files.to_f,
"num_outbound_cmds" => num_outbound_cmds.to_f,
"count" => count.to_f,
"srv_count" => srv_count.to_f,
"serror_rate" => serror_rate.to_f,
"srv_serror_rate" => srv_serror_rate.to_f,
"rerror_rate" => rerror_rate.to_f,
"srv_rerror_rate" => srv_rerror_rate.to_f,
"same_srv_rate" => same_srv_rate.to_f,
"diff_srv_rate" => diff_srv_rate.to_f,
"srv_diff_host_rate" => srv_diff_host_rate.to_f,
"dst_host_count" => dst_host_count.to_f,
"dst_host_srv_count" => dst_host_srv_count.to_f,
"dst_host_same_srv_rate" => dst_host_same_srv_rate.to_f,
"dst_host_same_src_port_rate" => dst_host_same_src_port_rate.to_f,
"dst_host_diff_srv_rate" => dst_host_diff_srv_rate.to_f,
"dst_host_srv_diff_host_rate" => dst_host_srv_diff_host_rate.to_f,
"dst_host_serror_rate" => dst_host_serror_rate.to_f,
"dst_host_srv_serror_rate" => dst_host_srv_serror_rate.to_f,
"dst_host_rerror_rate" => dst_host_rerror_rate.to_f,
"dst_host_srv_rerror_rate" => dst_host_srv_rerror_rate.to_f)
# 3. training
ret = client.add(data)
# 4. output results
if (ret.score != Float::INFINITY) and (ret.score != 1.0) then
print ret, ' ', label
end
}
}
|
解説¶
config.json
設定は単体のJSONで与えられます。JSONの各フィールドは以下のとおりです。
- method
異常検知に使用するアルコリズムを指定します。 Anomalyで指定できるのは、Recommenderベースの"lof"およびNearest Neighborベースの"light_lof"です。 今回は"lof"(Local Outlier Factor)を指定します。
- parameter
- methodで設定した異常検知アルゴリズムのパラメータを設定します。
- 今回は"lof"を利用するため、Recommender API に従ってパラメータを設定します。
- converter
特徴変換の設定を指定します。 ここでは、"num_rules"と"string_rules"を設定しています。
"num_rules"は数値特徴の抽出規則を指定します。 "key"は"*"つまり、すべての"key"に対して、"type"は"num"なので、指定された数値をそのまま重みに利用する設定です。 具体的には、valueが"2"であれば"2"を、"6"であれば"6"を重みとします。
"string_rules"は文字列特徴の抽出規則を指定します。 "key"は"*"、"type"は"str"、"sample_weight"は"bin"、"global_weight"は"bin"としています。 これは、すべての文字列に対して、指定された文字列をそのまま特徴として利用し、各key-value毎の重みと今までの通算データから算出される、大域的な重みを常に"1"とする設定です。
anomaly.rb
anomaly.rbでは、csvから読み込んだデータをJubatusサーバ与え、外れ値を検出し出力します。
- Jubatus Serverへの接続設定
Jubatus Serverへの接続を行います(20行目)。 Jubatus ServerのIPアドレス、Jubatus ServerのRPCポート番号を設定します。
- 学習用データの準備
AnomalyClientでは、Datumをaddメソッドに与えることで、学習および外れ値検知が行われます。 今回はKDDカップ(Knowledge Discovery and Data Mining Cup)の結果(TEXTファイル)を元に学習用データを作成していきます。 まず、学習用データの元となるTEXTファイルを読み込みます(23-24行目)。 このTEXTファイルはカンマ区切りで項目が並んでいるので、取得した1行を’,’で分割し要素ごとに分けます(25行目)。 取得した要素を用いて学習用データdatumを作成します(26-67行目)。
- データの学習(学習モデルの更新)
AnomalyClientのaddメソッドに2. で作成したデータを渡します(69行目)。 addメソッドの第1引数は、タスクを識別するZookeeperクラスタ内でユニークな名前を指定します。(スタンドアロン構成の場合、空文字("")を指定) 第2引数として、先ほど2. で作成したDatumを指定します。 戻り値として、tuple<string, float>型で点IDと異常値を返却します。
- 結果の出力
addメソッドの戻り値である異常値から外れ値かどうかを判定します。 異常値が無限ではなく、1.0以外の場合は外れ値と判断し出力します(72-74行目)。
サンプルプログラムの実行¶
[データのダウンロード]
$ wget http://kdd.ics.uci.edu/databases/kddcup99/kddcup.data_10_percent.gz $ gunzip kddcup.data_10_percent.gz $ mv kddcup.data_10_percent kddcup.data_10_percent.txt
[Jubatus Serverでの作業]
jubaanomalyを起動します。
$ jubaanomaly --configpath config.json
[Jubatus Clientでの作業]
必要なパッケージとRubyクライアントを用意し、実行します。
$ ruby anomaly.rb
[実行結果]
id_with_score{id: 194, score: 1.0000441074371338} normal. id_with_score{id: 494, score: 1.4595649242401123} normal. id_with_score{id: 1127, score: 1.0642377138137817} normal. id_with_score{id: 1148, score: 1.0404019355773926} normal. id_with_score{id: 1709, score: 1.2717968225479126} normal. id_with_score{id: 2291, score: 1.388629674911499} normal. id_with_score{id: 2357, score: 1.0560613870620728} normal. id_with_score{id: 2382, score: 0.9994010925292969} normal. id_with_score{id: 2499, score: 0.7581642270088196} normal. id_with_score{id: 2549, score: 1.011017084121704} normal. id_with_score{id: 2553, score: 1.263816475868225} normal. id_with_score{id: 2985, score: 1.408186435699463} normal. ... ...(以下略)