メトリクス設計 ― 北極星・ガードレール・代理指標
本記事では、実験で何を成功と判定するかを先に決める設計を扱います。北極星指標・ガードレール指標・効果が出るまで遅い指標の代理・指標の感度といった論点を整理し、「指標を後から選んで有利な結果を拾う」事故を防ぎます。
by Shin
実験の「成功」は、何で判定すればいいのか。結論から言えば、北極星指標とガードレール指標を走らせる前に固定します。後から指標を選べば、ノイズの中でたまたま都合よく動いたものを「効果」と読んでしまうからです。この記事では、何を北極星に据えるか、何をガードレールで見張るか、効果が出るまで遅い指標をどう代理するか、そして指標の感度がそのまま必要サンプル数になることを、架空のD2C「SOLNA」のスキーマで具体化します。
棲み分けを先に宣言しておきます。対になる因果連載は、A/Bが打てない現場で観測データから因果に迫る側でした。本連載は逆に、自分でランダム割付した介入を設計して因果を測る側にいます。メトリクス設計はその入口で、「自分で割り付けた実験の結果を、何をもって成功と判定するか」を事前に決める作業です。なお SOLNA は連載共通の架空企業(D2Cスキンケアの定期購入モデル)で、以下の数値はすべて説明用のイメージであり実測値ではありません。
多くのチームは「メトリクス設計」を、ダッシュボードに並べるKPIを選ぶ作業だと捉えています。実験設計の言葉で言い換えると、指標は感度の仕様を持った測定器です。どの指標を北極星に選ぶかは、必要サンプル数(=かかる時間とコスト)を選ぶことであり、同時に「何を見逃すか」という盲点を選ぶことでもあります。この視点に立つと、指標選びは美学ではなく工学になります。
主要指標(北極星)を先に決める
北極星指標は一つに絞ります。理由は単純で、複数を「主指標」と呼んだ瞬間、どれかは動くので、後から動いたものを主役に据え替えられます。これは判定ではなく後付けです(後述する罠の本体でもあります)。
絞り込みは二つの条件のせめぎ合いになります。事業の意思決定を動かすかと、実験期間内に動くかです。SOLNA で北極星の候補になるのは、ユーザーあたり売上(revenue)・コンバージョン(期間内に1注文以上)・注文数(orders_n)あたりでしょう。事業に近いのは売上ですが、近い指標ほど分散が大きく、検出に必要なサンプルが膨らみます。ここを数字で見ておきます。
import numpy as np
import pandas as pd
# 実験母集団(messages.holdout_flag で treatment/holdout に割付済みと仮定)。
# まず「どの指標を北極星にするか」を決めるため、候補をユーザー単位に畳む。
agg = (orders.groupby("customer_id")
.agg(revenue=("amount", "sum"),
orders_n=("order_id", "count"))
.reset_index())
# 期間内に注文ゼロのユーザーも母集団に含める(実験対象に合わせてゼロ埋め)。
per_user = (exposed.merge(agg, on="customer_id", how="left")
.fillna({"revenue": 0, "orders_n": 0}))
per_user["converted"] = (per_user["orders_n"] > 0).astype(int)
def profile(x):
mu, sd = x.mean(), x.std(ddof=1)
cv = sd / mu if mu else np.nan # 変動係数 = 感度の代理
return pd.Series({"mean": mu, "std": sd, "cv": cv})
candidates = ["converted", "revenue", "orders_n"]
summary = per_user[candidates].apply(profile).T
# 相対MDE(相対的に何%動けば検出したいか)を固定すると、
# 必要サンプル数は n ∝ CV^2 / MDE_rel^2(連続指標。導出は第1回)。
mde_rel = 0.05
summary["rel_n"] = (summary["cv"] / mde_rel) ** 2
summary["rel_n"] /= summary["rel_n"].min() # 最小の指標を1に正規化
print(summary.round(2))架空の SOLNA で回すと、出力イメージはこうなります。
| 指標 | mean | std | cv | rel_n |
|---|---|---|---|---|
| converted | 0.10 | 0.30 | 3.0 | 1.0 |
| revenue | 1,500 | 6,000 | 4.0 | 1.8 |
| orders_n | 0.15 | 0.66 | 4.4 | 2.1 |
読み方はこうです。コンバージョンを北極星にすれば最少のサンプルで判定できます。同じ相対差を売上で見ようとすると、変動係数(CV)が大きいぶん約1.8倍のユーザーが要ります。ここで使った関係は で、必要サンプル数の絶対値の導出と statsmodels での計算は第1回に譲ります。本記事の論点は、この比が指標選びの予算表になることです。
では感度の高いコンバージョンを選べばいいかというと、そう単純ではありません。コンバージョンは「買ったか否か」しか見ないので、客単価(AOV)だけを押し上げる施策には反応しません。アップセルやバンドルのように、買う人数は変えず一人あたりの金額を動かす仮説なら、北極星をコンバージョンにした時点でその効果は構造的に見えなくなります。
仮説が動かすものから逆算するのが原則です。施策が主に人数を動かすならコンバージョン、主に金額を動かすなら売上、頻度ならば注文数。どれが本命かを言語化できないうちは、まだ実験を走らせる段階ではありません。
ガードレール指標(壊していないかの見張り)
北極星だけ見て採否を決めると、別の場所を壊しながら勝つ施策を通してしまいます。ガードレール指標は「北極星が上がっても、ここが許容を超えて悪化したら採用しない」という拒否権です。SOLNA なら、定期解約率(subscriptions の status == 'cancelled')・低評価率(reviews の rating <= 2)・配信のオプトアウト率(messages 側)あたりが候補になります。
ガードレールで最も多い設計ミスは、判定基準を「有意差が出たら赤」にすることです。サンプルが増えるほど検定は微小な差でも有意になるので、件数を集めれば集めるほどガードレールは必ずどこか赤くなります。正しくは事前に決めた許容悪化マージンを超えたら赤、という非劣性(non-inferiority)の枠組みで見ます。
# ガードレール: 北極星が上がっても、これらが許容マージンを超えて悪化したら不採用。
# 「有意差で赤」ではなく「事前に決めた許容悪化を超えたら赤」で判定する。
def rate(df, fn):
return fn(df).mean()
guardrails = {
# 指標 : (集計関数, 許容する相対悪化)
"cancel_rate": (lambda d: (d["sub_status"] == "cancelled"), 0.02),
"low_rating": (lambda d: (d["rating"] <= 2), 0.00),
"optout_rate": (lambda d: (d["optout"] == 1), 0.01),
}
rows = []
for name, (fn, margin) in guardrails.items():
base = rate(holdout, fn) # 対照群の水準
test = rate(treatment, fn) # 介入群の水準
rel = (test - base) / base if base else np.nan
rows.append({"metric": name, "holdout": base, "treatment": test,
"rel_change": round(rel, 4), "margin": margin,
"flag": "alert" if rel > margin else "ok"})
print(pd.DataFrame(rows))許容マージンはビジネス判断で決める値で、統計から自動では出てきません。低評価率のように「一切の悪化を許さない」ものはマージンをゼロに、解約率のように多少のノイズを飲める指標は数%に置きます。マージンを置く行為そのものが、何を守りたいかの宣言になります。
なお、ガードレールを何十個も並べると、対照と介入の偶然のブレでどれかは必ずマージンを超えます。これは多重比較の問題で、補正の作法自体は第3回で扱います。メトリクス設計の側でやるべきことは、ガードレールを「壊れたら事業が痛む数個」に絞り、それぞれにマージンを事前固定しておくことです。
代理指標と感度(遅い指標をどう測るか)
本当に動かしたい北極星が、実験期間内に確定しないことは多いです。SOLNA で「90日定着」や「LTV」を北極星にしたくても、実験を2〜4週間で締めるなら、その数字は実験終了時点でまだ確定していません。確定を待てば実験は遅くなり、回数が稼げません。
そこで速い**代理指標(surrogate)**を立てます。たとえば「7日以内の2回目購入=アクティベーション」を、遅い「90日定着」の先読みに使います。代理が正当かは思い込みで決めず、過去コホートで検証します——代理が立った人と立たなかった人で、後の定着率が実際に分かれるかを見ます。
# 遅い北極星(例: 90日定着 = 3サイクル以上継続)を、
# 速い代理指標(例: 7日以内の2回目購入)で先読みできるか検証する。
# 過去コホートで「代理の有無」と「後の定着」の関係を見る。
cohort = customers.merge(
orders.assign(day=(orders["order_at"] - customers["first_order_at"]).dt.days),
on="customer_id", how="left")
activated = (cohort.query("order_type == 'repeat' and 1 <= day <= 7")
.groupby("customer_id").size().gt(0))
panel = customers.assign(
activated=customers["customer_id"].map(activated).fillna(False),
retained_90=(customers["n_cycles"] >= 3)) # 90日 ≒ 3サイクルを定着の定義に
tab = panel.groupby("activated")["retained_90"].agg(["mean", "size"])
lift = tab.loc[True, "mean"] / tab.loc[False, "mean"]
print(tab.round(3), "\nlift:", round(lift, 2))架空の出力イメージでは、アクティベーションした層の90日定着が0.55前後、しなかった層が0.18前後、リフトが約3倍——代理は遅い指標を十分に先読みしている、という絵になります。
ただし注意があります。この検証は過去の観測データの相関にすぎません。施策(介入)の下では、代理だけが動いて本来の成果が動かない、という逆転(surrogate paradox)が起こりえます。たとえば「2回目購入を煽るクーポン」は7日以内の再購入を確かに増やすが、値引き目当ての解約予備軍を増やして90日定着はむしろ下げる、という筋がありえます。だから代理指標は「進める/作り直す」の速い判断に使い、本命の結論は長期観測の仕組みを作り後追い確認します。長期追跡の設計は最終回で扱います。
感度の話をもう一度。代理指標を選ぶ理由は速さだけではなく、感度——すなわち分散の小ささ——でもあります。前節の予算表で見たとおり、感度の高い指標は少ないサンプルで動きます。手元のサンプルが足りないなら、実験前の共変量で分散そのものを削る手もありますが、それは第5回の主題なのでここでは触れません。メトリクス設計の段階では、「事業への近さ」と「感度」と「速さ」の三つを天秤にかけて、判定に使う指標の組を決める、と捉えておけばよいでしょう。
指標を後から選ぶ罠
ここまでの設計がすべて、結局は一つの規律に集約されます。主指標・ガードレール・代理指標を、走らせる前に登録して固定することです。
なぜそこまで厳格にするのか。指標を後から選べる状態は、偽陽性を量産する装置になります。効果がまったく無い施策(帰無=A/Aと同じ状態)でも、k 個の独立な指標を片端から検定すれば、少なくとも一つが有意水準 α で「有意」になる確率は
に膨らみます。 なら、 で約40%、 で約64%です。つまり指標を10個眺めて「動いたもの」を後から北極星に選べば、効いていない施策の4割を「成功」と誤って通すことになります。セグメントを後から掘る分析も、時間軸で何度も覗くこと(peeking)も、構造はこれと同じ「後から有利な切り口を選ぶ」仲間です。
防ぎ方は単純で、事前登録に尽きます。実験を始める前に、主指標を一つ、ガードレールを数個、代理指標とその検証根拠、そして分析計画(誰を母集団とし、いつ締め、どう検定するか)を文書に固定します。実験後に増えた指標やセグメントは「次の仮説のための探索」であって「今回の判定」ではない、と役割を分けて扱います。探索を禁じる必要はありません——判定と混ぜないだけです。
後付けセグメント分析の危険は第3回、いつ止めてよいか(時間方向の覗き見)は第4回で、それぞれ実務の作法として掘り下げます。本記事の主張は一点、指標は測ってから選ぶものではなく、測る前に決めるものだということです。
章末チェックリスト
- 北極星を一つに絞り、それが「事業を動かす」と「実験期間で動く」を満たすか確認したか
- 仮説が動かすもの(人数/金額/頻度)から北極星を逆算したか
- 指標ごとの感度(CV)を見て、必要サンプル数の予算を把握したか
- ガードレールを数個に絞り、それぞれに許容悪化マージンを事前設定したか(有意差基準にしていないか)
- 遅い北極星に代理指標を立て、過去コホートでその妥当性を検証したか
- 主指標・ガードレール・代理・分析計画を、走らせる前に事前登録したか
ここまでが「何を成功とするか」を測る前に決める設計でした。分けられない施策での測定や、観測データから因果に迫る手法は、対になる因果編と地続きになっています。次回は、正しく回しているつもりのA/Bがどこで誤るか——ランダム割付・SRM(標本比率ミスマッチ)・多重比較・後付け分析の罠を一通り押さえます。