【数据分析实战经验】航空公司客户价值分析 LRMFC 模型(K-means聚类,工具python)

时间:2024-04-16 10:04:18

简单介绍

聚类算法属于无监督学习的一种,而其中KMeans算法是比较常用的聚类算法。

主要思想是: 1、在给定K值和K个初始类簇中心点的情况下,把每个点(亦即数据记录)分到离其最近的类簇中心点所代表的类簇中。 2、 所有点分配完毕之后,根据一个类簇内的所有点重新计算该类簇的中心点(取平均值)。 3、再迭代的进行分配点和更新类簇中心点的步骤,直至类簇中心点的变化很小,或者达到指定的迭代次数。

本文数据量:62988, 共有44个客户属性,其中包含了会员卡号、入会时间、性别、年龄、会员卡级别、在观测窗口内的飞行公里数、飞行时间等

第一步:数据探索

拿到数据集,先进行整体上的观察

    import pandas as pd
  import numpy as np
  df = pd.read_csv( \'air_data.csv\', encoding = \'utf-8\') #读取原始数据,指定UTF-8编码(需要用文本编辑器将数据装换为UTF-8编码)
  print(df.shape)
  print(df.info)

在这里插入图片描述 看看前5行

    df.head()

在这里插入图片描述 简单加工一下44属性名称 在这里插入图片描述 进行空值,最小,最大值的计算

    ex = df.describe(percentiles = [], include = \'all\').T #包括对数据的基本描述,percentiles参数是指定计算多少的分位数表(如1/4分位数、中位数等);T是转置,转置后更方便查阅
  ex[\'null\'] = len(df)- ex[\'count\'] #describe()函数自动计算非空值数,需要手动计算空值数
  ex = ex[[\'null\', \'max\', \'min\']]
  ex.columns = [u\'空值数\', u\'最大值\', u\'最小值\'] #表头重命名
  ex

在这里插入图片描述 发现数据集存在票价为空,总飞行公里数大于0的脏数据

具体处理方法如下: 删去票价为0的数据 及票价为0,折扣率不为0,总飞行公里数大于0的记录

第二步:数据清洗

    df= df[df[\'SUM_YR_1\'].notnull()&df[\'SUM_YR_2\'].notnull()] #票价非空值才保留
   
  #只保留票价非零的,或者平均折扣率与总飞行公里数同时为0的记录。
  index1 = df[\'SUM_YR_1\'] != 0
  index2 = df[\'SUM_YR_2\'] != 0
  index3 = (df[\'SEG_KM_SUM\'] == 0) & (df[\'avg_discount\'] == 0) #该规则是删去脏数据,要么有飞有折扣有公里数,要么就都是折扣为0且里程数为0
  df= df[index1 | index2 | index3] #该规则是“或”
  df.T

在这里插入图片描述 在这里插入图片描述 最终得到62044样本量

第三步 数据规约

在客户分类中,RFM模型是一个经典的分类模型,——最近消费(Recency)、消费频率(Frequency)、消费金额(Monetary)细分客户群体,从而分析不同群体的客户价值。

同样金额的不同旅客对公司的价值是不同的,比如买长航线低等级舱位的旅客与短途高等级舱位旅客相比,后者相对价值更高。因此,M消费金额不能用于衡量客户价值的一个因素,我们将其分解成两个。一定时间内的飞行里程M,一定时间内所坐舱位的平均折扣系数C。

最终我们选择: L(客户入会时间距今月数)、 R(客户最近一次乘机时间距今月数)、 F(客户在样本时间内乘机次数)、 M(客户在样本时间内的飞行里程)、 C(客户在样本时间内乘坐舱位的平均折扣系数) 因此,我们选择入会时间(FFP_date)、样本观测结束时间LOAD TIME、飞行次数(flight count)、平均折扣率(AVG DISCOUNT)、总飞行公里数(seg-km-sum)、最后一次乘机时间距今时长(last to end)这6个属性进行分析,删去其他弱相关属性

第四步 数据转换–LRMFC

L=LOAD_TIME-FFP_DATE(入会时长)

R=LAST_TO_END(最近一次乘机时间)

F=FLIGHT_COUNT(频次)

M=SEG_KM_SUM(飞行公里数)

C=AVG_DISCOUNT(平均折扣率)

    df[\'LOAD_TIME\']=pd.to_datetime(df[\'LOAD_TIME\']) #将字符串格式转换为日期格式
  df[\'FFP_DATE\'] = pd.to_datetime(df[\'FFP_DATE\'])
  df[\'L\']=df[\'LOAD_TIME\']- df[\'FFP_DATE\']
  #特征提取,只选L,LAST_TO_END,SEG_KM_SUM,avg_discount
  #即入会时间离观测结束的天数,最近一次乘机的月数,观测窗口的飞行次数,总飞行里程,折扣平均
   
  df1 = df[[\'L\',\'LAST_TO_END\',\'SEG_KM_SUM\',\'FLIGHT_COUNT\',\'avg_discount\']]
   
  df1=df1.rename(
      columns = {\'L\':\'L入会时间\',\'LAST_TO_END\':\'R最近消费距今时间\',\'SEG_KM_SUM\':\'M总里程\',\'FLIGHT_COUNT\':\'F飞行次数\',\'avg_discount\':\'C平均折扣率\'},
      inplace = False
  )
  df1.head()

在这里插入图片描述 观察一下各组数据间的最大最小值 在这里插入图片描述 由于不同的属性相差范围较大,这里进行标准化处理

    ##数据标准化
  df1 = (df1 - df1.mean(axis = 0))/(df1.std(axis = 0)) #简洁的语句实现了标准化变换,类似地可以实现任何想要的变换。
  df1.columns=[\'Z\'+i for i in df1.columns] #表头重命名。
  df1.head()

在这里插入图片描述

第五步 模型构建

首先采用无监督学习中K-means 进行模型构建,首先根据上述5个客户指标进行聚类,其次根据结果结合业务针对不同客户群进行分析,并进行排名。

K-Means算法主要就在于k=n_cluster参数的确定上面,到底是将k确定为几能进行更好的分类.因为是无监督的聚类分析问题,所以不存在绝对正确的值,需要进行研究试探。

这里采用计算SSE(肘点)的方法,尝试找到最好的K数值。

SSE值代表了每一个数据点离聚类中心的距离的评分,即为误差平方。当k小于真实聚类数时,随着k增大数据之间的聚合度会增加,SSE下降幅度会很大,当k快达到真实聚类值时,SSE下降幅度会变平稳,就想一个手肘的形状,肘点即为最优k值。

注:刚学完吴恩达机器学习,其实有时候K值也要参考实际商业价值来决定,例如卖T恤,是只卖3种型号,S、M、L还是xs,s,m,l,xl,等,哪种更符合人群,影响后续销量,这些都不一定是靠肘点能得到的,这点要注意。

代码如下

    ##模型构建
  from sklearn.cluster import KMeans #导入K均值聚类算法
  import matplotlib.pyplot as plt
  SSE = []
  for k in range(1,9):
      estimator = KMeans(n_clusters=k)
      estimator.fit(df1)
      SSE.append(estimator.inertia_)#样本到最近的聚类中心的距离平方之和
  X = range(1,9)
  plt.xlabel(\'k\')
  plt.ylabel(\'SSE\')
  plt.plot(X,SSE,\'o-\')
  plt.show()

在这里插入图片描述 观察图像,并没有的所谓的“肘”点出现,基本上是随k值的增大逐渐减小的。在k=4,5这段区间变化放缓 设K=5

    #取k=5进行的类别聚类
  k = 5                      
  #df1中读取数据并进行聚类分析
  #调用k-means算法#
  kmodel = KMeans(n_clusters = k, n_jobs = 4) #n_jobs是并行数,一般等于CPU数较好
  kmodel.fit(df1) #训练模型
   
  kmodel.cluster_centers_ #查看聚类中心
  kmodel.labels_ #查看各样本对应的类别
    r1 = pd.Series(kmodel.labels_).value_counts() #统计各个类别的数目
    r2 = pd.DataFrame(kmodel.cluster_centers_)#找出聚类中心
    # 所有簇中心坐标值中最大值和最小值
    max = r2.values.max()
    min = r2.values.min()
    r = pd.concat([r2, r1], axis = 1) #横向连接(0是纵向),得到聚类中心对应的类别下的数目
    r.columns = list(df1.columns) + [u\'各类别人数\'] #重命名表头
    r

在这里插入图片描述

第六步 绘制可视化雷达图

注:此部分代码主要参考 传送门

    ##绘图
    ## 中文和负号的正常显示
    plt.rcParams[\'font.sans-serif\'] = \'SimHei\'
    plt.rcParams[\'font.size\'] = 12.0
    plt.rcParams[\'axes.unicode_minus\'] = False
    fig=plt.figure(figsize=(10, 8))
    
    ax = fig.add_subplot(111, polar=True)
    center_num = r.values
    feature = ["L入会时间", "R最近消费距今时间", "M总里程", "F飞行次数程", "C平均折扣率"]
    N =len(feature)
    for i, v in enumerate(center_num):
        # 设置雷达图的角度,用于平分切开一个圆面
        angles=np.linspace(0, 2*np.pi, N, endpoint=False)
        # 为了使雷达图一圈封闭起来,需要下面的步骤
        center = np.concatenate((v[:-1],[v[0]]))
        angles=np.concatenate((angles,[angles[0]]))
        # 绘制折线图
        ax.plot(angles, center, \'o-\', linewidth=2, label = "第%d簇人群,%d人"% (i+1,v[-1]))
        # 填充颜色
        ax.fill(angles, center, alpha=0.25)
        # 添加每个特征的标签
        ax.set_thetagrids(angles * 180/np.pi, feature, fontsize=15)
        # 设置雷达图的范围
        ax.set_ylim(min-0.1, max+0.1)
        # 添加标题
        plt.title(\'客户群特征分析图\', fontsize=20)
        # 添加网格线
        ax.grid(True)
        # 设置图例
        plt.legend(loc=\'upper right\', bbox_to_anchor=(1.3,1.0),ncol=1,fancybox=True,shadow=True)
        
    # 显示图形
    plt.show()
    

在这里插入图片描述

第七步 总结分析

基于LRFMC模型的具体含义,我们可以对这5个客户群进行价值排名。同时,将这5个客户群重新定义为五个等级的客户类别:重要保持客户,重要挽留客户,重要发展客户,一般发展客户,低价值客户。 注意:每次跑出来的类型顺序会不一样,要做好辨别。

对应客户群1: 重要保持客户:这类客户乘坐的次数(F)和飞行的里程数(M)都很高。折扣率(C)和入会时间(L)也不低,说明他们经常乘坐飞机,且有一定经济实力,是航空公司的高价值客户。

对应客户群2 最大的特点是时间间隔差值(R)最大,其他指标表现一般,分析可能是“季节型客户”,一年中可能有一段时间需要乘坐飞机进行旅行等等,属于一般发展客户

对应客户群3 重要挽留客户:这类客户最大的特点就是入会的时间(L)较长,入会时间长(L),平均折扣率较低,而且总里程和总次数都不高,分析可能是流失的客户,需要在争取一下,尽量让他们“回心转意”;

对应客户群4: 重要发展客户:这类客户平均折扣率很高(C),最近乘坐过本航班时间间隔(R)短,但是乘坐的次数(F)和(M)都很低,成为会员的时间也很近(L),说明这些乘客刚入会员不久,所以乘坐飞机次数少,是未来重要发展客户。

对应客户群5

低价值客户:这类客户乘坐时间间隔长(R)或乘坐次数(F)和总里程(M)低,平均折扣也很低,各方面的数据都是比较低的

最终将表格的客户进行分类

    df1[\'聚类类别\'] = kmodel.labels_
    #划分客户类别
    for i in range(len(df1)):
        if df1[\'聚类类别\'][i] == 0:
            df1[\'聚类类别\'][i] = \'重要保持客户\'
    
        elif df1[\'聚类类别\'][i] == 1:
            df1[\'聚类类别\'][i] = \'一般发展客户\'
    
        elif df1[\'聚类类别\'][i] == 2:
            df1[\'聚类类别\'][i] = \'重要挽留客户\'
    
        elif df1[\'聚类类别\'][i] == 3:
            df1[\'聚类类别\'][i] = \'重要发展客户\'
        else:
            df1[\'聚类类别\'][i] = \'低价值客户\'
    
    #重命名属性
        df1.columns = [\'L\',\'R\',\'M\',\'F\',\'C\',\'客户类别\']

结果如下 在这里插入图片描述

参考文章: 1 2 3

保持渴求,不要沉寂

在这里插入图片描述