我试图根据已有的数据创建一个分布,然后从该分布中随机绘制。这是我所拥有的:

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为分位数)。

在示例中,限制的默认值xaxb太小。以下对我适用于scipy 0.9.0,在创建函数实例时可以设置xaxb

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的请求,以改善此问题,因此在下一发行版中,xaxb将自动扩展,以避免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/

10-12 03:52