使用SciPy或NumPy生成具有指定权重的离散随机变量

时间:2012-07-07 07:35:13

标签: python random numpy scipy

我正在寻找一个简单的函数,它可以根据相应的(也是指定的)概率生成指定随机值的数组。我只需要它来生成浮点值,但我不明白为什么它不能生成任何标量。我可以想到从现有函数构建这个函数的许多方法,但我想我可能只是错过了一个明显的SciPy或NumPy函数。

E.g:

>>> values = [1.1, 2.2, 3.3]
>>> probabilities = [0.2, 0.5, 0.3]
>>> print some_function(values, probabilities, size=10)
(2.2, 1.1, 3.3, 3.3, 2.2, 2.2, 1.1, 2.2, 3.3, 2.2)

注意:我找到了 scipy.stats.rv_discrete ,但我不明白它是如何运作的。具体来说,我不明白这(下面)的含义以及它应该做什么:

numargs = generic.numargs
[ <shape(s)> ] = ['Replace with resonable value', ]*numargs

如果rv_discrete是我应该使用的,你能否提供一个简单的例子和​​对上述“形状”陈述的解释?

4 个答案:

答案 0 :(得分:25)

这是一个简短的,相对简单的函数,它返回加权值,它使用NumPy的digitizeaccumulaterandom_sample

import numpy as np
from numpy.random import random_sample

def weighted_values(values, probabilities, size):
    bins = np.add.accumulate(probabilities)
    return values[np.digitize(random_sample(size), bins)]

values = np.array([1.1, 2.2, 3.3])
probabilities = np.array([0.2, 0.5, 0.3])

print weighted_values(values, probabilities, 10)
#Sample output:
[ 2.2  2.2  1.1  2.2  2.2  3.3  3.3  2.2  3.3  3.3]

它的工作原理如下:

  1. 首先使用accumulate我们创建垃圾箱。
  2. 然后我们使用0
  3. 创建一堆随机数(1random_sample之间)
  4. 我们使用digitize来查看这些数字属于哪些垃圾箱。
  5. 并返回相应的值。

答案 1 :(得分:15)

你正朝着一个好方向前进:内置scipy.stats.rv_discrete()直接创建了一个离散的随机变量。以下是它的工作原理:

>>> from scipy.stats import rv_discrete  

>>> values = numpy.array([1.1, 2.2, 3.3])
>>> probabilities = [0.2, 0.5, 0.3]

>>> distrib = rv_discrete(values=(range(len(values)), probabilities))  # This defines a Scipy probability distribution

>>> distrib.rvs(size=10)  # 10 samples from range(len(values))
array([1, 2, 0, 2, 2, 0, 2, 1, 0, 2])

>>> values[_]  # Conversion to specific discrete values (the fact that values is a NumPy array is used for the indexing)
[2.2, 3.3, 1.1, 3.3, 3.3, 1.1, 3.3, 2.2, 1.1, 3.3]

上面的分发distrib因此会从values列表中返回索引

更一般地说,rv_discrete()在其values=(…,…)参数的第一个元素中采用一系列整数值,并在这种情况下返回这些值;无需转换为特定(浮点)值。这是一个例子:

>>> values = [10, 20, 30]
>>> probabilities = [0.2, 0.5, 0.3]
>>> distrib = rv_discrete(values=(values, probabilities))
>>> distrib.rvs(size=10)
array([20, 20, 20, 20, 20, 20, 20, 30, 20, 20])

其中(整数)输入值以所需的概率直接返回。

答案 2 :(得分:4)

您还可以使用Lea,一个专门用于离散概率分布的纯Python包。

>>> distrib = Lea.fromValFreqs((1.1,2),(2.2,5),(3.3,3))
>>> distrib
1.1 : 2/10
2.2 : 5/10
3.3 : 3/10
>>> distrib.random(10)
(2.2, 2.2, 1.1, 2.2, 2.2, 2.2, 1.1, 3.3, 1.1, 3.3)

Etvoilà!

答案 3 :(得分:3)

最简单的DIY方式是将概率总结为累积分布。 这样,您可以将单位间隔分割为长度等于原始概率的子间隔。现在在[0,1)上生成一个随机数统一,并查看它所处的间隔。