From 01de59f347eac2a23835063279d507417d7d0cda Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 29 May 2026 00:43:31 -0500 Subject: [PATCH] fix: use correct eval_metric for multiclass classification in XGBoost When ml_task is multiclass_classification and the user selects 'f1' as eval_metric, XGBoost was defaulting to 'accuracy' internally because 'f1' is not a native XGBoost metric for multiclass. This fix ensures f1 and accuracy are explicitly routed as custom metrics in the multiclass case, consistent with how LightGBM handles it. Adds a test case covering eval_metric='f1' in multiclass with sensitive features. --- supervised/algorithms/xgboost.py | 3 ++- .../test_multi_class_classification.py | 23 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/supervised/algorithms/xgboost.py b/supervised/algorithms/xgboost.py index 34cfadb9..73451a91 100644 --- a/supervised/algorithms/xgboost.py +++ b/supervised/algorithms/xgboost.py @@ -41,11 +41,12 @@ def time_constraint(env): def xgboost_eval_metric(ml_task, automl_eval_metric): - # the mapping is almost the same eval_metric_name = automl_eval_metric if ml_task == MULTICLASS_CLASSIFICATION: if automl_eval_metric == "logloss": eval_metric_name = "mlogloss" + elif automl_eval_metric in ["f1", "accuracy"]: + eval_metric_name = automl_eval_metric # será manejado como custom_metric return eval_metric_name diff --git a/tests/tests_fairness/test_multi_class_classification.py b/tests/tests_fairness/test_multi_class_classification.py index 3dab884f..8682bc1c 100644 --- a/tests/tests_fairness/test_multi_class_classification.py +++ b/tests/tests_fairness/test_multi_class_classification.py @@ -4,7 +4,7 @@ import numpy as np import pandas as pd -from supervised import AutoML +from supervised import AutoML, automl class FairnessInMultiClassClassificationTest(unittest.TestCase): @@ -53,3 +53,24 @@ def test_init(self): self.assertTrue(len(automl._models[0].get_fairness_optimization()) > 1) self.assertTrue(automl._models[0].get_worst_fairness() is not None) self.assertTrue(automl._models[0].get_best_fairness() is not None) + + def test_with_f1_metric(self): + X = np.random.uniform(size=(30, 2)) + y = np.array(["A", "B", "C"] * 10) + S = pd.DataFrame({"sensitive": ["D", "E"] * 15}) + + automl = AutoML( + results_path=self.automl_dir, + model_time_limit=10, + algorithms=["Xgboost"], + eval_metric="f1", # ← el bug que se corrige + explain_level=0, + train_ensemble=False, + stack_models=False, + validation_strategy={"validation_type": "split"}, + start_random_models=1, + ) + + automl.fit(X, y, sensitive_features=S) + self.assertGreater(len(automl._models), 0) + self.assertEqual(automl._eval_metric, "f1") \ No newline at end of file