【问题标题】:How to randomly generate decreasing numbers in Python?如何在 Python 中随机生成递减数字?
【发布时间】:2013-01-10 15:06:50
【问题描述】:

我想知道是否有办法在一定范围内生成递减数字? 我想编程一直输出到0,范围内的最大数必须是正数。

例如,如果范围是 (0, 100),这可能是一个可能的输出: 96 57 43 23 9 0

对不起,我原来的帖子造成了混乱

【问题讨论】:

  • 您的意见是什么?您是否需要能够指定或保证输出多少个数字?生成的所有数字都应该是唯一的吗?
  • 另外,你想要整数吗?浮点值?范围是否可以包含 0 或负值?
  • 这个问题的语义似乎产生了各种各样的答案。是减少的范围还是只是数字?您是在寻找生成器,还是只对生成数字列表感到满意。
  • @Fiona,你知道随机变量概率分布吗?如果没有,请找一本标题为“概率导论”的数学书,然后阅读第一章。然后,您将拥有准确表达问题的语言,以及(如果您进一步阅读)解决问题的方法。
  • 我必须运行一个循环,不断发送数字直到它达到 0。所以范围可以从 0 到一个非常大的数字。以下是一个简短的列表作为示例:105、97、43、35、29、18、3、0。

标签: python random python-2.7 numbers


【解决方案1】:

我会生成一个包含 n 个随机数的列表,然后将它们从高到低排序。

【讨论】:

  • 这不会像每次在更窄的范围内生成一个新数字那样随机。
  • “随机”是一个相当模糊的术语。我会说这将是一种不同类型的随机性。我认为这将是统一的。
  • @hayden 是的,我认为,随着时间的推移,使用这种方法超过钳制到最后生成的值,你会在初始范围内获得更统计上的均匀分布。但它确实牺牲了效率。
  • 没错。这个解决方案是统一的,而另一个则绝对不是。此外,优化它也很容易——您可以按顺序添加新元素,而不是排序。
  • 关于 Fiona 是否想要生成器或生成数字的问题是模棱两可的。这是我的回答,因为她只想让他们在现场生成。
【解决方案2】:

几乎没有什么需要注意的。从X > 0 开始并在每个步骤中从(0,X) 中获取一个随机数并用它替换X 的算法是不好的。为什么?因为(假设random 行为正常)每一步的预期值都在区间(0,X) 的中间。这意味着这些数字的序列预计收敛到0 的速度与(1/2)^N 一样快。确实可以很容易地看出,大多数数字都接近0,即使是巨大的初始价值。这意味着这些数字的分布并不均匀,这是大多数时候所期望的属性。

这是一个主要缺点,尽管生成 Nth 数字的复杂性是 O(N) 并且(更重要的是)内存使用量是 O(1)

另一种解决方案是只取N 随机数并对其进行排序。这还不错,虽然这个算法的复杂度是O(N log(N))(或者说和底层排序算法的复杂度一样),如果我们把元素按顺序排列而不是排序,它可以降低到O(N),但是内存使用是O(N) - 我们必须记住所有元素。但是这些数字会均匀分布,这是一个很大的优势!

按照 Jon Louis Bentley 的论文“Generating sorted lists of random numbers”中的想法,这里的算法可能是最优化的算法(至少我知道)并产生均匀分布的数字:

import math
import random

def generate( min = 0, max = 10, number = 100 ):
    start = 0
    for i in xrange( number, 0, -1 ):
        start = start + math.log( random.random( ) ) / i
        next = math.exp( start ) * ( max - min ) + min
        yield next

for number in generate( ):
    print number

请注意,这个算法的复杂度仍然是O(N)(我怀疑它会变得更低),但内存使用量是O(1),并且这些数字均匀分布在(min,max) 的区间内,这并不明显,但确实如此。唯一的缺点是我们必须在开始之前知道要生成多少个数字。

也可以看看这个帖子:

Generating sorted random ints without the sort? O(n)

可能有用。

【讨论】:

  • 谢谢您,您的代码运行良好,但是有没有办法只生成整数或者它们必须是浮点数以避免重复?
  • @FionaKwok 好吧,你总是可以产生 next 的整数部分,并且只有当它与之前的 next 产生的值不同时才这样做。但是,您无法控制将获得多少整数,但是由于分布仍然是均匀的,因此您将明确地获得一些。因此,如果您想控制一切,那么可能会生成随机值并将它们按顺序排列就是这样做的方法。
【解决方案3】:

喜欢:

from random import random
min=0
max=10
oldval=1.

while True:
  oldval=oldval*random()
  randval=min+(max-min)*oldval

【讨论】:

  • 这非常可靠,只要您尝试生成浮点值,或者您不介意整数重复,并且您对控制输出数量不感兴趣。
  • 这个解决方案同样的问题:收敛到0的速度非常快,分布根本不均匀。
  • 肯定的;但它没有说明需要统一分布
【解决方案4】:

这里有一些选择。这应该会产生接近卡方分布的值,之后的值会从比之前的值更小的范围中选择:

import random
random_range = range(10) 
numbers = [random.choice(random_range[:i]) for i in range(10, 0, -1)]

这也可以用浮点数来完成:

import random
max = 10.0
min = 0.0
desired = 100
step = (max - min) / desired
numbers = [random.random() * (max - (i * step)) for i in range(desired)]

或者,从递减的滑动窗口中选择随机值可以提供均匀分布。

import random, numpy
max = 10.0
min = 0.0
desired = 100
step = float(min - max) / desired
window = 1.0
numbers = [x + (random.random() * window) - (window / 2.0) for x in numpy.arange(max, min, step)]

如果需要单调递减的数字列表,则设置window <= step 将提供一个。祝你好运!

【讨论】:

  • -1:完全没有减少。例如,它可能以2, 5 开头。
  • 阅读 OP。它没有说生成递减数字的列表,而是生成递减范围内的数字。
  • 很公平。我将撤消 -1,但我真的怀疑这是否是 OP 正在寻找的。​​span>
  • 也许不是。但是 OP 并不清楚他们在寻找什么。
【解决方案5】:

基于@brentlance 的想法,这将适用于任何整数范围,正数、负数或两者兼有:

import random

random_decreasing_integers_from_range = (i for i in xrange(max, min - 1, -1) if random.random() > .5)

如果您希望能够指定输出的数量,这里有一个尝试,至少尝试保持整个范围内的分布有点均匀:

import random

def random_decreasing_integers_from_range(min, max, num_outputs):
    range_size = abs(max - min)
    if range_size < num_outputs:
        raise ValueError('Distance from min to max must be equal to or greater than num_outputs.')
    output_count = 0
    for iteration, value in enumerate(xrange(max, min - 1, -1)):
        # if we only have enough values left to satisfy the number requested,
        # yield value
        if num_outputs - output_count == range_size - iteration + 1:
            output_count += 1
            yield value
        # else yield value randomly, weighted by how far in to the range we are
        # and how many values we have left to yield of the total requested
        else:
            ratio_consumed = float(iteration + 1) / range_size
            ratio_yielded = float(output_count) / num_outputs
            if random.random() < (1 - ratio_yielded) * ratio_consumed:
                output_count += 1
                yield value
        # if we've yielded the requested number of values, stop
        if output_count == num_outputs:
            break

这工作得相当好,但是当 num_outputs 不在 range_size 的 10% 到 25% 之间时,它似乎会崩溃。在下限,偏向范围的中间部分确实显示出来,而在上限,短路条件开始导致结果真正偏向范围的下限。

【讨论】:

  • 我一直在研究一个使用 itertools 的更详细的版本,但我将其简化为这个并忘记删除导入。现已删除。
【解决方案6】:

谢谢大家的回答。但是我找到了解决我自己问题的方法,我认为这很简单,我想与大家分享。

import random
i = 1000000  

while i > 0:
    i = random.randint(0, i)
    print i

【讨论】:

    【解决方案7】:

    这将使您在 0..1 范围内递减随机数。

    import random
    def generate():
        n = 1.0
        while n:
            n = random.random() * n
            yield n
    iterator = generate()
    iterator.next()
    

    请注意,由于浮点数的精度有限,数字不可避免地会达到 0,因此该函数会在一段时间后停止生成数字。

    【讨论】:

      【解决方案8】:

      不是 python 专家...但这是我的基本想法:

      a=10000
      for i in range(1,50):
         b=random.randint(1,a)
         print(b)
         a=b
      

      【讨论】:

      • 请注意这个解决方案的一个很大的弱点:因为在每一站你都会缩短范围,然后它会收敛到1(而且它做得非常快,实际上是指数级的)。所以分布根本不均匀,对于足够大的范围(1000?),大多数元素将只是 1。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-13
      • 1970-01-01
      • 2021-09-23
      • 2021-11-29
      • 2013-11-13
      • 1970-01-01
      • 2018-06-23
      相关资源
      最近更新 更多