「Pyroを使ったベイジアンABテスト」

「焚火(ピロ)を使ったベイジアンABテストの効果」

Pyroを使用したベイジアン思考とABテストの初歩

クレジット:PixabayのFree-Photos

この記事は、Pythonの確率プログラミング言語(PPL)であるPyroを使用したABテストの紹介です。Pyroは、PyMCの代替となるもので、ベイズ統計的推論の理解を深めるために作成され、他の人々にも役立つことを目的としています。したがって、フィードバックは歓迎されます。

はじめに

Pythonでベイジアンモデリングを行う経験は以前にPyMCで行ったことがあります。ただし、最新バージョンのいくつかとの互換性に問題があることがわかりました。他の確率的プログラミング言語の調査を通じて、バックエンドでPyTorchをサポートするUberによって開発された汎用のPPLであるPyroを知りました。以下にPyroとPyTorchのドキュメントへのリンクがあります。

Pyro

ディープユニバーサル確率プログラミング

pyro.ai

PyTorchのドキュメント – PyTorch 2.1 ドキュメント

PyTorchは、GPUとCPUを使用したディープラーニングのための最適化されたテンソルライブラリです。このドキュメントでは説明されている機能があります…

pytorch.org

Pyroを探索する中で、このパッケージを使用したABテストのエンドツーエンドのチュートリアルを見つけるのが難しかったです。この記事は、そのギャップを埋めることを目指しています。

この記事は5つのセクションで構成されています。最初のセクションでは、ベイジアン思考についての入門的な説明を行い、方法論の背後にある哲学を説明します。Pyroと統計的推論を行うために使用されるベイジアン手法についても簡単に説明します。次に、Pyroを使用してABテストを実施し、その結果について話します。そして、ビジネスの設定でのベイジアンABテストの必要性を説明します。最後のセクションではまとめます。

ベイジアンの基礎

ベイジアンプロセスは、高いレベルでは比較的単純です。まず、興味のある変数があります。その変数に関する現在の理解を確率分布で表現し(ベイズの世界ではすべてが確率分布です)、それを事前分布と呼びます。ベイズ推論における確率は認識によって生まれるものであるため、事前分布は不確実性の表明と同じくらい、理解になります。その後、現実世界からイベントを観察します。これらの観察結果は、興味のある変数の理解を更新するために使用されます。新たな理解の状態は事後分布と呼ばれます。また、データを観察した場合に興味のある変数の確率(事後分布)で事後を特徴付けます。このプロセスは、以下のフローダイアグラムで示されています。ここで、thetaは興味のある変数、dataは観察したイベントの結果です。

ベイジアンプロセス

ベイジアンプロセスは実際には循環的であり、世界を観察した後にこのプロセスを繰り返します。以前の事後分布が新しい事前分布となり、新しいイベントを観察し、再び理解を更新します。ナイート・シルバーは著書『The Signal and the Noise』で述べたように、私たちの不確実性は「少なくなりますが、少なくなりますが、少なくなります」というようになります。変数に関する私たちの不確実性を継続的に減らし、確実性の状態に収束していきますが(しかし、完全に確定することはできません)。数学的には、このような思考方法はベイズの定理によって捉えられます。

ベイズの定理

実際には、ベイズの定理は高次元の大きなモデルに対して計算的に手に負えなくなる場合があります。この問題を解決するための多くの手法がありますが、今日はマルコフ連鎖モンテカルロ(MCMC)と呼ばれる方法を使用します。MCMCは確率分布からサンプルを効率的に抽出するためのアルゴリズムのクラスです(私たちはハミルトニアンモンテカルロと呼ばれるものを使用します)。この記事では詳しくは触れませんが、参考になる資料を後で紹介します。今の時点では、ベイズの定理は計算できるほど複雑ではないことを理解してください。したがって、MCMCなどの高度なアルゴリズムの力を借りることで解決します。この記事では、Pyroを使用したMCMCに焦点を当てます。ただし、PyroはStochastic Variational Inference(SVI)の使用を強調しており、ここでは詳しく説明しません。

Pyroを使用したABテスト

新しいウェブサイトのランディングページを設計し、その結果がコンバージョンに与える影響を理解したいとする会社を考えてみましょう。コンバージョンとは、訪問者がランディングページに到達した後にウェブセッションを継続するかどうかのことです。テストグループAでは、コントロールグループとして現在のランディングページが表示されます。テストグループBでは、新しいランディングページが表示されます。この記事の残りでは、テストグループAをコントロールグループ、グループBを治療グループと呼ぶことにします。ビジネスはこの変更に懐疑的で、セッションのトラフィックを80/20の割合で選択しました。各テストグループの総訪問者数とページのコンバージョン数は以下の通りです。

テストの観測

ABテストの帰無仮説は、2つのテストグループのページのコンバージョンに変化がないということです。頻度論的なフレームワークでは、これはコントロールグループと治療グループのページのコンバージョン率、つまりr_cとr_tに対して以下のように表されます。

帰無仮説と対立仮説

有意性検定では、帰無仮説を棄却するか否定できないかを検討します。ベイズのフレームワークでは、我々は異なる形で帰無仮説を表現します。

さて、テスト中に何が起こっているのかを詳しく説明しましょう。私たちが関心を持っている変数はページのコンバージョン率です。これは、独立な訪問者の数を総訪問者数で割ることで単純に計算されます。この率を生成するイベントは、訪問者がページをクリックするかどうかです。ここでは、各訪問者に対して2つの可能な結果があります。訪問者がページをクリックしてコンバージョンするか、しないかです。一部の方々は、それぞれの独立訪問者に対して、これがベルヌーイ試行の例であると認識するかもしれません。試行は1回で、2つの可能な結果があります。これらのベルヌーイ試行の集まりを収集すると、二項分布になります。ランダム変数Xが二項分布に従うとき、次のように表します。

二項分布表記法

ここで、nは訪問者数(またはベルヌーイ試行の数)であり、pは各試行でのイベントの確率です。ここではpが興味の対象です。つまり、各テストグループでの訪問者がページのコンバージョンする確率を理解したいのです。データを観測しましたが、前のセクションで説明したように、まず事前確率を定義する必要があります。ベイズ統計学では常に、事前確率を確率分布として定義する必要があります。先ほど述べたように、この確率分布は不確実性の表現です。ベータ分布は確率のモデリングによく使われます。なぜなら、[0,1]の範囲で定義されるからです。さらに、ベータ分布を事前確率として使用すると、尤度関数の二項分布から事後分布が同じ分布から生成されるという便利な性質が得られます。ベータ分布は二つのパラメータ、アルファと混乱するかもしれないベータによって定義されます。

ベータ分布の表記

過去のデータにアクセスすることで、情報を持った事前確率を主張することができます。必ずしも過去のデータが必要であるわけではありませんが、直感を使って理解を深めることもできます。しかし、今のところはどちらも持っていないと仮定します(後でこのチュートリアルでは情報を持った事前確率を使用しますが、影響を示すために無知な状態から始めます)。企業のサイトでの変換率についての理解がないと仮定し、したがって私たちの事前確率をBeta(1,1)と定義します。これはフラットな事前確率と呼ばれます。この関数の確率分布は下のグラフのように見え、[0,1]の間に定義された一様分布と同じです。Beta(1,1)の事前確率を主張することで、ページの変換率のすべての可能な値が等しい確率であるということを表します。

クレジット:著者

今、私たちは必要なすべての情報を持っています。事前確率とデータがあります。では、コードに入ってみましょう。ここで提供されるコードは、Pyroを使用してABテストを始めるためのフレームワークを提供します。そのため、パッケージのいくつかの機能を無視しています。コードをさらに最適化し、Pyroの機能を最大限に活用するためには、公式ドキュメントを参照することをおすすめします。

まず、パッケージをインポートする必要があります。最後の行は良い習慣であり、ノートブックで作業している場合に特に役立ちます。ビルドアップしたパラメータのストアをクリアします。

import pyroimport pyro.distributions as distfrom pyro.infer import NUTS, MCMCimport torchfrom torch import tensorimport matplotlib.pyplot as pltimport seaborn as snsfrom functools import partialimport pandas as pdpyro.clear_param_store()

Pyroのモデルは通常のPython関数として定義されます。これは、直感的に理解できるため、便利です。

def model(beta_alpha, beta_beta):    def _model_(traffic: tensor, number_of_conversions: tensor):        # ストキャスティックプリミティブを定義する        prior_c = pyro.sample('prior_c', dist.Beta(beta_alpha, beta_beta))        prior_t = pyro.sample('prior_t', dist.Beta(beta_alpha, beta_beta))        priors = torch.stack([prior_c, prior_t])        # 観測されたストキャスティックプリミティブを定義する        with pyro.plate('data'):            observations = pyro.sample('obs', dist.Binomial(traffic, priors),\                             obs = number_of_conversions)    return partial(_model_)

ここで解説するべきいくつかのポイントがあります。まず、外側の関数内にラップされた関数があり、外側の関数が内側の関数の部分関数を返します。これにより、コードを変更する必要なく事前確率を変更することができます。内部関数で定義された変数をプリミティブと呼び、モデル内の変数と考えてください。モデルには、ストキャスティックと観測されたストキャスティックの2つのタイプのプリミティブがあります。Pyroでは、明示的にその違いを定義する必要はありません。観測されたプリミティブはpyro.sample()メソッドにobs引数を追加するだけで十分であり、Pyroはそれを適切に解釈します。観測されたプリミティブは、コードがよりきれいになるためにpyro.plate()コンテキストマネージャ内に含まれています。私たちのストキャスティックプリミティブは、外側の関数から受け取ったalphaとbetaのパラメータによって特徴付けられたBeta分布です。先ほど説明したように、これを等しいものとしてヌル仮説を主張します。次に、tensor.stack()を使用してこれらの2つのプリミティブをスタックし、NumPy配列の連結操作に似た操作を実行します。これによりテンソルが返されるため、Pyroでの推論に必要なデータ構造が得られます。モデルが定義されたので、推論ステージに移りましょう。

先ほど述べたように、このチュートリアルではMCMCを使用します。次の関数は、上記で定義したモデルと事後分布を生成するために使用するサンプルの数をパラメータとして受け取ります。また、データもモデルと同様に関数に渡します。

def run_infernce(model, number_of_samples, traffic, number_of_conversions):    kernel = NUTS(model)    mcmc = MCMC(kernel, num_samples = number_of_samples, warmup_steps = 200)    mcmc.run(traffic, number_of_conversions)    return mcmc

この関数の内部の最初の行では、カーネルを定義しています。カーネルは、ノンユーターンサンプラー(NUTS)クラスを使用して定義されています。NUTSはハミルトニアンモンテカルロの自動チューニングバージョンであり、Pyroに対して事後確率空間からサンプリングする方法を示しています。このトピックについては、この記事では詳しくは触れませんが、一時的には、NUTSを使用することで確率空間から知能的にサンプリングできることを知っていれば十分です。カーネルは次の行でMCMCクラスを初期化するために使用され、NUTSを使用するように指定されています。MCMCクラスにはnumber_of_samples引数が渡されており、これは事後分布を生成するために使用されるサンプル数です。初期化されたMCMCクラスをmcmc変数に割り当て、run()メソッドを呼び出し、データをパラメータとして渡します。関数はmcmc変数を返します。

これで必要なすべてです。以下のコードは、データを定義し、先ほど作成した関数をBeta(1,1)事前分布を使用して呼び出します。

traffic = torch.tensor([5523., 1379.])conversions =torch.tensor([2926., 759.])inference = run_infernce(model(1,1), number_of_samples = 1000, \               traffic = traffic, number_of_conversions = conversions)

trafficとconversionsテンソルの最初の要素は、コントロールグループのカウントであり、各テンソルの 2 番目の要素は処理グループのカウントです。モデル関数をパラメータとともに渡し、定義したテンソルと共に渡します。このコードを実行すると、事後サンプルが生成されます。以下のコードを実行して事後サンプルを抽出し、Pandasのデータフレームに渡します。

posterior_samples = inference.get_samples()posterior_samples_df = pd.DataFrame(posterior_samples)

このデータフレームの列名は、モデル関数で定義したプリミティブの文字列です。データフレームの各行には、事後分布から抽出されたサンプルが含まれており、これらのサンプルの各々はページ変換率、つまり私たちの二項分布を制御する確率値pの推定値を表します。サンプルを返したので、事後分布をプロットすることができます。

結果

2つのテストグループのABテストの結果を視覚化するための洞察に富んだ方法は、共同カーネル密度プロットです。これにより、確率空間のサンプルの密度を両方の分布にわたって視覚化することができます。以下のグラフは、弊社が作成したデータフレームから生成することができます。

Credit: Author

上記のグラフに含まれる確率空間は、対角線に沿って分割することができ、線より上の領域は処理グループの変換率の推定値がコントロールグループよりも高いことを示します。プロットの例のように、事後から抽出されたサンプルは、処理グループの変換率が高いと示唆する領域に密集しています。処理グループの事後分布がコントロールグループよりも幅広いことに注意することが重要です。これは処理グループでのデータ観測が少ないためです。それにもかかわらず、プロットは処理グループがコントロールグループを上回ったことを強く示しています。事後からのサンプルの配列を収集し、要素ごとの差を取ることによって、処理グループがコントロールグループを上回る確率が90.4%であると言えます。この数値は、事後から抽出したサンプルの90.4%が共同密度プロットの対角線よりも上に配置されることを示しています。

これらの結果は、フラット(情報を持たない)事前分布を使用して得られました。観測データの利用可能性が限られている場合、情報を持つ事前分布の使用は、モデルを改善するのに役立つ場合があります。異なる事前分布の効果を調査することは有益な練習です。以下のプロットは、Beta(2,2)事前分布の確率密度関数と、モデルを再実行したときに生成する共同プロットを示しています。Beta(2,2)事前分布を使用すると、両方のテストグループに対して非常に似た事後分布が得られることがわかります。

Credit: Author

事後から抽出したサンプルによれば、処理グループがコントロールよりも優れている確率は91.5%です。したがって、フラットな事前分布を使用する場合とは異なり、処理グループがコントロールよりも優れているという確信度が高まります。ただし、この例では違いはほとんどありません。

これらの結果についてもう1つ強調したい点があります。推論を実行する際、私たちはPyroに対して事後分布から1000のサンプルを生成するように指示しました。これは任意の数値であり、サンプルの数を変更することで結果が変わる可能性があります。サンプルの数を増やす効果を強調するために、制御グループと処理グループの観測値が同じであり、それぞれの全体的なコンバージョン率が50%であるABテストを実行しました。Beta(2,2)事前分布を使用して、サンプルの数を増やすごとに次の事後分布が生成されます。

クレジット:著者

サンプルをただ10個だけ使用して推論を実行すると、制御グループと処理グループの事後分布は比較的広く、異なる形状を持ちます。引き出すサンプル数が増えるにつれ、分布は収束し、最終的にはほぼ同一の分布を生成します。さらに、統計分布の2つの特性、中心極限定理と大数の法則を観察します。中心極限定理は、サンプルの平均の分布がサンプル数の増加に従って正規分布に収束することを述べており、上記のプロットからも確認できます。また、大数の法則は、サンプルサイズが大きくなるにつれて、サンプルの平均が母集団の平均に収束することを述べています。テストサンプルのそれぞれで観察される変換率である0.5ほどとなっているのは、右下のタイルの分布の平均がそうであるためです。

ベイジアンABテストのビジネスケース

ベイジアンABテストは、事業のテストと学習の文化を向上させるのに役立ちます。ベイジアン統計推論により、テストの微小な改善が長期の確率に依存することなく迅速に検出できます。テストの結論に早く到達できるため、学習のスピードが向上します。また、ベイジアンABテストでは、’のぞき見’によって得られた結果によってテストが重要に劣化していると示された場合、テストを早期に中止することも可能です。そのため、テストの機会費用が大幅に削減されます。これはベイジアンABテストの主な利点です。結果を常にモニタリングし、事後確率を常に更新できます。逆に、テスト主体での改善の早期検出は、ビジネスが収益を向上させる変更を迅速に実装するのに役立ちます。顧客に直接対応する事業は、テスト結果を素早く実装し、分析できる能力が必要です。これはベイジアンABテストのフレームワークによって実現されます。

まとめ

この記事では、ベイジアン思考の概要とPyroを使用したベイジアンABテストの結果について簡単に説明しました。この記事が参考になったことを願っています。前書きでも述べたように、フィードバックは歓迎されています。約束どおり、以下にさらなる参考資料へのリンクを提供しました。

おすすめの資料

以下の書籍はベイジアン推論についての良い洞察を提供しています:

  • The Signal and the Noise: The Art and Science of Prediction — Nate Silver
  • The Book of Why: The New Science of Cause and Effect — Judea Pearl and Dana Mackenzie. この書籍は主に因果関係に焦点を当てていますが、第3章はベイズについての価値ある読み物です。
  • Bayesian Methods for Hackers: Probabilistic Programming and Bayesian Inference — Cameron Davidson-Pilon. この書籍はGitでも利用できますので、以下にリンクを示します。

GitHub — CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers: aka “Bayesian…

aka “Bayesian Methods for Hackers”: An introduction to Bayesian methods + probabilistic programming with a…

github.com

以下のVoAGI記事はMCMCの詳細な説明を提供しています。

Monte Carlo Markov Chain (MCMC) explained

MCMC methods are a family of algorithms that uses Markov Chains to perform Monte-Carlo estimate.

towardsdatascience.com

ベイズ推論問題、MCMCと変分推論

統計学におけるベイズ推論問題の概要。

towardsdatascience.com

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more