将随机数生成器偏向某个整数n,偏差为b。

3
给定一个整数范围R = [a, b](其中a >= 0且b <= 100),该范围内存在一个偏差整数n以及一些偏移量b,我可以使用什么公式来使随机数生成器朝向n的方向倾斜呢?
例如,如果我有1到10的数字并且没有指定偏差数字,那么理论上我应该有等概率地随机选择其中一个。
但是如果我指定一个特定的偏差数字(比如说3),那么随机数生成器应该会比其他数字更频繁地选择3。
如果我除了指定偏差数字之外还指定了一个偏移量2,那么随机数生成器应该更频繁地从1到5中选择数字,而不是6到10中选择数字。
我应该使用哪个算法来实现这个功能呢?
如果需要,我正在使用Ruby。

抱歉回答错误,我错过了它是整数的事实。您只是想要一些“任意”的转换,还是它必须具有明确定义的属性(例如均值和标准差等于给定的足够大的样本)? - andrew cooke
如果没有偏差,您可以使用均匀分布,如果有偏差,则可以使用正态分布吗? - zimdanen
@andrewcooke 任意的转换都可以。我只是希望数字生成器更频繁地选择某些值。只要在我的例子中我得到更多的3,那就很好了。或者,通过偏差,更多的1到5。如果在这种情况下3仍然是更高的,那就太好了。 - MxLDevs
为什么正态分布太偏斜?这完全取决于您选择的标准差 - 您可以随意选择。 - andrew cooke
你提供的解决方案存在问题,andrew cooke。Keikoku建议他/她正在寻找可能是多模态偏差的解决方案。 - Jérémie
显示剩余2条评论
3个回答

3
我认为最简单的方法是从具有所需属性的正态(又名高斯)分布中进行采样,然后转换结果:
  • 生成给定均值和标准差的正态值
  • 四舍五入到最近的整数
  • 如果在给定范围之外(正态可以产生整个范围从负无穷大到正无穷大的值),则丢弃并重复

如果您需要从均匀分布生成正态分布,则最简单的变换是 "box-muller"。

您可能需要担心一些细节。特别是,Box-Muller 在范围上受限制(它永远不会生成极不可能的值)。因此,如果您给出非常狭窄的范围,那么您将永远无法获得完整的值范围。其他变换没有那么受限制——我建议使用 Ruby 提供的任何内容(查找“normal”或“gaussian”)。

此外,请注意对值进行四舍五入。例如,2.6 到 3.4 应全部变为 3。如果您仅丢弃小数点(因此,3.0 到 3.999 变为 3),则会存在偏差。

如果你真的关心效率,并且不想丢弃值,你可以简单地发明一些东西。其中一种欺骗的方法是将均匀变量与偏差值混合(例如,9/10的时间生成均匀分布的值,1/10的时间返回3)。在某些情况下,如果你只关心样本的平均值,这可能已经足够了。


对于第一种方法,这意味着如果我给出mean=2和sd=3,那么这有效地排除了像8这样的数字被选择,对吧?也许我可以生成另一个随机数来选择是否丢弃? - MxLDevs
不,你会得到8。那是离均值2个标准差之外的位置((8-2)/3=2),所以没有问题;它只是不太常见。理论上,正态分布可以无限延伸(实际上Box-Muller方法并不完全符合这一点,但Ruby可能有一个更好的正态/高斯随机数生成器)。请参见编辑。 - andrew cooke
我使用 rnd = [1,1,1,2].sample 来获得 1/4 的概率得到 2。 - Kris

0
对于第一部分"But if I do give a specific bias number (say, 3), then the number generator should be drawing 3 a more frequently than the other numbers.",有一个非常简单的解决方案:
def randBias(a,b,biasedNum=None, bias=0):
   x = random.randint(a, b+bias)
   if x<= b:
       return x
   else:
       return biasedNum

对于第二部分,我会说这取决于任务。如果你需要从相同的分布中生成十亿个随机数,我会明确计算数字的概率并使用加权随机数生成器(参见Random weighted choice)。

0

如果您想要一个单峰分布(其中偏差只集中在数字范围的一个特定值上,例如您所述的3),那么andrew cooke提供的答案很好——主要是因为它允许您非常精确地微调偏差。

然而,如果您希望进行多个偏差——例如,您希望有一个三峰分布,其中数字a、(a+b)/2和b比其他数字更频繁出现,那么最好实现加权随机选择。

这方面的一个简单算法在StackOverflow上的一个最近的问题中给出;它的复杂度是线性的。使用这样的算法,您只需维护一个列表,最初包含{a,a+1,a+2,...,b-1,b}(大小为b-a+1),当您想要向X添加偏差时,您会将X的几个副本添加到列表中——取决于您想要偏差多少。然后从列表中随机选择一个项目。

如果你想要更高效的方法,最有效的方法被称为“别名方法”,由Denis Bzowy在Python中实现得非常清晰;一旦你的数组被预处理,它就可以在恒定的时间内运行(但这意味着一旦完成预处理,你就不能再更新偏差了——或者你需要重新处理表格)。

这两种技术的缺点是,与高斯分布不同,偏向X并不会对X-1和X+1产生影响。为了模拟这种效果,你需要做一些如下的事情

def addBias(x, L):
   L = concatList(L, [x, x, x, x, x])
   L = concatList(L, [x+2])
   L = concatList(L, [x+1, x+1]) 
   L = concatList(L, [x-1,x-1,x-1])
   L = concatList(L, [x-2])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接