2012-07-07 88 views
32

我正在寻找一个简单函数,该函数可以基于它们相应的(也是指定的)概率生成指定的随机值数组。我只需要它来生成浮点值,但我不明白为什么它不应该能够生成任何标量。我可以从现有函数中想出很多构建这种方法的方法,但我想我可能只是错过了一个明显的SciPy或NumPy函数。使用SciPy或NumPy生成具有指定权重的离散随机变量

例如为:

>>> 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是我应该使用的是什么,请你为我提供了一个简单的例子和​​上面的“的解释形状“声明?

回答

42

从离散分布绘图直接内置到numpy中。 该功能被称为random.choice(很难找到没有任何参考numpy文档中的离散分布)。

elements = [1.1, 2.2, 3.3] 
probabilities = [0.2, 0.5, 0.3] 
np.random.choice(elements, 10, p=probabilities) 
+3

大!但是,正确的语法是:np.random.choice(元素,10,p = list(概率)) – Sina 2016-02-01 03:13:39

+0

不错。我认为这个版本在我发布我的原始问题后出来了(我认为这是我第一次在1.7.0发布,我相信这是在2013年发布的)。 – TimY 2016-07-22 09:01:40

+0

非常好!似乎工作也没有强制列表:np.random。选择(元素,10,p =概率))。 – zeycus 2016-07-26 17:37:10

24

这是一个简短的,相对简单的函数,它返回加权值,它使用NumPy的digitize,accumulaterandom_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. 然后我们使用random_sample
  3. 我们使用digitize看到的BIN这些数字陷入创建一批随机数(0之间,并且1)。
  4. 并返回相应的值。
+1

是的,这基本上是我在想什么,但我只是认为可能有一个内置的功能,正是这样做。从它的声音来看,没有这样的事情。我必须承认 - 我不会那么高雅。 - 谢谢 – TimY 2012-07-07 15:40:30

+0

NumPy直接提供'numpy.cumsum()',它可以用来代替'np.add.accumulate()'('np.add()'不是很常用,所以我推荐使用'cumsum )')。 – EOL 2013-02-02 08:11:18

+0

+1对于有用的'numpy.digitize()'!但是,SciPy实际上提供了直接回答问题的功能 - 请参阅我的答案。 – EOL 2013-02-02 08:29:55

3

最简单的DIY方式是将概率归结为累积分布。 通过这种方式,您可以将单位间隔分成长度等于原始概率的子间隔。现在在[0,1)上生成一个单一的随机数统一,并且看它到达了哪个间隔。

+1

是的,这基本上是我在想什么,但我只是认为可能有一个内置函数完全是这样。从它的声音来看,没有这样的事情。 – TimY 2012-07-07 15:37:35

14

你正朝着一个很好的方向前进:内置的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]) 

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

+4

注意:我尝试过运行timeit,它比fraxel的纯粹numpy版本慢100倍。你有没有机会知道这是为什么? – TimY 2013-02-02 12:55:25

+0

哇,有趣!在10k元素上,我甚至得到了300倍慢的因素。我快速浏览了一下代码:执行了很多检查,但我猜他们无法解释运行时间上的这么大的差异;我没有足够深入到Scipy代码,以便能够看到差异可能来自哪里... – EOL 2013-02-02 13:23:43

+0

@TimY我的天真猜测是,缓慢是由于更多的工作在纯Python中完成,所做的工作较少(在(在Python中的数学/科学软件包倾向于包装C代码。) – dbliss 2016-02-17 15:20:51

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) 

等voilà!