②机器学习分类算法之XGBoost(集成学习算法)

简介: 机器学习分类算法之XGBoost(集成学习算法)

调参步骤及思想

选择较高的学习速率(learning rate)。一般情况下,学习速率的值为0.1。但是,对于不同的问题,理想的学习速率有时候会在0.05到0.3之间波动。选择对应于此学习速率的理想决策树数量。XGBoost有一个很有用的函数“cv”,这个函数可以在每一次迭代中使用交叉验证,并返回理想的决策树数量。


对于给定的学习速率和决策树数量,进行决策树特定参数调优(max_depth, min_child_weight, gamma, subsample, colsample_bytree)。在确定一棵树的过程中,我们可以选择不同的参数,待会儿我会举例说明。


xgboost的正则化参数的调优。(lambda, alpha)。这些参数可以降低模型的复杂度,从而提高模型的表现。


降低学习速率,确定理想参数。


XGBoost代码案例

XGBoost效果确实不错,但是前提是要将参数不断地优化和调整,这样最终才能得到一个较好的模型,下面依然以一个实际的案例进行XGBoost代码演示


#导入所需要的包
from sklearn.metrics import precision_score
from sklearn.model_selection import train_test_split
import xgboost as xgb
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import classification_report
from sklearn.model_selection import GridSearchCV #网格搜索
import matplotlib.pyplot as plt#可视化
import seaborn as sns#绘图包
# 忽略警告
import warnings
warnings.filterwarnings("ignore")

相关性分析

plt.figure(figsize=(20,20))
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
sns.heatmap(df.corr(),cmap="YlGnBu",annot=True)
plt.title("相关性分析图")

image.png

XGBoost无参数模型


model=xgb.XGBClassifier()
# 训练模型
model.fit(X_train,y_train)
# 预测值
y_pred = model.predict(X_test)
'''
评估指标
'''
# 求出预测和真实一样的数目
true = np.sum(y_pred == y_test )
print('预测对的结果数目为:', true)
print('预测错的的结果数目为:', y_test.shape[0]-true)
# 评估指标
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,cohen_kappa_score
print('预测数据的准确率为: {:.4}%'.format(accuracy_score(y_test,y_pred)*100))
print('预测数据的精确率为:{:.4}%'.format(
      precision_score(y_test,y_pred)*100))
print('预测数据的召回率为:{:.4}%'.format(
      recall_score(y_test,y_pred)*100))
# print("训练数据的F1值为:", f1score_train)
print('预测数据的F1值为:',
      f1_score(y_test,y_pred))
print('预测数据的Cohen’s Kappa系数为:',
      cohen_kappa_score(y_test,y_pred))
# 打印分类报告
print('预测数据的分类报告为:','
',
      classification_report(y_test,y_pred))

效果还是不错,比之前用其他的模型反复的调优的效果还好,但是这不是XGBoost的最终效果

image.png

n_estimators(学习曲线)

scorel = []
for i in range(0,300,10):
    model = xgb.XGBClassifier(n_estimators=i+1,
                                 n_jobs=--4,
                                 random_state=90).fit(X_train,y_train)
    score = model.score(X_test,y_test)
    scorel.append(score)
print(max(scorel),(scorel.index(max(scorel))*10)+1)  #作图反映出准确度随着估计器数量的变化,51的附近最好
plt.figure(figsize=[20,5])
plt.plot(range(1,300,10),scorel)
plt.show()


image.png

继续迭代优化,缩小范围


scorel = []
for i in range(0,20,1):
    model = xgb.XGBClassifier(n_estimators=i+1,
                                 n_jobs=--4,
                                 random_state=90).fit(X_train,y_train)
    score = model.score(X_test,y_test)
    scorel.append(score)
print(max(scorel),(scorel.index(max(scorel))*1)+1)  #作图反映出准确度随着估计器数量的变化,51的附近最好
plt.figure(figsize=[20,5])
plt.plot(range(0,20,1),scorel)
plt.show()

image.png

max_depth(学习曲线)

scorel = []
for i in range(0,20,1):
    model = xgb.XGBClassifier(max_depth =i,
                                 n_estimators=8,
                                 n_jobs=--4,
                                 random_state=90).fit(X_train,y_train)
    score = model.score(X_test,y_test)
    scorel.append(score)
print(max(scorel),(scorel.index(max(scorel))*1)+1)  #作图反映出准确度随着估计器数量的变化,51的附近最好
plt.figure(figsize=[20,5])
plt.plot(range(0,20,1),scorel)
plt.show()


image.png


效果有所提升,继续调优,但是我们知道XGBoost的参数过于的多,如果按照传统的学习曲线迭代调优,效果可能局限在局部最优 ,下面试试XGBoost的交叉验证


调整max_depth 和min_child_weight

param_test1 = {
# 'n_estimators':list(range(3,15,1)),
 'max_depth':list(range(3,10,2)),
 'min_child_weight':list(range(1,6,2))
}
gsearch1 = GridSearchCV(estimator = xgb.XGBClassifier( learning_rate =0.1, n_estimators=8, max_depth=8,
 min_child_weight=1, gamma=0, subsample=0.8, colsample_bytree=0.8,
 objective= 'binary:logistic', nthread=4, scale_pos_weight=1, seed=27), 
 param_grid = param_test1, scoring='roc_auc',iid=False, cv=5)
gsearch1=gsearch1.fit(X,y)
gsearch1.best_params_, gsearch1.best_score_
({'max_depth': 3, 'min_child_weight': 5}, 0.9200952807471878)

进一步调整


param_test1 = {
 'max_depth':list(range(8,11,1)),
 'min_child_weight':list(range(1,4,1))
}
gsearch1 = GridSearchCV(estimator = xgb.XGBClassifier( learning_rate =0.1, n_estimators=7, max_depth=3,
 min_child_weight=5, gamma=0, subsample=0.8, colsample_bytree=0.8,
 objective= 'binary:logistic', nthread=4, scale_pos_weight=1, seed=27), 
 param_grid = param_test1, scoring='roc_auc',iid=False, cv=5)
gsearch1.fit(X,y)
gsearch1.best_params_, gsearch1.best_score_
({'max_depth': 8, 'min_child_weight': 3}, 0.9158850465045336)

调整gamma

param_test3 = {
 'gamma':[i/10.0 for i in range(0,5)]
}
gsearch3 = GridSearchCV(estimator = xgb.XGBClassifier( learning_rate =0.1, n_estimators=8, max_depth=8,
 min_child_weight=3, gamma=0, subsample=0.8, colsample_bytree=0.8,
 objective= 'binary:logistic', nthread=4, scale_pos_weight=1,seed=27), 
 param_grid = param_test3, scoring='roc_auc',iid=False, cv=5)
gsearch3.fit(X,y)
gsearch3.best_params_, gsearch3.best_score_

({'gamma': 0.4}, 0.9103697321364825)

调整subsample 和colsample_bytree

param_test5 = {
 'subsample':[i/100.0 for i in range(75,90,5)],
 'colsample_bytree':[i/100.0 for i in range(75,90,5)]
}
gsearch5 = GridSearchCV(estimator = xgb.XGBClassifier( learning_rate =0.1, n_estimators=8, max_depth=8,
 min_child_weight=3, gamma=0.4, subsample=0.8, colsample_bytree=0.8,
 objective= 'binary:logistic', nthread=4, scale_pos_weight=1,seed=27), 
 param_grid = param_test5, scoring='roc_auc',iid=False, cv=5)
gsearch5.fit(X_train,y_train)
gsearch5.best_params_, gsearch5.best_score_
({'colsample_bytree': 0.85, 'subsample': 0.85}, 0.9420290874342445)

效果一下就有了显著的提升,继续调参,因为这个参数还是比较的重要有放回随机抽样


调整正则化参数

param_test6 = {
 'reg_alpha':[1e-5, 1e-2, 0.1, 1, 100]
}
gsearch6 = GridSearchCV(estimator = xgb.XGBClassifier( learning_rate =0.1, n_estimators=8, max_depth=8,
 min_child_weight=3, gamma=0.2, subsample=0.85, colsample_bytree=0.85,
 objective= 'binary:logistic', nthread=4, scale_pos_weight=1,seed=27), 
 param_grid = param_test6, scoring='roc_auc',iid=False, cv=5)
gsearch6.fit(X_train,y_train)
gsearch6.best_params_, gsearch6.best_score_
({'reg_alpha': 1e-05}, 0.9426155352636133)
param_test6 = {
 'learning_rate':[0.01, 0.02, 0.1, 0.2]
}
gsearch6 = GridSearchCV(estimator = xgb.XGBClassifier( learning_rate =0.1, n_estimators=8, max_depth=8,
 min_child_weight=1, gamma=0.2, subsample=0.8, colsample_bytree=0.85,
 objective= 'binary:logistic', nthread=4, scale_pos_weight=1,seed=27), 
 param_grid = param_test6, scoring='roc_auc',iid=False, cv=5)
gsearch6.fit(X_train,y_train)
gsearch6.best_params_, gsearch6.best_score_
({'learning_rate': 0.1}, 0.9506471151048836)

网格搜索

根据前面所出来的参数,可以进一步的缩放数值,最后采用暴力搜索网格调参,但是由于XGBoost本身就是一个运行速度慢,占据CPU的一个模型,加上网格搜索速度反而变的更慢了,所以这里需要谨慎设置参数,不然电脑会跑的嗡嗡响


# learning_rate =0.1, n_estimators=8, max_depth=8,
#  min_child_weight=1, gamma=0.2, subsample=0.8, colsample_bytree=0.85,
#  objective= 'binary:logistic', nthread=4, scale_pos_weight=1,seed=27
import numpy as np
from sklearn.model_selection import GridSearchCV
parameters = {'n_estimators':np.arange(6,10,1)
              ,'max_depth':np.arange(6,10,1)
              ,"colsample_bytree":np.arange(0.8,0.9,0.05)
              ,"subsample":np.arange(0.8,0.9,0.05)
              ,'gamma':np.arange(0.1,0.5,0.1)
              ,'min_child_weight':np.arange(1,3,1)
}
clf = xgb.XGBClassifier(random_state=25)
GS = GridSearchCV(clf, parameters, cv=5) # cv交叉验证
GS.fit(X_train,y_train)
print(GS.best_params_)
print(GS.best_score_)
{'colsample_bytree': 0.8, 'gamma': 0.4, 'max_depth': 7, 'min_child_weight': 1, 'n_estimators': 8, 'subsample': 0.8}
0.9048780487804878

额,这么说呢,网格搜索的效果还不如自己之前的参数靠谱,事实上说明,我们在优化参数的时候,按照固定思维得出的数值只是一个参考值,我们自己还可以做一些调整(细微的)


最终模型代码

model=xgb.XGBClassifier(eta =0.1, n_estimators=8, max_depth=8,
 min_child_weight=2, gamma=0.8, subsample=0.85, colsample_bytree=0.8)
# 训练模型
model.fit(X_train,y_train)
# 预测值
y_pred = model.predict(X_test)
'''
评估指标
'''
# 求出预测和真实一样的数目
true = np.sum(y_pred == y_test )
print('预测对的结果数目为:', true)
print('预测错的的结果数目为:', y_test.shape[0]-true)
# 评估指标
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,cohen_kappa_score
print('预测数据的准确率为: {:.4}%'.format(accuracy_score(y_test,y_pred)*100))
print('预测数据的精确率为:{:.4}%'.format(
      precision_score(y_test,y_pred)*100))
print('预测数据的召回率为:{:.4}%'.format(
      recall_score(y_test,y_pred)*100))
# print("训练数据的F1值为:", f1score_train)
print('预测数据的F1值为:',
      f1_score(y_test,y_pred))
print('预测数据的Cohen’s Kappa系数为:',
      cohen_kappa_score(y_test,y_pred))
# 打印分类报告
print('预测数据的分类报告为:','
',
      classification_report(y_test,y_pred))

image.png


效果还是不错的,和随机森林有点相近,从这里也可以看出集成学习的优势所在


绘制特征重要性图

from xgboost import plot_importance
# plt.figure(figsize=(15,15))
plt.rcParams["figure.figsize"] = (14, 8)
plot_importance(model)

image.png

XGBoost可视化

xgboosts=xgb.to_graphviz(model)
xgboosts.format = 'png'
xgboosts.view('./xgboost')

image.png


这里绘制来一个树的过程,其中leaf代表预测分数

ROC曲线AUC面积

# ROC曲线、AUC
from sklearn.metrics import precision_recall_curve
from sklearn import metrics
# 预测正例的概率
y_pred_prob=model.predict_proba(X_test)[:,1]
# y_pred_prob ,返回两列,第一列代表类别0,第二列代表类别1的概率
#https://blog.csdn.net/dream6104/article/details/89218239
fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2)
#pos_label,代表真阳性标签,就是说是分类里面的好的标签,这个要看你的特征目标标签是0,1,还是1,2
roc_auc = metrics.auc(fpr, tpr)  #auc为Roc曲线下的面积
# print(roc_auc)
plt.figure(figsize=(8,6))
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.plot(fpr, tpr, 'r',label='AUC = %0.2f'% roc_auc)
plt.legend(loc='lower right')
# plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0, 1.1])
plt.ylim([0, 1.1])
plt.xlabel('False Positive Rate') #横坐标是fpr
plt.ylabel('True Positive Rate')  #纵坐标是tpr
plt.title('Receiver operating characteristic example')
plt.show()


image.png

在使用XGBoost的过程中,遇到了很多的参数调优问题,其次就是CPU不足,运行网格搜索的时候,最后有人推荐去使用lightGBM这种轻量级的,但是好像也有数据量的局限性,后期可以测试一下效果。


数据的数量每天都在增加,对于传统的数据科学算法来说,很难快速的给出结果。LightGBM的前缀‘Light’表示速度很快。LightGBM可以处理大量的数据,运行时占用很少的内存。另外一个理由,LightGBM为什么这么受欢迎是因为它把重点放在结果的准确率上。LightGBM还支持GPU学习,因此,数据科学家广泛的使用LightGBM来进行数据科学应用的部署。

不建议在小数据集上使用LightGBM。LightGBM对过拟合很敏感,对于小数据集非常容易过拟合。对于多小属于小数据集,并没有什么阈值,但是从我的经验,我建议对于10000+以上的数据的时候,再使用LightGBM。


相关文章
|
8天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
27 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
29天前
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
|
17天前
|
机器学习/深度学习 人工智能 算法
探索机器学习中的决策树算法
【10月更文挑战第29天】本文将深入浅出地介绍决策树算法,一种在机器学习中广泛使用的分类和回归方法。我们将从基础概念出发,逐步深入到算法的实际应用,最后通过一个代码示例来直观展示如何利用决策树解决实际问题。无论你是机器学习的初学者还是希望深化理解的开发者,这篇文章都将为你提供有价值的见解和指导。
|
4月前
|
监控 druid Java
spring boot 集成配置阿里 Druid监控配置
spring boot 集成配置阿里 Druid监控配置
291 6
|
4月前
|
Java 关系型数据库 MySQL
如何实现Springboot+camunda+mysql的集成
【7月更文挑战第2天】集成Spring Boot、Camunda和MySQL的简要步骤: 1. 初始化Spring Boot项目,添加Camunda和MySQL驱动依赖。 2. 配置`application.properties`,包括数据库URL、用户名和密码。 3. 设置Camunda引擎属性,指定数据源。 4. 引入流程定义文件(如`.bpmn`)。 5. 创建服务处理流程操作,创建控制器接收请求。 6. Camunda自动在数据库创建表结构。 7. 启动应用,测试流程启动,如通过服务和控制器开始流程实例。 示例代码包括服务类启动流程实例及控制器接口。实际集成需按业务需求调整。
374 4
|
4月前
|
消息中间件 Java 测试技术
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
325 1
|
5月前
|
消息中间件 Java Kafka
springboot集成kafka
springboot集成kafka
169 2
|
5月前
|
消息中间件 Java Kafka
集成Kafka到Spring Boot项目中的步骤和配置
集成Kafka到Spring Boot项目中的步骤和配置
269 7
|
5月前
|
监控 前端开发 Java
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
|
4月前
|
消息中间件 Java Kafka
Spring Boot与Apache Kafka Streams的集成
Spring Boot与Apache Kafka Streams的集成