Splunkと機械学習（実践編）

[前回の記事](http://qiita.com/kikeyama/items/20688617bf885c1c9361)では[Splunk Machine Learning Toolkit App](https://splunkbase.splunk.com/app/2890/)（略してMLTK）のインストールと基本的な使い方について書きました。
今回はMLTKに含まれる機械学習のコマンド、マクロの使い方を書きたいと思います。

# はじめに
機械学習を使って目指すのは、

**リアルタイムに問題点や課題を検知・予測し、それを意思決定につなげてオペレーションやビジネスの質を向上すること**

です。

アメリカのドーナツチェーン店におけるSplunk事例があります。

[YouTube: Art of the Possible: Smart Retail](https://youtu.be/K-6X1SqHops)（英語）

1:09あたりからMachine Learning Toolkitの利用について触れられています。
使われているモデルは比較的単純なものですが、販売数をリアルタイムに予測しアラートをあげることで、販売戦略や在庫管理に活用しているものとなります。

重要なのは**リアルタイムな意思決定**です。
（大事なことなので2回言っておきます）

# Machine Learning Toolkitを使う前に...
Splunkと機械学習という組み合わせは、あらゆる種類のデータ・ログを取り込んで、思い通りに整形・加工して、過去のデータから未来への知見を得るというものになります。

まさにビッグデータですね。

基本的なことにはなりますが、以下のステップが必要となります。

1. 学習に必要となるデータの収集（セキュリティの場合だと、Firewall、IDS/IPS、Proxy、DNSあらゆるログが対象となります）
2. 学習とモデル作成
3. モデル検証
4. リアルタイムのデータに適用

学習の変数とするデータが足りなかったり適切でないために高精度のモデルが作成できない場合、Step-1に戻ってデータを収集・加工するところを見直す必要があります。

前回も書きましたが、**トライ&エラー**が大事です。

# やってみよう
ということで、実際にSplunkとMLTKを使ってみましょう。

## 環境
自分のMac端末にSplunkをインストールして動かしました。

- Splunk Enterprise 6.5.3
- Machine Learning Toolkit 2.2.0

## データ
今回はMLTKに既に入っている、マルウェア検知のためのデータを使います。
SplunkのMLTK Appで、サーチ画面に入り、下記のコマンドを実行します。

```
| inputlookup firewall_traffic.csv
```

<img width="1361" alt="Screen Shot 2017-05-08 8.14.46 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/bfaf0c17-f37c-1c83-ac8d-bd2e1d5cb30e.png">

Firewallのログから作成されたデータを想定しているみたいです。

ソースIP/ポート（`src_ip`/`src_port`）や宛先IP/ポート（`dest_ip`/`dest_port`）、脆弱性の有無（`has_known_vulnerability`）、送受信サイズ（`bytes_received`/`bytes_sent`）等々がありますね。

実際にはFirewallだけではここまでのデータは取得できないでしょう。
脆弱性スキャンやパケットキャプチャ、CMDB、syslog等も組み合わせてデータ作成する必要がありそうです。

## アルゴリズム
今回は**ロジスティック回帰**を使います。
これは**教師あり学習**になるので、学習データに対する答え（ラベル）を与えてやる必要があります。

マルウェア検知なので、予測する対象は`used_by_malware`の値とします。
教師あり学習では、ラベルを与えることで学習したモデルが正解に近いかどうかを判断して、より精度の高いモデルを作ることがキモです。
なので、今回のデータでは既に正解データとして`used_by_malware`フィールドの値が入っています。

## Splunk MLTKコマンドを使ってみよう
それでは、Splunk MLTKを使ってみましょう。

### 学習データと検証データを分類する: `sample`コマンド
最初のステップとして、モデル作成のための学習データと評価のための検証データを分けます。
機械学習では、かならず学習データと検証データは全く別々のものにしましょう。
それを実現するコマンドは`sample`コマンドです。
これはMLTK Appに入っているカスタムコマンドです。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123
```

このコマンドでは、`partitions=10`を指定することで、元のデータを10個に分類しています。
ただし、このコマンドは毎回ランダムに分類するため、学習データと検証データを完全に分けることができません。

そこで、`seed`オプションを使います。
このオプションで指定する数字が分類のキーとなり、ランダムではなく一定のものとなります。
この場合、`seed=123`と指定しているので、学習と検証それぞれのステップでこのオプションを指定すれば、分類がランダムではなく同じ分類となります。

<img width="955" alt="Screen Shot 2017-05-08 8.46.03 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/6d6b7bcf-fee0-3000-f542-1531f3a0eb85.png">

<img width="137" alt="Screen Shot 2017-05-08 8.48.15 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/f8b7466a-34df-d781-1bf8-bfe7dc54ee0a.png">

`partition_number`というフィールドができて、0〜9の数字で分類されていますね。

### 学習データの抽出: `search`コマンド
分類によって生成された`partition_number`フィールドを使って、学習データのみを抽出します。
使用するコマンドは`search`ですが、これはMLTKではなく、Splunkそのもののコアコマンドです。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123 
| search partition_number<5
```

学習データと検証データを5:5の割合で分類することを想定して、`partition_number`が5未満のものを抽出しました。

<img width="955" alt="Screen Shot 2017-05-08 8.52.23 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/8a273dfd-682a-48df-6326-a1346f05fa9f.png">

0〜4のもののみ抽出されていますね。
これが学習データとなります。

### モデル作成: `fit`コマンド
本題のモデル作成になります。
ここでは、MLTK Appのカスタムコマンド`fit`を使います。

`fit`コマンドの使い方は...

```
fit <アルゴリズム> <ラベルフィールド> from <学習フィールド（スペース区切りで複数可> into <モデル名>
```

です。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123 
| search partition_number<5 
| fit LogisticRegression used_by_malware from has_known_vulnerabirlity dest_ip dest_port src_ip src_port bytes_sent bytes_received into malware_logisticregression_qiita
```

学習データとして、`has_known_vulnerabirlity` `dest_ip dest_port` `src_ip` `src_port` `bytes_sent` `bytes_received`を指定しました。

保存したモデル名は何でも良いですが、アルゴリズム名やラベル名、プロジェクト名（もしくはID）等を入れたネーミングルールを決めると良いでしょう。
今回は`malware_logisticregression_qiita`としました。

### モデル検証: `apply`コマンド
`fit`コマンドで作成したモデルを検証するのに`apply`コマンドを使います。

使い方は...

```
apply <保存したモデル名>
```

こでだけです。

`sample`コマンドで分類したパーティションのうち、5以上のものを使って検証します。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123 
| search partition_number>=5 
| apply malware_logisticregression_qiita
```

<img width="1108" alt="Screen Shot 2017-05-08 9.31.52 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/a1f9e275-612a-3847-899c-7a61325f8f7e.png">

<img width="192" alt="Screen Shot 2017-05-08 9.32.41 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/16badf2d-f6c2-e181-1182-29622fdd20ca.png">

`predicted(used_by_malware)`フィールドができていますね。

### 評価: `` `classificationstatistics` ``マクロ
マクロ`` `classificationstatistics` ``を使って、Precision, Recall, Accuracyを算出します。
それぞれの説明は[前回の投稿](http://qiita.com/kikeyama/items/20688617bf885c1c9361#predict-categorical-fields)をご参照ください。

使い方は...

```
classificationstatistics(<実測値のフィールド名>, <予測値>)
```

です。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123 
| search partition_number>=5 
| apply malware_logisticregression_qiita as predicted 
| `classificationstatistics(used_by_malware,predicted)`
```

<img width="455" alt="Screen Shot 2017-05-08 9.40.07 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/af7c1c61-380a-f6e0-f329-6c8bc7c86c02.png">

Accuracyが0.53なので、あまり精度は良くないですね。

### Confusion Matrix: `` `confusionmatrix` ``マクロ
フィールド内の値 - yes / no が実測に対してどのように予測されているかの集計をします。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123 
| search partition_number>=5 
| apply malware_logisticregression_qiita as predicted 
| `confusionmatrix(used_by_malware,predicted)`
```

<img width="979" alt="Screen Shot 2017-05-08 9.46.09 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/ebb5c23c-9571-8cba-24cc-5516d66f7018.png">

実測値noの予測値noが17,318に対して予測値yesが2,663
実測値yesの予測値yesが9,060に対して予測値yesが20,434

という見方になります。

### モデル作成のやり直し
精度を上げるために学習データを見直しましょう。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123 
| search partition_number<5 
| fit LogisticRegression used_by_malware from has_known_vulnerabirlity src_port dest_port bytes_sent bytes_received packets_sent packets_received　into malware_logisticregression_qiita
```

`src_ip`を削除し、`dest_port` `packets_sent` `packets_received`を追加しました。

```
| inputlookup firewall_traffic.csv 
| sample partitions=10 seed=123 
| search partition_number>=5 
| apply malware_logisticregression_qiita as predicted 
| `classificationstatistics(used_by_malware,predicted)`
```

<img width="417" alt="Screen Shot 2017-05-08 10.24.40 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/174837/7779d83f-4485-c6b3-a69d-13562c6d18c0.png">

今度はAccuracyが0.75まで上昇しましたね。

このモデルを予測に使うことにしましょう。

# 最後に
Splunk Machine Learning Toolkitのサーチコマンドやマクロを中心に書きましたが、大事なのは機械学習をする目的と、それによって成し遂げるビジネスやオペレーションの改善です。

Splunkでの機械学習のやり方としては、`sample` `fit` `apply`を適材適所で使うことが大事でしょう。
サーチコマンドのマニュアルは[こちら](http://docs.splunk.com/Documentation/MLApp/latest/User/Customsearchcommands)をご参照ください。

また、教師あり学習の場合は正解を与える必要があるので、機械学習の前段階のデータ取り込み・加工の部分や学習データ、正解データの作成は知恵と経験が必要となるかもしれません。
そこらへんはまた要望があればまとめようかと思います。