返回介绍

3.目标函数

发布于 2024-01-28 21:41:24 字数 7059 浏览 0 评论 0 收藏 0

使用误差平方和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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文