我的问题不是关于特定语言,而是如何解决问题。
如何生成随机数但出现的概率不同,例如,
5 --> 63%
10 --> 29.99%
25 --> 7%
50 --> 0.01%
80 --> 0.0001%
百分比以游戏为例,仅此而已。
我的问题不是关于特定语言,而是如何解决问题。
如何生成随机数但出现的概率不同,例如,
5 --> 63%
10 --> 29.99%
25 --> 7%
50 --> 0.01%
80 --> 0.0001%
百分比以游戏为例,仅此而已。
一种相当通用的方法是在数据结构中(例如在两个单独的列表中)包含要生成的可能数字以及每个数字的可能“相对权重”,例如它们出现的百分比概率。
从权重列表中,我们得到一个概率列表。我们必须确保概率加起来为 1,因此在包含这些权重的列表中,我们可以将每个元素除以所有元素的总和。
从概率列表中,我们构建了另一个“累积”概率列表,对于每个元素,它是其概率加上所有先前概率的总和。
例如,如果输入列表是:
“重新调整”的权重将是:
累积概率为:
因此,一旦我们有了后者,算法将是:
acumuladas
,找到第一个超过上一节得到的数字的元素的索引(在例子中,第一个满足的数字是0.92989907,其索引为1)datos
具有该索引的那个(继续示例,所选的一个将是datos[1]
10。如果第一步生成均匀分布在 0 和 1 之间的随机数,该算法将选择
datos
具有指定概率的数字。扩大
如果有人觉得它有用,并且为了与其他语言进行比较,这里有一个 Python 中的可能实现:
为了了解它是如何进行的,我生成了 10,000 个具有给定分布的随机数,并计算每个随机数出现的次数:
同事@abulafia 在我前面,但由于他已经用 C# 编写了演示该方法的代码,所以我将其留在这里。
基本上,方法是一样的。关于:
1-有两个大小相等的集合,一个带有值,另一个带有概率
2- 计算累积权重,即对于每个数组位置,放置该位置的值加上之前的总和。
3- 得到一个介于0和权重值之和之间的随机数(理想情况下为1)
4- 获得大于得到的随机数的第一个值的索引,即选择的值的索引。
让我们来看看代码:
正如您在此示例中所看到的,我随机滚动 10,000 次以查看该方法是否正常工作。这是运行输出的示例:
如您所见,此方法可以很好地适应输入百分比。
要生成离散随机变量,有两种情况:第一种情况已经开发 -有替换- 第二种情况没有替换。
有人提到灵感来自游戏,我想到了扑克牌。这些在分发之前被打乱或排列,后者不应与变量的变化或蒙蒂霍尔问题混淆,因为概率随每次提取而变化。
继续纸牌的情况,开始时获得任何纸牌的概率为 1/54,第二次抽到的概率为 1/53,依此类推。
取以下输入值
假设我们需要提取三个数据。
在第一次提取之前,有一个累积概率图,这与在这个趋势中已经被详细替换的情况相同。 生成伪随机数0.725... - 介于 0 和 1- 之间时,它位于纵坐标轴(y 轴)上,它对应于横坐标的数字 10(x 轴)
由于 10 出现,剩余的概率被相加,然后这个结果除以它们中的每一个......就像在卡片的例子中一样,54 个中的一个出现,我将所有剩余的概率相加,得到 53 和总数将每张牌除以 1/53。
因此,第二次提取的输入数据如下:
作为它的图形表示:
当数字 5 出现时,输入数据及其相应的概率图,如果需要进行第三次提取,则保持这样的状态。
提取带有样本的名称,并且正是这个数量进入循环 - 作为条件 - 直到提取所需的数据。
总结算法可以表述如下:
我们有数据 ( d )、它的概率 ( p )、样本大小 ( m ) 和当前提取量 ( q ),最初为零
最后澄清一下,如果样本是所有数据的大小,这相当于对数据进行置换,即洗牌,尽管与这些不同,您的情况很有趣,因为概率不同。
生成离散随机变量的一个实际应用是银行的虚拟键盘,其中键 {1,2,3,4,5,6,7,8,9,0} 必须为每个会话混合或排列和 /或用户。
这是离散 va 生成的 Lua 实现,有和没有替换
您可以在repli中运行 Lua 代码here
最后,我在R中制作了图形,源代码在replit中,但我在Skitch中编辑了它。