Memory 提取和收集Julia中生成器随机子样本的有效方法
考虑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] 但是这对于元素很多的生成器来说是不有效的,用这么多的元素来收集一些东
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