Source code for skfolio.distribution._base

"""Base Distribution Estimator."""

# Copyright (c) 2023-2026
# Authors: The skfolio developers
# Credits: Matteo Manzi, Vincent Maladière, Carlo Nicolini
# SPDX-License-Identifier: BSD-3-Clause

from __future__ import annotations

from abc import ABC, abstractmethod
from enum import auto

import numpy as np
import sklearn.base as skb

from skfolio.typing import ArrayLike, FloatArray
from skfolio.utils.tools import AutoEnum


[docs] class SelectionCriterion(AutoEnum): """Enum representing the selection criteria. Attributes ---------- AIC : str Akaike Information Criterion (AIC) BIC : str Bayesian Information Criterion (BIC) """ AIC = auto() BIC = auto()
[docs] class BaseDistribution(skb.BaseEstimator, ABC): """Base Distribution Estimator. This abstract class serves as a foundation for distribution models in skfolio. random_state : int, RandomState instance or None, default=None Seed or random state to ensure reproducibility. """ def __init__(self, random_state: int | None = None): self.random_state = random_state @property @abstractmethod def n_params(self) -> int: """Number of model parameters.""" pass @property @abstractmethod def fitted_repr(self) -> str: """String representation of the fitted model.""" pass
[docs] @abstractmethod def fit(self, X: ArrayLike, y=None) -> BaseDistribution: """Fit the univariate distribution model. Parameters ---------- X : array-like of shape (n_observations, n_features) The input data. y : None Ignored. Provided for compatibility with scikit-learn's API. Returns ------- self : BaseDistribution Returns the instance itself. """ pass
[docs] @abstractmethod def score_samples(self, X: ArrayLike) -> FloatArray: """Compute the log-likelihood of each sample (log-pdf) under the model. Parameters ---------- X : array-like of shape (n_observations, n_features) The input data. Returns ------- density : ndarray of shape (n_observations,) Log-likelihood values for each observation in X. """ pass
[docs] def sample(self, n_samples: int = 1): """Generate random samples from the fitted model. Parameters ---------- n_samples : int, default=1 Number of samples to generate. Returns ------- X : array-like of shape (n_samples, 1) List of samples. """ pass
[docs] def score(self, X: ArrayLike, y=None): """Compute the total log-likelihood under the model. Parameters ---------- X : array-like of shape (n_observations, n_features) An array of data points for which the total log-likelihood is computed. y : None Ignored. Provided for compatibility with scikit-learn's API. Returns ------- logprob : float The total log-likelihood (sum of log-pdf values). """ return np.sum(self.score_samples(X))
[docs] def aic(self, X: ArrayLike) -> float: r"""Compute the Akaike Information Criterion (AIC) for the model given data X. The AIC is defined as: .. math:: \mathrm{AIC} = -2 \, \log L \;+\; 2 k, where - :math:`\log L` is the total log-likelihood - :math:`k` is the number of parameters in the model A lower AIC value indicates a better trade-off between model fit and complexity. Parameters ---------- X : array-like of shape (n_observations, n_features) The input data on which to compute the AIC. Notes ----- In practice, both AIC and BIC measure the trade-off between model fit and complexity, but BIC tends to prefer simpler models for large :math:`n` because of the :math:`\ln(n)` term. Returns ------- aic : float The AIC of the fitted model on the given data. References ---------- .. [1] "A new look at the statistical model identification", Akaike (1974). """ log_likelihood = self.score(X) return 2 * (self.n_params - log_likelihood)
[docs] def bic(self, X: ArrayLike) -> float: r"""Compute the Bayesian Information Criterion (BIC) for the model given data X. The BIC is defined as: .. math:: \mathrm{BIC} = -2 \, \log L \;+\; k \,\ln(n), where - :math:`\log L` is the (maximized) total log-likelihood - :math:`k` is the number of parameters in the model - :math:`n` is the number of observations A lower BIC value suggests a better fit while imposing a stronger penalty for model complexity than the AIC. Parameters ---------- X : array-like of shape (n_observations, n_features) The input data on which to compute the BIC. Returns ------- bic : float The BIC of the fitted model on the given data. Notes ----- In practice, both AIC and BIC measure the trade-off between model fit and complexity, but BIC tends to prefer simpler models for large :math:`n` because of the :math:`\ln(n)` term. References ---------- .. [1] "Estimating the dimension of a model", Schwarz, G. (1978). """ log_likelihood = self.score(X) n = X.shape[0] return -2 * log_likelihood + self.n_params * np.log(n)