当前位置:   article > 正文

xgboost分类_XGBoost多分类预测

机器学习增加衍生变量

88334ef7634a4d9c85e2540898323ce2.png

1. 数据预处理

  1. 对缺失值进行填充
  2. 根据业务增加衍生变量,比如占比、分级化、TOP打横等等
  3. 根据业务删除相应的指标
  4. 对离散型的指标进行one-hot序列编码

2. 模型选择

可以进行多分类预测的模型有 逻辑回归、决策树、神经网络、随机森林、xgboost,发现效果排名靠前的依次是 XGBoost、随机森林、决策树

3. 模型调用

通过调用python相关包,对XGBoost分类模型进行参数调整,使模型效果更好。

  1. # 导入的包
  2. from xgboost.sklearn import XGBClassifier
  3. # 调用XGBClassifier方法,括号内都是默认的参数值,可对这些参数进行调整
  4. XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
  5. colsample_bynode=1, colsample_bytree=1, gamma=0,
  6. learning_rate=0.1, max_delta_step=0, max_depth=8,
  7. min_child_weight=1, missing=None, n_estimators=100, n_jobs=1,
  8. nthread=None, num_class=5, objective='multi:softprob',
  9. random_state=0, reg_alpha=0, reg_lambda=1, scale_pos_weight=1,
  10. seed=None, silent=None, subsample=1, verbosity=1)

4. 参数说明

1. 常调整的参数

  • booster:默认为'gbtree'
    • ‘gbtree‘:树模型作为基分类器,比线性模型的效果好很多
    • ’gblinear’ :线性模型作为基分类器
  • n_estimators:默认为 100
    • 估计器的数量
  • learning_rate:默认为 0.1
    • 学习率,控制每次迭代更新权重时的步长。值越小,训练的越慢。
    • 取值范围:[0,1]。典型值为0.001, 0.003, 0.01, 0.03, 0.1, 0.2, 0.3
  • objective:目标参数,需要被最小化的损失函数,默认值为‘binary:logistic‘
    • ‘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‘:采用softmax目标函数处理多分类问题,需要多设置一个参数num_class(类别个数),返回预测的类别(不是概率)。
  • ‘multi:softprob‘:和multi:softmax参数类似,但是输出结果是每个样本属于各个类别的概率。
  • ‘rank:pairwise‘:set XGBoost to do ranking task by minimizing the pairwise loss
  • max_depth :默认为3
    • 树的最大深度,用于防止过拟合问题。
    • 越大越容易过拟合。
    • 典型值:3~10
  • min_child_weight:默认为 1
    • 拆分节点权重和阈值
    • 如果节点的样本权重和小于该阈值,就不再进行拆分。在线性回归模型中,这个是指建立每个模型所需要的最小样本数。
    • 值越大,算法越保守。取值范围为:[0,∞]
  • gamma:默认为 0
    • 损失阈值,在树的一个叶节点上进一步分裂所需的最小损失减少量
    • gamma值越大,算法越保守。
    • 取值范围为:[0,∞]
    • 典型值:0.1、0.2
  • scale_pos_weight :默认为 1
    • 处理样本不平衡问题。在样本高度不平衡时,将参数设置大于0,可以加快算法收敛
  • nthread:默认为 None
    • 主要用于并行计算,系统的内核数需要作为变量。如果希望运行所有的内核,就不需要设置该参数,程序会自己检测到该值。
  • silent:默认为 True
    • silent=True时,不输出中间过程(默认)
    • silent=False时,输出中间过程
  • n_jobs:默认为1
    • 线程数目

2. 不经常调整的参数

  • base_score :默认为 0.5
    • 所有实例的初始预测得分,整体偏倚
  • reg_alpha:默认为 0
    • 权重的 L1 正则化项(和Lasso regression类似)。这个主要是用在数据维度很高的情况下,可以提高运行速度。
  • reg_lambda:默认为 1
    • 控制XGBoost模型复杂度的权重值的L2正则化项参数
    • 参数越大,模型越不容易过拟合
  • subsample :默认为1
    • 随机选取一定比例的样本来训练树。设置为0.5,则意味着XGBoost将从整个样本集合中随机的抽取出50%子样本建立树模型,这能够防止过拟合。
    • 取值范围为:(0,1]。减小这个参数的值,算法会更加保守,避免过拟合。但是,如果这个值设置得过小,它可能会导致欠拟合。
    • 典型值:0.5-1。
  • colsample_bytree :默认为 1
    • 指的是每棵树随机选取的特征的比例取值范围(0,1]。
    • 取值范围(0,1]。
  • colsample_bylevel :默认为 1
    • 指的是树的每个层级分裂时子样本的特征所占的比例,这个一般很少用。因为subsample和colsample_bytree组合做的事与之类似。
  • max_delta_step:默认为 0
    • 每棵树的最大权重估计。如果它的值被设置为0,意味着没有约束;如果它被设置为一个正值,能够权重的变化将会变得相对保守。通常这个参数不会被使用,但如果是极度不平衡的逻辑回归将会有所帮助。把它范围设置为1-10之间也许能控制更新。 取值范围为:[0,∞]
  • seed:默认为 None
    • 随机数种子,设置它可以复现随机数据的结果,也可以用于调整参数。
  • missing:默认为 None
    • 在数据中,标注为缺失值的表示。如果为None,则默认为np.nan
  • random_state:默认为 0

5. XGBoost多分类模型python脚本

  1. import pandas as pd
  2. from sklearn.model_selection import train_test_split
  3. from xgboost.sklearn import XGBClassifier
  4. from sklearn.metrics import classification_report
  5. from sklearn.metrics import f1_score, precision_score, recall_score
  6. from sklearn.externals import joblib # 将模型导出所需包
  7. def get_cust_age_stage(birth_year):
  8. """根据出生年份获取年龄段"""
  9. age_stage = []
  10. for i in range(len(birth_year)):
  11. if int(birth_year[i]) == 0:
  12. age_stage.append("未知")
  13. elif int(birth_year[i]) < 1960:
  14. age_stage.append("60前")
  15. elif int(birth_year[i]) < 1970:
  16. age_stage.append("60后")
  17. elif int(birth_year[i]) < 1980:
  18. age_stage.append("70后")
  19. elif int(birth_year[i]) < 1990:
  20. age_stage.append("80后")
  21. elif int(birth_year[i]) < 2000:
  22. age_stage.append("90后")
  23. elif int(birth_year[i]) >= 2000:
  24. age_stage.append("00后")
  25. else:
  26. age_stage.append("未知")
  27. return age_stage
  28. def get_top5_onehot(data):
  29. """对c字段排名top5的进行one hot"""
  30. # 获取top5的值
  31. c_top5_counts = data['c'].value_counts()[:5]
  32. c_top5_names = list(c_top5_counts.keys())
  33. # 进行one-hot编码,只保留top5的列
  34. c_one_hot = pd.get_dummies(data['c'])
  35. c_top5 = c_one_hot[c_top5_names]
  36. # 将top5的列合并到data
  37. data = data.join(c_top5)
  38. return data
  39. def get_quantile_20_values(input_data):
  40. """按照分位数切分为20等分"""
  41. grade = pd.DataFrame(columns=['quantile', 'value'])
  42. for i in range(0, 21):
  43. grade.loc[i, 'quantile'] = i / 20.0
  44. grade.loc[i, 'value'] = input_data.quantile(i / 20.0)
  45. cut_point = grade['value'].tolist() # 20等分的分位数的值
  46. # 对20等分的分位数的值 进行去重
  47. s_unique = []
  48. for i in range(len(cut_point)):
  49. if cut_point[i] not in s_unique:
  50. s_unique.append(cut_point[i])
  51. return s_unique
  52. def get_quantile_interregional(s_unique):
  53. """根据去重后的分位数,构造区间"""
  54. interregional = []
  55. for i in range(1, len(s_unique)):
  56. interregional.append([i, s_unique[i - 1], s_unique[i]])
  57. if i == len(s_unique) - 1 and len(interregional) < 20:
  58. interregional.append([i + 1, s_unique[i], s_unique[i]])
  59. return interregional
  60. def get_current_level(item_data,interregional):
  61. """根据分位数区间获取当前数所对应的的级别"""
  62. level = 0
  63. for i in range(len(interregional)):
  64. if item_data >= interregional[i][1] and item_data <interregional[i][2]:
  65. level = interregional[i][0]
  66. break
  67. elif interregional[i][1] == interregional[i][2]:
  68. level = interregional[i][0]
  69. break
  70. return level
  71. def get_division_level(input_data):
  72. """根据分位数划分对应级别"""
  73. # 获取去重后20等分的分位数的值
  74. s_unique = get_quantile_20_values(input_data)
  75. # 构造分位数区间,输出格式[index,下限,上限] 区间为左闭右开
  76. interregional = get_quantile_interregional(s_unique)
  77. # 根据分位数区间对数据划分不同等级
  78. quantile_20_level = []
  79. for item in input_data:
  80. quantile_20_level.append(get_current_level(item, interregional))
  81. return quantile_20_level
  82. def pre_processing(data):
  83. """对数据进行预处理"""
  84. # 1. 增加衍生变量
  85. # 年龄
  86. data['年龄'] = get_cust_age_stage(data['出生年份'])
  87. # 本月平均时长
  88. data['本月平均时长'] = data['本月时长'].div(data['本月次数'],axis=0)
  89. data['g'] = data['a'] - data['b']
  90. # 2. 填充数据
  91. col_name_0 = ['a', 'b','g', 'k'] # 需要填充为数字0的指标名
  92. values = {}
  93. for i in col_name_0:
  94. values[i] = 0
  95. # 不加inplace=True,数据不会被填充
  96. data.fillna(value=values, inplace=True)
  97. data.fillna({'m':'未知', 'z':'未知'}, inplace=True) # m/z列需要填充为字符串
  98. # 对c指标进行one-hot处理
  99. data = get_top5_onehot(data)
  100. # 3. 分级化
  101. col_name_level = ['d', 'e', 'f']
  102. for i in range(len(col_name_level)):
  103. new_col_name = col_name_level[i] + "_TILE20"
  104. data[new_col_name] = get_division_level(data[col_name_level[i]])
  105. return data
  106. def get_model_columns(input_data):
  107. """获取建模指标列名,列表类型"""
  108. total_col_names = input_data.columns
  109. del_col_names = ['a','b','c']
  110. model_col_names = [i for i in total_col_names if i not in del_col_names]
  111. return model_col_names
  112. def importance_features_top(model_str, model, x_train):
  113. """打印模型的重要指标,排名top10指标"""
  114. print("打印XGBoost重要指标")
  115. feature_importances_ = model.feature_importances_
  116. feature_names = x_train.columns
  117. importance_col = pd.DataFrame([*zip(feature_names, feature_importances_)],
  118. columns=['a', 'b'])
  119. importance_col_desc = importance_col.sort_values(by='b', ascending=False)
  120. print(importance_col_desc.iloc[:10, :])
  121. def print_precison_recall_f1(y_true, y_pre):
  122. """打印精准率、召回率和F1值"""
  123. print("打印精准率、召回率和F1值")
  124. print(classification_report(y_true, y_pre))
  125. f1 = round(f1_score(y_true, y_pre, average='macro'), 2)
  126. p = round(precision_score(y_true, y_pre, average='macro'), 2)
  127. r = round(recall_score(y_true, y_pre, average='macro'), 2)
  128. print("Precision: {}, Recall: {}, F1: {} ".format(p, r, f1))
  129. def xgboost_model(x_train,y_train):
  130. """用XGBoost进行建模,返回训练好的模型"""
  131. xgboost_clf = XGBClassifier(min_child_weight=6,max_depth=15,
  132. objective='multi:softmax',num_class=5)
  133. print("-" * 60)
  134. print("xgboost模型:", xgboost_clf)
  135. xgboost_clf.fit(x_train, y_train)
  136. # # 打印重要性指数
  137. importance_features_top('xgboost', xgboost_clf, x_train)
  138. # 保存模型
  139. joblib.dump(xgboost_clf, './model/XGBoost_model_v1.0')
  140. return xgboost_clf
  141. filename = "./文件对应路径.xlsx"
  142. data = pd.read_excel(filename)
  143. # 数据预处理,包括填充数据,增加衍生变量、分级化、top打横
  144. data_processed = pre_processing(data)
  145. # 根据业务删除某些变量,获取建模所需指标
  146. model_col_names = get_model_columns(input_data)
  147. model_data = data_processed[model_col_names]
  148. # 将数据拆分为输入数据和输出数据
  149. data_y = model_data['label']
  150. data_x = model_data.drop(['label'], axis=1)
  151. # 数据集拆分为训练集和测试集两部分 使用随机数种子,确保可以复现
  152. x_train, x_test, y_train, y_test = train_test_split(data_x,data_y,
  153. test_size=0.3,random_state=1)
  154. # 建模
  155. xgboost_clf = xgboost_model(x_train, y_train)
  156. # 预测
  157. pre_y_test = xgboost_clf.predict(x_test)
  158. # 打印测试集的结果信息,包含precision、recall、f1-socre
  159. print("-" * 30, "测试集", "-" * 30)
  160. print_precison_recall_f1(y_test, pre_y_test)
  • 如果需要将数据集划分为训练集、测试集和验证集的话,采用下面的代码即可
  1. # 1、将数据划分为训练集、测试集两部分 使用随机数种子,确保可以复现
  2. x_train, x_test_valid, y_train, y_test_valid =train_test_split(data_x,data_y,
  3. test_size=0.4,random_state=1)
  4. # 2、将测试集数据划分为 测试集 和 验证集 两部分
  5. x_test, x_vaild, y_test, y_valid = train_test_split(x_test_valid, y_test_valid,
  6. test_size=0.5,random_state=1)
  • 在训练模型的时候,也可以选择对应的评测函数eval_metric。常见的有:
    • “rmse”:均方根误差
    • “logloss”:负对数似然函数值
    • “error”:二分类错误率(阈值为0.5) . 大于0.5的是正例,否则是负例
    • “merror”:多分类错误率.
    • “mlogloss”:多分类 logloss 损失函数
    • “auc”:曲线下的面积
  1. eval_set = [(x_train, y_train), (x_test, y_test)]
  2. xgboost_clf.fit(x_train, y_train, eval_metric="merror", eval_set=eval_set,
  3. verbose=True)

总结

在调参的过程中,对这句话有了深刻的理解,"数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已"。当你调参效果都提升不大的时候,可以考虑再重新对数据和特征进行研究和处理,效果会有所提高。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/97486
推荐阅读
相关标签
  

闽ICP备14008679号