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)
@ -1297,7 +1308,7 @@ class rv_continuous(rv_generic):
self.expandarr = 1 self.expandarr = 1
if not hasattr(self, 'numargs'): if not hasattr(self,'numargs'):
#allows more general subclassing with *args #allows more general subclassing with *args
cdf_signature = inspect.getargspec(self._cdf.im_func) cdf_signature = inspect.getargspec(self._cdf.im_func)
numargs1 = len(cdf_signature[0]) - 2 numargs1 = len(cdf_signature[0]) - 2
@ -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
@ -2279,7 +2292,7 @@ class rv_continuous(rv_generic):
""" """
Return MLEs for shape, location, and scale parameters from data. Return MLEs for shape, location, and scale parameters from data.
MLE stands for Maximum Likelihood Estimate. Starting estimates for MLE stands for Maximum Likelihood Estimate. Starting estimates for
the fit are given by input arguments; for any arguments not provided the fit are given by input arguments; for any arguments not provided
with starting estimates, ``self._fitstart(data)`` is called to generate with starting estimates, ``self._fitstart(data)`` is called to generate
such. such.
@ -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