Splunkで統計を勉強する（度数分布表histogram）

@7GHz さんの[記事](https://qiita.com/7GHz/items/abac19ef5d22bc391691)でグラフがかけることがわかったので、自分もSplunkを間違った方向に使っていきたいと思う。

#はじめに
やはり巷ではビッグデータやらＡＩやら機械学習が流行っているのになんとか乗っていきたい。
でも、統計の基本がないので少しずつ勉強していきたいと思う。

統計といえば、ということで代表値を求めて、度数分布表を書いてみようと思う。

[Splunk Machine Learning Toolkit](https://splunkbase.splunk.com/app/2890/)が必要です。
#サンプルデータ
```Splunk:SPL
| makeresults count=1000
| eval value=random() % 100 + 1
| table value
```

| value |
|--:|
| 37 |
| 43 |
| 93 |
| ... |
とりあえずは１０００個の１〜１００までの数を作った。
#代表値
**R**でいうところの`summary()`
基本的には[ここらへん](https://docs.splunk.com/Documentation/Splunk/8.0.1/Search/Aboutcalculatingstatistics)（About calculating statistics）のコマンドを使っていくことになる

```Splunk:SPL
| stats
| transpose 0
```

| column | row 1 | description |
|:--|--:|:--|
| count(value) | 1000 | フィールドXの出現回数
| distinct_count(value) | 100 |フィールドXの個別の値のカウント
| max(value) | 100 |フィールドXの最大値
| mean(value) | 49.784 |フィールドXの算術平均
| median(value) | 50 |フィールドXの中央値
| min(value) | 1 |フィールドXの最小値。
| mode(value) | 45 |フィールドXの最頻値
| stdev(value) | 28.3523755830301 |フィールドXの標本標準偏差 *1
| sum(value) | 49784 |フィールドXの合計
| sumsq(value) | 3281500 |フィールドXの値の2乗の合計
| var(value) | 803.8572012012013 |フィールドXの不偏分散
*1　[不偏分散の正の平方根](https://bellcurve.jp/statistics/glossary/1168.html)

なにも引数をいれない`stats`だとこういった結果がでる。
今回調べてみたら、基本的な値は出てますね。

Rの`summary()`だと`Min. 1st Qu.  Median    Mean 3rd Qu.    Max. `なのであと少し足りない。

```Splunk:SPL
| eventstats
| eventstats exactperc25(value) as "Q1(value)" exactperc75(value) as "Q3(value)"
| head 1
| transpose 0
```

| column | row 1 |
|:--|--:|
| Q1(value) | 26 |
| Q3(value) | 76 |
| count(value) | 1000 |
| distinct_count(value) | 100 |
| max(value) | 100 |
| mean(value) | 51.353 |
| median(value) | 52 |
| min(value) | 1 |
| mode(value) | 88 |
| stdev(value) | 28.68493012395561 |
| sum(value) | 51353 |
| sumsq(value) | 3459133 |
| var(value) | 822.8252162162161 |

`stats`だと元のデータが変更されるため、`eventstats`で集計した。
Splunkのフィールド名は数字から始まるのは奨励されていないので、一応変えてみたのと、あと余計な行は消してます。

これで代表値が出揃った。

##MLTK
ここまで書いてきて、衝撃の事実。
[MLTK](https://docs.splunk.com/Documentation/MLApp)で一発でだせるという
Appを「サーチ」から「Splunk® Machine Learning Toolkit」変更して

```Splunk:SPL
| makeresults count=1000
| eval value=random() % 100 + 1
| table value
| `boxplot`
```
| calculations | value |
|:--|--:|
| exactperc25 | 29 |
| exactperc75 | 78 |
| max | 100 |
| median | 53 |
| min | 1 |

```Splunk:`boxplot`
| makeresults count=1000 
| eval value=((random() % 100) + 1) 
| ifields + value 
| untable _x field_name value 
| stats min exactperc25 median exactperc75 max by field_name 
| untable field_name calculations value 
| xyseries calculations field_name value 
| eval calculations=rtrim(calculations,"(value)")
```
⌘＋⇧＋e（🍎）で先ほどのクエリーを展開してみたもの。
なるほど、参考になります。`transpose`で楽しちゃいけませんね
#histogram
[MLTK Custom Visualizations](https://docs.splunk.com/Documentation/MLApp/latest/User/Customvisualizations)にやり方が書いているのでまずはそこからやってみる。

Appを「サーチ」から「Splunk® Machine Learning Toolkit」変更して

```
| bin value bins=10
```
結果がでない...。数を自動的には数えてもらえないらしい。
あとは1〜100までの数だけど、`bin`だと0〜10でまとめてしまい、100~110の欄ができてしまう。
それはダメだろう。（そんなもんなんでしょうか？）

##つくりました。
```Splunk:SPL
| makeresults count=1000
| eval value=random() % 100 + 1
| table value
| stats count by value
| sort value
| streamstats current=f count(eval(value%10==0)) as session
| eventstats min(value) as start max(value) as end by session
| eval bins=start."-".end
| stats sum(count) as count by bins
| table bins count
```
![qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/80e7382a-67a4-79b8-f6f1-7eb52a5134e0.png)
##解説

 1. 1〜10をひとかたまりにするために`streamstats`で10ずつ数えた。
   - `streamstats`を使うので、`sort`して、`current=f`と`value%10==0`で10ずつになる。
 2. いちいち_bin_を作るのが大変なので`eventstats`で先ほどの塊ごと、最小値と最大値で_bin_を作った。
 3. それを`stats`でまとめて不要なフィールドを削除
 4. Histogram Chartで表示

##度数分布表
ここまで書いていて衝撃の事実。
度数分布表って**以上〜未満**で書くのね。
テストの点とかだと百点って最後に含めると・・・・。そいつはいけない。

```Splunk:SPL
| makeresults count=1000
| eval value=random() % 100 + 1
| eval value=if(value=100,99,value)
| chart count(value) as count by value span=10
```
`bin`でいいかとも思ったが、せっかくなので`chart`を使ってみる。
せこく、100の項を99に変更して集計している。
これできれいに出来た。

一応`bin`バージョンも

```Splunk:SPL
| makeresults count=1000 
| eval value=((random() % 100) + 1) 
| bin value
| eval value=if(value="100-110","90-100",value)
| stats count by value
```

#まとめ
MLTKがあると、統計値関連はだいたいなんとかなりそうな気がしてる。
度数分布表が出来たので、次も頑張りたいと思う。

:sweat:統計をきちんとやっていないからこうなんだな。