在一个范围内生成均匀分布的倍数/样本
问题的具体实例
我有一个从1到100的整数范围。我想在此范围内生成n个总数,即尽可能均匀分布并包括第一个和最后一个值。在一个范围内生成均匀分布的倍数/样本
例
start = 1, end = 100, n = 5
Output: [1, 25, 50, 75, 100]
start = 1, end = 100, n = 4
Output: [1, 33, 66, 100]
start = 1, end = 100, n = 2
Output: [1, 100]
我现在有
其实我有一个工作的做法,但我一直觉得我是在想这和失去了一些东西更加简单?这是最有效的方法,还是可以改进?
def steps(start, end, n):
n = min(end, max(n, 2) - 1)
mult = end/float(n)
yield start
for scale in xrange(1, n+1):
val = int(mult * scale)
if val != start:
yield val
注意,我保证,这个函数总是返回至少范围的下限和上限值。所以,我强制n >= 2
只是为了搜索引用,我用这个来从渲染的序列中采样图像帧,你通常需要第一个,中间,最后一个。但我希望能够更好地处理真正长的图像序列并获得更好的覆盖。
解决:从选择的答案
我结束了使用@ vartec的回答这个稍作修改的版本,是一台发电机,并帽安全n
值:
def steps(start,end,n):
n = min(end, max(n, 2))
step = (end-start)/float(n-1)
return (int(round(start+x*step)) for x in xrange(n))
您需要适当的四舍五入:
def steps(start,end,n):
if n<2:
raise Exception("behaviour not defined for n<2")
step = (end-start)/float(n-1)
return [int(round(start+x*step)) for x in range(n)]
使用range有什么问题?这里是你如何使用它
>>> def steps(start,end,n):
return [start]+range(start-1,end,end/(n-1))[1:]+[end]
>>> steps(1,100,5)
[1, 25, 50, 75, 100]
>>> steps(1,100,2)
[1, 100]
>>>
>>> from itertools import count
>>> def steps(start,end,n):
yield start
begin = start if start>1 else 0
c = count(begin,(end-begin)/(n-1))
next(c)
for _ in range(n-2):
yield next(c)
yield end
>>> list(steps(1,100,2))
[1, 100]
>>> list(steps(1,100,5))
[1, 25, 50, 75, 100]
>>> list(steps(1,100,4))
[1, 33, 66, 100]
>>> list(steps(50,100,3))
[50, 75, 100]
>>> list(steps(10,100,10))
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
可缩短至
>>> from itertools import islice, count
>>> def steps(start,end,n):
yield start
begin = start if start>1 else 0
c = islice(count(begin,(end-begin)/(n-1)),1,None)
for _ in range(n-2):
yield next(c)
yield end
问题使用range
是步骤必须是整数,并让你获得四舍五入问题,如steps(1,100,4) == [1, 33, 66, 100]
。如果你想要整数输出,但想尽可能多的步骤,使用浮动作为你的步骤。
>>> def steps(start,end,n):
... step = (end-start)/float(n-1)
... return [int(round(start+i*step)) for i in range(n)]
>>> steps(1,100,5)
>>> [1, 26, 51, 75, 100]
>>> steps(1,100,4)
>>> [1, 34, 67, 100]
>>> steps(1,100,2)
>>> [1, 100]
>>>
额外的依赖,或许矫枉过正,但短,测试,应该给出正确的结果:numpy.linspace
>>> numpy.linspace(1, 100, 4).astype(int).tolist()
[1, 34, 67, 100]
啊真酷!我想在这种情况下限制我的依赖关系,但我投了赞成票并记住这是可用的。谢谢! – jdi 2012-04-10 16:15:29
您的代码不处理'名单(步骤(50,100,3))' – jamylak 2012-04-10 08:26:40
'[1,33,66,100]'不是最可能的,它应该是'[1,33,67,100]',毕竟66.66(6)应该是四舍五入,不会下降。 – vartec 2012-04-10 09:03:03
例如2你的号码没有均匀分布(见我的答案)还是我想念什么? – bmu 2012-04-10 09:05:26