前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于XGBoost的用户流失预测

基于XGBoost的用户流失预测

作者头像
HsuHeinrich
发布2023-03-29 13:58:41
1K0
发布2023-03-29 13:58:41
举报
文章被收录于专栏:HsuHeinrichHsuHeinrich

基于XGBoost的用户流失预测

小P:小H,我怎么能知道哪些用户有可能会流失呢?我这里有一份数据,你帮忙看看哪些字段更有助于寻找流失用户 小H:我只需要告诉你哪些特征更重要是吗? 小P:对对~ 小H:这个可以用机器学习的算法进行训练,最常见的就是Kaggle大杀器XGBoost

在日常业务挖掘中,XGBoost具有准确性高、数据友好等优点,可以快速地对历史数据进行训练,数据分析师也往往是基于业务角度去进行数据挖掘,因此特征都是具有业务意义的统计数据,数据质量较高。当然这种逻辑思维也会有一定的缺陷,那就是考虑的特征不全面。

本文主要介绍在日常数据挖掘过程中的一些流程化的东西,例如从数据探索->特征工程->数据建模->结果展示。

相关函数

在开始之前,介绍下自定义模块keyIndicatorMapping。这个是数据挖掘中常用的函数集合,例如变量的处理、指标评估、评估图表等。大致如下图~

可以通过%load命令加载查看这个模块内的所有函数。这里函数有点多,因为这里的部分函数会在后面的数据挖掘案例中用到。每个函数的用途和定义都有明确注释,相信大伙肯定能看懂,限于篇幅这里就不再额外讲解了。

代码语言:javascript
复制
%load '/Users/heinrich/Desktop/Heinrich-blog/数据分析使用手册/keyIndicatorMapping.py'

上述自定义模块keyIndicatorMapping如果有需要的同学可关注公众号HsuHeinrich,回复【数据挖掘-自定义函数】自动获取~

数据探索

市面上封装好的EDA库很多,这里介绍个人比较喜欢的一款sweetviz。只需简单的一句analyze即可得到所有变量的信息,以及和y的关系图。

代码语言:javascript
复制
!pip install git+https://github.com/fbdesignpro/sweetviz.git # 安装(常规安装有点问题)
代码语言:javascript
复制
# 通过sweetviz生成EDA报告 建议低特征使用
import sweetviz as sv # 自动eda
sv.analyze(raw_data, y_col).show_notebook()

image-20221221162158778

不过我更喜欢自己查看数据,sweetviz辅助探索。

导入相关库

代码语言:javascript
复制
import pandas as pd
import numpy as np
import math
from sklearn.model_selection import train_test_split  # 数据分区库
import xgboost as xgb
from sklearn.metrics import accuracy_score, auc, confusion_matrix, f1_score, \
    precision_score, recall_score, roc_curve  # 导入指标库
from imblearn.over_sampling import SMOTE  # 过抽样处理库SMOTE
import matplotlib.pyplot as plt
import prettytable  # 导入表格库
from pandas_profiling import ProfileReport # 自动eda
import sweetviz as sv # 自动eda
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import ticker
import seaborn as sns
import os
import shutil 
import toad  
from sklearn.model_selection import GridSearchCV 
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplit
import itertools
from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm

# 绘图初始化
%matplotlib inline
pd.set_option('display.max_columns', None) # 显示所有列
sns.set(style="ticks")
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

# 导入自定义模块
import sys
sys.path.append("/Users/heinrich/Desktop/Heinrich-blog/数据分析使用手册")
from keyIndicatorMapping import *

数据准备

以下数据如果有需要的同学可关注公众号HsuHeinrich,回复【数据挖掘-XGB】自动获取~

代码语言:javascript
复制
# 读取数据
raw_data = pd.read_csv('classification.csv', delimiter=',', dtype=str)  # 读取数据文件
raw_data.head()

image-20230206150542709

代码语言:javascript
复制
# 变量分类

# 通过var_class_dic函数将原始数据的特征分为不同的类【指标、日期、数值、字符串】
var_class_dic = var_class(raw_data, 'churn')
# 通过get_key函数获取相对应的列名
y_col = get_key(var_class_dic, 'y')[0]
date_col = get_key(var_class_dic, 'date')
number_col = get_key(var_class_dic, 'number')
object_col = get_key(var_class_dic, 'object')
代码语言:javascript
复制
# 更改数据类型
raw_data = raw_data.apply(pd.to_numeric, errors='ignore') # 把能转换成数字的都转换成数字,不能转化的由error=True参数控制忽略掉。
raw_data[date_col] = raw_data[date_col].apply(pd.to_datetime) # 转时间列
代码语言:javascript
复制
# 查看数据基本信息
toad.detector.detect(raw_data)

image-20230206150632442

代码语言:javascript
复制
# 数据审查
na_count = raw_data.isnull().any().sum() # 缺失值样本量
n_samples, n_features = raw_data.shape  # 总样本量 总特征数
print('samples: {0}| features: {1} | na count: {2}'.format(n_samples, n_features, na_count))
代码语言:javascript
复制
samples: 1000| features: 42 | na count: 4

单变量描述

  • 分类变量查看
代码语言:javascript
复制
# 分类单变量查看
var_eda(raw_data, 'level', y_col)
plt.show()

output_14_0

代码语言:javascript
复制
# 分类变量批量查看

# 定义最优组合
num_plots = len(object_col)
num_cols = math.ceil(np.sqrt(num_plots))
num_rows = math.ceil(num_plots/num_cols)

# 设置图片大小
fig= plt.figure(figsize = (24, 18))
# 绘制分类变量eda
for i,x in enumerate(object_col):
    plt.subplot(num_rows, num_cols, i+1)
    var_eda(raw_data, x, y_col, fonts=20)
# 设置网格图格式
matplotlib.rcParams.update({'font.size': 25})
fig.suptitle(f'distribution by {y_col}')
fig.text(-0.01, 0.5, 'count', va='center', rotation='vertical')
fig.text(1.01, 0.5, y_col, va='center', rotation='vertical')
plt.tight_layout()
plt.subplots_adjust(wspace =0.25, hspace =0.25) # 调整子图间距
plt.show()

output_15_0

  • 连续变量查看
代码语言:javascript
复制
# 连续变量分箱
raw_data_nums=number_col_bins(raw_data, number_col, y_col)
# 连续单变量查看
var_eda(raw_data_nums, 'retention_days', y_col)
plt.show()

output_18_0

代码语言:javascript
复制
# 连续变量批量查看

# 定义最优组合
num_plots = len(number_col)
num_cols = math.ceil(np.sqrt(num_plots))
num_rows = math.ceil(num_plots/num_cols)

# 设置图片大小
fig= plt.figure(figsize = (24, 18))
# 绘制分类变量eda
for i,x in enumerate(number_col):
    plt.subplot(num_rows, num_cols, i+1)
    var_eda(raw_data_nums, x, y_col, fonts=20)
# 设置网格图格式
matplotlib.rcParams.update({'font.size': 25})
fig.suptitle(f'distribution by {y_col}')
fig.text(-0.01, 0.5, 'count', va='center', rotation='vertical')
fig.text(1.01, 0.5, y_col, va='center', rotation='vertical')
plt.tight_layout()
plt.subplots_adjust(wspace =0.25, hspace =0.25) # 调整子图间距
plt.show()

output_19_0

多变量分析

  • 维度交叉
代码语言:javascript
复制
#查看变量交互情况
var_cross_eda(x='level', y='churn', df=raw_data, col='sex', row='voice', hue='reg_source')

output_21_0

  • 相关性热力图
代码语言:javascript
复制
# 特征初筛 特征较多的热图不好看,这里做个初筛降低下维度
# 缺失率>0.7,IV<0.1,相关系数>0.7
ex_lis = ['churn'] # 定义不筛选变量,例如目标变量
df_s1, drop_lst= toad.selection.select(raw_data, raw_data['churn'], 
                                                   empty=0.7, iv=0.1, 
                                                   corr=0.7, 
                                                   return_drop=True, 
                                                   exclude=ex_lis)  
print("keep:", df_s1.shape[1],  
      "drop empty:", len(drop_lst['empty']), 
      "drop iv:", len(drop_lst['iv']),  
      "drop corr:", len(drop_lst['corr']))
代码语言:javascript
复制
keep: 18 drop empty: 1 drop iv: 13 drop corr: 10
代码语言:javascript
复制
# 相关性热力图
plt.figure(figsize=(18, 12))
sns.set(font_scale=1.5)
sns.heatmap(df_s1.corr(), cmap='YlGnBu', annot=True, annot_kws = {'size':11})
plt.show()

output_23_0

特征工程

特征工程应在训练集上操作,避免加入测试集或验证集信息(主要是标签信息)。基于业务角度的特征工程较少(因为在通过sql提取数据时基本已经处理过了),这也是数据分析与算法工程师的区别之一,算法工程师在清洗数据和特征工程的工作量往往是最大的。 我们常做的特征工程就是缺失值处理、分箱(连续变量离散化)、标签转化(get_dummies、LabelEncoder、OneHotEncoder)、标准化(MinMaxScaler、StandardScaler)。下期会针对常见的不常见的特征工程做个大汇总,敬请期待吧~

代码语言:javascript
复制
# XGBoost无需过多的数据处理
X,y = raw_data.drop(y_col, axis=1),raw_data[y_col]  # 分割X,y
代码语言:javascript
复制
# 填充缺失值 因为SMOTE处理时不允许缺失值,XGBoost本身是接受空值的
X = X.fillna(X.mean())
# 样本均衡处理
model_smote = SMOTE(random_state=0)  # 建立SMOTE模型对象 设置随机种子,保持采样样本一致
X, y = model_smote.fit_resample(X,y)  # 输入数据并作过抽样处理
代码语言:javascript
复制
# 拆分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=.3, random_state=0)  # 将数据分为训练集和测试集

数据建模

模型训练

代码语言:javascript
复制
# XGB分类模型训练
param_dist = {'n_estimators': 10, 'subsample': 0.8, 'learning_rate':0.1,
              'max_depth': 10, 'n_jobs': -1, 
              'eval_metric':'logloss', 'use_label_encoder':False}
model_xgb = xgb.XGBClassifier(**param_dist)
model_xgb.fit(X_train, y_train)
代码语言:javascript
复制
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=1, eval_metric='logloss',
              gamma=0, gpu_id=-1, importance_type='gain',
              interaction_constraints='', learning_rate=0.1, max_delta_step=0,
              max_depth=10, min_child_weight=1, missing=nan,
              monotone_constraints='()', n_estimators=10, n_jobs=-1,
              num_parallel_tree=1, random_state=0, reg_alpha=0, reg_lambda=1,
              scale_pos_weight=1, subsample=0.8, tree_method='exact',
              use_label_encoder=False, validate_parameters=1, verbosity=None)

模型评估

  • 模型初评
代码语言:javascript
复制
model_confusion_metrics(model_xgb, X_test, y_test, 'test')
model_core_metrics(model_xgb, X_test, y_test, 'test')
代码语言:javascript
复制
confusion matrix for test
 +----------+--------------+--------------+
|          | prediction-0 | prediction-1 |
+----------+--------------+--------------+
| actual-0 |     192      |      22      |
| actual-1 |      63      |     159      |
+----------+--------------+--------------+
core metrics for test
 +------+----------+-----------+--------+-------+------+
| auc  | accuracy | precision | recall |   f1  |  ks  |
+------+----------+-----------+--------+-------+------+
| 0.87 |  0.805   |   0.753   | 0.897  | 0.819 | 0.64 |
+------+----------+-----------+--------+-------+------+
  • 模型参数调优
代码语言:javascript
复制
# 参数值搜索
adj_parameters = {
    'max_depth': [1, 3, 5, 10], 
    'n_estimators': [5, 10, 50, 100], 
    'learning_rate': [0.01, 0.05, 0.1, 0.2]
    }  # 指定模型中参数的范围

# 网格搜索+交叉验证
clf = xgb.XGBClassifier(**param_dist)
model_gs = GridSearchCV(clf, adj_parameters, scoring='roc_auc', cv=5) 
model_gs.fit(X_train, y_train)  # 训练交叉检验模型
print('Best score is:', model_gs.best_score_)  # 获得交叉检验模型得出的最优得分
print('Best parameter is:', model_gs.best_params_)  # 获得交叉检验模型得出的最优参数

# 获取最佳训练模型
model_xgb = model_gs.best_estimator_  # 获得交叉检验模型得出的最优模型对象
代码语言:javascript
复制
Best score is: 0.8827344902394294
Best parameter is: {'learning_rate': 0.05, 'max_depth': 10, 'n_estimators': 100}
  • 核心指标整体评估
代码语言:javascript
复制
model_confusion_metrics(model_xgb, X_test, y_test, 'test')
model_core_metrics(model_xgb, X_test, y_test, 'test')
代码语言:javascript
复制
confusion matrix for test
 +----------+--------------+--------------+
|          | prediction-0 | prediction-1 |
+----------+--------------+--------------+
| actual-0 |     195      |      19      |
| actual-1 |      50      |     172      |
+----------+--------------+--------------+
core metrics for test
 +-------+----------+-----------+--------+------+-------+
|  auc  | accuracy | precision | recall |  f1  |   ks  |
+-------+----------+-----------+--------+------+-------+
| 0.915 |  0.842   |   0.796   | 0.911  | 0.85 | 0.691 |
+-------+----------+-----------+--------+------+-------+
  • 模型区分能力与排序能力评估
代码语言:javascript
复制
fig = plt.figure(figsize=(18,12))
plt.subplot(221)
plot_roc(model_xgb, X_test, y_test, name='test')
plt.subplot(222)
plot_ks(model_xgb, X_test, y_test, name='test')
plt.subplot(223)
plot_pr(model_xgb, X_test, y_test, name='test')
plt.subplot(224)
plot_lift(model_xgb, X_test, y_test, name='test')
plt.tight_layout()
plt.show()

output_40_0

  • 模型泛化能力评估
代码语言:javascript
复制
fig = plt.figure(figsize=(18,12))
plt.subplot(221)
plot_cv_box(model_xgb, X_test, y_test, name='test')
plt.subplot(222)
plot_learning_curve(model_xgb, X_test, y_test, name='test')
plt.tight_layout()
plt.show()

output_42_0

结果展示

  • 特征重要性
代码语言:javascript
复制
# 特征重要性排序
fig = plt.figure(figsize=(8,5))
feature_topN(model_xgb, X_test)
plt.show()

# 方法2
# xgb.plot_importance(model_xgb, max_num_features=10, importance_type='gain')

output_44_0

  • 预测结果
代码语言:javascript
复制
# 输出预测结果
pre_labels = pd.DataFrame(model_xgb.predict(X_test), columns=['labels'])  # 获得预测标签
pre_pro = pd.DataFrame(model_xgb.predict_proba(X_test), columns=['pro1', 'pro2'])  # 获得预测概率
predict_pd = pd.concat((pre_labels, pre_pro), axis=1)  # 合并数据
predict_pd.head()

labels

pro1

pro2

0

1

0.118373

0.881627

1

1

0.258572

0.741428

2

1

0.106693

0.893307

3

0

0.690167

0.309833

4

0

0.911336

0.088664

  • 树形规则输出
代码语言:javascript
复制
# 输出树形规则图
xgb.to_graphviz(model_xgb, num_trees=0, yes_color='#638e5e', no_color='#a40000') 

# 保存图片
image = xgb.to_graphviz(model_xgb, num_trees=1, yes_color='#638e5e', no_color='#a40000') 
#Set a different dpi (work only if format == 'png')
image.graph_attr = {'dpi':'400'}
image.render('xgb', directory='xgbPic', format = 'pdf') # 设置参数为png、svg、dot、pdf等

image-20221221171520594

上图就是xgb.pdf文件的部分截图,to_graphviz会展示一颗树的具体规则,例如这里展示的是num_trees=0(第0颗)。

总结

日常在做数据挖掘的时候需要依场景而定,但整体步骤基本一致。读者也可自行尝试构建自己的建模风格~

机器学习算法很多,不过应重点掌握逻辑回归(弱模型质检员)、随机森林(通用模型质检员)和XGBoost(强模型质检员),当然并不是因为它们的质检员身份,而是因为这三类算法的思想很有代表性。

其它类型算法可在工作之余继续学习~

共勉~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HsuHeinrich 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基于XGBoost的用户流失预测
    • 相关函数
      • 数据探索
        • 导入相关库
        • 数据准备
        • 单变量描述
        • 多变量分析
      • 特征工程
        • 数据建模
          • 模型训练
          • 模型评估
        • 结果展示
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档