統計には、ブルートコンピューターのパワーを使用して、分析せずに多くの実用的な質問に対するおおよその答えを得ることができる不正な方法もあります:ブートストラップ(英語ブートストラップ )。 1979年にBradley Efronによって発明され、出版されました。
あらゆる種類のものを取引し、多くの方法で顧客を引き付けるオンラインストアがあるとします。 ページ上の画像やボタンの位置、広告テキスト、AdWords、パートナーサイトのバナーなど、常に何かをテストしていることは明らかです。 そして、ここに最新の結果があります-私たちに来た893人のテストグループで34を購入し、到着した923人のコントロールグループで28を購入しました。
問題が発生します-ボスに行き、「テストグループではコンバージョンが3.81%、コントロールグループでは3.03%、26%の改善がありますか、私のボーナスはどこですか?」と言います。
この問題を分析的に解決することは難しくありません。 2つのランダム変数(テストグループとコントロールグループのコンバージョン率)が表示されます。 多数の観測値がある場合、二項分布は正規分布に似ています。 違いに興味があります。 正規分布は無限に割り切れ、平均値を減算して分散を加算すると、平均値34 / 893-28 / 923 = 0.77%と分散(34/893)*(1-34 / 893)/ 893 +(28/923)*(1- 28/923)/ 923。 標準偏差は分散の根に等しく、この場合は0.85%です。 95%の確率の真の値は、期待値からプラスまたはマイナス2標準偏差内、つまり-0.93%から2.48%の間にあります。
そのため、賞品はまだ輝いていません。引き続きデータを収集する必要があります。
次に、ブートストラップによって同じ問題を解決します。 基本的な考え方は次のとおりです。実験を何度も繰り返して、結果の分布を見てみるといいでしょう。 しかし、これを行うことはできません。したがって、不公平に行動します。利用可能なデータからサンプルを引き出し、各サンプルが実験を繰り返した結果のふりをします。
アルゴリズム:
- 利用可能な観測からランダムに1つの観測を選択します。
- 観測がある限り、ポイント1を繰り返します。 同時に、それらのいくつかを数回選択しますが、一部はまったく選択しません-これは正常です。
- この新しいサンプルでは、関心のあるメトリックを検討します。 結果を覚えています。
- 手順1〜3を何度も繰り返します。 たとえば、1万。 少ない可能性もありますが、精度は低下します。 もっと可能ですが、時間がかかります。
これで分布を確認したり、そこから何かを計算したりできます。 たとえば、信頼区間、中央値または標準偏差。
何の分布についても想定していないことに注意してください。 分布は非対称で、太い尾があり、一般に奇妙な形をしています。 アルゴリズムはこれから変更されません。
確かに、奇跡は起こりません。 ディストリビューションに期待がない場合(そのようなことが起こる)、ブートストラップはそれを見つけません。 まあ、つまり、彼はサンプルの期待値を見つけますが、一般集団は期待しません。 サンプルが代表的でない場合や単純に小さい場合も同様です。
ブートストラップは簡単に実装できます。 以下の例はCで記述され(より単純にすることはできません)、I / Oに加えて、疑似乱数ジェネレーターとソートの2つのライブラリー関数のみを使用します。 それを分解してみましょう。
プロローグには特別なコメントは必要ありません。 Cには
bool
はありません。データを
int
保存します。
#include <stdio.h> #include <stdlib.h> typedef int Data_t; #define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
オンザフライで選択を行い、それに基づいてコンバージョン率を計算する関数。
より正確な平均値計算アルゴリズムを使用する方がより正確です。
しかし、この例ではこれは重要ではありません。
static double bootstrap(const Data_t* data, unsigned n) { unsigned i; double sum = 0; for (i = 0; i < n; i++) { sum += data[rand() % n]; } return sum / n; }
関数を比較して結果を並べ替える
static int compare(const void* a, const void* b) { if (*(double*)a > *(double*)b) return 1; if (*(double*)a < *(double*)b) return -1; return 0; }
ソースデータ
int main(int argc, char* argv[]) { Data_t test[893] = { 0 }; Data_t control[923] = { 0 }; unsigned i; for (i = 0; i < 34; i++) { test[i] = 1; } for (i = 0; i < 28; i++) { control[i] = 1; }
コマンドラインのパラメーターを使用して、擬似乱数ジェネレーターを初期化します。 もし私たちが
すべてを正しく行った場合、これを変更しても結果はあまり泳ぎません
パラメータ。
if (argc == 2) { srand(atoi(argv[1])); }
ここで結果を追加します
double t_minus_c[10000];
メインサイクル
for (i = 0; i < ARRAY_SIZE(t_minus_c); i++) { t_minus_c[i] = bootstrap(test, ARRAY_SIZE(test)) - bootstrap(control, ARRAY_SIZE(control)); }
95%の信頼区間を決定します。結果を並べ替え、下から2.5%、上から同じ量を破棄し、結果を表示します。
qsort(t_minus_c, ARRAY_SIZE(t_minus_c), sizeof(double), compare); printf("LCL=%g%%\n", 100. * t_minus_c[250]); printf("UCL=%g%%\n", 100. * t_minus_c[9750]); return 0; }
私たちはチェックします:
$ gcc -wall -o bootstrap bootstrap.c $ ./bootstrap LCL = -0.891368% UCL = 2.43898%
他の擬似乱数を使用してさらに数回:
$ ./bootstrap 42 LCL = -0.86589% UCL = 2.43898% $ ./bootstrap 2013 LCL = -0.959673% UCL = 2.52184%
理論的な結果のように見えます(-0.93%から2.48%)。
そして、なぜ都市のフェンスは?
このタスクには単純な分析ソリューションがありますが、多くの実際の問題には、まったくないか、そうでない場合がありますが、非常に複雑です。 コンバージョン率ではなく、クライアントからの利益と彼を引き付けるコストの比率に関心があると想像してください。 このようなメトリックの分布は正規ではない可能性が高く、数式は数行に収まりません。 ただし、ブートストラップはまったく同じように機能し、
Data_t
を
double
変更して新しいデータをそこに配置するだけです。
一次資料
- エフロンB(1979)。 ブートストラップ方法:ジャックナイフの別の見方。 アン。 統計学者 7 1–26
- ドナルド・E・クヌース。 半数値アルゴリズム、The Art of Computer Programmingの第2巻、4.2.2章、232ページ。Addison-Wesley、ボストン、第3版、1998年。