prog2_fit_distr

2041 days ago by macieksk

%html <style> <!-- pre { white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } --> </style> <pre> Zadanie polega na napisaniu współpracujących ze sobą klas służących do dopasowywania danych do rozkładów ( z pakietu scipy.stats) i rysowania ich. http://glowingpython.blogspot.com/2012/07/distribution-fitting-with-scipy.html Klasy i metody do napisania: 1. DataContainer -> podobnie jak w zadaniu Boxcar https://brain.fuw.edu.pl/edu/TI:Wst%C4%99p_do_programowania_obiektowego/Zadania Może niech zwraca (i przechowuje?) dane w postaci np.array --Metody * new_data(dt) * new_data_fromiter(iter) * sample(size) - zwraca losową próbke danych * lastn(n) * __str__ 2. DistributionFitter Klasa ta korzysta z wbudowanych metod .fit rozkładów (scipy.stats.norm.fit, expon.fit, logistic.fit ) lub metody ze scipy.optimize (fmin lub minimize) minimalizującej Sum(-LogPdf(x,param)) w podanym zakresie param(s), czyli dopasowywanie rozkladu metodą MLE:MaximalLikelihoodEstimation Należy napisać co najmniej dwie podklasy tej klasy: a) jedną dla rozkladów z scipy.stats, które mają metode .fit (norm,expon,logistic,...) b) i drugą, dla rozkładów które nie mają tej metody (geom,poisson,binom) używającą fmin. --Metody: *__init__(distribution_name,param_bounds) metoda, która ustawia dopasowywaną dystrybucję, oraz zakres przeszukiwanych parametrów * fit(obiekt_DataContainer, ...) - zwraca obiekt podklasy FittedDist * diagnostic() - wypisuje diagnostyke fitowania, którą zebrał podczas wywołania fit (argument retall=True dla funkcji fmin) 3. FittedDist - klasa rozkładu z dopasowanymi parametrami. i jej podklasy dla poszczególnych rozkładów lub co najmniej 2 podklasy: dla rozkladów ciągłych i dyskretnych (które zamiast .pdf mają .pmf) --Metody: *__init__(...) *params() - słownik dofitowanych parametrów *distr_name @property - nazwa dopasowanego rozkladu *loglik @property - log-likelihood z dopasowania rozkladu *reliable_range() - zwraca zakres x-ów w jakim należy rysować/używać rozkład *pdf(x) *cdf(x) *__getattribute__(...) - generyczne przechwycenie i przekazanie parametrów do wszystkich sensownych metod rozkładu, jak wyżej - wyjaśnienie na zajęciach *rvs(size) * __str__ 4. DistFitPlotter Przy pomocy matplotlib rysowane są histogramy, i nałożone gęstości rozkładów, jak w przykładzie http://glowingpython.blogspot.com/2012/07/distribution-fitting-with-scipy.html *hist(dataContainer) *plot(obiekt_FittedDist) *plot_many(lista_FittedDist) *compare_fits(...) 5. DistFitTester Klasa testująca pozostałe klasy. * test1 * test2 * ... * test(distribution) - testuje fitowanie do rozkładu losowej próbki z tego samego rozkładu. 
       
Zadanie polega na napisaniu współpracujących ze sobą klas służących do dopasowywania danych do rozkładów ( z pakietu scipy.stats) i rysowania ich.
http://glowingpython.blogspot.com/2012/07/distribution-fitting-with-scipy.html

Klasy i metody do napisania:

1. DataContainer -> podobnie jak w zadaniu Boxcar https://brain.fuw.edu.pl/edu/TI:Wst%C4%99p_do_programowania_obiektowego/Zadania
Może niech zwraca (i przechowuje?) dane w postaci np.array 
--Metody
* new_data(dt)
* new_data_fromiter(iter)
* sample(size) - zwraca losową próbke danych 
* lastn(n)
* __str__

2. DistributionFitter
Klasa ta korzysta z wbudowanych metod .fit rozkładów (scipy.stats.norm.fit, expon.fit, logistic.fit ) lub metody ze scipy.optimize (fmin lub minimize) minimalizującej Sum(-LogPdf(x,param)) w podanym zakresie param(s), czyli dopasowywanie rozkladu metodą MLE:MaximalLikelihoodEstimation

Należy napisać co najmniej dwie podklasy tej klasy:
a) jedną dla rozkladów z scipy.stats, które mają metode .fit (norm,expon,logistic,...)
b) i drugą, dla rozkładów które nie mają tej metody (geom,poisson,binom) używającą fmin.
--Metody: 
*__init__(distribution_name,param_bounds) metoda, która ustawia dopasowywaną dystrybucję, oraz zakres przeszukiwanych parametrów 
* fit(obiekt_DataContainer, ...) - zwraca obiekt podklasy FittedDist
* diagnostic() - wypisuje diagnostyke fitowania, którą zebrał podczas wywołania fit (argument retall=True dla funkcji fmin)

3. FittedDist - klasa rozkładu z dopasowanymi parametrami. 
i jej podklasy dla poszczególnych rozkładów lub co najmniej 2 podklasy: dla rozkladów ciągłych i dyskretnych (które zamiast .pdf mają .pmf)
--Metody:
*__init__(...)
*params() - słownik dofitowanych parametrów
*distr_name @property - nazwa dopasowanego rozkladu
*loglik     @property - log-likelihood z dopasowania rozkladu
*reliable_range() - zwraca zakres x-ów w jakim należy rysować/używać rozkład
*pdf(x)
*cdf(x)
*__getattribute__(...) - generyczne przechwycenie i przekazanie parametrów do wszystkich sensownych metod rozkładu, jak wyżej - wyjaśnienie na zajęciach
*rvs(size) 
* __str__

4. DistFitPlotter
Przy pomocy matplotlib rysowane są histogramy, i nałożone gęstości rozkładów, jak 
w przykładzie http://glowingpython.blogspot.com/2012/07/distribution-fitting-with-scipy.html
*hist(dataContainer)
*plot(obiekt_FittedDist)
*plot_many(lista_FittedDist)
*compare_fits(...)

5. DistFitTester
Klasa testująca pozostałe klasy.
* test1
* test2
* ...
* test(distribution) - testuje fitowanie do rozkładu losowej próbki z tego samego rozkładu.
                                
                            
# Generyczne generowanie metod w klasie # poprzez przesloniecie metody __getattribute__ object.__getattribute__? 
       

Type: <type 'wrapper_descriptor'>

Definition: object.__getattribute__( [noargspec] )

Docstring:


x.__getattribute__('name') <==> x.name
# Generyczne generowanie metod w klasie # poprzez przesloniecie metody __getattribute__ class A(object): def f(self,x): return 2*x def g(self,x): return 4*x def h(self): return 'h' class B(A): def j(self): return 'j' def __getattribute__(self,fname): if fname in ('f','g'): #Dla dwóch nazw funkcji zwracamy trochę zmienione funkcje return lambda x: super(B,self).__getattribute__(fname)(x)+1 else: #Dla pozostałych nazw bez zmian return super(B,self).__getattribute__(fname) ## ## 
       
b=B() print b.h() print b.j() 
       
h
j
print b.f(1) 
       
3
print b.g(1) 
       
5
 
       
######## # Przykladowe rozwiazanie do uzupelnienia import scipy.stats from numpy import sum ######## Klasa czesciowo abstrakcyjna, z ktorej bedziemy dziedziczyc class FittedDistribution(): def __init__(self,fit_params): self._fit_params = fit_params def scipy_distr(self): raise Exception('Abstract method') def __str__(self): return "{0}(params={1},scipy={2})".format(self.__class__.__name__, self._fit_params, self.scipy_distr()) def pdf(self, x): self.scipy_distr().pdf(x, *self._fit_params) def logpdf(self, x): self.scipy_distr().logpdf(x, *self._fit_params) def loglik(self,x): return sum(self.logpdf(x)) #TODO more methods ########## W koncu definiujemy klasy których będziemy używać class NormFittedDistribution(FittedDistribution): def scipy_distr(self): return scipy.stats.norm class GeomFittedDistribution(FittedDistribution): def scipy_distr(self): return scipy.stats.geom class PoissonFittedDistribution(FittedDistribution): def scipy_distr(self): return scipy.stats.poisson ## ## 
       
print NormFittedDistribution((0,1)) 
       
NormFittedDistribution(params=(0,
1),scipy=<scipy.stats.distributions.norm_gen object at
0x5822b50>)
######## Klasa czesciowo abstrakcyjna, z ktorej bedziemy dziedziczyc class DistributionFitter(): def fitted_distr_class(self): '''Returns an appropriate FittedDistribution Subclass''' raise Exception('Abstract method') def scipy_distr(self): '''Returns an appropriate scipy.stats.distr object''' raise Exception('Abstract method') def _fit_params(self,data): '''The function which makes the actual fitting. To be written in subclasses. ''' raise Exception('Abstract method') def fit(self,data): '''Fits parameters and returns FittedDistribution subclass.''' fit_params = self._fit_params(data) fitted = self.fitted_distr(fit_params) self._diagnostics = "LogLik.{0}".format(fitted.loglik(data)) return fitted def fitted_distr(self,params): '''Returns an appropriate FittedDistribution object''' FClass = self.fitted_distr_class() return FClass(params) def diagnostics(self): return self._diagnostics ######## Definiujemy podklasy które potrafią fitować w konkretny sposób class DistributionFitter_simple(DistributionFitter): def _fit_params(self,data): '''Fits parameters using fit method: scipy.stats.distr.fit''' params = self.scipy_distr().fit(data) return params class DistributionFitter_fmin(DistributionFitter): def _fit_params(self,data): '''Fits parameters using scipy.optimize.fmin''' #TODO return params def __init__(self,param_range): '''Saves range of parameters to be fitted.''' #TODO pass ########## W koncu definiujemy klasy których będziemy używać class NormDistributionFitter(DistributionFitter_simple): def fitted_distr_class(self): return NormFittedDistribution def scipy_distr(self): return scipy.stats.norm class GeomDistributionFitter(DistributionFitter_simple): def fitted_distr_class(self): return GeomFittedDistribution def scipy_distr(self): return scipy.stats.geom class PoissonDistributionFitter(DistributionFitter_fmin): def fitted_distr_class(self): return PoissonFittedDistribution def scipy_distr(self): return scipy.stats.poisson ### ### 
       
#Testujemy klasy from numpy import mean,var class DistFitTester(): def test_norm(self): nfitter = NormDistributionFitter() print "Used fitter: {0}".format(nfitter) rsample = scipy.stats.norm.rvs(loc=1,scale=2,size=1000) print "Sample: Mean:{0},Var:{1}".format(mean(rsample),var(rsample)) fit = nfitter.fit(rsample) print "Fitted:{0}".format(fit) dft=DistFitTester() dft.test_norm() 
       
Used fitter: <__main__.NormDistributionFitter instance at
0x598a2d8>
Sample: Mean:1.01391751039,Var:3.845176297
Fitted:NormFittedDistribution(params=(1.0139175103943179,
1.960912108433795),scipy=<scipy.stats.distributions.norm_gen
object at 0x5822b50>)
from numpy import mean,var,sqrt #Dodajemy nowe klasy potrafiace fitowac w inny sposob class DistributionFitter_moments(DistributionFitter): def _fit_args(self,data): loc = mean(data) scale = sqrt(var(data)) return dict(loc=loc, scale=scale) class NormDistributionFitter_bymoments(DistributionFitter_moments): def fitted_distr_class(self): return NormFittedDistribution ### ### 
       
http://pastebin.com/8Vw3T8LF