我有一个一维np.ndarray
,里面充满了定义分类分布的非标准化对数概率。我想从这个分布中抽取一个整数索引。由于许多概率都很小,对对数概率进行归一化和指数化会带来很大的数值误差,因此我不能使用np.random.choice
。实际上,我正在寻找一个与TensorFlow的tf.random.categorical
等效的NumPy,它处理非标准化的对数概率。
如果NumPy中没有直接实现此目的的函数,那么实现这种采样的有效方式是什么?
发布于 2021-01-24 06:16:28
通常,存在具有自定义分布的many ways to choose an integer,但它们中的大多数采用与给定概率成比例的权重。如果权重是对数概率,则需要一种略有不同的方法。也许最简单的算法是拒绝采样,下面将对其进行描述并用Python实现。在下面的算法中,最大对数概率是max
,并且有k
个整数可供选择。
对数权重在[0 ]中取一个均匀的随机整数,将-
ex
.i
- max
,ex
小于对数权重,返回i
。否则,请转至步骤1.拒绝采样的时间复杂度平均而言是恒定的,特别是当max
设置为等于真正的最大权重时。另一方面,每个样本的预期迭代次数在很大程度上取决于分布的形状。另请参阅“公平芯片/偏置硬币加载芯片”算法中的Keith Schwarz's discussion。
现在,此算法的Python代码如下所示。
import random
import math
def categ(c):
# Do a weighted choice of an item with the
# given log-probabilities.
cm=max(c) # Find max log probability
while True:
# Choose an item at random
x=random.randint(0,len(c)-1)
# Choose it with probability proportional
# to exp(c[x])
y=cm-random.expovariate(1)
# Alternatively: y=math.log(random.random())+cm
if y<c[x]:
return x
上面的代码一次生成一个变量,并且只使用Python的基本模块,而不是NumPy。Another answer展示了如何在NumPy中通过随机变量块一次实现拒绝采样(尽管在不同的随机采样任务中演示)。
https://stackoverflow.com/questions/65867476
复制