例如,如果我有1到10的数字并且没有指定偏差数字,那么理论上我应该有等概率地随机选择其中一个。
但是如果我指定一个特定的偏差数字(比如说3),那么随机数生成器应该会比其他数字更频繁地选择3。
如果我除了指定偏差数字之外还指定了一个偏移量2,那么随机数生成器应该更频繁地从1到5中选择数字,而不是6到10中选择数字。
我应该使用哪个算法来实现这个功能呢?
如果需要,我正在使用Ruby。
如果您需要从均匀分布生成正态分布,则最简单的变换是 "box-muller"。
您可能需要担心一些细节。特别是,Box-Muller 在范围上受限制(它永远不会生成极不可能的值)。因此,如果您给出非常狭窄的范围,那么您将永远无法获得完整的值范围。其他变换没有那么受限制——我建议使用 Ruby 提供的任何内容(查找“normal”或“gaussian”)。
此外,请注意对值进行四舍五入。例如,2.6 到 3.4 应全部变为 3。如果您仅丢弃小数点(因此,3.0 到 3.999 变为 3),则会存在偏差。
如果你真的关心效率,并且不想丢弃值,你可以简单地发明一些东西。其中一种欺骗的方法是将均匀变量与偏差值混合(例如,9/10的时间生成均匀分布的值,1/10的时间返回3)。在某些情况下,如果你只关心样本的平均值,这可能已经足够了。
rnd = [1,1,1,2].sample
来获得 1/4 的概率得到 2。 - Krisdef randBias(a,b,biasedNum=None, bias=0):
x = random.randint(a, b+bias)
if x<= b:
return x
else:
return biasedNum
如果您想要一个单峰分布(其中偏差只集中在数字范围的一个特定值上,例如您所述的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])