2

我有一系列项目,我想从中取样。

我的印象是 Set 是一个很好的采样结构,在折叠中我会返回原始或修改后的集合,而检索到的元素会丢失,这取决于我是否想要替换 not。但是,似乎没有直接从 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)

编辑:积极跟踪我给的东西,而不是跟踪我仍然可以给的东西,这会使它更简单、更有效。

4

2 回答 2

5

对于没有替换的采样,您可以只置换源序列并获取您想要采样的任何元素

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

要进行替换采样只需从源序列中选择一个随机元素 n 次

let sampleWithReplacement n s =
    let a = Array.ofSeq s
    Seq.init n (fun _ -> a.[rnd.Next(a.Length)])

然而,这些可能不是拥有大量数据集的最有效方法

于 2013-02-26T13:47:09.307 回答
2

继续我们的评论...如果您想随机采样一个序列而不将整个事物放入内存中,您可以生成一组随机索引,其大小与您想要的样本大小(与您已有的没有太大不同):

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)
于 2013-02-26T19:54:43.977 回答