3.目标函数
使用误差平方和SSE作为度量聚类质量的目标函数,对于两种不同的聚类结果,选择误差平方和较小的分类结果。
连续属性的SSE计算公式为:
文档数据的SSE计算公式为:
簇Ei的聚类中心ei计算公式为:
表5-13为上述公式的符号说明。
表5-13 符号表
下面结合具体案例来实现本节开始提出问题。
部分餐饮客户的消费行为特征数据见表5-14。根据这些数据将客户分类成不同客户群,并评价这些客户群的价值。
表5-14 消费行为特征数据
采用K-Means聚类算法,设定聚类个数K为3,最大迭代次数为500次,距离函数取欧氏距离。
K-Means聚类算法的Python代码如代码清单5-4所示。
代码清单5-4 K-Means聚类算法代码
#-*- coding: utf-8 -*- #使用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 model = KMeans(n_clusters = k, n_jobs = 4, max_iter = iteration) #分为k类,并发数4 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) + [u'类别数目'] #重命名表头 print(r) #详细输出原始数据及其类别 r = pd.concat([data, pd.Series(model.labels_, index = data.index)], axis = 1) #详细 输出每个样本对应的类别 r.columns = list(data.columns) + [u'聚类类别'] #重命名表头 r.to_excel(outputfile) #保存结果
代码详见:示例程序/code/k_means.py
注意 事实上,Scikit-Learn中的K-Means算法仅仅支持欧氏距离,原因在于采用其他的距离并不一定能够保证算法的收敛性。
执行K-Means聚类算法输出的结果见表5-15。
表5-15 聚类算法输出结果
接着用Pandas和Matplotlib绘制的不同客户分群的概率密度函数图,通过这些图能直观地比较不同客户群的价值,代码如下。
绘制聚类后的概率密度图(接代码清单5-4)
def density_plot(data, title): #自定义作图函数 import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号 plt.figure() for i in range(len(data.iloc[0])): #逐列作图 (data.iloc[:,i]).plot(kind='kde', label = data.columns[i], linewidth = 2) plt.ylabel(u'密度') plt.xlabel(u'人数') plt.title(u'聚类类别%s各属性的密度曲线' %title) plt.legend() return plt 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(u'密度') for i in range(k)] plt.legend() return plt pic_output = '../tmp/pd_' #概率密度图文件名前缀 for i in range(k): density_plot(data[r[u'聚类类别']==i]).savefig(u'%s%s.png' %(pic_output, i))
代码详见:示例程序/code/k_means.py
分群的概率密度函数图如图5-12~图5-14所示。
图5-12 分群1的概率密度函数图
客户价值分析如下。
分群1特点:R间隔相对较小,主要集中在0~30天;消费次数集中在10~25次;消费金额在500~2000。
分群2特点:R间隔分布在0~30天;消费次数集中在0~12次;消费金额在0~1800。
图5-13 分群2的概率密度函数图
图5-14 分群3的概率密度函数图
分群3特点:R间隔相对较大,间隔分布在30~80天;消费次数集中在0~15次;消费金额在0~2000。
对比分析:分群1时间间隔较短,消费次数多,而且消费金额较大,是高消费、高价值人群。分群2的时间间隔、消费次数和消费金额处于中等水平,代表着一般客户。分群3的时间间隔较长,消费次数较少,消费金额也不是特别高,是价值较低的客户群体。
5.2.3 聚类分析算法评价
聚类分析仅根据样本数据本身将样本分组。其目标是实现组内的对象相互之间是相似的(相关的),而不同组中的对象是不同的(不相关的)。组内的相似性越大,组间差别越大,聚类效果就越好。
(1)purity评价法
purity方法是极为简单的一种聚类评价方法,只需计算正确聚类数占总数的比例。
其中,x=(x1,x2,…,xk)是聚类的集合。xk表示第k个聚类的集合。y=(y1,y2,…,yk)表示需要被聚类的集合,yi表示第i个聚类对象。n表示被聚类集合对象的总数。
(2)RI评价法
实际上,这是一种用排列组合原理来对聚类进行评价的手段,RI评价公式如下。
其中,R是指被聚在一类的两个对象被正确分类了,W是指不应该被聚在一类的两个对象被正确分开了,M指不应该放在一类的对象被错误的放在了一类,D指不应该分开的对象被错误的分开了。
(3)F值评价法
这是基于上述RI方法衍生出的一个方法,F评价公式如下。
其中,p=R/(R+M),r=R/(R+D)。
实际上RI方法就是把准确率p和召回率r看得同等重要,事实上,有时候我们可能需要某一特性更多一点,这时候就适合使用F值方法。
5.2.4 Python主要聚类分析算法
Python的聚类相关的算法主要在Scikit-Learn中,Python里面实现的聚类主要包括K-Means聚类、层次聚类、FCM以及神经网络聚类,其主要相关函数如表5-16所示。
表5-16 聚类主要函数列表
这些不同模型的使用方法是大同小异的,基本都是先用对应的函数建立模型,然后用.fit()方法来训练模型,训练好之后,就可以用.label_方法给出样本数据的标签,或者用.predict()方法预测新的输入的标签。
此外,Scipy库也提供了一个聚类子库scipy.cluster,里边提供了一些聚类算法,如层次聚类等,但没有Scikit-Learn那么完善和丰富。scipy.cluster的好处是它的函数名和功能基本跟Python是一一对应的(Scpiy致力于让Python称为Python般强大),如层次聚类的linkage、dendrogram等,因此已经熟悉Python的朋友,可以尝试使用Scipy提供的聚类库,在此就不详细介绍了。
下面介绍一个聚类结果可视化的工具——TSNE。
TSNE是Laurens van der Maaten和Geoffrey Hintton在2008年提出的,它的定位是高维数据的可视化。我们总喜欢能够直观地展示研究结果,聚类也不例外。然而,通常来说输入的特征数是高维的(大于3维),一般难以直接以原特征对聚类结果进行展示。而TSNE提供了一种有效的数据降维方式,让我们可以在2维或者3维的空间中展示聚类结果。
下面我们用TSNE对上述KMeans聚类的结果以二维的方式展示出来。
代码清单5-5 用TSNE进行数据降维并展示聚类结果
#-*- coding: utf-8 -*- #接k_means.py from sklearn.manifold import TSNE tsne = TSNE() tsne.fit_transform(data_zs) #进行数据降维 tsne = pd.DataFrame(tsne.embedding_, index = data_zs.index) #转换数据格式 import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号 #不同类别用不同颜色和样式绘图 d = tsne[r[u'聚类类别'] == 0] plt.plot(d[0], d[1], 'r.') d = tsne[r[u'聚类类别'] == 1] plt.plot(d[0], d[1], 'go') d = tsne[r[u'聚类类别'] == 2] plt.plot(d[0], d[1], 'b*') plt.show()
代码详见:示例程序/code/tsne.py
结果如图5-15所示。
图5-15 聚类效果图
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论