autoemulate 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. autoemulate/__init__.py +0 -0
  2. autoemulate/compare.py +503 -0
  3. autoemulate/cross_validate.py +97 -0
  4. autoemulate/data_splitting.py +30 -0
  5. autoemulate/datasets.py +48 -0
  6. autoemulate/emulators/__init__.py +27 -0
  7. autoemulate/emulators/gaussian_process.py +129 -0
  8. autoemulate/emulators/gaussian_process_mogp.py +90 -0
  9. autoemulate/emulators/gradient_boosting.py +138 -0
  10. autoemulate/emulators/light_gbm.py +144 -0
  11. autoemulate/emulators/neural_net_sk.py +163 -0
  12. autoemulate/emulators/neural_net_torch.py +192 -0
  13. autoemulate/emulators/neural_networks/__init__.py +2 -0
  14. autoemulate/emulators/neural_networks/base.py +36 -0
  15. autoemulate/emulators/neural_networks/get_module.py +20 -0
  16. autoemulate/emulators/neural_networks/mlp.py +72 -0
  17. autoemulate/emulators/neural_networks/rbf.py +346 -0
  18. autoemulate/emulators/polynomials.py +96 -0
  19. autoemulate/emulators/random_forest.py +157 -0
  20. autoemulate/emulators/rbf.py +152 -0
  21. autoemulate/emulators/support_vector_machines.py +168 -0
  22. autoemulate/experimental_design.py +91 -0
  23. autoemulate/hyperparam_searching.py +174 -0
  24. autoemulate/logging_config.py +75 -0
  25. autoemulate/metrics.py +36 -0
  26. autoemulate/model_processing.py +148 -0
  27. autoemulate/plotting.py +340 -0
  28. autoemulate/printing.py +156 -0
  29. autoemulate/save.py +107 -0
  30. autoemulate/simulations/__init__.py +0 -0
  31. autoemulate/simulations/epidemic.py +55 -0
  32. autoemulate/simulations/projectile.py +223 -0
  33. autoemulate/utils.py +473 -0
  34. autoemulate-0.1.0.dist-info/LICENSE +21 -0
  35. autoemulate-0.1.0.dist-info/METADATA +115 -0
  36. autoemulate-0.1.0.dist-info/RECORD +37 -0
  37. autoemulate-0.1.0.dist-info/WHEEL +4 -0
File without changes
autoemulate/compare.py ADDED
@@ -0,0 +1,503 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ import pandas as pd
4
+ from sklearn.base import BaseEstimator
5
+ from sklearn.decomposition import PCA
6
+ from sklearn.metrics import make_scorer
7
+ from sklearn.model_selection import cross_validate
8
+ from sklearn.model_selection import KFold
9
+ from sklearn.model_selection import PredefinedSplit
10
+ from sklearn.model_selection import train_test_split
11
+ from sklearn.pipeline import Pipeline
12
+ from sklearn.preprocessing import StandardScaler
13
+ from sklearn.utils.validation import check_is_fitted
14
+ from sklearn.utils.validation import check_X_y
15
+ from tqdm.autonotebook import tqdm
16
+
17
+ from autoemulate.cross_validate import _run_cv
18
+ from autoemulate.cross_validate import _update_scores_df
19
+ from autoemulate.data_splitting import _split_data
20
+ from autoemulate.emulators import MODEL_REGISTRY
21
+ from autoemulate.hyperparam_searching import _optimize_params
22
+ from autoemulate.logging_config import _configure_logging
23
+ from autoemulate.metrics import METRIC_REGISTRY
24
+ from autoemulate.model_processing import _get_and_process_models
25
+ from autoemulate.plotting import _plot_model
26
+ from autoemulate.plotting import _plot_results
27
+ from autoemulate.printing import _print_cv_results
28
+ from autoemulate.printing import _print_model_names
29
+ from autoemulate.printing import _print_setup
30
+ from autoemulate.save import ModelSerialiser
31
+ from autoemulate.utils import _get_full_model_name
32
+ from autoemulate.utils import _get_model_names_dict
33
+ from autoemulate.utils import _redirect_warnings
34
+ from autoemulate.utils import get_mean_scores
35
+ from autoemulate.utils import get_model_name
36
+ from autoemulate.utils import get_short_model_name
37
+
38
+
39
+ class AutoEmulate:
40
+ """
41
+ The AutoEmulate class is the main class of the AutoEmulate package. It is used to set up and compare
42
+ different emulator models on a given dataset. It can also be used to save and load models, and to
43
+ print and plot the results of the comparison.
44
+ """
45
+
46
+ def __init__(self):
47
+ """Initializes an AutoEmulate object."""
48
+ self.X = None
49
+ self.y = None
50
+ self.is_set_up = False
51
+
52
+ def setup(
53
+ self,
54
+ X,
55
+ y,
56
+ param_search=False,
57
+ param_search_type="random",
58
+ param_search_iters=20,
59
+ test_set_size=0.2,
60
+ scale=True,
61
+ scaler=StandardScaler(),
62
+ reduce_dim=False,
63
+ dim_reducer=PCA(),
64
+ cross_validator=KFold(n_splits=5, shuffle=True),
65
+ n_jobs=None,
66
+ model_subset=None,
67
+ verbose=0,
68
+ log_to_file=False,
69
+ ):
70
+ """Sets up the automatic emulation.
71
+
72
+ Parameters
73
+ ----------
74
+ X : array-like, shape (n_samples, n_features)
75
+ Simulation input.
76
+ y : array-like, shape (n_samples, n_outputs)
77
+ Simulation output.
78
+ param_search : bool
79
+ Whether to perform hyperparameter search over predifined parameter grids.
80
+ param_search_type : str
81
+ Type of hyperparameter search to perform. Can be "grid", "random", or "bayes".
82
+ param_search_iters : int
83
+ Number of parameter settings that are sampled. Only used if
84
+ param_search=True and param_search_type="random".
85
+ scale : bool, default=True
86
+ Whether to scale the data before fitting the models using a scaler.
87
+ scaler : sklearn.preprocessing.StandardScaler
88
+ Scaler to use. Defaults to StandardScaler. Can be any sklearn scaler.
89
+ reduce_dim : bool, default=False
90
+ Whether to reduce the dimensionality of the data before fitting the models.
91
+ dim_reducer : sklearn.decomposition object
92
+ Dimensionality reduction method to use. Can be any method in `sklearn.decomposition`
93
+ with an `n_components` parameter. Defaults to PCA. Specify n_components like so:
94
+ `dim_reducer=PCA(n_components=2)` for choosing 2 principal components, or
95
+ `dim_reducer=PCA(n_components=0.95)` for choosing the number of components that
96
+ explain 95% of the variance. Other methods can have slightly different n_components
97
+ parameter inputs, see the sklearn documentation for more details. Dimension reduction
98
+ is always performed after scaling.
99
+ cross_validator : sklearn.model_selection object
100
+ Cross-validation strategy to use. Defaults to KFold with 5 splits and shuffle=True.
101
+ Can be any object in `sklearn.model_selection` that generates train/test indices.
102
+ n_jobs : int
103
+ Number of jobs to run in parallel. `None` means 1, `-1` means using all processors.
104
+ model_subset : list
105
+ List of models to use. If None, uses all models in MODEL_REGISTRY.
106
+ verbose : int
107
+ Verbosity level. Can be 0, 1, or 2.
108
+ log_to_file : bool
109
+ Whether to log to file.
110
+ """
111
+ self.X, self.y = self._check_input(X, y)
112
+ self.train_idxs, self.test_idxs = _split_data(
113
+ self.X, test_size=test_set_size, random_state=42
114
+ )
115
+ self.model_names = _get_model_names_dict(MODEL_REGISTRY, model_subset)
116
+ self.models = _get_and_process_models(
117
+ MODEL_REGISTRY,
118
+ model_subset=list(self.model_names.keys()),
119
+ y=self.y,
120
+ scale=scale,
121
+ scaler=scaler,
122
+ reduce_dim=reduce_dim,
123
+ dim_reducer=dim_reducer,
124
+ )
125
+ self.metrics = self._get_metrics(METRIC_REGISTRY)
126
+ self.cross_validator = cross_validator
127
+ self.param_search = param_search
128
+ self.search_type = param_search_type
129
+ self.param_search_iters = param_search_iters
130
+ self.scale = scale
131
+ self.scaler = scaler
132
+ self.n_jobs = n_jobs
133
+ self.logger = _configure_logging(log_to_file, verbose)
134
+ self.is_set_up = True
135
+ self.dim_reducer = dim_reducer
136
+ self.reduce_dim = reduce_dim
137
+ self.cv_results = {}
138
+
139
+ self.print_setup()
140
+
141
+ def _check_input(self, X, y):
142
+ """Checks and possibly converts the input data.
143
+
144
+ Parameters
145
+ ----------
146
+ X : array-like, shape (n_samples, n_features)
147
+ Simulation input.
148
+ y : array-like, shape (n_samples, n_outputs)
149
+ Simulation output.
150
+
151
+ Returns
152
+ -------
153
+ X_converted : array-like, shape (n_samples, n_features)
154
+ Simulation input.
155
+ y_converted : array-like, shape (n_samples, n_outputs)
156
+ Simulation output.
157
+ """
158
+ X, y = check_X_y(X, y, multi_output=True, y_numeric=True, dtype="float32")
159
+ y = y.astype("float32") # needed for pytorch models
160
+ return X, y
161
+
162
+ def _get_metrics(self, METRIC_REGISTRY):
163
+ """
164
+ Get metrics from REGISTRY
165
+
166
+ Parameters
167
+ ----------
168
+ METRIC_REGISTRY : dict
169
+ Registry of metrics.
170
+
171
+ Returns
172
+ -------
173
+ List[Callable]
174
+ List of metric functions.
175
+ """
176
+ return [metric for metric in METRIC_REGISTRY.values()]
177
+
178
+ def compare(self):
179
+ """Compares the emulator models on the data. self.setup() must be run first.
180
+
181
+ Returns
182
+ -------
183
+ scores_df : pandas.DataFrame
184
+ Dataframe containing the scores for each model, metric and fold.
185
+ """
186
+ if not self.is_set_up:
187
+ raise RuntimeError("Must run setup() before compare()")
188
+
189
+ # Freshly initialise scores dataframe when running compare()
190
+ self.scores_df = pd.DataFrame(
191
+ columns=["model", "short", "metric", "fold", "score"]
192
+ ).astype(
193
+ {
194
+ "model": "object",
195
+ "short": "object",
196
+ "metric": "object",
197
+ "fold": "int64",
198
+ "score": "float64",
199
+ }
200
+ )
201
+
202
+ if self.param_search:
203
+ pb_text = "Optimising and cross-validating"
204
+ else:
205
+ pb_text = "Cross-validating"
206
+
207
+ with tqdm(total=len(self.models), desc="Initializing") as pbar:
208
+ for i, model in enumerate(self.models):
209
+ model_name = get_model_name(model)
210
+ pbar.set_description(f"{pb_text} {model_name}")
211
+
212
+ with _redirect_warnings(self.logger):
213
+ try:
214
+ # hyperparameter search
215
+ if self.param_search:
216
+ self.models[i] = _optimize_params(
217
+ X=self.X[self.train_idxs],
218
+ y=self.y[self.train_idxs],
219
+ cv=self.cross_validator,
220
+ model=model,
221
+ search_type=self.search_type,
222
+ niter=self.param_search_iters,
223
+ param_space=None,
224
+ n_jobs=self.n_jobs,
225
+ logger=self.logger,
226
+ )
227
+
228
+ # run cross validation
229
+ fitted_model, cv_results = _run_cv(
230
+ X=self.X[self.train_idxs],
231
+ y=self.y[self.train_idxs],
232
+ cv=self.cross_validator,
233
+ model=model,
234
+ metrics=self.metrics,
235
+ n_jobs=self.n_jobs,
236
+ logger=self.logger,
237
+ )
238
+ except Exception:
239
+ self.logger.exception(
240
+ f"Error cross-validating model {model_name}"
241
+ )
242
+ continue
243
+ finally:
244
+ pbar.update(1)
245
+
246
+ self.models[i] = fitted_model
247
+ self.cv_results[model_name] = cv_results
248
+
249
+ # update scores dataframe
250
+ self.scores_df = _update_scores_df(
251
+ self.scores_df,
252
+ model_name,
253
+ self.cv_results[model_name],
254
+ )
255
+
256
+ # get best model
257
+ best_model_name, self.best_model = self.get_model(
258
+ rank=1, metric="r2", name=True
259
+ )
260
+
261
+ return self.best_model
262
+
263
+ def get_model(self, rank=1, metric="r2", name=False):
264
+ """Get a fitted model based on it's rank in the comparison.
265
+
266
+ Parameters
267
+ ----------
268
+ rank : int
269
+ Rank of the model to return. Defaults to 1, which is the best model, 2 is the second best, etc.
270
+ metric : str
271
+ Metric to use for determining the best model.
272
+ name : bool
273
+ If True, returns tuple of model name and model. If False, returns only the model.
274
+
275
+ Returns
276
+ -------
277
+ model : object
278
+ Model fitted on full data.
279
+ """
280
+
281
+ if not hasattr(self, "scores_df"):
282
+ raise RuntimeError("Must run compare() before get_model()")
283
+
284
+ # get average scores across folds
285
+ means = get_mean_scores(self.scores_df, metric)
286
+ # get model by rank
287
+ if (rank > len(means)) or (rank < 1):
288
+ raise RuntimeError(f"Rank must be >= 1 and <= {len(means)}")
289
+ chosen_model_name = means.iloc[rank - 1]["model"]
290
+
291
+ # get best model:
292
+ for model in self.models:
293
+ if get_model_name(model) == chosen_model_name:
294
+ chosen_model = model
295
+ break
296
+
297
+ # check whether the model is fitted
298
+ check_is_fitted(chosen_model)
299
+
300
+ if name:
301
+ return chosen_model_name, chosen_model
302
+ return chosen_model
303
+
304
+ def refit_model(self, model):
305
+ """Refits a model on the full data.
306
+
307
+ Parameters
308
+ ----------
309
+ model : object
310
+ Usually a fitted model.
311
+
312
+ Returns
313
+ -------
314
+ model : object
315
+ Refitted model.
316
+ """
317
+ if not hasattr(self, "X"):
318
+ raise RuntimeError("Must run setup() before refit_model()")
319
+
320
+ model.fit(self.X, self.y)
321
+ return model
322
+
323
+ def refit_models(self):
324
+ """(Re-) fits all models on the full data.
325
+
326
+ Returns
327
+ -------
328
+ models : dict
329
+ dict with refitted models.
330
+ """
331
+ if not hasattr(self, "X"):
332
+ raise RuntimeError("Must run setup() before refit_models()")
333
+ for i in range(len(self.models)):
334
+ self.models[i] = self.refit_model(self.models[i])
335
+ return self.models
336
+
337
+ def save_model(self, model=None, path=None):
338
+ """Saves model to disk.
339
+
340
+ Parameters
341
+ ----------
342
+ model : object, optional
343
+ Model to save. If None, saves the best model.
344
+ If "all", saves all models.
345
+ path : str
346
+ Path to save the model.
347
+ """
348
+ if not hasattr(self, "best_model"):
349
+ raise RuntimeError("Must run compare() before save_model()")
350
+ serialiser = ModelSerialiser()
351
+
352
+ if model is None or not isinstance(model, (Pipeline, BaseEstimator)):
353
+ raise ValueError(
354
+ "Model must be provided and should be a scikit-learn pipeline or model"
355
+ )
356
+ serialiser._save_model(model, path)
357
+
358
+ def save_models(self, path=None):
359
+ """Saves all models to disk.
360
+
361
+ Parameters
362
+ ----------
363
+ path : str
364
+ Directory to save the models.
365
+ If None, saves to the current working directory.
366
+ """
367
+ if not hasattr(self, "best_model"):
368
+ raise RuntimeError("Must run compare() before save_models()")
369
+ serialiser = ModelSerialiser()
370
+ serialiser._save_models(self.models, path)
371
+
372
+ def load_model(self, path=None):
373
+ """Loads a model from disk."""
374
+ serialiser = ModelSerialiser()
375
+ if path is None:
376
+ raise ValueError("Filepath must be provided")
377
+
378
+ return serialiser._load_model(path)
379
+
380
+ def print_model_names(self):
381
+ """Print available models"""
382
+ _print_model_names(self)
383
+
384
+ def print_setup(self):
385
+ """Print the setup of the AutoEmulate object."""
386
+ _print_setup(self)
387
+
388
+ def print_results(self, model=None, sort_by="r2"):
389
+ """Print cv results.
390
+
391
+ Parameters
392
+ ----------
393
+ model : str, optional
394
+ The name of the model to print. If None, the best fold from each model will be printed.
395
+ If a model name is provided, the scores for that model across all folds will be printed.
396
+ sort_by : str, optional
397
+ The metric to sort by. Default is "r2", can also be "rmse".
398
+ """
399
+ model_name = (
400
+ _get_full_model_name(model, self.model_names) if model is not None else None
401
+ )
402
+ _print_cv_results(
403
+ self.models,
404
+ self.scores_df,
405
+ model_name=model_name,
406
+ sort_by=sort_by,
407
+ )
408
+
409
+ def plot_results(
410
+ self,
411
+ model=None,
412
+ plot="standard",
413
+ n_cols=3,
414
+ figsize=None,
415
+ output_index=0,
416
+ ):
417
+ """Plots the results of the cross-validation.
418
+
419
+ Parameters
420
+ ----------
421
+ model : str
422
+ Name of the model to plot. If None, plots best folds of each models.
423
+ If a model name is specified, plots all folds of that model.
424
+ plot_type : str, optional
425
+ The type of plot to draw:
426
+ “standard” draws the observed values (y-axis) vs. the predicted values (x-axis) (default).
427
+ “residual” draws the residuals, i.e. difference between observed and predicted values, (y-axis) vs. the predicted values (x-axis).
428
+ n_cols : int
429
+ Number of columns in the plot grid.
430
+ figsize : tuple, optional
431
+ Overrides the default figure size.
432
+ output_index : int
433
+ Index of the output to plot. Default is 0.
434
+ """
435
+ model_name = (
436
+ _get_full_model_name(model, self.model_names) if model is not None else None
437
+ )
438
+ _plot_results(
439
+ self.cv_results,
440
+ self.X,
441
+ self.y,
442
+ model_name=model_name,
443
+ n_cols=n_cols,
444
+ plot=plot,
445
+ figsize=figsize,
446
+ output_index=output_index,
447
+ )
448
+
449
+ def evaluate_model(self, model=None):
450
+ """
451
+ Evaluates the model on the hold-out set.
452
+
453
+ Parameters
454
+ ----------
455
+ model : object
456
+ Fitted model.
457
+
458
+ Returns
459
+ -------
460
+ scores_df : pandas.DataFrame
461
+ Dataframe containing the model scores on the test set.
462
+ """
463
+ if model is None:
464
+ raise ValueError("Model must be provided")
465
+
466
+ y_pred = model.predict(self.X[self.test_idxs])
467
+ scores = {}
468
+ for metric in self.metrics:
469
+ scores[metric.__name__] = metric(self.y[self.test_idxs], y_pred)
470
+
471
+ scores_df = pd.concat(
472
+ [
473
+ pd.DataFrame({"model": [get_model_name(model)]}),
474
+ pd.DataFrame({"short": [get_short_model_name(model)]}),
475
+ pd.DataFrame(scores, index=[0]),
476
+ ],
477
+ axis=1,
478
+ ).round(3)
479
+
480
+ return scores_df
481
+
482
+ def plot_model(self, model, plot="standard", n_cols=2, figsize=None):
483
+ """Plots the model predictions vs. the true values.
484
+
485
+ Parameters
486
+ ----------
487
+ model : object
488
+ Fitted model.
489
+ plot : str, optional
490
+ The type of plot to draw:
491
+ “standard” draws the observed values (y-axis) vs. the predicted values (x-axis) (default).
492
+ “residual” draws the residuals, i.e. difference between observed and predicted values, (y-axis) vs. the predicted values (x-axis).
493
+ n_cols : int, optional
494
+ Number of columns in the plot grid for multi-output. Default is 2.
495
+ """
496
+ _plot_model(
497
+ model,
498
+ self.X[self.test_idxs],
499
+ self.y[self.test_idxs],
500
+ plot,
501
+ n_cols,
502
+ figsize,
503
+ )
@@ -0,0 +1,97 @@
1
+ import re
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from sklearn.metrics import make_scorer
6
+ from sklearn.model_selection import cross_validate
7
+ from sklearn.model_selection import PredefinedSplit
8
+ from sklearn.model_selection import train_test_split
9
+
10
+ from autoemulate.utils import get_model_name
11
+
12
+
13
+ def _run_cv(X, y, cv, model, metrics, n_jobs, logger):
14
+ """Runs cross-validation on a model.
15
+
16
+ Parameters
17
+ ----------
18
+ X : array-like
19
+ Features.
20
+ y : array-like
21
+ Target variable.
22
+ cv : int, cross-validation generator or an iterable, default=None
23
+ Determines the cross-validation splitting strategy.
24
+ model : scikit-learn model
25
+ Model to cross-validate.
26
+ metrics : list
27
+ List of metrics to use for cross-validation.
28
+ n_jobs : int
29
+ Number of jobs to run in parallel.
30
+ logger : logging.Logger
31
+ Logger object.
32
+
33
+ Returns
34
+ -------
35
+ fitted_model : scikit-learn model
36
+ Fitted model.
37
+ cv_results : dict
38
+ Results of the cross-validation.
39
+ """
40
+ # The metrics we want to use for cross-validation
41
+ scorers = {metric.__name__: make_scorer(metric) for metric in metrics}
42
+
43
+ logger.info(f"Cross-validating {get_model_name(model)}...")
44
+ logger.info(f"Parameters: {model.named_steps['model'].get_params()}")
45
+
46
+ cv_results = None
47
+ try:
48
+ cv_results = cross_validate(
49
+ model,
50
+ X,
51
+ y,
52
+ cv=cv,
53
+ scoring=scorers,
54
+ n_jobs=n_jobs,
55
+ return_estimator=True,
56
+ return_indices=True,
57
+ )
58
+ except Exception as e:
59
+ logger.exception(f"Failed to cross-validate {get_model_name(model)}")
60
+
61
+ # refit the model on the whole dataset
62
+ fitted_model = model.fit(X, y)
63
+
64
+ return fitted_model, cv_results
65
+
66
+
67
+ def _update_scores_df(scores_df, model_name, cv_results):
68
+ """Updates the scores dataframe with the results of the cross-validation.
69
+
70
+ Parameters
71
+ ----------
72
+ scores_df : pandas.DataFrame
73
+ DataFrame with columns "model", "metric", "fold", "score".
74
+ model_name : str
75
+ Name of the model.
76
+ cv_results : dict
77
+ Results of the cross-validation.
78
+
79
+ Returns
80
+ -------
81
+ None
82
+ Modifies the self.scores_df DataFrame in-place.
83
+
84
+ """
85
+ # Gather scores from each metric
86
+ # Initialise scores dataframe
87
+ for key in cv_results.keys():
88
+ if key.startswith("test_"):
89
+ for fold, score in enumerate(cv_results[key]):
90
+ scores_df.loc[len(scores_df.index)] = {
91
+ "model": model_name,
92
+ "short": "".join(re.findall(r"[A-Z]", model_name)).lower(),
93
+ "metric": key.split("test_", 1)[1],
94
+ "fold": fold,
95
+ "score": score,
96
+ }
97
+ return scores_df
@@ -0,0 +1,30 @@
1
+ import numpy as np
2
+ from sklearn.model_selection import train_test_split
3
+
4
+
5
+ def _split_data(X, test_size=0.2, random_state=None):
6
+ """Splits the data into training and testing sets.
7
+
8
+ Parameters
9
+ ----------
10
+ X : array-like, shape (n_samples, n_features)
11
+ Simulation input.
12
+ test_size : float, default=0.2
13
+ Proportion of the dataset to include in the test split.
14
+ random_state : int, RandomState instance or None, default=None
15
+ Controls the shuffling applied to the data before applying the split.
16
+
17
+ Returns
18
+ -------
19
+ train_idx : array-like
20
+ Indices of the training set.
21
+ test_idx : array-like
22
+ Indices of the testing set.
23
+ """
24
+
25
+ idxs = np.arange(X.shape[0])
26
+ train_idxs, test_idxs = train_test_split(
27
+ idxs, test_size=test_size, random_state=random_state
28
+ )
29
+
30
+ return train_idxs, test_idxs
@@ -0,0 +1,48 @@
1
+ from pathlib import Path
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from sklearn.model_selection import train_test_split
6
+
7
+ data_dir = Path(__file__).parent.parent / "data"
8
+
9
+
10
+ def fetch_data(dataset, split=False, test_size=0.2, random_state=42):
11
+ """
12
+ Fetch a dataset by name.
13
+
14
+ Parameters
15
+ ----------
16
+ dataset : str
17
+ Dataset to load. Can be any of the following strings:
18
+
19
+ - **cardiac1**: ionic atrial cell model data from LH sampling.
20
+ - **cardiac2**: isotonic contraction ventricular cell model, no LH sampling.
21
+ - **cardiac3**: CircAdapt: four-chamber pressure and volume CircAdapt ODE model from LH sampling.
22
+ - **cardiac4**: four chamber: 3D-0D four-chamber electromechanics model to predict pressure and volume biomarkers for cardiac function.
23
+ - **cardiac5**: passive mechanics: inflated volumes and mean atrial and ventricular fiber strains for a passive inflation.
24
+ - **cardiac6**: tissue electrophysiology: predict total atrial and ventricular activation times with an Eikonal model.
25
+ - **climate1**: GENIE model: predict climate variables SAT, ACC, VEGC, SOILC, MAXPMOC, OCN_O2, fCaCO3, SIAREA_S.
26
+ - **engineering1**: Cantilever truss simulation.
27
+ split : bool, optional
28
+ Whether to split the data into training and testing sets. Default is False.
29
+ test_size : float, optional
30
+ The proportion of the dataset to include in the test split. Default is 0.2.
31
+ random_state : int, optional
32
+ Controls the shuffling applied to the data before applying the split. Default is 42.
33
+
34
+ Returns
35
+ -------
36
+ X : array-like
37
+ Simulation parameters / inputs.
38
+ y : array-like
39
+ Simulation outputs.
40
+ """
41
+ data_dir_dataset = data_dir / dataset / "processed"
42
+ X = pd.read_csv(data_dir_dataset / "parameters.csv").to_numpy()
43
+ y = pd.read_csv(data_dir_dataset / "outputs.csv").to_numpy()
44
+
45
+ if split:
46
+ return train_test_split(X, y, test_size=test_size, random_state=random_state)
47
+ else:
48
+ return X, y