- ブラウザURL入力
- DNS名前→IP
- ルータ経路選択
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理今ここ
- DB保存
性能の数字を週ごとに見て、悪かったものに手を入れる。運用でよくある流れです。今回は、その「直したら良くなった」から対策の効果だけを取り出す方法を見ます。
まず結論
先週いちばん遅かったものは、何もしなくても今週は速く見えることが多い。測った値は「本当の遅さ」と「その週の揺れ」の和で、最悪を選ぶと上に揺れたものも一緒に選ぶからです。
だから「最悪を直したら良くなった」は、前後の比較だけでは効果の証拠になりません。同じ基準で選んだものを無作為に分け、手を入れない対照群と比べて初めて、対策の分が取り出せます。
200本のエンドポイントの p95 を毎週測る模型で、1週目に最も遅かった10本の平均は約273ミリ秒でした(全体の平均は約200ミリ秒)。2週目、何も変えずにこの10本を測り直すと、平均はおおよそどうなるでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
測った値は、本当の遅さとその週の揺れの和
模型の設定はこうです。200本のエンドポイントそれぞれに本当の p95 があり、平均200・標準偏差20ミリ秒でばらつきます。週ごとの測定には、さらに標準偏差30ミリ秒の揺れが乗ります。2週目の揺れは1週目と無関係に引き直し、対策は何もしません。
1週目に最も遅かった10本は、2種類のものから選ばれます。本当に遅いものと、その週たまたま上に揺れたものです。2週目、本当の遅さは残り、揺れは引き直されます。だから途中まで戻ります。
どこまで戻るかは、揺れと本当の差の大きさの比で決まります。この模型では揺れ(30)のほうが本当の差(20)より大きいので、選んだときの隔たりの多くは揺れです。設定から計算すると、全体の平均からの隔たりのうち2週目に残るのは約3割(0.308、コードの最終行)。実際に回すと、73.3 ミリ秒の隔たりのうち 22.1 が残りました。
- ・全200本の2週目の平均は 199.9 で動かない。戻るのは値で選んだ部分だけ
- ・200 まで戻りきらないのは、この10本が本当に平均より遅めだから
模型を2000回回す
標準ライブラリだけの模型です。引数 EFFECT は後で使う「対策が本当に縮めるミリ秒」で、まずは 0(何もしない)で回します。
import random, statistics as st, sys
EFFECT = float(sys.argv[1]) if len(sys.argv) > 1 else 0.0 # ms the fix really removes
SEED = 1
TRUE_SD, NOISE_SD = 20, 30
rng = random.Random(SEED)
R = 2000
w1_worst, w2_worst, w1_best, w2_best, w2_all = [], [], [], [], []
drop, t_minus_c = [], []
for _ in range(R):
true = [rng.gauss(200, TRUE_SD) for _ in range(200)] # real p95 of 200 endpoints (ms)
w1 = [t + rng.gauss(0, NOISE_SD) for t in true] # week 1 measurement
w2 = [t + rng.gauss(0, NOISE_SD) for t in true] # week 2 measurement
ranked = sorted(range(200), key=lambda i: -w1[i])
worst10 = ranked[:10]
w1_worst.append(st.mean(w1[i] for i in worst10))
w2_worst.append(st.mean(w2[i] for i in worst10))
w1_best.append(st.mean(w1[i] for i in ranked[-10:]))
w2_best.append(st.mean(w2[i] for i in ranked[-10:]))
w2_all.append(st.mean(w2))
worst20 = ranked[:20]
rng.shuffle(worst20)
fixed, control = worst20[:10], worst20[10:]
for i in fixed:
w2[i] -= EFFECT
drop.append(st.mean(w1[i] - w2[i] for i in fixed))
t_minus_c.append(st.mean(w2[i] for i in fixed) - st.mean(w2[i] for i in control))
def show(name, v):
s = sorted(v)
print(f"{name:<22} median {st.median(s):6.1f} 95% of runs [{s[int(R*.025)]:6.1f}, {s[int(R*.975)]:6.1f}]")
print(f"EFFECT={EFFECT} runs={R} seed={SEED}")
show("worst10 week1", w1_worst)
show("worst10 week2", w2_worst)
show("best10 week1", w1_best)
show("best10 week2", w2_best)
show("all 200 week2", w2_all)
show("fixed: week1-week2", drop)
show("week2 fixed-control", t_minus_c)
share = TRUE_SD**2 / (TRUE_SD**2 + NOISE_SD**2)
print(f"share kept = {TRUE_SD}^2 / ({TRUE_SD}^2 + {NOISE_SD}^2) = {share:.3f}")
EFFECT=0.0 runs=2000 seed=1worst10 week1 median 273.3 95% of runs [ 261.6, 285.6]worst10 week2 median 222.1 95% of runs [ 200.7, 243.6]best10 week1 median 126.5 95% of runs [ 113.1, 137.8]best10 week2 median 177.0 95% of runs [ 156.6, 199.1]all 200 week2 median 199.9 95% of runs [ 194.9, 205.0]fixed: week1-week2 median 43.5 95% of runs [ 21.2, 67.0]week2 fixed-control median 0.1 95% of runs [ -30.0, 31.2]share kept = 20^2 / (20^2 + 30^2) = 0.308
worst10 の2行が本題です。何もしていないのに、中央値で約51ミリ秒速くなりました。2000回のうち中央の95%で見ても、2週目は 243.6 を超えません。
all 200 week2 は 199.9。全体は戻りません。 戻るのは、1週目の値で選んだ部分だけです。向きは逆でも同じで、最速10本は 126.5 → 177.0 と遅いほうへ戻ります。
模型で、1週目の最遅10本が2週目に速く見えた理由として、模型の設定から言えるのはどれですか。
戻るのは、値で選んだときだけ
この現象は「平均への回帰」と呼ばれます。Barnett らの論文の抄録はこう説明します(本文は確認できておらず、以下は抄録からです)。
Regression to the mean (RTM) is a statistical phenomenon that can make natural variation in repeated data look like real change.
目立つ条件も抄録にあります。with increasing measurement error and when follow-up measurements are only examined on a sub-sample selected using a baseline value。揺れが大きいことと、最初の値で選んだ一部だけを追うこと。模型の2つの観察(隔たりの約7割が消えた・全体は動かない)がそのまま対応します。
では、最悪の10本に本当に対策を入れたら、効果はどう取り出すのか。同じ基準で選んだものを無作為に2つに分け、片方にだけ手を入れます。戻りは両方に同じように起きるので、2週目に2群を比べれば戻りは打ち消されます。人が「直せそうなもの」を選んで分けると、群の違いに対策以外のものが混ざります。
Galton が親子の身長で書いたこと
戻りを数字で書いた古い原典が Galton 1886 です。遺伝の研究で、種子の大きさと人の身長を調べました。親の側の値(原文の mid-parentage)からの隔たりと、子の隔たりの関係を、p.252 でこう書いています。
By the use of this word and that of “mid-parentage” we can define the law of regression very briefly. It is that the height-deviate of the offspring is, on the average, two-thirds of the height-deviate of its mid-parentage.
親の隔たりのうち、子に平均して残るのは3分の2。模型の「2週目に残るのは約3割」と同じ形の関係です(対応づけは本教材の整理です)。Galton はこれを遺伝の法則として書き、両側に同じく働くことも明記しています(p.253)。
The law is even-handed; it levies the same heavy succession-tax on the transmission of badness as well as of goodness.
模型の最速10本が遅いほうへ戻ったのと同じ向きの対称性です。なお Galton の語は regression towards mediocrity で、「平均への回帰」は後の用語です。Galton が統計の錯覚を見つけた、という言い方は原典に無い解釈を足すことになります。
最遅20本を無作為に10本ずつ分け、片方にだけ対策を入れました。対策の効果として読むべき数字はどれですか。
効かない対策(EFFECT=0)
最遅20本を無作為に分け、片方に何もしない対策を入れました。対策群の前後差は中央値43.5ミリ秒の改善に見えますが、2週目の対照群との差は0.1で、効果は無いと読めます。
fixed: week1-week2 median 43.5 95% of runs [ 21.2, 67.0]week2 fixed-control median 0.1 95% of runs [ -30.0, 31.2]share kept = 20^2 / (20^2 + 30^2) = 0.308
本当に30ミリ秒縮める対策(EFFECT=30)
同じ模型で、対策群の2週目を本当に30ミリ秒縮めました。前後差は73.5で、そのうち約44は回帰の分です。対照群との差は−29.9で、入れた効果とほぼ一致します。
fixed: week1-week2 median 73.5 95% of runs [ 51.2, 97.0]week2 fixed-control median -29.9 95% of runs [ -60.0, 1.2]share kept = 20^2 / (20^2 + 30^2) = 0.308
前後差は 43.5 と 73.5 で、どちらも改善に見えます。効かない対策と効く対策を見分けているのは、どの数字でしょうか。
何もしない対策でも前後差が出る理由を思い出し、その分を消す比べ方を探してください。
この章のまとめ
- 測った値は本当の値+その回の揺れ。最悪で選ぶと、上に揺れたものも選ぶ。
- 何もしなくても、選んだ部分は平均の側へ途中まで戻る。模型では 273.3 → 222.1(seed=1、2000回の中央値)。
- 戻りは揺れが大きいほど、最初の値で選んだ一部を追うほど目立つ(Barnett らの抄録)。全体の平均は戻らない。
- Galton 1886 は親子の身長で、隔たりが平均して3分の2に縮む法則を書き、高い側にも低い側にも働くと明記した。
- 効果は前後差ではなく、無作為に分けた対照群との差で読む。何もしない対策でも前後差は 43.5 出た。
- 「改善はすべて回帰」も誤り。効く対策の分は対照群との差として残る。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
Barnett らの抄録は、平均への回帰がより目立つ条件として何を挙げていますか。
用語集(3語)
- 平均への回帰
- 極端な値で選んだものを測り直すと、平均の側へ戻って見える現象。測定値に偶然の揺れが含まれるときに起きる。Galton 1886 の語は regression towards mediocrity。
- 対照群
- 対策を入れる群と同じ基準で選び、手を入れずに置いておく群。戻りは両群に同じように起きるので、差を取ると対策の分だけが残る。
- 無作為な割り付け
- どれを対策群にするかを乱数で決めること。人が選ぶと「直せそうなもの」に偏り、群の差に対策以外の違いが混ざる。
出典(一次ソース)
- Galton, F. (1886) Regression towards Mediocrity in Hereditary Stature. The Journal of the Anthropological Institute of Great Britain and Ireland 15:246–263 ↗
- Barnett, A. G., van der Pols, J. C., Dobson, A. J. (2005) Regression to the mean: what it is and how to deal with it. International Journal of Epidemiology 34(1):215–220(オンライン先行 2004。本教材は抄録のみ参照) ↗
- Kohavi, R. et al. (2012) Trustworthy Online Controlled Experiments: Five Puzzling Outcomes Explained. KDD 2012, pp.786–794 ↗