Python 创建一个范围内的随机整数序列,并且它们之间的距离最小

Python 创建一个范围内的随机整数序列,并且它们之间的距离最小,python,numpy,random,Python,Numpy,Random,生成在特定范围内均匀分布且每个元素之间距离最小的随机值整数的特定nr的最快方法是什么 例如,给定一个介于0和20之间的序列范围,我们希望创建5个元素,每个元素之间至少有3个点的距离,结果可能是这样的[0,5,11,14,19]或[2,5,9,13,18] 我创建了一个循环来实现这一点,但是当我想要创建数百万个范围时,它非常慢 这是: np.cumsum(np.ones((5,), np.int) * 3 + np.random.randint(0, maxn, (5,))) - 3 将给你5个

生成在特定范围内均匀分布且每个元素之间距离最小的随机值整数的特定nr的最快方法是什么

例如,给定一个介于0和20之间的序列范围,我们希望创建5个元素,每个元素之间至少有3个点的距离,结果可能是这样的
[0,5,11,14,19]
[2,5,9,13,18]

我创建了一个循环来实现这一点,但是当我想要创建数百万个范围时,它非常慢

这是:

np.cumsum(np.ones((5,), np.int) * 3 + np.random.randint(0, maxn, (5,))) - 3
将给你5个随机数,间隔至少3点

您必须调整
maxn
以获得正确的随机数最大值。也许您可能想要稍微大一点的
maxn
,并且拒绝元素超过最大值(20)的样本


注意:您没有说明您要寻找的最终分布,例如,如果您希望结果样本均匀分布在有效样本的空间上,或者其他任何情况,如果这很重要的话。

以下方法如何:如果您希望5个相邻元素之间的间距为3,但希望总范围为20,然后你就有了
20-(5-1)*3个“松弛”步骤,你可以在元素之间的间隙中随机分配这些步骤。假设我们在该范围内生成一个数字,并将其分散在元素之间,那么我们最终得到如下代码:

import numpy, random

n = 5
limit = 20
mingap = 3

slack = 20 - mingap * (n - 1)

def generate():
    steps = random.randint(0, slack)

    increments = numpy.hstack([numpy.ones((steps,)), numpy.zeros((n,))])
    numpy.random.shuffle(increments)

    locs = numpy.argwhere(increments == 0).flatten()
    return numpy.cumsum(increments)[locs] + mingap * numpy.arange(0, n)
[  0.   3.   6.   9.  12.]
[  0.   3.   6.  10.  13.]
[  2.   5.   8.  12.  15.]
[  1.   4.   7.  12.  16.]
[  0.   4.   7.  10.  13.]
[  0.   3.   6.   9.  12.]
[  1.   4.   9.  12.  16.]
[  0.   7.  10.  13.  16.]
[  0.   5.   8.  11.  14.]
[  1.   4.   8.  11.  17.]
如果随后调用此
generate()
函数十次,将得到一组向量,如下所示:

import numpy, random

n = 5
limit = 20
mingap = 3

slack = 20 - mingap * (n - 1)

def generate():
    steps = random.randint(0, slack)

    increments = numpy.hstack([numpy.ones((steps,)), numpy.zeros((n,))])
    numpy.random.shuffle(increments)

    locs = numpy.argwhere(increments == 0).flatten()
    return numpy.cumsum(increments)[locs] + mingap * numpy.arange(0, n)
[  0.   3.   6.   9.  12.]
[  0.   3.   6.  10.  13.]
[  2.   5.   8.  12.  15.]
[  1.   4.   7.  12.  16.]
[  0.   4.   7.  10.  13.]
[  0.   3.   6.   9.  12.]
[  1.   4.   9.  12.  16.]
[  0.   7.  10.  13.  16.]
[  0.   5.   8.  11.  14.]
[  1.   4.   8.  11.  17.]

这个答案是对我先前答案的后续评论

你说你想要均匀分布的数字,但这当然是不可能的,因为这些数字必须至少间隔3个点

因此,我为您提供了一致随机性的不同定义:假设您可以枚举所有与您的条件相关的有效向量。为此,我编写了一个函数:

def space_gen(xmin, xmax, len, min_dist, result=[]):
    if len:
        for x in range(xmin, xmax - (len - 1) * min_dist):
            yield from space_gen(x + min_dist, xmax, len - 1, min_dist, result + [x])
    else:
        yield result
让我们考虑一下这个问题的一个较小的例子。假设您需要3个从0到10(不包括)的随机数向量,间距至少为4点:

>>> list(space_gen(0,10,3,4))
[[0, 4, 8], [0, 4, 9], [0, 5, 9], [1, 5, 9]]
该列表是根据该规则的所有有效结果的完整枚举

现在,您可以从此列表中统一采样(请参见示例)

现在,您的问题大小(即范围或向量大小)可能会使问题实例太大而无法穷举

但您仍然可以使用此“暴力”枚举来检查方法是否生成真正均匀分布的样本

对于问题实例(0-20范围,5长度,3分钟距离),仍然可行:

>>> len(list(space_gen(0,21,5,3)))
1287
例如,我们可以检查rwp的配方是否生成均匀分布的样本(根据此定义):

我们观察到这种计数分布:

显然,有些向量比其他向量更频繁地出现

我们还可以检查我提出的第一个解决方案:

def generate1():
    maxn=15
    while 1:
        x = np.cumsum(np.ones((5,), np.int) * 3 + np.random.randint(0, maxn, (5,))) - 3
        if x[-1] <= 20:
            return x
def generate1():
最大值=15
而1:
x=np.cumsum(np.one((5,),np.int)*3+np.random.randint(0,maxn,(5,))-3

如果x[-1],则不明显可以选择一个固定的
maxn
,以保证序列中的最大值不大于20。将较大的值设置为
maxn
可能会使值的分布偏离零,这可能不是OP想要的。嗯,我现在尝试了不同的设置,但我不知道如何获得我正在查看的序列for@rwp:请澄清。你的意思是如果这样做和拒绝抽样?因为如果
maxn
的值很高,您将不得不拒绝大量样本,如果我理解正确的话,这是OP首先想要避免的。@RaduS:maxn
=3时,您或多或少会得到您想要的。使用
maxn
=10更“公平”,尽管您必须拒绝最后数量超过20的样本。数字的最终分布在某种程度上是相关的吗?你不能让结果的数字均匀分布,同时遵守最小距离的条件,因为这将删除一些组合,例如[0,0,0,0,0]或[0,2,4,6,8],因此每个分布不能是均匀随机的。但是,如果您列举了有效的配置,那么您可以从中统一采样。我将添加另一个答案来提供一个例子,如果这对您有效…起点的条件是什么,以及您如何定义它们之间的步骤?!!起点可以是任何接近最小距离的值,在这种情况下,它可以是,0,1,2,3,4,5,6。它们之间的距离是最小距离加上随机距离,但不够大,以至于其他数字无法容纳–为什么这个值准确,你是如何计算最小距离的?最小距离只是条件的一部分,它是给定的。例如,“最小距离”(min distance)将永远不会变大,因此元素将不适合给定的序列。是要均匀分布,还是要强制使用最小距离?你不能两者兼得。好吧,谢谢@rwp,这看起来真的很有趣,我会用它做更多的测试,但到目前为止,看起来像是我所期待的,经过一些调整,这就是我所期待的。我只是在上面加了一些过滤器,效果非常好。非常感谢。