確率統計確率統計
超幾何分布サンプリング; Hyper Geometric Distribution Sampling

概要
超幾何分布サンプリング
超幾何分布とは以下の式で表現される確率分布。ある属性をもつ\(K\)個の要素を含む\(N\)の要素からなる母集団から\(M\)個の要素を抽出した時、 その属性をもつ要素の個数が\(k\)である確率を示す。なお\(K\)と\(M\)を入れ替えても同じ確率分布になる。

$$ P[X=k] = \frac{ {}_K \mathrm{C}_k \dot {}_{N-K} \mathrm{C}_{M-k} }{ {}_N \mathrm{C}_M }, \quad Max(0, M+K-N) \leq k \leq Min(M, K) $$
超幾何分布

超幾何分布に従う確率変数の生成にはルーレット選択アルゴリズムを用いる。そのために確率分布を求めるが、二項係数から求めようとするとオーバーフローなどの問題が生じる。そこで以下の漸化式を用いる。
$$ \begin{eqnarray} p(k; N, K, M) &=& \frac{ {}_K \mathrm{C}_k \dot {}_{N-K} \mathrm{C}_{M-k} }{ {}_N \mathrm{C}_M } \\ p(M; N, N, M) &=& 1 \\ p(k; N, K-1, M) &=& \frac{K-k}{K} p(k; N, K, M)+\frac{k+1}{K}p(k+1; N, K, M) \end{eqnarray} $$
ソースコード

namespace ExRandom.Discrete {
    public class HyperGeometricRandom : Random {
        readonly MT19937 mt;
        readonly int[] indexs;
        readonly double[] probs;

        public HyperGeometricRandom(MT19937 mt, int n = 30, int k = 20, int m = 10) { 
            if(mt == null) {
                throw new ArgumentNullException();
            }

            if(n <= 0 || k <= 0 || m <= 0 || n < k || n < m) {
                throw new ArgumentException();
            }

            if(k < m) {
                int swap;
                swap = k;  k = m;  m = swap;
            }

            int max = m, min = Math.Max(0, k + m - n);
            double p;
            double[] next_probs;

            this.mt = mt;

            this.indexs = new int[max - min + 1];
            this.probs = new double[max - min + 1];

            for(int i = 0; i < indexs.Length; i++) {
                indexs[i] = i + min;
            }

            probs[max - min] = 1;

            for(int i = n, j; i > k; i--) {
                next_probs = new double[max - min + 1];

                for(j = Math.Max(max - n + i, min); j <= max; j++) {
                    if(j > 0) {
                        p = (double)(i - j) / (double)(i);

                        next_probs[j - min] = probs[j - min] * p;
                        next_probs[j - min - 1] += probs[j - min] * (1 - p);
                    }
                    else { 
                        next_probs[j - min] = probs[j - min];
                    }
                }

                probs = next_probs;
            }

            Array.Sort(this.probs, this.indexs);
        }

        public override int Next() {
            double r = mt.NextDouble_OpenInterval1();

            for(int i = probs.Length - 1; i >= 0; i--) {
                r -= probs[i];
                if(r <= 0) {
                    return indexs[i];
                }
            }

            return indexs[probs.Length - 1];
        }
    }
}

関連項目
メルセンヌ・ツイスタ
各種確率分布サンプリング基本クラス

ライブラリライブラリ
確率統計確率統計
線形代数線形代数
幾何学幾何学
最適化最適化
微分方程式微分方程式
画像処理画像処理
補間補間
機械学習機械学習
クラスタリングクラスタリング
パズルゲーム・パズル
未分類未分類