Как написать собственную метрику оценки F1 в легком gbm python в классификации Multiclass - PullRequest
0 голосов
/ 02 июля 2018

Может кто-нибудь помочь мне, как написать пользовательский счет F1 для классификации мультикласса в Python ???

Редактировать: я редактирую вопрос, чтобы дать лучшую картину того, что я хочу сделать

Это моя функция для пользовательской метрики оценки eval f1 для задачи мультикласса с 5 классами.

def evalerror(preds, dtrain):
    labels = dtrain.get_label()
    preds = preds.reshape(-1, 5)
    preds = preds.argmax(axis = 1)
    f_score = f1_score(preds, labels, average = 'weighted')
    return 'f1_score', f_score, True

Примечание. Причина, по которой я изменяю форму, состоит в том, что истинное значение валидации имеет длину 252705, тогда как preds - это массив длиной 1263525, который в 5 раз больше фактического. Причина в том, что LGB выводит вероятности каждого класса для каждого прогноза.

Ниже я преобразую данные поезда и проверки в формат, который будет принимать LGB.

dtrain = lgb.Dataset(train_X, label= train_Y, free_raw_data = False)
dvalid = lgb.Dataset(valid_X, label= valid_Y, free_raw_data = False, 
                     reference= dtrain)

Ниже приведена модель ЛГБ, которую я подгоняю к данным обучения. Как вы можете видеть, я передал пользовательскую функцию evalerror в свою модель на feval, а также данные проверки dvalid, для которых я хочу увидеть оценку f1 во время тренировки. Я тренирую модель в течение 10 итераций.

evals_result = {}
num_round = 10
lgb_model = lgb.train(params, 
                      dtrain, 
                      num_round, 
                      valid_sets = dvalid, 
                      feval = evalerror,
                      evals_result = evals_result)

Поскольку модель обучается в течение 10 раундов, показатель F1 для каждой итерации в наборе проверки отображается ниже, что неверно, поскольку я получаю около 0,18.

[1]     valid_0's multi_logloss: 1.46839        valid_0's f1_score: 0.183719
[2]     valid_0's multi_logloss: 1.35684        valid_0's f1_score: 0.183842
[3]     valid_0's multi_logloss: 1.26527        valid_0's f1_score: 0.183853
[4]     valid_0's multi_logloss: 1.18799        valid_0's f1_score: 0.183909
[5]     valid_0's multi_logloss: 1.12187        valid_0's f1_score: 0.187206
[6]     valid_0's multi_logloss: 1.06452        valid_0's f1_score: 0.187503
[7]     valid_0's multi_logloss: 1.01437        valid_0's f1_score: 0.187327
[8]     valid_0's multi_logloss: 0.97037        valid_0's f1_score: 0.187511
[9]     valid_0's multi_logloss: 0.931498       valid_0's f1_score: 0.186957
[10]    valid_0's multi_logloss: 0.896877       valid_0's f1_score: 0.18751

Но как только модель обучается за 10 итераций, я запускаю приведенный ниже код для прогнозирования на том же наборе проверки.

lgb_prediction = lgb_model.predict(valid_X)
lgb_prediction = lgb_prediction.argmax(axis = 1)
lgb_F1 = f1_score(lgb_prediction, valid_Y, average = 'weighted')
print("The Light GBM F1 is", lgb_F1)

The Light GBM F1 is 0.743250263548

Примечание: я не изменил здесь, как я сделал это в пользовательской функции, потому что lgb_model.predict() выводит массив numpy (252705, 5) Также обратите внимание, что я передаю valid_X, а не dvalid, потому что при прогнозировании нам придется передавать исходный формат, а не разреженный, как мы передаем в lgb.train()

Когда я прогнозирую тот же набор данных проверки, я получаю оценку F1 0,743250263548, что достаточно хорошо. Таким образом, я ожидаю, что результат проверки F1 на 10-й итерации будет таким же, как и прогноз, который я предсказал после обучения модели.

Может кто-нибудь помочь мне с тем, что я делаю неправильно. Спасибо

Ответы [ 2 ]

0 голосов
/ 23 декабря 2018

У меня была такая же проблема.

Lgb-прогнозы выводятся в виде плоского массива.

Осмотрев его, я выяснил, что он выглядит так:

вероятность выборки a для класса i находится на

num_classes*(a-1) + i позиция

Что касается вашего кода, он должен быть таким:

    def evalerror(preds, dtrain):

        labels = dtrain.get_label()
        preds = preds.reshape(5, -1).T
        preds = preds.argmax(axis = 1)
        f_score = f1_score(labels , preds,  average = 'weighted')
        return 'f1_score', f_score, True
0 голосов
/ 02 июля 2018
sklearn.metrics.f1_score(y_true, y_pred, labels=None, pos_label=1, average=’binary’, sample_weight=None)[source]

Итак, согласно этому вы должны исправить:

#f1_score(labels , preds)
def evalerror(preds, dtrain):
    labels = dtrain.get_label()
    preds = preds.reshape(-1, 5)
    preds = preds.argmax(axis = 1)
    f_score = f1_score(labels , preds,  average = 'weighted')
    return 'f1_score', f_score, True
...