【问题标题】:Sample without replacement in golang在 golang 中无需替换的示例
【发布时间】:2018-06-13 18:42:48
【问题描述】:

从 golang 的切片中不替换的最佳采样方式是什么?

a := make([]int, 100)
for i := range a {
    a[i] = i
}

# TODO sample 5 elements from a without replacement.

【问题讨论】:

    标签: go random slice sampling


    【解决方案1】:

    如果集合大小整体相对较小,或者您要对集合的大部分进行采样,最简单的方法是打乱元素并选择第一个n

    rand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
    fmt.Println(a[:5])
    

    https://play.golang.org/p/lQx44Mn9RQL

    如果您不想打乱整个集合,但可以更改集合的顺序(或复制整个集合),您可以通过从切片中删除它们来更有效地“记录”使用的值。

    // create a copy of the slice header
    c := a
    samples := make([]int, n)
    
    for i := 0; i < n; i++ {
        r := int(rand.Int63n(int64(len(c))))
        samples[i] = c[r]
    
        // remove the sample from the copy slice
        c[r], c[len(c)-1] = c[len(c)-1], c[r]
        c = c[:len(c)-1]
    }
    

    如果集合规模很大并且您只采样一小部分,您可以通过记录样本索引而不重复它来从原始集合中进行不修改的采样。显然,随着样本大小与集合大小的比率增加,碰撞次数会增加,从而降低效率。

    例如:

    // record indexes here to prevent duplicates
    indexes := make(map[int]bool)
    
    // create n random indexes
    for i := 0; i < n; i++ {
        var r int
        for {
            r = int(rand.Int63n(int64(len(a))))
            if indexes[r] {
                continue
            }
            break
        }
    
        indexes[r] = true
    }
    
    samples := make([]int, 0, n)
    for i := range indexes {
        samples = append(samples, a[i])
    }
    

    【讨论】:

    • 这会修改原始数组,我假设“不替换”意味着原始数组不会被修改。您需要先制作一份副本。
    • @Zak:“没有替换”只是意味着不会对同一个元素进行多次采样。不能很好地修改原始切片可能是另一个要求,但此处未指定。
    • 好的,不错。直到
    • @JimB 对“无替换”的定义是正确的。但是,当 a 很大时,此解决方案的计算成本很高。
    • @alpaca:您的示例不大,这使其成为合适的解决方案。否则,您可以从原始集合中删除随机样本,或者如果您不想修改集合,只需记录样本索引并且不要重复它们。
    【解决方案2】:

    根据样本需要的随机性,我可能会将元素复制到map[T]struct{}(其中T 是结果类型)和range 中作为我的结果。

    // assume input is []int
    res := make([]int, len(input))
    desorted := make(map[int]struct{})
    
    for _, v := range input {
            desorted[v] = struct{}
    }
    
    i := 0
    for k, _ := range desorted {
            res[i] = k
            i++
    }
    

    【讨论】:

      猜你喜欢
      • 2011-09-26
      • 2023-02-20
      • 1970-01-01
      • 2012-08-02
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 2012-02-25
      • 1970-01-01
      相关资源
      最近更新 更多