我有一个N
元素的列表,我想要采样尽可能均匀的M (<= N)
值。更具体地说,选择应该最小化采样点之间的间距差异。例如,假设我正在构造一个布尔索引数组(即在python
中)来选择元素,
我尝试了算法(来自这个类似但不同的问题:How do you split a list into evenly sized chunks?) :
q, r = divmod(N, M)
indices = [q*jj + min(jj, r) for jj in range(M)]
有时效果很好:
N=11 M=6
good_index = [0 1 0 1 0 1 0 1 0 1 0]
N=14 M=6
good_index = [0 1 1 0 1 1 0 1 0 1 0 1 0 1]
这里,第一个例子是微不足道的,因为阵列可以被均匀地划分。第二个例子不能均匀划分,但点之间的间距尽可能相似(2,2,1,1,1,1)。
但通常效果不佳:
N=16 M=10
bad_index = [0 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0]
N=14 M=10
bad_index = [0 1 0 1 0 1 0 1 0 0 0 0 0 0]
因为你最后堆积了价值。
编辑1:woops,只是意识到上面的每个列表在技术上是倒置的(0应该是1,反之亦然)....但仍然应该传达正确的想法。
编辑2:上述算法往往效果更好(即选择随机数的视觉检查比概念上更简单的算法,
step = int(floor(N/M))
last = M * step # this prevents us from getting M+1 elements
indices = [ii for ii in range(0, last, step)]
答案 0 :(得分:2)
查看一些测试的结果(甚至包括上面的测试结果),问题出在M > N/2
时。即当超过一半的值被采样时。但它适用于M < N/2
。所以我现在使用的解决方案只是在M > N/2
:
注意:这实际上是为N
元素创建一个大小为M
的 False 的屏蔽列表,尽可能均匀分布。 < / p>
import numpy as np
def even_select(N, M):
if M > N/2:
cut = np.zeros(N, dtype=int)
q, r = divmod(N, N-M)
indices = [q*i + min(i, r) for i in range(N-M)]
cut[indices] = True
else:
cut = np.ones(N, dtype=int)
q, r = divmod(N, M)
indices = [q*i + min(i, r) for i in range(M)]
cut[indices] = False
return cut
如果它们存在,我仍然会对更优雅的解决方案感兴趣。