F#中的采样:设置是否足够?
我有一系列的项目,我想从中取样 我的印象是,一个集合将是一个很好的取样结构,在一个折叠中,我将返回原始集合或一个修改过的集合,其中检索到的元素丢失,这取决于我是否希望替换掉它。 然而,似乎没有直接从集合中检索元素的方法 我有什么遗漏吗?或者我应该使用一组索引,以及一个代理函数,该函数从某个随机F#中的采样:设置是否足够?,f#,set,sampling,F#,Set,Sampling,我有一系列的项目,我想从中取样 我的印象是,一个集合将是一个很好的取样结构,在一个折叠中,我将返回原始集合或一个修改过的集合,其中检索到的元素丢失,这取决于我是否希望替换掉它。 然而,似乎没有直接从集合中检索元素的方法 我有什么遗漏吗?或者我应该使用一组索引,以及一个代理函数,该函数从某个随机位置
位置
开始,直到找到一个成员为止
就是沿着这条线,
module Seq =
let modulo (n:int) start =
let rec next i = seq { yield (i + 1)%n ; yield! next (i+1)}
next start
module Array =
let Sample (withReplacement:bool) seed (entries:'T array) =
let prng, indexes = new Random(seed), Set(Seq.init (entries |> Array.length) id)
Seq.unfold (fun set -> let N = set |> Set.count
let next = Seq.modulo N (prng.Next(N)) |> Seq.truncate N |> Seq.tryFind(fun i -> set |> Set.exists ((=) i))
if next.IsSome then
Some(entries.[next.Value], if withReplacement then set else Set.remove next.Value set)
else
None)
编辑:积极地跟踪我给出的内容,而不是跟踪我仍然可以给出的内容,这将使它更简单、更有效。对于不替换的采样,您可以只排列源序列并获取您想要采样的元素的数量
let sampleWithoutReplacement n s =
let a = Array.ofSeq s
seq { for i = a.Length downto 1 do
let j = rnd.Next i
yield a.[j]
a.[j] <- a.[i - 1] }
|> Seq.take n
对于庞大的数据集,这些可能不是最有效的方法,但是,继续我们的评论。如果您想随机对序列进行采样,而不将整个内容写入内存,则可以生成一组与所需样本大小相同的随机索引(与您已有的索引没有太大区别):
是的,我意识到如果我假设有一个数组,它将是直接的。我从集合的概念开始。我的问题用词没有意义。在你的第二部分中,应该是“取样而不替换…”吗?保罗:不,这似乎是正确的。然而,我会在那里使用Seq.unfold,因为它只是一个无限序列。添加初始列表是superfluous@nicolas我应该把代码和评论匹配起来;第一部分说的是“带替换的采样”,而那里的代码说的是
sampleWithoutReplacement
,这是我应该指出的。还将sampleWithReplacement更改为不使用初始[1..n]列表,如建议的那样“似乎没有直接从集合中检索元素的方法”你在找吗?不,我在找能给我返回一个元素的东西,要么从索引(不可能,否则集合必须维护一个对应表)要么只是一个随机元素(我猜树必须维护其子元素的计数)。我本来希望你能从一个集合中取样,但这可能是我在那些日子里过度暴露于统计数据。数组非常适合索引随机访问。是的,但结果是我有30万行的东西,我想取样1k,我们已经有一些内存问题了..那么你想随机采样一个序列吗?
let sampleWithReplacement n s =
let a = Array.ofSeq s
Seq.init n (fun _ -> a.[rnd.Next(a.Length)])
let rand count max =
System.Random()
|> Seq.unfold (fun r -> Some(r.Next(max), r))
|> Seq.distinct
|> Seq.take count
|> set
let takeSample sampleSize inputSize input =
let indices = rand sampleSize inputSize
input
|> Seq.mapi (fun idx x ->
if Set.contains idx indices then Some x else None)
|> Seq.choose id
let inputSize = 100000
let input = Seq.init inputSize id
let sample = takeSample 50 inputSize input
printfn "%A" (Seq.toList sample)