### 自定义用于lightGBM的多类别log-loss函数在python中返回错误

我正在尝试实现一个带有自定义目标函数的lightGBM分类器。我的目标数据有四个类别,并且我的数据被分成自然组,每组有12个观测值。

自定义目标函数需要实现以下两点:

  1. 预测模型的输出必须是概率性的,并且每个观测值的概率总和必须为1。这也被称为softmax目标函数,实现起来相对简单
  2. 每个组内每个类别的概率总和必须为1。这在二项分类空间中已被实现,称为条件逻辑模型。

总结来说,对于每个组(在我这里是4个观测值),概率在每列和每行中的总和应为1。我编写了一个略显粗糙的函数来实现这一点,但当我尝试在python的xgb框架中运行我的自定义目标函数时,我得到了以下错误:

TypeError: cannot unpack non-iterable numpy.float64 object

我的完整代码如下:

import lightgbm as lgbimport numpy as npimport pandas as pddef standardiseProbs(preds, groupSize, eta = 0.1, maxIter = 100):    # add groupId to preds dataframe    n = preds.shape[0]    if n % groupSize != 0:        print('The selected group size paramter is not compatible with the data')    preds['groupId'] = np.repeat(np.arange(0, int(n/groupSize)), groupSize)    #initialise variables    error = 10000    i = 0    # perform loop while error exceeds set threshold (subject to maxIter)    while error > eta and i<maxIter:        i += 1        # get sum of probabilities by game        byGroup = preds.groupby('groupId')[0, 1, 2, 3].sum().reset_index()        byGroup.columns = ['groupId', '0G', '1G', '2G', '3G']        if '3G' in list(preds.columns):            preds = preds.drop(['3G', '2G', '1G', '0G'], axis=1)        preds = preds.merge(byGroup, how='inner', on='groupId')        # adjust probs to be consistent across a game        for v in [1, 2, 3]:            preds[v] = preds[v] / preds[str(v) + 'G']        preds[0] = (groupSize-3)* (preds[0] / preds['0G'])        # sum probabilities by player        preds['rowSum'] = preds[3] + preds[2] + preds[1] + preds[0]        # adjust probs to be consistent across a player        for v in [0, 1, 2, 3]:            preds[v] = preds[v] / preds['rowSum']        # get sum of probabilities by game        byGroup = preds.groupby('groupId')[0, 1, 2, 3].sum().reset_index()        byGroup.columns = ['groupId', '0G', '1G', '2G', '3G']        # calc error        errMat = abs(np.subtract(byGroup[['0G', '1G', '2G', '3G']].values, np.array([(groupSize-3), 1, 1, 1])))        error = sum(sum(errMat))    preds = preds[['groupId', 0, 1, 2, 3]]    return predsdef condObjective(preds, train):    labels = train.get_label()    preds = pd.DataFrame(np.reshape(preds, (int(preds.shape[0]/4), 4), order='C'), columns=[0,1,2,3])    n = preds.shape[0]    yy = np.zeros((n, 4))    yy[np.arange(n), labels] = 1    preds['matchId'] = np.repeat(np.arange(0, int(n/4)), 4)    preds = preds[['matchId', 0, 1, 2, 3]]    preds = standardiseProbs(preds, groupSize = 4, eta=0.001, maxIter=500)    preds = preds[[0, 1, 2, 3]].values    grad = (preds - yy).flatten()    hess = (preds * (1. - preds)).flatten()    return grad, hessdef mlogloss(preds, train):    labels = train.get_label()    preds = pd.DataFrame(np.reshape(preds, (int(preds.shape[0]/4), 4), order='C'), columns=[0,1,2,3])    n = preds.shape[0]    yy = np.zeros((n, 4))    yy[np.arange(n), labels] = 1    preds['matchId'] = np.repeat(np.arange(0, int(n/4)), 4)    preds = preds[['matchId', 0, 1, 2, 3]]    preds = standardiseProbs(preds, groupSize = 4, eta=0.001, maxIter=500)    preds = preds[[0, 1, 2, 3]].values    loss = -(np.sum(yy*np.log(preds)+(1-yy)*np.log(1-preds))/n)    return lossn, k = 880, 5xtrain = np.random.rand(n, k)ytrain = np.random.randint(low=0, high=2, size=n)ltrain = lgb.Dataset(xtrain, label=ytrain)xtest = np.random.rand(int(n/2), k)ytest = np.random.randint(low=0, high=2, size=int(n/2))ltest = lgb.Dataset(xtrain, label=ytrain)lgbmParams = {'boosting_type': 'gbdt',               'num_leaves': 250,               'max_depth': 3,              'min_data_in_leaf': 10,               'min_gain_to_split': 0.75,               'learning_rate': 0.01,               'subsample_for_bin': 120100,               'min_child_samples': 70,               'reg_alpha': 1.45,               'reg_lambda': 2.5,               'feature_fraction': 0.45,               'bagging_fraction': 0.55,               'is_unbalance': True,               'objective': 'multiclass',               'num_class': 4,               'metric': 'multi_logloss',               'verbose': 1}lgbmModel = lgb.train(lgbmParams, ltrain, valid_sets=ltest,fobj=condObjective, feval=mlogloss, num_boost_round=5000, early_stopping_rounds=100, verbose_eval=50)

假设没有更好的方法来强制我的预测符合我设定的限制条件,我需要做什么才能使自定义目标函数正常工作?


回答:

这个错误的问题

    -> 2380                 eval_name, val, is_higher_better = feval_ret // this is the return of mlogloss       2381                 ret.append((data_name, eval_name, val, is_higher_better))       2382         return retTypeError: 'numpy.float64' object is not iterable

来自函数 mlogloss()。因为你把它用作评估函数 feval=mlogloss,它应该返回三样东西:它的名字、值和一个指示更高值是否更好的布尔值。

def mlogloss(...):...return "my_loss_name", loss_value, False

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注