jubatus-exampleを全部動かしてみる（中編）

この記事は[Jubatus Advent Calendar](http://qiita.com/advent-calendar/2016/jubatus) 3日目の記事です。3日目にして早くも遅刻してしまい大変申し訳ありません。。。

前編に引き続いてjubatus-exampleを動かしていきます。
前編が予想以上に重くなってしまったので、中編からは少し端折って書いていきます。

# 中編で実行するexample

- rent(regression)
- train_route(graph)
- language_detection(classifier)
- trivial_stat(stat)
- trivial_burst(burst)
- slot(bandit)
- iris(classifier)

# rent
rentは回帰分析で家賃を推測するexampleです。
物件の属性情報からその家賃を分析します。

## とりあえず動かす

### jubatusサーバの起動

```
$ jubaregression -f rent.json
2016-12-02 09:43:27,395 26905 INFO  [server_util.cpp:429] starting jubaregression 1.0.0 RPC server at 10.0.2.15:9199                                                                                                                   
    pid                  : 26905
    user                 : udagawa
    mode                 : standalone mode
    timeout              : 10
    thread               : 2
    datadir              : /tmp
    logdir               : 
    log config           : 
    zookeeper            : 
    name                 : 
    interval sec         : 16
    interval count       : 512
    zookeeper timeout    : 10
    interconnect timeout : 10

2016-12-02 09:43:27,396 26905 INFO  [server_util.cpp:165] load config from local file: /home/udagawa/work/qiita/advent_calendar2016/jubatus-example/rent/rent.json
2016-12-02 09:43:27,397 26905 FATAL [server_util.hpp:161] exception in main thread: jubatus::core::common::config_exception: invalid configuration
    (#0) Message: "regularization_weight" is not used (.parameter)
    (#0) Source: ../jubatus/server/server/../../server/framework/server_helper.hpp
    (#0) Line: 100
    (#0) Function: jubatus::server::framework::server_helper<S>::server_helper(const jubatus::server::framework::server_argv&, bool) [with Server = jubatus::server::regression_serv]
```

起動しませんでした。これはjubatus1.0.0のアップデートのタイミングでregressionのアルゴリズムとパラメータに変更があったためです。
コンフィグの`PA`を`PA1`に変えればとりあえず動きます。

```
$ sed s/PA/PA1/ rent.json > rent_PA1.json
$ jubaregression -f rent_PA1.json
2016-12-02 09:47:51,054 27278 INFO  [server_util.cpp:429] starting jubaregression 1.0.0 RPC server at 10.0.2.15:9199                                                                                                                   
    pid                  : 27278
    user                 : TkrUdagawa
    mode                 : standalone mode
    timeout              : 10
    thread               : 2
    datadir              : /tmp
    logdir               : 
    log config           : 
    zookeeper            : 
    name                 : 
    interval sec         : 16
    interval count       : 512
    zookeeper timeout    : 10
    interconnect timeout : 10

2016-12-02 09:47:51,054 27278 INFO  [server_util.cpp:165] load config from local file: /home/TkrUdagawa/jubatus-example/rent/rent_PA1.json
2016-12-02 09:47:51,054 27278 INFO  [regression_serv.cpp:113] config loaded: {
  "method": "PA1",
  "converter": {
    "num_filter_types": {},
    "num_filter_rules": [],
    "string_filter_types": {},
    "string_filter_rules": [],
    "num_types": {},
    "num_rules": [
      { "key": "*", "type": "num" }
    ],
    "string_types": {},
    "string_rules": [
      { "key": "aspect", "type": "str", "sample_weight": "bin", "global_weight": "bin" }
    ]
  },
  "parameter": {
    "sensitivity": 0.1,
    "regularization_weight": 3.402823e+38
  }
}

2016-12-02 09:47:51,055 27278 INFO  [server_helper.hpp:226] start listening at port 9199
2016-12-02 09:47:51,055 27278 INFO  [server_helper.hpp:233] jubaregression RPC server startup
```

今度は起動しました。

### クライアントの実行

このクライアントの実行にはpyyamlライブラリを入れる必要があります。
次にjubahome.pyというスクリプトを実行します。
`-t` で学習に用いるデータのファイル、`-a`で分析に用いるデータのファイルを指定します。

```
$ pip install pyyaml
$ python jubahomes.py -a ../dat/myhome.yml -t ../dat/rent-data.csv
train ... 145
rent .... 10.0
```

trainには学習に使ったデータの数、rentに家賃の予測結果が出力されます。


# train_route

次はjubagraphのexample、train_routeです。
駅間の接続情報を学習してグラフを構築し、指定された2つの駅をつなぐ最短経路をみつけます。

## とりあえず動かす

### jubatusサーバの起動

例によって最初にサーバを起動します。

```
$ jubagraph -f train_route.json
```

### クライアントの実行

次にクライアントプログラムを実行していきます。
はじめにグラフをつくるcreate_graph.pyを実行していきます。

```
$ python create_graph.py
=== Station IDs ===
0	品川
1	大崎
4	田町
7	浜松町
10	新橋
...
144	四ツ谷
147	御茶ノ水
```

作成したグラフのノードIDと対応する駅の名前が表示されます。
次に分析用スクリプトsearch_route.pyを実行します。引数に始点と終点のノードIDを指定します。

```
$ python search_route.py 0 144
Pseudo-Shortest Path (hops) from 0 to 144:
  0	品川
  4	田町
  7	浜松町
  10	新橋
  13	有楽町
  16	東京
  19	神田
  147	御茶ノ水
  144	四ツ谷
```

このようにノード0の品川駅からノード144の四ツ谷駅までの経路が表示されます。

# language_detection

次は入力された言語がどの言語っぽいかを判定するlanguage_detectionです。英語、ドイツ語、フランス語、イタリア語のテキストをjubatusに学習させ、ユーザから入力されたテキストがどの言語に該当するか推測します。
これは再びclassifierを使うexampleです。

## とりあえず動かす

### jubatusサーバの起動

例によってjubatusサーバを起動します。language_detectionには2種類のconfigファイルがあります。1つはspace_split.jsonは入力されたテキストをスペースで分割してJubatusに学習させる設定ファイルです。もう一方のnon_split.jsonはスペース分割を行わない設定ファイルです。特徴抽出の設定を入れないと期待した学習ができないことが体験できます。
今回はspace_split.jsonを使って起動します。

```
$ jubaclassifier -f space_split.json
```

### クライアントの実行

はじめに学習用のクライアントスクリプトtrain.pyを実行します。
datディレクトリ内にあるwikipediaのダンプデータを元に、各言語のデータを学習していきます。

```
$ python train.py
...
train ../dat/German : Wikipedia® ist eine eingetragene Marke der Wikimedia Foundation Inc. ...
train ../dat/German : DatenschutzÜber WikipediaImpressumMobile Ansicht ...
finished train of label ../dat/German 
```

このようにテキストを順番に学習していきます。
次に分析用のスクリプトを実行します。実行するとテキストの入力を促されるので、てきとうな文を打ち込みます。

```
$ python 
> This is a pen.
../dat/English -> 0.12816458940505981
../dat/Italian -> 0.09688062220811844
../dat/German -> 0.028819821774959564
../dat/Dutch -> -0.005660968832671642
../dat/French -> -0.19092027842998505
```

このように各言語に対するスコアが出力されます。

# trivial_stat
続いて統計計算を行うjubastatを使うexampleを実行していきます。
フルーツの大きさ、重さ、価格について統計値を求めます。

## とりあえず動かしてみる

### サーバの起動
例によってjubatusサーバを起動していきます。
jubastatサーバの設定ファイルはwindow_sizeだけを指定します。これは統計計算するときに用いるデータの数を指定するパラメータです。

```
$ jubastat -f stat.json
```

### クライアントの実行

クライアントプログラムを実行します。

```
$ python stat.py
sum : orangedia 1503.4
sdv : orangedia 10.868084075829087
max : orangedia 49.9
...
ent : melonpri 2.1964245302595096
mmt : melonpri 475.44642857142856
```

orange, apple, melon,それぞれの大きさ(dia), 重さ(wei), 価格(pri)について合計、標準偏差、最大、最小、エントロピー、モーメントが出力されます。


# trivial_burst

続いて実行するexampleはtivial_burstです。
これはjubatusのバースト検知機能(jubaburst)を使うexampleです。
バースト検知機能によって指定されたキーワード(ここでは"バルス")の急激な盛り上がりを検知します。

## とりあえず動かす

### jubatusサーバの起動

例によって最初にjubatusサーバを起動します。

```
$ jubaburst -f config.json
```

jubaburst の設定ファイルはアルゴリズムのメソッド(現在はKleinbergのバースト検知アルゴリズムのみ)の指定と、そのパラメータを設定するだけです。
パラメータの意味は20日の記事で[@ymhara](http://qiita.com/ymhara) さんが解説しれくれると思います。

### クライアントの実行
続いて、クライアントプログラムを実行していきます。

```
$ python burst_dummy_stream.py
$ python burst_dummy_stream.py
batch{all_data_count: 22262, relevant_data_count: 22222, burst_weight: 8.143779359973479}
batch{all_data_count: 20, relevant_data_count: 10, burst_weight: 0.0}
batch{all_data_count: 30, relevant_data_count: 5, burst_weight: 0.0}
batch{all_data_count: 0, relevant_data_count: 0, burst_weight: 0.0}
batch{all_data_count: 0, relevant_data_count: 0, burst_weight: 0.0}
```

結果の見方が難しいですね。
jubatusのバースト検知はデータをwindow単位に区切って計算します。windowの中は更に一定の間隔でbatchに区切られ、batchごとにburst状態にあるか、そうでないかの計算がされます。
上の実行例では、現在のwindowに含まれるbatchそれぞれの状態が示されています。
`all_data_count` がそのbatchに含まれるデータの数、`relevant_data_count`がbatch内でキーワードを含むデータの数。`burst_weight`はそのbatchが周囲のbatchと比べてどれだけ盛り上がっているかに対応します。
この例ではwindowの中の1番最初のbatchが前後のbatchに比べて大きく盛り上がっている様子が表示されています。


# slot

続いてバンディットアルゴリズムを使ったexample, slotを実行していきます。
このexampleでは`jubabandit`を使って一定回数slotを回したときに得られる報酬を最大化することを目指します。

## とりあえず動かす

### jubatusサーバの起動

まずはjubatusサーバを起動します。jubatus-example/slot/config ディレクトリに沢山あるconfigファイルの中から1つを選んで起動します。

```
$ jubabandit -f config/epsilon.json
```

今回はepsion-greedyアルゴリズムを使うコンフィグを選びました。詳細については12月8日に解説記事を書く予定です。

### クライアントの実行

クライアントプログラムを実行します。
```
$ python slot.py
cumulative reward is 5233.55
slot frequencies are:
[('a', 936), ('c', 36), ('b', 28)]
```

config/slot.confの中にクライアントの設定が書かれています。
`common`セクションの`iteration`キーでスロットを回す回数を設定します。
`slots`セクションでは用意するスロットの設定を書きます。
キー名がスロットの名前、値はカンマ区切りで指定し、順にスロットが当たりを出す確率、報酬の平均値、報酬の標準偏差に対応します。

実行結果はcumulative rewardが報酬の合計値、slot frequenciesにはそれぞれのスロットが何回プレイされたかを表示します。

スロットの設定を変えたり、jubatusサーバの起動に使うコンフィグファイルを変えると様々な結果が得られるようになります。いろいろ試してみてください。


# iris
続いてはirisです。
分類問題でよく使われるデータセット[iris](https://archive.ics.uci.edu/ml/datasets/Iris)を使います。
蕚片の長さと幅、花弁の長さと幅からあやめの品種を当てる分類問題を解いていきます。

## とりあえず動かす

### jubatusサーバの起動

例によってサーバを起動します。

```
$ jubaclassifier -f config.json
```

### クライアントの実行

iris.pyを実行していきます。

```
$ python iris.py 
python iris.py
Traceback (most recent call last):
  File "iris.py", line 74, in <module>
    run()
  File "iris.py", line 68, in run
    train_data, test_data  = split_train_test(dataset, k)
  File "iris.py", line 29, in split_train_test
    train_data = dataset[:len(dataset) / k * (k - 1)]
TypeError: slice indices must be integers or None or have an __index__ method
```

はい。動きません。
これはpython3以降では除算の結果がfloatで返ってくるからです。
実行できるようにするにはiris.pyの29行目、30行目で除算の結果をintにするよう書き換えます。

```python:iris.py
#(修正前)
train_data = dataset[:len(dataset) / k * (k - 1)]
test_data = dataset[len(dataset) / k * (k - 1):]

#(修正後)
train_data = dataset[:int(len(dataset) / k * (k - 1))]
test_data = dataset[int(len(dataset) / k * (k - 1)):]
```

改めてクライアントを実行します。

```
$ python iris.py
NG, answer:Iris-versicolor, estimated:Iris-virginica
NG, answer:Iris-versicolor, estimated:Iris-virginica
OK, answer:Iris-virginica, estimated:Iris-virginica
...
OK, answer:Iris-setosa, estimated:Iris-setosa
------------------
OK: 24
NG: 14
Accuracy: 0.631578947368421
```

実行すると、分類の成否、正しい分類先、jubatusの分類結果が表示されていきます。
最後に正解の数と不正解の数、Accuracyを表示します。



このあたりで、一旦区切ります。
明日も続いてjubatus-exampleの実行の記事です。