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