【问题标题】:How to get actual feature names in XGBoost feature importance plot without retraining the model?如何在不重新训练模型的情况下获得 XGBoost 特征重要性图中的实际特征名称?
【发布时间】:2019-07-22 20:20:08
【问题描述】:

我在 Stackoverflow 上遇到了几个问题,其中群众面临的问题是他们在拟合/训练 XGBoost 模型之前对训练数据进行预处理,例如使用中心和比例等,例如

`

scaler = MinMaxScaler(feature_range=(0, 1))
X = scaler.fit_transform(X)
my_model_name = XGBClassifier()
my_model_name.fit(X,Y)` 

其中 X 和 Y 分别是训练数据和标签,缩放会返回一个 2D NumPy 数组,从而丢失特征名称。

我已经训练了我的 XGBoost 模型,但使用的是预处理数据(使用 MinMaxScaler 进行中心和缩放)。因此,我处于类似的情况,列名/功能名称丢失。因此,当我尝试使用plot_importance(my_model_name) 时,它会导致特征重要性图,但只有特征名称为 f0、f1、f2 等,而不是数据集中的实际特征名称,这必须很明显。

关于 SO 的大多数答案都与以不丢失特征名称的方式训练模型有关(例如在数据框列上使用 pd.get_dummies。我有一个疑问,即在使用 @ 时如何获取实际特征名称987654324@,无需重新训练模型?有没有办法将原始训练数据(未经预处理,带有列名)的特征名称f0,f1,f2等映射到生成的特征重要性图上,以便实际功能名称绘制在图表中?非常感谢这方面的任何帮助。

【问题讨论】:

标签: python dataframe xgboost


【解决方案1】:

您是对的,当您将 NumPy 数组传递给 XGBoost 的 fit 方法时,您会丢失功能名称。在这种情况下,调用model.get_booster().feature_names 没有用处,因为返回的名称采用[f0, f1, ..., fn] 的形式,并且这些名称也显示在plot_importance 方法的输出中。

但是应该有几种方法可以实现您想要的 - 假设您将原始功能名称存储在某处,例如orig_feature_names = ['f1_name', 'f2_name', ..., 'fn_name'] 或直接 orig_feature_names = X.columns 如果 X 是 pandas DataFrame。

那么你应该能够:

  • 更改存储的特征名称 (model.get_booster().feature_names = orig_feature_names),然后使用 plot_importance 方法,该方法应该已经采用更新的名称并将其显示在绘图上
  • 或者由于此方法返回 matplotlib ax,您可以使用 plot_importance(model).set_yticklabels(orig_feature_names) 修改标签(但您必须设置正确的特征顺序)
  • 或者您可以将model.feature_importances_ 与您自己的原始特征名称结合起来(即自己绘制)
  • 同样,您也可以使用model.get_booster().get_score() 方法并将其与您的功能名称结合起来
  • 或者您可以尝试Learning API 和 xgboost DMatrix 并在创建数据集期间(缩放后)使用train_data = xgb.DMatrix(X, label=Y, feature_names=orig_feature_names) 指定您的特征名称(但我对这种训练方式没有太多经验,因为我通常使用Scikit-Learn API)

编辑:

感谢@Noob Programmer(参见下面的 cmets),基于使用不同的特征重要性方法可能会出现一些“不一致”。这些是最重要的:

  • xgboost.plot_importance 使用“权重”作为默认重要性类型(参见 plot_importance
  • model.get_booster().get_score() 也使用“重量”作为默认值(参见 get_score
  • model.feature_importances_ 取决于 importance_type 参数(model.importance_type),结果似乎被归一化为 1 的总和(参见 this comment

有关此主题的更多信息,请查看How to get feature importance

【讨论】:

  • model.feature_importance 和 plot_importance(model, type = "gain),不要给出相同的特征,所以第 3 点是不合法的。f 后面的数字,像“f1001”索引数据框中的特征?
  • @NoobProgrammer:感谢您的评论,请参阅更新后的答案。结果应该是一样的,不同的是归一化。如果您认为答案不够清楚,请随时更新答案。关于数字,是的,这些应该是数据帧(或 numpy 或任何输入数据)中特征的索引。这就是您可以使用model.get_booster().feature_names = orig_feature_names 的原因。或者您可以解析这些索引并直接在结果字典上使用它。
【解决方案2】:

您可以通过以下方式获取功能名称:

model.get_booster().feature_names

【讨论】:

  • 现在应该可以接受两位数的赞成票了:)
  • 正如您在我的回答中(甚至在问题中)所看到的,这不是正确的答案,因为当您将 numpy 数组传递给 fit 方法时,您会丢失原始特征名称。
  • 这就是为什么你应该传递 DataFrame 而不是 Numpy 数组。
  • 关于你的回答,你可能会在你的答案中添加关于使用 DataFrame 而不是 NumPy 数组的注释,因为现在它没有回答问题,因为用户正在使用 NumPy 数组,因此使用 model.get_booster().feature_names 确实不适合他。
  • 如果模型已经保存然后使用 save_model 和 load_model 加载,这将不起作用。
猜你喜欢
  • 2020-04-08
  • 2020-03-17
  • 1970-01-01
  • 2022-06-20
  • 2018-12-06
  • 2017-11-14
  • 2019-08-03
  • 2019-10-05
相关资源
最近更新 更多