Skip to content

Commit

Permalink
[ENH] activate tests for distribution base class defaults (#266)
Browse files Browse the repository at this point in the history
By accident, the tests for distribution base class default methods,
e.g., obtaining `pdf` form `log_pdf` if not implemented, were not
activated.

This PR remedies that, and also upgrades the test class to the new
distribution extension contract.

Depends on #281, for bugfixes of
bugs discovered through enabling the tests.
  • Loading branch information
fkiraly authored Apr 25, 2024
1 parent f1ced8f commit c3ef686
Showing 1 changed file with 64 additions and 21 deletions.
85 changes: 64 additions & 21 deletions skpro/distributions/tests/test_base_default_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from scipy.special import erfinv

from skpro.distributions.base import BaseDistribution
from skpro.utils.estimator_checks import check_estimator


# normal distribution with exact implementations removed
Expand All @@ -27,34 +28,76 @@ class _DistrDefaultMethodTester(BaseDistribution):
"capabilities:approx": ["pdfnorm", "mean", "var", "energy", "log_pdf", "cdf"],
"capabilities:exact": ["pdf", "ppf"],
"distr:measuretype": "continuous",
"broadcast_init": "on",
}

def __init__(self, mu, sigma, index=None, columns=None):
self.mu = mu
self.sigma = sigma
self.index = index
self.columns = columns

self._mu, self._sigma = self._get_bc_params(self.mu, self.sigma)
shape = self._mu.shape
super().__init__(index=index, columns=columns)

if index is None:
index = pd.RangeIndex(shape[0])
def _ppf(self, p):
"""Quantile function = percent point function = inverse cdf.
if columns is None:
columns = pd.RangeIndex(shape[1])
Parameters
----------
p : 2D np.ndarray, same shape as ``self``
values to evaluate the ppf at
super().__init__(index=index, columns=columns)
Returns
-------
2D np.ndarray, same shape as ``self``
ppf values at the given points
"""
mu = self._bc_params["mu"]
sigma = self._bc_params["sigma"]

icdf_arr = mu + sigma * np.sqrt(2) * erfinv(2 * p - 1)
return icdf_arr

def _pdf(self, x):
"""Probability density function.
Parameters
----------
x : 2D np.ndarray, same shape as ``self``
values to evaluate the pdf at
Returns
-------
2D np.ndarray, same shape as ``self``
pdf values at the given points
"""
mu = self._bc_params["mu"]
sigma = self._bc_params["sigma"]

pdf_arr = np.exp(-0.5 * ((x - mu) / sigma) ** 2)
pdf_arr = pdf_arr / (sigma * np.sqrt(2 * np.pi))
return pdf_arr

@classmethod
def get_test_params(cls, parameter_set="default"):
"""Return testing parameter settings for the estimator."""
# array case examples
params1 = {"mu": [[0, 1], [2, 3], [4, 5]], "sigma": 1}
params2 = {
"mu": 0,
"sigma": 1,
"index": pd.Index([1, 2, 5]),
"columns": pd.Index(["a", "b"]),
}
# scalar case examples
params3 = {"mu": 1, "sigma": 2}
return [params1, params2, params3]


def test_base_default():
"""Test default methods.
The _DistributionDefaultMethodTester class is not detected
by TestAllDistributions (it is private), so we need to test it explicitly.
def ppf(self, p):
"""Quantile function = percent point function = inverse cdf."""
d = self.loc[p.index, p.columns]
icdf_arr = d.mu + d.sigma * np.sqrt(2) * erfinv(2 * p.values - 1)
return pd.DataFrame(icdf_arr, index=p.index, columns=p.columns)

def pdf(self, x):
"""Probability density function."""
d = self.loc[x.index, x.columns]
pdf_arr = np.exp(-0.5 * ((x.values - d.mu) / d.sigma) ** 2)
pdf_arr = pdf_arr / (d.sigma * np.sqrt(2 * np.pi))
return pd.DataFrame(pdf_arr, index=x.index, columns=x.columns)
check_estimator invokes a TestAllDistributions call.
"""
check_estimator(_DistrDefaultMethodTester, raise_exceptions=True)

0 comments on commit c3ef686

Please sign in to comment.