Sto provando a creare una distribuzione basata su alcuni dati che ho, quindi disegno a caso da quella distribuzione. Ecco quello che ho:Creazione di nuove distribuzioni in scipy
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
Penso che questo stia facendo quello che voglio, ma ho spesso ottenere un errore (vedi sotto), quando cerco di fare d.rvs()
, e d.rvs(100)
non funziona mai. Sto facendo qualcosa di sbagliato? C'è un modo più semplice o migliore per farlo? Se si tratta di un bug in scipy, c'è un modo per aggirarlo?
Infine, c'è più documentazione sulla creazione di distribuzioni personalizzate da qualche parte? Il meglio che ho trovato è la documentazione scipy.stats.rv_continuous, che è piuttosto spartana e non contiene esempi utili.
Il traceback:
Traceback (most recent call last): File "testDistributions.py", line 19, in print d.rvs(size=100) File "/usr/local/lib/python2.6/dist-packages/scipy-0.10.0-py2.6-linux-x86_64.egg/scipy/stats/distributions.py", line 696, in rvs vals = self._rvs(*args) File "/usr/local/lib/python2.6/dist-packages/scipy-0.10.0-py2.6-linux-x86_64.egg/scipy/stats/distributions.py", line 1193, in _rvs Y = self._ppf(U,*args) File "/usr/local/lib/python2.6/dist-packages/scipy-0.10.0-py2.6-linux-x86_64.egg/scipy/stats/distributions.py", line 1212, in _ppf return self.vecfunc(q,*args) File "/usr/local/lib/python2.6/dist-packages/numpy-1.6.1-py2.6-linux-x86_64.egg/numpy/lib/function_base.py", line 1862, in call theout = self.thefunc(*newargs) File "/usr/local/lib/python2.6/dist-packages/scipy-0.10.0-py2.6-linux-x86_64.egg/scipy/stats/distributions.py", line 1158, in _ppf_single_call return optimize.brentq(self._ppf_to_solve, self.xa, self.xb, args=(q,)+args, xtol=self.xtol) File "/usr/local/lib/python2.6/dist-packages/scipy-0.10.0-py2.6-linux-x86_64.egg/scipy/optimize/zeros.py", line 366, in brentq r = _zeros._brentq(f,a,b,xtol,maxiter,args,full_output,disp) ValueError: f(a) and f(b) must have different signs
Modifica
Per chi fosse curioso, seguendo i consigli nella risposta di seguito, ecco il codice che funziona:
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)
Quindi, quando stiamo facendo quanto sopra e chiamando 'randoms = getDistribution (Mydata)' e quindi 'randoms = randoms.rvs (size = 1000)' esegue i tre 'def' all'interno della classe? calcolando il pdf, integrandolo ecc? – ThePredator
Ottengo i miei randoms per seguire la distribuzione dei dati, ma vorrei arrotondarlo in modo che non segua esattamente la distribuzione dei dati. Per questo ho regolato manualmente la larghezza di banda in 'kernel'. Ad esempio, qualcosa di simile al modo in cui specifichiamo una funzione PDF e quindi utilizziamo la funzione PDF per creare annunci di ricerca usando Metropolis Hastings. – ThePredator