algorithm - 从离散概率分布算法中采样
问题描述
我正在解决 Sedgewick 书中的一项任务:
编写一个带有构造函数的类 Sample ,该构造函数将双精度值的数组 p[] 作为参数并支持以下两个操作: random() — 返回一个索引 i,概率为 p[i]/T(其中 T 是总和p[] 中的数字)
我认为有一个简单的解决方案:将所有边界值存储在数组中并找到低于随机样本的第一个值,例如,我们有 (value, weight) 对:(1, 10.0), (2, 20.0), (3, 10.0), (4, 10.0)。我们将其转换为(1, 0.0), (2, 10.0), (3, 30.0), (4, 40),采样随机值[0-50](例如35),发现>30,所以答案是'3'。
但是书中有一个建议:
使用一个完整的二叉树,其中每个节点都有隐含的权重 p[i]。在每个节点中存储其子树中所有节点的累积权重。要生成随机索引,请在 0 和 T 之间选择一个随机数,并使用累积权重来确定要探索的子树的哪个分支。
我在 github 上看到了这个解决方案:https ://github.com/reneargento/algorithms-sedgewick-wayne/blob/master/src/chapter2/section4/Exercise35_Sampling.java
但我不明白它为什么起作用:我们将有一些树,而不是表示范围,它们将具有像 (3, 10), (4, 10) 这样的节点,如何搜索与随机样本“最近”的节点将有助于找到一个正确的节点?
解决方案
你的想法是在正确的轨道上,但并不完全在那里。你想做逆变换采样。您正在考虑的逐步函数是给定离散分布的逆累积密度函数 (cdf)。更传统的做法是在区间 [0..1) 上使用 X 轴上的搜索值来编写它。1、2、3 和 4 的权重分别为 1/5、2/5、1/5、1/5。您希望将区间分割成这种大小的片段,并将这些区间映射到它们各自的值:
[0 .. 1/5) -> 1 // Note interval widths are 1/5,2/5,1/5,1/5 as desired.
[1/5 .. 3/5) -> 2
[3/5 .. 4/5) -> 3
[4/5 .. 1) -> 4
正如您所说,将间隔的顶部及其值存储在数组中就足够了。在 C 中,
struct IntervalTop {
double r;
int value;
} cdf[] = {{.2, 1}, {.6, 2}, {.8, 3}, {1.0, 4}};
现在在 [0..1) 中生成一个随机值并查找相应的子区间以确定该值。例如,0.1 在第一个区间,所以返回 1。0.7 在第三个区间,所以返回 3。对于初学者来说,简单的线性搜索可以正常工作:
double r = ... // Compute random double 0.0 <= r < 1.0 .
for (int i = 0; ; ++i)
if (cdf[i].r > r)
return cdf[i].value;
但是这样一来,搜索时间就会随着间隔的数量而增加。
提高性能的一个简单方法是用二分搜索替换循环。然后搜索时间随着间隔数的对数增长。
但塞奇威克希望你更努力地工作,大概是为了学习。
他的提议也有运行时间 O(log(n)),但它更复杂。他说使用完整的二叉搜索树。每个节点包含值、权重 (w) 以及以该节点为根的子树中所有权重 (t) 的总和。所以对于这个问题,...
____3(w=1/5,t=1)____
/ \
2(w=2/5,t=3/5) 4 (w=1/5,t=1/5)
/
1(w=1/5,t=1/5)
实际上,您不需要算法的权重(这就是 S 说它们是“隐式”的原因),但是将它们包括在这里可以更容易地看到正在发生的事情。
如上所述,您将在 [0..1) 中生成一个随机数 r,但在这里您将使用 r 的值作为指导来搜索树。
您将通过查看 tree.t、tree.left.t 和 tree.right.t(丢失的孩子相当于 .t 值为零)并使用这些值做出与二进制相同的决定来做到这一点搜索会在上面。
我会在这里停下来,这样你的乐趣就不会被破坏。
推荐阅读
- python-3.x - 我的 Python 游戏敌人正在循环移动
- java - 从内部停止线程并从外部通知
- iis - 具有布尔属性的脚本上的出站 IIS 重写规则不起作用
- c# - c# - ASP.NET web api 控制器在注入服务时不工作
- angular - 使用带有自定义组件属性的 ngx 转换值
- macos - MacOS CoreData 故障删除传播预取失败
- google-chrome - PageSpeed Insights 不会返回结果 - Lighthouse 错误
- node.js - 如何在启动 mocha 时解决错误并在反应项目中使用 babel7 要求 ES6 模块
- python - setup.py 文件不包含在包中
- angular - Angular 9 可访问性:为 arial-label 组合字符串和绑定