如何从离散分布中采样?

机器算法验证 可能性 分布 随机生成 加权抽样
2022-02-03 21:19:42

假设我有一个分布来控制单个随机变量 X 的可能结果。这类似于 [0.1, 0.4, 0.2, 0.3],因为 X 的值是 1、2、3、4。

是否有可能从这个分布中抽样,即在给定结果的概率的情况下,在每个可能的结果上生成伪随机数。所以如果我想知道得到 2 的概率是多少,采样操作可能会返回 0.34 或类似的值。

我问的原因是我正在尝试根据研究论文为强化学习方法实施动作选择策略。根据我从论文中收集到的信息,作者能够通过“通过自适应数值积分获得的累积概率密度函数映射均匀分布 U[0,1]”来对分布进行采样。然后,他从中对每次试验的转移概率进行采样......

我将不胜感激有关此的任何信息...

提前致谢

4个回答

当然。这是一个 R 函数,它将从该分发n时间中进行采样,并进行替换:

sampleDist = function(n) { 
    sample(x = c(1,2,3,4), n, replace = T, prob = c(0.1, 0.4, 0.2, 0.3)) 
}

# > sampleDist(10)
# [1] 4 2 2 2 2 2 4 1 2 2

如果你想再低一点,你可以通过查看 R 源代码(用 C 编写)来查看实际使用的算法:

/* Unequal probability sampling; with-replacement case 
 * n are the lengths of p and perm. p contains probabilities, perm
 * contains the actual outcomes, and ans contains an array of values 
 * that were sampled.
 */

static void ProbSampleReplace(int n, double *p, int *perm, int nans, int *ans)
{
    double rU;
    int i, j;
    int nm1 = n - 1;

    /* record element identities */
    for (i = 0; i < n; i++)
        perm[i] = i + 1;

    /* sort the probabilities into descending order */
    revsort(p, perm, n);

    /* compute cumulative probabilities */
    for (i = 1 ; i < n; i++)
        p[i] += p[i - 1];

    /* compute the sample */
    for (i = 0; i < nans; i++) {
        rU = unif_rand();
        for (j = 0; j < nm1; j++) {
            if (rU <= p[j])
                break;
            }
        ans[i] = perm[j];
    }
}

针对评论中的问题,这里概述了一些可能*比 cdf 方法更快的离散分布方法。

* 我说“可能”是因为对于一些离散的情况,实施良好的逆 cdf 方法可以非常快。如果不引入额外的技巧,一般情况下很难快速完成。

对于问题示例中的四种不同结果的情况,逆 cdf 方法(或有效等效方法)的幼稚版本很好;但是如果有数百(或数千或数百万)个类别,它可能会变得很慢而不会变得更聪明(您当然不希望通过 cdf顺序搜索,直到找到 cdf 超过随机数的第一个类别制服)。有一些比这更快的方法。

[您可以看到我在下面提到的前几件事与使用索引定位值的比顺序更快的方法有关,因此在某种程度上只是“使用 cdf 的更智能版本”。我们当然可以查看“标准”方法来解决“搜索排序文件”等相关问题,并最终找到比顺序性能快得多的方法;如果您可以调用合适的函数,那么这些标准方法通常可能就是您所需要的。]

无论如何,对于一些从离散分布生成的有效方法。


1)“表法”。而不是成为O(n)为了n类别,一旦设置,(a)中的“简单”版本(如果分布合适)是O(1).


a)简单方法- 假设有理概率(在上述数据示例中完成):
- 设置一个包含 10 个单元格的数组,其中包含一个“1”、四个“2”、两个“3”和三个“4”。使用离散制服进行采样(从连续制服很容易做到),您将获得简单快速的代码。

b)更复杂的情况- 不需要“好的”概率。采用2k单元格,或者更确切地说,您最终会使用更少的单元格。因此,例如,考虑以下内容:

x         0        1      2       3      4      5      6
P(X=x)   0.4581  0.0032  0.1985  0.3298 0.0022 0.0080 0.0002

(当然,我们可以有 10000 个细胞并使用之前的精确方法,但是如果这些概率不合理怎么办?)

让我们使用k=8. 将概率乘以2k并截断以找出我们需要的每种细胞类型的数量:

  x          0        1      2       3      4      5      6         Tot
P(X=x)     0.4581  0.0032  0.1985  0.3298 0.0022 0.0080 0.0002    1.0000
[256p(x)]   117       0     50      84      0      2      0         253

然后最后 3 个单元基本上是“从另一个分布生成”(即 p(x) - \frac{\lfloor 256 p(x)\rfloor}{256} 归一化为 pmf):

  x*       0        1        2        3        4        5        6          Tot
P(X=x*)  0.091200 0.273067 0.272000 0.142933 0.187733 0.016000 0.017067   1.000000

“溢出”表可以通过任何合理的方法来完成(你只有大约 1% 的时间到达这里,它不需要那么快)。所以253256在我们生成一个随机制服的时候,使用它的前 8 位来选择一个随机单元格,并输出单元格中的值;在初始设置之后,所有这些都可以非常快速地完成。另一个3256有一次我们点击了一个显示“从第二个表生成”的单元格。几乎总是,你生成一个单一的制服(0,1)并从乘法、截断和访问数组元素的成本中获取离散随机数。

2)“平方直方图”方法;这有点与(1)有关,但每个单元格实际上可以生成两个值中的一个,具体取决于(连续)均匀。所以你生成一个从 1 到 n 的离散值,然后在每个值中,检查是生成它的主值还是它的第二个值。它适用于有界随机变量。没有溢出表,它通常使用比方法(1)小得多的表。通常,它被设置为使 1:n 的选择使用统一随机数的前几位,其余部分告诉您要输出该 bin 的两个值中的哪一个。

概述该方法的最简单方法可能是在上面的示例中进行:

将分布视为具有 4 个 bin 的直方图:

原始“直方图”

我们把最高的条的顶部切掉,把它们放在较短的里面,“把它弄平”。条形的平均“高度”为 0.25。所以我们从第二根柱子上剪下 0.15 把它放在第一根柱子上,把第四根柱子剪掉 0.05 把它放在第三根柱子上:

“平方”直方图

它总是可以以这样一种方式组织它,即没有一个 bin 最终有超过 2 种颜色,尽管一种颜色可能最终出现在几个 bin 中。

所以现在你随机选择 4 个 bin 之一(需要制服顶部的 2 个随机位)。然后,您使用剩余的位来指定一个均匀分布的垂直位置,并与颜色之间的间隔进行比较,以确定要输出两个值中的哪一个。虽然非常快,但它通常不如“表格”方法快。

--

这些方法可以适应处理无界变量,同样,它“主要是快速的”。

参考: http: //www.jstatsoft.org/v11/i03/paper

其中相对较慢的部分是创建值表;当你知道你将要生成什么时(“我们需要在未来多次从这个分布中采样值”)而不是试图在你去的时候创建它,它们是合适的。“我们需要尽快从这个样本中抽取一百万个值,但我们再也不需要这样做了”创建了不同的优先级;在许多情况下,查找排序值的一些“标准计算方法”(即更快地执行 cdf 方法)实际上可能是您的最佳选择。


还有其他从离散分布生成的快速方法。仔细编码,您可以进行一些非常快速的生成。例如:

3)拒绝方法(“接受-拒绝”)可以用离散分布来完成;如果您有一个离散的主要函数(“包络”),它是一个放大的离散 pmf,您已经可以快速生成它,它会直接适应,并且在某些情况下可以非常快。更一般地,您可以利用能够从连续分布生成的优势(例如,通过将结果离散回离散包络)。

在这里假设我们有一些离散的概率函数f我们没有方便的 cdf(或逆 cdf)——事实上,在这个插图中,我们甚至没有归一化常数,所以我们的图是非归一化的:

自然数上的非归一化单峰离散概率质量函数图; 它的模式为 2 并最终以近似几何的方式衰减

现在我们需要找到一些方便生成的离散概率函数g, 可以乘以一个常数c并且在任何地方至少和f(我们需要确保这对所有人都是正确的x值)。那是,c.g(x)f(x)尽一切可能x价值观。

有时一个合适的g很容易识别,但一个有用的选择是对左侧部分采用离散均匀分布和尾部至少与f在右侧。两个相当方便的选择是几何分布(当尾部的下降速度不低于指数时)和离散的帕累托或离散的半柯西分布,通过取X对于一些帕累托或半柯西随机变量X(在任何一种情况下,当 pmf 的下降速度慢于指数下降时)。

(就此而言,几何本身可以通过离散指数来生成。)

在这种情况下,左侧的离散制服和右侧的几何效果非常好:

具有上述均匀和几何包络的先前离散 pmf(主函数)

(提醒:这里绘制的是未归一化的 pmf,因此 y 轴不代表概率,而是与概率成正比的东西)

然后该过程是模拟建议值的问题xg,模拟制服,U(0,c.g(x))而如果U<f, 接受提议x(否则拒绝它并生成一个新的提议x)。

在python中你可以做类似的事情

    from scipy.stats import rv_discrete

    x=[1,2,3,4]
    px=[0.1,0.4,0.2,0.3]

    sample=rv_discrete(values=(x,px)).rvs(size=10)

这将为您提供 10 个分布中的样本。您可以重复此操作,然后找到 2 的样本比例。

是的,这是可能的并且相当容易,具体取决于您使用的工具。

在 R 中,它将是sample(1:4, n, prob=c(0.1,0.4,0.2,0.3), replace=TRUE)n要采样的值的数量。

在没有等效功能的工具中,您仍然可以生成一个统一的值,然后您的 RV 如果低于 0.1,则等于 1,如果介于 0.1 和 0.5 之间,则等于 2,如果介于 0.5 和 0.7 之间,则等于 3,如果大于 0.7(即是映射到累积的想法)。

对于您的示例,您还可以从具有一个 1、四个 2、两个 3 和三个 4 的集合中均匀采样以获得相同的概率。