聚类分析
在当前市场环境下,消费者需求显现出日益差异化和个性化的趋势。随着我国市场化程度的逐步深入,以及信息技术的不断渗透,餐饮企业经常会碰到如下问题:
1)如何通过餐饮客户消费行为的测量,进一步评判餐饮客户的价值和对餐饮客户进行细分,找到有价值的客户群和需要关注的客户群?
2)如何对菜品进行合理分析,以便区分哪些菜品畅销且毛利高,哪些菜品滞销且毛利低?
餐饮企业遇到的这些问题,其实都可以通过聚类分析来解决。
一、常用聚类分析算法
与分类不同,聚类分析是在没有给定划分类别的情况下,根据数据相似度进行样本分组的一种方法。与分类模型需要使用有类标记样本构成的训练数据不同,聚类模型可以建立在无类标记的数据上,是一种非监督的学习算法。聚类的输入是一组未被标记的样本,聚类根据数据自身的距离或相似度将它们划分为若干组,划分的原则是组内样本最小化而组间(外部)距离最大化,如图1所示。

图1 聚类分析建模原理
常用聚类方法见表1。
表1 常用聚类方法

常用聚类分析算法见表2。
表2 常用聚类分析算法

二、K-Means聚类算法
K-Means算法[1]是典型的基于距离的非层次聚类算法,在最小化误差函数的基础上将数据划分为预定的类数K,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。
1.算法过程
K-Means聚类算法过程如下:
1)从n个样本数据中随机选取k个对象作为初始的聚类中心。
2)分别计算每个样本到各个聚类中心的距离,将对象分配到距离最近的聚类中。
3)所有对象分配完成后,重新计算k个聚类的中心。
4)与前一次计算得到的k个聚类中心比较,如果聚类中心发生变化,转至步骤2),否则转至步骤5)。
5)当质心不发生变化时,停止并输出聚类结果。
聚类的结果可能依赖于初始聚类中心的随机选择,使得结果严重偏离全局最优分类。实践中,为了得到较好的结果,通常选择不同的初始聚类中心,多次运行K-Means算法。在所有对象分配完成后,重新计算k个聚类的中心时,对于连续数据,聚类中心取该簇的均值,但是当样本的某些属性是分类变量时,均值可能无定义,此时可以使用K-众数方法。
2.数据类型与相似性的度量
(1)连续属性
对于连续属性,要先对各属性值进行零-均值规范,再进行距离的计算。K-Means聚类算法中,一般需要度量样本之间的距离、样本与簇之间的距离以及簇与簇之间的距离。
度量样本之间的相似性最常用的是欧几里得距离、曼哈顿距离和闵可夫斯基距离;度量样本与簇之间的距离可以用样本到簇中心的距离d(ei,x);度量簇与簇之间的距离可以用簇中心的距离d(ei,ej)。
设有p个属性来表示n个样本的数据矩阵阵 ,则其欧几里得距离为式(5-23),曼哈顿距离为式(5-24),闵可夫斯基距离为式(5-25)。

式(5-25)中,q为正整数,q=1时即为曼哈顿距离;q=2时即为欧几里得距离。
(2)文档数据
度量文档数据时可使用余弦相似性。先将文档数据整理成文档—词矩阵格式,如表3所示。
表3 文档—词矩阵

式(5-26)是两个文档之间的相似度的计算公式。

3.目标函数
使用误差平方和SSE作为度量聚类质量的目标函数,对于两种不同的聚类结果,选择误差平方和较小的分类结果。
式(5-27)为连续属性的SSE计算公式。

式(5-28)为文档数据的SSE计算式。

式(5-29)为簇Ei的聚类中心ei的计算公式。

对于上述公式,各符号表示的含义见表4。
表4 符号表

下面结合具体案例来实现本节开始提出的问题。
部分餐饮客户的消费行为特征数据如表5所示。根据这些数据将客户分成不同客户群,并评价这些客户群的价值。
表5 消费行为特征数据

采用K-Means聚类算法,设定聚类个数k为3,最大迭代次数为500次,距离函数取欧氏距离,如代码清单5-4所示。
代码清单5-4 使用K-Means算法聚类消费行为特征数据
import pandas as pd # 参数初始化 inputfile = '../data/consumption_data.xls' # 销量及其他属性数据 outputfile = '../tmp/data_type.xls' # 保存结果的文件名 k = 3 # 聚类的类别 iteration = 500 # 聚类最大循环次数 data = pd.read_excel(inputfile, index_col='Id') # 读取数据 data_zs = 1.0 * (data - data.mean()) / data.std() # 数据标准化 from sklearn.cluster import KMeans # 分为k类,并发数4 model = KMeans(n_clusters=k, n_jobs=4, max_iter=iteration,random_state=1234) model.fit(data_zs) # 开始聚类 # 简单打印结果 r1 = pd.Series(model.labels_).value_counts() # 统计各个类别的数目 r2 = pd.DataFrame(model.cluster_centers_) # 找出聚类中心 r = pd.concat([r2, r1], axis=1) # 横向连接(0是纵向),得到聚类中心对应的类别下的数目 r.columns = list(data.columns) + ['类别数目'] # 重命名表头 print(r) # 详细输出原始数据及其类别 r = pd.concat([data, pd.Series(model.labels_, index=data.index)], axis=1) # 详细输出每个样本对应的类别 r.columns = list(data.columns) + ['聚类类别'] # 重命名表头 r.to_excel(outputfile) # 保存结果 |
对于代码清单5-4需要注意的是,事实上scikit-learn库中的K-Means算法仅仅支持欧氏距离,原因在于采用其他的距离不一定能够保证算法的收敛性。
执行代码清单5-4得到的结果见表6。
表6 聚类算法输出结果

接着用pandas和Matplotlib绘制不同客户分群的概率密度函数图,通过这些图能直观地比较不同客户群的价值,如代码清单5-5所示,得到的结果如图2、图3、图4所示。
代码清单5-5 绘制聚类后的概率密度图
def density_plot(data): # 自定义作图函数 import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 p = data.plot(kind='kde', linewidth=2, subplots=True, sharex=False) [p[i].set_ylabel('密度') for i in range(k)] plt.legend() return plt pic_output = '../tmp/pd' # 概率密度图文件名前缀 for i in range(k): density_plot(data[r['聚类类别']==i]).savefig('%s%s.png' %(pic_output, i)) |

图2 分群1的概率密度函数图

图3 分群2的概率密度函数图
利用图可以分析出客户价值,具体如下:

图4 分群3的概率密度函数图
1)分群1特点:R间隔相对较大,间隔分布在30~80天;消费次数集中在0~15次;消费金额在0~2000元。
2)分群2特点:R间隔相对较小,主要集中在0~30天;消费次数集中在10~25次;消费金额在500~2000元。
3)分群3特点:R间隔分布在0~30天;消费次数集中在0~12次;消费金额在0~1800元。
4)对比分析:分群1时间间隔较短,消费次数多,而且消费金额较大,是高消费高价值人群。分群2时间间隔、消费次数和消费金额处于中等水平,代表着一般客户。分群3时间间隔较长,消费次数较少,消费金额也不是特别高,是价值较低的客户群体。
实验代码

