python 使用GPU和optuna的CatBoost分类器的自定义指标

wgx48brx  于 2023-04-19  发布在  Python
关注(0)|答案(1)|浏览(215)

我有以下目标函数在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):
        true_positives = ((y_true[:, 0] == -1) & (y_pred[:, 0] == -1)).sum() + ((y_true[:, 1] == 1) & (y_pred[:, 1] == 1)).sum()
        false_positives = ((y_true[:, 0] != -1) & (y_pred[:, 0] == -1)).sum() + ((y_true[:, 1] != 1) & (y_pred[:, 1] == 1)).sum()
        return true_positives / (true_positives + false_positives + 1e-8)
    
 
    model = catboost.CatBoostClassifier(**params, custom_metric='Precision: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)
    pred_labels = np.rint(preds)
    
    score = custom_precision(true_labels_test, pred_labels)

这是一个不平衡的分类问题,其中我的类权重如下:{-1:12.5,0:0.5,1:10}。我只关心类-1和1获得高的True Positives分数,这就是为什么我写了自定义精度函数。此外,我的训练池有一个weight_vector,因为不是所有的样本都有相同的“质量”。我的池看起来像这样:

num_train_pool = catboost.Pool(data=X_train,
                               label=y_train,
                               weight=y_train_weights,
                               feature_names=X_train.columns.to_list())

运行优化后,我得到了这个:

CatBoostError: catboost/private/libs/options/loss_description.cpp:34: Invalid metric description, it should be in the form "metric_name:param1=value1;...;paramN=valueN"

我认为我正确地遵循了CatBoost指南,但无法找出我的代码中的错误。有任何反馈吗?

l7mqbcuq

l7mqbcuq1#

问题在于你如何构造Catboost对象。你需要根据错误消息重新格式化你的字符串,我建议在你的params dict中包括你的custom_metric,以避免任何混乱。
尝试将params更改为:

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),
          'custom_metric': 'Precision:custom_precision=1,0,-1',
          'random_seed': 65
         }

然后你的Catboost构造函数:
model = catboost.CatBoostClassifier(**params)

相关问题