导读: 大家好,我是云朵君,最近有很多小伙伴留言说,想要我分享一些数据挖掘实战案例。今天就来给大家分享一个这么一个项目。本次数据挖掘主要目的是理清楚数据挖掘的一般过程与基本方法,并没有进行太过复杂的挖掘分析,或许会存在很多分析不够深入的情况,欢迎各位大佬交流讨论。文章较长,建议收藏转发阅读。
app客户流失及客户行为偏好分析(仅供参考) 20**年*月 - 20**年*月 分类信息app,通过数据挖掘分析影响用户流失的关键因素、深入了解用户行为偏好以此做出调整,提升客户留存率,增强客户黏性,并通过随机森林算法预测客户流失,通过特征创造使模型分数提高2个百分点。 项目内容:
- 探索数据分布,缺失情况,针对性的进行缺失值填补,对于缺失较少的重要特征选择随机森林缺失填补法,使用3sigma、箱型图分析等对异常值进行处理,对分类型变量进行编码。
- 使用方差过滤、F检验过滤掉一部分特征,进行WOE分箱,对每个特征分箱结果进行可视化,分析每个特征分箱情况并以此分析 用户行为偏好,使用各个特征的IV值进一步筛选特征。
- 训练随机森林模型,模型调参、评估,输出模型,以此模型对用户流失进行预测,以便针对性地挽留用户。训练逻辑回归模型,通过其算法可解释性强的特点(特征系数)来对用户流失关键因素进行阐述。
使用工具: python、pandas、numpy、matplotlib、seaborn、sklearn库
在做一个数据挖掘项目前,需要预先拟好主要思路,比如目标是什么,先做什么,再做什么,有哪些注意事项等等。
本次案例内容,包括数据、代码均可在公众号「数据STUDIO」后台回复【210514】获取!
项目背景
项目目的
深入了解用户画像及行为偏好,挖掘出影响用户流失的关键因素,并通过算法预测客户访问的转化结果,从而更好地完善产品设计、提升用户体验!
数据说明
此次数据是携程用户一周的访问数据,为保护客户隐私,已经将数据经过了脱敏,和实际商品的订单量、浏览量、转化率等有一些差距,不影响问题的可解性。
模型选择
本次项目主要从三个方面来分析,客户流失、客户转化和客户价值。
- 客户流失
目标变量label表示是否流失,是0-1二分类问题,目的是需要挖掘出关键因素,拟选用逻辑回归做模型训练及预测。
- 客户转化
预测客户转化率,是连续型变量预测问题,拟选择集成数模型--随机森林回归。
- 客户价值
为了更加细致的挖掘客户价值,选择RFM客户价值模型进行分析。
数据预处理
数据探索
具体理论可以参见Python数据分析之数据探索分析(EDA)。
缺失值矩阵可视化
缺失值可视化两种思路,定性化和定量化两个思路。直接定性观察整体缺失情况,即用第三方模块missingno
绘制矩阵图,下图中白色部分为缺失值。
import missingno as msno
msno.matrix(data)
缺失值分布
另一个是定量化分析,即计算每个字段的缺失值比例,通过核密度估计图绘制缺失值分布图。
右下图可见缺失值分布是双峰分布,第一高峰在0左右,表明大部分数据是完整的或仅存在少部分缺失。第二高峰在30%~40%左右,因此对于缺失值的处理,需要根据不同缺失情况定制不同的缺失值处理方案。
代码语言:javascript复制import seaborn as sns
sns.kdeplot(null['缺失比'],shade=True)
经过一系列探索分析,本次数据有以下特点:
- 689945条记录, 49个特征
- 两个标签,一个分类标签,一个连续型标签
- 数据缺失严重
- 存在多个偏态,需与业务人员沟通,以便更好地处理
- 无重复值
数据清洗
数据清洗主要包括去除重复值、处理缺失值、处理异常值、⽣成衍生变量等操作。其中处理顺序根据实际处理过程涉及的问题而定,这里的顺序仅供参考。
去除重复值
对于一般模型影响不大,但对于回归模型⽽言,容易导致回归系数标准误降低,使得对应p值减⼩。重复值过多,样本随机误差降低,造成参数的贡献程度会被高估。本案例没有重复值,可以略过。
异常值处理
首先处理异常值,最低酒店定价有小于0的,有等于1的值,明显属于异常值。异常值处理方法较多,常见有直接删除,当缺失值处理等等,本例中,我们用盖帽法处理此异常值。
代码语言:javascript复制# 定义盖帽法函数
def block_lower(x):
# x是输⼊入的Series对象,替换1%分位数
ql = x.quantile(.01)
out = x.mask(x<ql,ql)
return(out)
def block_upper(x):
# x是输⼊入的Series对象,l替换99%分位数
qu = x.quantile(.99)
out = x.mask(x>qu,qu)
return(out)
lowestprice
: 当前酒店可定最低价lowestprice_pre
: 24小时内已访问次数最多酒店可订最低价
缺失值处理
可以参见缺失值处理,本次案例缺失值填补方案。
- 分类型变量用
众数填补
- 含有负数的特征用
中值填补
- 方差大于100的连续型变量用
中值填补
- 缺失35%用
常数 -1 填充
单独做一类 - 其余变量用
均值填补
- 超过80%
直接删除
变量
特征选择
本次选用简单粗暴的方差过滤、F_检验、 以及嵌入法特征选择,利用树模型的特征重要性输出结合模型效果,选择对模型贡献最大的那个几个变量。事实证明,此方法效果明显,最后成功选择出8个特征。
方法 | 说明 |
---|---|
方差过滤 | 方差等于0 的直接过滤,结果无过滤特征 |
F_检验 | 过滤没有相关性的变量。pvalues_f < 0.01 直接过滤,过滤掉6个特征 |
嵌入法特征选择 | 经过选择,等到贡献最大的8个特征 |
嵌入法特征选择学习曲线
利用随机森林特征重要性属性feature_importances_
定义阈值范围,以嵌入选择模型SelectFromModel
为基础,通过交叉验证cross_val_score
得到每个阈值下模型得分情况。
绘制得到学习曲线如下图所示,在阈值为0.0295956
时,模型精确度得分最高--
# 主要代码
X_embedded = SelectFromModel(RFC_clf,
threshold=i).fit_transform(Xtrain,Ytrain)
val = cross_val_score(RFC_clf,
X_embedded,
Ytrain,cv=5).mean()
score.append(val)
过滤高度相关的特征
热图用于特征间的相关性分析,通过绘制热图,分析发现有以下两个高度相关的变量,最终删除特征cityuvs
。
代码语言:javascript复制
cityuvs
:昨日访问当前城市同入住日期的app uv数cityorders
昨日提交当前城市同入住日期的app订单数
sns.heatmap(Xtrain_new.corr(),
annot=True,linewidths=1)
经过数据预处理及特征选择后,最终得到如下数据:
客户流失预测模型
客户流失预测模型的实现方法属于分类算法,常用算法包括逻辑回归、支持向量机、随机森林等。这里总结了下模型选择的一些参考,见文末附录。
大部分情况下,流失客户的样本分类是少数类,需要注意处理样本不均衡问题。
经过数据预处理后,我们决定利用逻辑回归了解用户画像及行为偏好,挖掘出影响用户流失的关键因素,并辅以随机森林分类器进行预测客户流失。
需要知道关键因素,要求模型需要有很好的可解释性,因此选用逻辑回归模型。但从模型评价结果(ROC曲线面积)来看,逻辑回归并不是很理想。
若需要同时追求模型预测精确度,则选取集成模型或其他强学习模型。这里选用大家熟知的随机森林分类器。
特征变量分析
在将数据用于模型训练之前,需要先对变量进行深入分析。分析变量间是否存在高度相关性,连续性变量是否需要离散化,离散变量是否需要编码等等。
代码语言:javascript复制ax = plt.figure(figsize=(8,15))
for i in range(len(train_data.columns[:-1])):
ax.add_subplot(8,1,i 1)
sns.kdeplot(train_data.iloc[:,i],shade=True)
plt.title(l_[i])
plt.tight_layout();
不难发现,除访问时间点外,特征均成右偏分布。因此将连续型、分类型变量做分箱处理,此处我们选用WEO分箱处理。
WOE分箱
WOE(Weight of Evidence) 好样本比坏样本的比例的对数。 WOE编码: 追求组间差异大、组内差异小、必须要有好坏两种分类。
WOE对于一个箱子来说,WOE越大,代表好样本越多。
每个箱子,
在这个特征上箱子的个数。
是这个箱内的标签为0的样本占整个特征中所有标签为0的⽐。
代表了特征对预测函数的贡献度。
为什么要引⼊分箱
分箱的本质,其实就是离散化连续变量。
- 评分结果需要有一定的稳定性
- 分类型变量: 个数比较少就可以不作处理,如果取值过多会导致"变量膨胀"
分箱的要求
- 不需要分箱变量: 对于分类型变量如果取值较少,⼀般⽆需分箱
- 分箱结果的有序性: 对于有序型变量(数值型、有序离散型)
- 分箱的平衡性: 严格情况下,每⼀个箱⼦的占比不能相差太大。⼀般要求占比最小的箱⼦不低于5%
- 分箱的单调性: 严格情况下,有序型变量分箱后每个箱⼦的坏样本率与箱子呈单调关系
分箱的个数: 5个以内,5-7个比较合适
分箱优缺点:
- 优点: 稳定、缺失值处理理、异常值处理理、不需要归一化
- 缺点: 有信息丢失、需要再进⾏一次编码
常⽤的分箱⽅法
- 有监督: 决策树分箱法、卡⽅分箱
- 无监督: 等距、等深、聚类
我们总结出一个特征进行分箱的步骤:
- 我们⾸先把连续型变量分成⼀组数量较多的分类型变量,⽐如,将几万个样本分成100组,或50组(尽量有监督的分箱)
- 确保每⼀组中都要包含两种类别的样本,否则IV值会⽆法计算
- 我们对相邻的组进⾏卡方检验,卡方检验的P值很大的组进⾏合并,直到数据中的组数⼩于设定的N箱为止
- 我们让⼀个特征分别分成[2,3,4.....20]箱,观察每个分箱个数下的IV值如何变化,找出最适合的分箱个数
- 分箱完毕后,我们计算每个箱的WOE值,观察分箱效果
这些步骤都完成后,我们可以对各个特征都进行分箱,然后观察每个特征的IV值,以此来挑选特征。下⾯我们就对每个x生成⼀个对象、记录IV值、生成WOE图。此处代码需要运⾏⾃定义函数所在⽂件,若有需要,可关注「数据STUDIO」并回复【210514】获取哦!每个x变量运行结果如下。
特征IV值
计算每个变量的IV值,并排序后绘制条形图。通过对比分析并去掉IV值最小,即对模型基本没有贡献的两个特征——sid
, lastpvgap
。
计算Cr的IV值
以计算用户转化率为例,进行WOE分箱并计算对应的IV值。通过分析得到如下结论。
用户转化率在小于1.14%
时用户留存较多。随着用户转化率增大时,流失用户流失增大,但注意在大于1.925%
往上,客户留存在变多。
Lasthtlordergap 一年内距上次下单时长
一年内距上次下单时长在(2.5,1327)区间内转化结果最差,随着时间延长,流失风险降低,需要关注两次下单时间间隔较长的用户。
H 访问时间点
访问时间点在上午时,客户留存效果并不好,在晚上7点后访问的客户,流失率少,且随着时间点推移,留存在明显增大,在凌晨时仍存在留存客户优势。
Cityorders 昨日提交当前城市同入住app订单数
昨日提交当前城市同入住app订单数在第5箱(2.25,2.294)区间内留存结果最好。
除第5箱外,客户留存结果随着订单数增加而逐渐降低,在大于0.37时,留存客户少于流失客户,客户流失风险较大。
visitnum_oneyear 年访问次数
年访问次数在61650前期有较小的浮动,在大于61650时出现高峰 。只有访问次数高到一定程度时(超过15000),该特征才能较明显的客户留存。
WOE值与特征转换
得到每个变量的WOE值,将所有特征值换成对应的WOE值。
逻辑回归模型建立与评估
特征工程完毕后建立逻辑回归模型,并利用召回率,假正率,ROC曲线评估模型。
建立逻辑回归
代码语言:javascript复制from sklearn.linear_model import LogisticRegression
LR = LogisticRegression().fit(X_train,Y_train)
并计算各特征系数与截距:
评估逻辑回归
并计算在训练集和测试集分数分别如下:
LR.score(X_train,Y_train) | LR.score(X_test,Y_test) | |
---|---|---|
score | 0.728283 | 0.726898 |
core metrics
------- ---------- ----------- -------- -------
| auc | accuracy | precision | recall | f1 |
------- ---------- ----------- -------- -------
| 0.675 | 0.727 | 0.741 | 0.951 | 0.833 |
------- ---------- ----------- -------- -------
ROC曲线
代码语言:javascript复制from sklearn.metrics import auc,accuracy_score,recall_score,f1_score
y_score = LR.predict_proba(X_test) # 随机森林
fpr, tpr, thresholds = roc_curve(Y_test, y_score[:, 1])
roc_auc = auc(fpr, tpr)
def drawRoc(roc_auc,fpr,tpr):
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
drawRoc(roc_auc, fpr, tpr)
模型改进
我们发现逻辑回归ROC较低,我们试图从特征角度上来改进模型。
生成衍生变量
M = ordernum_oneyear * avgprice ordernum_oneyear 用户年订单数 avgprice 平均价格
我们将平均价格和年订单量相乘得到年消费,发现客户年消费越多,流失越多。
将生产的衍射变量进行WOE分箱。
- 从IV值看:此特征对标签有较大的贡献度;
- 从客户箱子来看,总体呈现单调递减,客户年消费越多,流失风险越大。
d : 访问日期 arrival :入住日期
此时想到一开始我们之间将日期时间删除处理,现在将其处理后带入模型看看什么效果。
用入住日期减去访问日期得到间隔日期delta,发现客户在入住前很早就访问,留存率会很大。
将生产的衍射变量进行WOE分箱。
- 从IV值看:此特征对标签有较大的贡献度;
- 从客户箱子来看,总体呈现单调递增,客户浏览日期距离入住日期越久,流失越少。
模型改进评估
建立逻辑回归
并计算各特征系数与截距:
评估逻辑回归
计算在训练集和测试集分数分别如下:
LR.score(X_train,Y_train) | LR.score(X_test,Y_test) | |
---|---|---|
score | 0.732319 | 0.731017 |
core metrics
-------- ---------- ----------- -------- -------
| auc | accuracy | precision | recall | f1 |
-------- ---------- ----------- -------- -------
| 0.6895 | 0.731 | 0.745 | 0.949 | 0.835 |
-------- ---------- ----------- -------- -------
经生成两个衍生变量后,逻辑回归模型ROC得分提高2个百分点。
随机森林分类模型
模型建立与调参数
随机森林分类器目的是辅助预测客户流失,因此利用清洗好的数据直接利用网格搜索进行调参数:
n_estimators = range(10, 201, 10) max_depth= range(3, 21,1) min_samples_split= range(2, 22, 1) min_samples_leaf = range(1, 12, 1) n_estimators = range(10, 201, 10)
得到最佳参数组合为
代码语言:javascript复制model = RFC(n_estimators=180
,max_depth=20
,min_samples_leaf=1
,min_samples_split=2
,random_state=0)
模型评估
最后随机森林分类器在保证未出现过拟合的情况下,ROC曲线面积达到0.97
。
客户价值
接下来,为了进一步挖掘客户价值,提升用户体验,我们运用了RFM客户价值模型。
RFM客户价值模型
根据客户价值模型,我们定义一年内距离上次下单时长为R
,年订单量为F
,平均价格为M
。
客户价值度用来评估用户的价值情况,是区分客户价值的重要模型和参考依据,也是衡量不同营销效果的关键指标之一。价值度模型一般基于交易行为产生,衡量的是有实体转化价值的行为。 RFM模型是根据客户最近一次购买时间R(Recency)、购买频率 F(Frequency)、购买金额M(Monetary)计算得出RFM得分,通过这 三个维度来评估客户的订单活跃价值,常用来做客户分群或价值区分。 RFM模型基于一个固定时间点来做模型分析,因此今天做的RFM得分跟7天前做的结果可能不一样,原因是每个客户在不同的时间节点所得到的数据不同。
得到 RFM 得分后的思路
- 基于3个维度做用户群体划分和解读,对用户价值做分析。
- 基于汇总得分评估所有会员的价值价值,做活跃度排名。
- 作为维度输入和其他维度一起做输入变量,为数据挖掘和分析建模提高基础。
数据预处理
在特征选择方面,我们在之前的特征基础上添加了一些我们认为与客户价值有关的变量。对特征进行缺失值分析得到:
同样对数据进行深入探索,因为本次价值模型无需划分测试集和训练集,又数据量足够多,因此我们直接将有缺失值的记录删除。
价值模型
以客户转化率做目标变量,利用随机森林回归模型计算出各价值指标权重,然后分布计算出每个用户的RFM得分,分别以权重加和,及标签组合来表示价值得分。本次RFM模型构建方法仅供参考!
另外,为了体现流失客户及留存客户优势比,参照最优分箱公式,创造了一个类别,以-1表示。其计算方法是:
第一步:以RFM分群和标签聚合,分别对客户id
计数,以及RFM得分求和
groupby(['rfm_group','label'])
第二步:对留存和流失客户求差。就是用不同类别的个数总和求差,乘以 RFM得分总和求差取对数
代码语言:javascript复制 groupby(['rfm_group','label'])
当然,这里是我参数优势比的原理创造的计算公式,其实用价值及是否合理,还需跟业务结合。这里仅作参考。
代码语言:javascript复制number(-1) = (number_0 -number_1)*log(sum(rfm_score)_0/sum(rfm_score)_1)
可视化价值模型
标签 0 是留存用户,标签 1 是流失用户,标签 -1 是留存减流失乘以优势比。
代码语言:javascript复制# 显示图形
bar3d = Bar3D("", width=900, height=600)
range_color = ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf',
'#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
bar3d.add(
"rfm分组结果", "", "",
[d.tolist() for d in data_display.values],
is_visualmap=True,
visual_range=[0, data_display['number'].max()],
visual_range_color=range_color,
grid3d_width=200,
grid3d_height=80,
grid3d_depth=80
)
bar3d
我们可以看到在以R
就是一年内距离上次下单时长为轴,其两端留存和流失客户均很多,且 R
等于 1 就是距离时间越久,客户流失就越少,与我们用WOE分箱分析结果一致。
客户转化预测
由上面分析报告可知,影响客户流失的两大因素:
- 用户转化率
- 一年内距离上次下单时长
因此我们以客户转化率为目标标签,进行进一步预测分析。
数据处理与特征创造与选择
数据处理特征创造等类同于前面步骤,在这里就不赘述了。
在缺失值处理方面不同的是,我们直接将 cr
缺失的记录直接删除了,这样处理的原因是,一是剩余数据量较多,足够随机森林预测。二是随机森林以后实用袋外数据进行模型评估。
以连续特征 cr
客户转化率作为目标标签,利用随机森林回归器输出特征重要性来选择出使得模型分数最高的那几个特征。本次选择出了13个对模型贡献度较大特征。
我可以看到排名第一的仍然是一年内距离上次下单时间对用户转化率的影响最高。
相比对客户流失影响的特征,多了历史订单数,历史取消订单数及星级偏好,客户价值
等。
模型训练与调参数
运用网格搜索方法对随机森林分类器进行调参,得到最佳参数:(这里注意调参时间较长,小伙伴们可以尝试运用贝叶斯优化调参方法)
代码语言:javascript复制model = RFR(n_estimators=180
,max_depth=25
,min_samples_leaf=1
,min_samples_split=2
,random_state=0
)
因此得到该模型,在测试集预测得分92.26%
。最后可以保存模型以供模型部署使用。
项目总结
我们使用了逻辑回归模型和客户价值模型对客户流失进行深入挖掘,找出了影响客户流失的关键因素:
用户转化率
——用户转化率大时,流失用户占比反而在逐渐增大。
一年内距上次下单时长
——一年内距上次下单时长在(2.5,1327)区间内最容易流失,但时间越久的,约容易留存。
访问时间点
——白天访问转化率低,晚上7点后访问客户更易转化。
昨日提交当前城市同入住app 订单数
—— 订单数越大,客户流失风险越大, 但在(2.25,2.294)区间内转化结果最好。
创造的特征M,delta
M客户年花费
越大,流失风险越大。delta
随着访问日期与入住日期距离越近,客户更易流失,也就是没怎么访问就入住的酒店,相比而言,在入住之前就有关注酒店的客户,黏性就越大。
用户画像
我们总结出易流失人群和留存客户人群特征,对客户进行一个简单的画像。针对易流失人群,推荐具体业务可以从三个维度将本次分析结果落地。
- 时间维度,如访问时间维度,下单间隔维度
- 数量维度,如访问量,订单量等
- 价格维度,价格敏感度,客户年消费金额等
易留存人群特征 一年内距上次下单时长在(1,1.075)区间 用户转化率在( 1,1.075 )区间 访问时间在晚上 订单数在2.294以下 年访问次数超过15003 年消费越小 入住日期与访问日期间隔越长
易流失人群特征 一年内距上次下单时长在(2.5,1327)区间 用户转化率在(1.505,1.925)区间 访问时间在上午 App订单数在2.61以上 年访问次数在小于15000 年消费越大 入住日期与访问日期间隔越短
附录如何选择算法
如何选择聚类算法
- 如果数据集是高维的 —— 谱聚类,它是子空间划分的一种。
- 如果数据是中小规模:
- 100万以内 —— K_Means
- 100万以上 —— MiniBatchKMeans(每类抽取一部分样本聚类,精度下降,速度提高)
- 数据集中有噪声(离群点) —— 基于密度的带有噪声的 DBSCAN 。
- 如果追求更高的分类准确性,选择谱聚类比K_Means准确性更好。
如何选择回归分析算法
- 数据集本身结构简单、分布规律有明显线性关系——简单线性回归,基于最小二乘法的普通线性回归。
- 自变量数量少或降维后得到了二维变量(包括预测变量)——直接使用散点图,发现自变量和因变量之间的相互关系,然后再选择最佳回归方法
- 自变量间有较强共线性关系——岭回归,L2正则化,对多重共线性灵活处理的方法
- 如果噪声较多——推荐主成分回归,通过对参与回归的主成分的合理选择,可以去掉噪声;各个主成分相互正交,解决多元回归共线性问题。
- 高维度变量下——正则化回归方法,Lasso、Ridge、ElasticNet。降维、逐步回归
- 可使用交叉验证做多个模型的效果对比,验证多个算法
- 注重模型的可解释性—— 线性回归、逻辑回归、对数回归、二项式或多项式回归
- 集成或组合方法——加权、均值等方法确定最终输出结果(一旦确认来多个方法,又不确定取舍)
如何选择分类分析算法
- 文本文类——朴素贝叶斯
- 训练集较小——朴素贝叶斯、支持向量机,高偏差低方差低分类算法,不容易过拟合
- 训练集较大——基本都适用
- 关注模型等计算时间和模型易用性——不用支持向量机和人工神经网络
- 重视算法准确性——支持向量机、GBDT、XGBoost、Adaboost等基于Boosting等集成方法
- 重视算法稳定性或模型鲁棒性——随机森林、组合投票模型等基于Bagging的集成方法
- 预得到预测结果的概率信息,基于预测概率做进一步应用——逻辑回归
- 担心离群点或数据不可分并且需要清晰的决策规则——决策树