聚类算法属于无监督学习的一种,而其中KMeans算法是比较常用的聚类算法。
主要思想是: 1、在给定K值和K个初始类簇中心点的情况下,把每个点(亦即数据记录)分到离其最近的类簇中心点所代表的类簇中。 2、 所有点分配完毕之后,根据一个类簇内的所有点重新计算该类簇的中心点(取平均值)。 3、再迭代的进行分配点和更新类簇中心点的步骤,直至类簇中心点的变化很小,或者达到指定的迭代次数。
本文数据量:62988,
第一步:数据探索
拿到数据集,先进行整体上的观察
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\',\'客户类别\']
结果如下
参考文章:
保持渴求,不要沉寂