我试图根据已有的数据创建一个分布,然后从该分布中随机绘制。这是我所拥有的:
from scipy import stats
import numpy
def getDistribution(data):
kernel = stats.gaussian_kde(data)
class rv(stats.rv_continuous):
def _cdf(self, x):
return kernel.integrate_box_1d(-numpy.Inf, x)
return rv()
if __name__ == "__main__":
# pretend this is real data
data = numpy.concatenate((numpy.random.normal(2,5,100), numpy.random.normal(25,5,100)))
d = getDistribution(data)
print d.rvs(size=100) # this usually fails
我认为这可以达到我想要的目的,但是当我尝试执行
d.rvs()
时,经常出现错误(请参阅下文),并且d.rvs(100)
永远无法正常工作。难道我做错了什么?有没有更简单或更好的方法来做到这一点?如果这是scipy中的错误,是否有解决方法?最后,是否有更多关于在某个地方创建自定义发行版的文档?我发现的最好的是scipy.stats.rv_continuous文档,它很简陋,没有任何有用的示例。
追溯:
编辑
对于那些好奇的人,按照下面的答案中的建议,下面的代码可以工作:
from scipy import stats
import numpy
def getDistribution(data):
kernel = stats.gaussian_kde(data)
class rv(stats.rv_continuous):
def _rvs(self, *x, **y):
# don't ask me why it's using self._size
# nor why I have to cast to int
return kernel.resample(int(self._size))
def _cdf(self, x):
return kernel.integrate_box_1d(-numpy.Inf, x)
def _pdf(self, x):
return kernel.evaluate(x)
return rv(name='kdedist', xa=-200, xb=200)
最佳答案
具体到您的回溯:
rvs使用cdf的倒数ppf创建随机数。由于您未指定ppf,因此它是通过rootfinding算法brentq
计算的。 brentq
在函数应为零的位置上搜索上下限(查找x使得cdf(x)= q,q为分位数)。
在示例中,限制的默认值xa
和xb
太小。以下对我适用于scipy 0.9.0,在创建函数实例时可以设置xa
,xb
def getDistribution(data):
kernel = stats.gaussian_kde(data)
class rv(stats.rv_continuous):
def _cdf(self, x):
return kernel.integrate_box_1d(-numpy.Inf, x)
return rv(name='kdedist', xa=-200, xb=200)
当前有一个对scipy的请求,以改善此问题,因此在下一发行版中,
xa
和xb
将自动扩展,以避免f(a) and f(b) must have different signs
异常。关于此的文档不多,最简单的方法是遵循一些示例(并在邮件列表中询问)。
编辑:加法
pdf :由于您还具有gaussian_kde给出的密度函数,因此我将添加
_pdf
方法,这将使某些计算更加有效。edit2:加法
rvs :如果您对生成随机数感兴趣,那么gaussian_kde提供了一种重采样方法。可以通过从数据中采样并添加高斯噪声来生成随机采样。因此,这将比使用ppf方法的通用rvs更快。我会编写一个._rvs方法,该方法仅调用gaussian_kde的resample方法。
预计算ppf :我不知道预计算ppf的任何常规方法。但是,我想到的方法(但到目前为止尚未尝试过)是在许多点上预先计算ppf,然后使用线性插值来近似ppf函数。
edit3:关于
_rvs
在评论中回答Srivatsan的问题_rvs
是由公共(public)方法rvs
调用的特定于发行版的方法。 rvs
是一种通用方法,它执行一些参数检查,添加位置和比例,并设置属性self._size
(即所请求的随机变量数组的大小),然后调用特定于分布的方法._rvs
或它的通用对应方法。 ._rvs
中的额外参数是形状参数,但是由于在这种情况下没有参数,因此*x
和**y
是多余的且未使用。我不知道
size
或.rvs
方法的形状在多变量情况下的效果如何。这些分布是为单变量分布而设计的,可能无法完全适用于多变量情况,或者可能需要进行一些调整。关于python - 在scipy中创建新的发行版,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10678546/