一.背景与挖掘目标
数据源
基于一份航空公司的数据,数据包含信息有客户基本信息、乘机信息、以及积分信息等详细数据,大约6万多条数据,依据末次飞行时间LAST_FLIGHT_DATE,以2020.3.31为结束时间,选取宽度为2年的时间段作为分析观测窗口。
数据中,客户乘机信息主要重点字段包含:
LOAD_TIME-观测结束时间
FLIGHT_COUNT-观测窗口内飞行次数
SUM_YR_1-观测窗口票价收入1
SUM_YR_2-观测窗口票价收入2
SEG_KM_SUM-观测窗口的总飞行公里数
LAST_FLIGHT_DATE-末次飞行日期
AVG_FLIGHT_COUNT-平均飞行次数
BEGIN_TO_FIRST-首次飞行日期
LAST_TO_END-最后一次乘机时间至观测窗口结束时长
AVG_INTERVAL-平均乘机时间间隔
MAX_INTERVAL-最大乘机间隔
客户基本信息主要重点字段包含:
MEMBER_NO-会员卡号
FFP_DATE-入会时间
FIRST_FLIGHT_DATE-第一次飞行日期
GENDER-性别
FFP_TIER-会员卡级别
WORK_CITY-工作地城市
WORK_PROVINCE-工作地省份
WORK_COUNTRY-工作地国家
AGE-年龄
积分信息主要重点字段包含:
BP_SUM-总基本积分
EP_SUM_YR_1-总基本积分1
EP_SUM_YR_2-总基本积分2
AVG_BP_SUM-平均积分
EXCHANGE_COUNT-积分兑换次数
avg_discount-平均折扣率
PY_Flight_Count-PY飞行次数
LY_Flight_Count-LY飞行次数
PY_BP_SUM-PY基本积分
LY_BP_SUM-LY基本积分
EP_SUM-总精英积分
Points_Sum-总累计积分
Point_NotFlight-非乘机的积分变动次数
数据挖掘目标
1.借助航空公司客户数据,对客户进行分类;
2.对不同客户类别进行特征分类,比较不同客户群体的客户价值;
二.数据探索性分析
首先读取数据,观测下各字段数据类型,各自段空值情况。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
air_data = pd.read_csv('data/air_data.csv',encoding='utf-8')
explore = air_data.describe().T
explore['null'] = len(air_data)-explore['count']
探索性结果描述如下。
接下来分别从客户信息、乘机信息、积分信息等三个角度进行数据探索,寻找客户信息的分布规律。
2.1 客户信息分布
绘制各年份会员入会人数直方图,接下来的思路是用到RFM客户价值分析模型。因此需要对数据进行初步探索。
ffp = air_data['FFP_DATE'].apply(lambda x:datetime.strptime(x,'%Y/%m/%d'))
ffp_year = ffp.map(lambda x:x.year)
# 绘制各年份会员入会人数直方图
import seaborn as sns
sns.set(); np.random.seed(0)
sns.distplot(ffp_year)
提取不同级别会员的人数,画图。
lv_four = pd.value_counts(air_data['FFP_TIER'])[4]
lv_five = pd.value_counts(air_data['FFP_TIER'])[5]
lv_six = pd.value_counts(air_data['FFP_TIER'])[6]
##画图
plt.bar(x=['4','5','6'], height=[lv_four,lv_five,lv_six], width=0.4, alpha=0.8, color='#689FB0')
plt.xlabel('会员等级')
plt.ylabel('会员人数')
plt.title('会员各级别人数')
plt.show()
了解会员的年龄分布状况。绘制会员年龄分布箱型图
age = air_data['AGE'].dropna().astype(int)
import seaborn as sns
plt.figure(figsize = (4,6))
sns.set(style="whitegrid")
sns.boxplot(data=age)
2.2 乘机信息分布
选取最后一次乘机至结束的时长LAST_TO_END、客户乘机信息中的飞行次数FLIGHT_COUNT、总飞行公里数SEG_KM_SUM,进行探索分析,探索客户的乘机信息分布情况。
绘制各年份会员入会人数直方图。
lte = air_data['LAST_TO_END']#最后一次乘机时间至观测窗口结束时长,空窗时长
fc = air_data['FLIGHT_COUNT']#观测窗口内飞行次数
sks = air_data['SEG_KM_SUM']#观测窗口内总飞行公里数
# 绘制各年份会员入会人数直方图
import seaborn as sns
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
sns.set(); np.random.seed(0)
sns.distplot(lte)
绘制飞行次数分布图。
import seaborn as sns
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
sns.set(); np.random.seed(0)
sns.distplot(fc)
绘制飞行公里数分布箱型图。
plt.figure(figsize = (4,6))
sns.set(style="whitegrid")
sns.boxplot(data=sks)
2.3 相关性分析
客户信息属性之间存在相关性,选取入会时间、会员卡级别、客户年龄、飞行次数、总飞行公里数、最后一次乘机时间至观测窗口结束时长、积分兑换次数、总累计积分属性,通过相关系数矩阵与热力图分析各属性之间的相关性。
找出相关性系数air_dt_corr 。
data_corr = air_data[['FFP_TIER','FLIGHT_COUNT','LAST_TO_END','SEG_KM_SUM','EXCHANGE_COUNT','Points_Sum']]
data_corr['AGE'] = air_data['AGE'].fillna(0).astype(int)
data_corr['ffp_year'] = ffp_year #会员入会年份
air_dt_corr = data_corr.corr(method='pearson')
画出相关性系数热力图。
plt.figure(figsize=(10,10))
mask = np.zeros_like(air_dt_corr,dtype=np.bool)
mask[np.triu_indices_from(mask)] = True
cmap = sns.diverging_palette(220,10,as_cmap=True)
g = sns.heatmap(air_dt_corr,mask=mask,cmap=cmap,square=True,annot=True,fmt='0.2f')
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
plt.show
三.基于RFM模型的客户价值分析
在衡量客户价值的过程中,以广泛应用的RFM模型为基础,进行新的模型搭建。
从以上相关性关系图中可以看出客户属性之间存在相关性。因此,选取客户关系长度L、消费时间间隔R、消费频率F、飞行里程M、折扣系数C五个特征作为衡量客户价值的特征。
客户关系长度L:会员入会时间距离观测窗口结束的月数,数据表没有直接给出,需要用(LOAD_TIME-FFP_DATE);
消费时间间隔R:LAST_TO_END,客户最近一次乘坐飞机距观测窗口结束的月数;
消费频率F:FLIGHT_COUNT,客户在观测窗口内乘坐飞机的次数;
飞行里程M:SEG_KM_SUM,客户在观测窗口内累计飞行的公里数;
折扣系数C:avg_discount,客户在观测窗口内乘坐舱位所对应的折扣系数的平均值;
3.1 数据标准化
在原有数据基础上进行属性选取。
# 选取需求属性
airline_selection = air_data[['FFP_DATE','LOAD_TIME','LAST_TO_END','FLIGHT_COUNT','SEG_KM_SUM','avg_discount']]
#构造属性L
airline_selection['L'] = \
(pd.to_datetime(air_data['LOAD_TIME'])-pd.to_datetime(air_data['FFP_DATE'])).astype(str).str.split().str[0]
airline_selection = airline_selection.iloc[:,2:]
属性选取之后,发现这些指标不在同一量级,为了接下来进行模型训练,需要先做数据标准化处理。
##数据标准化处理
from sklearn.preprocessing import StandardScaler
stand_data = StandardScaler().fit_transform(airline_selection)
pd.DataFrame(stand_data)
标准化数据的结果。
3.2 K-Means模型构建
将上述数据进行K-Means聚类。找到各个聚集点的质心cluster_center。
from sklearn.cluster import KMeans
#构建模型
kmeans_model = KMeans(n_clusters=5,n_jobs=4,random_state=123)
fit_kmeans = kmeans_model.fit(stand_data)
kmeans_cc = kmeans_model.cluster_centers_ #聚类中心
kmeans_labels = kmeans_model.labels_ #样本的类别标签
#输出聚类分群结果
cluster_center = pd.DataFrame(kmeans_cc,columns=['ZL','ZR','ZF','ZM','ZC'])
cluster_center.index = pd.DataFrame(kmeans_model.labels_ ).drop_duplicates().iloc[:,0]
最终质心如图。
3.3 客户价值分群雷达图
# 客户分群雷达图
labels = ['ZL','ZR','ZF','ZM','ZC']
legen = ['客户群' + str(i + 1) for i in cluster_center.index] # 客户群命名,作为雷达图的图例
lstype = ['-','--',(0, (3, 5, 1, 5, 1, 5)),':','-.']
kinds = list(cluster_center.iloc[:, 0])
# 由于雷达图要保证数据闭合,因此再添加L列,并转换为 np.ndarray
cluster_center = pd.concat([cluster_center, cluster_center[['ZL']]], axis=1)
centers = np.array(cluster_center.iloc[:, 0:])
# 分割圆周长,并让其闭合
n = len(labels)
angle = np.linspace(0, 2 * np.pi, n, endpoint=False)
angle = np.concatenate((angle, [angle[0]]))
# 绘图
fig = plt.figure(figsize = (8,6))
ax = fig.add_subplot(111, polar=True) # 以极坐标的形式绘制图形
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 画线
for i in range(len(kinds)):
ax.plot(angle, centers[i], linestyle=lstype[i], linewidth=2, label=kinds[i])
# 添加属性标签
ax.set_thetagrids(angle * 180 / np.pi, labels)
plt.title('客户特征分析雷达图')
plt.legend(legen)
plt.show()
图像结果呈现。
质心的分布状态。
3.4 总结
画出雷达图也就是为各个客户群体划分界限。接下来需要根据业务特征下定义,评估每项指标的高中低界限在哪里,给每个客户贴标签。
例如:
客户群体1在特征C处的值最大,在特征F,M处的值最小,说明客户群体1偏好乘坐高级舱位。
客户群体2在特征F、M上的值最大,且在特征R上的值最小,说明客户群体2的会员频繁乘机,近期都有乘机记录。
客户群体3在R处的值相对最大,在特征L、F、M和C处的值都较小,说明客户群体3已经很久没有乘机记录,是入会时间短的低价值客户群。
客户群体4在所有特征值上都较小,且在特征L处最小,说明客户群体4属于新入会员较多的群体。
客户群体5在L处最大,在R处值最小,其他特征比较适中,说明客户群体5入会时间较长,飞行频率也较高,是有高价值的客户群。