Skip to content

Commit 753cc50

Browse files
committed
Alter saving of QRF model to use clize, rather than saving within the plugin.
1 parent 9f7e1c8 commit 753cc50

9 files changed

Lines changed: 66 additions & 92 deletions

improver/calibration/load_and_train_quantile_regression_random_forest.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ def __init__(
4343
random_state: Optional[int] = None,
4444
transformation: Optional[str] = None,
4545
pre_transform_addition: float = 0,
46-
compression: int = 5,
4746
):
4847
"""Initialise the LoadAndTrainQRF plugin."""
4948
self.feature_config = feature_config
@@ -59,7 +58,6 @@ def __init__(
5958
self.random_state = random_state
6059
self.transformation = transformation
6160
self.pre_transform_addition = pre_transform_addition
62-
self.compression = compression
6361
self.quantile_forest_installed = quantile_forest_package_available()
6462

6563
def _split_cubes_and_parquet_files(
@@ -355,7 +353,7 @@ def process(
355353
forecast_df = self._add_features_to_df(forecast_df, cube_inputs)
356354
forecast_df, truth_df = self.filter_bad_sites(forecast_df, truth_df)
357355

358-
TrainQuantileRegressionRandomForests(
356+
result = TrainQuantileRegressionRandomForests(
359357
target_name=self.target_cf_name,
360358
feature_config=self.feature_config,
361359
n_estimators=self.n_estimators,
@@ -364,6 +362,6 @@ def process(
364362
random_state=self.random_state,
365363
transformation=self.transformation,
366364
pre_transform_addition=self.pre_transform_addition,
367-
compression=self.compression,
368365
model_output=model_output,
369366
)(forecast_df, truth_df)
367+
return result

improver/calibration/quantile_regression_random_forest.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from typing import Optional
88

9-
import joblib
109
import numpy as np
1110
import pandas as pd
1211

@@ -206,8 +205,6 @@ def __init__(
206205
random_state: Optional[int] = None,
207206
transformation: Optional[str] = None,
208207
pre_transform_addition: np.float32 = 0,
209-
compression: int = 5,
210-
model_output: Optional[str] = None,
211208
**kwargs,
212209
) -> None:
213210
"""Initialise the plugin.
@@ -246,10 +243,6 @@ def __init__(
246243
Transformation to be applied to the data before fitting.
247244
pre_transform_addition (float):
248245
Value to be added before transformation.
249-
compression (int):
250-
Compression level for saving the model.
251-
model_output (str):
252-
Full path including model file name that will store the pickled model.
253246
kwargs:
254247
Additional keyword arguments for the quantile regression model.
255248
@@ -264,8 +257,6 @@ def __init__(
264257
self.transformation = transformation
265258
_check_valid_transformation(self.transformation)
266259
self.pre_transform_addition = pre_transform_addition
267-
self.compression = compression
268-
self.output = model_output
269260
self.kwargs = kwargs
270261
self.expected_coordinate_order = ["forecast_reference_time", "forecast_period"]
271262

@@ -353,9 +344,7 @@ def process(
353344
target_values = combined_df["ob_value"].values
354345

355346
# Fit the quantile regression model
356-
qrf_model = self.fit_qrf(feature_values, target_values)
357-
358-
joblib.dump(qrf_model, self.output, compress=self.compression)
347+
return self.fit_qrf(feature_values, target_values)
359348

360349

361350
class ApplyQuantileRegressionRandomForests(PostProcessingPlugin):

improver/cli/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ def with_output(
312312
pass_through_output=False,
313313
compression_level=1,
314314
least_significant_digit: int = None,
315+
output_file_type="netCDF",
315316
**kwargs,
316317
):
317318
"""Add `output` keyword only argument.
@@ -346,15 +347,20 @@ def with_output(
346347
Returns:
347348
Result of calling `wrapped` or None if `output` is given.
348349
"""
350+
import joblib
351+
349352
from improver.utilities.save import save_netcdf
350353

351354
result = wrapped(*args, **kwargs)
352355

353-
if output and result:
356+
if output and output.endswith(".nc"):
354357
save_netcdf(result, output, compression_level, least_significant_digit)
355358
if pass_through_output:
356359
return ObjectAsStr(result, output)
357360
return
361+
elif output and output.endswith((".pickle", ".pkl")):
362+
joblib.dump(result, output, compress=compression_level)
363+
return
358364
return result
359365

360366

improver/cli/train_quantile_regression_random_forest.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010

1111
@cli.clizefy
12+
@cli.with_output
1213
def process(
1314
*file_paths: cli.inputpath,
1415
feature_config: cli.inputjson,
@@ -24,8 +25,6 @@ def process(
2425
random_state: int = None,
2526
transformation: str = None,
2627
pre_transform_addition: float = 0,
27-
compression: int = 5,
28-
output: str = None,
2928
):
3029
"""Training a model using Quantile Regression Random Forest.
3130
@@ -92,10 +91,6 @@ def process(
9291
Transformation to be applied to the data before fitting.
9392
pre_transform_addition (float):
9493
Value to be added before transformation.
95-
compression (int):
96-
Compression level for saving the model.
97-
output (str):
98-
Full path including model file name that will store the pickled model.
9994
Returns:
10095
None:
10196
The function creates a pickle file.
@@ -119,9 +114,7 @@ def process(
119114
random_state=random_state,
120115
transformation=transformation,
121116
pre_transform_addition=pre_transform_addition,
122-
compression=compression,
123117
)(
124118
file_paths,
125-
model_output=output,
126119
)
127120
return result

improver_tests/acceptance/test_train_quantile_regression_random_forest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_basic(
5959
"5",
6060
"--random-state",
6161
"42",
62-
"--compression",
62+
"--compression-level",
6363
"5",
6464
"--output",
6565
output_path,

improver_tests/calibration/quantile_regression_random_forests_calibration/test_load_and_apply_quantile_regression_random_forest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ def test_load_and_apply_qrf(
7878
feature_config = {"wind_speed_at_10m": ["mean", "std", "latitude", "longitude"]}
7979

8080
model_output = _run_train_qrf(
81-
tmp_path,
8281
feature_config,
8382
n_estimators,
8483
max_depth,
@@ -98,6 +97,7 @@ def test_load_and_apply_qrf(
9897
],
9998
realization_data=[2, 6, 10],
10099
truth_data=[4.2, 6.2, 4.1, 5.1],
100+
tmp_path=tmp_path,
101101
)
102102

103103
frt = "20170103T0000Z"
@@ -182,7 +182,6 @@ def test_unexpected(
182182
quantiles = [0.5]
183183

184184
model_output = _run_train_qrf(
185-
tmp_path,
186185
feature_config,
187186
n_estimators,
188187
max_depth,
@@ -202,6 +201,7 @@ def test_unexpected(
202201
],
203202
realization_data=[2, 6, 10],
204203
truth_data=[4.2, 6.2, 4.1, 5.1],
204+
tmp_path=tmp_path,
205205
)
206206

207207
frt = "20170103T0000Z"

improver_tests/calibration/quantile_regression_random_forests_calibration/test_load_and_train_quantile_regression_random_forest.py

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"""Unit tests for the LoadAndTrainQRF plugin."""
66

77
import iris
8-
import joblib
98
import numpy as np
109
import pandas as pd
1110
import pytest
@@ -380,10 +379,6 @@ def test_load_and_train_qrf(
380379
truth_path = truth_creation(tmp_path)
381380
file_paths = [forecast_path, truth_path]
382381

383-
model_output_dir = tmp_path / "train_qrf"
384-
model_output_dir.mkdir(parents=True)
385-
model_output = str(model_output_dir / "qrf_model.pkl")
386-
387382
if include_static:
388383
ancil_path = _create_ancil_file(tmp_path, sorted(list(set(wmo_ids))))
389384
file_paths.append(ancil_path)
@@ -407,9 +402,7 @@ def test_load_and_train_qrf(
407402
transformation="log",
408403
pre_transform_addition=1,
409404
)
410-
plugin(file_paths, model_output=model_output)
411-
412-
qrf_model = joblib.load(model_output)
405+
qrf_model = plugin(file_paths)
413406

414407
assert qrf_model.n_estimators == n_estimators
415408
assert qrf_model.max_depth == max_depth
@@ -446,10 +439,6 @@ def test_load_and_train_qrf_no_paths(tmp_path, make_files):
446439
for file_path in file_paths:
447440
(tmp_path / file_path).mkdir(parents=True, exist_ok=True)
448441

449-
model_output_dir = tmp_path / "train_qrf"
450-
model_output_dir.mkdir(parents=True)
451-
model_output = str(model_output_dir / "qrf_model.pkl")
452-
453442
plugin = LoadAndTrainQRF(
454443
experiment="latestblend",
455444
feature_config=feature_config,
@@ -464,11 +453,9 @@ def test_load_and_train_qrf_no_paths(tmp_path, make_files):
464453
transformation="log",
465454
pre_transform_addition=1,
466455
)
467-
result = plugin(file_paths, model_output=model_output)
456+
result = plugin(file_paths)
468457
# Expecting None since no valid paths are provided
469458
assert result is None
470-
# Check if the model output file is not created
471-
assert not (model_output_dir / "qrf_model.pkl").exists()
472459

473460

474461
@pytest.mark.parametrize(
@@ -491,10 +478,6 @@ def test_load_and_train_qrf_mismatches(tmp_path, cycletime, forecast_periods):
491478
tmp_path / "partition" / "truth_table/",
492479
]
493480

494-
model_output_dir = tmp_path / "train_qrf"
495-
model_output_dir.mkdir(parents=True)
496-
model_output = str(model_output_dir / "qrf_model.pkl")
497-
498481
plugin = LoadAndTrainQRF(
499482
experiment="latestblend",
500483
feature_config=feature_config,
@@ -509,11 +492,9 @@ def test_load_and_train_qrf_mismatches(tmp_path, cycletime, forecast_periods):
509492
transformation="log",
510493
pre_transform_addition=1,
511494
)
512-
result = plugin(file_paths, model_output=model_output)
495+
result = plugin(file_paths)
513496
# Expecting None since no valid paths are provided
514497
assert result is None
515-
# Check if the model output file is not created
516-
assert not (model_output_dir / "qrf_model.pkl").exists()
517498

518499

519500
@pytest.mark.parametrize(
@@ -581,10 +562,6 @@ def test_unexpected(
581562
truth_path = truth_creation(tmp_path)
582563
file_paths = [forecast_path, truth_path]
583564

584-
model_output_dir = tmp_path / "train_qrf"
585-
model_output_dir.mkdir(parents=True)
586-
model_output = str(model_output_dir / "qrf_model.pkl")
587-
588565
# Create an instance of LoadAndTrainQRF with the required parameters
589566
plugin = LoadAndTrainQRF(
590567
experiment="latestblend",
@@ -603,7 +580,7 @@ def test_unexpected(
603580

604581
if exception == "non_matching_truth":
605582
with pytest.raises(IOError, match="The requested filepath"):
606-
plugin(file_paths, model_output=model_output)
583+
plugin(file_paths)
607584
elif exception == "missing_static_feature":
608585
feature_config = {
609586
"wind_speed_at_10m": ["mean", "std"],
@@ -622,13 +599,13 @@ def test_unexpected(
622599
plugin.process(file_paths=file_paths)
623600
elif exception == "no_percentile_realization":
624601
with pytest.raises(ValueError, match="The forecast parquet file"):
625-
plugin(file_paths, model_output=model_output)
602+
plugin(file_paths)
626603
elif exception == "alternative_forecast_period":
627604
with pytest.raises(ValueError, match="The forecast_periods argument"):
628-
plugin(file_paths, model_output=model_output)
605+
plugin(file_paths)
629606
elif exception == "no_quantile_forest_package":
630607
plugin.quantile_forest_installed = False
631-
result = plugin(file_paths, model_output=model_output)
608+
result = plugin(file_paths)
632609
assert result is None
633610
else:
634611
raise ValueError(f"Unknown exception type: {exception}")

0 commit comments

Comments
 (0)