数据介绍
本题我们使用Criteo所共享的一周展示广告数据,数据中提炼了13个连续特征、26个离散特征和用户是否点击了该页面广告的标签。
数据预处理:对连续特征做等频的离散化处理,对类目特征做one hot encoding
参数说明
通用参数
- booster:基学习器类型,gbtree,gblinear 或 dart(增加了 Dropout) ,gbtree 和 dart 使用基于树的模型,而 gblinear 使用线性模型;
- silent:使用 0 会打印更多信息;
- nthread:运行时线程数;
Booster 参数
树模型
- List itemeta(learning_rate):更新过程中用到的收缩步长,(0, 1];
- gamma:在节点分裂时,只有在分裂后损失函数的值下降了,才会分裂这个节点。Gamma 指定了节点分裂所需的最小损失函数下降值。这个参数值越大,算法越保守;
- max_depth:树的最大深度,这个值也是用来避免过拟合的;
- min_child_weight:决定最小叶子节点样本权重和。当它的值较大时,可以避免模型学习到局部的特殊样本。但如果这个值过高,会导致欠拟合;
- max_delta_step:这参数限制每颗树权重改变的最大步长。如果是 0 意味着没有约束。如果是正值那么这个算法会更保守,通常不需要设置;
- subsample:这个参数控制对于每棵树,随机采样的比例。减小这个参数的值算法会更加保守,避免过拟合。但是这个值设置的过小,它可能会导致欠拟合;
- colsample_bytree:用来控制每颗树随机采样的列数的占比;
- colsample_bylevel:用来控制的每一级的每一次分裂,对列数的采样的占比;
- lambda(reg_lambda):L2 正则化项的权重系数,越大模型越保守;
- alpha(reg_alpha):L1 正则化项的权重系数,越大模型越保守;
- tree_method:树生成算法,auto, exact, approx, hist, gpu_exact, gpu_hist;
- scale_pos_weight:各类样本十分不平衡时,把这个参数设置为一个正数,可以使算法更快收敛。典型值是 sum(negative cases) / sum(positive cases);
Dart 额外参数
- sample_type:采样算法;
- normalize_type:标准化算法;
- rate_drop:前置树的丢弃率,有多少比率的树不进入下一个迭代,[0, 1];
- one_drop:设置为 1 的话每次至少有一棵树被丢弃;
- skip_drop:跳过丢弃阶段的概率,[0, 1],非零的 skip_drop 比 rate_drop 和 one_drop 有更高的优先级;
线性模型
- lambda(reg_lambda):L2 正则化项的权重系数,越大模型越保守;
- alpha(reg_alpha):L1 正则化项的权重系数,越大模型越保守;
- lambda_bias(reg_lambda_bias):L2 正则化项的偏置;
学习任务参数
- objective:这个参数定义需要被最小化的损失函数;
- base_score:初始化预测分数,全局偏置;
- eval_metric:对于有效数据的度量方法,取值范围取决于 objective;
- seed:随机数种子,相同的种子可以复现随机结果,用于调参;
建立模型步骤
- 使用pd.read_csv导入数据;
- 使用聚类算法离散化连续特征;
- 使用one hot处理类别特征;
- 建立xgboost模型;
- 使用XGBoost 提供的 cv 函数进行自动化参数选择;
- 使用 Sklearn 的 GridSearchCV 自动测试参数;
- 拟合模型,输出预测结果;
项目代码
详细调优参考:https://zhuanlan.zhihu.com/p/33700459
#! /usr/bin/env python3.6
# _*_ coding:utf-8 _*_
import xgboost as xgb
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from xgboost.sklearn import XGBClassifier
from sklearn.model_selection import GridSearchCV
from xgboost import callback
#忽略numpy的警告,因为numpy版本问题,有时使用会报警告
import warnings
warnings.filterwarnings(module='sklearn*', action='ignore', category=DeprecationWarning)
#加载数据
train = pd.read_csv(r'C:/Users/guan/Downloads/adver/train.csv')
test = pd.read_csv(r'C:/Users/guan/Downloads/adver/test.csv')
train1 = train.drop('Label', axis=1)
#不对train和test进行组合的话,两个数据内类目特征不一致,会导致onehot编码不同
train_test = train1.append(test)
#聚类离散化函数
def cluster_plot(x,column,k):
data = x[column].copy()
s = x[column][:len(x)]
data.dropna(inplace=True)#丢弃nan值
data = data.values
#使用聚类算法找出连续数据的k个聚类点
kmodel = KMeans(n_clusters=k)
kmodel.fit(data.reshape(len(data),1))
c = pd.DataFrame(kmodel.cluster_centers_, columns=['a']).sort_values(by='a')
w1 = c.rolling(window=2).mean().iloc[1:]#rolling——mean()移动平均函数
w2 = [-3] + list(w1['a']) + [s.max()]
cluster_d = pd.cut(s, bins=w2, labels=range(k))#cut函数根据bins等频分割data,labels返回分割后的标签
return cluster_d
#对I1-I13离散化
ob_feature1 = ['I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9', 'I11', 'I12', 'I13']
for o in ob_feature1:
train_test[o] = cluster_plot(train_test, o, 10)
train_test['I10'] = cluster_plot(train_test, 'I10', 4)
#处理类目特征函数
def str2int(x,column):
a = x[column].copy()
a.dropna(inplace=True)
lables = a.unique().tolist()
value_dict = {}
for index, value in enumerate(lables, start=1):
value_dict[value] = index
return x[column].apply(lambda s: value_dict.get(s))
#处理类目特征C1-C26
ob_feature2 = [* map(lambda x:'C' + str(x), list(range(27))[1:])]
for p in ob_feature2:
train_test[p] = str2int(train_test, p)
#对类目特征独热编码
ytrain=train['Label']
xgb_train_test = pd.get_dummies(train_test, columns=ob_feature2)
#加载的I1-I13为category类型,转换为float类型
for i in ob_feature1:
xgb_train_test[i] = xgb_train_test[i].astype('float64')
xgb_train_test['I10'] = xgb_train_test['I10'].astype('float64')
#分割训练集和预测集
xgb_train = xgb_train_test[:1599]
xgb_train = xgb_train.drop('Id', axis=1)
dtest = xgb_train_test[1599:]
#参数调优
#寻找最佳迭代次数函数
#cv_folds 是交叉验证的份数,early_stopping_rounds 是在多少次迭代 metrics 没有变好的情况下提前结束,
#这个函数可以找到此参数组下最佳的迭代次数(n_estimators)
def model_cv(model, X, y, cv_folds=5, early_stopping_rounds=50, seed=0):
xgb_param = model.get_xgb_params()
xgtrain = xgb.DMatrix(X, label=y)
cvresult = xgb.cv(xgb_param, xgtrain, num_boost_round=model.get_params()['n_estimators'], nfold=cv_folds,
metrics='auc', seed=seed, callbacks=[xgb.callback.print_evaluation(show_stdv=False),
xgb.callback.early_stop(early_stopping_rounds)])
num_round_best = cvresult.shape[0] - 1
print('Best round num: ', num_round_best)
return num_round_best
#建立模型
num_round = 85
seed = 0
max_depth = 10
min_child_weight = 1
gamma = 0
subsample = 0.8
colsample_bytree = 0.8
scale_pos_weight = 1
reg_alpha = 1
reg_lambda = 1e-5
learning_rate = 0.1
model = XGBClassifier(learning_rate=learning_rate, n_estimators=num_round, max_depth=max_depth,
min_child_weight=min_child_weight, gamma=gamma, subsample=subsample, reg_alpha=reg_alpha,
reg_lambda=reg_lambda, colsample_bytree=colsample_bytree, objective='binary:logistic',
nthread=4, scale_pos_weight=scale_pos_weight, seed=seed)
# num_round = model_cv(model, xgb_train, ytrain)
#自动测试参数
def gridsearch_cv(model, test_param, X, y, cv=5):
if __name__ == '__main__':#不加这会报错
gsearch = GridSearchCV(estimator=model, param_grid=test_param, scoring='roc_auc', n_jobs=4, iid=False, cv=cv)
gsearch.fit(X, y)
print('CV Results: ', gsearch.cv_results_)
print('Best Params: ', gsearch.best_params_)
print('Best Score: ', gsearch.best_score_)
return gsearch.best_params_
# 调整 max_depth,min_child_weight,1.max_depth=9,1.min_child_weight=1,1.bestscore=0.6963890572291257
# param_test1 = {
# 'max_depth': range(3, 10, 2),
# 'min_child_weight': range(1, 10, 2)}
# param_test1 = {
# 'max_depth': [8, 9, 10],
# 'min_child_weight': [1, 2]}
# gridsearch_cv(model, param_test1, xgb_train, ytrain)
#调整gamma
param_test2 = {
'gamma': [i / 10.0 for i in range(0, 5)]}
# gridsearch_cv(model, param_test2, xgb_train, ytrain)
model.fit(xgb_train, ytrain)
dtest1 = dtest.drop('Id', axis=1)
results = model.predict_proba(dtest1)#输出预测结果的概率
r = map(lambda x: results[x][1], range(len(results)))
results = pd.Series(list(r), name="Predicted")
submission = pd.concat([dtest['Id'], results], axis=1)#组合id和结果
submission.to_csv("adver_Result_xgboost.csv", index=False)#保存