K-Means聚类分析--RFM模型

1 项目介绍

携程作为中国领先的综合性旅行服务公司,每天向超过2.5亿会员提供全方位的旅行服务,在这海量的网站访问量中,我们可分析用户的行为数据来挖掘潜在的信息资源,用K-means对用户进行画像,并针对不同的用户类别,提出可行的营销建议。

2 数据准备

2.1数据集来源:

数据集包括:训练集和测试集。训练集为2016.05.15-2016.05.21期间一周的访问数据,测试集为2016.05.22-2016.05.28期间一周的访问数据。本篇文章主要讨论的是聚类分析,所以只用训练集。

2.2 字段描述
K-Means聚类分析--RFM模型_第1张图片

3 数据处理

3.1 导入数据

#导入基础包
%matplotlib inline
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

#读取数据
df=pd.read_csv('./userlostprob_train.txt',sep='\t')
df.describe()

3.2 一致化处理

K-Means聚类分析--RFM模型_第2张图片
通过查看数据类型,发现所有字段中只有d、arrival两个字符串格式,分别代表预定时间和入住时间,都为yyyy-mm-dd日期形式,将其相减可得到“提前预定的天数”,得到新的衍生变量特征

# 转为日期型格式
df['arrival']=pd.to_datetime(df['arrival'])
df['d']=pd.to_datetime(df['d'])
# 相减得到“提前预定天数”列
df['day_advanced']=(df['arrival']-df['d']).dt.days
# 删除原有列
df=df.drop(['d','arrival'],axis=1)

3.3 异常值处理

通过描述统计观察发现,delta_price1、delta_price2、lowestprice、customer_value_profit、ctrip_profits这几个变量最小值为负值,需要对其处理。同时,结合四分位和极值,发现有极大或极小的异常值,如decisionhabit_user、historyvisit_avghotelnum等,较多字段都存在异常值,对所有字段一并进行处理。

for col in ['delta_price1','delta_price2','lowestprice']:
    df.loc[df[col]<0,col]=df[col].median()  # 填充中位数
for col in ['customer_value_profit','ctrip_profits']:
    df.loc[df[col]<0,col]=0  # 填充0
#极值处理
for i in df.columns:
    df.loc[df[i]<np.percentile(df[i],1),i]=np.percentile(df[i],1)
    df.loc[df[i]>np.percentile(df[i],99),i]=np.percentile(df[i],99)

3.4 缺失值处理

df.isnull().sum()

3.4.1缺失值删除

特征值中只有iforderpv_24h、sid、h、day_advanced这四个是不存在缺失的,其他的44个特征都是存在缺失值的,并且大部分的缺失值都挺多的,因此需要对缺失值进行处理
利用dropna(thresh=n)过滤方式,删除行列缺失值大于80%的数据。这里重点理解thresh参数的用法。

# 删除缺失值比例大于80%的行和列
print('删除空值前数据维度是:{}'.format(df.shape))
df.dropna(axis=0,thresh=df.shape[1]*0.2,inplace=True)  
df.dropna(axis=1,thresh=df.shape[0]*0.2,inplace=True)
print('删除空值后数据维度是:{}'.format(df.shape))

在这里插入图片描述

3.4.2缺失值补充

对缺失值补充前,先查看一下各变量的数值分布。

df.hist(figsize=(20,20))
plt.savefig('hist.png')

K-Means聚类分析--RFM模型_第3张图片
通过上图看出’businessrate_pre’,‘businessrate_pre2’,‘cancelrate_pre’,'customereval_pre2 '这些字段大体服从正态分布,可以用均值填充;其余字段大都呈右偏态分布,右偏分布就不可以用均值填充了,因为会受到极值的影响,但中位数不太受异常值或者极值的影响,使用中位数填充比较合适。

filter_mean=['businessrate_pre','businessrate_pre2','cancelrate_pre','customereval_pre2 ']
for i in df.columns:
    if i in filter_mean:
        df[i].fillna(df[i].mean(),inplace=True)
    else:
        df[i].fillna(df[i].median(),inplace=True)

3.5极值处理

通过上面数据描述分析,数据集中还存在极值,过大或者过小的值会对模型分析造成影响,这里通过截断填充的方式,分别对极小值和极大值进行处理。

for i in df.columns:
	#小于1%分位数的用1%分位数填充
    df.loc[df[i]<np.percentile(df[i],1),i]=np.percentile(df[i],1)   
    # 大于99%分位数的用99%分位数填充
    df.loc[df[i]>np.percentile(df[i],99),i]=np.percentile(df[i],99)  

4 数据分析

4.1 指标选取

RFM模型是衡量客户价值和客户创利能力的重要工具和手段,其有三个指标:最近一次消费时间间隔(Recency),消费频率(Frequency),消费金额(Monetary)。本数据集中三个指标并不都是直接给出,需要进行分析提取。

  • Recency:选用lasthtlordergap(距离上次下单时长)此字段。
  • Frequency:选用ordernum_oneyear(用户年订单数)此字段。
  • Monetary:选用avgprice(平均价格),consuming_capacity(消费能力指数)这两个字段作为消费金额指标,合并为consume_level。
consume_level=['avgprice','consuming_capacity']    # 合并字段作为消费水平

from sklearn.decomposition import PCA   #利用PCA主成分分析无监督的降维方法

pca=PCA(n_components=1)  #n_components设置为1
df['consume_level']=pca.fit_transform(df[consume_level])  #返回降维后的数据

df.drop(consume_level,axis=1,inplace=True)  #删除冗余列

4.2RFM建模分析

#字段重名
rfm = df[['lasthtlordergap','ordernum_oneyear','consume_level']]  
rfm.rename(columns={'lasthtlordergap':'recency','ordernum_oneyear':'frequency','consume_level':'monetary'},inplace=True)

#利用MinMaxScaler进行归一化处理
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaler.fit(rfm)
rfm = pd.DataFrame(scaler.transform(rfm),columns=['recency','frequency','monetary'])

#分箱
rfm['R']=pd.qcut(rfm["recency"], 2)
rfm['F']=pd.qcut(rfm["frequency"], 2)
rfm['M']=pd.qcut(rfm["monetary"], 2)

# 根据分箱情况进行编码,二分类可以直接用标签编码方式
from sklearn.preprocessing import LabelEncoder
rfm['R']=LabelEncoder().fit(rfm['R']).transform(rfm['R'])  
rfm['F']=LabelEncoder().fit(rfm['F']).transform(rfm['F'])
rfm['M']=LabelEncoder().fit(rfm['M']).transform(rfm['M'])

#定义RFM模型,需要特别注意的是,R值代表距离上次消费时间间隔,值越小客户价值越高,与F和M值正好相反。
def get_label(r,f,m):
    if (r==0)&(f==1)&(m==1):
        return '高价值客户'
    if (r==1)&(f==1)&(m==1):
        return '重点保持客户'
    if((r==0)&(f==0)&(m==1)):
        return '重点发展客户'
    if (r==1)&(f==0)&(m==1):
        return '重点挽留客户'
    if (r==0)&(f==1)&(m==0):
        return '一般价值客户'
    if (r==1)&(f==1)&(m==0):
        return '一般保持客户'
    if (r==0)&(f==0)&(m==0):
        return '一般发展客户'
    if (r==1)&(f==0)&(m==0):
        return '潜在客户'

def RFM_convert(df):
    df['Label of Customer']=df.apply(lambda x:get_label(x['R'],x['F'],x['M']),axis=1)
    
    df['R']=np.where(df['R']==0,'高','低')
    df['F']=np.where(df['F']==1,'高','低')
    df['M']=np.where(df['M']==1,'高','低')
    
    return df[['R','F','M','Label of Customer']]

rfm1=RFM_convert(rfm)
rfm1.head(5)

K-Means聚类分析--RFM模型_第4张图片
通过数据可视化直观看一下各类用户的占比情况

value_counts=rfm1["Label of Customer"].value_counts().values
labels=rfm1["Label of Customer"].value_counts().index
explode=[0.1,0.1,0.1,0,0,0,0,0]
color=['deepskyblue','steelblue','lightskyblue','aliceblue','skyblue','cadetblue','cornflowerblue','dodgerblue']
plt.figure(figsize=(10, 7))

plt.pie(x=value_counts,labels=labels,autopct='%.2f%%',explode=explode,colors=color,wedgeprops={'linewidth':0.5,'edgecolor':'black'},
textprops={'fontsize':12,'color':'black'})
plt.legend(labels,bbox_to_anchor=(1, 1), loc='best', borderaxespad=0.7)
plt.title('客户类别细分情况')
plt.show()

K-Means聚类分析--RFM模型_第5张图片
通过饼形图观察看出,一般发展客户数最多,占比40.72%,其次是潜在客户,高价值客户。

4.3 KMeans聚类分析

上面RFM模型只用到数据集中lasthtlordergap、ordernum_oneyear、avgprice、consuming_capacity这几个直接相关变量,但这些变量并不能完全涵盖用户特征,所以,接下来用K-Means聚类的方法引入其他变量进一步探究分析,观察不同类别客户的特征。

4.3.1相关性分析

观察整个数据集可以大体分为两个类别:用户信息和酒店信息。用户信息,即主体是用户,如consuming_capacity (消费能力指数)、price_sensitive(价格敏感指数)、starprefer(星级偏好)等,这些变量主要描述的是用户信息;酒店信息,即主体是酒店,如hotelcr (当前酒店历史cr),commentnums (当前酒店点评数)、novoters (当前酒店评分人数)等,这些变量主要描述的酒店信息。

# 用户特征提取
user_features=['visitnum_oneyear','starprefer','sid','price_sensitive','ordernum_oneyear','ordercanncelednum','ordercanceledprecent','lastpvgap',
               'lasthtlordergap','landhalfhours','iforderpv_24h','historyvisit_totalordernum','historyvisit_avghotelnum','h',
               'delta_price2','delta_price1','decisionhabit_user','customer_value_profit','ctrip_profits','cr','consume_level']
#生成用户特征的相关性矩阵
user_corr=df[user_features].corr()

#绘制用户特征的相关性矩阵热度图
fig,ax = plt.subplots(figsize=(18, 12))
sns.heatmap(user_corr, xticklabels=True, yticklabels=True, square=False, linewidths=.5, annot=True, cmap="YlGnBu")

K-Means聚类分析--RFM模型_第6张图片
从热图中看出:

  • ordernum_oneyear和historyvisit_totalordernum的相关性高达0.93,两者都是表示用户1年内订单数,特征选取时可以只选择其一,这里选择ordernum_oneyear作为用户年订单数的特征;
  • delta_price1和delta_price2的相关性达到了0.91,前者表示用户偏好价格-24小时浏览最多酒店价格,后者表示用户偏好价格-24小时浏览酒店平均价格,一定程度上说明浏览最多的酒店价格影响着平均价格,可以理解为众数和平均数的关系,这里选择PCA提取一个主成分表示用户价格偏好;
  • decisionhabit_user和historyvisit_avghotelnum相关性达到了0.89,前者表示用户决策习惯,后者表示近3个月用户历史日均访问酒店数,说明用户的决策习惯可能是基于用户近3个月的日均访问数判定的,这里选择用PCA提取一个主成分表示用户近期的日均访问量;
  • customer_value_profit和ctrip_profits这两个特征之间相关性达到了0.85,前者表示用户近一年的价值,后者也表示用户价值,细分区别在于衡量的时间长度不同,这里也选择PCA提取一个主成分表示用户价值。

4.3.2PCA降维

PCA降维可以在尽量保证“信息量不丢失”的情况下,对原始特征进行降维,也就是尽可能将原始特征往具有最大投影信息量的维度上进行投影,将原特征投影到这些维度上,使降维后信息量损失最小。

#删除historyvisit_totalordernum列
delete_columns = ['historyvisit_totalordernum']
df.drop(delete_columns,axis=1,inplace= True)

#PCA主成分分析
from sklearn.decomposition import PCA
#定义降维函数
def PCA_transform(df,col,new_col,n=1):
    pca=PCA(n_components=n)
    pca.fit(df[col])
    df[new_col]=pca.transform(df[col])    # 添加新生成列
    df.drop(col,axis=1,inplace= True)   # 删除原来的特征列
#选择特征
price_prefer=['delta_price1','delta_price2']                       # 用户价格偏好
visit_num=['decisionhabit_user','historyvisit_avghotelnum']        #用户访问数
c_value=['customer_value_profit','ctrip_profits']                  # 用户价值
#应用函数
PCA_transform(df,price_prefer,'price_prefer')
PCA_transform(df,visit_num,'visit_num')
PCA_transform(df,c_value,'c_value'

4.3.3K-Means聚类

K-Means算法是一种基于划分的无监督聚类算法,它以 k 为参数,把 n 个数据对象分成 k 个簇,使簇内具有较高的相似度,而簇间的相似度较低。

# 选取刻画用户的重要指标
user_feature = ['consume_level','c_value','day_advanced','h','lasthtlordergap','lastpvgap',
                'landhalfhours','ordernum_oneyear','ordercanceledprecent','price_sensitive','price_prefer','sid','starprefer','visit_num']
user_attributes = df[user_feature]

# 数据标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(user_attributes)
user_attributes = scaler.transform(user_attributes)

#K-Means聚类
from sklearn.cluster import KMeans
Kmeans=KMeans(n_clusters=3,random_state=13)                                     # 建立KMean模型
Kmeans.fit(user_attributes)                                                     # 训练模型
k_char=Kmeans.cluster_centers_                                                  # 得到每个分类的质心
personas=pd.DataFrame(k_char.T,index=user_feature,columns=['0类','1类','2类'])  # 用户画像表
personas

K-Means聚类分析--RFM模型_第7张图片

#绘制热力图
fig,ax = plt.subplots(figsize=(5, 10))
sns.heatmap(personas, xticklabels=True, yticklabels=True, square=False, linewidths=.5, annot=True, cmap="YlGnBu")

K-Means聚类分析--RFM模型_第8张图片
从热力图中可以直观看出:

  • 1类特征比较明显,consume_level消费水平为1.6,ordernum_oneyear用户年订单数为0.91,starprefer星级偏好为1.1,多个正向字段都为最大值,我们判定1类为高价值用户;
  • 2类特征中,lasthtlordergap一年内距离上次下单时长为1.8是三类中最大的,ordernum_oneyear用户年订单数为-0.46是三类中最小,c_value用户价值为-0.33也是三类中最小的,我们判定2类为低价值用户;
  • 0类,相对1类和2类特征不明显,大都处于中间值,我们判定0类为中价值用户。
#绘制饼形图
class_k=list(Kmeans.labels_)  # 每个类别的用户个数
percent=[class_k.count(0)/len(user_attributes),class_k.count(1)/len(user_attributes),class_k.count(2)/len(user_attributes)]   # 每个类别用户个数占比

fig, ax = plt.subplots(figsize=(11,11))
colors=['chocolate','sandybrown','peachpuff']
types=['中价值用户','高价值用户','低价值用户']
ax.pie(percent,radius=1,autopct='%.2f%%',pctdistance=0.75,colors=colors,labels=types)
ax.pie([1], radius=0.6,colors='w')
plt.show()

K-Means聚类分析--RFM模型_第9张图片

从饼形图中看出,高价值用户和低价值用户占比比较接近,都在15%左右;处于中间的中价值用户占比最高,占比约70%。

5 总结

基于上面聚类分析得到的用户特征,分别对不同价值用户给出运营建议:

  • 高价值用户:消费能力高,预定量和预定频率也都比较高,偏好星级酒店,但对价格比较敏感,这部分群体可能为商务人士,经常需要出差住宿但公司对差旅报销有价格限制,针对这部分用户群体,可以集中推荐交通便利、性价比高的商务酒店,同时,可以加强和企业合作,推广携程企业版,方便差旅审批报销,加强用户黏性;
  • 中价值用户分析:用户访问数和访问频率都比价高,但预定量不是很高,喜欢低价格的,说明这部分用户有一定的订房需求但比较注重价格,长时间在搜索对比价格,决策时间比较长,可以优化推荐算法,对这部分用户主要推送价格实惠的酒店,同时,系统对比其他订房平台上的房间价格,低于其他平台价格的房间可以特别标注全网最低,节省用户决策时间,提高用户体验,从而提升用户在本平台的使用率;
  • 低价值用户分析:最明显的特征就是登录访问频率低(距离上次访问间隔时间长),这部分用户可能是偶尔才在携程平台上预定酒店,重点在于激活用户,对长久未登录使用用户,可以发放优惠券,刺激消费;这部分群体也有可能住宿方面需求原本就小,目前属于潜在用户,可以定期推送平台信息,继续维持用户。

你可能感兴趣的:(案例分析,数据分析)