wavetrainer 0.3.18__tar.gz → 0.3.20__tar.gz

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 (80) hide show
  1. {wavetrainer-0.3.18/wavetrainer.egg-info → wavetrainer-0.3.20}/PKG-INFO +1 -1
  2. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/setup.py +1 -1
  3. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/__init__.py +1 -1
  4. wavetrainer-0.3.20/wavetrainer/drift_mixed_sampler.py +75 -0
  5. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/normaliser/powertransformer_normaliser.py +35 -2
  6. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/trainer.py +16 -0
  7. {wavetrainer-0.3.18 → wavetrainer-0.3.20/wavetrainer.egg-info}/PKG-INFO +1 -1
  8. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer.egg-info/SOURCES.txt +1 -0
  9. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/LICENSE +0 -0
  10. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/MANIFEST.in +0 -0
  11. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/README.md +0 -0
  12. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/requirements.txt +0 -0
  13. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/setup.cfg +0 -0
  14. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/tests/__init__.py +0 -0
  15. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/tests/model/__init__.py +0 -0
  16. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/tests/model/catboost_kwargs_test.py +0 -0
  17. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/tests/trainer_test.py +0 -0
  18. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/calibrator/__init__.py +0 -0
  19. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/calibrator/calibrator.py +0 -0
  20. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/calibrator/calibrator_router.py +0 -0
  21. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/calibrator/conformal_quantile_calibration.py +0 -0
  22. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/calibrator/vennabers_calibrator.py +0 -0
  23. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/create.py +0 -0
  24. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/crps.py +0 -0
  25. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/exceptions.py +0 -0
  26. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/fit.py +0 -0
  27. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/__init__.py +0 -0
  28. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/catboost/__init__.py +0 -0
  29. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/catboost/catboost_classifier_wrap.py +0 -0
  30. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/catboost/catboost_kwargs.py +0 -0
  31. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/catboost/catboost_model.py +0 -0
  32. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/catboost/catboost_regressor_wrap.py +0 -0
  33. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/lightgbm/__init__.py +0 -0
  34. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/lightgbm/lightgbm_model.py +0 -0
  35. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/model.py +0 -0
  36. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/model_router.py +0 -0
  37. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/tabpfn/__init__.py +0 -0
  38. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/tabpfn/tabpfn_model.py +0 -0
  39. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/xgboost/__init__.py +0 -0
  40. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/xgboost/early_stopper.py +0 -0
  41. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/xgboost/xgboost_logger.py +0 -0
  42. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model/xgboost/xgboost_model.py +0 -0
  43. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/model_type.py +0 -0
  44. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/normaliser/__init__.py +0 -0
  45. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/normaliser/combined_normaliser.py +0 -0
  46. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/normaliser/normaliser.py +0 -0
  47. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/params.py +0 -0
  48. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/__init__.py +0 -0
  49. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/base_selector_reducer.py +0 -0
  50. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/combined_reducer.py +0 -0
  51. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/constant_reducer.py +0 -0
  52. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/correlation_reducer.py +0 -0
  53. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/duplicate_reducer.py +0 -0
  54. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/fast_correlation_based_reducer.py +0 -0
  55. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/non_categorical_numeric_columns.py +0 -0
  56. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/nonnumeric_reducer.py +0 -0
  57. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/pca_reducer.py +0 -0
  58. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/reducer.py +0 -0
  59. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/select_by_single_feature_performance_reducer.py +0 -0
  60. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/smart_correlation_reducer.py +0 -0
  61. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/reducer/unseen_reducer.py +0 -0
  62. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/selector/__init__.py +0 -0
  63. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/selector/selector.py +0 -0
  64. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/stratified_brier_score_loss.py +0 -0
  65. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/threshold_callback.py +0 -0
  66. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/__init__.py +0 -0
  67. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/class_weights.py +0 -0
  68. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/combined_weights.py +0 -0
  69. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/exponential_weights.py +0 -0
  70. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/linear_weights.py +0 -0
  71. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/noop_weights.py +0 -0
  72. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/sigmoid_weights.py +0 -0
  73. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/weights.py +0 -0
  74. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/weights/weights_router.py +0 -0
  75. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/windower/__init__.py +0 -0
  76. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer/windower/windower.py +0 -0
  77. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer.egg-info/dependency_links.txt +0 -0
  78. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer.egg-info/not-zip-safe +0 -0
  79. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer.egg-info/requires.txt +0 -0
  80. {wavetrainer-0.3.18 → wavetrainer-0.3.20}/wavetrainer.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wavetrainer
3
- Version: 0.3.18
3
+ Version: 0.3.20
4
4
  Summary: A library for automatically finding the optimal model within feature and hyperparameter space.
5
5
  Home-page: https://github.com/8W9aG/wavetrainer
6
6
  Author: Will Sackfield
@@ -23,7 +23,7 @@ def install_requires() -> typing.List[str]:
23
23
 
24
24
  setup(
25
25
  name='wavetrainer',
26
- version='0.3.18',
26
+ version='0.3.20',
27
27
  description='A library for automatically finding the optimal model within feature and hyperparameter space.',
28
28
  long_description=long_description,
29
29
  long_description_content_type='text/markdown',
@@ -2,5 +2,5 @@
2
2
 
3
3
  from .create import create
4
4
 
5
- __VERSION__ = "0.3.18"
5
+ __VERSION__ = "0.3.20"
6
6
  __all__ = ("create",)
@@ -0,0 +1,75 @@
1
+ """A custom Optuna sampler for dynamic environments."""
2
+
3
+ from typing import Sequence
4
+
5
+ import optuna
6
+
7
+
8
+ class DriftMixedSampler(optuna.samplers.BaseSampler):
9
+ """A custom sampler that interleaves TPE with pure random sampling to combat data drift."""
10
+
11
+ def __init__(self, random_mix_ratio: float = 0.20, seed: int | None = None):
12
+ self._tpe_sampler = optuna.samplers.TPESampler(
13
+ seed=seed, constant_liar=True, multivariate=True
14
+ )
15
+ self._random_sampler = optuna.samplers.RandomSampler(seed=seed)
16
+ self._random_mix_ratio = random_mix_ratio
17
+
18
+ def reseed_rng(self) -> None:
19
+ self._tpe_sampler.reseed_rng()
20
+ self._random_sampler.reseed_rng()
21
+
22
+ def infer_relative_search_space(
23
+ self, study: optuna.Study, trial: optuna.trial.FrozenTrial
24
+ ):
25
+ return self._tpe_sampler.infer_relative_search_space(study, trial)
26
+
27
+ def sample_relative(
28
+ self, study: optuna.Study, trial: optuna.trial.FrozenTrial, search_space
29
+ ):
30
+ if (
31
+ trial.number > 0
32
+ and self._random_mix_ratio > 0
33
+ and trial.number % int(1 / self._random_mix_ratio) == 0
34
+ ):
35
+ return self._random_sampler.sample_relative(study, trial, search_space)
36
+ return self._tpe_sampler.sample_relative(study, trial, search_space)
37
+
38
+ def sample_independent(
39
+ self,
40
+ study: optuna.Study,
41
+ trial: optuna.trial.FrozenTrial,
42
+ param_name: str,
43
+ param_distribution,
44
+ ):
45
+ if (
46
+ trial.number > 0
47
+ and self._random_mix_ratio > 0
48
+ and trial.number % int(1 / self._random_mix_ratio) == 0
49
+ ):
50
+ return self._random_sampler.sample_independent(
51
+ study, trial, param_name, param_distribution
52
+ )
53
+ return self._tpe_sampler.sample_independent(
54
+ study, trial, param_name, param_distribution
55
+ )
56
+
57
+ def before_trial(
58
+ self, study: optuna.Study, trial: optuna.trial.FrozenTrial
59
+ ) -> None:
60
+ if hasattr(self._tpe_sampler, "before_trial"):
61
+ self._tpe_sampler.before_trial(study, trial)
62
+ if hasattr(self._random_sampler, "before_trial"):
63
+ self._random_sampler.before_trial(study, trial)
64
+
65
+ def after_trial(
66
+ self,
67
+ study: optuna.Study,
68
+ trial: optuna.trial.FrozenTrial,
69
+ state: optuna.trial.TrialState,
70
+ values: Sequence[float] | None,
71
+ ) -> None:
72
+ if hasattr(self._tpe_sampler, "after_trial"):
73
+ self._tpe_sampler.after_trial(study, trial, state, values)
74
+ if hasattr(self._random_sampler, "after_trial"):
75
+ self._random_sampler.after_trial(study, trial, state, values)
@@ -11,6 +11,7 @@ import numpy as np
11
11
  import optuna
12
12
  import pandas as pd
13
13
  import scipy # type: ignore
14
+ from sklearn.exceptions import InconsistentVersionWarning # type: ignore
14
15
  from sklearn.preprocessing import PowerTransformer # type: ignore
15
16
 
16
17
  from ..exceptions import WavetrainException
@@ -40,7 +41,10 @@ class PowerTransformerNormaliser(Normaliser):
40
41
  pass
41
42
 
42
43
  def load(self, folder: str) -> None:
43
- self._pt = joblib.load(os.path.join(folder, _POWERTRANSFORMER_REDUCER_FILE))
44
+ with warnings.catch_warnings():
45
+ warnings.simplefilter("ignore", category=InconsistentVersionWarning)
46
+ self._pt = joblib.load(os.path.join(folder, _POWERTRANSFORMER_REDUCER_FILE))
47
+
44
48
  with open(
45
49
  os.path.join(folder, _POWERTRANSFORMER_COLUMNS_FILENAME),
46
50
  "r",
@@ -88,6 +92,35 @@ class PowerTransformerNormaliser(Normaliser):
88
92
  neginf=0.0,
89
93
  )
90
94
  except ValueError as exc:
91
- print(exc)
95
+ # --- Diagnostic Check ---
96
+ subset = df[self._pt_cols]
97
+
98
+ print("\n" + "=" * 50)
99
+ print("🚨 DATA VALIDATION ERROR DIAGNOSTIC 🚨")
100
+
101
+ # Check specifically for infinite values
102
+ inf_mask = np.isinf(subset)
103
+ if inf_mask.any().any():
104
+ bad_cols = [col for col in subset.columns if inf_mask[col].any()]
105
+ print(f"-> Found infinities (inf or -inf) in columns: {bad_cols}")
106
+
107
+ for col in bad_cols:
108
+ print(f"\nOffending values in '{col}':")
109
+ # Filter and print only the rows where this specific column has an infinity
110
+ print(subset[col][inf_mask[col]])
111
+ else:
112
+ # Fallback: If it's not strictly 'inf', it's an unusually large number
113
+ print(
114
+ "-> No strict infinities found. Values are likely exceeding float64 capacity."
115
+ )
116
+ print(
117
+ "\nTop 5 largest absolute values by column to help you hunt it down:"
118
+ )
119
+ print(subset.abs().max().sort_values(ascending=False).head(5))
120
+
121
+ print("=" * 50 + "\n")
122
+
123
+ # Raise the exception as usual so the pipeline stops and you can read the logs
92
124
  raise WavetrainException() from exc
125
+
93
126
  return df
@@ -21,6 +21,7 @@ from sklearn.metrics import (accuracy_score, brier_score_loss, log_loss,
21
21
 
22
22
  from .calibrator.calibrator_router import CalibratorRouter
23
23
  from .crps import crps
24
+ from .drift_mixed_sampler import DriftMixedSampler
24
25
  from .exceptions import WavetrainException
25
26
  from .fit import Fit
26
27
  from .model.catboost.catboost_model import CatboostModel
@@ -50,6 +51,7 @@ _IDX_USR_ATTR_KEY = "idx"
50
51
  _DT_COLUMN_KEY = "dt_column"
51
52
  _MAX_FALSE_POSITIVE_REDUCTION_STEPS_KEY = "max_false_positive_reduction_steps"
52
53
  _CORRELATION_CHUNK_SIZE_KEY = "correlation_chunk_size"
54
+ _RANDOM_MIX_RATIO_KEY = "random_mix_ratio"
53
55
  _BAD_OUTPUT = -1000.0
54
56
 
55
57
 
@@ -109,6 +111,7 @@ class Trainer(Fit):
109
111
  insert_nulls: bool = False,
110
112
  use_power_transformer: bool = False,
111
113
  use_correlation_reducer: bool = True,
114
+ random_mix_ratio: float = 0.20,
112
115
  n_jobs: int = 1,
113
116
  ):
114
117
  tqdm.tqdm.pandas()
@@ -168,6 +171,7 @@ class Trainer(Fit):
168
171
  )
169
172
  if correlation_chunk_size is None:
170
173
  correlation_chunk_size = params.get(_CORRELATION_CHUNK_SIZE_KEY)
174
+ random_mix_ratio = params.get(_RANDOM_MIX_RATIO_KEY, 0.20)
171
175
  else:
172
176
  with open(params_file, "w", encoding="utf8") as handle:
173
177
  validation_size_value = None
@@ -200,6 +204,7 @@ class Trainer(Fit):
200
204
  _DT_COLUMN_KEY: dt_column,
201
205
  _MAX_FALSE_POSITIVE_REDUCTION_STEPS_KEY: max_false_positive_reduction_steps,
202
206
  _CORRELATION_CHUNK_SIZE_KEY: correlation_chunk_size,
207
+ _RANDOM_MIX_RATIO_KEY: random_mix_ratio,
203
208
  },
204
209
  handle,
205
210
  )
@@ -217,6 +222,7 @@ class Trainer(Fit):
217
222
  self._insert_nulls = insert_nulls
218
223
  self._use_power_transformer = use_power_transformer
219
224
  self._use_correlation_reducer = use_correlation_reducer
225
+ self._random_mix_ratio = random_mix_ratio
220
226
  self._n_jobs = n_jobs
221
227
  self._cached_reducers = {}
222
228
  self._cached_normalizers = {}
@@ -231,6 +237,12 @@ class Trainer(Fit):
231
237
  if os.path.exists(sampler_file):
232
238
  with open(sampler_file, "rb") as handle:
233
239
  restored_sampler = pickle.load(handle)
240
+
241
+ if restored_sampler is None:
242
+ restored_sampler = DriftMixedSampler(
243
+ random_mix_ratio=self._random_mix_ratio
244
+ )
245
+
234
246
  return optuna.create_study(
235
247
  study_name="wavetrain",
236
248
  storage=storage_name,
@@ -641,6 +653,10 @@ class Trainer(Fit):
641
653
  last_processed_dt = test_idx
642
654
 
643
655
  if did_fit:
656
+ sampler_file = os.path.join(column_dir, _SAMPLER_FILENAME)
657
+ with open(sampler_file, "wb") as handle:
658
+ pickle.dump(study.sampler, handle)
659
+
644
660
  target_names = ["F1", "Brier"]
645
661
  # fig = optuna.visualization.plot_pareto_front(
646
662
  # study, target_names=target_names
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wavetrainer
3
- Version: 0.3.18
3
+ Version: 0.3.20
4
4
  Summary: A library for automatically finding the optimal model within feature and hyperparameter space.
5
5
  Home-page: https://github.com/8W9aG/wavetrainer
6
6
  Author: Will Sackfield
@@ -10,6 +10,7 @@ tests/model/catboost_kwargs_test.py
10
10
  wavetrainer/__init__.py
11
11
  wavetrainer/create.py
12
12
  wavetrainer/crps.py
13
+ wavetrainer/drift_mixed_sampler.py
13
14
  wavetrainer/exceptions.py
14
15
  wavetrainer/fit.py
15
16
  wavetrainer/model_type.py
File without changes
File without changes
File without changes
File without changes