#展示各类参数的调参过程
#目的就是测试集的效果不能更差且与训练集的距离减小,主要防止过拟合
dfull=xgb.DMatrix(X,y)#其余参数都是默认
param1={"silent":True#并非默认
,"obj":"reg:linear"#并非默认
,"subsample":1
,"max_depth":6
,"eta":0.3
,"gamma":0.3
,"lambda":1
,"alpha":0
,"colsample_bytree":1
,"colsample_bylevel":1
,"colsample_bynode":1
,"nfold":5}
param2={"silent":True#并非默认
,"obj":"reg:linear"#并非默认
,"subsample":1
,"max_depth":3
,"eta":0.05
,"gamma":20
,"lambda":3.5
,"alpha":0.2
,"colsample_bytree":0.4
,"colsample_bylevel":0.6
,"colsample_bynode":1
,"nfold":5}
param3={"silent":True#并非默认
,"obj":"reg:linear"#并非默认
,"subsample":1
,"max_depth":2
,"eta":0.05
,"gamma":0
,"lambda":1
,"alpha":0
,"colsample_bytree":1
,"colsample_bylevel":0.4
,"colsample_bynode":1
,"nfold":5}
num_round=200
cvresult1=xgb.cv(param1,dfull,num_round)
cvresult2=xgb.cv(param2,dfull,num_round)
cvresult3=xgb.cv(param3,dfull,num_round)
plt.figure(figsize=(20,10))
plt.plot(range(1,201),cvresult1.iloc[:,0],color="red",label="train,orgnal")
plt.plot(range(1,201),cvresult1.iloc[:,2],color="black",label="test,orgnal")
plt.plot(range(1,201),cvresult2.iloc[:,0],color="yellow",label="train,last")
plt.plot(range(1,201),cvresult2.iloc[:,2],color="blue",label="test,last")
plt.plot(range(1,201),cvresult3.iloc[:,0],color="pink",label="train,this")
plt.plot(range(1,201),cvresult3.iloc[:,2],color="gray",label="test,this")
plt.legend(fontsize="xx-large")#能够让图例字体变大
plt.show()
在这个调整过程中,大家可能会有几个问题:
- 一个个参数调整太麻烦,可不可以使用网格搜索呢?
当然可以!只要电脑有足够的计算资源,并且你信任网格搜索,那任何时候我们都可以使用网格搜索。只是使用的时
候要注意,首先XGB的参数非常多,参数可取的范围也很广,究竟是使用np.linspace或者np.arange作为参数的备选
值也会影响结果,而且网格搜索的运行速度往往不容乐观,因此建议至少先使用xgboost.cv来确认参数的范围,否则
很可能花很长的时间做了无用功。
并且,在使用网格搜索的时候,最好不要一次性将所有的参数都放入进行搜索,最多一次两三个。有一些互相影响的
参数需要放在一起使用,比如学习率eta和树的数量n_estimators
- 调参的时候参数的顺序会影响调参结果吗?
会影响,因此在现实中,我们会优先调整那些对模型影响巨大的参数。在这里,我建议的剪枝上的调参顺序是:
n_estimators与eta共同调节,gamma或者max_depth,采样和抽样参数(纵向抽样影响更大),最后才是正则化
的两个参数。当然,可以根据自己的需求来进行调整。
- 调参之后测试集上的效果还没有原始设定上的效果好怎么办?
如果调参之后,交叉验证曲线确实显示测试集和训练集上的模型评估效果是更加接近的,推荐使用调参之后的效果。
我们希望增强模型的泛化能力,然而泛化能力的增强并不代表着在新数据集上模型的结果一定优秀,因为未知数据集
并非一定符合全数据的分布,在一组未知数据上表现十分优秀,也不一定就能够在其他的未知数据集上表现优秀。因
此不必过于纠结在现有的测试集上是否表现优秀。当然了,在现有数据上如果能够实现训练集和测试集都非常优秀,
那模型的泛化能力自然也会是很强的
#使用pickle进行保存和调用
import pickle
dtrain=xgb.DMatrix(Xtrain,ytrain)
param={"silent":True#并非默认
,"obj":"reg:linear"#并非默认
,"subsample":1
,"max_depth":2
,"eta":0.05
,"gamma":0
,"lambda":1
,"alpha":0
,"colsample_bytree":1
,"colsample_bylevel":0.4
,"colsample_bynode":1
,"nfold":5}
num_round=200
bst=xgb.train(param,dtrain,num_round)
#保存模型
pickle.dump(bst,open("xgboostonboston.dat","wb"))
##注意,open中我们往往使用w或者r作为读取的模式,但其实w与r只能用于文本文件,当我们希望导入的不是文本文件,而
#是模型本身的时候,我们使用"wb"和"rb"作为读取的模式。其中wb表示以二进制写入,rb表示以二进制读入
#重新打开jupyter lab
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split as TTS
from sklearn.metrics import mean_squared_error as MSE
import pickle
import xgboost as xgb
data = load_boston()
X = data.data
y = data.target
Xtrain,Xtest,Ytrain,Ytest = TTS(X,y,test_size=0.3,random_state=420)
#注意,如果我们保存的模型是xgboost库中建立的模型,则导入的数据类型也必须是xgboost库中的数据类型
dtest = xgb.DMatrix(Xtest,Ytest)
#导入模型
loaded_model = pickle.load(open("xgboostonboston.dat", "rb"))
print("Loaded model from: xgboostonboston.dat")
#做预测
ypreds = loaded_model.predict(dtest)
from sklearn.metrics import mean_squared_error as MSE, r2_score
MSE(Ytest,ypreds)
r2_score(Ytest,ypreds)
#Joblib是SciPy生态系统中的一部分,它为Python提供保存和调用管道和对象的功能,处理NumPy结构的数据尤其高
#效,对于很大的数据集和巨大的模型非常有用。Joblib与pickle API非常相似
bst = xgb.train(param, dtrain, num_round)
import joblib
#同样可以看看模型被保存到了哪里
joblib.dump(bst,"xgboost-boston.dat")
loaded_model = joblib.load("xgboost-boston.dat")
ypreds = loaded_model.predict(dtest)
MSE(Ytest, ypreds)
r2_score(Ytest,ypreds)
#使用sklearn中的模型
from xgboost import XGBRegressor as XGBR
bst = XGBR(n_estimators=200
,eta=0.05,gamma=20
,reg_lambda=3.5
,reg_alpha=0.2
,max_depth=4
,colsample_bytree=0.4
,colsample_bylevel=0.6).fit(Xtrain,Ytrain)
joblib.dump(bst,"xgboost-boston.dat")
loaded_model = joblib.load("xgboost-boston.dat")
#则这里可以直接导入Xtest
ypreds = loaded_model.predict(Xtest)
MSE(Ytest, ypreds)
#在这两种保存方法下,我们都可以找到保存下来的dat文件,将这些文件移动到任意计算机上的python下的环境变量
#路径中(使用sys.path进行查看),则可以使用import来对模型进行调用。注意,模型的保存调用与自写函数的保存
#调用是两回事,大家要注意区分