基于GPU与Optuna的CatBoost分类器自定义指标报错排查
解决CatBoost自定义指标的格式错误问题
错误根源
你触发的Invalid metric description错误,核心原因是自定义指标的传入方式完全错误:
- CatBoost的
custom_metric参数仅用于给内置指标传递自定义参数(比如Precision:class_id=1),不能用来指定自定义函数 - 真正传入自定义评估函数,需要使用
eval_metric参数,且直接传入函数对象,而非字符串格式
修复步骤及完整代码
1. 修正自定义指标的传入方式
将CatBoostClassifier初始化时的custom_metric='Precision:custom_precision'替换为eval_metric=custom_precision
2. 适配多分类任务的自定义函数签名
CatBoost对多分类任务的自定义指标函数,会传入以下参数:
y_true: 一维数组,存储样本的真实类别标签y_pred: 二维数组(形状[样本数, 类别数]),存储每个样本属于各类别的概率
你之前的函数错误地将y_true当成了二维数组,需要调整逻辑。
3. 补充Optuna目标函数的返回值
原代码最后没有返回score,Optuna的目标函数必须返回优化目标值,否则无法完成超参数搜索。
修改后的完整目标函数代码:
def objective(trial, data=data): num_train_pool = data["num_train_pool"] num_test_pool = data["num_test_pool"] true_labels_test = data["true_labels_test"] params = { 'objective': 'MultiClass', 'task_type': 'GPU', 'logging_level': 'Verbose', 'bootstrap_type': 'Bayesian', 'learning_rate': trial.suggest_loguniform('learning_rate', 1e-4, 1), 'depth': trial.suggest_int('depth', 3, 12), 'l2_leaf_reg': trial.suggest_loguniform('l2_leaf_reg', 1e-2, 1), 'border_count': trial.suggest_int('border_count', 32, 255) } def custom_precision(y_true, y_pred): # 获取每个样本的预测类别(概率最大的类别) pred_labels = y_pred.argmax(axis=1) # 计算-1类的真阳性和假阳性 tp_neg1 = ((y_true == -1) & (pred_labels == -1)).sum() fp_neg1 = ((y_true != -1) & (pred_labels == -1)).sum() # 计算1类的真阳性和假阳性 tp_pos1 = ((y_true == 1) & (pred_labels == 1)).sum() fp_pos1 = ((y_true != 1) & (pred_labels == 1)).sum() total_tp = tp_neg1 + tp_pos1 total_fp = fp_neg1 + fp_pos1 return total_tp / (total_tp + total_fp + 1e-8) # 修正自定义指标的传入方式 model = catboost.CatBoostClassifier(**params, eval_metric=custom_precision, random_seed=65) model.fit( num_train_pool, verbose=0, eval_set=num_test_pool, early_stopping_rounds=5 ) preds = model.predict(num_test_pool) score = custom_precision(true_labels_test, model.predict_proba(num_test_pool)) # 必须返回优化目标值给Optuna return score
额外注意事项
- 你已经通过
Pool传入了类别权重,训练时模型会自动应用这些权重,无需在自定义指标中重复处理 - 如果需要基于自定义指标做早停,确保
eval_metric指定的是该函数,CatBoost会自动用它来判断早停条件 - 多分类任务中,
model.predict()返回的是直接的类别标签,而自定义指标在fit过程中接收的y_pred是概率矩阵,因此在计算最终score时,需要传入predict_proba的结果以保持逻辑一致
内容的提问来源于stack exchange,提问作者Luis Miguel
相关产品推荐
相关产品推荐

