我有一系列项目,我想从中抽样。
我的印象是,一个Set会有一个好的结构来取样,在折叠中我会回复原始或修改的集合,其中检索到的元素缺失,这取决于我是否要更换。 但是,似乎没有方法直接从Set中检索元素。
我有什么遗失的吗?或者我应该使用一组索引,以及从某个随机position < Set.count
开始的代理函数,并一直向上找到一个成员?
就是这一行
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)
编辑:积极跟踪我给出的内容,而不是跟踪我仍然可以提供的内容会使其更简单,更有效。
答案 0 :(得分:5)
对于没有替换的的采样,您可以只是置换源seq并采用您想要采样的许多元素
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中选择一个随机元素n次
let sampleWithReplacement n s =
let a = Array.ofSeq s
Seq.init n (fun _ -> a.[rnd.Next(a.Length)])
这些可能不是使用大数据集的最有效方法
答案 1 :(得分:2)
继续我们的评论...如果你想随机抽样一个序列而不将整个事物扼杀到内存中,你可以生成一组随机索引,大小与你想要的样本一样(与你已有的不同): / p>
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)