当前位置:   article > 正文

科大讯飞“电信客户流失预测挑战赛”baseline复现笔记_机器学习电信预测办理宽带比赛

机器学习电信预测办理宽带比赛

在复现此竞赛baseline之前,我通过相关资料的学习,粗略了解了集成学习算法框架,给代码加了很详细的注释。下面是复现本次算法所用的学习资料,供零基础同学参考:

网课:清华大学袁博老师“数据挖掘”课程的集成学习部分,上篇博客有发布笔记。

           B站集成学习:XGBoost, lightGBM_哔哩哔哩_bilibili

书籍:周志华老师“机器学习”第1,2,8章

博客:https://blog.csdn.net/qq_41905413/article/details/125284656,好多代码是通过此文了解的


赛事链接:https://challenge.xfyun.cn/topic/info?type=telecom-customer&ch=ds22-dw-zs01


一、赛事背景

随着市场饱和度的上升,电信运营商的竞争也越来越激烈,电信运营商亟待解决减少用户流失,延长用户生命周期的问题。对于客户流失率而言,每增加5%,利润就可能随之降低25%-85%。因此,如何减少电信用户流失的分析与预测至关重要。

鉴于此,运营商会经常设有客户服务部门,该部门的职能主要是做好客户流失分析,赢回高概率流失的客户,降低客户流失率。某电信机构的客户存在大量流失情况,导致该机构的用户量急速下降。面对如此头疼的问题,该机构将部分客户数据开放,诚邀大家帮助他们建立流失预测模型来预测可能流失的客户。

二、赛事任务

给定某电信机构实际业务中的相关客户信息,包含69个与客户相关的字段,其中“是否流失”字段表明客户会否会在观察日期后的两个月内流失。任务目标是通过训练集训练模型,来预测客户是否会流失,以此为依据开展工作,提高用户留存。

三、赛题数据

赛题数据由训练集和测试集组成,总数据量超过25w,包含69个特征字段。为了保证比赛的公平性,将会从中抽取15万条作为训练集,3万条作为测试集,同时会对部分字段信息进行脱敏。

特征字段
客户ID、地理区域、是否双频、是否翻新机、当前手机价格、手机网络功能、婚姻状况、家庭成人人数、信息库匹配、预计收入、信用卡指示器、当前设备使用天数、在职总月数、家庭中唯一订阅者的数量、家庭活跃用户数、....... 、过去六个月的平均每月使用分钟数、过去六个月的平均每月通话次数、过去六个月的平均月费用、是否流失

四、评估标准

本次竞赛的评价标准采用AUC指标,正样本为1,评估代码参考:

 五、赛题baseline

1.导入模块

  1. import pandas as pd # 用来导入csv文件
  2. # import os # 未用到的包
  3. # import gc # 未用到的包
  4. import lightgbm as lgb # LightGBM是一个梯度提升框架,使用基于树的学习算法,在xgboost上做了改进,速度更快,集成学习框架中的梯度提升算法
  5. import xgboost as xgb # 极度梯度提升,集成学习框架中的梯度提升算法
  6. from catboost import CatBoostRegressor # 一种集成学习算法
  7. # from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge # 未用到的包
  8. # from sklearn.preprocessing import MinMaxScaler # 未用到的包
  9. # from gensim.models import Word2Vec # 未用到的包
  10. # import math # 未用到的包
  11. import numpy as np # 用来存储和处理大型矩阵
  12. # from tqdm import tqdm # 进度条库,未用到的包
  13. from sklearn.model_selection import StratifiedKFold, KFold
  14. from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, log_loss # roc_auc_score,即使用AUC作为评估指标
  15. # import matplotlib.pyplot as plt # 未用到的包
  16. # import time # 未用到的包
  17. import warnings
  18. warnings.filterwarnings('ignore')

2.数据预处理

  1. # 1数据预处理
  2. # pd.set_option('display.max_columns', None) # 设置显示时显示所有列
  3. train = pd.read_csv('train.csv') # 训练集,带有“是否流失”标签
  4. test = pd.read_csv('test.csv') # 测试集
  5. # print(train.head()) # 读取前5行数据
  6. # train.isnull().any() # 检测是否有缺失数据,本题不必验证
  7. # 链接数据
  8. # axis=0表示按行拼接train(15万行)和test(3万行),拼接后的data有18万行
  9. # ignore_index=True表示忽略两个数据集原有的索引(分别是0-149999;0-29999),从头到尾重新赋索引值(0-179999)
  10. data = pd.concat([train, test], axis=0, ignore_index=True)

3.训练数据/测试数据准备

  1. # 2训练数据/测试数据准备
  2. # 导出特征名称
  3. features = [f for f in data.columns if f not in ['是否流失','客户ID']] # 获取67个客户字段,不包括'是否流失','客户ID'字段
  4. train = data[data['是否流失'].notnull()].reset_index(drop=True) # 取拼接数据集里的训练集,并重置索引
  5. test = data[data['是否流失'].isnull()].reset_index(drop=True) # 取拼接数据集里的测试集,并重置索引
  6. # 分别对测试集,训练集提取特征数据
  7. x_train = train[features] # 处理后的训练集,字段67个,非原来的69个(数据的多维特征)
  8. x_test = test[features] # 处理后的测试集,字段67个,非原来的68个
  9. # 提取训练集标签
  10. y_train = train['是否流失'] # 获取训练集中字段'是否流失'的值,共15万个(标注信息)

4.构建模型

  1. # 3构建模型 clf:classifier 分类器(有监督学习就是找一个x_train到y_train的映射)
  2. # clf:为模型库函数,train_x:训练数据集特征数据,train_y:训练数据集标签
  3. # test_x:测试集特征数据,clf_name:选择不同的模型,对应不同的模型名称
  4. def cv_model(clf, train_x, train_y, test_x, clf_name):
  5. folds = 5 # 代表交叉验证中的折数
  6. seed = 2022 # 随机种子
  7. # 交叉验证函数,这里是5折随机交叉验证
  8. kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
  9. # 声明变量train和test用于存储预测结果
  10. train = np.zeros(train_x.shape[0])
  11. test = np.zeros(test_x.shape[0])
  12. # 声明列表 cv_scores 用于存储每折交验证后结果得分
  13. cv_scores = []
  14. # 循环遍历每折交叉验证
  15. for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
  16. print('************************************ {} ************************************'.format(str(i + 1)))
  17. # 提取对应的训练集特征数据、验证集特征数据及其对应标签
  18. trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]
  19. # 根据模型名称开始判断选择相应模型
  20. if clf_name == "lgb":
  21. # 由于模型需要加载特定数据格式、类型,因此在此处完成数据格式、类型转换
  22. train_matrix = clf.Dataset(trn_x, label=trn_y)
  23. valid_matrix = clf.Dataset(val_x, label=val_y)
  24. '''
  25. params是一个字典,里面包含着训练中的参数关键字和对应的值,形式是params = {‘booster’:’gbtree’,’eta’:0.1}
  26. params中参数解释:
  27. objective: 目标函数的选择要根据问题确定,如果是回归问题 ,一般是 reg:linear , reg:logistic , count:poisson 如果是分类问题,一般是binary:logistic ,rank:pairwise
  28. booster:表示应用的弱学习器的类型, 推荐用默认参数可选的有gbtree, dart, gblinear
  29. a: gblinear是线性模型,表现很差,接近一个LASSO
  30. b: dart是树模型的一种,思想是每次训练新树的时候,随机从前m轮的树中扔掉一些,来避免过拟合
  31. gbtree即是论文中主要讨论的树模型,推荐使用
  32. eval_metric:根据objective而定
  33. a: 模型性能度量方法,主要根据objective而定,也可以自定义一些,下面列举一些常见的
  34. b: rmse : root mean square error 也就是平方误差和开根号
  35. c: mae : mean absolute error 误差的绝对值再求平均
  36. d: auc : area under curve roc曲线下面积
  37. e: aucpr: area under the pr curve pr曲线下面积
  38. gamma:叶子节点分裂时所需要的最小的损失减少量,这个值越大,叶子节点越难分裂,所以算法就越保守
  39. min_child_weight:
  40. a: 最小的叶子节点权重
  41. b: 在普通的GBM中,叶子节点样本没有权重的概念,其实就是等权重的,也就相当于叶子节点样本个数
  42. c: 越小越没有限制,容易过拟合,太高容易欠拟合
  43. max_depth:
  44. a: 树的最大深度
  45. b: 这个值对结果的影响算是比较大的了,值越大,树的深度越深,模型的复杂度就越高,就越容易过拟合
  46. c: 注意如果这个值被设置的较大,会吃掉大量的内存
  47. d: 一般来说比价合适的取值区间为[3, 10]
  48. lambda: 损失函数中的L2正则化项的系数,类似RidgeRegression,减轻过拟合
  49. sub_sample:
  50. a: 样本抽样比例
  51. b: 在每次训练的随机选取sub_sample比例的样本来作为训练样本
  52. colsample_by*:
  53. a: 这里实际上有3个参数,借助了随机森林的特征抽样的思想,3个参数可以同时使用
  54. b: colsample_bytree 更常用,每棵树的特征抽样比例
  55. c: colsample_bylevel 每一层深度的树特征抽样比例
  56. d: colsample_bynode 每一个节点的特征抽样比例
  57. eta: 就是常说的学习速率,控制每一次学习的权重缩减,给后来的模型提供更多的学习空间
  58. tree_method:
  59. xgboost中使用的树约束算法。xgboost的分布式训练支持 hist 和 approx。
  60. a: auto:使用启发式选择最快的方法。中小数据集:精确的贪心算法;大数据集:近似算法
  61. b: exact:精确的贪心算法
  62. c: approx:近似的贪心算法,使用分位数图和梯度直方图
  63. d: hist: 快速直方图优化近似贪心算法,它使用了一些性能改进,比如垃圾缓存
  64. e: gpu_exact: exact 算法的GPU实现
  65. f: gpu_hist:hist 算法的GPU实现
  66. nthread:
  67. a: 训练过程中的并行线程数
  68. b: 如果用的是sklearn的api,那么使用n_jobs来代替
  69. seed: 随机数种子
  70. silent: 不推荐使用,推荐使用verbosity参数来代替,功能更强大
  71. train_matrix: 训练的数据
  72. num_boost_round: 这是指提升迭代的个数
  73. evals: 这是一个列表,用于对训练过程中进行评估列表中的元素。形式是evals = [(dtrain,’train’),(dval,’val’)]或者是evals = [(dtrain,’train’)],
  74. 对于第一种情况,它使得我们可以在训练过程中观察验证集的效果。
  75. verbose_eval: (可以输入布尔型或数值型),也要求evals 里至少有一个元素。如果为True ,则对evals中元素的评估结果会输出在结果中;如果输入数字,假设为5,则每隔5个迭代输出一次。
  76. early_stopping_rounds:
  77. 早期停止次数 ,假设为100,验证集的误差迭代到一定程度在100次内不能再继续降低,就停止迭代。
  78. 这要求evals 里至少有一个元素,如果有多个,按最后一个去执行。返回的是最后的迭代次数(不是最好的)。
  79. 如果early_stopping_rounds存在,则模型会生成三个属性,bst.best_score,bst.best_iteration,和bst.best_ntree_limit。
  80. '''
  81. params = {
  82. 'boosting_type': 'gbdt',
  83. 'objective': 'binary',
  84. 'metric': 'auc',
  85. 'min_child_weight': 5,
  86. 'num_leaves': 2 ** 5,
  87. 'lambda_l2': 10,
  88. 'feature_fraction': 0.7,
  89. 'bagging_fraction': 0.7,
  90. 'bagging_freq': 10,
  91. 'learning_rate': 0.2,
  92. 'seed': 2022,
  93. 'n_jobs': -1
  94. }
  95. # 训练模型
  96. model = clf.train(params, train_matrix, 50000, valid_sets=[train_matrix, valid_matrix],categorical_feature=[], verbose_eval=3000, early_stopping_rounds=200)
  97. # 利用训练好的模型对验证集数据进行预测,验证模型效果
  98. val_pred = model.predict(val_x, num_iteration=model.best_iteration)
  99. # 利用训练好的模型对测试集数据进行预测
  100. test_pred = model.predict(test_x, num_iteration=model.best_iteration)
  101. print(list(sorted(zip(features, model.feature_importance("gain")), key=lambda x: x[1], reverse=True))[:20])
  102. if clf_name == "xgb":
  103. # 由于模型需要加载特定数据格式、类型,因此在此处完成数据格式、类型转换
  104. train_matrix = clf.DMatrix(trn_x, label=trn_y)
  105. valid_matrix = clf.DMatrix(val_x, label=val_y)
  106. test_matrix = clf.DMatrix(test_x)
  107. # params为模型中指定参数,可参照上方关于xgb模型参数解释
  108. params = {'booster': 'gbtree', # 使用的弱学习器,有两种选择:gbtree(默认)和gblinear;
  109. # gbtree是基于树形的提升计算,gblinear是基于线性模型的提升计算
  110. 'objective': 'binary:logistic', # 二分类的logistic,objective用来定义学习任务及相应的损失函数
  111. 'eval_metric': 'auc',
  112. 'gamma': 1, # 叶子节点进行划分时需要损失函数价绍德最小值
  113. 'min_child_weight': 1.5,
  114. 'max_depth': 5, # 树的最大深度,缺省值为6
  115. 'lambda': 10, # 正则化权重
  116. 'subsample': 0.7, # 训练模型的样本占总样本的比例,用于防止过拟合
  117. 'colsample_bytree': 0.7, # 建立树时对特征进行采样的比例
  118. 'colsample_bylevel': 0.7,
  119. 'eta': 0.2, # 加法模型中使用的收缩步长
  120. 'tree_method': 'exact',
  121. 'seed': 2020, # 随机数种子,随便取
  122. 'nthread': 36, # XGBoost运行时的线程数,缺省时是当前系统获得的最大线程数
  123. "silent": True, # True表示以缄默方式运行,False则打印运行时的信息(默认)
  124. }
  125. watchlist = [(train_matrix, 'train'), (valid_matrix, 'eval')]
  126. # xgboost模型训练
  127. model = clf.train(params, train_matrix, num_boost_round=50000, evals=watchlist, verbose_eval=3000,early_stopping_rounds=200)
  128. # 利用训练好的模型对验证集数据进行预测,验证模型效果
  129. val_pred = model.predict(valid_matrix, ntree_limit=model.best_ntree_limit)
  130. # 利用训练好的模型对测试集数据进行预测
  131. test_pred = model.predict(test_matrix, ntree_limit=model.best_ntree_limit)
  132. if clf_name == "cat":
  133. params = {'learning_rate': 0.2,
  134. 'depth': 5,
  135. 'l2_leaf_reg': 10,
  136. 'bootstrap_type': 'Bernoulli',
  137. 'od_type': 'Iter',
  138. 'od_wait': 50,
  139. 'random_seed': 11,
  140. 'allow_writing_files': False
  141. }
  142. model = clf(iterations=20000, **params)
  143. model.fit(trn_x, trn_y, eval_set=(val_x, val_y),cat_features=[], use_best_model=True, verbose=3000)
  144. val_pred = model.predict(val_x)
  145. test_pred = model.predict(test_x)
  146. train[valid_index] = val_pred
  147. test = test_pred / kf.n_splits
  148. cv_scores.append(roc_auc_score(val_y, val_pred))
  149. print(cv_scores)
  150. # 输出K折交叉验证结果
  151. print("%s_scotrainre_list:" % clf_name, cv_scores)
  152. # 输出K折交叉验证结果的均值
  153. print("%s_score_mean:" % clf_name, np.mean(cv_scores))
  154. # 输出K折交叉验证结果标准差
  155. print("%s_score_std:" % clf_name, np.std(cv_scores))
  156. return train, test
  157. # 定义lgb模型,进行调用
  158. def lgb_model(x_train, y_train, x_test):
  159. lgb_train, lgb_test = cv_model(lgb, x_train, y_train, x_test, "lgb")
  160. return lgb_train, lgb_test
  161. # 定义xgb模型,进行调用
  162. def xgb_model(x_train, y_train, x_test):
  163. xgb_train, xgb_test = cv_model(xgb, x_train, y_train, x_test, "xgb")
  164. return xgb_train, xgb_test
  165. # 定义cat模型,进行调用
  166. def cat_model(x_train, y_train, x_test):
  167. cat_train, cat_test = cv_model(CatBoostRegressor, x_train, y_train, x_test, "cat")
  168. return cat_train, cat_test
  169. lgb_train, lgb_test = lgb_model(x_train, y_train, x_test)

5.提交结果

  1. # 4提交结果,保存测试集预测结果至test_sub.csv文件中
  2. test['是否流失'] = lgb_test
  3. test[['客户ID','是否流失']].to_csv('test_sub.csv', index=False)

分别使用LightGBM,XGBoost,CATBOOST三种算法运行了代码,以下是提交到网站后获得的分数:

LightGBM算法设置交叉验证折数分别为5,7的结果

XGBoost算法设置交叉验证折数分别为5,7的结果

CATBOOST算法结果

 

 总结:

由返回分数可见,LightGBM算法是三个算法中最优秀的,而且增加交叉验证折数能获得更好的结果,但是代码运行时长也会增加,最长的一次差不多两个小时。通过对本次竞赛代码的学习,我对机器学习解决问题的流程有了具体的认识。此外,之后要学会利用云端的免费算力资源帮助自己训练模型,否则自己的笔记本很难承受长时间的cpu满负荷运行,比如Kaggle Kernels。后续还需要通过特定的任务来了解更多不同的模型,做好总结。

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

闽ICP备14008679号