Memory 提取和收集Julia中生成器随机子样本的有效方法

Memory 提取和收集Julia中生成器随机子样本的有效方法,memory,iteration,julia,generator,Memory,Iteration,Julia,Generator,考虑Julia中的一个生成器,如果收集它,将占用大量内存 g=(x^2 for x=1:9999999999999999) 我想随机抽取一个小样本(比如说1%),但我不想收集()对象,因为这会占用大量内存 直到现在,我使用的技巧是 temp=collect((( rand()>0.01 ? nothing : x ) for x in g)) random_sample= temp[temp.!=nothing] 但是这对于元素很多的生成器来说是不有效的,用这么多的元素来收集一些东

考虑Julia中的一个生成器,如果收集它,将占用大量内存

g=(x^2 for x=1:9999999999999999)

我想随机抽取一个小样本(比如说1%),但我不想收集()对象,因为这会占用大量内存

直到现在,我使用的技巧是

temp=collect((( rand()>0.01 ? nothing : x ) for x in g))
random_sample= temp[temp.!=nothing]

但是这对于元素很多的生成器来说是不有效的,用这么多的元素来收集一些东西似乎是不对的

任何想法都将受到高度赞赏。我想诀窍是能够从生成器中获取随机元素,而不必为所有元素分配内存


非常感谢

如果发电机的状况如下则可以使用发电机:

[v for v in g if rand() < 0.01]
编辑

这里有自我避免采样器和水库采样器的示例,它们为您提供固定的输出大小。您希望得到的输入越小,使用自回避采样器就越好:

function self_avoiding_sampler(source_size, ith, target_size)
    rng = 1:source_size
    idx = rand(rng)
    x1 = ith(idx)
    r = Vector{typeof(x1)}(undef, target_size)
    r[1] = x1
    s = Set{Int}(idx)
    sizehint!(s, target_size)
    for i = 2:target_size
        while idx in s
            idx = rand(rng)
        end
        @inbounds r[i] = ith(idx)
        push!(s, idx)
    end
    r
end

function reservoir_sampler(g, target_size)
    r = Vector{Int}(undef, target_size)
    for (i, v) in enumerate(g)
        if i <= target_size
            @inbounds r[i] = v
        else
            j = rand(1:i)
            if j < target_size
                @inbounds r[j] = v
            end
        end
    end
    r
end
函数自\u避免\u采样器(源\u大小、第i个、目标\u大小)
rng=1:源大小
idx=兰特(兰特)
x1=ith(idx)
r=向量{typeof(x1)}(未定义,目标大小)
r[1]=x1
s=集合{Int}(idx)
sizehint!(s,目标尺寸)
对于i=2:目标尺寸
而idx在s
idx=兰特(兰特)
结束
@边界内r[i]=ith(idx)
推(s,idx)
结束
R
结束
功能储液罐\u取样器(g,目标\u尺寸)
r=向量{Int}(未定义,目标大小)
对于枚举(g)中的(i,v)

但是,如果我?这种方法不能保证每次使用完全相同数量的项目(例如,约1%的项目)(如问题中所暗示的),而是选择项目,使每个项目有1%的机会被选中。这是问题中使用的算法,因此我认为这不应改变。我只是改变了方法,以表明您不必收集发电机。如果您想获得结果的精确大小,根据输入的性质,有几种可能的选项。储层取样是@phg指示的一种选择。在这种情况下,简单的自避免采样应该是快速的,但它需要索引到生成器中。我将在答案中添加这样一个例子。这是一个真正优雅的
水库采样器
实现!根本没有不直观的划分。
function self_avoiding_sampler(source_size, ith, target_size)
    rng = 1:source_size
    idx = rand(rng)
    x1 = ith(idx)
    r = Vector{typeof(x1)}(undef, target_size)
    r[1] = x1
    s = Set{Int}(idx)
    sizehint!(s, target_size)
    for i = 2:target_size
        while idx in s
            idx = rand(rng)
        end
        @inbounds r[i] = ith(idx)
        push!(s, idx)
    end
    r
end

function reservoir_sampler(g, target_size)
    r = Vector{Int}(undef, target_size)
    for (i, v) in enumerate(g)
        if i <= target_size
            @inbounds r[i] = v
        else
            j = rand(1:i)
            if j < target_size
                @inbounds r[j] = v
            end
        end
    end
    r
end