diff --git a/experiment/trend_analysis/non_stationary_trends.py b/experiment/trend_analysis/non_stationary_trends.py index 66913e07dd9fbc9b514cfd8e4569bab837438748..627e3281cd2897c9c3ff954730cb909ac5bf5c11 100644 --- a/experiment/trend_analysis/non_stationary_trends.py +++ b/experiment/trend_analysis/non_stationary_trends.py @@ -106,10 +106,10 @@ class AbstractNonStationaryTrendTest(object): # Load the estimator only once if self.multiprocessing: with Pool(self.nb_cores) as p: - stationary_estimator, *non_stationary_estimators = p.map(self.load_estimator, [None] + years) + stationary_estimator, *non_stationary_estimators = p.map(self.get_estimator, [None] + years) else: - stationary_estimator = self.load_estimator(None) - non_stationary_estimators = [self.load_estimator(year) for year in years] + stationary_estimator = self.get_estimator(None) + non_stationary_estimators = [self.get_estimator(year) for year in years] self._starting_point_to_estimator[None] = stationary_estimator for year, non_stationary_estimator in zip(years, non_stationary_estimators): self._starting_point_to_estimator[year] = non_stationary_estimator diff --git a/extreme_estimator/estimator/abstract_estimator.py b/extreme_estimator/estimator/abstract_estimator.py index 1b8ac471f656efc7a3a3d7321b799aa14ce0b34f..857fef72b9d33d0f060412f036aba0f80a6ff04f 100644 --- a/extreme_estimator/estimator/abstract_estimator.py +++ b/extreme_estimator/estimator/abstract_estimator.py @@ -56,7 +56,7 @@ class AbstractEstimator(object): return LinearMarginFunction.from_coef_dict(coordinates=self.dataset.coordinates, gev_param_name_to_dims=margin_model.margin_function_start_fit.gev_param_name_to_dims, coef_dict=self.result_from_fit.margin_coef_dict, - starting_point=margin_model.transformed_starting_point) + starting_point=margin_model.starting_point) # @property # def max_stable_fitted(self) -> AbstractMarginFunction: diff --git a/extreme_estimator/estimator/full_estimator/abstract_full_estimator.py b/extreme_estimator/estimator/full_estimator/abstract_full_estimator.py index 1c472b1a08c1466bb545b33a78d3adb2161e3a9f..38b59b5b3c2a218ba6caf746a95264ec341ec381 100644 --- a/extreme_estimator/estimator/full_estimator/abstract_full_estimator.py +++ b/extreme_estimator/estimator/full_estimator/abstract_full_estimator.py @@ -62,8 +62,8 @@ class FullEstimatorInASingleStepWithSmoothMargin(AbstractFullEstimator): @property def df_coordinates_temp(self): - df_coordinates_temp = self.dataset.coordinates.df_temporal_coordinates(self.train_split) - return self.linear_margin_model.add_starting_temporal_point(df_coordinates_temp) + return self.dataset.coordinates.df_temporal_coordinates_for_fit(split=self.train_split, + starting_point=self.linear_margin_model.starting_point) def _fit(self): # Estimate both the margin and the max-stable structure diff --git a/extreme_estimator/estimator/margin_estimator/abstract_margin_estimator.py b/extreme_estimator/estimator/margin_estimator/abstract_margin_estimator.py index 3456cd456f175ad2c3df7b71a31ead3f793b1b4f..8a747fde45f0cbab5501c296d6761140fa4ab68e 100644 --- a/extreme_estimator/estimator/margin_estimator/abstract_margin_estimator.py +++ b/extreme_estimator/estimator/margin_estimator/abstract_margin_estimator.py @@ -31,8 +31,8 @@ class LinearMarginEstimator(AbstractMarginEstimator): def _fit(self): maxima_gev_specialized = self.dataset.maxima_gev_for_spatial_extremes_package(self.train_split) df_coordinates_spat = self.dataset.coordinates.df_spatial_coordinates(self.train_split) - df_coordinates_temp = self.dataset.coordinates.df_temporal_coordinates(self.train_split) - df_coordinates_temp = self.margin_model.add_starting_temporal_point(df_coordinates_temp) + df_coordinates_temp = self.dataset.coordinates.df_temporal_coordinates_for_fit(split=self.train_split, + starting_point=self.margin_model.starting_point) self._result_from_fit = self.margin_model.fitmargin_from_maxima_gev(data=maxima_gev_specialized, df_coordinates_spat=df_coordinates_spat, df_coordinates_temp=df_coordinates_temp) @@ -43,4 +43,3 @@ class LinearMarginEstimator(AbstractMarginEstimator): def extract_function_fitted(self) -> LinearMarginFunction: return self.extract_function_fitted_from_the_model_shape(self.margin_model) - diff --git a/extreme_estimator/extreme_models/margin_model/linear_margin_model.py b/extreme_estimator/extreme_models/margin_model/linear_margin_model.py index 87f361f3e26d997f27bf6e1f5b8a6b57cbda9402..14b1b7d9fdf8ce3d2f332f923567215b96be5c32 100644 --- a/extreme_estimator/extreme_models/margin_model/linear_margin_model.py +++ b/extreme_estimator/extreme_models/margin_model/linear_margin_model.py @@ -28,14 +28,14 @@ class LinearMarginModel(ParametricMarginModel): self.margin_function_sample = LinearMarginFunction(coordinates=self.coordinates, gev_param_name_to_coef=coef_sample, gev_param_name_to_dims=gev_param_name_to_dims, - transformed_starting_point=self.transformed_starting_point) + starting_point=self.starting_point) # Load start fit coef coef_start_fit = self.gev_param_name_to_linear_coef(param_name_and_dim_to_coef=self.params_start_fit) self.margin_function_start_fit = LinearMarginFunction(coordinates=self.coordinates, gev_param_name_to_coef=coef_start_fit, gev_param_name_to_dims=gev_param_name_to_dims, - transformed_starting_point=self.transformed_starting_point) + starting_point=self.starting_point) @property def default_param_name_and_dim_to_coef(self) -> dict: diff --git a/extreme_estimator/extreme_models/margin_model/margin_function/independent_margin_function.py b/extreme_estimator/extreme_models/margin_model/margin_function/independent_margin_function.py index 581b272339d78c3a1b31a757bec3e9024457ad59..281b40c83ba6a1800cc4848e53de6322ab34d924 100644 --- a/extreme_estimator/extreme_models/margin_model/margin_function/independent_margin_function.py +++ b/extreme_estimator/extreme_models/margin_model/margin_function/independent_margin_function.py @@ -19,22 +19,21 @@ class IndependentMarginFunction(AbstractMarginFunction): super().__init__(coordinates) self.gev_param_name_to_param_function = None # type: Union[None, Dict[str, AbstractParamFunction]] - def get_gev_params(self, coordinate: np.ndarray, already_transformed: bool = False) -> GevParams: + def get_gev_params(self, coordinate: np.ndarray, is_transformed: bool = True) -> GevParams: """Each GEV parameter is computed independently through its corresponding param_function""" + # Since all the coordinates are usually transformed by default + # then we assume that the input coordinate are transformed by default assert self.gev_param_name_to_param_function is not None assert len(self.gev_param_name_to_param_function) == 3 - if already_transformed: - transformed_coordinate = coordinate - else: - transformed_coordinate = self.transform(coordinate) + transformed_coordinate = coordinate if is_transformed else self.transform(coordinate) gev_params = {} for gev_param_name in GevParams.PARAM_NAMES: param_function = self.gev_param_name_to_param_function[gev_param_name] gev_params[gev_param_name] = param_function.get_gev_param_value(transformed_coordinate) return GevParams.from_dict(gev_params) - def transform(self, coordinate): - transformed_coordinate = self.coordinates.transform(coordinate) - return transformed_coordinate + def transform(self, coordinate: np.ndarray) -> np.ndarray: + return self.coordinates.transformation.transform_array(coordinate) + 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 4c1b0f2ab3e4ce6da0d01807de3eece14b8d6b04..ad975235f95926f6b46f6221a53f4e17beded1e5 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 @@ -28,9 +28,9 @@ class LinearMarginFunction(ParametricMarginFunction): COEF_CLASS = LinearCoef def __init__(self, coordinates: AbstractCoordinates, gev_param_name_to_dims: Dict[str, List[int]], - gev_param_name_to_coef: Dict[str, AbstractCoef], transformed_starting_point: Union[None, int] = None): + gev_param_name_to_coef: Dict[str, AbstractCoef], starting_point: Union[None, int] = None): self.gev_param_name_to_coef = None # type: Union[None, Dict[str, LinearCoef]] - super().__init__(coordinates, gev_param_name_to_dims, gev_param_name_to_coef, transformed_starting_point) + super().__init__(coordinates, gev_param_name_to_dims, gev_param_name_to_coef, starting_point) def load_specific_param_function(self, gev_param_name) -> AbstractParamFunction: return LinearParamFunction(dims=self.gev_param_name_to_dims[gev_param_name], diff --git a/extreme_estimator/extreme_models/margin_model/margin_function/parametric_margin_function.py b/extreme_estimator/extreme_models/margin_model/margin_function/parametric_margin_function.py index 2644744bb4ab6a1f79bc33d368194872962d0201..de4270791b472efef3425dcaef22002a68ae7338 100644 --- a/extreme_estimator/extreme_models/margin_model/margin_function/parametric_margin_function.py +++ b/extreme_estimator/extreme_models/margin_model/margin_function/parametric_margin_function.py @@ -31,9 +31,9 @@ class ParametricMarginFunction(IndependentMarginFunction): COEF_CLASS = None def __init__(self, coordinates: AbstractCoordinates, gev_param_name_to_dims: Dict[str, List[int]], - gev_param_name_to_coef: Dict[str, AbstractCoef], transformed_starting_point: Union[None, int] = None): + gev_param_name_to_coef: Dict[str, AbstractCoef], starting_point: Union[None, int] = None): # Starting point for the trend is the same for all the parameters - self.transformed_starting_point = transformed_starting_point + self.starting_point = starting_point super().__init__(coordinates) self.gev_param_name_to_dims = gev_param_name_to_dims # type: Dict[str, List[int]] @@ -61,15 +61,19 @@ class ParametricMarginFunction(IndependentMarginFunction): def load_specific_param_function(self, gev_param_name) -> AbstractParamFunction: raise NotImplementedError - def get_gev_params(self, coordinate: np.ndarray, already_transformed: bool = False) -> GevParams: - transformed_coordinate = self.transform(coordinate) - if self.transformed_starting_point is not None: + @property + def transformed_starting_point(self): + return self.coordinates.temporal_coordinates.transformation.transform_array(np.array([self.starting_point])) + + def get_gev_params(self, coordinate: np.ndarray, is_transformed: bool = True) -> GevParams: + if self.starting_point is not None: + starting_point = self.transformed_starting_point if is_transformed else self.starting_point # Shift temporal coordinate to enable to model temporal trend with starting point assert self.coordinates.has_temporal_coordinates assert 0 <= self.coordinates.idx_temporal_coordinates < len(coordinate) - if transformed_coordinate[self.coordinates.idx_temporal_coordinates] < self.transformed_starting_point: - transformed_coordinate[self.coordinates.idx_temporal_coordinates] = self.transformed_starting_point - return super().get_gev_params(transformed_coordinate, already_transformed=True) + if coordinate[self.coordinates.idx_temporal_coordinates] < starting_point: + coordinate[self.coordinates.idx_temporal_coordinates] = starting_point + return super().get_gev_params(coordinate, is_transformed=is_transformed) @classmethod def from_coef_dict(cls, coordinates: AbstractCoordinates, gev_param_name_to_dims: Dict[str, List[int]], diff --git a/extreme_estimator/extreme_models/margin_model/parametric_margin_model.py b/extreme_estimator/extreme_models/margin_model/parametric_margin_model.py index feb0f46b67228f75453b51d2ffdf1259880a13f8..e9241c4586cf96df592a4e30a41657ad5cd9ddab 100644 --- a/extreme_estimator/extreme_models/margin_model/parametric_margin_model.py +++ b/extreme_estimator/extreme_models/margin_model/parametric_margin_model.py @@ -23,29 +23,11 @@ class ParametricMarginModel(AbstractMarginModel, ABC): """ :param starting_point: starting coordinate for the temporal trend """ - # Load transformed starting point - if starting_point is None: - self.transformed_starting_point = None - else: - assert isinstance(coordinates, (AbstractSpatioTemporalCoordinates, AbstractTemporalCoordinates)) - temporal_coordinate = np.array([starting_point]) - self.transformed_starting_point = coordinates.temporal_coordinates.transform(temporal_coordinate)[0] - + self.starting_point = starting_point self.margin_function_sample = None # type: ParametricMarginFunction self.margin_function_start_fit = None # type: ParametricMarginFunction super().__init__(coordinates, use_start_value, params_start_fit, params_sample) - def add_starting_temporal_point(self, df_coordinates_temp: pd.DataFrame): - # Enforce a starting point for the temporal trend - if self.transformed_starting_point is not None: - # Compute the indices to modify - ind_to_modify = df_coordinates_temp.iloc[:, 0] <= self.transformed_starting_point # type: pd.Series - # Assert that some coordinates are selected but not all (at least 20 data should be left for temporal trend) - assert 0 < sum(ind_to_modify) < len(ind_to_modify) - 20 - # Modify the temporal coordinates to enforce the stationarity - df_coordinates_temp.loc[ind_to_modify] = self.transformed_starting_point - return df_coordinates_temp - def fitmargin_from_maxima_gev(self, data: np.ndarray, df_coordinates_spat: pd.DataFrame, df_coordinates_temp: pd.DataFrame) -> ResultFromFit: assert data.shape[1] == len(df_coordinates_spat) 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 index 48237de33f77c42c7709ac2004a08846d4ade4be..9f9a80578985c9e6e111a9744b82afc5df38b1f5 100644 --- a/extreme_estimator/extreme_models/margin_model/temporal_linear_margin_model.py +++ b/extreme_estimator/extreme_models/margin_model/temporal_linear_margin_model.py @@ -18,8 +18,6 @@ class TemporalLinearMarginModel(LinearMarginModel): 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 assert data.shape[1] == len(df_coordinates_temp.values) res = safe_run_r_estimator(function=r('gev.fit'), use_start=self.use_start_value, diff --git a/spatio_temporal_dataset/coordinates/abstract_coordinates.py b/spatio_temporal_dataset/coordinates/abstract_coordinates.py index 9a8f63de57e20bfde1e5d936b5d90a55cf2514b6..1f1dd4f67267d483bf2edd9cd32f29530958699d 100644 --- a/spatio_temporal_dataset/coordinates/abstract_coordinates.py +++ b/spatio_temporal_dataset/coordinates/abstract_coordinates.py @@ -58,12 +58,13 @@ class AbstractCoordinates(object): # Transformation attribute if transformation_class is None: transformation_class = IdentityTransformation + self.transformation_class = transformation_class # type: type # Transformation only works for float coordinates accepted_dtypes = [self.COORDINATE_TYPE] assert len(self.df_all_coordinates.select_dtypes(include=accepted_dtypes).columns) \ == len(coordinate_columns), 'coordinates columns dtypes should belong to {}'.format(accepted_dtypes) # Transformation class is instantiated with all coordinates - self.transformation = transformation_class(self.df_all_coordinates) + self.transformation = transformation_class(self.df_all_coordinates) # type: AbstractTransformation assert isinstance(self.transformation, AbstractTransformation) # Load the slicer @@ -130,20 +131,17 @@ class AbstractCoordinates(object): # Merged DataFrame of df_coord with s_split return self.df_all_coordinates.join(self.df_split) - # Normalize - - def transform(self, coordinate: np.ndarray) -> np.ndarray: - coordinate_array_as_float = coordinate.astype(self.COORDINATE_TYPE) - return self.transformation.transform_array(coordinate=coordinate_array_as_float) - # Split - def df_coordinates(self, split: Split = Split.all) -> pd.DataFrame: - df_transformed_coordinates = self.transformation.transform_df(self.df_all_coordinates) + def df_coordinates(self, split: Split = Split.all, transformed=True) -> pd.DataFrame: + if transformed: + df_transformed_coordinates = self.transformation.transform_df(self.df_all_coordinates) + else: + df_transformed_coordinates = self.df_all_coordinates return df_sliced(df=df_transformed_coordinates, split=split, slicer=self.slicer) - def coordinates_values(self, split: Split = Split.all) -> np.ndarray: - return self.df_coordinates(split).values + def coordinates_values(self, split: Split = Split.all, transformed=True) -> np.ndarray: + return self.df_coordinates(split, transformed=transformed).values def coordinates_index(self, split: Split = Split.all) -> pd.Index: return self.df_coordinates(split).index @@ -193,11 +191,11 @@ class AbstractCoordinates(object): def has_spatial_coordinates(self) -> bool: return self.nb_coordinates_spatial > 0 - def df_spatial_coordinates(self, split: Split = Split.all) -> pd.DataFrame: + def df_spatial_coordinates(self, split: Split = Split.all, transformed=True) -> pd.DataFrame: if self.nb_coordinates_spatial == 0: return pd.DataFrame() else: - return self.df_coordinates(split).loc[:, self.coordinates_spatial_names].drop_duplicates() + return self.df_coordinates(split, transformed).loc[:, self.coordinates_spatial_names].drop_duplicates() @property def nb_stations(self, split: Split = Split.all) -> int: @@ -225,11 +223,36 @@ class AbstractCoordinates(object): def has_temporal_coordinates(self) -> bool: return self.nb_coordinates_temporal > 0 - def df_temporal_coordinates(self, split: Split = Split.all) -> pd.DataFrame: + def df_temporal_coordinates(self, split: Split = Split.all, transformed=True) -> pd.DataFrame: if self.nb_coordinates_temporal == 0: return pd.DataFrame() else: - return self.df_coordinates(split).loc[:, self.coordinates_temporal_names].drop_duplicates() + return self.df_coordinates(split, transformed=transformed).loc[:, self.coordinates_temporal_names] \ + .drop_duplicates() + + def df_temporal_coordinates_for_fit(self, split=Split.all, starting_point=None) -> pd.DataFrame: + if starting_point is None: + return self.df_temporal_coordinates(split=split, transformed=True) + else: + # Load the un transformed coordinates + df_temporal_coordinates = self.df_temporal_coordinates(split=split, transformed=False) + # If starting point is not None, the transformation has not yet been applied + # thus we need to modify the coordinate with the starting point, and then to apply the transformation + # Compute the indices to modify + ind_to_modify = df_temporal_coordinates.iloc[:, 0] <= starting_point # type: pd.Series + # Assert that some coordinates are selected but not all + assert 0 < sum(ind_to_modify) < len(ind_to_modify) + # Modify the temporal coordinates to enforce the stationarity + df_temporal_coordinates.loc[ind_to_modify] = starting_point + # Load the temporal transformation object + temporal_transformation = self.temporal_coordinates.transformation_class( + df_temporal_coordinates) # type: AbstractTransformation + # Return the result of the temporal transformation + return temporal_transformation.transform_df(df_temporal_coordinates) + + @property + def temporal_coordinates(self): + raise NotImplementedError @property def nb_steps(self, split: Split = Split.all) -> int: diff --git a/spatio_temporal_dataset/coordinates/spatial_coordinates/abstract_spatial_coordinates.py b/spatio_temporal_dataset/coordinates/spatial_coordinates/abstract_spatial_coordinates.py index ef7553bbc52aa32f35082bf12d1813ee81459bff..bb27d6da34a610dc0558135129d43c970af9dad0 100644 --- a/spatio_temporal_dataset/coordinates/spatial_coordinates/abstract_spatial_coordinates.py +++ b/spatio_temporal_dataset/coordinates/spatial_coordinates/abstract_spatial_coordinates.py @@ -24,4 +24,4 @@ class AbstractSpatialCoordinates(AbstractCoordinates): raise Exception('Nb coordinates in csv: {} < Nb points desired: {}'.format(nb_coordinates, nb_points)) # Sample randomly nb_points coordinates df_sample = pd.DataFrame.sample(coordinates.df_merged, n=nb_points) - return cls.from_df(df=df_sample, train_split_ratio=train_split_ratio) + return cls.from_df(df=df_sample, train_split_ratio=train_split_ratio, **kwargs) diff --git a/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_1D.py b/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_1D.py index 15340ca1561e9d91b6b54d5695e1a05e6bbd57ad..e5366354b2240b979efbc936c21eed360cc2cb2e 100644 --- a/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_1D.py +++ b/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_1D.py @@ -13,19 +13,19 @@ class AbstractUniDimensionalSpatialCoordinates(AbstractSpatialCoordinates): class LinSpaceSpatialCoordinates(AbstractUniDimensionalSpatialCoordinates): @classmethod - def from_nb_points(cls, nb_points, train_split_ratio: float = None, start=-1.0, end=1.0): + def from_nb_points(cls, nb_points, train_split_ratio: float = None, start=-1.0, end=1.0, **kwargs): axis_coordinates = np.linspace(start, end, nb_points) df = pd.DataFrame.from_dict({cls.COORDINATE_X: axis_coordinates}) - return cls.from_df(df, train_split_ratio) + return cls.from_df(df, train_split_ratio, **kwargs) class UniformSpatialCoordinates(AbstractUniDimensionalSpatialCoordinates): @classmethod - def from_nb_points(cls, nb_points, train_split_ratio: float = None, start=-1.0, end=1.0): + def from_nb_points(cls, nb_points, train_split_ratio: float = None, start=-1.0, end=1.0, **kwargs): # Sample uniformly inside the circle df = cls.df_spatial(nb_points, start, end) - return cls.from_df(df, train_split_ratio) + return cls.from_df(df, train_split_ratio, **kwargs) @classmethod def df_spatial(cls, nb_points, start=-1.0, end=1.0): diff --git a/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_2D.py b/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_2D.py index 4498f65589280ac81279512f87f31c89fd96fe1e..a6c16539542c779740e9d146614ee06a900dd62d 100644 --- a/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_2D.py +++ b/spatio_temporal_dataset/coordinates/spatial_coordinates/coordinates_2D.py @@ -14,9 +14,9 @@ class AbstractBiDimensionalSpatialCoordinates(AbstractSpatialCoordinates): class LinSpaceSpatial2DCoordinates(AbstractBiDimensionalSpatialCoordinates): @classmethod - def from_nb_points(cls, nb_points, train_split_ratio: float = None, start=-1.0, end=1.0): + def from_nb_points(cls, nb_points, train_split_ratio: float = None, start=-1.0, end=1.0, **kwargs): df = cls.df_spatial(nb_points, start, end) - return cls.from_df(df, train_split_ratio) + return cls.from_df(df, train_split_ratio, **kwargs) @classmethod def df_spatial(cls, nb_points, start=-1.0, end=1.0): diff --git a/spatio_temporal_dataset/coordinates/spatial_coordinates/generated_spatial_coordinates.py b/spatio_temporal_dataset/coordinates/spatial_coordinates/generated_spatial_coordinates.py index cb48486ab6d9d98b990e2460e19912abed9c5115..a27bedba8c7d8f6ff3aae3e1435861170180dff2 100644 --- a/spatio_temporal_dataset/coordinates/spatial_coordinates/generated_spatial_coordinates.py +++ b/spatio_temporal_dataset/coordinates/spatial_coordinates/generated_spatial_coordinates.py @@ -21,8 +21,10 @@ class CircleSpatialCoordinates(AbstractSpatialCoordinates): return df @classmethod - def from_nb_points(cls, nb_points, train_split_ratio: float = None, max_radius=1.0, random=True): - return cls.from_df(cls.df_spatial(nb_points, max_radius, random), train_split_ratio) + def from_nb_points(cls, nb_points, train_split_ratio: float = None, max_radius=1.0, random=True, + transformation_class=None): + return cls.from_df(df=cls.df_spatial(nb_points, max_radius, random), + train_split_ratio=train_split_ratio, transformation_class=transformation_class) def visualization_2D(self): radius = 1.0 @@ -36,5 +38,5 @@ class CircleSpatialCoordinates(AbstractSpatialCoordinates): class CircleSpatialCoordinatesRadius2(CircleSpatialCoordinates): @classmethod - def from_nb_points(cls, nb_points, train_split_ratio: float = None, max_radius=1.0, random=True): - return 2 * super().from_nb_points(nb_points, train_split_ratio, max_radius, random) + def from_nb_points(cls, nb_points, train_split_ratio: float = None, max_radius=1.0, random=True, **kwargs): + return 2 * super().from_nb_points(nb_points, train_split_ratio, max_radius, random, **kwargs) diff --git a/spatio_temporal_dataset/coordinates/spatio_temporal_coordinates/abstract_spatio_temporal_coordinates.py b/spatio_temporal_dataset/coordinates/spatio_temporal_coordinates/abstract_spatio_temporal_coordinates.py index 26bb7e0b1421a995539045eb129981ee8e4adfdb..14c0b01aea0cd40eba13e42ad68129fe245f3c81 100644 --- a/spatio_temporal_dataset/coordinates/spatio_temporal_coordinates/abstract_spatio_temporal_coordinates.py +++ b/spatio_temporal_dataset/coordinates/spatio_temporal_coordinates/abstract_spatio_temporal_coordinates.py @@ -6,6 +6,8 @@ from spatio_temporal_dataset.coordinates.spatial_coordinates.abstract_spatial_co AbstractSpatialCoordinates from spatio_temporal_dataset.coordinates.temporal_coordinates.abstract_temporal_coordinates import \ AbstractTemporalCoordinates +from spatio_temporal_dataset.coordinates.transformed_coordinates.transformation.multiple_transformation import \ + MultipleTransformation from spatio_temporal_dataset.coordinates.utils import get_index_with_spatio_temporal_index_suffix from spatio_temporal_dataset.slicer.spatio_temporal_slicer import SpatioTemporalSlicer @@ -20,23 +22,30 @@ class AbstractSpatioTemporalCoordinates(AbstractCoordinates): super().__init__(df, slicer_class, s_split_spatial, s_split_temporal, None) # Spatial coordinates' if spatial_coordinates is None: - self.spatial_coordinates = AbstractSpatialCoordinates.from_df(df=self.df_spatial_coordinates(), - transformation_class=transformation_class) + self._spatial_coordinates = AbstractSpatialCoordinates.from_df( + df=self.df_spatial_coordinates(transformed=False), + transformation_class=transformation_class) else: - self.spatial_coordinates = spatial_coordinates + self._spatial_coordinates = spatial_coordinates # Temporal coordinates if temporal_coordinates is None: - self.temporal_coordinates = AbstractTemporalCoordinates.from_df(df=self.df_temporal_coordinates(), - transformation_class=transformation_class) + self._temporal_coordinates = AbstractTemporalCoordinates.from_df( + df=self.df_temporal_coordinates(transformed=False), + transformation_class=transformation_class) else: - self.temporal_coordinates = temporal_coordinates + self._temporal_coordinates = temporal_coordinates + # Combined the transformations + self.transformation_class = None + self.transformation = MultipleTransformation(transformation_1=self.spatial_coordinates.transformation, + transformation_2=self.temporal_coordinates.transformation) - def transform(self, coordinate: np.ndarray) -> np.ndarray: - *coordinate_spatial, coordinate_temporal = coordinate - transformed_coordinate_spatial = self.spatial_coordinates.transform(np.array(coordinate_spatial)) - transformed_coordinate_temporal = self.temporal_coordinates.transform(np.array([coordinate_temporal])) - transformed_coordinate = np.concatenate([transformed_coordinate_spatial, transformed_coordinate_temporal]) - return transformed_coordinate + @property + def spatial_coordinates(self): + return self._spatial_coordinates + + @property + def temporal_coordinates(self): + return self._temporal_coordinates @classmethod def get_df_from_df_spatial_and_coordinate_t_values(cls, coordinate_t_values, df_spatial): @@ -52,8 +61,8 @@ class AbstractSpatioTemporalCoordinates(AbstractCoordinates): @classmethod def from_spatial_coordinates_and_temporal_coordinates(cls, spatial_coordinates: AbstractSpatialCoordinates, temporal_coordinates: AbstractTemporalCoordinates): - df_spatial = spatial_coordinates.df_spatial_coordinates() - coordinate_t_values = temporal_coordinates.df_temporal_coordinates().iloc[:, 0].values + df_spatial = spatial_coordinates.df_spatial_coordinates(transformed=False) + coordinate_t_values = temporal_coordinates.df_temporal_coordinates(transformed=False).iloc[:, 0].values df = cls.get_df_from_df_spatial_and_coordinate_t_values(df_spatial=df_spatial, coordinate_t_values=coordinate_t_values) return cls(df=df, slicer_class=SpatioTemporalSlicer, diff --git a/spatio_temporal_dataset/coordinates/temporal_coordinates/abstract_temporal_coordinates.py b/spatio_temporal_dataset/coordinates/temporal_coordinates/abstract_temporal_coordinates.py index 8edda8474254c4bd0982b4b48e67634cb5d00007..c4362377471ffcf30014a3005d45695cd7d62033 100644 --- a/spatio_temporal_dataset/coordinates/temporal_coordinates/abstract_temporal_coordinates.py +++ b/spatio_temporal_dataset/coordinates/temporal_coordinates/abstract_temporal_coordinates.py @@ -12,7 +12,7 @@ class AbstractTemporalCoordinates(AbstractCoordinates): @property def transformed_distance_between_two_successive_years(self): - return self.transform(np.ones([1])) - self.transform(np.zeros([1])) + return self.transformation.transform_array(np.ones([1])) - self.transformation.transform_array(np.zeros([1])) @classmethod def from_df(cls, df: pd.DataFrame, train_split_ratio: float = None, transformation_class: type = None): diff --git a/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/abstract_transformation.py b/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/abstract_transformation.py index e6a5012ba5db3bc555b9154971b4d1becb134325..27a83545ea08704697c8d43a045e0301d714ae1e 100644 --- a/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/abstract_transformation.py +++ b/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/abstract_transformation.py @@ -8,6 +8,7 @@ class AbstractTransformation(object): def __init__(self, df_coordinates): self.df_coordinates = df_coordinates.copy() + # todo: we could add some checks on the type of the input data @property def nb_dimensions(self): return self.df_coordinates.shape[1] @@ -25,6 +26,8 @@ class AbstractTransformation(object): return pd.DataFrame(data, index=df_coord.index, columns=df_coord.columns) + + class IdentityTransformation(AbstractTransformation): def transform_array(self, coordinate: np.ndarray): diff --git a/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/multiple_transformation.py b/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/multiple_transformation.py new file mode 100644 index 0000000000000000000000000000000000000000..643bc455c10063aa651036b0dbec7c729e23fbd5 --- /dev/null +++ b/spatio_temporal_dataset/coordinates/transformed_coordinates/transformation/multiple_transformation.py @@ -0,0 +1,24 @@ +import numpy as np + +from spatio_temporal_dataset.coordinates.transformed_coordinates.transformation.abstract_transformation import \ + AbstractTransformation + + +class MultipleTransformation(AbstractTransformation): + + def __init__(self, transformation_1, transformation_2): + self.transformation_1 = transformation_1 # type: AbstractTransformation + self.transformation_2 = transformation_2 # type: AbstractTransformation + + @property + def nb_dimensions(self): + return self.transformation_1.nb_dimensions + self.transformation_2.nb_dimensions + + def transform_array(self, coordinate: np.ndarray): + super().transform_array(coordinate) + coordinate_1 = coordinate[:self.transformation_1.nb_dimensions] + transformed_coordinate_1 = self.transformation_1.transform_array(coordinate_1) + coordinate_2 = coordinate[-self.transformation_2.nb_dimensions:] + transformed_coordinate_2 = self.transformation_2.transform_array(coordinate_2) + transformed_coordinate = np.concatenate([transformed_coordinate_1, transformed_coordinate_2]) + return transformed_coordinate diff --git a/test/test_experiment/test_coordinate_sensitivity.py b/test/test_experiment/test_coordinate_sensitivity.py index ea4daa978f3e064fb8af9860896c0fff46a8619d..2674c703e04c3463fb3e766ad14145415ce5fbf7 100644 --- a/test/test_experiment/test_coordinate_sensitivity.py +++ b/test/test_experiment/test_coordinate_sensitivity.py @@ -31,16 +31,14 @@ class TestCoordinateSensitivity(unittest.TestCase): mu1s = [trend_test.get_mu_coefs(year)['mu_temporal'] for year in years] if self.DISPLAY: print('Stationary') - stationary_est = trend_test.load_estimator(trend_test.stationary_margin_model_class, - starting_point=None) + stationary_est = trend_test.get_estimator(starting_point=None) + print(stationary_est.margin_function_fitted.coordinates.df_all_coordinates) print(stationary_est.result_from_fit.convergence) print(stationary_est.margin_function_fitted.coef_dict) print('Non Stationary') - non_stationary_est = trend_test.load_estimator(trend_test.non_stationary_margin_model_class, - starting_point=1960) + non_stationary_est = trend_test.get_estimator(starting_point=1960) print(non_stationary_est.result_from_fit.convergence) - non_stationary_est = trend_test.load_estimator(trend_test.non_stationary_margin_model_class, - starting_point=1990) + non_stationary_est = trend_test.get_estimator(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) diff --git a/test/test_extreme_estimator/test_extreme_models/test_margin_temporal.py b/test/test_extreme_estimator/test_extreme_models/test_margin_temporal.py index 6ba798ee4bf4714fd6c3307e251a0cd334d22f72..17bb019a20c0887537b50b5aa707c4e2b19c3ef8 100644 --- a/test/test_extreme_estimator/test_extreme_models/test_margin_temporal.py +++ b/test/test_extreme_estimator/test_extreme_models/test_margin_temporal.py @@ -59,7 +59,7 @@ class TestMarginTemporal(unittest.TestCase): self.smooth_margin_model.margin_function_sample.mu1_temporal_trend, places=3) # Checks starting point parameter are well passed - self.assertEqual(2, estimator.margin_function_fitted.transformed_starting_point) + self.assertEqual(2, estimator.margin_function_fitted.starting_point) # Checks that parameters returned are indeed different coordinate1 = np.array([0.0, 0.0, 1]) mle_params_estimated_year1 = estimator.margin_function_fitted.get_gev_params(coordinate1).to_dict() diff --git a/test/test_extreme_estimator/test_extreme_models/test_margin_temporal_transformed.py b/test/test_extreme_estimator/test_extreme_models/test_margin_temporal_transformed.py index bb6f266272efa083d44fe390c89718532ce40b8a..df2e0b1c8e0c95330816a66d92380e0156605abe 100644 --- a/test/test_extreme_estimator/test_extreme_models/test_margin_temporal_transformed.py +++ b/test/test_extreme_estimator/test_extreme_models/test_margin_temporal_transformed.py @@ -14,7 +14,7 @@ from spatio_temporal_dataset.dataset.simulation_dataset import MarginDataset from test.test_utils import load_test_spatiotemporal_coordinates -class TestMarginTemporal(unittest.TestCase): +class TestMarginTemporalTransformed(unittest.TestCase): def setUp(self) -> None: set_seed_for_test(seed=42) @@ -23,7 +23,8 @@ class TestMarginTemporal(unittest.TestCase): self.nb_obs = 1 # Load some 2D spatial coordinates self.coordinates = load_test_spatiotemporal_coordinates(nb_steps=self.nb_steps, nb_points=self.nb_points, - transformation_class=BetweenZeroAndOneNormalization)[1] # type: AbstractSpatioTemporalCoordinates + transformation_class=BetweenZeroAndOneNormalization)[ + 1] # type: AbstractSpatioTemporalCoordinates self.smooth_margin_model = LinearNonStationaryLocationMarginModel(coordinates=self.coordinates, starting_point=2) self.dataset = MarginDataset.from_sampling(nb_obs=self.nb_obs, @@ -35,12 +36,14 @@ class TestMarginTemporal(unittest.TestCase): margin_model = LinearStationaryMarginModel(self.coordinates) estimator = LinearMarginEstimator(self.dataset, margin_model) estimator.fit() - ref = {'loc': 1.1650543404552496, 'scale': 1.1097775613768615, 'shape': 0.6737277802240037} + ref = {'loc': 1.1051277249518898, + 'scale': 1.0618264487048108, + 'shape': 0.7289248773961512} for year in range(1, 3): coordinate = np.array([0.0, 0.0, year]) - mle_params_estimated = estimator.margin_function_fitted.get_gev_params(coordinate).to_dict() - for key in ref.keys(): - self.assertAlmostEqual(ref[key], mle_params_estimated[key], places=3) + mle_params_estimated = estimator.margin_function_fitted.get_gev_params(coordinate, + is_transformed=False).to_dict() + self.assertEqual(mle_params_estimated, ref) def test_margin_fit_nonstationary(self): # Create estimator @@ -50,9 +53,11 @@ class TestMarginTemporal(unittest.TestCase): self.assertNotEqual(estimator.margin_function_fitted.mu1_temporal_trend, 0.0) # Checks that parameters returned are indeed different coordinate1 = np.array([0.0, 0.0, 1]) - mle_params_estimated_year1 = estimator.margin_function_fitted.get_gev_params(coordinate1).to_dict() + mle_params_estimated_year1 = estimator.margin_function_fitted.get_gev_params(coordinate1, + is_transformed=False).to_dict() coordinate3 = np.array([0.0, 0.0, 3]) - mle_params_estimated_year3 = estimator.margin_function_fitted.get_gev_params(coordinate3).to_dict() + mle_params_estimated_year3 = estimator.margin_function_fitted.get_gev_params(coordinate3, + is_transformed=False).to_dict() self.assertNotEqual(mle_params_estimated_year1, mle_params_estimated_year3) def test_margin_fit_nonstationary_with_start_point(self): @@ -62,12 +67,15 @@ class TestMarginTemporal(unittest.TestCase): self.assertNotEqual(estimator.margin_function_fitted.mu1_temporal_trend, 0.0) # Checks that parameters returned are indeed different coordinate1 = np.array([0.0, 0.0, 1]) - mle_params_estimated_year1 = estimator.margin_function_fitted.get_gev_params(coordinate1).to_dict() + mle_params_estimated_year1 = estimator.margin_function_fitted.get_gev_params(coordinate1, + is_transformed=False).to_dict() coordinate2 = np.array([0.0, 0.0, 2]) - mle_params_estimated_year2 = estimator.margin_function_fitted.get_gev_params(coordinate2).to_dict() + mle_params_estimated_year2 = estimator.margin_function_fitted.get_gev_params(coordinate2, + is_transformed=False).to_dict() self.assertEqual(mle_params_estimated_year1, mle_params_estimated_year2) coordinate5 = np.array([0.0, 0.0, 5]) - mle_params_estimated_year5 = estimator.margin_function_fitted.get_gev_params(coordinate5).to_dict() + mle_params_estimated_year5 = estimator.margin_function_fitted.get_gev_params(coordinate5, + is_transformed=False).to_dict() self.assertNotEqual(mle_params_estimated_year5, mle_params_estimated_year2) def fit_non_stationary_estimator(self, starting_point): diff --git a/test/test_extreme_estimator/test_extreme_models/test_max_stable_temporal.py b/test/test_extreme_estimator/test_extreme_models/test_max_stable_temporal.py index 6a359c9f3b478e9102013c8fd583c4ca55452039..e0b4c08a9b5687ebfa9cb0accc73657b161ff2e2 100644 --- a/test/test_extreme_estimator/test_extreme_models/test_max_stable_temporal.py +++ b/test/test_extreme_estimator/test_extreme_models/test_max_stable_temporal.py @@ -64,7 +64,7 @@ class TestMaxStableTemporal(unittest.TestCase): self.smooth_margin_model.margin_function_sample.mu1_temporal_trend, places=2) # Checks starting point parameter are well passed - self.assertEqual(2, estimator.margin_function_fitted.transformed_starting_point) + self.assertEqual(2, estimator.margin_function_fitted.starting_point) # Checks that parameters returned are indeed different coordinate1 = np.array([0.0, 0.0, 1]) mle_params_estimated_year1 = estimator.margin_function_fitted.get_gev_params(coordinate1).to_dict() diff --git a/test/test_extreme_estimator/test_margin_fits/test_gev/test_gev_temporal.py b/test/test_extreme_estimator/test_margin_fits/test_gev/test_gev_temporal.py index d8b1c71a98519ea9251ba3d64f79b12b482ffac1..8ffe351324c74f4df0d402ca2260899fb77a1da6 100644 --- a/test/test_extreme_estimator/test_margin_fits/test_gev/test_gev_temporal.py +++ b/test/test_extreme_estimator/test_margin_fits/test_gev/test_gev_temporal.py @@ -63,7 +63,7 @@ class TestGevTemporal(unittest.TestCase): estimator = self.fit_non_stationary_estimator(starting_point=3) self.assertNotEqual(estimator.margin_function_fitted.mu1_temporal_trend, 0.0) # Checks starting point parameter are well passed - self.assertEqual(3, estimator.margin_function_fitted.transformed_starting_point) + self.assertEqual(3, estimator.margin_function_fitted.starting_point) # Checks that parameters returned are indeed different mle_params_estimated_year1 = estimator.margin_function_fitted.get_gev_params(np.array([1])).to_dict() mle_params_estimated_year3 = estimator.margin_function_fitted.get_gev_params(np.array([3])).to_dict() diff --git a/test/test_spatio_temporal_dataset/test_coordinates.py b/test/test_spatio_temporal_dataset/test_coordinates.py index 5ee85578f5aee3412d19e2d28b660772e33abe92..feac9162a0b1f8de6582d56d51a94588782b5a96 100644 --- a/test/test_spatio_temporal_dataset/test_coordinates.py +++ b/test/test_spatio_temporal_dataset/test_coordinates.py @@ -1,8 +1,12 @@ import unittest +import numpy as np import pandas as pd from collections import Counter, OrderedDict +from extreme_estimator.extreme_models.utils import set_seed_for_test from spatio_temporal_dataset.coordinates.abstract_coordinates import AbstractCoordinates +from spatio_temporal_dataset.coordinates.spatio_temporal_coordinates.abstract_spatio_temporal_coordinates import \ + AbstractSpatioTemporalCoordinates from spatio_temporal_dataset.coordinates.spatio_temporal_coordinates.generated_spatio_temporal_coordinates import \ UniformSpatioTemporalCoordinates, GeneratedSpatioTemporalCoordinates from spatio_temporal_dataset.coordinates.spatial_coordinates.coordinates_1D import UniformSpatialCoordinates, \ @@ -13,8 +17,14 @@ from spatio_temporal_dataset.coordinates.spatial_coordinates.alps_station_3D_coo AlpsStation3DCoordinatesWithAnisotropy from spatio_temporal_dataset.coordinates.spatial_coordinates.generated_spatial_coordinates import \ CircleSpatialCoordinates +from spatio_temporal_dataset.coordinates.transformed_coordinates.transformation.abstract_transformation import \ + CenteredScaledNormalization +from spatio_temporal_dataset.coordinates.transformed_coordinates.transformation.uniform_normalization import \ + BetweenZeroAndOneNormalization from spatio_temporal_dataset.coordinates.utils import get_index_with_spatio_temporal_index_suffix from spatio_temporal_dataset.slicer.spatio_temporal_slicer import SpatioTemporalSlicer +from test.test_utils import load_test_spatiotemporal_coordinates, load_test_spatial_coordinates, \ + load_test_temporal_coordinates, load_test_1D_and_2D_spatial_coordinates class TestSpatialCoordinates(unittest.TestCase): @@ -103,5 +113,41 @@ class SpatioTemporalCoordinates(unittest.TestCase): [AbstractCoordinates.COORDINATE_X, AbstractCoordinates.COORDINATE_T]) +class TestCoordinatesWithTransformedStartingPoint(unittest.TestCase): + + def setUp(self) -> None: + set_seed_for_test(seed=42) + self.nb_points = 2 + self.nb_steps = 50 + self.nb_obs = 1 + + def test_starting_point_with_zero_one_normalization(self): + # Load some 2D spatial coordinates + coordinates = load_test_spatiotemporal_coordinates(nb_steps=self.nb_steps, nb_points=self.nb_points, + transformation_class=BetweenZeroAndOneNormalization)[ + 1] # type: AbstractSpatioTemporalCoordinates + df = coordinates.df_temporal_coordinates_for_fit(starting_point=2) + start_coordinates = df.iloc[2, 0] + self.assertEqual(start_coordinates, 0.0) + + def test_starting_point_with_centered_scaled_normalization(self): + # Load some 2D spatial coordinates + spatial_coordinate = load_test_1D_and_2D_spatial_coordinates(nb_points=self.nb_points, + transformation_class=BetweenZeroAndOneNormalization)[ + 0] + temporal_coordinates = \ + load_test_temporal_coordinates(nb_steps=self.nb_steps, transformation_class=CenteredScaledNormalization)[0] + coordinates = AbstractSpatioTemporalCoordinates.from_spatial_coordinates_and_temporal_coordinates( + spatial_coordinates=spatial_coordinate, + temporal_coordinates=temporal_coordinates) + # Check that df_all_coordinates have not yet been normalized + self.assertEqual(coordinates.df_temporal_coordinates(transformed=False).iloc[-1, 0], 49.0) + # Check that the normalization is working + self.assertAlmostEqual(coordinates.df_temporal_coordinates_for_fit(starting_point=None).iloc[0, 0], -1.697749375254331) + self.assertAlmostEqual(coordinates.df_temporal_coordinates_for_fit(starting_point=2).iloc[2, 0], -1.5739459974625107) + self.assertNotEqual(coordinates.df_temporal_coordinates_for_fit(starting_point=2).iloc[2, 0], + coordinates.df_temporal_coordinates_for_fit(starting_point=2).iloc[3, 0]) + + if __name__ == '__main__': unittest.main() diff --git a/test/test_utils.py b/test/test_utils.py index e3eb691e16f7590aa0f00843aeedbca2613db220..00fe031f846ae3ed6b5ec4b484af9c1356da638f 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -77,23 +77,27 @@ def load_test_max_stable_models(default_covariance_function=None): return max_stable_models -def load_test_spatial_coordinates(nb_points, coordinate_types, train_split_ratio=None): - return [coordinate_class.from_nb_points(nb_points=nb_points, train_split_ratio=train_split_ratio) +def load_test_spatial_coordinates(nb_points, coordinate_types, train_split_ratio=None, transformation_class=None): + return [coordinate_class.from_nb_points(nb_points=nb_points, train_split_ratio=train_split_ratio, + transformation_class=transformation_class) for coordinate_class in coordinate_types] -def load_test_1D_and_2D_spatial_coordinates(nb_points, train_split_ratio=None): +def load_test_1D_and_2D_spatial_coordinates(nb_points, train_split_ratio=None, transformation_class=None): return load_test_spatial_coordinates(nb_points, TEST_1D_AND_2D_SPATIAL_COORDINATES, - train_split_ratio=train_split_ratio) + train_split_ratio=train_split_ratio, + transformation_class=transformation_class) -def load_test_3D_spatial_coordinates(nb_points): - return load_test_spatial_coordinates(nb_points, TEST_3D_SPATIAL_COORDINATES) +def load_test_3D_spatial_coordinates(nb_points, transformation_class=None): + return load_test_spatial_coordinates(nb_points, TEST_3D_SPATIAL_COORDINATES, transformation_class=transformation_class) -def load_test_temporal_coordinates(nb_steps, train_split_ratio=None): - return [coordinate_class.from_nb_temporal_steps(nb_steps, train_split_ratio) for coordinate_class in - TEST_TEMPORAL_COORDINATES] +def load_test_temporal_coordinates(nb_steps, train_split_ratio=None, transformation_class=None): + return [coordinate_class.from_nb_temporal_steps(nb_temporal_steps=nb_steps, + train_split_ratio=train_split_ratio, + transformation_class=transformation_class) + for coordinate_class in TEST_TEMPORAL_COORDINATES] def load_test_spatiotemporal_coordinates(nb_points, nb_steps, train_split_ratio=None,