【发布时间】: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.
【问题讨论】:
从 golang 的切片中不替换的最佳采样方式是什么?
a := make([]int, 100)
for i := range a {
a[i] = i
}
# TODO sample 5 elements from a without replacement.
【问题讨论】:
如果集合大小整体相对较小,或者您要对集合的大部分进行采样,最简单的方法是打乱元素并选择第一个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])
}
【讨论】:
根据样本需要的随机性,我可能会将元素复制到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++
}
【讨论】: