2

サンプリングしたいアイテムの配列があります。

私は、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 に答える