From 65d8de60e3471194953fb3b9f0e24d54f6498cbb Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Mon, 30 Mar 2020 19:16:57 +0200 Subject: [PATCH] [contrasting project] add fitted_stationary_gev. remove gev fit classes --- .../visualization/study_visualizer.py | 6 +-- extreme_fit/distribution/gev/gev_fit.py | 15 ------ extreme_fit/distribution/gev/gevmle_fit.py | 29 ----------- extreme_fit/distribution/gev/ismev_gev_fit.py | 49 ------------------ .../estimator/margin_estimator/utils.py | 25 +++++++++ .../margin_function/linear_margin_function.py | 4 ++ .../presentation/statistical_model.py | 6 +-- .../test_gev/test_gevmle_fit.py | 44 ---------------- .../test_gev/test_stationary_gev_fit.py | 51 +++++++++++++++++++ 9 files changed, 85 insertions(+), 144 deletions(-) delete mode 100644 extreme_fit/distribution/gev/gev_fit.py delete mode 100644 extreme_fit/distribution/gev/gevmle_fit.py delete mode 100644 extreme_fit/distribution/gev/ismev_gev_fit.py delete mode 100644 test/test_extreme_fit/test_distribution/test_gev/test_gevmle_fit.py create mode 100644 test/test_extreme_fit/test_distribution/test_gev/test_stationary_gev_fit.py diff --git a/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py b/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py index a75e43b3..8a4fa435 100644 --- a/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py +++ b/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py @@ -12,6 +12,7 @@ import numpy as np import pandas as pd import seaborn as sns +from extreme_fit.estimator.margin_estimator.utils import fitted_stationary_gev from extreme_fit.model.result_from_model_fit.result_from_extremes.eurocode_return_level_uncertainties import \ EurocodeConfidenceIntervalFromExtremes, compute_eurocode_confidence_interval from extreme_data.meteo_france_data.scm_models_data.abstract_extended_study import AbstractExtendedStudy @@ -29,7 +30,6 @@ from extreme_fit.function.margin_function.abstract_margin_function import \ from extreme_fit.function.param_function.param_function import AbstractParamFunction from extreme_fit.model.max_stable_model.abstract_max_stable_model import CovarianceFunction from extreme_fit.distribution.gev.gev_params import GevParams -from extreme_fit.distribution.gev.ismev_gev_fit import IsmevGevFit from extreme_fit.distribution.gpd.gpd_params import GpdParams from extreme_fit.distribution.gpd.gpdmle_fit import GpdMleFit from spatio_temporal_dataset.coordinates.spatial_coordinates.abstract_spatial_coordinates import \ @@ -374,7 +374,7 @@ class StudyVisualizer(VisualizationParameters): # Display the graph of the max on top ax = plt.gca() _, y = self.smooth_maxima_x_y(massif_names.index(massif_name)) - gev_param = IsmevGevFit(x_gev=y).gev_params + gev_param = fitted_stationary_gev(x_gev=y) # Round up # d = {k: self.round_sig(v, 2) for k, v in d.items()} @@ -661,7 +661,7 @@ class StudyVisualizer(VisualizationParameters): @cached_property def massif_name_to_gev_mle_fitted(self) -> Dict[str, GevParams]: - return {massif_name: IsmevGevFit(self.df_maxima_gev.loc[massif_name]).gev_params + return {massif_name: fitted_stationary_gev(self.df_maxima_gev.loc[massif_name]) for massif_name in self.study.study_massif_names} @cached_property diff --git a/extreme_fit/distribution/gev/gev_fit.py b/extreme_fit/distribution/gev/gev_fit.py deleted file mode 100644 index ef81d978..00000000 --- a/extreme_fit/distribution/gev/gev_fit.py +++ /dev/null @@ -1,15 +0,0 @@ -import numpy as np - -from extreme_fit.distribution.gev.gev_params import GevParams - - -class GevFit(object): - - def __init__(self, x_gev: np.ndarray, block_size=None): - assert np.ndim(x_gev) == 1 - assert len(x_gev) > 1 - self.x_gev = x_gev - - @property - def gev_params(self) -> GevParams: - raise NotImplementedError \ No newline at end of file diff --git a/extreme_fit/distribution/gev/gevmle_fit.py b/extreme_fit/distribution/gev/gevmle_fit.py deleted file mode 100644 index 41288004..00000000 --- a/extreme_fit/distribution/gev/gevmle_fit.py +++ /dev/null @@ -1,29 +0,0 @@ -import numpy as np - -from extreme_fit.distribution.gev.gev_fit import GevFit -from extreme_fit.distribution.gev.gev_params import GevParams -from extreme_fit.model.utils import r - -""" -These two functions are “extremely light†functions to fit the GEV/GPD. These functions are mainlyuseful -to compute starting values for the Schlather and Smith mode -If more refined (univariate) analysis have to be performed, users should use more specialised pack-ages - - e.g. POT, evd, ismev, . . . . -""" - - -def spatial_extreme_gevmle_fit(x_gev): - res = r.gevmle(x_gev, method="Nelder") - return dict(zip(res.names, res)) - - -class GevMleFit(GevFit): - - def __init__(self, x_gev: np.ndarray, block_size=None): - super().__init__(x_gev, block_size) - self._gev_params = spatial_extreme_gevmle_fit(x_gev) - self.gev_params_object = GevParams.from_dict({**self._gev_params, 'block_size': block_size}) - - @property - def gev_params(self) -> GevParams: - return self.gev_params_object diff --git a/extreme_fit/distribution/gev/ismev_gev_fit.py b/extreme_fit/distribution/gev/ismev_gev_fit.py deleted file mode 100644 index ca7997aa..00000000 --- a/extreme_fit/distribution/gev/ismev_gev_fit.py +++ /dev/null @@ -1,49 +0,0 @@ -import numpy as np - -from extreme_fit.distribution.gev.gev_fit import GevFit -from extreme_fit.distribution.gev.gev_params import GevParams -import rpy2.robjects as ro - -from extreme_fit.model.utils import r, get_null - - -""" -IsMev fit functions -""" - - -def ismev_gev_fit(x_gev, y, mul): - """ - For non-stationary fitting it is recommended that the covariates within the generalized linear models are - (at least approximately) centered and scaled (i.e.the columns of ydat should be approximately centered and scaled). - """ - xdat = ro.FloatVector(x_gev) - gev_fit = r('gev.fit') - y = y if y is not None else get_null() - mul = mul if mul is not None else get_null() - res = gev_fit(xdat, y, mul) - - # r.assign('python_wrapping', True) - # r.source(file="""/home/erwan/Documents/projects/spatiotemporalextremes/extreme_fit/distribution/gev/wrapper_ismev_gev_fit.R""") - # y = np.arange(1, len(x_gev), 1).reshape((-11, 1)) - # res = r.gev_fit(data=xdat, y=y, trend=1) - return dict(zip(res.names, res)) - -class IsmevGevFit(GevFit): - # todo: this could be modeled with a margin_function depending only on time - # todo: I should remove the call to this object, in order to centralize all the calls - - def __init__(self, x_gev: np.ndarray, y=None, mul=None): - super().__init__(x_gev) - self.y = y - self.mul = mul - self.res = ismev_gev_fit(x_gev, y, mul) - - @property - def gev_params(self) -> GevParams: - assert self.y is None - gev_params_dict = dict(zip(GevParams.PARAM_NAMES, self.res['mle'])) - return GevParams.from_dict(gev_params_dict) - - - diff --git a/extreme_fit/estimator/margin_estimator/utils.py b/extreme_fit/estimator/margin_estimator/utils.py index 74e872a7..95dc74d0 100644 --- a/extreme_fit/estimator/margin_estimator/utils.py +++ b/extreme_fit/estimator/margin_estimator/utils.py @@ -1,4 +1,16 @@ +import pandas as pd + +from extreme_fit.distribution.gev.gev_params import GevParams from extreme_fit.estimator.margin_estimator.abstract_margin_estimator import LinearMarginEstimator +from extreme_fit.model.margin_model.linear_margin_model.temporal_linear_margin_models import StationaryTemporalModel +from spatio_temporal_dataset.coordinates.temporal_coordinates.generated_temporal_coordinates import \ + ConsecutiveTemporalCoordinates +from spatio_temporal_dataset.coordinates.transformed_coordinates.transformation.abstract_transformation import \ + CenteredScaledNormalization +from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset +from spatio_temporal_dataset.spatio_temporal_observations.abstract_spatio_temporal_observations import \ + AbstractSpatioTemporalObservations +from spatio_temporal_dataset.spatio_temporal_observations.annual_maxima_observations import AnnualMaxima def fitted_linear_margin_estimator(model_class, coordinates, dataset, starting_year, fit_method, **model_kwargs): @@ -6,3 +18,16 @@ def fitted_linear_margin_estimator(model_class, coordinates, dataset, starting_y estimator = LinearMarginEstimator(dataset, model) estimator.fit() return estimator + + +def fitted_stationary_gev(x_gev, fit_method, model_class=StationaryTemporalModel, starting_year=None, + transformation_class=CenteredScaledNormalization) -> GevParams: + coordinates = ConsecutiveTemporalCoordinates.from_nb_temporal_steps(nb_temporal_steps=len(x_gev), + transformation_class=CenteredScaledNormalization) + df = pd.DataFrame([pd.Series(dict(zip(coordinates.index, x_gev)))]).transpose() + observations = AnnualMaxima(df_maxima_gev=df) + dataset = AbstractDataset(observations=observations, coordinates=coordinates) + estimator = fitted_linear_margin_estimator(model_class, coordinates, dataset, starting_year, fit_method) + first_coordinate = coordinates.coordinates_values()[0] + gev_param = estimator.function_from_fit.get_gev_params(first_coordinate) + return gev_param diff --git a/extreme_fit/function/margin_function/linear_margin_function.py b/extreme_fit/function/margin_function/linear_margin_function.py index 7deb1ab3..81a9ee8d 100644 --- a/extreme_fit/function/margin_function/linear_margin_function.py +++ b/extreme_fit/function/margin_function/linear_margin_function.py @@ -61,6 +61,10 @@ class LinearMarginFunction(ParametricMarginFunction): coef_dict.update(coef.coef_dict(dims, self.idx_to_coefficient_name(self.coordinates))) return coef_dict + @property + def is_a_stationary_model(self) -> bool: + return all([v == 'NULL' for v in self.form_dict.values()]) + @property def form_dict(self) -> Dict[str, str]: form_dict = {} diff --git a/projects/exceeding_snow_loads/presentation/statistical_model.py b/projects/exceeding_snow_loads/presentation/statistical_model.py index 969eb23e..1a5e8dcd 100644 --- a/projects/exceeding_snow_loads/presentation/statistical_model.py +++ b/projects/exceeding_snow_loads/presentation/statistical_model.py @@ -1,8 +1,7 @@ import matplotlib.pyplot as plt import numpy as np -from extreme_fit.distribution.gev.gevmle_fit import GevMleFit -from extreme_fit.distribution.gev.ismev_gev_fit import ismev_gev_fit +from extreme_fit.estimator.margin_estimator.utils import fitted_stationary_gev def binomial_observation(): @@ -34,8 +33,7 @@ def histogram_for_gev(): study = CrocusSnowLoadTotal(altitude=1800) s = study.observations_annual_maxima.df_maxima_gev.loc['Vercors'] x_gev = s.values - gev = GevMleFit(x_gev) - gev_params = gev.gev_params + gev_params = fitted_stationary_gev(x_gev) samples = gev_params.sample(10000) nb = 10 epsilon = 0.0 diff --git a/test/test_extreme_fit/test_distribution/test_gev/test_gevmle_fit.py b/test/test_extreme_fit/test_distribution/test_gev/test_gevmle_fit.py deleted file mode 100644 index 184be222..00000000 --- a/test/test_extreme_fit/test_distribution/test_gev/test_gevmle_fit.py +++ /dev/null @@ -1,44 +0,0 @@ -import unittest - -import numpy as np - -from extreme_fit.model.utils import r, set_seed_r -from extreme_fit.distribution.gev.gev_params import GevParams -from extreme_fit.distribution.gev.gevmle_fit import GevMleFit -from extreme_fit.distribution.gev.ismev_gev_fit import IsmevGevFit - - -class TestGevMleFit(unittest.TestCase): - - def setUp(self) -> None: - set_seed_r() - r(""" - N <- 50 - loc = 0; scale = 1; shape <- 1 - x_gev <- rgev(N, loc = loc, scale = scale, shape = shape) - start_loc = 0; start_scale = 1; start_shape = 1 - """) - - def test_gevmle_fit(self): - estimator = GevMleFit(x_gev=np.array(r['x_gev'])) - mle_params_ref = {'loc': 0.0219, 'scale': 1.0347, 'shape': 0.8290} - self.fit_estimator(estimator, ref=mle_params_ref) - - def test_ismev_gev_fit(self): - estimator = IsmevGevFit(x_gev=np.array(r['x_gev'])) - ismev_ref = {'loc': 0.0219, 'scale': 1.0347, 'shape': 0.8295} - self.fit_estimator(estimator, ismev_ref) - - # def test_s - - def fit_estimator(self, estimator, ref): - # Compare the MLE estimated parameters to the reference - mle_params_estimated = estimator.gev_params - self.assertIsInstance(mle_params_estimated, GevParams) - mle_params_estimated = mle_params_estimated.to_dict() - for key in ref.keys(): - self.assertAlmostEqual(ref[key], mle_params_estimated[key], places=3) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/test_extreme_fit/test_distribution/test_gev/test_stationary_gev_fit.py b/test/test_extreme_fit/test_distribution/test_gev/test_stationary_gev_fit.py new file mode 100644 index 00000000..737bab80 --- /dev/null +++ b/test/test_extreme_fit/test_distribution/test_gev/test_stationary_gev_fit.py @@ -0,0 +1,51 @@ +import unittest + +import numpy as np + +from extreme_fit.estimator.margin_estimator.utils import fitted_stationary_gev +from extreme_fit.model.margin_model.linear_margin_model.abstract_temporal_linear_margin_model import \ + TemporalMarginFitMethod +from extreme_fit.model.utils import r, set_seed_r +from extreme_fit.distribution.gev.gev_params import GevParams + + +class TestStationaryGevFit(unittest.TestCase): + + def setUp(self) -> None: + set_seed_r() + r(""" + N <- 50 + loc = 0; scale = 1; shape <- 1 + x_gev <- rgev(N, loc = loc, scale = scale, shape = shape) + start_loc = 0; start_scale = 1; start_shape = 1 + """) + + def test_stationary_gev_fit_with_ismev(self): + params_estimated = fitted_stationary_gev(x_gev=np.array(r['x_gev']), + fit_method=TemporalMarginFitMethod.is_mev_gev_fit) + ref = {'loc': 0.0219, 'scale': 1.0347, 'shape': 0.8295} + self.fit_estimator(params_estimated, ref) + + def test_stationary_gev_fit_with_mle(self): + params_estimated = fitted_stationary_gev(x_gev=np.array(r['x_gev']), + fit_method=TemporalMarginFitMethod.extremes_fevd_mle) + ref = {'loc': 0.02191974259369493, 'scale': 1.0347946062900268, 'shape': 0.829052520147379} + self.fit_estimator(params_estimated, ref) + + def test_stationary_gev_fit_with_l_moments(self): + params_estimated = fitted_stationary_gev(x_gev=np.array(r['x_gev']), + fit_method=TemporalMarginFitMethod.extremes_fevd_l_moments) + ref = {'loc': 0.0813843045950251, 'scale': 1.1791830110181365, 'shape': 0.6610403806908737} + self.fit_estimator(params_estimated, ref) + + def fit_estimator(self, params_estimated, ref): + # Compare the MLE estimated parameters to the reference + self.assertIsInstance(params_estimated, GevParams) + params_estimated = params_estimated.to_dict() + print(params_estimated) + for key in ref.keys(): + self.assertAlmostEqual(ref[key], params_estimated[key], places=3) + + +if __name__ == '__main__': + unittest.main() -- GitLab