Hi,
I’m quite new to pymc (I’m using v5.6.1), so my question may not be a good one…
I want to use LKJCholeskyCov with the sd_dist parameter, which requires a distribution of the standard deviation. I want to use InverseGamma for the variance, so I need to get the “square-root of a distribution”.
So I tried to write a general transformation of a (continuous, non-negative) distribution in_dist, to an out_dist, such that for some c != 0, if X ~ in_dist, then Y = X**c ~ out_dist
I found CustomDist, and tried the following:
import pymc
class PowerTransformed:
"""
Power-transformed distribution: Y = X**c, X ~ in_dist
in_dist: a PyMC distribution instance
c: power (any nonzero real)
"""
def __init__(self, in_dist, c: float):
assert c != 0.0
self.in_dist = in_dist
self.c = c
def logp(self, y: float):
assert y >= 0.0
c = self.c
x = pymc.math.pow(y, 1.0 / c)
log_jac = -pymc.math.log(pymc.math.abs(c)) + (1.0 / c - 1) * pymc.math.log(y)
return self.in_dist.logp(x) + log_jac
def random(self, size):
x = pymc.draw(self.in_dist, draws=size)
return x ** self.c
def dist(self, **kwargs):
return pymc.CustomDist(
name=f"X**{self.c})",
logp=self.logp,
#random=lambda rng, size=None: self.random(size=size),
shape=kwargs.get("shape", ()),
dtype=kwargs.get("dtype", "float64"),
)
The “random=…” in CustomDist is commented-out because it raises an error:
BlockModelAccessError: Model variables cannot be created in the random function. Use the
.dist
API to create such variables.
But I don’t mange to use the “dist=” parameter instead.
I hope that’s not too much of a mess.
How can this (or something else) be made to work?