Repository URL to install this package:
|
Version:
0.11.1 ▾
|
# -*- coding: utf-8 -*-
"""
Created on Sun May 09 22:35:21 2010
Author: josef-pktd
License: BSD
todo:
change moment calculation, (currently uses default _ppf method - I think)
>>> lognormalg.moment(4)
Warning: The algorithm does not converge. Roundoff error is detected
in the extrapolation table. It is assumed that the requested tolerance
cannot be achieved, and that the returned result (if full_output = 1) is
the best which can be obtained.
array(2981.0032380193438)
"""
import warnings # for silencing, see above...
import numpy as np
from numpy.testing import assert_almost_equal
from scipy import stats, special
from statsmodels.sandbox.distributions.extras import (
squarenormalg, absnormalg, negsquarenormalg, squaretg)
# some patches to scipy.stats.distributions so tests work and pass
# this should be necessary only for older scipy
#patch frozen distributions with a name
stats.distributions.rv_frozen.name = property(lambda self: self.dist.name)
#patch f distribution, correct skew and maybe kurtosis
def f_stats(self, dfn, dfd):
arr, where, inf, sqrt, nan = np.array, np.where, np.inf, np.sqrt, np.nan
v2 = arr(dfd*1.0)
v1 = arr(dfn*1.0)
mu = where(v2 > 2, v2 / arr(v2 - 2), inf)
mu2 = 2*v2*v2*(v2+v1-2)/(v1*(v2-2)**2 * (v2-4))
mu2 = where(v2 > 4, mu2, inf)
#g1 = 2*(v2+2*v1-2)/(v2-6)*sqrt((2*v2-4)/(v1*(v2+v1-2)))
g1 = 2*(v2+2*v1-2.)/(v2-6.)*np.sqrt(2*(v2-4.)/(v1*(v2+v1-2.)))
g1 = where(v2 > 6, g1, nan)
#g2 = 3/(2*v2-16)*(8+g1*g1*(v2-6))
g2 = 3/(2.*v2-16)*(8+g1*g1*(v2-6.))
g2 = where(v2 > 8, g2, nan)
return mu, mu2, g1, g2
#stats.distributions.f_gen._stats = f_stats
stats.f.__class__._stats = f_stats
#correct kurtosis by subtracting 3 (Fisher)
#after this it matches halfnorm for arg close to zero
def foldnorm_stats(self, c):
arr, where, inf, sqrt, nan = np.array, np.where, np.inf, np.sqrt, np.nan
exp = np.exp
pi = np.pi
fac = special.erf(c/sqrt(2))
mu = sqrt(2.0/pi)*exp(-0.5*c*c)+c*fac
mu2 = c*c + 1 - mu*mu
c2 = c*c
g1 = sqrt(2/pi)*exp(-1.5*c2)*(4-pi*exp(c2)*(2*c2+1.0))
g1 += 2*c*fac*(6*exp(-c2) + 3*sqrt(2*pi)*c*exp(-c2/2.0)*fac + \
pi*c*(fac*fac-1))
g1 /= pi*mu2**1.5
g2 = c2*c2+6*c2+3+6*(c2+1)*mu*mu - 3*mu**4
g2 -= 4*exp(-c2/2.0)*mu*(sqrt(2.0/pi)*(c2+2)+c*(c2+3)*exp(c2/2.0)*fac)
g2 /= mu2**2.0
g2 -= 3.
return mu, mu2, g1, g2
#stats.distributions.foldnorm_gen._stats = foldnorm_stats
stats.foldnorm.__class__._stats = foldnorm_stats
#-----------------------------
DECIMAL = 5
class Test_Transf2(object):
@classmethod
def setup_class(cls):
cls.dist_equivalents = [
#transf, stats.lognorm(1))
#The below fails on the SPARC box with scipy 10.1
#(lognormalg, stats.lognorm(1)),
#transf2
(squarenormalg, stats.chi2(1)),
(absnormalg, stats.halfnorm),
(absnormalg, stats.foldnorm(1e-5)), #try frozen
#(negsquarenormalg, 1-stats.chi2), # will not work as distribution
(squaretg(10), stats.f(1, 10))
] #try both frozen
l,s = 0.0, 1.0
cls.ppfq = [0.1,0.5,0.9]
cls.xx = [0.95,1.0,1.1]
cls.nxx = [-0.95,-1.0,-1.1]
def test_equivalent(self):
xx, ppfq = self.xx, self.ppfq
for d1,d2 in self.dist_equivalents:
## print d1.name
assert_almost_equal(d1.cdf(xx), d2.cdf(xx), err_msg='cdf'+d1.name)
assert_almost_equal(d1.pdf(xx), d2.pdf(xx),
err_msg='pdf '+d1.name+d2.name)
assert_almost_equal(d1.sf(xx), d2.sf(xx),
err_msg='sf '+d1.name+d2.name)
assert_almost_equal(d1.ppf(ppfq), d2.ppf(ppfq),
err_msg='ppq '+d1.name+d2.name)
assert_almost_equal(d1.isf(ppfq), d2.isf(ppfq),
err_msg='isf '+d1.name+d2.name)
self.d1 = d1
self.d2 = d2
## print d1, d2
## print d1.moment(3)
## print d2.moment(3)
#work around bug#1293
if hasattr(d2, 'dist'):
d2mom = d2.dist.moment(3, *d2.args)
else:
d2mom = d2.moment(3)
assert_almost_equal(d1.moment(3), d2mom,
DECIMAL,
err_msg='moment '+d1.name+d2.name)
# silence warnings in scipy, works for versions
# after print changed to warning in scipy
orig_filter = warnings.filters[:]
warnings.simplefilter('ignore')
try:
s1 = d1.stats(moments='mvsk')
s2 = d2.stats(moments='mvsk')
finally:
warnings.filters = orig_filter
#stats(moments='k') prints warning for lognormalg
assert_almost_equal(s1[:2], s2[:2],
err_msg='stats '+d1.name+d2.name)
assert_almost_equal(s1[2:], s2[2:],
decimal=2, #lognorm for kurtosis
err_msg='stats '+d1.name+d2.name)
def test_equivalent_negsq(self):
#special case negsquarenormalg
#negsquarenormalg.cdf(x) == stats.chi2(1).cdf(-x), for x<=0
xx, nxx, ppfq = self.xx, self.nxx, self.ppfq
d1,d2 = (negsquarenormalg, stats.chi2(1))
#print d1.name
assert_almost_equal(d1.cdf(nxx), 1-d2.cdf(xx), err_msg='cdf'+d1.name)
assert_almost_equal(d1.pdf(nxx), d2.pdf(xx))
assert_almost_equal(d1.sf(nxx), 1-d2.sf(xx))
assert_almost_equal(d1.ppf(ppfq), -d2.ppf(ppfq)[::-1])
assert_almost_equal(d1.isf(ppfq), -d2.isf(ppfq)[::-1])
assert_almost_equal(d1.moment(3), -d2.moment(3))
ch2oddneg = [v*(-1)**(i+1) for i,v in
enumerate(d2.stats(moments='mvsk'))]
assert_almost_equal(d1.stats(moments='mvsk'), ch2oddneg,
err_msg='stats '+d1.name+d2.name)
if __name__ == '__main__':
tt = Test_Transf2()
tt.test_equivalent()
tt.test_equivalent_negsq()
debug = 0
if debug:
print(negsquarenormalg.ppf([0.1,0.5,0.9]))
print(stats.chi2.ppf([0.1,0.5,0.9],1))
print(negsquarenormalg.a)
print(negsquarenormalg.b)
print(absnormalg.stats( moments='mvsk'))
print(stats.foldnorm(1e-10).stats( moments='mvsk'))
print(stats.halfnorm.stats( moments='mvsk'))