【问题标题】:Random Number Generator with given Interval and Mean in Python not C#Python中给定区间和平均值的随机数生成器不是C#
【发布时间】:2017-07-11 15:49:23
【问题描述】:

我正在使用 Python 2.7.12Anaconda 4.2.0 (64-bit)。尝试使用 random 包生成随机数。我需要在interval 中生成n 数字,它们的平均值应该是specified value。例如:

我希望1442,00091,000 之间随机生成数字,并且我希望这些数字的平均值为60,000

我知道如何使用随机数产生整数:

random.randint(42000, 91000)

我可以把它放在一个 for 循环中,但是,我怎样才能将它们的平均值调整为 60,000

【问题讨论】:

  • 它们应该如何分发?高斯?
  • 如何完全随机生成它们,计算它们的平均值,最后稍微移动它们以获得所需的结果?
  • @JacobG python != c#
  • 想要一组具有特定属性的随机数(“它们的平均值应为 60”)的问题是这两个方面相互矛盾。您可以有一个随机数生成器,它将产生围绕给定平均值的随机数。如果你取其中的 14 个,那一组会有不同的平均值。

标签: python random


【解决方案1】:
while True:  # until a good sample was found
  s = [ random.randint(42000, 91000) for _ in range(13) ]
  v = 60000 + (60000 - (sum(s) / len(s))) * 13
  if 42000 <= v <= 91000:
    s.append(v)
    break
print sum(s) / len(s)  # will print 60000

这会从标准生成器创建 13 个随机值并计算第 14 个值,因此平均值正好是 60000。由于第 14 个值可能不在给定范围内,它会一次又一次地尝试此操作,直到可能出现有效的第 14 个值.

这既不优雅也不好看。但问题也是如此。

编辑:

这种方法适用于给定的数字,但由于它正在重试某些内容,因此它可能会无限期地针对不同的数字运行(例如 range = [42k, 91k],mean = 60k,count = 100k)。

如果您随机创建 99999 个元素,它们的平均值将在 (42k+91k)/2 左右,并且用于将其平衡回 60k 的单个元素是不够的(因此总是在范围之外)。您可以使用稍微复杂一点的随机数生成器,生成 42k 到 91k 之间的随机数,平均值为 60k(如果您不知道如何操作,请询问另一个问题!)。使用这个其他随机数生成器将提高您终止的机会。

提高终止机会从而找到结果的第二种方法是用更小的块构建结果,每个块都具有希望的平均值:使用我介绍的方法创建 5000 个 20 个元素的块。

当然,你可以将这两种方法结合起来。

【讨论】:

  • 这是对一个矛盾问题的最佳答案。 @user8028576,您要求使用 a=42000b=91000 构建离散均匀分布。问题是,从数学上讲,这个分布的平均值应该是 (a + b) / 2 = 66,500,或者是 ab 的平均值,而不是 60,000。所以你将你的分布描述为 random 而不是;它表现出偏度以符合您想要的较低均值。
  • 回答我的问题。谢谢@Alfe。
  • 平均值不应为 66,500,因为不仅有两个(最小和最大)数字。有 14 个数字。
  • @BradSolomon OP 根本没有提到均匀分布。 [a, b] 范围内的随机数仍然可以具有均值 c ≠ mean(a, b)。考虑随机()*随机()。这将在 [0, 1] 范围内,但平均值为 0.25,并且所有数字都是完全随机的。我考虑过想出一个花哨的公式,但由于 OP 不希望 distribution 具有特定的平均值,而是希望 sample 具有特定的平均值,因此无论如何这都无济于事。
  • 我意识到您的公式对于大量n(例如150)不是很有效。还有其他建议吗?
【解决方案2】:

有很多方法可以在两个值和特定平均值之间生成随机数。 Python 已经为其中一些方法内置了方法,但是当我说有很多方法时,我是认真的。

最简单的方法是使用三角分布。 random.triangular(low, high, mode) 将从低和高之间的分布中产生一个数字,具有指定的模式。这可能已经足够了,但如果你真的想要一个平均值,你可以使用以下函数:

def triangular_mean(low, high, mean):
    mode = 3 * mean - low - high
    return random.triangular(low, high, mode)

如果您想变得更复杂,可以通过调用random.beta(alpha,beta) 来使用测试版分发。这些真的很灵活而且很奇怪;这张来自 Wikipedia 的图片突出了它们的奇怪之处。

beta 分布的平均值为alpha/(alpha+beta),结果始终介于 0 和 1 之间,因此要将其扩展到您的用例,让我们将其封装在这个函数中:

def beta_mean(low, high, mean, alpha):
    offset = low
    scale = high - low
    true_mean = (mean - offset)/scale
    beta = (alpha/true_mean) - alpha
    return offset + scale * random.beta(alpha, beta)

在上面的函数中,alpha会改变分布的形状而不改变均值;它会改变分布的中位数、众数、方差和其他属性。

您可以将其他发行版包装在函数中以适合您的用例,但我猜以上两个将适合您想要的任何用例。

这些也会产生浮点数,因此如果您需要整数,则必须将它们转换为整数,方法是编辑函数或在调用它们后显式转换它们。

【讨论】:

  • 我相信 OP 有兴趣修复 sample 平均值而不是 population 平均值。
  • 可能我无法获得该功能。但是,当我运行它一次时,我想它应该产生 60,000,因为我们预计它的意思是 60,000。但是,它会产生 50585.37639745854,一个并非真正接近 60,000 的随机数。
猜你喜欢
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-02
相关资源
最近更新 更多