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

时间:2018-04-20 18:54:49

标签: python numpy random

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

例如,假设序列范围在0到20之间,我们想要创建5个元素,每个元素之间至少有3个点距离,结果可能类似于[0,5,11,14,19][2,5,9,13,18] < / p>

我创建了一个实现此目的的循环,但是当我想创建数百万的范围时它非常慢。

3 个答案:

答案 0 :(得分:1)

此:

np.cumsum(np.ones((5,), np.int) * 3 + np.random.randint(0, maxn, (5,))) - 3

会给你5个随机数,间隔至少3个点。

您必须调整maxn才能获得随机数的正确最大值。也许您可能希望稍微大一些maxn以及其元素超过最大值(20)的拒绝样本。

注意:您没有说明您要查找的最终分发版本,例如如果您希望结果样本在有效样本的空间内均匀分布,或其他任何内容,如果这很重要。

答案 1 :(得分:1)

以下方法如何:如果你想在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)

如果您再调用此generate()函数十次,则会得到一组向量,如下所示:

[  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.]

答案 2 :(得分:1)

这个答案是我之前回答的评论的后续内容。

你说你想要均匀分布的数字,但当然这是不可能的,同时尊重数字必须间隔至少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]]

该列表是根据该规则的所有有效结果的完整枚举。

现在您可以从此列表中统一采样(请参阅示例random.choice)。

现在问题大小(即范围或矢量大小)可能使问题实例太大而无法详尽枚举。

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

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

>>> len(list(space_gen(0,21,5,3)))
1287

例如,我们可以检查rwp的配方是否生成均匀分布的样本(根据此定义):

space = list(space_gen(0, 21, 5, 3))
counter = {tuple(x): 0 for x in space}
for _ in range(200000):
    x = tuple(map(int,generate()))
    counter[x] += 1
import matplotlib.pyplot as plt
a = np.array(sorted(counter.values()))
plt.hist(a, bins=len(space))
plt.show()

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

histogram plot

显然,有些向量比其他向量更常出现。

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

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

即使使用maxn = 15并使用拒绝采样,它仍然有点偏斜并且不完全一致。使用与以前相同的基准/绘图代码:

histogram plot