从离散分布中生成随机数的算法?

时间:2012-04-08 16:25:18

标签: algorithm math random

  

设计一个快速算法,重复生成数字   离散分布:给定一个非负实数的数组a []   总和为1,目标是以概率a [i]

返回索引i

我在一本在线算法手册“Java编程入门”,第4.2章:排序和搜索(http://introcs.cs.princeton.edu/java/42sort/)中找到了这个问题。

提示说:

  

形成累积和的数组s [],使得s [i]是[]的前i个元素的总和。现在,生成0到1之间的随机实数r,并使用二进制搜索返回索引i,其中s [i]≤s[i + 1]。

一些我怎么也无法理解提示,因此无法找到解决方案..

4 个答案:

答案 0 :(得分:8)

有很多方法可以解决这个问题。 This article 描述了众多方法,优势,弱点和运行时。最后得出一个算法,该算法需要O(n)预处理时间,然后在每个时间O(1)生成数字。

您正在寻找的特定方法在“轮盘赌选择”下进行了描述。

希望这有帮助!

答案 1 :(得分:2)

这是一个实现'轮盘赌'技术的Python算法。如果没有图形,很难解释。通过templatetypedef链接的文章应该做得很好。另外,请注意,此算法实际上并不需要对权重进行规范化(它们不需要总和为1),但这仍然有效。

import random

trials = 50
selected_indices = []

# weights on each index
distrib = [0.1, 0.4, 0.2, 0.3]

index = random.randrange(0, len(distrib) - 1)
max_weight = max(distrib)
B = 0
# generate 'trials' random indices
for i in range (trials):

    # increase B by a factor which is
    # guaranteed to be much larger than our largest weight
    B = B + random.uniform(0, 2 * max_weight)

    # continue stepping through wheel until B lands 'within' a weight
    while(B > distrib[index]):
        B = B - distrib[index]
        index = (index + 1) % len(distrib)
    selected_indices.append(index)

print("Randomly selected indices from {0} trials".format(trials))
print(selected_indices)

答案 2 :(得分:0)

这是来自wakkerbot / megahal的片段。这里的权重是(无符号)整数,它们的总和在node-> childsum中。为了获得最大速度,子项按降序排序(或多或少)。 (权重预计具有幂律分布,只有少数高权重和许多较小权重)

    /*
     *          Choose a symbol at random from this context.
     *          weighted by ->thevalue
     */
    credit = urnd( node->childsum );
    for(cidx=0; 1; cidx = (cidx+1) % node->branch) {
        symbol = node->children[cidx].ptr->symbol;
        if (credit < node->children[cidx].ptr->thevalue) break;
        /* 20120203 if (node->children[cidx].ptr->thevalue == 0) credit--; */
        credit -= node->children[cidx].ptr->thevalue;
    }
done:
    // fprintf(stderr, "{+%u}", symbol );
    return symbol;

答案 3 :(得分:0)

根据粒度,您可以使用100,1000或10000元素创建索引。假设分布(a,b,c,d)与p =(10%,20%,30%,40%),我们创建一个地图:

val prob = Map ('a' -> 10, 'b' -> 20, 'c' -> 30, 'd' -> 40) 
val index = (for (e <- prob;
  i <- (1 to e._2)) yield e._1 ).toList 

index: List[Char] = List(a, a, a, a, a, a, a, a, a, a, 
b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, 
c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, 
d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d)

我们现在可以非常快速地选择所需概率的元素:

val x = index (random.nextInt (100))

x现在是40%d,10%a,依此类推。设置简短,快速访问。

这些数字甚至不需要总计100,但你必须计算一次范围,然后:

val max = prob.map (_._2).sum 
val x = index (random.nextInt (max))