【问题标题】:How to efficiently sample the continuous negative binomial distribution?如何有效地对连续负二项分布进行采样?
【发布时间】:2016-11-23 23:23:52
【问题描述】:

首先,就上下文而言,我正在开发一款游戏,当你做好事时,你会获得正积分,而当你做坏事时,你会获得负积分,每个积分对应于掷硬币,如果你得到正面,那么发生了一些事情(如果它是一个积极的信用是好的,如果它是一个负面的信用是坏的),否则什么都不会发生。

交易是我想处理多个学分和分数学分的情况,我希望翻转用完学分,这样如果发生好/坏的事情,剩余的学分就会结转。一个直接的方法是只执行一堆试验,特别是对于分数信用的情况,我们可以将信用的数量乘以 X 和发生某事的可能性乘以 1/X(分布具有相同的期望但重量略有不同);不幸的是,这对用户可以获得多少积分以及积分数中的小数位数设置了实际限制,因为这会导致无限量的工作。

我想做的是利用我正在对连续负二项分布进行采样这一事实,这是获得正面需要多少次试验的分布,即如果 f(X) 是分布然后 f(X) 给出了在我们遇到正面之前会有 X 个反面的概率,其中 X 不必是整数。如果我可以对这个分布进行采样,那么我可以做的是,如果 X 是尾部的数量,那么我可以看到 X 是大于还是小于学分数;如果它大于然后我们用完所有的学分但什么也没有发生,如果它小于或等于那么会发生一些好事,我们从学分数中减去 X。此外,由于分布是连续的,我可以轻松处理分数学分。

有谁知道我能够有效地对连续负二项分布进行采样的方法(即从该分布生成随机数的函数)?

【问题讨论】:

    标签: random statistics


    【解决方案1】:

    这个问题在 StatsExchange 上可能会得到更好的回答,但在这里我会尝试一下。

    您是正确的,尝试直接计算它的计算成本很高,因为您无法避免 beta 和/或 gamma 函数依赖关系。我知道的唯一统计上有效的近似值是,如果所需的成功次数s 很大,并且p 既不是很小也不是很大,那么您可以使用具有特殊平均值的正态分布来近似它和方差。你可以阅读更多here,但我猜这个近似值通常不适用于你。

    负二项分布也可以近似为泊松分布的混合,但这并不能让您摆脱伽马函数的依赖。

    据我所知,唯一有效的负二项式采样器使用优化的接受-拒绝技术。此 PDF here 的第 10-11 页描述了该方法背后的概念。此 PDF here 的第 6 页(内部第 295 页)包含使用相关技术对二项式偏差进行采样的源代码。请注意,即使这些方法仍然需要随机均匀偏差以及sqrt()log()gammln() 调用。对于少量试验(可能少于 100 次?),如果仅使用快速随机数生成器模拟试验甚至比接受-拒绝技术更快,我一点也不感到惊讶。绝对从获得快速 PRNG 开始;它们并非生而平等。

    编辑:

    只要p不是非常大(太接近 1.0),以下伪代码可能会相当有效地绘制随机离散负二项分布值。它将返回在达到您的第一个“期望”结果之前所需的试验次数(这实际上是分配方面的第一个“失败”):

    // assume p and r are the parameters to the neg. binomial dist.
    // r = number of failures (you'll set to one for your purpose)
    // p = probability of a "success"
    double rnd = _rnd.nextDouble(); // [0.0, 1.0)
    int k = 0;  // represents the # of successes that occur before 1st failure
    double lastPmf = (1 - p)^r;
    double cdf = lastPmf;
    while (cdf < rnd)
    {
        lastPmf *= (p * (k+r) / (k+1));
        cdf += lastPmf;
        k++;
    }
    return k;
    // or return (k+1) to also count the trial on which the failure occurred
    

    使用递归关系可以避免在每个步骤中独立重复阶乘。我认为使用这个,再加上将小数精度限制为 1 或 2 个小数位(因此您只需要分别乘以 10 或 100)可能适合您的目的。你只画了一个随机数,其余的只是乘法——应该很快。

    【讨论】:

    • 感谢您的链接!我最初的计划是直接模拟事物,但后来我意识到,如果玩家获得 1000 个积分并且我允许保留两位小数,那么我将需要进行 100,000 次试验,我宁愿不对积分数设置上限.
    • 想一想,也许我只限制小数位数并使用离散分布会更好;你有关于如何采样的参考吗?
    • @GregoryCrosswhite 请看我的编辑——这个方法应该很快。
    • 哦,哇,这正是我所需要的! :-D 我会试试看的。