【问题标题】:Julia: best way to sample from successively shrinking range?Julia:从连续缩小的范围中采样的最佳方法是什么?
【发布时间】:2017-11-26 00:00:07
【问题描述】:

我想对k 数字进行采样,其中第一个数字是从1:n 中采样的,第二个是从1:n-1 中采样的,第三个是从1:n-2 中采样的,依此类推。

我有以下实现

function shrinksample(n,k)
    [rand(1:m) for m in n:-1:n-k+1]
end

Julia 中有更快的解决方案吗?

【问题讨论】:

  • 我不认为你的功能正在做你所说的,但你所要求的仍然是一种更快的方法
  • @zombie 修复了我的代码中的错误
  • 为什么不只是[rand(1:n-m) for m in 1:k] 就像你的问题所说的那样?
  • nk 会是什么? k 会小吗(与 n 相比)?你会抽取多少样本?这些参数对于优化很重要。
  • @MichaelK.Borregaard [rand(1:n-m) for m in 0:k-1] ...

标签: random julia sample sampling


【解决方案1】:

下面的想法来自randperm的实现,由于nk是相同的顺序,这是合适的,因为需要相同类型的随机性(两者都有大小为n的输出空间阶乘):

function fastshrinksample(r::AbstractRNG,n,k)
    a = Vector{typeof(n)}(k)
    @assert n <= Int64(2)^52
    k == 0 && return a
    mask = (1<<(64-leading_zeros(n)))-1
    nextmask = mask>>1
    nn = n
    for i=1:k
        a[i] = 1+Base.Random.rand_lt(r, nn, mask)
        nn -= 1
        if nn == nextmask
            mask, nextmask = nextmask, nextmask>>1
        end
    end
    return a
end

fastshrinksample(n,k) = fastshrinksample(Base.Random.GLOBAL_RNG, n, k)

基准测试为一个测试实例提供了 3 倍的改进:

julia> using BenchmarkTools

julia> @btime shrinksample(10000,10000);
  310.277 μs (2 allocations: 78.20 KiB)

julia> @btime fastshrinksample(10000,10000);
  91.815 μs (2 allocations: 78.20 KiB)

诀窍主要是使用内部的Base.Random.rand_lt,而不是常规的rand(1:n)

【讨论】:

  • 最好也添加一个@assertk&lt;=n
  • @assert n
【解决方案2】:

如果这对随机性不是很敏感(您不是在做密码学),那么以下应该非常快速且非常简单:

blazingshrinksample(n,k) = (Int)[trunc(Int,(n-m)rand()+1) for m in 0:k-1]

与您的实现和 Dan 一起测试,我得到了这个:

using BenchmarkTools

@btime shrinksample(10000,10000);
  259.414 μs (2 allocations: 78.20 KiB)

@btime fastshrinksample(10000,10000);
  66.713 μs (2 allocations: 78.20 KiB)

@btime blazingshrinksample(10000,10000);
  33.614 μs (2 allocations: 78.20 KiB)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 2012-11-01
    相关资源
    最近更新 更多