The model I’m building at the moment requires that a random variable, r, is drawn from a modified exponential distribution, that looks like this:
where L is a free parameter.
I recently moved to PyMC3 from PyStan, where I’ve implemented this prior before. For those familiar with Stan, the way I set this up there was:
functions {
def custom_lpdf(real r, real L){
return log((1/(2*L^3)) * (r*r) * exp(-r/L));
}
}
...
model {
r ~ custom(L);
}
I’m struggling to find guidelines on how to implement this same feature in PyMC3. Does anybody have experience setting up custom prior functions in PyMC3 that could point me in the right direction?
import pymc3 as pm
def custom_lpdf(L):
def lpdf(r):
return (2*pm.math.log(r)) - (r/L) - (3*pm.math.log(L)) - pm.math.log(2)
return lpdf
with pm.Model() as model:
r = pm.DensityDist('r', custom_lpdf(2), testval=1)
trace = pm.sample()
The drawn samples can then be found in trace['r']. But in my test, this produced a lot of divergent samples, which may introduce a bias in your results. You can fix that by telling the Hamilton-Monte-Carlo-Sampler to sample its values in a transformed space, where the derivatives are nicer, by writing
import pymc3 as pm
def custom_lpdf(L):
def lpdf(r):
return (2*pm.math.log(r)) - (r/L) - (3*pm.math.log(L)) - pm.math.log(2)
return lpdf
with pm.Model() as model:
r = pm.DensityDist('r', custom_lpdf(2), testval=1,
transform=pm.distributions.transforms.Log())
trace = pm.sample()
Huge thanks for the swift and clear response! I had bits and pieces of the puzzle but your examples have made it clear what I should be doing.
If I understand correctly the log-probability of your modified exponential distribution is
That’s right (although the 2 should be logged, I think, although as @Dominik points out it’s inclusion doesn’t matter), and what I do in practice.
I think it is correct, as it is conditioned on L as well in the Stan code snippet.
This is correct— it’s a prior on distances to observed star where L is the distance scale and r is the distances. In practice, I have L as a hyperparameter and draw the latent parameters r from the prior function p(r | L).