目标:
识别客户价值应用最广泛的模型是通过3个指标,来进行客户细分,识别出高价值的客户,简称RFM模型。
在RFM模型中,消费金额表示在一段时间内,客户购买该企业产品金额的总和。由于航空票价受到运输距离、舱位等级等多种因素,同样消费金额的不同旅客对航空公司的价值是不同的。例如,一位购买长航线、低等级舱位的旅客与一位购买短航线、高等级舱位票的旅客相比,后者对于航空公司而言价值可能更高。因此,这个指标并不适用于航空公司的客户价值分析。
我们选择客户在一定时间内累积的飞行里程M和客户在一定时间内乘坐舱位所对应的折扣系数的平均值C两个指标代替消费金融。此外,考虑航空公司会员入会时间的长短在一定程度上能够影响客户价值,所以在模型中增加客户关系长度L,作为区分客户的另一指标。
航空公司LRFMC模型
模型 | L | R | F | M | C |
---|---|---|---|---|---|
航空公司LRFMC模型 | 会员入会时间距观测窗口结束的月数 | 客户最近一次乘坐公司飞机距观测窗口结束的月数 | 客户在观测窗口内乘坐公司飞机的次数 | 客户在观测窗口内累计的飞行里程 | 客户在观测窗口内乘坐舱位对应的折扣系数的平均值 |
本案例采用聚类的方法识别客户价值,通过对这5个指标进行K-Means聚类,识别出最有价值客户。
本案例航空客户价值分析的总体流程如图所示:
航空客运信息挖掘主要包括以下步骤:
以2014-03-31为结束时间,选取宽度为两年的时间段作为分析观测窗口,抽取观测窗口内有乘机记录的所以客户的详细数据形成历史数据。
对于后续新增的客户详细信息,以后续新增数据中最新的时间点作为结束时间,采用上述同样的方法进行抽取,形成增量数据。
#探索分析
#返回缺失值个数以及最大最小值
import pandas as pd
datafile = 'G:/Python数据分析与挖掘实战/chapter7/demo/data/air_data.csv' #原始数据,第一行为属性标签
resultfile = 'G:/Python数据分析与挖掘实战/chapter7/zl/explore.xls' #数据探索结果表
data = pd.read_csv(datafile, encoding='utf-8')
explore = data.describe(percentiles=[], include='all').T #转置后方便查阅
explore.head()
explore['null'] = len(data) - explore['count'] #describe()函数自动计算非空值数,需要手动计算空值数
explore = explore[['null', 'max', 'min']] #只选取部分探索结果
explore.columns = ['空值数','最大值','最小值'] #表头重命名
explore.head()
explore.to_excel(resultfile) #导出结果
通过对数据观察发现原始数据中存在票价为空值,票价最小值为0,折扣率最小值为0,总飞行公里数大于0的记录。票价为空值的数据可能是客户不存在乘机记录造成,其他数据可能是客户乘坐0折机票或者积分兑换产生的。
1.数据清洗
通过数据探索分析,发现数据中存在缺失值,票价最小值为0、折扣率最小值为0、总飞行里程数大于0的记录。由于删除后数据量为62044,异常样本数据所占比例较小,对于问题影响不大,因此对其进行丢弃处理。
#数据清洗
import pandas as pd
datafile = 'G:/Python数据分析与挖掘实战/chapter7/demo/data/air_data.csv'
cleanedfile = 'G:/Python数据分析与挖掘实战/chapter7/zl/data_cleaned.xls' #数据清洗后保存的文件
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.to_excel(cleanedfile)#导出结果(数据集较大)
data.shape
输出结果:
(62044, 44)
2.属性规约
原始数据中属性太多,根据航空公司客户价值LRFMC模型,选择与LRFMC指标相关的6个属性:FFP_DATE、LOAD_TIME、FLIGHT_COUNT、AVG_DISCOUNT、SEG_KM_SUM、LAST_TO_END。删除与其不相关、弱相关或冗余的属性。
#属性规约
filter_data = data[['FFP_DATE','LOAD_TIME','FLIGHT_COUNT','avg_discount','SEG_KM_SUM','LAST_TO_END']]
filter_data.head()
from datetime import datetime
#转化成datetime格式,才能加减
filter_data = filter_data.copy()
filter_data['FFP_DATE_1'] = filter_data['FFP_DATE'].apply(lambda x : datetime.strptime(x, '%Y/%m/%d'))
filter_data['LOAD_TIME_1'] = filter_data['LOAD_TIME'].apply(lambda x : datetime.strptime(x, '%Y/%m/%d'))
#格式转化
def interval_time(dd):
return dd.days/30
filter_data['L'] = (filter_data['LOAD_TIME_1'] - filter_data['FFP_DATE_1']).apply(interval_time)
filter_data.head()
filter_data = filter_data.rename(columns={'LAST_TO_END':'R', 'FLIGHT_COUNT':'F', 'SEG_KM_SUM':'M', 'avg_discount':'C'})
filter_data.head()
#挑选指定列,LRFMC模型
data_selected = filter_data[['L','R','F','M','C']]
data_slc = 'G:/Python数据分析与挖掘实战/chapter7/zl/data_selected.xlsx'
data_selected.to_excel(data_slc)
data_selected.describe()
从上图可以看出,5个指标的取值范围数据差异较大,为了消除数量级数据带来的影响,需要对数据进行标准化处理。
#标准化处理
data_zscored = 'G:/Python数据分析与挖掘实战/chapter7/zl/data_zscored.xlsx'
data_z = (data_selected - data_selected.mean(axis=0)) / (data_selected.std(axis=0))
data_z.columns = ['Z' + i for i in data_selected.columns] #表头重命名
data_z.head()
data_z.to_excel(data_zscored, index=False) #数据写入
客户价值分析模型构建主要包括:
K-Means
聚类算法对客户数据进行客户分群,聚成5类(需要结合业务的理解与分析来确定客户的类别数量)#K-Means聚类
from sklearn.cluster import KMeans
k = 5 #分为5类
kmodel = KMeans(n_clusters=k, n_jobs=4) #封装,n_jobs是并行数,一般等于CPU较好
kmodel.fit(data_z) #训练模型
kmodel.cluster_centers_ #查看聚类中心
kmodel.labels_ #查看各样本对应的类别
#简单打印结果
s = pd.Series(['客户群1','客户群2','客户群3','客户群4','客户群5'], index=[0,1,2,3,4])
r1 = pd.Series(kmodel.labels_).value_counts() #统计各个类别的数目
r2 = pd.DataFrame(kmodel.cluster_centers_ ) #找出聚类中心
r = pd.concat([s,r1,r2],axis=1) #横向连接,0是纵向连接
r.columns =[u'聚类名称'] +[u'聚类个数'] + list(data_z.columns) #重命名表头
r
#客户价值分析
#代码来自 https://blog.csdn.net/Just_youHG/article/details/83904618
import numpy as np
import matplotlib.pyplot as plt
%matplotlib
#中文和负号的正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
kinds = r.iloc[:,0] #第一列:客户群
labels = r.iloc[:, 2:].columns #取到标签:ZL,ZR,ZF,ZM,ZC
centers = pd.concat([r.iloc[:, 2:], r.iloc[:,2]], axis=1) #封闭起来
centers = np.array(centers)
n = len(labels)
angles = np.linspace(0, 2*np.pi, n, endpoint=False) #将一个圆划分为5块
angles = np.concatenate((angles, [angles[0]])) #使雷达图封闭起来
fig = plt.figure()
ax = fig.add_subplot(111, polar=True) #设置坐标为极坐标
#画若干个五边形
floor = np.floor(centers.min()) #大于最小值的最大整数
ceil = np.ceil(centers.max()) #小于最大值的最小整数
for i in np.arange(floor, ceil+0.5, 0.5):
ax.plot(angles, [i] * (n+1), '--', lw=0.5, color='black')
#画不同客户群的分割线
for i in range(n):
ax.plot([angles[i], angles[i]], [floor, ceil], '-', lw=0.5, color='black')
#画不同的客户群所占的大小
for i in range(len(kinds)):
ax.plot(angles, centers[i], lw=2, label=kinds[i])
#ax.fill(angles, centers[i])
ax.set_thetagrids(angles * 180 / np.pi, labels) # 设置显示的角度,将弧度转换为角度
plt.legend(loc='lower right', bbox_to_anchor=(1.5, 0.0)) # 设置图例的位置,在画布外
#美化
ax.set_theta_zero_location('N' )# 设置极坐标的起点(即0°)在正北方向,即相当于坐标轴逆时针旋转90°
ax.spines['polar'].set_visible(False) # 不显示极坐标最外圈的圆
ax.grid(False) # 不显示默认的分割线
ax.set_yticks([]) # 不显示坐标间隔
plt.show()
客户群体特征描述表:
由上述特征分析的图标说明每个客户群都有显著不同的表现特征,基于该特征描述,定义五个级别的客户类别:
客户群 | 排名 | 排名含义 | 人数 |
---|---|---|---|
客户群2 | 1 | 重要保持客户 | 5337 |
客户群3 | 2 | 重要发展客户 | 4216 |
客户群5 | 3 | 重要挽留客户 | 12118 |
客户群4 | 4 | 一般客户 | 24638 |
客户群1 | 5 | 低价值客户 | 15735 |
特征分析: