在golang中没有替换的样本

时间:2018-06-13 18:42:48

标签: go random slice sampling

在没有从golang中的切片替换的情况下采样的最佳方法是什么?

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

# TODO sample 5 elements from a without replacement.

2 个答案:

答案 0 :(得分: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])
}

答案 1 :(得分:0)

根据样本的随机性,我可能会将元素复制到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++
}