Source code for tailestim.estimators.base

"""Base class for tail index estimation."""

from abc import ABC, abstractmethod
from typing import Any, Dict, Tuple, Union

import numpy as np
from numpy.random import BitGenerator, Generator, RandomState, SeedSequence

from .result import TailEstimatorResult


[docs] class BaseTailEstimator(ABC): """Abstract base class for tail index estimation. This class defines the common interface and utility methods for all tail estimation implementations. Each specific estimation method should inherit from this class and implement the required abstract methods. Parameters ---------- bootstrap : bool, default=True Whether to use double-bootstrap for optimal threshold selection. May not be applicable for all methods. base_seed: None | SeedSequence | BitGenerator | Generator | RandomState, default=None Base random seed for reproducibility of bootstrap. Only used for methods with bootstrap. **kwargs : dict Additional parameters specific to each estimation method. """ def __init__( self, bootstrap: bool = True, base_seed: Union[ None, SeedSequence, BitGenerator, Generator, RandomState ] = None, **kwargs, ): self.bootstrap = bootstrap self.base_seed = base_seed self.kwargs = kwargs self.results = None @abstractmethod def _estimate(self, ordered_data: np.ndarray) -> Tuple: """Core estimation method to be implemented by each specific estimator. Parameters ---------- ordered_data : np.ndarray Data array in decreasing order. Returns ------- Tuple Estimation results specific to each method. """ pass
[docs] def fit(self, data: np.ndarray) -> None: """Fit the estimator to the data. Parameters ---------- data : np.ndarray Input data array (e.g., degree sequence). The data will automatically be sorted in decreasing order. """ ordered_data = np.sort(data)[ ::-1 ] # Each estimating functions require the data to be in decreasing order self.results = self._estimate(ordered_data)
[docs] @abstractmethod def get_params(self) -> Dict[str, Any]: """Get the parameters of the estimator. Returns ------- dict Dictionary containing the parameters of the estimator. """ return {"bootstrap": self.bootstrap, "base_seed": self.base_seed, **self.kwargs}
[docs] @abstractmethod def get_result(self) -> TailEstimatorResult: """Get the estimated parameters. Returns ------- TailEstimatorResult Object containing the estimated parameters. Parameters and results included varies by method. Examples -------- >>> hill = HillEstimator() >>> hill.fit(data) >>> result = hill.get_result() >>> gamma = result.gamma_ >>> xi = result.xi_ """ if self.results is None: raise ValueError("Model not fitted yet. Call fit() first.") return TailEstimatorResult()
[docs] def __repr__(self) -> str: """Return a string representation of the estimator.""" return f"{self.__class__.__name__}(bootstrap={self.bootstrap}, base_seed={self.base_seed}, kwargs={self.kwargs})"
[docs] def __str__(self) -> str: """Format estimation object as a string.""" # Create a string with the estimator type and fitted status estim_str = "-" * 50 + "\n" estim_str += f"Estimator Type: {self.__class__.__name__}\n" estim_str += "-" * 50 + "\n" estim_str += f"Fitted: {'Yes' if self.results is not None else 'No'}\n" # Add the arguments provided estim_str += "Arguments:\n" estim_str += f" bootstrap: {self.bootstrap}\n" estim_str += f" base_seed: {self.base_seed}\n" # Add any additional kwargs if self.kwargs: for key, value in self.kwargs.items(): estim_str += f" {key}: {value}\n" # If the model is not fitted, return just the estim_str if self.results is None: return estim_str + "Model not fitted yet. Call fit() first." return estim_str