携程客戶流失案例-數據預處理篇

项目背景

在今天产品高度同质化的阶段,市场竞争不断加剧,企业与企业之间的竞争,主要集中在对客户的争夺上。“用户就是上帝”促使众多企业不惜代价去争夺尽可能多的新客户。但是,在企业不惜代价发展新用户的过程中,往往会忽视老用户的流失情况,结果就导致出现新用户在源源不断的增加,辛苦找来的老用户却在悄无声息的流失的窘状。
如何处理客户流失的问题,成为一个非常重要的课题。那么,我们如何从数据汇总挖掘出有价值的信息,来防止客户流失呢?

行业情况:携程曾占据在线酒店的主要市场,但是随着美团在2017年加入,格局很快被打破


2018年3月在线酒店预定平台情况

从下图可以看出:行业Top3的用户重合率较低,用户差异度明显。用户与市场竞争具有很大的相关性。

2018年2月-3月重合用户

项目目标

  • 挖掘用户流失的关键因素
  • 预测客户的转化效果
  • 用户画像

项目方案

  • 使用pandas,numpy,sklearn.processing对数据进行预处理
  • 使用LogisticRedression和DecisionTreeClassifier预测
  • 用K-Means对用户进行画像,针对不同用户类别,提出可行建议

项目流程

  1. 数据预处理
    • 衍生变量
    • 删除缺失比列>80%的列
    • 过滤无用维度
    • 异常值负数处理
    • 缺失值填充
    • 极值处理
    • 相关性
    • 标准化处理
  2. 建模预测
    • LogisticRedression预测
    • DecisionTreeClassifier预测
    • 结果可视化
  3. 用户画像
    • 用K-Means对用户进行画像
  1. 数据预处理
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

df = pd.read_csv('userlostprob.txt',sep = '\t')
df.info()    #查看数据信息
df.head()  #查看前5行数据
df.describe()   #查看数值型数据描述统计信息
携程客戶流失案例-數據預處理篇_第1张图片
好多個特徵啊

看一下每個特徵的含義,最大最小值
特徵含義在https://www.jianshu.com/p/c77d4f4cea3c拿的

maxx = []     #放最大值的列表
minn = []     #放最小值的列表
for i in df.columns:                  #遍歷
    maxx.append(df[i].max())    #插入 
    minn.append(df[i].min())     

data = pd.DataFrame(df.columns,columns = ['name'])  #dataframe生成
chinese = pd.read_csv('description.csv')   #讀取之前爬的含義列表
chinese = chinese.drop(['Unnamed: 0'], axis=1)  #刪一下第一行,之前標題沒處理好= =  
chinese = chinese.drop([0])         #爬完然後to_csv處理沒注意,多了一列索引

data = pd.merge(chinese,data, on='name')   #xxxjoinxxx on xxx =xxx
data['max'] = maxx  
data['min'] = minn
携程客戶流失案例-數據預處理篇_第2张图片
清晰了些
携程客戶流失案例-數據預處理篇_第3张图片
太多了。。

晚些再對著這個表幹活,現在看看缺失情況

data_count = df.count()     #計算個屬性的非空值數量
na_count = len(df) - data_count    #空值數量 =  總量 - 非空值
na_rate = na_count/len(df)         #空值占比 =  空值數量/總量
a = na_rate.sort_values(ascending=True) #控制占比的排序 基於上面的排序默認是從低到高
                                        #按values正序排列,不放倒序是为了后边的可視化展示排列
a1 = pd.DataFrame(a)
a1.head()
携程客戶流失案例-數據預處理篇_第4张图片
看的不舒服再轉成中文吧
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif']=['SimHei']
x = df.shape[1]   #有幾個屬性?
fig = plt.figure(figsize=(8,12)) #設置畫布大小
plt.barh(range(x),a1[0],color='steelblue',alpha=1)  ##框架句,(51條屬性,缺失占比,藍色)
plt.xlabel('数据缺失占比') #添加轴标签

#英文列名称
#columns1 = a1.index.values.tolist() 
#中文列名称
columns1 = data['chinese'].values.tolist() 

plt.yticks(range(x),columns1)
plt.xlim([0,1])                 #设置X轴的刻度范围

plt.show()
携程客戶流失案例-數據預處理篇_第5张图片
image.png

。。。有點多

数据预处理

衍生变量
删除80%+缺失值列
过滤无用维度
异常值负数处理
缺失值填充
极值处理


首先回顧一下表格

携程客戶流失案例-數據預處理篇_第6张图片
image.png

再回顧下之間的df.info()


image.png

對時間為object的進行處理

df['d'] = pd.to_datetime(df['d'])
df['arrival'] = pd.to_datetime(df['arrival'])

删除缺失值比列88%的列historyvisit_7ordernum

df = df.drop(['historyvisit_7ordernum'],axis=1)

處理酒店流失問題,判定哪些特徵有無用,可以刪掉,並取新列
從日期開始後面的指標乍一看都好像很有用,那前邊的幾個呢,
ld已有索引,沒有重複 可以刪掉
label後面留著算法驗證要用
訪問日期和入住日期乍看似乎沒有用,但似乎可以構成一個新的維度
就是提前了幾天訂酒店,似乎日常上越晚訂越不會流失
可以嘗試引入一下,并把這兩個刪掉

#引入
df['Advance booking'] = (df['arrival']-df['d']).dt.days
#無用的維度
filter_feature = ['sampleid','d','arrival']
feature = []
for x in df.columns:
    if x not in filter_feature:
        feature.append(x)

df_x = df[feature]
df_y = df['label']

异常值负数处的处理

#查找那些屬性有負數值


a = []
for i in range(len(data['min'])):             
    if type(data['min'][i]) == str:              #遍歷查找非int和float的值
        a.append(i)                                    #得到索引
data = data.drop(labels=a,axis=0)     #利用索引刪掉
data = data.reset_index()                  #重構索引

for i in range(len(data)):                       
    if data['min'][i] < 0:
        print(data['name'][i])
携程客戶流失案例-數據預處理篇_第7张图片
image.png

共6列有负值,
但其中deltaprice_pre2_t1(24小时内已访问酒店价格与对手价差均值)正常,
所以其余5列,分别为
客户价值 (ctrip_profits)
客户价值近1年 (customer_value_profit)
用户偏好价格-24小时浏览最多酒店价格(delta_price1)、
用户偏好价格-24小时浏览酒店平均价格(delta_price2)、
当年酒店可订最低价(lowestprice)


根據各特徵情況

客户价值近1年 (customer_value_profit)、
客户价值 (ctrip_profits) 替换为0

用户偏好价格-24小时浏览最多酒店价格(delta_price1)、
用户偏好价格-24小时浏览酒店平均价格(delta_price2)、
当年酒店可订最低价(lowestprice)按中位数处理

df_x.loc[df_x.customer_value_profit<0,'customer_value_profit'] = 0
df_x.loc[df_x.ctrip_profits<0,'ctrip_profits'] = 0
df_x.loc[df_x.delta_price1<0,'delta_price1'] = df_x['delta_price1'].median()
df_x.loc[df_x.delta_price2<0,'delta_price2'] = df_x['delta_price2'].median()
df_x.loc[df_x.lowestprice<0,'lowestprice'] = df_x['lowestprice'].median()

缺失值填充
查看数据分布情况

for i in range(0,48):
    #df_x.columns = data['chinese'] #中文化
    plt.figure(figsize=(2,1),dpi=100)
    plt.hist(df_x[df_x.columns[i]].dropna().get_values())
    plt.xlabel(df_x.columns[i])
plt.show()

注意他們的分佈情況


携程客戶流失案例-數據預處理篇_第8张图片
image.png

趋于正态分布的字段,用均值填充:字段有businesstate_pre2,cancelrate_pre,businessrate_pre;

fill_list = ['businessrate_pre','businessrate_pre2','cancelrate_pre']
for i in fill_list:
    df_x[i] = df_x[i].fillna(df_x[i].mean())

#df_x['businessrate_pre2'] = df_x['businessrate_pre2'].fillna(df_x['businessrate_pre2'].mean())
#這個是平均數替補

右偏分布的字段,用中位数填充

def filling(data):
    for i in range(0,48):
        df_x[df_x.columns[i]] = df_x[df_x.columns[i]].fillna(df_x[df_x.columns[i]].median())
    return df_x

filling(df_x)
携程客戶流失案例-數據預處理篇_第9张图片
前後填補對比

看看情況

df_count2 = df_x.count()
df_count2
携程客戶流失案例-數據預處理篇_第10张图片
data_count2 = df_x.count()
na_count2 = len(data_x) - data_count2
na_rate2 = na_count2/data_count2
aa2 = na_rate2.sort_values(ascending=False)
a3 = pd.DataFrame(aa2)

极值处理
盖帽法:某连续变量6西格玛之外的记录用正负3西格玛值替代,一般正负3西格玛包含99%的数据,所以默认凡小于百分之一分位数和大于百分之九十九分位数的值用百分之一分位数和百分之九十九分位数代替,俗称盖帽法

就是切比雪夫定理啦

携程客戶流失案例-數據預處理篇_第11张图片
image.png
data1 = np.array(data_x)  #将data_x替换成numpy格式

for i in range(0,len(data1[0])): #列循环,以便取到每列的值
    a = data1[:,i] #将每列的值赋值到a
    
    b = np.percentile(a,1) #计算1百分位数据
    c = np.percentile(a,99) #计算99百分位数据
    for j in range(0,len(data1[:,0])):
        if a[j] < b:
            a[j] = b
        elif a[j] > c:
            a[j] = c
        else:
            a[j]
            
data1 = pd.DataFrame(data1,columns=feature)  
dat = pd.concat((data1['consuming_capacity'],data1['customer_value_profit'],data1['ordercanncelednum'],data1['ordercanceledprecent'],data1['ctrip_profits'],data1['historyvisit_totalordernum'],data1['lastpvgap'],data1['lasthtlordergap']),axis=1)
dat.to_csv('rfm.csv',index=False)

檢查分佈情況

#检查处理后数据(极值和负值)
#箱线图检查极值
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
for i in range(0,48):
    plt.figure(figsize=(4,8),dpi=100)
    plt.boxplot(data1[data1.columns[i]].dropna().get_values())
    plt.xlabel(data1.columns[i])
plt.show()
#查看最小值是不是负数
list_check = ['ctrip_profits','customer_value_profit','delta_price1','delta_price2','lowestprice']
for i in list_check:
    print(data1[i].min())
携程客戶流失案例-數據預處理篇_第12张图片
image.png

最後情況


携程客戶流失案例-數據預處理篇_第13张图片
image.png

数据来源:链接:https://pan.baidu.com/s/1QDYDICb2Jo2pKgD98aDY2A
提取码:wawf

冠軍文章:https://cloud.tencent.com/developer/article/1063197

你可能感兴趣的:(携程客戶流失案例-數據預處理篇)