用xgboost进行特征选择

在这篇文章中,你将会学习到:

  1. xgboost对预测模型特征重要性排序的原理(即为什么xgboost可以对预测模型特征重要性进行排序)。
  2. 如何绘制xgboost模型得到的特征重要性条形图。
  3. 如何根据xgboost模型得到的特征重要性,在scikit-learn进行特征选择。

 

梯度提升算法是如何计算特征重要性的?

使用梯度提升算法的好处是在提升树被创建后,可以相对直接地得到每个属性的重要性得分。一般来说,重要性分数,衡量了特征在模型中的提升决策树构建中价值。一个属性越多的被用来在模型中构建决策树,它的重要性就相对越高。

属性重要性是通过对数据集中的每个属性进行计算,并进行排序得到。在单个决策书中通过每个属性分裂点改进性能度量的量来计算属性重要性,由节点负责加权和记录次数。也就说一个属性对分裂点改进性能度量越大(越靠近根节点),权值越大;被越多提升树所选择,属性越重要。性能度量可以是选择分裂节点的Gini纯度,也可以是其他度量函数。

最终将一个属性在所有提升树中的结果进行加权求和后然后平均,得到重要性得分。

 

绘制特征重要性

一个已训练的xgboost模型能够自动计算特征重要性,这些重要性得分可以通过成员变量feature_importances_得到。可以通过如下命令打印:

print(model.feature_importances_)
 
   
   
   
   

我们可以直接在条形图上绘制这些分数,以获得数据集中每个特征的相对重要性的直观显示。例如:


 
   
   
   
   
  1. # plot
  2. pyplot.bar(range(len(model.feature_importances_)), model.feature_importances_)
  3. pyplot.show()

我们可以通过在the Pima Indians onset of diabetes 数据集上训练XGBOOST模型来演示,并从计算的特征重要性中绘制条形图。


 
   
   
   
   
  1. # plot feature importance manually
  2. from numpy import loadtxt
  3. from xgboost import XGBClassifier
  4. from matplotlib import pyplot
  5. # load data
  6. dataset = loadtxt( 'pima-indians-diabetes.csv', delimiter= ",")
  7. # split data into X and y
  8. X = dataset[:, 0: 8]
  9. y = dataset[:, 8]
  10. # fit model no training data
  11. model = XGBClassifier()
  12. model.fit(X, y)
  13. # feature importance
  14. print(model.feature_importances_)
  15. # plot
  16. pyplot.bar(range(len(model.feature_importances_)), model.feature_importances_)
  17. pyplot.show()

运行这个示例,首先的输出特征重要性分数:

[0.089701, 0.17109634, 0.08139535, 0.04651163, 0.10465116, 0.2026578, 0.1627907, 0.14119601]

相对重要性条形图:

这种绘制的缺点在于,只显示了特征重要性而没有排序,可以在绘制之前对特征重要性得分进行排序。

通过内建的绘制函数进行特征重要性得分排序后的绘制,这个函数就是plot_importance(),示例如下:


 
   
   
   
   
  1. # plot feature importance using built-in function
  2. from numpy import loadtxt
  3. from xgboost import XGBClassifier
  4. from xgboost import plot_importance
  5. from matplotlib import pyplot
  6. # load data
  7. dataset = loadtxt( 'pima-indians-diabetes.csv', delimiter= ",")
  8. # split data into X and y
  9. X = dataset[:, 0: 8]
  10. y = dataset[:, 8]
  11. # fit model no training data
  12. model = XGBClassifier()
  13. model.fit(X, y)
  14. # plot feature importance
  15. plot_importance(model)
  16. pyplot.show()

运行示例得到条形图:

根据其在输入数组中的索引,特征被自动命名为f0-f7。在问题描述中手动的将这些索引映射到名称,我们可以看到,F5(身体质量指数)具有最高的重要性,F3(皮肤折叠厚度)具有最低的重要性。

 

根据xgboost特征重要性得分进行特征选择

特征重要性得分,可以用于在scikit-learn中进行特征选择。通过SelectFromModel类实现,该类采用模型并将数据集转换为具有选定特征的子集。这个类可以采取预先训练的模型,例如在整个数据集上训练的模型。然后,它可以阈值来决定选择哪些特征。当在SelectFromModel实例上调用transform()方法时,该阈值被用于在训练集和测试集上一致性选择相同特征。

在下面的示例中,我们首先在训练集上训练xgboost模型,然后在测试上评估。使用从训练数据集计算的特征重要性,然后,将模型封装在一个SelectFromModel实例中。我们使用这个来选择训练集上的特征,用所选择的特征子集训练模型,然后在相同的特征方案下对测试集进行评估。

示例:


 
   
   
   
   
  1. # select features using threshold
  2. selection = SelectFromModel(model, threshold=thresh, prefit= True)
  3. select_X_train = selection.transform(X_train)
  4. # train model
  5. selection_model = XGBClassifier()
  6. selection_model.fit(select_X_train, y_train)
  7. # eval model
  8. select_X_test = selection.transform(X_test)
  9. y_pred = selection_model.predict(select_X_test)

我们可以通过测试多个阈值,来从特征重要性中选择特征。具体而言,每个输入变量的特征重要性,本质上允许我们通过重要性来测试每个特征子集。

完整示例如下:


 
   
   
   
   
  1. # use feature importance for feature selection
  2. from numpy import loadtxt
  3. from numpy import sort
  4. from xgboost import XGBClassifier
  5. from sklearn.model_selection import train_test_split
  6. from sklearn.metrics import accuracy_score
  7. from sklearn.feature_selection import SelectFromModel
  8. # load data
  9. dataset = loadtxt( 'pima-indians-diabetes.csv', delimiter= ",")
  10. # split data into X and y
  11. X = dataset[:, 0: 8]
  12. Y = dataset[:, 8]
  13. # split data into train and test sets
  14. X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size= 0.33, random_state= 7)
  15. # fit model on all training data
  16. model = XGBClassifier()
  17. model.fit(X_train, y_train)
  18. # make predictions for test data and evaluate
  19. y_pred = model.predict(X_test)
  20. predictions = [round(value) for value in y_pred]
  21. accuracy = accuracy_score(y_test, predictions)
  22. print( "Accuracy: %.2f%%" % (accuracy * 100.0))
  23. # Fit model using each importance as a threshold
  24. thresholds = sort(model.feature_importances_)
  25. for thresh in thresholds:
  26. # select features using threshold
  27. selection = SelectFromModel(model, threshold=thresh, prefit= True)
  28. select_X_train = selection.transform(X_train)
  29. # train model
  30. selection_model = XGBClassifier()
  31. selection_model.fit(select_X_train, y_train)
  32. # eval model
  33. select_X_test = selection.transform(X_test)
  34. y_pred = selection_model.predict(select_X_test)
  35. predictions = [round(value) for value in y_pred]
  36. accuracy = accuracy_score(y_test, predictions)
  37. print( "Thresh=%.3f, n=%d, Accuracy: %.2f%%" % (thresh, select_X_train.shape[ 1], accuracy* 100.0))

运行示例,得到输出:


 
   
   
   
   
  1. Accuracy: 77.95%
  2. Thresh= 0.071, n= 8, Accuracy: 77.95%
  3. Thresh= 0.073, n= 7, Accuracy: 76.38%
  4. Thresh= 0.084, n= 6, Accuracy: 77.56%
  5. Thresh= 0.090, n= 5, Accuracy: 76.38%
  6. Thresh= 0.128, n= 4, Accuracy: 76.38%
  7. Thresh= 0.160, n= 3, Accuracy: 74.80%
  8. Thresh= 0.186, n= 2, Accuracy: 71.65%
  9. Thresh= 0.208, n= 1, Accuracy: 63.78%

我们可以看到,模型的性能通常随着所选择的特征的数量而减少。在这一问题上,可以对测试集准确率和模型复杂度做一个权衡,例如选择4个特征,接受准确率从77.95%降到76.38%。这可能是对这样一个小数据集的清洗,但对于更大的数据集和使用交叉验证作为模型评估方案可能是更有用的策略。

你可能感兴趣的:(sklearn,xgboost)