From 85cd07b73fe0fb893099ec39d126b1ea90627f10 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 27 May 2025 20:39:31 +0200 Subject: [PATCH] fix(qav3): properly handle objectives weighting for some metrics MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../freqaimodels/QuickAdapterRegressorV3.py | 32 +++++++++++-------- .../user_data/strategies/QuickAdapterV3.py | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py index 04a6c0c..ec48d55 100644 --- a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py +++ b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py @@ -45,7 +45,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel): https://github.com/sponsors/robcaulk """ - version = "3.7.71" + version = "3.7.72" @cached_property def _optuna_config(self) -> dict: @@ -464,10 +464,10 @@ class QuickAdapterRegressorV3(BaseRegressionModel): metric: str, p_order: float, ) -> np.ndarray: - weights = self.ft_params.get( - "label_weights", [1.0] * normalized_matrix.shape[1] + np_weights = np.array( + self.ft_params.get("label_weights", [1.0] * normalized_matrix.shape[1]) ) - if len(weights) != normalized_matrix.shape[1]: + if np_weights.size != normalized_matrix.shape[1]: raise ValueError("label_weights length must match number of objectives") ideal_point = np.ones(normalized_matrix.shape[1]) @@ -483,31 +483,37 @@ class QuickAdapterRegressorV3(BaseRegressionModel): "hamming", "jaccard", "jensenshannon", - "kulczynski1", + "kulczynski1", # deprecated since version 1.15.0 "mahalanobis", "matching", "minkowski", "rogerstanimoto", "russellrao", "seuclidean", - "sokalmichener", + "sokalmichener", # deprecated since version 1.15.0 "sokalsneath", "sqeuclidean", "yule", }: - cdist_kwargs = {"w": weights} + cdist_kwargs = {"w": np_weights} + if metric in { + "jensenshannon", + "mahalanobis", + "seuclidean", + }: + del cdist_kwargs["w"] if metric == "minkowski" and isinstance(p_order, float): cdist_kwargs["p"] = p_order return sp.spatial.distance.cdist( normalized_matrix, - ideal_point.reshape(1, -1), # Reshape ideal_point to 2D + ideal_point.reshape(1, -1), # reshape ideal_point to 2D metric=metric, **cdist_kwargs, ).flatten() elif metric == "hellinger": return np.sqrt( np.sum( - np.array(weights) + np_weights * (np.sqrt(normalized_matrix) - np.sqrt(ideal_point)) ** 2, axis=1, ) @@ -519,12 +525,10 @@ class QuickAdapterRegressorV3(BaseRegressionModel): "power_mean": p_order, }[metric] return sp.stats.pmean( - ideal_point, p=p, weights=weights - ) - sp.stats.pmean(normalized_matrix, p=p, weights=weights, axis=1) + ideal_point, p=p, weights=np_weights + ) - sp.stats.pmean(normalized_matrix, p=p, weights=np_weights, axis=1) elif metric == "weighted_sum": - return np.sum( - np.array(weights) * (ideal_point - normalized_matrix), axis=1 - ) + return np.sum(np_weights * (ideal_point - normalized_matrix), axis=1) elif metric == "d1": if normalized_matrix.shape[0] < 2: return np.full(normalized_matrix.shape[0], np.inf) diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index 40767b7..7ebc979 100644 --- a/quickadapter/user_data/strategies/QuickAdapterV3.py +++ b/quickadapter/user_data/strategies/QuickAdapterV3.py @@ -60,7 +60,7 @@ class QuickAdapterV3(IStrategy): INTERFACE_VERSION = 3 def version(self) -> str: - return "3.3.73" + return "3.3.74" timeframe = "5m" -- 2.43.0