SplunkでA/Bテストの統計的仮説検定

# はじめに

Splunkではマシンデータをはじめとして様々な業務データもお手軽に取得、分析できます。

データの分析方法の一つとして[A/Bテスト](https://ja.wikipedia.org/wiki/A/B%E3%83%86%E3%82%B9%E3%83%88)など何かしらの操作を行った結果でデータの値に差異があるかどうか確かめることができます。
例）アプリの改修によりWebページ表示速度は向上したか、コンバージョンレートは上がったかとか

もしSplunkのダッシュボードなんかで、ポチポチと比較対象のデータセット選ぶだけで前処理から分析まで全部やってくれたらすっごく便利ですよね。

差異があるかどうか（誤差ではないか）を確かめる方法として[統計的仮説検定](https://ja.wikipedia.org/wiki/%E4%BB%AE%E8%AA%AC%E6%A4%9C%E5%AE%9A)という分野があります。
本記事ではSplunkではどのような検定が可能か、また、検定を行う手順をご紹介したいと思います。

# 環境

- Splunk
- MLTK（Machine Learning Tool Kit）

MTLKに検定用SPLが揃っています。すばらしい！
※ちなみに中身は[SciPy](https://docs.scipy.org/doc/scipy/reference/index.html)を使用してます。

もしご自身のSplunkにインストールされていない場合はさくっとインストールお願いします。
[Splunk Machine Learning Toolkit](https://splunkbase.splunk.com/app/2890/)

Python for Scientific Computingも必要です。
MLTKではちょくちょく使いますのでこちらもインストールしておきましょう。
[Python for Scientific Computing (for Mac)](https://splunkbase.splunk.com/app/2881/)
[Python for Scientific Computing (for Linux 64-bit)](https://splunkbase.splunk.com/app/2882/)
[Python for Scientific Computing (for Windows 64-bit)](https://splunkbase.splunk.com/app/2883/)


# 利用可能な検定

[こちら](https://docs.splunk.com/Documentation/MLApp/latest/User/ScoreCommand#Statistical_testing_.28statstest.29)にMLTKで利用可能な検定一覧が載っています。

本記事作成時点の最新版のMTLK v5.2.1では以下が使えます。
なお、本記事ではそれぞれの詳細には立ち入りません。
詳しく知りたい方はwikipediaや解説ページなどLinkをつけておりますのでご参照くださいませ。

- Analysis of Variance (Anova)：[分散分析](https://ja.wikipedia.org/wiki/%E5%88%86%E6%95%A3%E5%88%86%E6%9E%90)
- Augmented Dickney-Fuller (Adfuller)：[拡張ディッキー–フラー検定](https://ja.wikipedia.org/wiki/%E6%8B%A1%E5%BC%B5%E3%83%87%E3%82%A3%E3%83%83%E3%82%AD%E3%83%BC%E2%80%93%E3%83%95%E3%83%A9%E3%83%BC%E6%A4%9C%E5%AE%9A)
- Energy distance：[エネルギー距離（英語版wiki）](https://en.wikipedia.org/wiki/Energy_distance)
- Kolmogorov-Smirnov (KS) test (1 sample)：[1標本KS（コルモゴロフ–スミルノフ）検定](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%AB%E3%83%A2%E3%82%B4%E3%83%AD%E3%83%95%E2%80%93%E3%82%B9%E3%83%9F%E3%83%AB%E3%83%8E%E3%83%95%E6%A4%9C%E5%AE%9A)
- Kolmogorov-Smirnov (KS) test (2 samples)：[2標本KS（コルモゴロフ–スミルノフ）検定](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%AB%E3%83%A2%E3%82%B4%E3%83%AD%E3%83%95%E2%80%93%E3%82%B9%E3%83%9F%E3%83%AB%E3%83%8E%E3%83%95%E6%A4%9C%E5%AE%9A)
- Kwiatkowski-Phillips-Schmidt-Shin (KPSS)：[KPSS検定（英語版wiki）](https://en.wikipedia.org/wiki/KPSS_test)
- Mannwhitneyu：[マン・ホイットニーのU検定](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%B3%E3%83%BB%E3%83%9B%E3%82%A4%E3%83%83%E3%83%88%E3%83%8B%E3%83%BC%E3%81%AEU%E6%A4%9C%E5%AE%9A)
- Normal test：[正規性の検定](https://bellcurve.jp/statistics/glossary/2066.html)
- One-way ANOVA：[一元配置分散分析](https://ja.wikipedia.org/wiki/%E4%B8%80%E5%85%83%E9%85%8D%E7%BD%AE%E5%88%86%E6%95%A3%E5%88%86%E6%9E%90)
- T-test (1 sample)：[1標本t検定](https://ja.wikipedia.org/wiki/T%E6%A4%9C%E5%AE%9A)
- T-test (2 independent samples)：[対応のない2標本t検定](https://ja.wikipedia.org/wiki/T%E6%A4%9C%E5%AE%9A)
- T-test (2 related samples)：[対応のある2標本t検定](https://ja.wikipedia.org/wiki/T%E6%A4%9C%E5%AE%9A)
- Wasserstein distance：[ワッサースタイン計量](https://ja.wikipedia.org/wiki/%E3%83%AF%E3%83%83%E3%82%B5%E3%83%BC%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%B3%E8%A8%88%E9%87%8F)
- Wilcoxon：[ウィルコクソンの符号順位検定](https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A3%E3%83%AB%E3%82%B3%E3%82%AF%E3%82%BD%E3%83%B3%E3%81%AE%E7%AC%A6%E5%8F%B7%E9%A0%86%E4%BD%8D%E6%A4%9C%E5%AE%9A)

# マン・ホイットニーのU検定を試してみる

この中から、使用用途が広くて、私が大好きなマン・ホイットニーのU検定を実際に試してみたいと思います。

U検定は独立した2標本の間に有意差があるかどうかを確かめるための検定です。
母集団が正規分布でなかったり異常値があっても有効な[ノンパラメトリック検定](http://lbm.ab.a.u-tokyo.ac.jp/~omori/kensyu/nonpara.htm)の一つです。
（ただし検定力を犠牲にしているので、正規分布であればt検定などパラメトリック検定の方が正確。正規分布かどうかの確認は検定の中の[Normal test](https://docs.splunk.com/Documentation/MLApp/latest/User/Scorecommand#Normal-test)で行えます）

冒頭の例のように「アプリの改修によりWebページ表示速度が向上したか」みたいな場合、これを使えば「ほんとにー？誤差じゃないのぉ？」という輩に対して「統計的に有意に向上してます（ｷﾘｯ」と言えるすごいやつです。


## U検定用のSPL

SPLの解説は[こちら](https://docs.splunk.com/Documentation/MLApp/latest/User/Scorecommand#MannWhitneyU)です。

```go:SPL
|score mannwhitneyu <a_field> against <b_field> use_continuity=<true|false> alternative=<less|two-sided|greater> alpha=<int>
```

こんだけ！

`a_field`、`b_field`は検定対象の値を含むフィールドで、各サンプルは20以上が必要です。


パラメータの説明です。
**use_continuity**：連続性補正を行うか。デフォルトtrue。　※コイン投げの裏表など離散値でも連続値として近似する方法。
**alternative**：片側検定（less：AはBより小さい or greater：AはBより大きい）か、両側検定（two-sided：大小のどちらか）。デフォルトtwo-sided。　※事前に大小の前提を置くのは、よほどの理由がないといけない（改修で悪化もあり得るし）ので、デフォルト通り両側検定を使うべき。
**alpha**：有意水準。デフォルト0.05（5%）。

## 試してみます

標本Aを800～1000、標本Bを850～1050の間でランダムに値を生成し試してみます。
※範囲指定のrandomは[こちら](https://community.splunk.com/t5/Archive/How-do-I-generate-a-random-number-between-a-specific-range/m-p/378229)のSplunk Answersを参考にさせてもらいました

```go:SPL
| makeresults count=100
``` 標本Aをランダムで作成 ```
| eval sample_a_high = 1000
| eval sample_a_low = 800
| eval sample_a = round(((random() % sample_a_high)/(sample_a_high)) * (sample_a_high - sample_a_low) + sample_a_low)
``` 標本Bをランダムで作成 ```
| eval sample_b_high = 1050
| eval sample_b_low = 850
| eval sample_b = round(((random() % sample_b_high)/(sample_b_high)) * (sample_b_high - sample_b_low) + sample_b_low)
``` 標本A、BをU検定で両側検定。 ```
| score mannwhitneyu sample_a against sample_b
```

結果は以下の通りです。

```go:SPL結果（有意差あり）
statistic, p-value, Test decision (alpha=0.05)
2637.0, 7.799973305062498e-09, Reject the null hypothesis that it is equally likely that a randomly selected value from the first sample will be less than or greater than a randomly selected value from the second sample
```

p値が有意水準である0.05をはるかに下回って（7.799973305062498e-09）、null hypothesis（帰無仮説=標本A、Bは同じだよという仮説）は棄却、つまり「差が無いとは言えないよ」 という結果が出ました。

ちなみに差が無い場合は以下の結果になります。

```go:SPL結果（有意差なし）
statistic, p-value, Test decision (alpha=0.05)
5328.5, 0.4228595890372442, Fail to reject the null hypothesis that it is equally likely that a randomly selected value from the first sample will be less than or greater than a randomly selected value from the second sample
```

p値が0.05以上なので、帰無仮説の棄却に失敗、つまり「差が無いという仮説を採択したよ」という結果です。

注意点として、これは大小の有意差にしか言及しておらず、どれだけ違うの？という点については何も言ってくれないので、そこはstatsで値を確かめる必要があります。

#まとめ

- SplunkのMLTKでお手軽に統計的仮設検定を試してみました。
- 検定手法は主なものは用意されていますので、今回は2標本のU検定でしたが、例えば分散分析を使って3標本のデータを検定するなど様々なパターンにも対応できます。
- Splunkの使用範囲が広がりますね！