【问题标题】:How to choose or optimize the labels so that we get better multiclass classification results?如何选择或优化标签以便我们获得更好的多类分类结果?
【发布时间】:2020-10-10 22:14:14
【问题描述】:

最近我在做一个 Kaggle 项目“Prudential Life Insurance Assessment”,竞争对手谈论改变标签以获得更好的指标。

在那次特定的比赛中,目标有 8 个类别 (1-8),但 one of the guy 使用不同的标签 (-1.6, 0.7, 0.3, 3.15, 4.53, 6.5, 6.77, 9.0)another example 他们使用 [-1.6, 0.7, 0.3, 3.15, 4.53, 6.5, 6.77, 9.0] 而不是 [1,2,3,4,5,6,7,8]

我想知道如何得出这些神奇的数字?

我愿意接受任何想法/技巧/建议来进行此类转变。非常感谢您的投入!

示例代码

# imports
import numpy as np
import pandas as pd
import seaborn as sns
import xgboost as xgb
from sklearn import metrics
from sklearn.model_selection import train_test_split

# data
df = sns.load_dataset('iris')
df['species'] = pd.factorize(df['species'])[0]
df = df.sample(frac=1,random_state=100)

# train test split
X = df.drop('species',axis=1)
y = df['species']
Xtrain,  Xtest, ytrain, ytest = train_test_split(X,y,stratify=y,random_state=100)

# modelling
model = xgb.XGBClassifier(objective='multi:softprob', random_state=100)
model.fit(Xtrain, ytrain)
preds = model.predict(Xtest)
kappa = metrics.cohen_kappa_score(ytest, preds, weights='quadratic')

print(kappa)

我的想法

  • 标签可以取的数字实际上是无限的,如何将[1-8] 转换为[x-y]

  • 我们是否应该随机选择 8 个数字并检查所有数字的 kappa。这似乎是最不合理的想法,可能永远不会奏效。

  • 是否有某种梯度下降方法可以解决这个问题?也许不是,只是一个想法。

参考链接

【问题讨论】:

  • 我认为您正在看到他们进行这种硬编码,因此可以使用“回归”建模而不是“分类”。
  • 是的,他们正在对值进行硬编码,但我对如何以更科学的方式“硬编码”这些好的值感兴趣。

标签: python pandas machine-learning xgboost feature-engineering


【解决方案1】:

您问题中的第一个链接实际上包含答案:

#硬编码值是通过使用模拟退火优化 CV 分数获得的

还有后来作者cmets:

起初我是一个一个地优化参数,但后来我切换到通过网格搜索和模拟退火的组合同时优化它们。我不确定我是否找到了 CV 分数的全局最大值,即使在玩弄了各种模拟退火设置之后也是如此。也许遗传算法会有所帮助。

第二个链接的解决方案具有相同的值,因为(可能)作者从第一个解决方案中复制了它们(参见他们的 cmets):

灵感来自:https://www.kaggle.com/mariopasquato/prudential-life-insurance-assessment/linear-model/code

简单地说 - 您可以将这些值视为您的学习算法的元参数(嗯,它们确实如此)。通过这种方式,您可以定义一个函数F(metaparameters),以便计算它的单个值,您可以在训练集上进行全面训练并在验证集上输出损失(或者最好只使用 n 折交叉验证并使用 CV 损失)。然后你的任务就变成了优化函数F,使用你喜欢的任何优化方法来找到最好的元参数集——例如。第一个解决方案的作者声称他们使用了网格搜索和模拟退火。

优化本身没有元调整的小例子:

import numpy as np
cnt = 0
def use_a_function_which_calls_training_and_computes_cv_instead_of_this(x):
    global cnt
    cnt += 1
    return ((x - np.array([-1.6, 0.7, 0.3, 3.15, 4.53, 6.5, 6.77, 9.0]))**2).sum()

my_best_guess_for_the_initial_parameters = np.array([1.,2.,3.,4.,5.,6.,7.,8.])
optimization_results = scipy.optimize.basinhopping(
    use_a_function_which_calls_training_and_computes_cv_instead_of_this,
    my_best_guess_for_the_initial_parameters,
    niter=100)
print("Times function was called: {0}".format(cnt))
print(optimization_results.x)

示例输出:

Times function was called: 3080
[-1.6         0.7         0.3         3.15        4.52999999  6.5
  6.77        8.99999999]

您很可能想尝试优化本身的参数,甚至可能编写自定义优化器和/或回调来制定步骤。但是,即使是默认参数也有可能至少在某种程度上对您有用。如果您发现太多时间对函数进行一次计算,您可以例如尝试使用完整数据的较小子集等进行初始优化。

【讨论】:

  • 显然我已经阅读了两位作者关于该主题的所有 cmets 和 kaggle 讨论。我只是好奇你如何执行这些网格搜索和模拟退火。如果您在回答时附上一些code,我会很乐意接受您的回答。
  • 只是为了澄清-您请求的示例代码仅用于例如模拟退火本身,而不是如何使用交叉验证等计算损失?
  • 是的,我很欣赏你的努力,模拟退火只是网格搜索的一种方法。我更感兴趣的是如何选择初始值,例如[1,2,3],并获得更合理的值。网格搜索实际上有无限的选择。例如,在线性回归 alpha 中,我们可以选择对数刻度 1e-5, 1e-4, 1, 10 等,但这里是实数的完整范围。你有什么建议如何从最初的猜测开始,比如说[1,2,3] 然后选择理性的超参数?
  • 我不想让你失望,但这里没有灵丹妙药。如果您知道最终结果应该以绝对值本身有意义的方式使用 - 您可以从 [1,2,3,4,5,6,7,8] 开始。如果您知道这些是例如您可能希望在 logit 空间中选择一些均匀间隔的间隔,如果这些是对数尺度,那么您可以选择均匀间隔的值并将 exp 应用于它们(并在相应的空间中优化 - 即统一、logit 或指数或对数不管你想怎么称呼它)。
  • @astro123 ,用一个使用 scipy 进行优化的玩具示例更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2023-02-03
  • 2011-12-30
  • 2022-09-30
  • 2019-08-13
  • 2020-04-25
  • 1970-01-01
  • 2019-05-26
  • 2023-03-08
相关资源
最近更新 更多