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

Tim*_*imY 44 python random numpy scipy

我正在寻找一个简单的函数,它可以根据相应的(也是指定的)概率生成指定随机值的数组.我只需要它来生成浮点值,但我不明白为什么它不能生成任何标量.我可以想到从现有函数构建这个函数的许多方法,但我想我可能只是错过了一个明显的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)
Run Code Online (Sandbox Code Playgroud)

注意:我发现了scipy.stats.rv_discrete,但我不明白它是如何工作的.具体来说,我不明白这(下面)的含义是什么,也不应该做什么:

numargs = generic.numargs
[ <shape(s)> ] = ['Replace with resonable value', ]*numargs
Run Code Online (Sandbox Code Playgroud)

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

小智 61

从离散分布中绘制直接构建为numpy.该函数称为random.choice(在numpy docs中没有任何对离散分布的引用很难找到).

elements = [1.1, 2.2, 3.3]
probabilities = [0.2, 0.5, 0.3]
np.random.choice(elements, 10, p=probabilities)
Run Code Online (Sandbox Code Playgroud)

  • 大!但是,正确的语法是:np.random.choice(elements,10,p = list(probabilities)) (3认同)
  • 非常好!似乎也可以在不强制转换为列表的情况下工作:np.random.choice(elements, 10, p=probabilities))。 (2认同)

fra*_*xel 25

这里是返回加权值短,功能比较简单,它采用与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]
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:

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


Eri*_*got 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]
Run Code Online (Sandbox Code Playgroud)

因此,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])
Run Code Online (Sandbox Code Playgroud)

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

  • 注意:我尝试在其上运行timeit,它似乎比fraxel的纯粹numpy版本慢100倍.你有没有机会知道为什么会这样? (4认同)

ev-*_*-br 5

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