Updated distributions.py

master
Per.Andreas.Brodtkorb 14 years ago
parent a2e91f6116
commit 508c74421b

@ -69,10 +69,10 @@ __all__ = [
'weibull_max', 'genlogistic', 'genpareto', 'genexpon', 'genextreme', 'weibull_max', 'genlogistic', 'genpareto', 'genexpon', 'genextreme',
'gamma', 'gengamma', 'genhalflogistic', 'gompertz', 'gumbel_r', 'gamma', 'gengamma', 'genhalflogistic', 'gompertz', 'gumbel_r',
'gumbel_l', 'halfcauchy', 'halflogistic', 'halfnorm', 'hypsecant', 'gumbel_l', 'halfcauchy', 'halflogistic', 'halfnorm', 'hypsecant',
'gausshyper', 'invgamma', 'invnorm', 'invweibull', 'johnsonsb', 'gausshyper', 'invgamma', 'invnorm', 'invgauss', 'invweibull',
'johnsonsu', 'laplace', 'levy', 'levy_l', 'levy_stable', 'johnsonsb', 'johnsonsu', 'laplace', 'levy', 'levy_l',
'logistic', 'loggamma', 'loglaplace', 'lognorm', 'gilbrat', 'levy_stable', 'logistic', 'loggamma', 'loglaplace', 'lognorm',
'maxwell', 'mielke', 'nakagami', 'ncx2', 'ncf', 't', 'gilbrat', 'maxwell', 'mielke', 'nakagami', 'ncx2', 'ncf', 't',
'nct', 'pareto', 'lomax', 'powerlaw', 'powerlognorm', 'powernorm', 'nct', 'pareto', 'lomax', 'powerlaw', 'powerlognorm', 'powernorm',
'rdist', 'rayleigh', 'reciprocal', 'rice', 'recipinvgauss', 'rdist', 'rayleigh', 'reciprocal', 'rice', 'recipinvgauss',
'semicircular', 'triang', 'truncexpon', 'truncnorm', 'semicircular', 'triang', 'truncexpon', 'truncnorm',
@ -352,6 +352,58 @@ class general_cont_ppf(object):
def __call__(self, q, *args): def __call__(self, q, *args):
return self.vecfunc(q, *args) return self.vecfunc(q, *args)
# Frozen RV class
class rv_frozen_old(object):
def __init__(self, dist, *args, **kwds):
self.args = args
self.kwds = kwds
self.dist = dist
def pdf(self, x): #raises AttributeError in frozen discrete distribution
return self.dist.pdf(x, *self.args, **self.kwds)
def cdf(self, x):
return self.dist.cdf(x, *self.args, **self.kwds)
def ppf(self, q):
return self.dist.ppf(q, *self.args, **self.kwds)
def isf(self, q):
return self.dist.isf(q, *self.args, **self.kwds)
def rvs(self, size=None):
kwds = self.kwds.copy()
kwds.update({'size':size})
return self.dist.rvs(*self.args, **kwds)
def sf(self, x):
return self.dist.sf(x, *self.args, **self.kwds)
def stats(self, moments='mv'):
kwds = self.kwds.copy()
kwds.update({'moments':moments})
return self.dist.stats(*self.args, **kwds)
def median(self):
return self.dist.median(*self.args, **self.kwds)
def mean(self):
return self.dist.mean(*self.args, **self.kwds)
def var(self):
return self.dist.var(*self.args, **self.kwds)
def std(self):
return self.dist.std(*self.args, **self.kwds)
def moment(self, n):
return self.dist.moment(n, *self.args, **self.kwds)
def entropy(self):
return self.dist.entropy(*self.args, **self.kwds)
def pmf(self,k):
return self.dist.pmf(k, *self.args, **self.kwds)
def interval(self, alpha):
return self.dist.interval(alpha, *self.args, **self.kwds)
# Frozen RV class # Frozen RV class
class rv_frozen(object): class rv_frozen(object):
''' Frozen continous or discrete 1D Random Variable object (RV) ''' Frozen continous or discrete 1D Random Variable object (RV)
@ -429,7 +481,7 @@ class rv_frozen(object):
def stats(self, moments='mv'): def stats(self, moments='mv'):
''' Some statistics of the given RV''' ''' Some statistics of the given RV'''
kwds = dict(moments=moments) kwds = dict(moments=moments)
return self.dist.stats(*self.par) return self.dist.stats(*self.par, **kwds)
def median(self): def median(self):
return self.dist.median(*self.par) return self.dist.median(*self.par)
def mean(self): def mean(self):
@ -450,47 +502,6 @@ class rv_frozen(object):
return self.dist.interval(alpha, *self.par) return self.dist.interval(alpha, *self.par)
# Frozen RV class
class rv_frozen_old(object):
def __init__(self, dist, *args, **kwds):
self.args = args
self.kwds = kwds
self.dist = dist
def pdf(self,x): #raises AttributeError in frozen discrete distribution
return self.dist.pdf(x,*self.args,**self.kwds)
def cdf(self,x):
return self.dist.cdf(x,*self.args,**self.kwds)
def ppf(self,q):
return self.dist.ppf(q,*self.args,**self.kwds)
def isf(self,q):
return self.dist.isf(q,*self.args,**self.kwds)
def rvs(self, size=None):
kwds = self.kwds
kwds.update({'size':size})
return self.dist.rvs(*self.args,**kwds)
def sf(self,x):
return self.dist.sf(x,*self.args,**self.kwds)
def stats(self,moments='mv'):
kwds = self.kwds
kwds.update({'moments':moments})
return self.dist.stats(*self.args,**kwds)
def median(self):
return self.dist.median(*self.args, **self.kwds)
def mean(self):
return self.dist.mean(*self.args, **self.kwds)
def var(self):
return self.dist.var(*self.args, **self.kwds)
def std(self):
return self.dist.std(*self.args, **self.kwds)
def moment(self,n):
return self.dist.moment(n,*self.args,**self.kwds)
def entropy(self):
return self.dist.entropy(*self.args,**self.kwds)
def pmf(self,k):
return self.dist.pmf(k,*self.args,**self.kwds)
def interval(self,alpha):
return self.dist.interval(alpha, *self.args, **self.kwds)
def stirlerr(n): def stirlerr(n):
@ -881,7 +892,7 @@ class rv_generic(object):
args, loc, scale = self._fix_loc_scale(args, loc, scale) args, loc, scale = self._fix_loc_scale(args, loc, scale)
cond = logical_and(self._argcheck(*args),(scale >= 0)) cond = logical_and(self._argcheck(*args),(scale >= 0))
if not all(cond): if not all(cond):
raise ValueError, "Domain error in arguments." raise ValueError("Domain error in arguments.")
# self._size is total size of all output values # self._size is total size of all output values
self._size = product(size, axis=0) self._size = product(size, axis=0)
@ -1016,7 +1027,7 @@ class rv_generic(object):
""" """
kwds['moments'] = 'v' kwds['moments'] = 'v'
res = math.sqrt(self.stats(*args, **kwds)) res = sqrt(self.stats(*args, **kwds))
return res return res
def interval(self, alpha, *args, **kwds): def interval(self, alpha, *args, **kwds):
@ -1041,7 +1052,7 @@ class rv_generic(object):
""" """
alpha = arr(alpha) alpha = arr(alpha)
if any((alpha > 1) | (alpha < 0)): if any((alpha > 1) | (alpha < 0)):
raise ValueError, "alpha must be between 0 and 1 inclusive" raise ValueError("alpha must be between 0 and 1 inclusive")
q1 = (1.0-alpha)/2 q1 = (1.0-alpha)/2
q2 = (1.0+alpha)/2 q2 = (1.0+alpha)/2
a = self.ppf(q1, *args, **kwds) a = self.ppf(q1, *args, **kwds)
@ -1321,8 +1332,10 @@ class rv_continuous(rv_generic):
# of _mom0_sc, vectorize cannot count the number of arguments correctly. # of _mom0_sc, vectorize cannot count the number of arguments correctly.
if longname is None: if longname is None:
if name[0] in ['aeiouAEIOU']: hstr = "An " if name[0] in ['aeiouAEIOU']:
else: hstr = "A " hstr = "An "
else:
hstr = "A "
longname = hstr + name longname = hstr + name
# generate docstring for subclass instances # generate docstring for subclass instances
@ -1963,8 +1976,8 @@ class rv_continuous(rv_generic):
""" """
if (floor(n) != n): if (floor(n) != n):
raise ValueError, "Moment must be an integer." raise ValueError("Moment must be an integer.")
if (n < 0): raise ValueError, "Moment must be positive." if (n < 0): raise ValueError("Moment must be positive.")
if (n == 0): return 1.0 if (n == 0): return 1.0
if (n > 0) and (n < 5): if (n > 0) and (n < 5):
signature = inspect.getargspec(self._stats.im_func) signature = inspect.getargspec(self._stats.im_func)
@ -2092,7 +2105,7 @@ class rv_continuous(rv_generic):
scale = theta[-1] scale = theta[-1]
args = tuple(theta[:-2]) args = tuple(theta[:-2])
except IndexError: except IndexError:
raise ValueError, "Not enough input arguments." raise ValueError("Not enough input arguments.")
if not self._argcheck(*args) or scale <= 0: if not self._argcheck(*args) or scale <= 0:
return inf return inf
x = arr((x-loc) / scale) x = arr((x-loc) / scale)
@ -2256,7 +2269,7 @@ class rv_continuous(rv_generic):
restore = None restore = None
else: else:
if len(fixedn) == len(index): if len(fixedn) == len(index):
raise ValueError, "All parameters fixed. There is nothing to optimize." raise ValueError("All parameters fixed. There is nothing to optimize.")
def restore(args, theta): def restore(args, theta):
# Replace with theta for all numbers not in fixedn # Replace with theta for all numbers not in fixedn
# This allows the non-fixed values to vary, but # This allows the non-fixed values to vary, but
@ -2290,8 +2303,8 @@ class rv_continuous(rv_generic):
Parameters Parameters
---------- ----------
data : array-like data : array_like
Data to use in calculating the MLEs. Data to use in calculating the MLEs
args : floats, optional args : floats, optional
Starting value(s) for any shape-characterizing arguments (those not Starting value(s) for any shape-characterizing arguments (those not
provided will be determined by a call to ``_fitstart(data)``). provided will be determined by a call to ``_fitstart(data)``).
@ -2305,7 +2318,7 @@ class rv_continuous(rv_generic):
floc : hold location parameter fixed to specified value. floc : hold location parameter fixed to specified value.
fscale : hold scale parameter fixed to specified value fscale : hold scale parameter fixed to specified value.
method : of estimation. Options are method : of estimation. Options are
'ml' : Maximum Likelihood method (default) 'ml' : Maximum Likelihood method (default)
@ -2324,7 +2337,7 @@ class rv_continuous(rv_generic):
""" """
Narg = len(args) Narg = len(args)
if Narg > self.numargs: if Narg > self.numargs:
raise ValueError, "Too many input arguments." raise ValueError("Too many input arguments.")
start = [None]*2 start = [None]*2
if (Narg < self.numargs) or not (kwds.has_key('loc') and if (Narg < self.numargs) or not (kwds.has_key('loc') and
kwds.has_key('scale')): kwds.has_key('scale')):
@ -2345,7 +2358,7 @@ class rv_continuous(rv_generic):
try: try:
optimizer = getattr(optimize, optimizer) optimizer = getattr(optimize, optimizer)
except AttributeError: except AttributeError:
raise ValueError, "%s is not a valid optimizer" % optimizer raise ValueError("%s is not a valid optimizer" % optimizer)
vals = optimizer(func,x0,args=(ravel(data),),disp=0) vals = optimizer(func,x0,args=(ravel(data),),disp=0)
vals = tuple(vals) vals = tuple(vals)
if restore is not None: if restore is not None:
@ -4112,30 +4125,67 @@ for x > 0, a > 0.
## Inverse Normal Distribution ## Inverse Normal Distribution
# scale is gamma from DATAPLOT and B from Regress # scale is gamma from DATAPLOT and B from Regress
_invnorm_msg = \
"""The `invnorm` distribution will be renamed to `invgauss` after scipy 0.9"""
class invnorm_gen(rv_continuous): class invnorm_gen(rv_continuous):
def _rvs(self, mu): def _rvs(self, mu):
warnings.warn(_invnorm_msg, DeprecationWarning)
return mtrand.wald(mu, 1.0, size=self._size) return mtrand.wald(mu, 1.0, size=self._size)
def _pdf(self, x, mu): def _pdf(self, x, mu):
warnings.warn(_invnorm_msg, DeprecationWarning)
return 1.0/sqrt(2*pi*x**3.0)*exp(-1.0/(2*x)*((x-mu)/mu)**2) return 1.0/sqrt(2*pi*x**3.0)*exp(-1.0/(2*x)*((x-mu)/mu)**2)
def _logpdf(self, x, mu): def _logpdf(self, x, mu):
warnings.warn(_invnorm_msg, DeprecationWarning)
return -0.5*log(2*pi) - 1.5*log(x) - ((x-mu)/mu)**2/(2*x) return -0.5*log(2*pi) - 1.5*log(x) - ((x-mu)/mu)**2/(2*x)
def _cdf(self, x, mu): def _cdf(self, x, mu):
warnings.warn(_invnorm_msg, DeprecationWarning)
fac = sqrt(1.0/x) fac = sqrt(1.0/x)
C1 = norm.cdf(fac*(x-mu)/mu) C1 = norm.cdf(fac*(x-mu)/mu)
C1 += exp(2.0/mu)*norm.cdf(-fac*(x+mu)/mu) C1 += exp(2.0/mu)*norm.cdf(-fac*(x+mu)/mu)
return C1 return C1
def _stats(self, mu): def _stats(self, mu):
warnings.warn(_invnorm_msg, DeprecationWarning)
return mu, mu**3.0, 3*sqrt(mu), 15*mu return mu, mu**3.0, 3*sqrt(mu), 15*mu
invnorm = invnorm_gen(a=0.0, name='invnorm', longname="An inverse normal", invnorm = invnorm_gen(a=0.0, name='invnorm', longname="An inverse normal",
shapes="mu",extradoc=""" shapes="mu",extradoc="""
Inverse normal distribution Inverse normal distribution
NOTE: `invnorm` will be renamed to `invgauss` after scipy 0.9
invnorm.pdf(x,mu) = 1/sqrt(2*pi*x**3) * exp(-(x-mu)**2/(2*x*mu**2)) invnorm.pdf(x,mu) = 1/sqrt(2*pi*x**3) * exp(-(x-mu)**2/(2*x*mu**2))
for x > 0. for x > 0.
""" """
) )
## Inverse Gaussian Distribution (used to be called 'invnorm'
# scale is gamma from DATAPLOT and B from Regress
class invgauss_gen(rv_continuous):
def _rvs(self, mu):
return mtrand.wald(mu, 1.0, size=self._size)
def _pdf(self, x, mu):
return 1.0/sqrt(2*pi*x**3.0)*exp(-1.0/(2*x)*((x-mu)/mu)**2)
def _logpdf(self, x, mu):
return -0.5*log(2*pi) - 1.5*log(x) - ((x-mu)/mu)**2/(2*x)
def _cdf(self, x, mu):
fac = sqrt(1.0/x)
C1 = norm.cdf(fac*(x-mu)/mu)
C1 += exp(2.0/mu)*norm.cdf(-fac*(x+mu)/mu)
return C1
def _stats(self, mu):
return mu, mu**3.0, 3*sqrt(mu), 15*mu
invgauss = invgauss_gen(a=0.0, name='invgauss', longname="An inverse Gaussian",
shapes="mu",extradoc="""
Inverse Gaussian distribution
invgauss.pdf(x,mu) = 1/sqrt(2*pi*x**3) * exp(-(x-mu)**2/(2*x*mu**2))
for x > 0.
"""
)
## Inverted Weibull ## Inverted Weibull
class invweibull_gen(rv_continuous): class invweibull_gen(rv_continuous):
@ -5009,7 +5059,7 @@ for x > 0, b > 0.
# FIXME: PPF does not work. # FIXME: PPF does not work.
class recipinvgauss_gen(rv_continuous): class recipinvgauss_gen(rv_continuous):
def _rvs(self, mu): #added, taken from invnorm def _rvs(self, mu): #added, taken from invgauss
return 1.0/mtrand.wald(mu, 1.0, size=self._size) return 1.0/mtrand.wald(mu, 1.0, size=self._size)
def _pdf(self, x, mu): def _pdf(self, x, mu):
return 1.0/sqrt(2*pi*x)*exp(-(1-mu*x)**2.0 / (2*x*mu**2.0)) return 1.0/sqrt(2*pi*x)*exp(-(1-mu*x)**2.0 / (2*x*mu**2.0))
@ -5100,9 +5150,9 @@ class truncexpon_gen(rv_continuous):
def _logpdf(self, x, b): def _logpdf(self, x, b):
return -x - log(-expm1(-b)) return -x - log(-expm1(-b))
def _cdf(self, x, b): def _cdf(self, x, b):
return (- expm1(-x)) / (-expm1(-b)) return expm1(-x) / expm1(-b)
def _ppf(self, q, b): def _ppf(self, q, b):
return - log(1 + q*expm1(-b)) return - log1p(q*expm1(-b))
def _munp(self, n, b): def _munp(self, n, b):
#wrong answer with formula, same as in continuous.pdf #wrong answer with formula, same as in continuous.pdf
#return gam(n+1)-special.gammainc(1+n,b) #return gam(n+1)-special.gammainc(1+n,b)
@ -5275,7 +5325,7 @@ Von Mises distribution
## Wald distribution (Inverse Normal with shape parameter mu=1.0) ## Wald distribution (Inverse Normal with shape parameter mu=1.0)
class wald_gen(invnorm_gen): class wald_gen(invgauss_gen):
"""A Wald continuous random variable. """A Wald continuous random variable.
%(before_notes)s %(before_notes)s
@ -5290,11 +5340,11 @@ class wald_gen(invnorm_gen):
def _rvs(self): def _rvs(self):
return mtrand.wald(1.0, 1.0, size=self._size) return mtrand.wald(1.0, 1.0, size=self._size)
def _pdf(self, x): def _pdf(self, x):
return invnorm._pdf(x, 1.0) return invgauss._pdf(x, 1.0)
def _logpdf(self, x): def _logpdf(self, x):
return invnorm._logpdf(x, 1.0) return invgauss._logpdf(x, 1.0)
def _cdf(self, x): def _cdf(self, x):
return invnorm._cdf(x, 1.0) return invgauss._cdf(x, 1.0)
def _stats(self): def _stats(self):
return 1.0, 1.0, 3.0, 15.0 return 1.0, 1.0, 3.0, 15.0
wald = wald_gen(a=0.0, name="wald", extradoc=""" wald = wald_gen(a=0.0, name="wald", extradoc="""
@ -5376,7 +5426,7 @@ def entropy(pk,qk=None):
else: else:
qk = arr(qk) qk = arr(qk)
if len(qk) != len(pk): if len(qk) != len(pk):
raise ValueError, "qk and pk must have same length." raise ValueError("qk and pk must have same length.")
qk = 1.0*qk / sum(qk,axis=0) qk = 1.0*qk / sum(qk,axis=0)
# If qk is zero anywhere, then unless pk is zero at those places # If qk is zero anywhere, then unless pk is zero at those places
# too, the relative entropy is infinite. # too, the relative entropy is infinite.
@ -5718,6 +5768,12 @@ class rv_discrete(rv_generic):
self._cdfvec.nin = self.numargs + 1 self._cdfvec.nin = self.numargs + 1
# generate docstring for subclass instances # generate docstring for subclass instances
if longname is None:
if name[0] in ['aeiouAEIOU']:
hstr = "An "
else:
hstr = "A "
longname = hstr + name
if self.__doc__ is None: if self.__doc__ is None:
self._construct_default_doc(longname=longname, extradoc=extradoc) self._construct_default_doc(longname=longname, extradoc=extradoc)
else: else:
@ -5728,6 +5784,8 @@ class rv_discrete(rv_generic):
def _construct_default_doc(self, longname=None, extradoc=None): def _construct_default_doc(self, longname=None, extradoc=None):
"""Construct instance docstring from the rv_discrete template.""" """Construct instance docstring from the rv_discrete template."""
if extradoc is None:
extradoc = ''
if extradoc.startswith('\n\n'): if extradoc.startswith('\n\n'):
extradoc = extradoc[2:] extradoc = extradoc[2:]
self.__doc__ = ''.join(['%s discrete random variable.'%longname, self.__doc__ = ''.join(['%s discrete random variable.'%longname,
@ -6275,8 +6333,8 @@ class rv_discrete(rv_generic):
""" """
if (floor(n) != n): if (floor(n) != n):
raise ValueError, "Moment must be an integer." raise ValueError("Moment must be an integer.")
if (n < 0): raise ValueError, "Moment must be positive." if (n < 0): raise ValueError("Moment must be positive.")
if (n == 0): return 1.0 if (n == 0): return 1.0
if (n > 0) and (n < 5): if (n > 0) and (n < 5):
signature = inspect.getargspec(self._stats.im_func) signature = inspect.getargspec(self._stats.im_func)
@ -6974,7 +7032,7 @@ dlaplace = dlaplace_gen(a=-inf,
Discrete Laplacian distribution. Discrete Laplacian distribution.
dlapacle.pmf(k,a) = tanh(a/2) * exp(-a*abs(k)) dlaplace.pmf(k,a) = tanh(a/2) * exp(-a*abs(k))
for a > 0. for a > 0.
""" """
) )

Loading…
Cancel
Save