Added binomial derivative and test

This commit is contained in:
Alan Saul 2016-04-01 21:21:37 +01:00
parent 91bebc8161
commit 378ac0ad06
2 changed files with 44 additions and 14 deletions

View file

@ -66,14 +66,17 @@ class Binomial(Likelihood):
:rtype: float :rtype: float
""" """
N = Y_metadata['trials'] N = Y_metadata['trials']
assert N.shape == y.shape
nchoosey = special.gammaln(N+1) - special.gammaln(y+1) - special.gammaln(N-y+1) nchoosey = special.gammaln(N+1) - special.gammaln(y+1) - special.gammaln(N-y+1)
return nchoosey + y*np.log(inv_link_f) + (N-y)*np.log(1.-inv_link_f) return nchoosey + y*np.log(inv_link_f) + (N-y)*np.log(1.-inv_link_f)
def dlogpdf_dlink(self, inv_link_f, y, Y_metadata=None): def dlogpdf_dlink(self, inv_link_f, y, Y_metadata=None):
""" """
Gradient of the pdf at y, given inverse link of f w.r.t inverse link of f. Gradient of the pdf at y, given inverse link of f w.r.t inverse link of f.
.. math::
\\frac{d^{2}\\ln p(y_{i}|\\lambda(f_{i}))}{d\\lambda(f)^{2}} = \\frac{y_{i}}{\\lambda(f)} - \\frac{(N-y_{i})}{(1-\\lambda(f))}
:param inv_link_f: latent variables inverse link of f. :param inv_link_f: latent variables inverse link of f.
:type inv_link_f: Nx1 array :type inv_link_f: Nx1 array
:param y: data :param y: data
@ -83,7 +86,8 @@ class Binomial(Likelihood):
:rtype: Nx1 array :rtype: Nx1 array
""" """
N = Y_metadata['trials'] N = Y_metadata['trials']
return y/inv_link_f - (N-y)/(1-inv_link_f) assert N.shape == y.shape
return y/inv_link_f - (N-y)/(1.-inv_link_f)
def d2logpdf_dlink2(self, inv_link_f, y, Y_metadata=None): def d2logpdf_dlink2(self, inv_link_f, y, Y_metadata=None):
""" """
@ -92,7 +96,7 @@ class Binomial(Likelihood):
.. math:: .. math::
\\frac{d^{2}\\ln p(y_{i}|\\lambda(f_{i}))}{d\\lambda(f)^{2}} = \\frac{-y_{i}}{\\lambda(f)^{2}} - \\frac{(1-y_{i})}{(1-\\lambda(f))^{2}} \\frac{d^{2}\\ln p(y_{i}|\\lambda(f_{i}))}{d\\lambda(f)^{2}} = \\frac{-y_{i}}{\\lambda(f)^{2}} - \\frac{(N-y_{i})}{(1-\\lambda(f))^{2}}
:param inv_link_f: latent variables inverse link of f. :param inv_link_f: latent variables inverse link of f.
:type inv_link_f: Nx1 array :type inv_link_f: Nx1 array
@ -107,7 +111,32 @@ class Binomial(Likelihood):
(the distribution for y_i depends only on inverse link of f_i not on inverse link of f_(j!=i) (the distribution for y_i depends only on inverse link of f_i not on inverse link of f_(j!=i)
""" """
N = Y_metadata['trials'] N = Y_metadata['trials']
return -y/np.square(inv_link_f) - (N-y)/np.square(1-inv_link_f) assert N.shape == y.shape
return -y/np.square(inv_link_f) - (N-y)/np.square(1.-inv_link_f)
def d3logpdf_dlink3(self, inv_link_f, y, Y_metadata=None):
"""
Third order derivative log-likelihood function at y given inverse link of f w.r.t inverse link of f
.. math::
\\frac{d^{2}\\ln p(y_{i}|\\lambda(f_{i}))}{d\\lambda(f)^{2}} = \\frac{2y_{i}}{\\lambda(f)^{3}} - \\frac{2(N-y_{i})}{(1-\\lambda(f))^{3}}
:param inv_link_f: latent variables inverse link of f.
:type inv_link_f: Nx1 array
:param y: data
:type y: Nx1 array
:param Y_metadata: Y_metadata not used in binomial
:returns: Diagonal of log hessian matrix (second derivative of log likelihood evaluated at points inverse link of f.
:rtype: Nx1 array
.. Note::
Will return diagonal of hessian, since every where else it is 0, as the likelihood factorizes over cases
(the distribution for y_i depends only on inverse link of f_i not on inverse link of f_(j!=i)
"""
N = Y_metadata['trials']
assert N.shape == y.shape
inv_link_f2 = np.square(inv_link_f)
return 2*y/inv_link_f**3 - 2*(N-y)/(1.-inv_link_f)**3
def samples(self, gp, Y_metadata=None): def samples(self, gp, Y_metadata=None):
""" """

View file

@ -117,6 +117,9 @@ class TestNoiseModels(object):
self.positive_Y = np.exp(self.Y.copy()) self.positive_Y = np.exp(self.Y.copy())
tmp = np.round(self.X[:, 0]*3-3)[:, None] + np.random.randint(0,3, self.X.shape[0])[:, None] tmp = np.round(self.X[:, 0]*3-3)[:, None] + np.random.randint(0,3, self.X.shape[0])[:, None]
self.integer_Y = np.where(tmp > 0, tmp, 0) self.integer_Y = np.where(tmp > 0, tmp, 0)
self.ns = np.random.poisson(50, size=self.N)[:, None]
p = np.abs(np.cos(2*np.pi*self.X + np.random.normal(scale=.2, size=(self.N, self.D)))).mean(1)
self.binomial_Y = np.array([np.random.binomial(self.ns[i], p[i]) for i in range(p.shape[0])])[:, None]
self.var = 0.2 self.var = 0.2
self.deg_free = 4.0 self.deg_free = 4.0
@ -204,15 +207,6 @@ class TestNoiseModels(object):
}, },
"laplace": True "laplace": True
}, },
#"Student_t_log": {
#"model": GPy.likelihoods.StudentT(gp_link=link_functions.Log(), deg_free=5, sigma2=self.var),
#"grad_params": {
#"names": [".*t_noise"],
#"vals": [self.var],
#"constraints": [(".*t_noise", self.constrain_positive), (".*deg_free", self.constrain_fixed)]
#},
#"laplace": True
#},
"Gaussian_default": { "Gaussian_default": {
"model": GPy.likelihoods.Gaussian(variance=self.var), "model": GPy.likelihoods.Gaussian(variance=self.var),
"grad_params": { "grad_params": {
@ -273,6 +267,13 @@ class TestNoiseModels(object):
"laplace": True, "laplace": True,
"ep": False #Should work though... "ep": False #Should work though...
}, },
"Binomial_default": {
"model": GPy.likelihoods.Binomial(),
"link_f_constraints": [partial(self.constrain_bounded, lower=0, upper=1)],
"Y": self.binomial_Y,
"Y_metadata": {'trials': self.ns},
"laplace": True,
},
#, #,
#GAMMA needs some work!"Gamma_default": { #GAMMA needs some work!"Gamma_default": {
#"model": GPy.likelihoods.Gamma(), #"model": GPy.likelihoods.Gamma(),