XGBOOST模型介绍

前言
这是机器学习系列的第三篇文章,对于住房租金预测比赛的总结这将是最后一篇文章了,比赛持续一个月自己的总结竟然也用了一个月,牵强一点来说机器学习也将会是一个漫长的道路,后续机器学习的文章大多数以知识科普为主,毕竟自己在机器学习这个领域是个渣渣,自己学到的新知识点会分享给大家的。
前面的文章谈了谈这次比赛非技术方面的收获,对数据集的初步了解和特征工程的处理,今天主要介绍这次使用的模型--xgboost。
xgboost模型介绍
关于xgboost的原理网络上的资源很少,大多数还停留在应用层面,自己也是仅仅学习了一点应用,关于原理可以参考陈天奇博士的这篇文章
https://xgboost.readthedocs.io/en/latest/tutorials/model.html。
简单介绍:
xgboost是一个监督模型,xgboost对应的模型本质是一堆cart树。用一堆树做预测,就是将每棵树的预测值加到一起作为最终的预测值。下图就是cart树和一堆cart树的示例,用来判断一个人是否会喜欢计算机游戏:
第二张图明了如何用一堆cart树做预测,就是简单将各个树的预测分数相加。
参数介绍:
官方参数介绍看这里:https://xgboost.readthedocs.io/en/latest/parameter.html#general-parameters
比较重要的参数介绍:
“reg:linear” –线性回归。“reg:logistic” –逻辑回归。“binary:logistic” –二分类的逻辑回归问题,输出为概率。“binary:logitraw” –二分类的逻辑回归问题,输出的结果为wtx。
“count:poisson”–计数问题的poisson回归,输出结果为poisson分布。在poisson回归中,max_delta_step的缺省值为0.7。(used to safeguard optimization)
“multi:softmax”–让xgboost采用softmax目标函数处理多分类问题,同时需要设置参数num_class(类别个数)
“multi:softprob” –和softmax一样,但是输出的是ndata * nclass的向量,可以将该向量reshape成ndata行nclass列的矩阵。没行数据表示样本所属于每个类别的概率。
lambda [default=0]l2 正则的惩罚系数alpha [default=0]l1 正则的惩罚系数
lambda_bias在偏置上的l2正则。缺省值为0(在l1上没有偏置项的正则,因为l1时偏置不重要)
eta [default=0.3]为了防止过拟合,更新过程中用到的收缩步长。在每次提升计算之后,算法会直接获得新特征的权重。eta通过缩减特征的权重使提升计算过程更加保守。取值范围为:[0,1]
max_depth[default=6]数的最大深度。缺省值为6,取值范围为:[1,∞]
min_child_weight [default=1]孩子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束。在现行回归模型中,这个参数是指建立每个模型所需要的最小样本数。该成熟越大算法越conservative取值范围为: [0,∞]
xgboost参数设置的代码示例:
1xgboost参数设置代码示例: 2 3#划分数据集 4x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.01,random_state=1729) 5print(x_train.shape,x_test.shape) 6 7#模型参数设置 8xlf=xgb.xgbregressor(max_depth=10, 9learning_rate=0.1,10n_estimators=10,11silent=true,12objective='reg:linear',13nthread=-1,14gamma=0,15min_child_weight=1,16max_delta_step=0,17subsample=0.85,18colsample_bytree=0.7,19colsample_bylevel=1,20reg_alpha=0,21reg_lambda=1,22scale_pos_weight=1,23seed=1440,24missing=none)2526xlf.fit(x_train,y_train,eval_metric='rmse',verbose=true,eval_set=[(x_test,y_test)],early_stopping_rounds=100)2728#计算分数、预测29preds=xlf.predict(x_test)
比赛代码
关于xgboost只是简单的做了一个介绍,自己也仅仅懂一点应用层,原理懂得不是很多,这次xgb代码分析使用的是第一名开源代码。
导入数据集
1importpandasaspd 2importnumpyasnp 3importmatplotlib.pyplotasplt 4 5train_data=pd.read_csv('train.csv') 6test_df=pd.read_csv('test.csv') 7train_df=train_data[train_data.loc[:,'time']<3] 8val_df=train_data[train_data.loc[:,'time']==3] 910deltrain_data
以默认参数的xgb分数为准,低于此基准线2.554的模型一律不考虑。
1defxgb_eval(train_df,val_df): 2train_df=train_df.copy() 3val_df=val_df.copy() 4 5try: 6fromsklearn.preprocessingimportlabelencoder 7lb_encoder=labelencoder() 8lb_encoder.fit(train_df.loc[:,'roomdir'].append(val_df.loc[:,'roomdir'])) 9train_df.loc[:,'roomdir']=lb_encoder.transform(train_df.loc[:,'roomdir'])10val_df.loc[:,'roomdir']=lb_encoder.transform(val_df.loc[:,'roomdir'])11exceptexceptionase:12print(e)1314importxgboostasxgb15x_train=train_df.drop(['rental'],axis=1)16y_train=train_df.loc[:,'rental'].values17x_val=val_df.drop(['rental'],axis=1)18y_val=val_df.loc[:,'rental'].values1920fromsklearn.metricsimportmean_squared_error2122try:23eval_df=val_df.copy().drop('time',axis=1)24exceptexceptionase:25eval_df=val_df.copy()2627reg_model=xgb.xgbregressor(max_depth=5,n_estimators=500,n_jobs=-1)28reg_model.fit(x_train,y_train)2930y_pred=reg_model.predict(x_val)31print(np.sqrt(mean_squared_error(y_val,y_pred)),end='')3233eval_df.loc[:,'y_pred']=y_pred34eval_df.loc[:,'re']=eval_df.loc[:,'y_pred']-eval_df.loc[:,'rental']3536print('')37feature=x_train.columns38fe_im=reg_model.feature_importances_39print(pd.dataframe({'fe':feature,'im':fe_im}).sort_values(by='im',ascending=false))4041importmatplotlib.pyplotasplt42plt.clf()43plt.figure(figsize=(15,4))44plt.plot([y_train.min(),y_train.max()],[0,0],color='red')45plt.scatter(x=eval_df.loc[:,'rental'],y=eval_df.loc[:,'re'])46plt.show()4748returneval_df
原生特征的丢弃尝试
以xgb做原生特征筛选,在原生特征中丢弃后不影响分数甚至涨分的特征有:time,rentroom(涨幅明显),roomdir,livingroom,renttype(涨幅明显),subwayline(涨幅明显),subwaydis(涨幅明显)。
1#丢弃各特征后的分数 2#‘time':2.558,'neighborhood':2.592,'rentroom':2.531,'height':2.57,'tolheight':2.591,'roomarea':3 3#'roomdir':2.548,'rentstatus':2.561,'bedroom':2.584,'livingroom':2.548,'bathroom':2.590,'renttype':2.538 4#'region':2.583,'busloc':2.594,'subwayline':2.521,'subwaysta':2.569,'subwaydis':2.537,'remodcond':2.571 5forcolintrain_df.columns: 6ifcol!='rental': 7print('dropcol:{}'.format(col)) 8tmp_train_df=train_df.drop([col],axis=1) 9tmp_val_df=val_df.drop([col],axis=1)10eval_df=xgb_eval(train_df=tmp_train_df,val_df=tmp_val_df)1112#一起丢弃:2.55313tmp_train_df=train_df.copy()14tmp_val_df=val_df.copy()15tmp_train_df.drop(['time','rentroom','roomdir','livingroom','renttype','subwayline','subwaydis'],axis=1,inplace=true)16tmp_val_df.drop(['time','rentroom','roomdir','livingroom','renttype','subwayline','subwaydis'],axis=1,inplace=true)17eval_df=xgb_eval(train_df=tmp_train_df,val_df=tmp_val_df)
特征选择
一股脑加上所有特征表现不佳,使用贪心策略(前向选择、后向选择)逐个添加特征。
1train_data=pd.read_csv('train.csv') 2train_df=train_data[train_data.loc[:,'time']<3] 3val_df=train_data[train_data.loc[:,'time']==3] 4 5drop_cols=['subwayline','rentroom','time']#需要丢弃的原生特征 6 7comb_train_df=train_df.copy() 8comb_val_df=val_df.copy() 910#前向特征选择这块我是用for循环暴力搜出来的最优特征组合,最终筛选出来的特征组合为:11#['ab_height','tolrooms','area/room','busloc_rank','subwayline_rank']1213comb_train_df.loc[:,'ab_height']=comb_train_df.loc[:,'height']/(comb_train_df.loc[:,'tolheight']+1)14comb_val_df.loc[:,'ab_height']=comb_val_df.loc[:,'height']/(comb_val_df.loc[:,'tolheight']+1)1516comb_train_df.loc[:,'tolrooms']=comb_train_df.loc[:,'livingroom']+comb_train_df.loc[:,'bedroom']+comb_train_df.loc[:,'bathroom']17comb_val_df.loc[:,'tolrooms']=comb_val_df.loc[:,'livingroom']+comb_val_df.loc[:,'bedroom']+comb_val_df.loc[:,'bathroom']18comb_train_df.loc[:,'area/room']=comb_train_df.loc[:,'roomarea']/(comb_train_df.loc[:,'tolrooms']+1)19comb_val_df.loc[:,'area/room']=comb_val_df.loc[:,'roomarea']/(comb_val_df.loc[:,'tolrooms']+1)2021rank_cols=['busloc','subwayline']22forcolinrank_cols:23rank_df=train_df.loc[:,[col,'rental']].groupby(col,as_index=false).mean().sort_values(by='rental').reset_index(drop=true)24rank_df.loc[:,col+'_rank']=rank_df.index+1#+1,为缺失值预留一个0值的rank25rank_fe_df=rank_df.drop(['rental'],axis=1)26comb_train_df=comb_train_df.merge(rank_fe_df,how='left',on=col)27comb_val_df=comb_val_df.merge(rank_fe_df,how='left',on=col)28try:29comb_train_df.drop([col],axis=1,inplace=true)30comb_val_df.drop([col],axis=1,inplace=true)31exceptexceptionase:32print(e)33fordrop_colindrop_cols:34try:35comb_train_df.drop(drop_col,axis=1,inplace=true)36comb_val_df.drop(drop_col,axis=1,inplace=true)37exceptexceptionase:38pass3940#贪心策略添加特征,目前为:2.40341eval_df=xgb_eval(train_df=comb_train_df,val_df=comb_val_df
调参对于不是很大的数据集可以用sklearn的gridcvsearch来暴力调参。示例代码:
1params={'depth':[3],2'iterations':[5000],3'learning_rate':[0.1,0.2,0.3],4'l2_leaf_reg':[3,1,5,10,100],5'border_count':[32,5,10,20,50,100,200]}6clf=gridsearchcv(cat,params,cv=3)7clf.fit(x_train_2,y_train_2)
对于较大的数据集,用第一种方法耗时特别长。2. 逐个参数调,先取定其它参数,遍历第一个参数,选择最优值,再调下一个参数。省时但有的时候容易陷入局部最优。3.观察数据的分布来调整对应的参数,如树模型的叶子节点数,变量较多,叶子数少欠拟合。
预测提交
1defxgb_pred(): 2train_df=pd.read_csv('train.csv') 3test_df=pd.read_csv('test.csv') 4 5try: 6fromsklearn.preprocessingimportlabelencoder 7lb_encoder=labelencoder() 8lb_encoder.fit(train_df.loc[:,'roomdir'].append(test_df.loc[:,'roomdir'])) 9train_df.loc[:,'roomdir']=lb_encoder.transform(train_df.loc[:,'roomdir'])10test_df.loc[:,'roomdir']=lb_encoder.transform(test_df.loc[:,'roomdir'])11exceptexceptionase:12print(e)1314train_df.loc[:,'ab_height']=train_df.loc[:,'height']/(train_df.loc[:,'tolheight']+1)15test_df.loc[:,'ab_height']=test_df.loc[:,'height']/(test_df.loc[:,'tolheight']+1)16train_df.loc[:,'tolrooms']=train_df.loc[:,'livingroom']+train_df.loc[:,'bedroom']+train_df.loc[:,'bathroom']17test_df.loc[:,'tolrooms']=test_df.loc[:,'livingroom']+test_df.loc[:,'bedroom']+test_df.loc[:,'bathroom']18train_df.loc[:,'area/room']=train_df.loc[:,'roomarea']/(train_df.loc[:,'tolrooms']+1)19test_df.loc[:,'area/room']=test_df.loc[:,'roomarea']/(test_df.loc[:,'tolrooms']+1)2021rank_cols=['busloc','subwayline']22forcolinrank_cols:23rank_df=train_df.loc[:,[col,'rental']].groupby(col,as_index=false).mean().sort_values(by='rental').reset_index(drop=true)24rank_df.loc[:,col+'_rank']=rank_df.index+1#+1,为缺失值预留一个0值的rank25rank_fe_df=rank_df.drop(['rental'],axis=1)26train_df=train_df.merge(rank_fe_df,how='left',on=col)27test_df=test_df.merge(rank_fe_df,how='left',on=col)28try:29train_df.drop([col],axis=1,inplace=true)30test_df.drop([col],axis=1,inplace=true)31exceptexceptionase:32print(e)33fordrop_colindrop_cols:34try:35train_df.drop(drop_col,axis=1,inplace=true)36test_df.drop(drop_col,axis=1,inplace=true)37exceptexceptionase:38pass3940print(train_df.columns,test_df.columns)4142importxgboostasxgb43x_train=train_df.drop(['rental'],axis=1)44y_train=train_df.loc[:,'rental'].values45test_id=test_df.loc[:,'id']46x_test=test_df.drop(['id'],axis=1)474849fromsklearn.metricsimportmean_squared_error5051reg_model=xgb.xgbregressor(max_depth=8,n_estimators=1880,n_jobs=-1)52reg_model.fit(x_train,y_train,eval_set=[(x_train,y_train)],verbose=100,early_stopping_rounds=10)5354y_pred=reg_model.predict(x_test)5556sub_df=pd.dataframe({57'id':test_id,58'price':y_pred59})60sub_df.to_csv('sub.csv',index=false)6162returnnone6364xgb_pred()
第一名xgb单模分数为1.94,线下线上是一致的,总特征数二十多个,跟自己的xgb相比,自己在特征组合方向有所欠缺,自己单模特征10个左右分数在2.01。

感恩高原义诊,丁真点赞vivo影像加获奖作品
上海芯旺微正式宣布,公司引入包括硅港资本等在内的A轮融资
华为智选海雀摄像头评测:性价比高,功能丰富
智能变电站技术基本概念
小米MIUI9大战华为EMUI5.0和努比亚-nubia UI:化繁为简智能更省电
XGBOOST模型介绍
SoC编解码芯片不断发展,推动监控标准化
什么是车速传感器你知道吗?
字节跳动全球设立研发中心,满足海外业务需求
知名智能穿戴厂商华米科技正式宣布与网易云音乐达成合作
光纤激光切割机软件系统的操作流程
一种机器学习算可以识别并预测基于性别的药物不良反应差异
由视频安防到视频内容服务 萤石智能家居摄像机迸发新生机
更长续航里程版本的特斯拉Model 3批准了在中国量产
「解决方案」科聪整体解决方案助力高性能清洁机器人落地
深度解析天线功能和特性
建设5G网络是一项巨大的投资但谁会愿意付钱
智能称重智能电子秤解决方案在农贸市场的应用
Nutanix和Pure Storag公布季度财报,股东相继退股
目前市面上各种类型的主流传感器介绍