如何在指定偏向下“随机”选择数字

9 投票
5 回答
5283 浏览
提问于 2025-04-18 18:35

我想知道怎么生成带有特定偏向的随机数字。比如说,我想在1和2之间选择一个数字,但希望选择1的概率高达90%。我想到的办法是...

import random

print random.choice([1, 1, 1, 1, 1, 1, 1, 1, 1, 2])

有没有更好的方法呢?我用的方法在简单的例子中有效,但最终我需要做一些更复杂的选择,偏向性可能会非常具体(比如37.65%的偏向),这就需要很长的列表了。

补充说明:我现在用的是numpy 1.6,所以不能使用numpy.random.choice。

5 个回答

0

类似这样的做法应该能解决问题,而且可以直接处理所有的浮点概率,而不需要创建一个中间数组。

import random
from itertools import accumulate  # for python 3.x

def accumulate(l):  # for python 2.x
    tmp = 0
    for n in l:
        tmp += n
        yield tmp

def random_choice(a, p):
    sums = sum(p)
    accum = accumulate(p)  # made a cumulative list of probability
    accum = [n / sums for n in accum]  # normalize
    rnd = random.random()
    for i, item in enumerate(accum):
        if rnd < item:
            return a[i]
0

在概率表中获取索引是很简单的。你可以根据需要的权重数量来制作一个表格,像这样:

prb = [0.5, 0.65, 0.8, 1]

你可以用类似下面的方式来获取索引:

 def get_in_range(prb, pointer):
    """Returns index of matching range in table prb"""
    found = 0
    for p in prb:
        if nr>p:
            found += 1
    return found

通过get_in_range返回的索引可以用来指向相应的值表。

使用示例:

import random
values = [1, 2, 3]
weights = [0.9, 0.99, 1]
result = values[get_in_range(prb, random.random())]

这里应该有选择1的概率是95%;选择2的概率是4%;选择3的概率是1%。

2

对于带替换的随机抽样,np.random.choice 中的核心代码是

            cdf = p.cumsum()
            cdf /= cdf[-1]
            uniform_samples = self.random_sample(shape)
            idx = cdf.searchsorted(uniform_samples, side='right')

所以我们可以在一个新函数中使用这个代码来做同样的事情(不过这个新函数没有错误检查和其他一些好看的功能):

import numpy as np


def weighted_choice(values, p, size=1):
    values = np.asarray(values)

    cdf = np.asarray(p).cumsum()
    cdf /= cdf[-1]

    uniform_samples = np.random.random_sample(size)
    idx = cdf.searchsorted(uniform_samples, side='right')
    sample = values[idx]

    return sample

示例:

In [113]: weighted_choice([1, 2], [0.9, 0.1], 20)
Out[113]: array([1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1])

In [114]: weighted_choice(['cat', 'dog', 'goldfish'], [0.3, 0.6, 0.1], 15)
Out[114]: 
array(['cat', 'dog', 'cat', 'dog', 'dog', 'dog', 'dog', 'dog', 'dog',
       'dog', 'dog', 'dog', 'goldfish', 'dog', 'dog'], 
      dtype='|S8')
4

np.random.choice()这个函数使用的算法其实很简单,如果你只需要一次抽取一个项目的话,自己动手实现也不难。

import numpy as np

def simple_weighted_choice(choices, weights, prng=np.random):
    running_sum = np.cumsum(weights)
    u = prng.uniform(0.0, running_sum[-1])
    i = np.searchsorted(running_sum, u, side='left')
    return choices[i]
16

np.random.choice 这个函数有一个叫 p 的参数,你可以用它来指定每个选择的概率:

np.random.choice([1,2], p=[0.9, 0.1])

撰写回答