8

我想用自定义指标训练一个 lgb 模型:f1_score平均weighted

我在这里浏览了 lightgbm 的高级示例,发现了自定义二进制错误函数的实现。我实现了类似的函数来返回 f1_score,如下所示。

def f1_metric(preds, train_data):

    labels = train_data.get_label()

    return 'f1', f1_score(labels, preds, average='weighted'), True

我尝试通过传递feval参数来训练模型,f1_metric如下所示。

evals_results = {}

bst = lgb.train(params, 
                     dtrain, 
                     valid_sets= [dvalid], 
                     valid_names=['valid'], 
                     evals_result=evals_results, 
                     num_boost_round=num_boost_round,
                     early_stopping_rounds=early_stopping_rounds,
                     verbose_eval=25, 
                     feval=f1_metric)

然后我得到ValueError: Found input variables with inconsistent numbers of samples:

训练集被传递给函数而不是验证集。

如何配置以通过验证集并返回 f1_score。?

4

2 回答 2

22

文档有点混乱。在描述您传递给 feval 的函数的签名时,他们将其参数称为 predstrain_data,这有点误导。

但以下似乎有效:

from sklearn.metrics import f1_score

def lgb_f1_score(y_hat, data):
    y_true = data.get_label()
    y_hat = np.round(y_hat) # scikits f1 doesn't like probabilities
    return 'f1', f1_score(y_true, y_hat), True

evals_result = {}

clf = lgb.train(param, train_data, valid_sets=[val_data, train_data], valid_names=['val', 'train'], feval=lgb_f1_score, evals_result=evals_result)

lgb.plot_metric(evals_result, metric='f1')

要使用多个自定义指标,请像上面一样定义一个整体自定义指标函数,在其中计算所有指标并返回元组列表。

编辑:固定代码,当然 F1 越大越好,应该设置为 True。

于 2018-06-28T11:53:21.500 回答
6

关于托比的回答:

def lgb_f1_score(y_hat, data):
    y_true = data.get_label()
    y_hat = np.round(y_hat) # scikits f1 doesn't like probabilities
    return 'f1', f1_score(y_true, y_hat), True

我建议将 y_hat 部分更改为:

y_hat = np.where(y_hat < 0.5, 0, 1)  

原因:我使用了 y_hat = np.round(y_hat) 并发现在训练期间 lightgbm 模型有时(非常不可能但仍然会发生变化)将我们的 y 预测视为多类而不是二元。

我的猜测:有时 y 预测会小到足以舍入到负值或 2?我不确定,但是当我使用 np.where 更改代码时,错误就消失了。

尽管我不确定 np.where 解决方案是否良好,但我花了一个早上来解决这个错误。

于 2019-11-07T03:34:56.430 回答