【A/Bテスト】比率の差の検定 (proportion z-test) を完全に理解する

# この記事で伝えたいこと

A/BテストにおいてはCTRやCVRのように**比率の差の検定 (proportion z-test)** を行うことが多い。
本記事ではこの検定を**完全に理解する**のを目的とする。

また、似たような検定手法としてよく出てくる**t検定** や**カイニ乗検定** との関連についても触れ、**特定条件下ではすべての検定手法が等しくなる** ことも述べる。

# A/Bテストと評価指標
まずは前提条件を整理しよう。
webサービス等でA/Bテストを行う場合を考えよう。
大体の場合、既存のサービスと何らかの変更を加えたバージョンの比較をする。
変更の種類はさまざまだが、例えばUIの変更や機械学習モデルの変更などである。

今、webサービスに訪れたユーザをランダムに50%ずつ割り当てるとしよう。

ここで既存のバージョンに割り当てられたユーザ群を**コントロール群（Control Group）**、変更を加えたバージョンに割り当てられたユーザ群を**介入群　（Treatment Group）** と呼ぼう。

こういったA/Bテストは別名**コントロール実験**と呼ばれたりする。

この記事のテーマは「**比率**」の検定だ。
例えばCTR (Click Through Rate)やCVR (Conversion Rate)などが挙げられる。
前者であればクリック率、後者は購入などのコンバージョン率である。

今後はCVRを例に取って考えよう。
全体のユーザの数を$N_{total}$、そのうちコンバージョンに至った人数を$N_{cv}$とすれば

```math
CVR = \frac{N_{cv}}{N_{total}}
```

となる。$0<N_{cv}<N_{total}$ だと考えられるのでCVRは０~１の値を取る。
ここからもCVRが**比率**であることがわかるだろう。

今後はこのCVRを例にControl群とTreatment群でCVRの違いがあるか？を考えていくことにしよう。
このような実験によって測定され、評価に用いる値は **評価指標**、あるいは単に **指標 (Metrics)** と呼ばれ、一般にはCTRやCVR以外にも売り上げなど様々な値がA/Bテストの指標として用いることがある。

:::note info
コンバージョン (CV)って何？
CVの定義はサービスによってさまざまだ。
例えばAmazonなどのECサイトであれば購入がCVだし、動画サイトなであれば視聴やチャンネル登録などがCVにあたる。
:::


# 差の検定ってどうやるんだっけ？

さて、まずは任意の評価指標での有意差検定を考えよう。
今回はTreatment Groupの指標の値がControl Groupの値より有意に大きいかどうかを知りたいことする。

もしTreat Groupの方が精度が良ければA/Bテスト後に導入、そうでなければ導入見送り、など今後の意思決定に活かすことができる。

これは言い換えればTreatmentとControlの差が0より大きいかどうかを知りたいということだ。

そこでA/BテストにおけるTreatmentとControlの"平均"の差の検定を考えよう。
なぜ平均の差なのか？
Treatment、Controlの評価指標それぞれは一定の広がりを持った分布であるが、その**期待値に有意な差があるか** が最も知りたい重要な情報だからだ。

Treatment、Controlの分布の平均の従う分布の平均を（$\mu_{t}, \mu_{c} $）、分散をそれぞれ（$\sigma_{Mt}^2, \sigma_{Mc}^2 $）と表すこととする。
(分散については、平均値が従う分布であることを分かりやすくするために$Mt, Mc$と書いた)
すると平均、分散は以下のようになる。

```math
\begin{align}
\mu_{\Delta} &= \mu_t - \mu_c, \\
\sigma_{\Delta}^2&= \sigma_{Mt}^2 + \sigma_{Mc}^2
\end{align}
```


差の分散は一般に上記のように二乗和で表すことができるのに注意。
これは以前別の記事で書いたが、誤差の伝播則などから簡単に導くことができる。

https://qiita.com/tetsuro731/items/fab033c97cf230527bce#%E5%92%8C%E5%B7%AE%E3%81%AE%E5%A0%B4%E5%90%88

元々の分布の分散を$\sigma_t, \sigma_c$とするとこの分散は標準誤差にあたるので

```math
\begin{align}
\sigma_{Mt}&= \frac{\sigma_t}{\sqrt{m}} \\
\sigma_{Mc}&= \frac{\sigma_c}{\sqrt{n}} \\
\end{align}
```
とも書ける。m, nは介入群、コントロール群それぞれの母数 (CVRの場合はユーザー数)である。

# 帰無仮説とp値

$\mu_{\Delta}, \sigma_{\Delta}$の式に戻る。

帰無仮説として
「**ControlとTreatmentの差がない**」
と仮定しよう。つまり、変更しても効果がないと仮定する。
すると、上の式において$\mu=0$ということになる。

ここからp値を計算して仮説検定を行うことができる。


ここでいうp値とは、$\mu=0$とした時に、とりうる確率が全体の何%以内に入っているかということだ。

例えばp値が0.05より小さければ、

「**帰無仮説が正しければ、こんなレアな事象が起きる確率は5%以下だよ**」

ということになる。
つまり、「帰無仮説は正しくなさそうだね」となり棄却され、介入効果があったと結論付けることができる。
逆にp値が大きければこの介入によって効果があったとは言えないということだ。
このあたりは統計で一般によく使われる検定手法だ。

ちなみにp値が0.05よりも大きければ95%の区間内に値が収まっていることになり、これを95%の**信頼区間**と言ったりする。

後々のために

$\mu_{\Delta} = \mu_t - \mu_c$ の値の分布を標準偏差で割った$(\mu_{t} - \mu_c)/\sqrt{\sigma_{Mt}^2 + \sigma_{Mc}^2}$という統計量を考えておこう。
この値は帰無仮説のもとでは
「**平均が0、分散が1**」の分布となる。

もし元の分布が正規分布（=ガウス分布）に従っていれば**標準正規分布**と呼ばれる形になる。
この統計量をZとおけば

```math
\begin{align}
Z &= \frac{\mu_{t} - \mu_c}{\sqrt{\sigma_{Mt}^2 + \sigma_{Mc}^2}} \\
&= \frac{\mu_{t} - \mu_c}{\sqrt{\frac{1}{m}\sigma_{t}^2 + \frac{1}{n}\sigma_{c}^2}} \\
&= \frac{\mu_{t} - \mu_c}{\sqrt{(\frac{1}{m}+\frac{1}{n})\sigma^2}}
\end{align}
```

と書くことができる。
なお、最後の変形では両グループにおいて分散が等しいという仮定を置いた。
（$\sigma_t=\sigma_c=\sigma$）

標準正規分布に従う量を作ることができれば、そこからp値を求めることができる。
この形は後々何回か出てくるので覚えておこう。



# 比率の差の検定を考えよう

さて、ここまで任意の評価指標についての差の検定を考えてきたので、そろそろ比率の検定を考えよう。
なお、ここでは十分にサンプルサイズがあると仮定する。

CVRの場合、ユーザごとに一定の確率p (=CVR)でコンバージョンがある二項分布であると考えることができる。
ここではそれぞれのユーザは独立であると仮定しよう。

このとき確率pの平均と分散はそれぞれ以下のようになる。

```math
\begin{align}
\mu&= p \\
\sigma^2&= p(1-p) \\
\end{align}
```

これを先ほどのZに代入してみよう。


```math
\begin{align}
Z &= \frac{\mu_{t} - \mu_c}{\sqrt{\sigma^2(\frac{1}{m}+\frac{1}{n})}} \\
&= \frac{p_{t} - p_c}{\sqrt{p(1-p)(\frac{1}{m} + \frac{1}{n}})}
\end{align}
```

1行目から2行目でいくつかの仮定をおいたので順に説明する。
まず、$p_t, p_c$はtreatment、controlそれぞれのCVRの実測値を表す。
また、ここでは両グループにおいて分散が等しいと仮定をおいているので、$\sigma^2 = p(1-p)$と置いている。
真の分散は知ることができないのでこの分散は実測値から$(Ncv_t + Ncv_c)/(m+n)$ のように両グループのデータを使って見積もる。

これが比率の差の検定で使う式である。
このZが標準正規分布に従うため、ここからp値を計算可能だ。

# このZは本当に標準正規分布なの？

...という疑問が湧くかもしれない。

まず、もともとの分布は2項分布であるが、今回は両グループの平均値が従う分布を考えている。
従って、**中心極限定理**からそれぞれの分布は正規分布に従い、差の分布も正規分布に従う。

また、厳密に言えば真のpの値はわかっておらず、あくまで推測値を用いていることも気になるかもしれないが、これもサンプルサイズが大きければほぼ正規分布とみなすことができる。

# t検定との関係は？

もしサンプルサイズが小さい場合は標準正規分布には従わず、t分布と呼ばれる分布に従う。
このt分布を用いた検定方法を**t検定**といい、この場合にもp値を求めることが可能だ。
ここで使うt統計量は以下のようになる。

```math
\begin{align}
T &= \frac{\mu_{t} - \mu_c}{\sqrt{(\frac{1}{m}+\frac{1}{n})S^2}}
\end{align}
```

これまでの議論で出てきた
```math
\begin{align}
Z &= \frac{\mu_{t} - \mu_c}{\sqrt{(\frac{1}{m}+\frac{1}{n})\sigma^2}}
\end{align}
```
と非常によく似た形をしている。
$\sigma$が真の分散を表しているのに対して$S$が不偏分散、つまり、測定値から求めた分散を表している違いだけだ。

もしt検定において十分なサンプルサイズがあればZと同じになる。
さらに言えば**比率の検定を行えば比率の差の検定の式とまったく同じになる**。

極端な話、比率の差の検定をt検定で条件を揃えて行うことも可能だ。

なお、この記事と被る部分も多いが、t検定については過去に以下の記事でもまとめたので興味があれば参考にしてほしい。

https://qiita.com/tetsuro731/items/1953296864af91dd2366

# カイニ乗検定との関係は？

今まで出てきたZ、Tを使った検定はそれぞれ標準正規分布、t分布を用いた検定だったが、カイニ乗検定はその名の通りカイニ乗分布を用いた検定だ。

カイニ乗統計量は

```math 
\chi^2=\Sigma\frac{(O_i - E_i)^2}{E_i}
```
と書くことができ、O、Eはそれぞれ
- O: 観測された頻度（観測値）
- E: 期待された頻度（理論値）

となる。この検定はクロス集計表のカテゴリデータについて行うことが多い。

というのも、カイ二乗分布は標準正規分布の二乗和で定義されるため、各カテゴリの値が理論値から正規分布でばらついていると仮定すれば、カイニ乗分布を利用してp値を求めることができるということだ。

そして2*2のクロス集計表の場合、実はZを用いた比率の差の検定と同じ形になる。
言い換えれば比率の差の検定はカイ二乗検定の特殊な場合と言える。

この説明だけだと分かりづらいと思うので、具体例で見てみよう。
Treatment, Controlそれぞれ10,000ユーザが母数で、前者は2000人、後者は2500人がコンバージョンに至ったとする。
その場合、以下のようなクロス集計表を作ることができる。

| Group | No Conversion | Conversion |Sum |
|:-----------|------------:|:------------:|:------------: |
| Control       | 8,000        | 2,000         |10,000|
| Treatment     | 7,500      | 2,500      |10,000|
| Sum     | 15,500      | 4,500       |20,000|

Sumの行と列を除いて考えればこの表は2×2である。
そして、カイ二乗検定量の自由度は一般に

```math 
(行の数-1)(列の数-1)
```
で表すことができる。
これは以下のようにイメージすれば良い。

Sumを固定した状態で1行だけを残して残りの行の値が確定したとしよう。
その場合残る1行の値は自動的に決まる。
行と列についてまったく同じことが言える。
従って、上の式が成り立つ。

今回のように2*2の場合は自由度1のカイ二乗分布。
**これは結局標準正規分布のことだ**。

次にカイニ乗検定の具体的な計算を見ていこう。
帰無仮説においてはControlとTreatmentで差がないと考える。

そこで、No ConverionとConversionについて期待度数を計算しよう。
単にNo Conversion, Conversionそれぞれ
$(8,000+7,500)/2 = 7,750$
$(２,000+2,500)/2 = 2,250$
と平均を求めれば良い。
あとはカイ二乗検定の式に当てはめて

```math 
\begin{align}

\chi^2&=\Sigma\frac{(O_i - E_i)^2}{E_i}\\
&=\frac{(8000-7750)^2+(7500-7750)^2}{7750} + \frac{(2000-2250)^2+(2500-2250)^2}{2250}
\end{align}
```
となる。
形こそ違うものの結局標準正規分布Zを用いた検定になる。
*詳細な計算は最後に追記

# Pythonでの検定方法

最後に、Pythonにおけるそれぞれのサンプルコードを載せておこう。
t検定とカイニ乗検定については`scipy.stats`のライブラリが使える。
z検定においては以下の`statsmodesl.stats`のライブラリが使える。

https://www.statsmodels.org/stable/generated/statsmodels.stats.proportion.proportions_ztest.html

どれも比率の差の検定でも使えるが、
- z検定: 施行回数と成功数を指定
- t検定: 正規分布に従う変数を指定
- カイニ乗検定: クロステーブルの値を指定

のようにinputの形式が微妙に違うのに気をつけよう。


## 比率のz検定（Proportion Z-Test）のサンプルコード

```python
from statsmodels.stats.proportion import proportions_ztest

# 成功数と試行回数
count = np.array([75, 30])  # 2つのグループでの成功数
nobs = np.array([100, 100])  # 2つのグループの試行回数

# 比率のz検定を実行
stat, pval = proportions_ztest(count, nobs)

print(f'Z統計量: {stat:.2f}, p値: {pval:.3f}')

```

## t検定 (T-Test)のサンプルコード

```python
from scipy import stats
import numpy as np

# 2つのサンプルデータセット
sample1 = np.random.normal(loc=50, scale=10, size=100)
sample2 = np.random.normal(loc=55, scale=10, size=100)

# 独立した2標本に対するt検定を実行
t_stat, p_val = stats.ttest_ind(sample1, sample2)

print(f't統計量: {t_stat:.2f}, p値: {p_val:.3f}')

```
## χニ乗検定 (Chi-Square Test)のサンプルコード

```python
from scipy.stats import chi2_contingency

# 2x2のクロステーブル
data = [[30, 10],  # 第一グループの成功数と失敗数
        [20, 40]]  # 第二グループの成功数と失敗数

# カイ二乗独立性検定を実行
chi2, p, dof, expected = chi2_contingency(data)

print(f'カイ二乗統計量: {chi2:.2f}, p値: {p:.3f}, 自由度: {dof}, 期待値: {expected}')

```

# まとめ

- 比率の差の検定は標準正規分布を仮定して行うことができる (proportion z-test)
- t検定、カイニ乗検定でも条件を揃えば使えるが、特に理由がなければ↑を使うのが無難だと思う
- 各検定はPython等のライブラリを用いて簡単に行うことができる