Skip to content

Commit 0654e7f

Browse files
committed
add alternative parametrization for AsymmetricLaplace
1 parent c4683fb commit 0654e7f

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

pymc/distributions/continuous.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,13 @@ class AsymmetricLaplace(Continuous):
14651465
Variance :math:`\frac{1+\kappa^{4}}{b^2\kappa^2 }`
14661466
======== ========================
14671467
1468+
AsymmetricLaplace distribution can be parameterized either in terms of kappa
1469+
or q. The link between the two parametrizations is given by
1470+
1471+
.. math::
1472+
1473+
\kappa = \sqrt(\frac{q}{1-q})
1474+
14681475
Parameters
14691476
----------
14701477
kappa : tensor_like of float
@@ -1473,20 +1480,41 @@ class AsymmetricLaplace(Continuous):
14731480
Location parameter.
14741481
b : tensor_like of float
14751482
Scale parameter (b > 0).
1483+
q : tensor_like of float
1484+
Symmetry parameter (0 < q < 1).
1485+
1486+
Notes
1487+
-----
1488+
The parametrization in terms of q is useful for quantile regression with q being the quantile
1489+
of interest.
14761490
"""
14771491
rv_op = asymmetriclaplace
14781492

14791493
@classmethod
1480-
def dist(cls, kappa, mu, b, *args, **kwargs):
1494+
def dist(cls, kappa=None, mu=None, b=None, q=None, *args, **kwargs):
1495+
kappa = cls.get_kappa(kappa, q)
14811496
b = at.as_tensor_variable(floatX(b))
14821497
kappa = at.as_tensor_variable(floatX(kappa))
1483-
mu = mu = at.as_tensor_variable(floatX(mu))
1484-
1485-
# mean = mu - (kappa - 1 / kappa) / b
1486-
# variance = (1 + kappa ** 4) / (kappa ** 2 * b ** 2)
1498+
mu = at.as_tensor_variable(floatX(mu))
14871499

14881500
return super().dist([b, kappa, mu], *args, **kwargs)
14891501

1502+
@classmethod
1503+
def get_kappa(cls, kappa=None, q=None):
1504+
if kappa is not None and q is not None:
1505+
raise ValueError(
1506+
"Incompatible parameterization. Either use "
1507+
"kappa or q to specify the distribution."
1508+
)
1509+
elif q is not None:
1510+
if isinstance(q, Variable):
1511+
q = check_parameters(q, q > 0, q < 1, msg="0 < q < 1")
1512+
else:
1513+
assert np.all((np.asarray(q) > 0) | (np.asarray(q) < 1))
1514+
kappa = (q / (1 - q)) ** 0.5
1515+
1516+
return kappa
1517+
14901518
def moment(rv, size, b, kappa, mu):
14911519
mean = mu - (kappa - 1 / kappa) / b
14921520

pymc/tests/distributions/test_continuous.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,19 @@ def seeded_asymmetriclaplace_rng_fn(self):
16471647
]
16481648

16491649

1650+
class TestAsymmetricLaplaceQ(BaseTestDistributionRandom):
1651+
pymc_dist = pm.AsymmetricLaplace
1652+
1653+
pymc_dist_params = {"mu": 0.0, "b": 2.0, "q": 0.9}
1654+
expected_kappa = pymc_dist.get_kappa(None, pymc_dist_params["q"])
1655+
expected_rv_op_params = {
1656+
"b": pymc_dist_params["b"],
1657+
"kappa": expected_kappa,
1658+
"mu": pymc_dist_params["mu"],
1659+
}
1660+
checks_to_run = ["check_pymc_params_match_rv_op"]
1661+
1662+
16501663
class TestExGaussian(BaseTestDistributionRandom):
16511664
def exgaussian_rng_fn(self, mu, sigma, nu, size, normal_rng_fct, exponential_rng_fct):
16521665
return normal_rng_fct(mu, sigma, size=size) + exponential_rng_fct(scale=nu, size=size)

0 commit comments

Comments
 (0)