从离散分布中改善样本的缩放比例

时间:2018-08-29 17:44:29

标签: performance random julia simulation stochastic-process

我最近开始与Julia一起玩耍,目前正在对二维格上的某些随机过程进行Monte Carlo模拟。每个站点都有一些相关的激活速率(平均每秒“执行某事”的次数),我们可以假设它们近似恒定。晶格位点激活的顺序是相关的,因此我们需要一种方法来随机选择一个特定位点,其概率与其激活率 成正比。

看起来sample(sites,weights(rates))包中的StatsBase正是我从测试我的代码结构(没有逻辑,只是循环和RNG)中寻找的东西,结果是{{1 }}与网站数量成线性比例。这意味着我的整体运行时规模像N ^(2 + 2)一样缩放,其中N在我的二维晶格的边长中(一个因素是总活动率增加的2,另一个是{{ 1}})。

现在,总活动率的增加是不可避免的,但是我认为“权重随机选择”方法的规模可以改善。更具体地说,人们应该能够以位点的数量(而不是线性的)实现对数缩放。例如,考虑以下功能(请原谅编码不良)

sample()

因为我们在每一步中将“可拾取”位点的数量减半,所以将需要n步才能从2 ^ n中选择一个特定位点(因此,对数缩放)。但是,在sample()的当前状态下,其速度比function randompick(indices,rates) cumrates = [sum(rates[1:i]) for i in indices] pick = rand()*cumrates[end] tick = 0 lowb = 0 highb = indis[end] while tick == 0 mid = floor(Int,(highb+lowb)/2) midrate = cumrates[mid] if pick > midrate lowb = mid else highb = mid end if highb-lowb == 1 tick = 1 end end return(highb) end 慢得多,因此缩放实际上是无关紧要的。有什么方法可以将这种方法简化为可以与randompick()竞争的形式,从而利用改进的缩放比例吗?

编辑:计算sample()的缩放比例也类似于N ^ 2,但是可以通过在整个代码中以正确的(累积的)形式使用sample()来解决。

2 个答案:

答案 0 :(得分:1)

我想尝试的一个简单版本是:

function randompick(rates)
    cumrates = cumsum(rates)
    pick = rand()*cumrates[end]
    searchsortedfirst(cumrates, pick)
end

searchsortedfirst的调用确实可以对数扩展,但是cumsum仅线性扩展,因此消除了它可能具有的任何优势。

如果rates是常数,则可以提前cumrates进行预处理,但是如果是这种情况,最好使用可以在恒定时间采样的alias tableDistributions.jl包中提供了一种实现方式:

using Distributions

s = Distributions.AliasTable(rates)
rand(s)

答案 1 :(得分:0)

我在this paper中发现了P. Hanusse的另一种采样方法,至少在允许的活动率处于相同数量级时,它似乎并不与N成比例。

这个想法是假设所有站点都具有相同的活动率,等于最活跃站点maxrate的活动率(以便将随机选择减少为单个RNG调用{{1 }}。一旦我们选择了一个站点,我们就将其(恒定)活动速率分为两个部分,即原始活动速率和“不执行”速率(第二个是恒定速率减去其原始速率)。现在我们生成第二个随机数rand(1:N)。如果为c = rand() * maxrate,我们将保留该站点选择并继续激活该站点,否则我们将返回统一的随机选择。

包含两个RNG调用的函数看起来像这样,第二个返回值确定是否必须重复调用。

c<rate[site]

这种方法的优点是,如果允许的活动速率彼此可比,则不应使用N进行缩放,因为我们只需要生成O(1)个随机数即可。