数分

【案例-数据挖掘】酒店流失情况预测

2019-09-25  本文已影响0人  X_Ran_0a11

案例源来自小白大神哈哈哈,给他笔芯:https://www.jianshu.com/p/7a3d94b1a191

ps:源数据的构造似乎有些问题,每行如果代表的是一个客户,但又具有一些酒店cr、uv率这些只属于酒店的特征,如果代表的是一个酒店,但又具有预定日期和入住日期这些只属于客户的特征。所以关于这一点就很不解。
之后好像反应过来,每一行可能代表每个客户进行一次酒店预定的信息,相关的酒店信息则对应其预定的那个酒店的情况。所以一个客户在里面是可能有很多条记录的,只是我们无法筛选出来。

分析思路:

0、数据准备
1、数据探索
2、特征工程
3、建模
4、RFM分析和用户画像

0、数据准备

0.1 模块及数据导入
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 解决坐标轴刻度负号乱码
plt.rcParams['axes.unicode_minus'] = False
# 解决中文乱码问题
plt.rcParams['font.sans-serif'] = ['Simhei']
%matplotlib inline
df=pd.read_csv(r'D:\Users\wuxiao\Desktop\userlostprob\userlostprob.txt',sep='\t')
df.head()
image.png
ps,如果仍然存在mac画图中文无法显示的问题:https://blog.csdn.net/qq_21904665/article/details/78732696
0.2 数据项基本信息
image.png

数据维度为689945*51,label为标签列,1为未流失,0为流失(等会儿再确认),samplied是id列?因为没有重复项,其余有49个特征项,下面将针对部分关键特征进行分析。

image.png

数据存在偏斜,但不平衡程度不大。


image.png

数据缺失值较多,特别是historyvisit_7ordernum缺失达到88%。

一、数据探索

1.1 预定日期和入住日期
df_d=df.d.value_counts().to_frame().reset_index()
df_arrival=df.arrival.value_counts().to_frame().reset_index()
time_table=df_d.merge(df_arrival,how='outer',on='index')
time_table.fillna(0,inplace=True)
time_table.set_index('index',inplace=True)
time_table.sort_index(inplace=True)

x=time_table.index
y1=time_table.arrival
y2=time_table.d

plt.figure(figsize=(13,5))
plt.style.use('bmh')
plt.plot(x,y1,c="r",label='入住人数');
plt.bar(x,y2,align="center",label='预定人数');
plt.title('访问和入住人数图',fontsize=20)
plt.xticks(rotation=45,fontsize=13)
plt.xlabel('日期');
plt.ylabel('人数',fontsize=13);
plt.legend(fontsize=13)
image.png

1.2 访问时间段

plt.figure(figsize=(15, 6))
plt.hist(df.h.dropna(), bins = 50, edgecolor = 'k');
#因为最多24个时段,所以bins再大的话,只是调整方块的间距了
plt.title('访问时间段',fontsize=20);
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.xlabel('访问时间',fontsize=18); 
plt.ylabel('人数',fontsize=18); 
image.png
1.3
plt.figure(figsize=(12, 4))

plt.subplot(121)
plt.plot(df.index,df.customer_value_profit,linewidth=0.5)
plt.title('客户近1年价值')

plt.subplot(122)
plt.plot(df.index,df.ctrip_profits,linewidth=0.5)
plt.title('客户价值')
image.png
1.4 消费能力指数
plt.figure(figsize=(12, 4))

plt.hist(df.consuming_capacity,bins=50,edgecolor='k')
plt.xlabel('消费能力指数')
plt.ylabel('人数')
plt.title('消费能力指数图')
image.png
1.5 价格敏感指数
plt.figure(figsize=(12, 4))

plt.hist(df['price_sensitive'].dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('价格敏感指数'); 
plt.ylabel('人数'); 
plt.title('价格敏感指数图');
image.png
1.6 入住酒店平均价格
plt.figure(figsize=(12, 4))
plt.subplot(121)
plt.hist(df.avgprice.dropna(),bins=50,edgecolor = 'k')
plt.xlabel('酒店价格'); 
plt.ylabel('偏好人数'); 
plt.title('酒店价格偏好');

plt.subplot(122)
plt.hist(df[df.avgprice<2000]['avgprice'].dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('酒店价格'); 
plt.ylabel('偏好人数'); 
plt.title('2000元以内酒店偏好');
image.png
1.7 酒店星级偏好
plt.figure(figsize=(10, 4))
plt.hist(df.starprefer.dropna(), bins = 50, edgecolor = 'k')
plt.xlabel('星级偏好程度')
plt.ylabel('选择人数');
plt.title('酒店星级偏好')
image.png
1.8 用户年订单数
plt.figure(figsize=(12, 4))
plt.subplot(121)
plt.hist(df.ordernum_oneyear.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('年订单数'); 
plt.ylabel('人数'); 
plt.title('客户年订单数分布');

plt.subplot(122)
plt.hist(df[df.ordernum_oneyear<100].ordernum_oneyear.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('年订单数'); 
plt.ylabel('人数'); 
plt.title('年订单数100单内的分布');
image.png
1.9 订单取消率
plt.figure(figsize=(10, 4))
plt.hist(df.ordercanceledprecent.dropna(),bins=50,edgecolor = 'k')
plt.xlabel('订单取消率')
plt.ylabel('人数')
plt.title('订单取消率')
image.png
1.10 举例上一次预定的时间
plt.figure(figsize=(10, 4))
plt.hist(df.lasthtlordergap.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('间隔时长'); plt.ylabel('人数'); 
plt.title('距离上次预定的时间');

image.png
1.11 新老客流失率
s_table=df[['label','sid']]
s_table['sid']=np.where(s_table['sid']==1,1,0)
s_table['flag']=1
s=s_table.groupby('sid').sum().reset_index()
s['rate']=s['label']/s['flag']                       # flag求和刚好是sid为0和1的个数,label求和刚好是流失人数,相除则为流失率

plt.figure(figsize=(12, 4))
plt.subplot(121)
percent=[s['flag'][0]/s['flag'].sum(),s['flag'][1]/s['flag'].sum()]
color=['steelblue','lightskyblue']
label=['老客','新访']
plt.pie(percent,autopct='%.2f%%',labels=label,colors=color)
plt.title('新老客户占比')

plt.subplot(122)
plt.bar(s.sid,s.rate,align='center',tick_label=label,edgecolor = 'k')
plt.ylabel('流失率')
plt.title('新老客户中的客户流失率')
image.png
1.12 酒店转换率
plt.figure(figsize=(10, 4))
plt.hist(df.hotelcr.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('酒店cr值');  
plt.title('酒店转换率');
image.png
1.13 酒店独立访客
plt.figure(figsize=(10, 4))
plt.hist(df.hoteluv.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('酒店uv值');  
plt.title('酒店历史独立访客量');
image.png
1.14 当前酒店点评数
plt.figure(figsize=(10, 4))
plt.hist(df.commentnums.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('点评数量');  
plt.title('酒店点评数');
image.png
1.15 当前酒店评分人数
plt.figure(figsize=(10, 4))
plt.hist(df.novoters.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('点评人数');  
plt.title('酒店评分人数');
image.png
1.16 当前酒店历史订单取消率
plt.figure(figsize=(10, 4))
plt.hist(df.cancelrate.dropna(), bins = 50, edgecolor = 'k');
plt.xlabel('订单取消率');  
plt.title('酒店订单取消率');
image.png
1.17 当前酒店可订最低价
plt.figure(figsize=(10, 4))
plt.plot(df.lowestprice.dropna())
plt.xlabel('酒店最低价');  
plt.title('酒店最低价');
image.png

二、特征工程

# 为了避免在原数据集上进行修改操作,我们将df复制一份
df1=df.copy()
2.1 字符串处理

原数据中,arrival和d都是字符串格式,可以将其详见得到“提前预定的天数”,并转化为新的数值特征。

## 增加列
# 将两个日期变量由字符串转换为日期型格式
df1['arrival']=pd.to_datetime(df1['arrival'])
df1['d']=pd.to_datetime(df1['d'])
# 生成提前预定时间列
df1['day_advanced']=(df1['arrival']-df1['d']).dt.days

## 删除列
df1=df1.drop(['d','arrival'],axis=1)

处理后:


image.png

ps:pd显示的模式有数值模式/datetime/其他格式,所以是可以转化成datetime格式再处理的。http://www.manongjc.com/article/3143.html,有空可以再研究

2.2 异常值处理

把用户价值的两个特征量customer_value_profit、ctrip_profits中的负值按0处理;把delta_price1、delta_price2、lowestprice中的负值按中位数处理。我个人也不知道为什么这么处理,因为里面很多特征并不知道具体含义。

filter1=['customer_value_profit','ctrip_profits']
filter2=['delta_price1','delta_price2','lowestprice']

for i in filter1:
    df1.loc[df1[i]<0,i]=0        ##用df1.loc[df1[i]<0][i]=0 会提示无法有点问题,所以还是得用前面的用法
    
for i in filter2:
    temp=df.delta_price1.mean()
    df1.loc[df1[i]<0,i]=temp    ##用df1.loc[df1[i]<0][i]=0 会提示无法有点问题,所以还是得用前面的用法

处理后:


image.png
2.3 缺失值处理

原数据中只有iforderpv_24h、sid、h、day_advanced这四个是不存在缺失的,其他的44个特征都是存在缺失值的,并且大部分的缺失值都挺多的,因此,我们接下来需要对缺失值进行处理。

2.3.1 空值删除

首先设定rate为0.2,如果某行或某列的数据缺失率超过(1-0.2)=0.8,则将其删除:

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

数据项基本满足正态分布或者右偏分布,对正态分布项,采用均值填充较合适,对右偏分布项,采用中位数填充更合适。原数据中,businessrate_pre2、cancelrate_pre、businessrate_pre趋于正态分布,齐豫趋于右偏分布(这一点没有详细考证)。

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

ps:偏态分布https://zhidao.baidu.com/question/361765236.html

image.png
2.5 极值处理

有些特征明显有异常大和异常小的值,这里分别用1%和99%分位数替换超过上下限的值。

for i in df1.columns:
    df1.loc[df1[i]<np.percentile(df1[i],1),i]=np.percentile(df1[i],1)
    df1.loc[df1[i]>np.percentile(df1[i],99),i]=np.percentile(df1[i],99)
2.3.4 相关性分析
# 用户特征提取(分两次提取,为了更好地显示图)
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','consuming_capacity','avgprice']
# 生成用户特征的相关性矩阵
corr_mat=df1[user_features].corr()

# 绘制用户特征的相关性矩阵热度图
plt.figure(figsize=(12,12))
sns.heatmap(corr_mat, xticklabels=True, yticklabels=True, square=False, linewidths=.5, annot=True, cmap='Blues')
image.png

可以看出,不少特征存在强相关性:

# 用户特征提取(分两次提取)
user_features=['hotelcr','hoteluv','commentnums','novoters','cancelrate','lowestprice','cr_pre','uv_pre','uv_pre2','businessrate_pre',
                'businessrate_pre2','customereval_pre2','commentnums_pre','commentnums_pre2','cancelrate_pre','novoters_pre','novoters_pre2',
                'deltaprice_pre2_t1','lowestprice_pre','lowestprice_pre2','firstorder_bu','historyvisit_visit_detailpagenum']
# 生成用户特征的相关性矩阵
corr_mat=df1[user_features].corr()

# 绘制用户特征的相关性矩阵热度图
plt.figure(figsize=(12,12))
sns.heatmap(corr_mat, xticklabels=True, yticklabels=True, square=False, linewidths=.5, annot=True, cmap='Blues')
image.png
2.6 降维
c_value=['customer_value_profit','ctrip_profits']                   # 用户价值
consume_level=['avgprice','consuming_capacity']                     # 用户消费水平
price_prefer=['delta_price1','delta_price2']                        # 用户偏好价格
hotel_hot=['commentnums','novoters']                                # 酒店热度
hotel_hot_pre=['commentnums_pre','novoters_pre']                    # 24小时内浏览次数最多的酒店热度
hotel_hot_pre2=['commentnums_pre2','novoters_pre2']                 # 24小时内浏览酒店的平均热度

from sklearn.decomposition import PCA
pca=PCA(n_components=1)
df1['c_value']=pca.fit_transform(df1[c_value])
df1['consume_level']=pca.fit_transform(df1[consume_level])
df1['price_prefer']=pca.fit_transform(df1[price_prefer])
df1['hotel_hot']=pca.fit_transform(df1[hotel_hot])
df1['hotel_hot_pre']=pca.fit_transform(df1[hotel_hot_pre])
df1['hotel_hot_pre2']=pca.fit_transform(df1[hotel_hot_pre2])

df1.drop(c_value,axis=1,inplace=True)
df1.drop(consume_level,axis=1,inplace=True)
df1.drop(price_prefer,axis=1,inplace=True)
df1.drop(hotel_hot,axis=1,inplace=True)
df1.drop(hotel_hot_pre,axis=1,inplace=True)
df1.drop(hotel_hot_pre2,axis=1,inplace=True)
df1.drop('historyvisit_totalordernum',axis=1,inplace=True)  ###把重复的一列删了
df1.drop('sampleid',axis=1,inplace=True)   ###把id列删了
image.png

ps: pca用法https://www.jianshu.com/p/8642d5ea5389

2.7 数据标准化
# 数据标准化
from sklearn.preprocessing import StandardScaler

y=df1['label']
x=df1.drop('label',axis=1)

scaler = StandardScaler()
X= scaler.fit_transform(x)   #先用fit求得训练数据的标准差和均值,再用transform将数据转化成

sklearn中标准化模块的用法:https://blog.csdn.net/u011734144/article/details/84066784
几种标准化的方法:
https://www.jianshu.com/p/fa73a07cd750
考虑到基本都是负荷正态分布或者偏态分布的,所以这里是标准化为标准正态分布,否则的话,采用min-max标准化等其他方法可能会更好。
标准化后的数据形态:

image.png

三、建模

先拆分训练集和数据集

from sklearn import model_selection

X_train,X_test,y_train,y_test = model_selection.train_test_split(X,y,test_size= 0.2,random_state=1)

PS:random_state相当于添加随机数种子进行标记https://www.jianshu.com/p/4deb2cb2502f

3.1 逻辑回归
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
from sklearn.metrics import classification_report

lr = LogisticRegression()                                        # 实例化一个LR模型
lr.fit(X_train,y_train)                                          # 训练模型
y_prob = lr.predict_proba(X_test)[:,1]                           # 预测1类的概率
y_pred = lr.predict(X_test)                                      # 模型对测试集的预测结果
fpr_lr,tpr_lr,threshold_lr = metrics.roc_curve(y_test,y_prob)    # 获取真阳率、伪阳率、阈值
auc_lr = metrics.auc(fpr_lr,tpr_lr)                              # AUC得分
score_lr = metrics.accuracy_score(y_test,y_pred)                 # 模型准确率


print('模型准确率为:{0},AUC得分为:{1}'.format(score_lr,auc_lr))
print('  ')
print(classification_report(y_test, y_pred, labels=None, target_names=None, sample_weight=None, digits=2))
image.png
3.2 朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
from sklearn import metrics
from sklearn.metrics import classification_report

gnb = GaussianNB()                                                # 实例化一个LR模型
gnb.fit(X_train,y_train)                                          # 训练模型
y_prob = gnb.predict_proba(X_test)[:,1]                           # 预测1类的概率
y_pred = gnb.predict(X_test)                                      # 模型对测试集的预测结果
fpr_gnb,tpr_gnb,threshold_gnb = metrics.roc_curve(y_test,y_prob)    # 获取真阳率、伪阳率、阈值
auc_gnb = metrics.auc(fpr_gnb,tpr_gnb)                              # AUC得分
score_gnb = metrics.accuracy_score(y_test,y_pred)                 # 模型准确率


print('模型准确率为:{0},AUC得分为:{1}'.format(score_gnb,auc_gnb))
print('  ')
print(classification_report(y_test, y_pred, labels=None, target_names=None, sample_weight=None, digits=2))
image.png
查看了一下预测的分为1类和0类的概率:
image.png
所以这里的贝叶斯概率并不是真实概率(真实概率为所有独立变量概率的成绩,理论上是一个很小很小的值,而不会是一个mean值在0.5左右的值)。
有空可以研究下他的算法代码
3.3 支持向量机
from sklearn.svm import SVC
from sklearn import metrics
from sklearn.metrics import classification_report

svc = SVC(kernel='rbf',C=1,max_iter=100).fit(X_train,y_train)
y_prob = svc.decision_function(X_test)                              # 决策边界距离
y_pred = svc.predict(X_test)                                        # 模型对测试集的预测结果
fpr_svc,tpr_svc,threshold_svc = metrics.roc_curve(y_test,y_prob)     # 获取真阳率、伪阳率、阈值
auc_svc = metrics.auc(fpr_svc,tpr_svc)                              # 模型准确率
score_svc = metrics.accuracy_score(y_test,y_pred)

print('模型准确率为:{0},AUC得分为:{1}'.format(score_gnb,auc_gnb))
print('  ')
print(classification_report(y_test, y_pred, labels=None, target_names=None, sample_weight=None, digits=2))
image.png
3.4 决策树
from sklearn import tree
from sklearn import metrics
from sklearn.metrics import classification_report

dtc = tree.DecisionTreeClassifier()                              # 建立决策树模型
dtc.fit(X_train,y_train)                                         # 训练模型
y_prob = dtc.predict_proba(X_test)[:,1]                          # 预测1类的概率
y_pred = dtc.predict(X_test)                                     # 模型对测试集的预测结果 
fpr_dtc,tpr_dtc,threshod_dtc= metrics.roc_curve(y_test,y_prob)   # 获取真阳率、伪阳率、阈值               
auc_dtc = metrics.auc(fpr_dtc,tpr_dtc)                           # AUC得分
score_dtc = metrics.accuracy_score(y_test,y_pred)                # 模型准确率

print('模型准确率为:{0},AUC得分为:{1}'.format(score_dtc,auc_dtc))
print('  ')
print(classification_report(y_test, y_pred, labels=None, target_names=None, sample_weight=None, digits=2))
image.png
3.5 随机森林
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics
from sklearn.metrics import classification_report

rfc = RandomForestClassifier()                                     # 建立随机森林分类器
rfc.fit(X_train,y_train)                                           # 训练随机森林模型
y_prob = rfc.predict_proba(X_test)[:,1]                            # 预测1类的概率
y_pred=rfc.predict(X_test)                                         # 模型对测试集的预测结果
fpr_rfc,tpr_rfc,threshold_rfc = metrics.roc_curve(y_test,y_prob)   # 获取真阳率、伪阳率、阈值  
auc_rfc = metrics.auc(fpr_rfc,tpr_rfc)                             # AUC得分
score_rfc = metrics.accuracy_score(y_test,y_pred)                  # 模型准确率

print('模型准确率为:{0},AUC得分为:{1}'.format(score_rfc,auc_rfc))
print('  ')
print(classification_report(y_test, y_pred, labels=None, target_names=None, sample_weight=None, digits=2))
image.png
3.6 模型比较
plt.style.use('bmh')
plt.figure(figsize=(13,10))

plt.plot(fpr_lr,tpr_lr,label='lr: {0:.3f}'.format(score_lr))                             # 逻辑回归
plt.plot(fpr_gnb,tpr_gnb,label='gnb:{0:.3f}'.format(score_gnb))                          # 朴素贝叶斯模型
plt.plot(fpr_svc,tpr_svc,label='svc:{0:.3f}'.format(score_svc))                                             # 支持向量机模型
plt.plot(fpr_dtc,tpr_dtc,label='dtc:{0:.3f}'.format(score_dtc))                          # 决策树
plt.plot(fpr_rfc,tpr_rfc,label='rfc:{0:.3f}'.format(score_rfc))                          # 随机森林

plt.legend(loc='lower right',prop={'size':25})
plt.xlabel('误诊率')
plt.ylabel('灵敏度')
plt.title('ROC曲线')
image.png

随机森林胜出!

调用决策树画图:
http://ywtail.github.io/2017/06/08/sklearn%E5%86%B3%E7%AD%96%E6%A0%91%E5%8F%AF%E8%A7%86%E5%8C%96/
本来想画图,但是又卡了,可能是因为变量太多了,想想也是。。

四、RFM分析和用户画像

4.1 RFM分析

RFM模型,即为:
R(Rencency):最近一次消费
F(Frequency):消费频率
M(Monetary):消费金额


image.png

在本案例中,我们选择lasthtlordergap(距离上次下单的时长)、ordernum_oneyear(用户年订单数)、consume_level(用户消费水平)分别作为R、F、M的值,对我们的用户群体进行聚类。

rfm = df1[['lasthtlordergap','ordernum_oneyear','consume_level']]  #consume_level是PCA后的特征变量

#归一化
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

#从0开始编码的,所以这里直接编码是可以的
rfm['R']=LabelEncoder().fit(rfm['R']).transform(rfm['R'])      #这里需要注意,R为距离上次下单的市场,越小则代表价值越高,所以这一点是反的
rfm['F']=LabelEncoder().fit(rfm['F']).transform(rfm['F'])
rfm['M']=LabelEncoder().fit(rfm['M']).transform(rfm['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']]

rfm0=RFM_convert(rfm)
rfm0.head(10)
image.png

各类客户的占比:

temp=rfm0.groupby('Label of Customer').size()

plt.figure(figsize=(12,12))
colors=['deepskyblue','steelblue','lightskyblue','aliceblue','skyblue','cadetblue','cornflowerblue','dodgerblue']
plt.pie(temp,radius=1,autopct='%.1f%%',pctdistance=0.75,colors=colors)
plt.pie([1],radius=0.6,colors='w')   ##可以用这种方式画空心
plt.title('客户细分情况')
plt.legend(temp.index)
image.png
4.2 用户画像

其实我们并不想将用户分的这么细,并且我们其实有挺多的用户行为特征数据,所以也并不想仅用RFM这3个指标进行分析。所以,我们接下来用K-Means聚类的方法将用户分为3类,观察不同类别客户的特征。

# 选取出几个刻画用户的重要指标
user_feature = ['decisionhabit_user','ordercanncelednum','ordercanceledprecent','consume_level','starprefer','lasthtlordergap','lastpvgap','h','sid',
                'c_value','landhalfhours','price_sensitive','price_prefer','day_advanced','historyvisit_avghotelnum','ordernum_oneyear']
user_attributes = df1[user_feature]
user_attributes.head()

# 数据标准化
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(user_attributes)

user_attributes = scaler.transform(user_attributes)
from sklearn.cluster import KMeans

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

plt.figure(figsize=(5,10))
sns.heatmap(personas, xticklabels=True, yticklabels=True, square=False, linewidths=.5, annot=True, cmap='Blues')
image.png
plt.figure(figsize=(9,9))

class_k=list(Kmeans.labels_)                          # 每个类别的用户个数
percent=[class_k.count(1)/len(user_attributes),class_k.count(0)/len(user_attributes),class_k.count(2)/len(user_attributes)]   # 每个类别用户个数占比

fig, ax = plt.subplots(figsize=(10,10))
colors=['aliceblue','steelblue','lightskyblue']
types=['中等群体','低价值用户','高价值用户']
ax.pie(percent,radius=1,autopct='%.2f%%',pctdistance=0.75,colors=colors,labels=types)
ax.pie([1], radius=0.6,colors='w')
image.png
4.3 用户画像分析
上一篇 下一篇

猜你喜欢

热点阅读