如何得到一个pythonscipy类型的连续有界rv分布对象?
How to obtain a python scipy-type continuous rv distribution object that is bounded?
我想定义一个有界版本的连续随机变量分布(例如,指数分布,但我可能也想使用其他分布)。边界是 0 和 1。我想
- 绘制随机变量(由
scipy.stats.rv_continuous.rvs
完成),
- 使用 ppf(百分比函数)(由
scipy.stats.rv_continuous.ppf
完成),并且可能
- 使用 cdf(累积密度函数)(由
scipy.stats.rv_continuous.cdf
完成)
我能想到的可能方法:
以临时方式获取随机变量并不困难
import scipy.stats
d = scipy.stats.expon(0, 3/10.) # an exponential distribution as an example
rv = d.rvs(size=target_number_of_rv)
rv = rv[0=<rv]
rv = rv[rv<=1]
while len(rv) < target_number_of_rv:
rv += d.rvs(1)
rv = rv[0=<rv]
rv = rv[rv<=1]
但是 1) 这是非通用的并且可能容易出错,并且 2) 它对 ppf 或 cdf 没有帮助。
子classing scipy.stats.rv_continuous,为is done here and here。因此,可以使用scipy.stats.rv_continuous的ppf。缺点是它需要 pdf(不仅仅是预定义的 rv_continuous 对象或无界分布和边界的 pdf),如果这是错误的,cdf 和 ppf 以及其他所有内容都会出错.
设计一个 class 用于将边界应用于 rv 生成并校正从 scipy.stats 中的无界对象获得的 ppf 值。缺点是这是非通用的并且也容易出错,并且可能难以纠正 ppf。我的感觉是,无界分布的 cdf 值可以通过超出范围的概率质量份额(总计、下限和上限)来衡量,但我可能是错的。这将适用于下限和上限 l 和 u 以及任何有效的分位数 x(l<=x<=u):(cdf(x)-cdf(l))/(cdf(u)-cdf(l)) .然而,获得 ppf 需要反转结果函数。
我的感觉是可能有更好、更通用的方法来做到这一点。在那儿?也许与同情?也许通过某种方式获取无界cdf的函数对象并直接修改它?
Python是版本:3.6.2,scipy是版本0.19.1。
如果分布是 scipy.stats
中可用的分布之一,那么您可以使用该分布的 cdf 评估其在两个边界之间的积分。否则,您可以定义 rv_continuous
的 pdf,然后使用其 cdf 来获得此积分。
现在,实际上,您拥有所需 pdf 的有界版本的 pdf,因为您已经在该积分中计算了它的归一化常数。您可以继续将 rv_continuous
与 pdf 的形式加上归一化常数和边界一起使用。
您的代码可能如下所示。变量scale
是根据scipy文档设置的。 norm
是指数 pdf 在 [0,1] 上的积分。只考虑了大约 0.49 的概率质量。因此,要生成指数,当截断到 [0,1] 区间时给出质量为 1 我们必须将其 pdf 除以该因子。
Truncated_expon
在文档中定义为 rv_continuous
的子类。通过提供它的 pdf,我们可以(至少对于这样一个简单的积分!)scipy 来计算这个分布的 cdf,从而计算随机样本。
我计算了一次的 cdf 作为支票。
>>> from scipy import stats
>>> lamda = 2/3
>>> scale = 1/lamda
>>> norm = stats.expon.cdf(1, scale=scale)
>>> norm
0.48658288096740798
>>> from math import exp
>>> class Truncated_expon(stats.rv_continuous):
... def _pdf(self, x, lamda):
... return lamda*exp(-lamda*x)/0.48658288096740798
...
>>> e = Truncated_expon(a=0, b=1, shapes='lamda')
>>> e.cdf(1, lamda=lamda)
1.0
>>> e.rvs(size=20, lamda=lamda)
array([ 0.20064067, 0.67646465, 0.89118679, 0.86093035, 0.14334989,
0.10505598, 0.53488779, 0.11606106, 0.41296616, 0.33650899,
0.95126415, 0.57481087, 0.04495104, 0.00308469, 0.23585195,
0.00653972, 0.59400395, 0.34919065, 0.91762547, 0.40098409])
我想定义一个有界版本的连续随机变量分布(例如,指数分布,但我可能也想使用其他分布)。边界是 0 和 1。我想
- 绘制随机变量(由
scipy.stats.rv_continuous.rvs
完成), - 使用 ppf(百分比函数)(由
scipy.stats.rv_continuous.ppf
完成),并且可能 - 使用 cdf(累积密度函数)(由
scipy.stats.rv_continuous.cdf
完成)
我能想到的可能方法:
以临时方式获取随机变量并不困难
import scipy.stats d = scipy.stats.expon(0, 3/10.) # an exponential distribution as an example rv = d.rvs(size=target_number_of_rv) rv = rv[0=<rv] rv = rv[rv<=1] while len(rv) < target_number_of_rv: rv += d.rvs(1) rv = rv[0=<rv] rv = rv[rv<=1]
但是 1) 这是非通用的并且可能容易出错,并且 2) 它对 ppf 或 cdf 没有帮助。
子classing scipy.stats.rv_continuous,为is done here and here。因此,可以使用scipy.stats.rv_continuous的ppf。缺点是它需要 pdf(不仅仅是预定义的 rv_continuous 对象或无界分布和边界的 pdf),如果这是错误的,cdf 和 ppf 以及其他所有内容都会出错.
设计一个 class 用于将边界应用于 rv 生成并校正从 scipy.stats 中的无界对象获得的 ppf 值。缺点是这是非通用的并且也容易出错,并且可能难以纠正 ppf。我的感觉是,无界分布的 cdf 值可以通过超出范围的概率质量份额(总计、下限和上限)来衡量,但我可能是错的。这将适用于下限和上限 l 和 u 以及任何有效的分位数 x(l<=x<=u):(cdf(x)-cdf(l))/(cdf(u)-cdf(l)) .然而,获得 ppf 需要反转结果函数。
我的感觉是可能有更好、更通用的方法来做到这一点。在那儿?也许与同情?也许通过某种方式获取无界cdf的函数对象并直接修改它?
Python是版本:3.6.2,scipy是版本0.19.1。
如果分布是 scipy.stats
中可用的分布之一,那么您可以使用该分布的 cdf 评估其在两个边界之间的积分。否则,您可以定义 rv_continuous
的 pdf,然后使用其 cdf 来获得此积分。
现在,实际上,您拥有所需 pdf 的有界版本的 pdf,因为您已经在该积分中计算了它的归一化常数。您可以继续将 rv_continuous
与 pdf 的形式加上归一化常数和边界一起使用。
您的代码可能如下所示。变量scale
是根据scipy文档设置的。 norm
是指数 pdf 在 [0,1] 上的积分。只考虑了大约 0.49 的概率质量。因此,要生成指数,当截断到 [0,1] 区间时给出质量为 1 我们必须将其 pdf 除以该因子。
Truncated_expon
在文档中定义为 rv_continuous
的子类。通过提供它的 pdf,我们可以(至少对于这样一个简单的积分!)scipy 来计算这个分布的 cdf,从而计算随机样本。
我计算了一次的 cdf 作为支票。
>>> from scipy import stats
>>> lamda = 2/3
>>> scale = 1/lamda
>>> norm = stats.expon.cdf(1, scale=scale)
>>> norm
0.48658288096740798
>>> from math import exp
>>> class Truncated_expon(stats.rv_continuous):
... def _pdf(self, x, lamda):
... return lamda*exp(-lamda*x)/0.48658288096740798
...
>>> e = Truncated_expon(a=0, b=1, shapes='lamda')
>>> e.cdf(1, lamda=lamda)
1.0
>>> e.rvs(size=20, lamda=lamda)
array([ 0.20064067, 0.67646465, 0.89118679, 0.86093035, 0.14334989,
0.10505598, 0.53488779, 0.11606106, 0.41296616, 0.33650899,
0.95126415, 0.57481087, 0.04495104, 0.00308469, 0.23585195,
0.00653972, 0.59400395, 0.34919065, 0.91762547, 0.40098409])