diff --git a/experiment/meteo_france_SCM_study/visualization/study_visualization/non_stationary_trends.py b/experiment/meteo_france_SCM_study/visualization/study_visualization/non_stationary_trends.py index 33b0031b6f2f86f5237d00c8d8c5d35a083b4063..ea6eff9af8698895c7ecc74731bad8c59bf93940 100644 --- a/experiment/meteo_france_SCM_study/visualization/study_visualization/non_stationary_trends.py +++ b/experiment/meteo_france_SCM_study/visualization/study_visualization/non_stationary_trends.py @@ -18,8 +18,9 @@ from utils import get_display_name_from_object_type class AbstractNonStationaryTrendTest(object): RESULT_ATTRIBUTE_METRIC = 'deviance' - def __init__(self, dataset: AbstractDataset, estimator_class, + def __init__(self, dataset: AbstractDataset, verbose, estimator_class, stationary_margin_model_class, non_stationary_margin_model_class): + self.verbose = verbose self.dataset = dataset self.estimator_class = estimator_class self.stationary_margin_model_class = stationary_margin_model_class @@ -33,9 +34,10 @@ class AbstractNonStationaryTrendTest(object): if (margin_model_class, starting_point) not in self._margin_model_class_and_starting_point_to_estimator: margin_model = margin_model_class(coordinates=self.dataset.coordinates, starting_point=starting_point) estimator = self._load_estimator(margin_model) - estimator_name = get_display_name_from_object_type(estimator) - margin_model_name = get_display_name_from_object_type(margin_model) - print('Fitting {} with margin: {} for starting_point={}'.format(estimator_name, margin_model_name, starting_point)) + if self.verbose: + estimator_name = get_display_name_from_object_type(estimator) + margin_model_name = get_display_name_from_object_type(margin_model) + print('Fitting {} with margin: {} for starting_point={}'.format(estimator_name, margin_model_name, starting_point)) estimator.fit() self._margin_model_class_and_starting_point_to_estimator[(margin_model_class, starting_point)] = estimator return self._margin_model_class_and_starting_point_to_estimator[(margin_model_class, starting_point)] @@ -79,12 +81,15 @@ class AbstractNonStationaryTrendTest(object): mu1_trends = [self.get_mu1(starting_point=year) for year in years] ax2 = ax.twinx() color_mu1 = 'c' - print(mu1_trends) + + if self.verbose: + print(mu1_trends) ax2.plot(years, mu1_trends, color_mu1 + 'o-') ax2.set_ylabel('mu1 parameter', color=color_mu1) ax.set_xlabel('starting year for the linear trend of mu1') - # align_yaxis_on_zero(ax, ax2) + if min(mu1_trends) < 0.0 < max(mu1_trends): + align_yaxis_on_zero(ax, ax2) title = self.display_name ax.set_title(title) ax.legend() @@ -94,7 +99,7 @@ class AbstractNonStationaryTrendTest(object): if complete_analysis: year_min, year_max, step = 1960, 1990, 1 else: - year_min, year_max, step = 1960, 1990, 10 + year_min, year_max, step = 1960, 1990, 5 years = list(range(year_min, year_max + 1, step)) return years @@ -111,8 +116,9 @@ class IndependenceLocationTrendTest(AbstractNonStationaryTrendTest): class ConditionalIndedendenceLocationTrendTest(AbstractNonStationaryTrendTest): - def __init__(self, dataset): + def __init__(self, dataset, verbose=False): super().__init__(dataset=dataset, + verbose=verbose, estimator_class=LinearMarginEstimator, stationary_margin_model_class=LinearStationaryMarginModel, non_stationary_margin_model_class=LinearNonStationaryLocationMarginModel) @@ -124,8 +130,9 @@ class ConditionalIndedendenceLocationTrendTest(AbstractNonStationaryTrendTest): class MaxStableLocationTrendTest(AbstractNonStationaryTrendTest): - def __init__(self, dataset, max_stable_model): + def __init__(self, dataset, max_stable_model, verbose=False): super().__init__(dataset=dataset, + verbose=verbose, estimator_class=FullEstimatorInASingleStepWithSmoothMargin, stationary_margin_model_class=LinearStationaryMarginModel, non_stationary_margin_model_class=LinearNonStationaryLocationMarginModel) diff --git a/extreme_estimator/extreme_models/result_from_fit.py b/extreme_estimator/extreme_models/result_from_fit.py index 669c2f87ce35c32f43a5c60b832a46ddbe3ab861..e8f50a720b5034076227f764426a1fdb65d96180 100644 --- a/extreme_estimator/extreme_models/result_from_fit.py +++ b/extreme_estimator/extreme_models/result_from_fit.py @@ -37,6 +37,10 @@ class ResultFromFit(object): def deviance(self): raise NotImplementedError + @property + def convergence(self) -> str: + raise NotImplementedError + class ResultFromIsmev(ResultFromFit): diff --git a/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/uniform_normalization.py b/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/uniform_normalization.py index 950679bd927f721de7ad0b92a62e292e7bc8be98..8922ff7715b88eacc2ea8426d22728e18090ab2e 100644 --- a/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/uniform_normalization.py +++ b/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/uniform_normalization.py @@ -31,6 +31,31 @@ class BetweenZeroAndOneNormalization(UniformNormalization): return coord_scaled +class BetweenZeroAndTenNormalization(BetweenZeroAndOneNormalization): + + def uniform_normalization(self, coordinate_value: np.ndarray) -> np.ndarray: + return super().uniform_normalization(coordinate_value) / 10 + + +epsilon = 0.001 + + +class BetweenZeroAndOneNormalizationMinEpsilon(BetweenZeroAndOneNormalization): + + def __init__(self, df_coordinates): + super().__init__(df_coordinates) + gap = self.max_coord - self.min_coord + self.min_coord -= gap * epsilon + + +class BetweenZeroAndOneNormalizationMaxEpsilon(BetweenZeroAndOneNormalization): + + def __init__(self, df_coordinates): + super().__init__(df_coordinates) + gap = self.max_coord - self.min_coord + self.max_coord += gap * epsilon + + class BetweenMinusOneAndOneNormalization(BetweenZeroAndOneNormalization): """Normalize such that min(coord) >= (-1,-1) and max(coord) <= (1,1)""" 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 9ac704c843df470d27e23b04ff22aadf85659333..e65c488e289f21786eb1a3b1ab6db475abfbb35e 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 @@ -38,6 +38,12 @@ class AbstractSpatioTemporalObservations(object): else: return self.df_maxima_gev + def normalize(self): + # It should stay superior to 0 and lower or equal to 1 + # Thus the easiest way to do that is to divide by the maximum + maxima = self._df_maxima.values.flatten().max() + self._df_maxima /= maxima + @property def df_maxima_merged(self) -> pd.DataFrame: df_maxima_list = [] @@ -99,4 +105,8 @@ class AbstractSpatioTemporalObservations(object): def __str__(self) -> str: return self._df_maxima.__str__() + @_df_maxima.setter + def _df_maxima(self, value): + self.__df_maxima = value + diff --git a/test/test_experiment/test_coordinate_sensitivity.py b/test/test_experiment/test_coordinate_sensitivity.py index 8fcc5363587b856eaebe18ad32e2bdba0ef83f60..2672d7a6768e68ec9b52f1afca76e4bf5f780cf1 100644 --- a/test/test_experiment/test_coordinate_sensitivity.py +++ b/test/test_experiment/test_coordinate_sensitivity.py @@ -7,7 +7,8 @@ from experiment.meteo_france_SCM_study.visualization.study_visualization.non_sta ConditionalIndedendenceLocationTrendTest from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer from spatio_temporal_dataset.coordinates.transformed_coordinates.transformation.uniform_normalization import \ - BetweenZeroAndOneNormalization, BetweenMinusOneAndOneNormalization + BetweenZeroAndOneNormalization, BetweenMinusOneAndOneNormalization, BetweenZeroAndTenNormalization, \ + BetweenZeroAndOneNormalizationMinEpsilon, BetweenZeroAndOneNormalizationMaxEpsilon from utils import get_display_name_from_object_type @@ -15,11 +16,14 @@ class TestCoordinateSensitivity(unittest.TestCase): DISPLAY = False def test_coordinate_normalization_sensitivity(self): - altitudes = [3000] - transformation_classes = [BetweenZeroAndOneNormalization, BetweenMinusOneAndOneNormalization][:] - for transformation_class in transformation_classes: - study_classes = [CrocusSwe] - for study in study_iterator_global(study_classes, altitudes=altitudes, verbose=False): + altitudes = [300, 600, 900, 1200, 2100, 3000][-1:] + transformation_classes = [None, BetweenZeroAndOneNormalization, BetweenZeroAndOneNormalizationMinEpsilon, BetweenZeroAndOneNormalizationMaxEpsilon][1:2] + + study_classes = [CrocusSwe] + for study in study_iterator_global(study_classes, altitudes=altitudes, verbose=False): + if self.DISPLAY: + print(study.altitude) + for transformation_class in transformation_classes: study_visualizer = StudyVisualizer(study, transformation_class=transformation_class) study_visualizer.temporal_non_stationarity = True trend_test = ConditionalIndedendenceLocationTrendTest(study_visualizer.dataset) @@ -27,10 +31,20 @@ class TestCoordinateSensitivity(unittest.TestCase): mu1s = [trend_test.get_mu1(year) for year in years] if self.DISPLAY: print('Stationary') - print(trend_test.get_estimator(trend_test.stationary_margin_model_class, starting_point=None).margin_function_fitted.coef_dict) + stationary_est = trend_test.get_estimator(trend_test.stationary_margin_model_class, + starting_point=None) + print(stationary_est.result_from_fit.convergence) + print(stationary_est.margin_function_fitted.coef_dict) print('Non Stationary') - print(trend_test.get_estimator(trend_test.non_stationary_margin_model_class, starting_point=1960).margin_function_fitted.coef_dict) + non_stationary_est = trend_test.get_estimator(trend_test.non_stationary_margin_model_class, + starting_point=1960) + print(non_stationary_est.result_from_fit.convergence) + non_stationary_est = trend_test.get_estimator(trend_test.non_stationary_margin_model_class, + starting_point=1990) + print(non_stationary_est.result_from_fit.convergence) + print(non_stationary_est.margin_function_fitted.coef_dict) print(get_display_name_from_object_type(transformation_class), 'mu1s: ', mu1s) + print('\n') self.assertTrue(0.0 not in mu1s)