本文へスキップ

ガイド

オンライン実験(A/B テスト)

オフラインの比較は、新しいバージョンのほうが良いと言いました。本番環境での A/B テストは、同じ問いを実際のユーザーに投げかけます。あなた自身のルーターが単位(ユーザーまたはセッション)を 2 つのアームに無作為に割り当て、oloproof experiment はそのログを読み、他のすべてのルールと同じ 4 つの状態で答えます。この手法は、明示された条件のもとで独立した監査により承認されています。observed_until は結果ログを抽出した時点についてのあなたの申告であること、単位が独立に無作為化されたこと、どの単位の結果も他の単位のアームに依存しないこと、割り当て比率が変わる間に結果が変動しなかったこと、そして各回の確認がログ全体を読むことです。これらの条件の外では、答えは保証されません。

ログと宣言

CSV または JSONL の 2 つのファイル。単位ごとに 1 行の割り当てログ(あなたが宣言する単位の列と arm)と、単位とその value を持つ結果ログです。

experiment:
  name: checkout-v2
  unit: user
  allocation: {control: 0.5, treatment: 0.5}
  control: control
  treatment: treatment
  assignments: logs/assignments.csv
  outcomes: logs/outcomes.csv
  kind: rate
  rules:
    - {id: lift, kind: superiority}
    - {id: no-harm, kind: non_inferiority, margin: 0.01}
oloproof experiment experiment.yaml --policy release.yaml --json

kind: mean は宣言された range: [low, high] を取ります。direction: max は低いほうを良いと読みます。結果の行がない割り当て済みの単位は欠損とされ、各側でその最悪値で抑えられます。ただし missing_outcome: zero が、行がなければゼロを意味すると指定している場合は除きます。終了コードは最悪のルールのものです。ゼロを含め、すべての単位について行を記録してください。コンバージョンした単位だけを保持するコンバージョンログは、それ以外のすべての単位を欠損と読み、答えは INSUFFICIENT_EVIDENCE のままです。ゼロ埋めは、数えるすべての単位の結果ウィンドウが閉じていることを前提とします。1 時間前に割り当てられた単位はまだコンバージョンしておらず、それをゼロと数えると、より速くコンバージョンするアームが有利になります。割り当てログに assigned_at 列を置いて outcome_window_hours、as_of、observed_until(結果ログを抽出した時点)を宣言すれば、as_of までにウィンドウが閉じた単位だけが数えられます。それらがない場合、モニタリングの種類にかかわらず missing_outcome: zero は拒否されます。すべての時刻はオフセットまたは Z 付きで書いてください(2026-10-11T00:00:00Z)。どちらもない時刻は拒否されます。as_of は observed_until より後にできず、どちらも未来にはできません。抽出後の結果はログにないからです。ウィンドウが問いを決めます。48 時間のウィンドウは「48 時間以内にコンバージョンしたか」に答えるので、意図する結果の遅れをカバーしなければなりません。単位 ID は空白を取り除いたうえでテキストとして比較され、42.0 は 42 と読まれます。0 PASS、1 FAIL、3 INSUFFICIENT_EVIDENCE、4 MANUAL_REVIEW。

最初に確認すること

  • サンプル比。 各アームの単位数を宣言された配分に対して検定します(2 アームでは正確二項検定、それ以上ではカイ二乗、閾値 0.001)。不一致があるとすべてのルールが MANUAL_REVIEW になります。分割が壊れているということはアームがもはや比較可能でないということであり、同じ種類のデータを増やしても直りません。差を読む前に原因(ユーザーを落とすリダイレクト、一方のアームだけに適用されたボットフィルター)を見つけてください。
  • 2 つのアームにいる単位。 割り当てが漏れています。すべてのルールが MANUAL_REVIEW になります。
  • 1 つの単位に複数の結果行。 拒否されます。1 人のユーザーのイベントは独立ではないからです。aggregate: unit_mean を宣言すると、各単位自身の平均がその結果になります。このとき答えは平均的なイベントではなく、平均的なユーザーについてのものです。
  • 空のアーム。 結果が得られるまで INSUFFICIENT_EVIDENCE です。
  • missing_outcome: zero のもとで、どの割り当て済み単位とも一致しない結果行。 ゼロは結合に依存するため、壊れた結合は実在の単位をゼロと読んでしまいます。ID が一致するまで、すべてのルールは MANUAL_REVIEW になります。既定では、数えたうえで除外されます。

どう判定するか

各アームの平均には、Oloproof が 1 回の実行にすでに使っている区間(率には正確な Clopper-Pearson、それ以外にはベッティングによる有界平均)が与えられ、それぞれ誤差予算の半分を使います。差は 2 つの区間の反対側の端で抑えられます。これはどのサンプルサイズでも成り立ち、教科書の正規区間より広くなります。優越性のルールは区間全体がゼロより上にあるときに合格し、非劣性のルールは下端がマイナスのマージン以上にあるときに合格します。

monitoring: anytime は両方のアームにベッティング区間を使い、どれだけ頻繁に見ても、いつ止めても成り立ちます。ただしそれは、見るたびにその時点までのログ全体を渡す場合に限ります。読んだ後に期間で行を落としたり絞り込んだりしないでください。既定の fixed は、計画したサンプルサイズで一度だけ読みます。

複数の処置

treatment: の代わりに treatments: [b, c] を宣言し、各ルールに比較する処置を指定します(treatment: b)。各アームの区間は m 個のアームに対して 1 - alpha/m で取られるので、処置から対照を引いたすべての差が和集合の上界によって同時にカバーされます。処置ごとに 1 つのルール、それぞれ 1 つの主張で、その族全体が同時に成り立ちます。各アームが他のアームの分を負担するため、各区間は 2 アームのときより広くなります。処置が複数ある場合、レポートはそれを名指しするすべてのルールを通過した処置のうち最良のものを示し、それが通過した他のすべての処置から分離しているかどうかを述べます。各差は同じ同時区間で抑えられ、ゼロを含みません。同順位は宣言された順序を保ち、分離されることはありません。サンプル比のチェックはすでにすべてのアームを読みます。同時の保証は 1 つの実験ファイルのアームを対象とします。処置を複数のファイルに分けると、その保証は失われます。

比率メトリクス

クリック率はクリック数をセッション数で割ったものであり、多くのセッションを持つ 1 人のユーザーは多くの独立したユーザーではありません。単位ごとに 1 行で、すべての単位の値が収まる範囲とともに比率を宣言してください。

  ratio: {numerator: clicks, denominator: sessions, numerator_range: [0, 50], denominator_range: [1, 50]}
  aggregate: unit_sum   # only if a unit has several rows: they are added

推定対象は、各アームの分子の平均をその分母の平均で割ったものです。両方の平均はそれぞれ誤差予算の取り分で、承認済みの区間によって抑えられ、比率はそれらの端を割ることで抑えられます。そのため正規近似なしに、どのサンプルサイズでも成り立ちます。区間がゼロに届く分母では区間は得られません。範囲外の値は単位を名指しする設定エラーであり、切り詰められることはありません。デルタ法による区間は、通常はより狭く、横に表示されますが、判定には使われません。

テスト前の共変量

テスト前に測られた何か(先月の支出、先週のセッション数)に連動する結果は、それを取り除くとばらつきが小さくなります。各単位のテスト前の値と、このテストの結果を読む前に固定した係数を持ってきてください。

  covariate: {values: logs/pre_period.csv, range: [0, 500], theta_from: logs/history.csv}

判定される結果は Y - theta (X - c) です。theta は宣言する(theta:、任意で center:、既定は範囲の中央)か、テストより前の期間の履歴ファイル(covariate と outcome の列)から当てはめるもので、このテスト自身の結果から当てはめることはありません。X は割り当ての前に測られ、どの単位に X があるかも割り当ての前に決まっていたので、調整後の差は同じ推定対象を持ちます。ファイルに値のない単位は調整されません。調整後の結果の範囲が広くなるため、妥当な調整でも調整なしより区間が広くなることがあります。そのためレポートは両方の区間を示してどちらが狭いかを述べ、節約は主張しません。

新奇性と干渉の表示

novelty: {exposure_column: exposed_at, time_column: at, days: 7} は、割り当てログから各単位の最初の露出を、各結果行からその時刻を読み、露出後最初の days 日とそれ以降の差を表示します。早期の差が判定され、後の差が未判定または逆向きの場合は「新奇性効果の可能性」と名付けられます。この分割がルールを判定することはありません。ある帯に行を持たない単位は、最悪の値で抑えられるのではなく、その帯から除かれます。これは 1 行に 1 つの結果を取り、比率や共変量は取りません。

cluster_column: team は、複数のアームの単位を含むチームを数え、ある単位の結果が別の単位のアームに依存しうるかを問います。依存しうるなら、チームで無作為化し、それを単位として宣言してください。

複数の処置、比率、共変量は、2026 年 11 月 3 日に独立した監査とその確認によって、2 アームと同じ条件で承認されました。

オフラインとオンライン

オフラインの比較とそのメトリクスを指定すると(offline_comparison: <id>、offline_metric: pass_rate)、答えは判定された 2 つの方向が一致するかどうかを報告します。これは報告されるだけで何も判定しません。不一致はスイートを見直す理由であって、リリースに対する評決ではありません。

落とし穴

  • 途中で覗くこと。 固定期間のテストを毎日読み、良い日に止めると、偽の勝ちが膨らみます。サンプルサイズを計画するか、monitoring: anytime を宣言してください。
  • 新奇性と学習。 ユーザーは新しいものに反応し、やがて落ち着きます。最初の週の向上は薄れることがあります。ユーザーのサイクルをカバーできるだけ長く実行し、分割を見るには novelty: を宣言してください。
  • 干渉。 区間は、ある単位の結果が別の単位のアームに依存しないことを仮定します。共有在庫、マーケットプレイス、ソーシャル機能、あるいは一方のアームが温めたキャッシュはこれを壊します。その場合はより大きな単位(地域、チーム)で無作為化し、クラスターがどれだけ混ざっているかを見るには cluster_column: を宣言してください。
  • 変化する分割のもとでのドリフト。 区間は、テスト中に配分が一定だったこと、または配分が変わる間に結果がドリフトしなかったことを仮定します。10% から 50% への段階的な引き上げや、平日と週末にわたる 90/10 から 10/90 への切り替えは、各アームで期間の重みを変え、差に時間の効果を混ぜ込みます。サンプル比のチェックは合算した数を読むので、これに気づきません。分割を固定するか、引き上げ後の期間だけで判定してください。
  • 単位を変えること。 無作為化と分析は同じ単位で行ってください。ユーザーを無作為化してセッションを独立として数えると、区間が誤って狭くなります。

これでわからないこと

  • テストの期間、地域、トラフィックの外にいるユーザーにも結果が当てはまるかどうか。
  • テスト前に宣言しなかったメトリクスについてのこと。事後に選んだメトリクスは記述です。
  • ルーターが本当に無作為化したかどうか。サンプル比のチェックは大きな欠陥は捉えますが、微妙なものは捉えません。
  • 通過しなかった処置のうちどれが最良か。順位付けされるのは通過した処置だけです。層別配分とスイッチバック設計は実装されていません。