本文主要讨论的是以航空公司的会员数据,用RFM的思想结合聚类分析,挖掘不同客户群的价值并制定不同的营销策略。流程大致为:1.用Pandas对数据进行预处理; 2.用Matplotlib进行数据可视化和数据探索;3.用Sklearn来对客户聚类
1、故事的起源
2020年的新年假期对于大部分小伙伴来说是漫长和乏味的,而对于J来说,应该是类似的,但又是微妙的。不能和小伙伴聚会,没人带我去探险,也没教练带我打篮球,还要在家整天被老的。应付完家里的事,J以为可以静下心来,看书搓大招的时候,又会时不时有老阿姨满脸亲切低问:“老许,你要老婆不要?”结果放假前,信心满满,1、2、3点的小目标一个也没完成。终于有个还算清闲的周末了,J咬咬牙就继续写起了文章。
推荐一本《Python数据分析与挖掘实战》,文章以案例的方式讨论常规的数据挖掘问题,和常见统计、机器学习的算法的使用。第一次接触这本书还是在黄老师的数据挖掘课,那时候老师比较严格,大家都不敢选,还好J学分够了,可以自信的去蹭课了。虽然理论知识忘得差不多了,不过工具、理论、业务,还是从最简单的工具入手比较适合我。说朝花夕拾对咱这种小年轻来说可不适合,不过重温一下还是值得的,当时是R版的,换个工具再走一遍也好。哦,对了,我记得当时提班里的同学完成一个什么作业来着,题目不记得了,不过可是靠这个换来了两个女同学请我的一顿饭和一杯奶茶呢!(骄傲得瑟脸)
本文内容的数据和内容,主要来自第7章的航空公司客户价值分析,想跟这走一遍的小伙伴可以去看原书,找数据和代码。老师好像说要回收教程的呀,可为啥我R版的还在。。。
2、项目的内容展示
航空公司客户价值分析案例的流程,包括大致如下:
- 抽取航空公司2012年4月1日至2014年3月31日的数据。(说的跟真的似的,那为什么会有2014年2月29日的数,欺骗我感情!)
- 对抽取的数据进行探索性分析和数据预处理,包括缺失值处理,特征构建,标准化等操作
- 基于RFM模型,使用K-Means聚类算法进行客户分析
2.1探索性分析和数据预处理
我们的数据集,主要包含客户基本信息,乘机信息,积分信息3类信息,一共44个字段。其中比较重要的如下:
2.1.1客户基本信息
选取客户基本信息中的入会时间、性别、会员卡级别和年龄的字段进行探索分析,我们就会对该航空公司的会员有个大致的了解。会员的人数在2012年的增幅最大,男性占到了75%,会员的级别集中在4级,年龄集中在30-50岁之间。
2.1.2乘机信息
乘机信息是和客户价值关联最密切的信息,其中客户最近一次乘坐公司飞机距观测窗口结束的时长(观测窗口j结束时间2014年4月1日,单位为天),
飞行次数,总飞行里程数分别可以对应一个用户的R,F,M的信息。
该公司客户的最近一次乘机时间大多距离目当前窗口的时长集中在50-300天的区间内,活跃度满不错的,不过也能看到一部分会员的时长已经超过600天,已经有流失的可能。而飞行次数和总飞行里程数的分布比较类似,主要集中在箱体内,而箱体外的部分,2个指标似乎也比较相似,可能是同一类的高价值消费者。
2.1.3乘机信息
对于积分相关的信息,我们主要看的是积分的兑换次数和总累积积分。
绝大多数的积分主要集中在0-10次以内,表明公司对于积分的玩法似乎并不是很重视,绝大部分的会员都没有兑换积分的意识。而总累积积分的分布和飞行次数和飞行里程的分布比较接近,一定程度上可以用另外2个属性来代替。
2.2客户信息的相关性分析
我们选择最近一次乘坐公司飞机距观测窗口结束的时长,飞行次数,总飞行里程数,积分的兑换次数,总累积积分,入会年份和客户年龄进行不同特征间的相关性分析,其中主要用的是皮尔逊相关系数。
可以看到年龄和入会月份和其他的乘机信息似乎并没有很强的相关性,可以考虑舍弃这部分信息。而飞行总里程,飞行次数,累积积分间果然有比较强的相关性,因此,舍弃其中的部分特征或是用一些特征来代替和补充一些信息。
2.3数据的预处理
2.3.1数据的清洗
观察数据我们发现,存在票价为空,或是票价为0,或是折扣率为0且总飞行公里数为0的异常数据,还有J新发现的2014年2月29日的蜜汁数据(黑人问号脸)。
data = pd.read_csv(datafile,encoding=\'utf-8\') data = data[data[\'SUM_YR_1\'].notnull()*data[\'SUM_YR_2\'].notnull()] #票价非空值才保留 #只保留票价非零的,或者平均折扣率与总飞行公里数同时为0的记录。 index1 = data[\'SUM_YR_1\'] != 0 index2 = data[\'SUM_YR_2\'] != 0 index3 = (data[\'SEG_KM_SUM\'] == 0) & (data[\'avg_discount\'] == 0) #该规则是“与” data = data[index1 | index2 | index3] #该规则是“或” data.loc[data[data["LAST_FLIGHT_DATE"] == "2014/2/29 0:00:00"].index,"LAST_FLIGHT_DATE"] = "2014/2/28" #0229的错误日期处理
因此,对于整个数据集,我们做了以下的清洗行为:
- 丢弃票价为空的记录
- 保留票价不为0,或平均折扣率不为0且总飞行公里数大于0的记录
- 把入会时间2014年2月29日的异常记录改为2014年2月28日
2.3.2属性规约
识别客户价值应用最广泛的模型是通过3个指标:
- 最近消费时间间隔Recency
- 消费频率Frequency
- 消费金额Monetary
来进行客户细分,识别高价值的客户,简称RFM模型。
在RFM模型中,消费金额表示在一段时间内,客户购买该企业产品金额的总和。由于航空价受到运输距离、航位等级等多种因素影响,同样消费金额的不同旅客对航空公司的价值是不同的。所以消费金额这个指标并不适用于航空公司的客户价值分析。我们选择客户在一定时间内累积的飞行里程M和客户在一定时间内乘坐舱位所对应的折扣系数的平均值C,两个指标代替消费金额。
本案例将客户关系长度L、消费时间间隔R、消费频率F、飞行里程M、折扣系数的平均值C五个指标作为航空公司识别客户价值,记为LRFMC模型。
- L:会员入会时间距观测窗口结束的月数;
- R:客户最近一次乘坐公司飞机距观测窗口结束的月数
- F:客户在观测窗口内乘坐公司飞机的次数
- M:客户在观测窗口内累计的飞行里程
- C:客户在观测窗口内乘坐舱位所对应的折扣系数的平均值
原始数据中属性太多,根据航空公司客户价值LRFMC模型,选择与LRFMC指标相关的6个属性:FFP_DATE、LOAD_TIME、FLIGHT_COUNT、avg_discount、SEG_KM_SUM、LAST_TO_END。
1)L=LOAD_TIME-FFP_DATE(需要手动构造)
会员入会时间距观测窗口结束的月数=观测窗口的结束时间-入会时间【单位:天】
2)R=LAST_TO_END
客户最近一次乘坐公司飞机距观测窗口结束的月数=最后一次乘机时间至观察窗口末端时长【单位:天】
客户在观测窗口内乘坐公司飞机的次数=观测窗口的总飞行次数【单位:月】
客户在观测时间内在公司累计的飞行里程=观测窗口的总飞行公里数【单位:公里】
5)C=AVG_DISCOUNT
客户在观测时间内乘坐舱位多对应的折扣系数的平均值=平均折扣率【单位:无】
2.3.3标准化
考虑我们会使用聚类,而聚类的方法为K-Means聚类,涉及到距离的定义,默认为欧拉距离。特征的量纲会严重影响我们的聚类结果,我们有必要对原始数据进行标准化。由于特征大多符合正态分布(事实上并不是),就默认使用Z-score方法。
L = pd.to_datetime(data["LOAD_TIME"]) - pd.to_datetime(data["LAST_FLIGHT_DATE"]) data_features = pd.concat([L.dt.days,data[[\'LAST_TO_END\',\'FLIGHT_COUNT\',\'SEG_KM_SUM\',\'avg_discount\']]],axis = 1) data_features.columns = ["L","R","F","M","C"] data_features = (data_features - data_features.mean(axis = 0))/(data_features.std(axis = 0)) #简洁的语句实现了标准化变换,类似地可以实现任何想要的变换。 data_features.columns=[\'Z\'+i for i in data_features.columns] #表头重命名。
标准化后的字段对应为ZL,ZR,ZF,ZM,ZC。
2.4模型的构建
客户价值分析模型构建主要由两部分构成,第一部分根据航空公司客户5个指标的数据,对客户进行聚类分群。第二部分结合业务对每个客户群进行特征分析,分析客户价值,并对每个客户群进行排名。
2.4.1、客户聚类
from sklearn.cluster import KMeans k = 5 kmodel = KMeans(n_clusters = k, n_jobs = 4,random_state=123,init="k-means++") #n_jobs是并行数,一般等于CPU数较好 kmodel.fit(data_features) #训练模型 cluster_center = pd.DataFrame(kmodel.cluster_centers_,columns=data_features.columns) #查看聚类中心 cluster_center.index = pd.Series(kmodel.labels_ ).drop_duplicates().values cluster_count = pd.Series(kmodel.labels_ ).value_counts() cluster_count.name = "count" cluster_center = pd.concat([cluster_center,cluster_count],axis=1) cluster_center.index = ["客户群"+str(i + 1) for i in cluster_center.index] cluster_center.sort_index(inplace=True) cluster_center
我们把客户聚类成5类,并输出各类客户群的聚类中心和每类客户群的人数。
2.4.2.客户价值分析
labels = data.columns #标签 k = 5 #数据个数 color = [\'b\', \'g\', \'r\', \'c\', \'y\'] #指定颜色 label = [\'ZL\', \'ZR\', \'ZF\', \'ZM\', \'ZC\'] angles = np.linspace(0, 2*np.pi, k, endpoint=False) kmodel = KMeans(n_clusters = k, n_jobs = 4,random_state=123,init="k-means++") #n_jobs是并行数,一般等于CPU数较好 kmodel.fit(data_features) #训练模型 cluster_center = pd.DataFrame(kmodel.cluster_centers_,columns=data_features.columns) #查看聚类中心 cluster_center.index = pd.Series(kmodel.labels_ ).drop_duplicates().values cluster_count = pd.Series(kmodel.labels_ ).value_counts() cluster_center.index = ["客户群"+str(i + 1) for i in cluster_center.index] legen = cluster_center.index cluster_center = np.concatenate((cluster_center, cluster_center[["ZL"]]), axis=1) # 闭合 angles = np.linspace(0, 2*np.pi, k, endpoint=False) angles = np.concatenate((angles, [angles[0]])) fig = plt.figure(figsize=(8,8)) ax = fig.add_subplot(111, polar=True) #polar参数!! for i in range(len(legen)): ax.plot(angles, cluster_center[i], \'o-\', color = color[i], label = legen[i], linewidth=2)# 画线 ax.set_rgrids(np.arange(0.01, 3.5, 0.5), np.arange(-1, 2.5, 0.5), fontproperties="Microsoft Yahei") ax.set_thetagrids(angles * 180/np.pi, label, fontproperties="Microsoft Yahei") plt.legend(loc = 4) plt.show()
import seaborn as sns plt.subplots(figsize = (8,8)) sns.heatmap(cluster_center,cmap="Blues",annot=True,vmax=1,square=True)
针对聚类结果进行特征分析,其中
客户群 | 排名 | 排名含义 |
客户群3 | 1 | 重要保持客户 |
客户群1 | 2 | 重要发展客户 |
客户群5 | 3 | 重要挽留客户 |
客户群4 | 4 | 一般客户 |
客户群2 | 5 | 低价值客户 |
2.4.3K-Means模型的优化
K-Means聚类在训练时有两个问题需要解决:1)初始聚类中心的选择;2)聚类簇数的选择
关于聚类中心的选择K-Means++可以一定程度解决;关于聚类簇数的判断,可以用肘方法解决。(聚类算法的细节,轮廓系数有时间下次在讨论好了)
观察聚类簇数和簇内误差平方和的关系图,我们发现聚成3-6类都
相关文章
- [财务][数据化分析][帆软]如何量化你的用户价值?RFM模型综合实战 [数据分析][RFM模型]用数据分析用户
- kafka消费者客户端启动之后消费不到消息的原因分析
- 商品期货投资的那些事(九)点价交易,你为客户提供了什么价值? - 洛洛罗
- 一步一步教你PowerBI数据分析:制作客户RFM数据分析
- 大量客户反映wordpress的网站打开巨慢,经分析发现,这些网站大都使用了google的字体服务,由于最近google的服务已经被大陆屏蔽,所以wordpress的网站打开时,会卡在字体加载上。
- 第四次个人作业——关于微软必应词典android客户端的案例分析
- 个人博客作业Week3(微软必应词典客户端的案例分析)
- c#实例化继承类,必须对被继承类的程序集做引用 .net core Redis分布式缓存客户端实现逻辑分析及示例demo 数据库笔记之索引和事务 centos 7下安装python 3.6笔记 你大波哥~ C#开源框架(转载) JSON C# Class Generator ---由json字符串生成C#实体类的工具
- PHP的HTTP客户端Guzzle简单使用方法分析
- 基于TCP的一对回射客户/服务器程序及其运行过程分析( 上 )