From 743308abb34467c6e029e4f8439ab6e47f618bd0 Mon Sep 17 00:00:00 2001
From: Le Roux Erwan <erwan.le-roux@irstea.fr>
Date: Thu, 31 Oct 2019 16:14:45 +0100
Subject: [PATCH] [CONFIDENCE INTERVAL] add confidence interval test for the
 normal (i.e. delta) confidence interval method

---
 extreme_fit/distribution/gev/main_fevd_mle.R  | 17 +++++++--------
 .../abstract_extract_eurocode_return_level.py |  3 ++-
 .../abstract_result_from_extremes.py          |  8 +++----
 .../confidence_interval_method.py             |  7 +++++++
 .../result_from_bayesian_extremes.py          |  2 +-
 .../result_from_mle_extremes.py               | 21 +++++++++++++++++++
 .../test_model/test_confidence_interval.py    | 13 ++++++++++++
 7 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/extreme_fit/distribution/gev/main_fevd_mle.R b/extreme_fit/distribution/gev/main_fevd_mle.R
index 5a83f9b4..96901909 100644
--- a/extreme_fit/distribution/gev/main_fevd_mle.R
+++ b/extreme_fit/distribution/gev/main_fevd_mle.R
@@ -9,18 +9,15 @@ library(SpatialExtremes)
 source('fevd_fixed.R')
 # Sample from a GEV
 set.seed(42)
-N <- 100
-loc = 0; scale = 1; shape <- 0.1
+N <- 50
+loc = 0; scale = 1; shape <- 1
 x_gev <- rgev(N, loc = loc, scale = scale, shape = shape)
-
-
-# Add covariate
 coord <- matrix(ncol=1, nrow = N)
-coord[,1]=seq(1,N,1)
+coord[,1]=seq(0,N-1,1)
 colnames(coord) = c("T")
 coord = data.frame(coord, stringsAsFactors = TRUE)
-# res = fevd_fixed(x_gev, data=coord, method='MLE', verbose=TRUE, use.phi=FALSE)
-res = fevd_fixed(x_gev, data=coord, location.fun= ~T, method='MLE', verbose=TRUE, use.phi=FALSE, time.units = "years", units = "years")
+res = fevd_fixed(x_gev, data=coord, method='MLE', verbose=TRUE, use.phi=FALSE)
+# res = fevd_fixed(x_gev, data=coord, location.fun= ~T, method='MLE', verbose=TRUE, use.phi=FALSE, time.units = "years", units = "years")
 # print(res)
 
 # Some display for the results
@@ -34,10 +31,10 @@ print(res$results$par)
 
 
 # Confidence interval staionary
-# method = "proflik"
+method = "normal"
 res_ci = ci(res, alpha = 0.05, type = c("return.level", "parameter"),
     return.period = 50, method = method, xrange = NULL, nint = 20, verbose = FALSE,
-    tscale = FALSE, return.samples = FALSE)
+    tscale = FALSE)
 print(res_ci)
 
 # Bug to solve for the non stationary - the returned parameter do not match with the return level
diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_extract_eurocode_return_level.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_extract_eurocode_return_level.py
index f47b10dd..c0cd76d2 100644
--- a/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_extract_eurocode_return_level.py
+++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_extract_eurocode_return_level.py
@@ -45,7 +45,8 @@ class ExtractEurocodeReturnLevelFromCiMethod(AbstractExtractEurocodeReturnLevel)
     def confidence_interval_method(self):
         return self.result_from_fit.confidence_interval_method(self.eurocode_quantile,
                                                                self.alpha_for_confidence_interval,
-                                                               self.transformed_temporal_covariate)
+                                                               self.transformed_temporal_covariate,
+                                                               self.ci_method)
 
     @property
     def mean_estimate(self) -> np.ndarray:
diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py
index 0a93a88f..cbd16d9a 100644
--- a/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py
+++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py
@@ -16,13 +16,13 @@ class AbstractResultFromExtremes(AbstractResultFromModelFit):
 
     @property
     def is_non_stationary(self):
-        return len(self.gev_param_name_to_dim) == 0
+        return len(self.gev_param_name_to_dim) > 0
 
     def load_dataframe_from_r_matrix(self, name):
         r_matrix = self.name_to_value[name]
         return pd.DataFrame(np.array(r_matrix), columns=r.colnames(r_matrix))
 
-    def confidence_interval_method(self, quantile_level, alpha_interval, transformed_temporal_covariate):
+    def confidence_interval_method(self, quantile_level, alpha_interval, transformed_temporal_covariate, ci_method):
         return_period = round(1 / (1 - quantile_level))
         common_kwargs = {
             'return.period': return_period,
@@ -40,8 +40,8 @@ class AbstractResultFromExtremes(AbstractResultFromModelFit):
             qcov = r("make.qcov")(self.result_from_fit,
                                   **kwargs)
             common_kwargs['qcov'] = qcov
-        mean_estimate, confidence_interval = self._confidence_interval_method(common_kwargs)
+        mean_estimate, confidence_interval = self._confidence_interval_method(common_kwargs, ci_method)
         return mean_estimate, confidence_interval
 
-    def _confidence_interval_method(self, common_kwargs):
+    def _confidence_interval_method(self, common_kwargs, ci_method):
         raise NotImplementedError
diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py
index 3fb5da38..e151009e 100644
--- a/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py
+++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py
@@ -9,3 +9,10 @@ class ConfidenceIntervalMethodFromExtremes(Enum):
     ci_proflik = 3
     # Confidence interval from my functions
     my_bayes = 4
+
+
+ci_method_to_method_name = {
+    ConfidenceIntervalMethodFromExtremes.ci_normal: 'normal',
+    ConfidenceIntervalMethodFromExtremes.ci_boot: 'boot',
+    ConfidenceIntervalMethodFromExtremes.ci_proflik: 'proflik',
+}
diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_bayesian_extremes.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_bayesian_extremes.py
index 851d0837..b83915d8 100644
--- a/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_bayesian_extremes.py
+++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_bayesian_extremes.py
@@ -47,7 +47,7 @@ class ResultFromBayesianExtremes(AbstractResultFromExtremes):
         mean_posterior_parameters = self.df_posterior_samples.iloc[:, :-2].mean(axis=0)
         return self.get_coef_dict_from_posterior_sample(mean_posterior_parameters)
 
-    def _confidence_interval_method(self, common_kwargs):
+    def _confidence_interval_method(self, common_kwargs, ci_method):
         bayesian_ci_parameters = {
                 'burn.in': self.burn_in_nb,
                 'FUN': "mean",
diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py
index 079c4d63..08bbd976 100644
--- a/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py
+++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py
@@ -2,7 +2,10 @@ import numpy as np
 
 from extreme_fit.model.result_from_model_fit.result_from_extremes.abstract_result_from_extremes import \
     AbstractResultFromExtremes
+from extreme_fit.model.result_from_model_fit.result_from_extremes.confidence_interval_method import \
+    ci_method_to_method_name
 from extreme_fit.model.result_from_model_fit.utils import get_margin_coef_ordered_dict
+from extreme_fit.model.utils import r
 
 
 class ResultFromMleExtremes(AbstractResultFromExtremes):
@@ -13,3 +16,21 @@ class ResultFromMleExtremes(AbstractResultFromExtremes):
         d = self.get_python_dictionary(values)
         values = {i: param for i, param in enumerate(np.array(d['par']))}
         return get_margin_coef_ordered_dict(self.gev_param_name_to_dim, values)
+
+    def _confidence_interval_method(self, common_kwargs, ci_method):
+        method_name = ci_method_to_method_name[ci_method]
+        mle_ci_parameters = {
+                'method': method_name,
+            # xrange = NULL, nint = 20
+        }
+        res = r.ci(self.result_from_fit, **mle_ci_parameters, **common_kwargs)
+        if self.is_non_stationary:
+            a = np.array(res)[0]
+            lower, mean_estimate, upper, _ = a
+        else:
+            d = self.get_python_dictionary(res)
+            keys = ['50-year return level', '95% lower CI', '95% upper CI']
+            mean_estimate, lower, upper = [np.array(d[k])[0] for k in keys]
+        return mean_estimate, (lower, upper)
+
+
diff --git a/test/test_extreme_fit/test_model/test_confidence_interval.py b/test/test_extreme_fit/test_model/test_confidence_interval.py
index b7b4c528..55cc6290 100644
--- a/test/test_extreme_fit/test_model/test_confidence_interval.py
+++ b/test/test_extreme_fit/test_model/test_confidence_interval.py
@@ -72,6 +72,15 @@ class TestConfidenceInterval(unittest.TestCase):
         self.ci_method = ConfidenceIntervalMethodFromExtremes.ci_bayes
         self.model_class_to_triplet = self.bayesian_ci
 
+    def test_ci_normal(self):
+        self.fit_method = TemporalMarginFitMethod.extremes_fevd_mle
+        self.ci_method = ConfidenceIntervalMethodFromExtremes.ci_normal
+        self.model_class_to_triplet= {
+            StationaryTemporalModel: (-4.703945484843988, 30.482318639674023, 65.66858276419204),
+            NonStationaryLocationTemporalModel: (-4.223086740397132, 30.29842988666537, 64.81994651372787),
+            NonStationaryLocationAndScaleTemporalModel: (-15.17041284612494, 43.69511224410276, 102.56063733433047),
+        }
+
     def tearDown(self) -> None:
         for model_class, expected_triplet in self.model_class_to_triplet.items():
             eurocode_ci = self.compute_eurocode_ci(model_class)
@@ -100,6 +109,10 @@ class TestConfidenceIntervalModifiedCoordinates(TestConfidenceInterval):
     def test_ci_bayes(self):
         super().test_ci_bayes()
 
+    def test_ci_normal(self):
+        self.model_class_to_triplet = {}
+        self.assertTrue(True)
+
 
 if __name__ == '__main__':
     unittest.main()
-- 
GitLab