From f29ad0db6d26b2bdad2a7036602d5940170a24f5 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Tue, 7 May 2019 09:10:24 +0200 Subject: [PATCH] [EXTREME ESTIMATOR][MARGIN MODEL] add temporal linear margin model --- .../margin_function/linear_margin_function.py | 7 ++- .../temporal_linear_margin_model.py | 52 +++++++++++++++++++ .../extreme_models/result_from_fit.py | 30 +++++++++-- extreme_estimator/extreme_models/utils.py | 2 - .../coordinates/abstract_coordinates.py | 4 ++ .../abstract_spatio_temporal_observations.py | 2 +- 6 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 extreme_estimator/extreme_models/margin_model/temporal_linear_margin_model.py diff --git a/extreme_estimator/extreme_models/margin_model/margin_function/linear_margin_function.py b/extreme_estimator/extreme_models/margin_model/margin_function/linear_margin_function.py index 7545bc06..db54afeb 100644 --- a/extreme_estimator/extreme_models/margin_model/margin_function/linear_margin_function.py +++ b/extreme_estimator/extreme_models/margin_model/margin_function/linear_margin_function.py @@ -50,10 +50,9 @@ class LinearMarginFunction(ParametricMarginFunction): if self.starting_point is not None: # Shift temporal coordinate to enable to model temporal trend with starting point assert self.coordinates.has_temporal_coordinates - idx_coordinate_t = self.coordinates.coordinates_names.index(self.coordinates.COORDINATE_T) - assert 0 <= idx_coordinate_t < len(coordinate) - if coordinate[idx_coordinate_t] < self.starting_point: - coordinate[idx_coordinate_t] = self.starting_point + assert 0 <= self.coordinates.idx_temporal_coordinates < len(coordinate) + if coordinate[self.coordinates.idx_temporal_coordinates] < self.starting_point: + coordinate[self.coordinates.idx_temporal_coordinates] = self.starting_point return super().get_gev_params(coordinate) @classmethod diff --git a/extreme_estimator/extreme_models/margin_model/temporal_linear_margin_model.py b/extreme_estimator/extreme_models/margin_model/temporal_linear_margin_model.py new file mode 100644 index 00000000..42574333 --- /dev/null +++ b/extreme_estimator/extreme_models/margin_model/temporal_linear_margin_model.py @@ -0,0 +1,52 @@ +import numpy as np +import pandas as pd + +from extreme_estimator.extreme_models.margin_model.linear_margin_model import LinearMarginModel +from extreme_estimator.extreme_models.result_from_fit import ResultFromFit, ResultFromIsmev +from extreme_estimator.extreme_models.utils import r, ro, get_null +from extreme_estimator.extreme_models.utils import safe_run_r_estimator +from extreme_estimator.margin_fits.gev.gev_params import GevParams +from spatio_temporal_dataset.coordinates.abstract_coordinates import AbstractCoordinates + + +class TemporalLinearMarginModel(LinearMarginModel): + # Linearity only with respect to the temporal coordinates + + def __init__(self, coordinates: AbstractCoordinates, use_start_value=False, params_start_fit=None, + params_sample=None, starting_point=None): + super().__init__(coordinates, use_start_value, params_start_fit, params_sample, starting_point) + + def fitmargin_from_maxima_gev(self, data: np.ndarray, df_coordinates_spat: pd.DataFrame, + df_coordinates_temp: pd.DataFrame) -> ResultFromFit: + # Modify df_coordinates_temp + df_coordinates_temp = self.add_starting_temporal_point(df_coordinates_temp) + # Gev Fit + res = safe_run_r_estimator(function=r('gev.fit'), use_start=self.use_start_value, + xdat=ro.FloatVector(data[0]), y=df_coordinates_temp.values, mul=self.mul) + return ResultFromIsmev(res, self.margin_function_start_fit.gev_param_name_to_dims) + + @property + def mul(self): + return NotImplementedError + + +class StationaryStationModel(TemporalLinearMarginModel): + + def load_margin_functions(self, gev_param_name_to_dims=None): + super().load_margin_functions({}) + + @property + def mul(self): + return get_null() + + +class NonStationaryStationModel(TemporalLinearMarginModel): + + def load_margin_functions(self, gev_param_name_to_dims=None): + super().load_margin_functions({GevParams.LOC: [self.coordinates.idx_temporal_coordinates]}) + + @property + def mul(self): + return 1 + + diff --git a/extreme_estimator/extreme_models/result_from_fit.py b/extreme_estimator/extreme_models/result_from_fit.py index 9ddcf476..bc01dd8b 100644 --- a/extreme_estimator/extreme_models/result_from_fit.py +++ b/extreme_estimator/extreme_models/result_from_fit.py @@ -3,6 +3,8 @@ from typing import Dict from rpy2 import robjects from extreme_estimator.extreme_models.margin_model.param_function.linear_coef import LinearCoef +from extreme_estimator.margin_fits.gev.gev_params import GevParams +from spatio_temporal_dataset.coordinates.abstract_coordinates import AbstractCoordinates class ResultFromFit(object): @@ -27,17 +29,38 @@ class ResultFromFit(object): class ResultFromIsmev(ResultFromFit): - pass + + def __init__(self, result_from_fit: robjects.ListVector, gev_param_name_to_dim) -> None: + super().__init__(result_from_fit) + self.gev_param_name_to_dim = gev_param_name_to_dim @property - def mle(self): - return self.res['mle'] + def margin_coef_dict(self): + # Build the Coeff dict from gev_param_name_to_dim + coef_dict = {} + i = 0 + mle_values = self.name_to_value['mle'] + for gev_param_name in GevParams.PARAM_NAMES: + # Add intercept + intercept_coef_name = LinearCoef.coef_template_str(gev_param_name, LinearCoef.INTERCEPT_NAME).format(1) + coef_dict[intercept_coef_name] = mle_values[i] + i += 1 + # Add a potential linear temporal trend + if gev_param_name in self.gev_param_name_to_dim: + temporal_coef_name = LinearCoef.coef_template_str(gev_param_name, AbstractCoordinates.COORDINATE_T).format(1) + coef_dict[temporal_coef_name] = mle_values[i] + i += 1 + return coef_dict + @property + def all_parameters(self): + return self.margin_coef_dict @property def nllh(self): return self.res['nllh'] + class ResultFromSpatialExtreme(ResultFromFit): """ Handler from any result with the result of a fit functions from the package Spatial Extreme @@ -45,7 +68,6 @@ class ResultFromSpatialExtreme(ResultFromFit): FITTED_VALUES_NAME = 'fitted.values' CONVERGENCE_NAME = 'convergence' - @property def convergence(self) -> str: convergence_value = self.name_to_value[self.CONVERGENCE_NAME] diff --git a/extreme_estimator/extreme_models/utils.py b/extreme_estimator/extreme_models/utils.py index afeaf6fb..581723ad 100644 --- a/extreme_estimator/extreme_models/utils.py +++ b/extreme_estimator/extreme_models/utils.py @@ -16,8 +16,6 @@ from rpy2.rinterface._rinterface import RRuntimeError from rpy2.robjects import numpy2ri from rpy2.robjects import pandas2ri -from extreme_estimator.extreme_models.result_from_fit import ResultFromFit, ResultFromSpatialExtreme - r = ro.R() numpy2ri.activate() pandas2ri.activate() diff --git a/spatio_temporal_dataset/coordinates/abstract_coordinates.py b/spatio_temporal_dataset/coordinates/abstract_coordinates.py index f4653bd4..95229f9f 100644 --- a/spatio_temporal_dataset/coordinates/abstract_coordinates.py +++ b/spatio_temporal_dataset/coordinates/abstract_coordinates.py @@ -202,6 +202,10 @@ class AbstractCoordinates(object): df_temporal_coordinates = self.df_temporal_coordinates(split) return int(df_temporal_coordinates.min()), int(df_temporal_coordinates.max()), + @property + def idx_temporal_coordinates(self): + return self.coordinates_names.index(self.COORDINATE_T) + # Spatio temporal attributes @property diff --git a/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py b/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py index 8b7076d0..483db946 100644 --- a/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py +++ b/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py @@ -12,7 +12,7 @@ class AbstractSpatioTemporalObservations(object): OBSERVATIONS_GEV = 'obs_gev' OBSERVATIONS_FRECH = 'obs_frech' - def __init__(self, df_maxima_frech: pd.DataFrame = None, df_maxima_gev: pd.DataFrame = None): + def __init__(self, df_maxima_gev: pd.DataFrame = None, df_maxima_frech: pd.DataFrame = None): """ Main attribute of the class is the DataFrame df_maxima Index are coordinates index -- GitLab