Package BIP :: Package Bayes :: Package general :: Module Bayes
[hide private]
[frames] | no frames]

Source Code for Module BIP.Bayes.general.Bayes

  1  """ 
  2  This module implements classes to represent an arbitrary Bayesian random variable. 
  3   
  4  """ 
  5  # copyright 2007 Flavio Codeco Coelho 
  6  # Licensed under GPL v3 
  7  from numpy import arange,compress, array, exp 
  8  import like, sys 
  9  import pylab as P 
 10  from scipy import stats 
 11   
 12  ## Conjugate prior list: distribution types which have supported conjugate prior  
 13   
 14  conjlist = [ 
 15      'bernoulli', 
 16      'binom', 
 17      'nbinom', #negative binomial 
 18      'poisson', 
 19      'geom', #geometric 
 20      ] 
 21   
 22  ## Factory functions for continuous and discrete variables  
23 -def Continuous(priortype,pars, range,resolution=1024):
24 return __BayesC(priortype,pars, range,resolution)
25
26 -def Discrete(priortype,pars, range,resolution=1024):
27 return __BayesD(priortype,pars, range,resolution)
28
29 -class _BayesVar(object):
30 """ 31 Bayesian random variate. 32 """
33 - def __init__(self, disttype,pars, rang,resolution=1024):
34 ''' 35 Initializes random variable. 36 37 :parameters: 38 - `disttype`: must be a valid RNG from scipy.stats 39 - `pars`: are the parameters of the distribution. 40 - `rang`: range of the variable support. 41 - `resolution`: resolution of the support. 42 ''' 43 self.distn = dist_type.name 44 self._flavorize(disttype(*pars), disttype) 45 self.pars = pars 46 self.rang = rang 47 self.res = (rang[1]-rang[0])*1./resolution 48 self.likefun = self._Likelihood(self.distn) 49 self.likelihood = None 50 self.data = [] 51 self.posterior=array([])
52
53 - def _flavorize(self,pt, ptbase):
54 ''' 55 Add methods from distribution type 56 ''' 57 self.cdf = pt.cdf 58 self.isf = pt.isf 59 if isinstance(ptbase,stats.rv_continuous): 60 self.pdf = pt.pdf 61 elif isinstance(ptbase,stats.rv_discrete): 62 self.pdf = pt.pmf 63 else: sys.exit('Invalid distribution object') 64 self.ppf = pt.ppf 65 self.rvs = pt.rvs
66 - def _update(self):
67 """ 68 Calculate likelihood function 69 """ 70 if self.data: 71 d = self.data[-1] 72 sc = self.pars[1] 73 m = self.rang[0] 74 M = self.rang[1] 75 step = self.res 76 #self.likefun returns log-likelihood 77 lik = exp(array([self.likefun((d,i,sc)) for i in arange(m,M,step)])) 78 self.likelihood = lik/sum(lik)
79
80 - def addData(self, data = []):
81 """ 82 Adds dataset to variable's data store 83 """ 84 self.data.append(array(data)) 85 self._update()
86
87 - def getPriorSample(self,n):
88 ''' 89 Returns a sample from the prior distribution 90 91 :Parameters: 92 - `n`: Sample size. 93 ''' 94 return self.rvs(size=n)
95
96 - def getPriorDist(self):
97 """ 98 Returns the prior PDF. 99 """ 100 return self.pdf(arange(self.rang[0],self.rang[1],self.res))
101
102 - def getPosteriorSample(self, n):
103 """ 104 Return a sample of the posterior distribution. 105 Uses SIR algorithm. 106 107 :Parameters: 108 - `n`: Sample size. 109 """ 110 if self.posterior.any():# Use last posterior as prior 111 k= stats.kde.gausian_kde(self.posterior) 112 s= k.resample(n) 113 else: 114 s = self.getPriorSample(n) 115 if self.data: 116 m = self.rang[0] 117 M = self.rang[1] 118 step = self.res 119 supp = arange(m,M,step)#support 120 s = compress(less(s.ravel(),M) & greater(s.ravel(),m),s)#removing out-of-range samples 121 d = stats.uniform.rvs(loc=0,scale=1,size=len(s))#Uniform 0-1 samples 122 w = self.pdf(supp)*self.likelihood 123 w = w/sum(w) #normalizing weights 124 sx = searchsorted(supp,s) 125 w = w[sx-1]#search sorted returns 1-based binlist 126 post = compress(d<w,s) 127 self.posterior = post 128 return post 129 else: 130 return array([])
131
132 - def _Likelihood(self,typ):
133 ''' 134 Defines parametric family of the likelihood function. 135 Returns likelihood function. 136 137 :Parameters: 138 - `typ`: must be a string. 139 ''' 140 #TODO: expand for more distribution types 141 if typ == 'norm': 142 return lambda(x):like.Normal(x[0],x[1],1./x[2]) 143 elif typ == 'expon': 144 return lambda(x):(1./x[2])**x[0].size*exp(-(1./x[2])*sum(x[0])) 145 elif typ == 'beta': 146 return lambda(x):like.Beta(x[0],x[1],x[2])
147
148 - def _postFromConjugate(dname,*pars):
149 ''' 150 Returns posterior distribution function using conjugate prior theory 151 ''' 152 if not self.data: 153 return 154 if dname == 'bernoulli': 155 pdist = stats.beta(pars[0])
156 # TODO: finish this 157
158 -class __BayesC(_BayesVar, stats.rv_continuous):
159 - def __init__(self, priortype,pars, range,resolution=512):
160 _BayesVar.__init__(self, priortype,pars, range,resolution)
161
162 -class __BayesD(_BayesVar, stats.rv_discrete):
163 - def __init__(self, priortype,pars, range,resolution=512):
164 _BayesVar.__init__(self, priortype,pars, range,resolution)
165 if __name__=="__main__": 166 #bv = BayesVar(stats.norm,(3,1),range=(0,5)) 167 bv = Continuous(stats.norm,(3,1),range=(0,5), resolution=1000) 168 data = ones(10) 169 bv.addData(data) 170 p = bv.getPosteriorSample(200000) 171 P.plot(arange(bv.rang[0],bv.rang[1], bv.res),bv.likelihood/max(bv.likelihood), 'ro', lw=2) 172 P.plot(arange(bv.rang[0],bv.rang[1], bv.res),bv.getPriorDist(),'g+',lw=2) 173 P.hist(p, normed=1) 174 P.legend(['Likelihood','Prior', 'Posterior']) 175 P.title('Bayesian inference') 176 P.savefig('bayesvar.png',dpi=400) 177 P.show() 178