詳細な説明は、以下の解説記事をご覧ください。
javascriptにより、ブラウザから実行できるプログラムです。単一のhtmlファイルですので、何をしているのかはソースを見れば分かります。
- http://lfics81.techblog.jp/confidence_interval_ja.html(日本語版)
- http://lfics81.techblog.jp/confidence_interval.html(英語版)
一応、安全性は確認しておりますが、バグやファイル改ざん等のリスクまでは対応できません。利用する際には自己責任でお願い致します。このプログラムの使用に関して、当方は一切の責任を負いません。
古いブラウザだと動かないかもしれません。
対局数が多い場合には、処理に時間がかかることがあります。
英語版の表記は以下の意味です。
- 「games」:対局数。
- 「wins」:勝ち数。
- 「draws」:引き分け数。
- 「confidence interval」:信頼区間。
- 「Calculate」:計算実行。
- 「Select all」:全選択。
- 「winning percentage」:勝率。
- 「standard error」:標準誤差。
- 「relative Elo rating」:相対イロレーティング。
「removed from games」は引き分けを対局数から取り除く場合、「transformed into (draws / 2) wins」は引き分け数の半分(端数は切り捨て)を勝ち数に加える場合に選択してください。
このプログラムは、パブリックドメイン(公有)扱いとします。ご自由にお使いください。
以下はc++版の関数です。やっていることは基本的にjavascript版と同じですが、コメントが付いています。
#include <algorithm> // std::minとstd::maxのため。windows.hの名前衝突に注意。 #include <cmath> // 数学関数のため。 // ---------------------------------------------- double log10_binomial(const int & n, const int & k) // 二項係数 C(n, k) の常用対数。 // ---------------------------------------------- { const int m = std::min(k , (n - k)); double s = 0.0; for (int i = 1; i <= m; i++) { s += std::log10((n - m + i) / double(i)); // オーバーフロー対策で対数での計算。 // 常識的な範囲の計算なら対数を取らずに掛け算のやり方でもよい。 // javascript版では場合分けで少し高速化。 } return(s); } // ---------------------------------------------- double binomial_distribution(const int & n, const int & k, const double & p) // 二項分布 C(n, k) * p^{k} * (1 - p)^{n - k} の値。 // ---------------------------------------------- { return(std::pow(10.0, (log10_binomial(n, k) + k * std::log10(p) + (n - k) * std::log10(1.0 - p)))); // オーバーフロー対策で対数での計算。 } // ---------------------------------------------- void confidence_interval(const int & n, const int & k, const double & a, double & p, double & p_min, double & p_max, double & dr, double & dr_min, double & dr_max) // 入力:対局数n、勝利数k、[100 * (1 - a)]%信頼区間のa。 // 出力:勝率推定値p、勝率下限値p_min、勝率上限値p_max、レート差推定値dr、レート差下限値dr_min、レート差上限値dr_max。 // ---------------------------------------------- { if ((n < 5) || (k <= 0) || (k >= n) || (a <= 0.0) || (a >= 1.0)) { // 本来はエラー処理、ここでは省略。 return; } // 勝率推定。 p = k / double(n); // 挟み撃ちで区間を絞っていくための初期値。 int k_min = 0; int k_max = n; // 区間境界での二項分布の値の初期値。 double b_min = binomial_distribution(n, k_min, p); double b_max = binomial_distribution(n, k_max, p); // 確率の積算値。0から始めて、a越えを目指す。 double s = 0.0; while (true) // a超えまでの無限ループ。 { // 境界の分布値が小さい方を狭めていく。 if (b_min < b_max) { s += b_min; if (s >= a) {break;} // 超えたら抜ける。越える前が信頼区間。 k_min++; b_min = binomial_distribution(n, k_min, p); } else { s += b_max; if (s >= a) {break;} // 超えたら抜ける。越える前が信頼区間。 k_max--; b_max = binomial_distribution(n, k_max, p); } } // 区間を勝率に直す。 p_min = k_min / double(n); p_max = k_max / double(n); // レート差の計算。 dr = 400.0 * std::log10(p / (1 - p)); dr_min = (k_min == 0) ? -1.E308 : (400.0 * std::log10(p_min / (1 - p_min))); dr_max = (k_max == n) ? 1.E308 : (400.0 * std::log10(p_max / (1 - p_max))); // 念のために対数の発散を避けているが、普通の環境なら不要。 return; }