1.算法简介

AP(Affinity Propagation)通常被翻译为近邻传播算法或者亲和力传播算法,是在2007年的Science杂志上提出的一种新的聚类算法。AP算法的基本思想是将全部数据点都当作潜在的聚类中心(称之为exemplar),然后数据点两两之间连线构成一个网络(相似度矩阵),再通过网络中各条边的消息(responsibility和availability)传递计算出各样本的聚类中心。

2.相关概念(假如有数据点i和数据点j)

      

(图1)                                     (图2)                                       (图3)

1)相似度: 点j作为点i的聚类中心的能力,记为S(i,j)。一般使用负的欧式距离,所以S(i,j)越大,表示两个点距离越近,相似度也就越高。使用负的欧式距离,相似度是对称的,如果采用其他算法,相似度可能就不是对称的。

2)相似度矩阵:N个点之间两两计算相似度,这些相似度就组成了相似度矩阵。如图1所示的黄色区域,就是一个5*5的相似度矩阵(N=5)

3)  preference:指点i作为聚类中心的参考度(不能为0),取值为S对角线的值(图1红色标注部分),此值越大,最为聚类中心的可能性就越大。但是对角线的值为0,所以需要重新设置对角线的值,既可以根据实际情况设置不同的值,也可以设置成同一值。一般设置为S相似度值的中值。(有的说设置成S的最小值产生的聚类最少,但是在下面的算法中设置成中值产生的聚类是最少的)

4)Responsibility(吸引度):指点k适合作为数据点i的聚类中心的程度,记为r(i,k)。如图2红色箭头所示,表示点i给点k发送信息,是一个点i选点k的过程。

5)Availability(归属度):指点i选择点k作为其聚类中心的适合程度,记为a(i,k)。如图3红色箭头所示,表示点k给点i发送信息,是一个点k选diani的过程。

6)exemplar:指的是聚类中心。

7)r (i, k)加a (i, k)越大,则k点作为聚类中心的可能性就越大,并且i点隶属于以k点为聚类中心的聚类的可能性也越大

3.数学公式

1)吸引度迭代公式:

    (公式一)

说明1:Rt+1(i,k)表示新的R(i,k),Rt(i,k)表示旧的R(i,k),也许这样说更容易理解。其中λ是阻尼系数,取值[0.5,1),用于算法的收敛

说明2:网上还有另外一种数学公式:

    (公式二)

sklearn官网的公式是:

       (公式三)

我试了这两种公式之后,发现还是公式一的聚类效果最好。同样的数据都采取S的中值作为参考度,我自己写的算法聚类中心是5个,sklearn提供的算法聚类中心是十三个,但是如果把参考度设置为p=-50,则我自己写的算法聚类中心很多,sklearn提供的聚类算法产生标准的3个聚类中心(因为数据是围绕三个中心点产生的),目前还不清楚这个p=-50是怎么得到的。

2)归属度迭代公式

说明:At+1(i,k)表示新的A(i,k),At(i,k)表示旧的A(i,k)。其中λ是阻尼系数,取值[0.5,1),用于算法的收敛

4.算法流程

1)设置实验数据。使用sklearn包中提供的函数,随机生成以[1, 1], [-1, -1], [1, -1]三个点为中心的150个数据。

  1. def init_sample():
  2. """
  3. 第一步:生成测试数据
  4. 1.生成实际中心为centers的测试样本300个,
  5. 2.Xn是包含150个(x,y)点的二维数组
  6. 3.labels_true为其对应的真是类别标签
  7. """
  8. # 生成的测试数据的中心点
  9. centers = [[1, 1], [-1, -1], [1, -1]]
  10. # 生成数据
  11. X, label_true = make_blobs(n_samples=150, centers=centers, cluster_std=0.5, random_state=0)
  12. return X, label_true

   2)计算相似度矩阵,并且设置参考度,这里使用相似度矩阵的中值

   3)计算吸引度矩阵,即R值。

  4)计算归属度矩阵,即A值

  5)迭代更新R值和A值。终止条件是聚类中心在一定程度上不再更新或者达到最大迭代次数

   6)根据求出的聚类中心,对数据进行分类

这个步骤产生的是一个归类列表,列表中的每个数字对应着样本数据中对应位置的数据的分类

完整代码

  1. # -*- coding: utf-8 -*-
  2.  
  3. """
  4. @Datetime: 2019/3/31
  5. @Author: Zhang Yafei
  6. """
  7. import matplotlib.pyplot as plt
  8. import numpy as np
  9. from sklearn.datasets.samples_generator import make_blobs
  10.  
  11. def init_sample():
  12. """
  13. 第一步:生成测试数据
  14. 1.生成实际中心为centers的测试样本300个,
  15. 2.Xn是包含150个(x,y)点的二维数组
  16. 3.labels_true为其对应的真是类别标签
  17. """
  18. # 生成的测试数据的中心点
  19. centers = [[1, 1], [-1, -1], [1, -1]]
  20. # 生成数据
  21. X, label_true = make_blobs(n_samples=150, centers=centers, cluster_std=0.5, random_state=0)
  22. return X, label_true
  23.  
  24. class AP(object):
  25. """ AP聚类 """
  26.  
  27. def __init__(self):
  28. self.Xn = None
  29. self.Xn_len = None
  30. self.R = None
  31. self.A = None
  32. self.simi_matrix = None
  33. self.class_cen = None
  34.  
  35. def fit(self, data):
  36. self.Xn = data
  37. self.Xn_len = len(data)
  38. # 初始化R、A矩阵
  39. self.R = np.zeros((self.Xn_len, self.Xn_len))
  40. self.A = np.zeros((self.Xn_len, self.Xn_len))
  41. # 计算相似度
  42. self.cal_simi()
  43. # 输出聚类中心
  44. self.class_cen = self.cal_cls_center()
  45.  
  46. def cal_simi(self):
  47. """
  48. 计算相似度矩阵
  49. 这个数据集的相似度矩阵,最终是二维数组
  50. 每个数字与所有数字的相似度列表,即矩阵中的一行
  51. 采用负的欧式距离计算相似度
  52. :return:
  53. """
  54. simi = [[-np.sqrt((m[0] - n[0]) ** 2 + (m[1] - n[1]) ** 2) for n in self.Xn] for m in self.Xn]
  55.  
  56. # 设置参考度,即对角线的值,一般为最小值或者中值
  57. # p = np.min(simi) ##11个中心
  58. # p = np.max(simi) ##14个中心
  59.  
  60. p = np.median(simi) ##5个中心
  61. for i in range(self.Xn_len):
  62. simi[i][i] = p
  63.  
  64. self.simi_matrix = simi
  65.  
  66. def iter_update_R(self, old_r=0, lam=0.5):
  67. """
  68. 计算吸引度矩阵,即R
  69. 公式1:r(n+1) =s(n)-(s(n)+a(n))-->简化写法,具体参见上图公式
  70. 公式2:r(n+1)=(1-λ)*r(n+1)+λ*r(n)
  71. 迭代更新R矩阵
  72. :param old_r: 更新前的某个r值
  73. :param lam: 阻尼系数,用于算法收敛
  74. :return:
  75. """
  76. # 此循环更新R矩阵
  77. for i in range(self.Xn_len):
  78. for k in range(self.Xn_len):
  79. old_r = self.R[i][k]
  80. if i != k:
  81. max1 = self.A[i][0] + self.R[i][0] ##注意初始值的设置
  82. for j in range(self.Xn_len):
  83. if j != k:
  84. if self.A[i][j] + self.R[i][j] > max1:
  85. max1 = self.A[i][j] + self.R[i][j]
  86. ##更新后的R[i][k]值
  87. self.R[i][k] = self.simi_matrix[i][k] - max1
  88. ##带入阻尼系数重新更新
  89. self.R[i][k] = (1 - lam) * self.R[i][k] + lam * old_r
  90. else:
  91. max2 = self.simi_matrix[i][0] ##注意初始值的设置
  92. for j in range(self.Xn_len):
  93. if j != k:
  94. if self.simi_matrix[i][j] > max2:
  95. max2 = self.simi_matrix[i][j]
  96. ##更新后的R[i][k]值
  97. self.R[i][k] = self.simi_matrix[i][k] - max2
  98. ##带入阻尼系数重新更新
  99. self.R[i][k] = (1 - lam) * self.R[i][k] + lam * old_r
  100. print("max_r:" + str(np.max(self.R)))
  101.  
  102. def iter_update_A(self, old_a=0, lam=0.5):
  103. """
  104. 迭代更新A矩阵
  105. :param old_r: 更新前的某个r值
  106. :param lam: 阻尼系数,用于算法收敛
  107. :return:
  108. """
  109. old_a = 0 ##更新前的某个a值
  110. lam = 0.5 ##阻尼系数,用于算法收敛
  111. ##此循环更新A矩阵
  112. for i in range(self.Xn_len):
  113. for k in range(self.Xn_len):
  114. old_a = self.A[i][k]
  115. if i == k:
  116. max3 = self.R[0][k] ##注意初始值的设置
  117. for j in range(self.Xn_len):
  118. if j != k:
  119. if self.R[j][k] > 0:
  120. max3 += self.R[j][k]
  121. else:
  122. max3 += 0
  123. self.A[i][k] = max3
  124. # 带入阻尼系数更新A值
  125. self.A[i][k] = (1 - lam) * self.A[i][k] + lam * old_a
  126. else:
  127. max4 = self.R[0][k] # 注意初始值的设置
  128. for j in range(self.Xn_len):
  129. # 上图公式中的i!=k 的求和部分
  130. if j != k and j != i:
  131. if self.R[j][k] > 0:
  132. max4 += self.R[j][k]
  133. else:
  134. max4 += 0
  135.  
  136. # 上图公式中的min部分
  137. if self.R[k][k] + max4 > 0:
  138. self.A[i][k] = 0
  139. else:
  140. self.A[i][k] = self.R[k][k] + max4
  141.  
  142. # 带入阻尼系数更新A值
  143. self.A[i][k] = (1 - lam) * self.A[i][k] + lam * old_a
  144. print("max_a:" + str(np.max(self.A)))
  145.  
  146. def cal_cls_center(self, max_iter=100, curr_iter=0, max_comp=30, curr_comp=0):
  147. """
  148. 计算聚类中心
  149. 进行聚类,不断迭代直到预设的迭代次数或者判断comp_cnt次后聚类中心不再变化
  150. :param max_iter: 最大迭代次数
  151. :param curr_iter: 当前迭代次数
  152. :param max_comp: 最大比较次数
  153. :param curr_comp: 当前比较次数
  154. :return:
  155. """
  156. class_cen = [] # 聚类中心列表,存储的是数据点在Xn中的索引
  157. while True:
  158. # 计算R矩阵
  159. self.iter_update_R()
  160. # 计算A矩阵
  161. self.iter_update_A()
  162. # 开始计算聚类中心
  163. for k in range(self.Xn_len):
  164. if self.R[k][k] + self.A[k][k] > 0:
  165. if k not in class_cen:
  166. class_cen.append(k)
  167. else:
  168. curr_comp += 1
  169. curr_iter += 1
  170. print('iteration the {}'.format(curr_iter))
  171. if curr_iter >= max_iter or curr_comp > max_comp:
  172. break
  173. return class_cen
  174.  
  175. def c_list(self):
  176. # 根据聚类中心划分数据
  177. c_list = []
  178. for m in self.Xn:
  179. temp = []
  180. for j in self.class_cen:
  181. n = Xn[j]
  182. d = -np.sqrt((m[0] - n[0]) ** 2 + (m[1] - n[1]) ** 2)
  183. temp.append(d)
  184. # 按照是第几个数字作为聚类中心进行分类标识
  185. c = class_cen[temp.index(np.max(temp))]
  186. c_list.append(c)
  187. print(c_list)
  188. return c_list
  189.  
  190. def plot(class_cen, X, c_list):
  191. # 画图
  192. colors = ['red', 'blue', 'black', 'green', 'yellow']
  193. plt.figure(figsize=(8, 6))
  194. plt.xlim([-3, 3])
  195. plt.ylim([-3, 3])
  196. for i in range(len(X)):
  197. d1 = Xn[i]
  198. d2 = Xn[c_list[i]]
  199. c = class_cen.index(c_list[i])
  200. plt.plot([d2[0], d1[0]], [d2[1], d1[1]], color=colors[c], linewidth=1)
  201. # if i == c_list[i] :
  202. # plt.scatter(d1[0],d1[1],color=colors[c],linewidth=3)
  203. # else :
  204. # plt.scatter(d1[0],d1[1],color=colors[c],linewidth=1)
  205. plt.savefig('AP 聚类.png')
  206. plt.show()
  207.  
  208. if __name__ == '__main__':
  209. # 初始化数据
  210. Xn, labels_true = init_sample()
  211. ap = AP()
  212. ap.fit(data=Xn)
  213. class_cen = ap.class_cen
  214. # for i in class_cen:
  215. # print(str(i)+":"+str(Xn[i]))
  216. c_list = ap.c_list()
  217. plot(class_cen=class_cen, X=Xn, c_list=c_list)

AP.py

效果图

5.sklearn包中的AP算法

1)函数:sklearn.cluster.AffinityPropagation

2)主要参数:

damping : 阻尼系数,取值[0.5,1)

convergence_iter :比较多少次聚类中心不变之后停止迭代,默认15

max_iter :最大迭代次数

preference :参考度

3)主要属性

cluster_centers_indices_ : 存放聚类中心的数组

labels_ :存放每个点的分类的数组

n_iter_ : 迭代次数

4)示例

preference(即p值)取不同值时的聚类中心的数目在代码中注明了。

  1. # -*- coding: utf-8 -*-
  2.  
  3. """
  4. @Datetime: 2019/3/31
  5. @Author: Zhang Yafei
  6. """
  7.  
  8. import numpy as np
  9. from sklearn.cluster import AffinityPropagation
  10. from sklearn.datasets.samples_generator import make_blobs
  11.  
  12. def init_sample():
  13. """
  14. 第一步:生成测试数据
  15. 1.生成实际中心为centers的测试样本300个,
  16. 2.Xn是包含150个(x,y)点的二维数组
  17. 3.labels_true为其对应的真是类别标签
  18. """
  19. # 生成的测试数据的中心点
  20. centers = [[1, 1], [-1, -1], [1, -1]]
  21. # 生成数据
  22. X, label_true = make_blobs(n_samples=150, centers=centers, cluster_std=0.5, random_state=0)
  23. return X, label_true
  24.  
  25. def simi_matrix(Xn):
  26. simi = []
  27. for m in Xn:
  28. ##每个数字与所有数字的相似度列表,即矩阵中的一行
  29. temp = []
  30. for n in Xn:
  31. ##采用负的欧式距离计算相似度
  32. s =-np.sqrt((m[0]-n[0])**2 + (m[1]-n[1])**2)
  33. temp.append(s)
  34. simi.append(temp)
  35. return simi
  36.  
  37. if __name__ == '__main__':
  38. Xn, label_true = init_sample()
  39. simi_matrix = simi_matrix(Xn)
  40.  
  41. p = -50 ##3个中心
  42. #p = np.min(simi) ##9个中心,
  43. #p = np.median(simi) ##13个中心
  44.  
  45. ap = AffinityPropagation(damping=0.5, max_iter=500, convergence_iter=30, preference=p).fit(Xn)
  46. cluster_centers_indices = ap.cluster_centers_indices_
  47. print(ap.labels_)
  48. for idx in cluster_centers_indices:
  49. print(Xn[idx]

sklearn_AP.py

 6.AP算法的优点

1) 不需要制定最终聚类族的个数

2) 已有的数据点作为最终的聚类中心,而不是新生成一个族中心。

3)模型对数据的初始值不敏感。

    4)对初始相似度矩阵数据的对称性没有要求。 

    5).相比与k-centers聚类方法,其结果的平方差误差较小。

7.AP算法的不足

1)AP算法需要事先计算每对数据对象之间的相似度,如果数据对象太多的话,内存放不下,若存在数据库,频繁访问数据库也需要时间。

    2)AP算法的时间复杂度较高,一次迭代大概O(N3)

    3)聚类的好坏受到参考度和阻尼系数的影响。

Python实现聚类算法AP的更多相关文章

  1. 机器学习:Python实现聚类算法(一)之AP算法

    1.算法简介 AP(Affinity Propagation)通常被翻译为近邻传播算法或者亲和力传播算法,是在2007年的Science杂志上提出的一种新的聚类算法.AP算法的基本思想是将全部数据点都 ...

  2. 机器学习:Python实现聚类算法(二)之AP算法

    1.算法简介 AP(Affinity Propagation)通常被翻译为近邻传播算法或者亲和力传播算法,是在2007年的Science杂志上提出的一种新的聚类算法.AP算法的基本思想是将全部数据点都 ...

  3. 机器学习:Python实现聚类算法(三)之总结

    考虑到学习知识的顺序及效率问题,所以后续的几种聚类方法不再详细讲解原理,也不再写python实现的源代码,只介绍下算法的基本思路,使大家对每种算法有个直观的印象,从而可以更好的理解函数中参数的意义及作 ...

  4. 机器学习:Python实现聚类算法(一)之K-Means

    1.简介 K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一.K-means算法的基本思想是:以空间中k个点为中心进行聚类,对最靠近他们的对象归类.通过迭代的方法,逐次更新各 ...

  5. AP聚类算法(Affinity propagation Clustering Algorithm )

    AP聚类算法是基于数据点间的"信息传递"的一种聚类算法.与k-均值算法或k中心点算法不同,AP算法不需要在运行算法之前确定聚类的个数.AP算法寻找的"examplars& ...

  6. AP聚类算法(转)

    Affinity Propagation (AP) 聚类是2007年在Science杂志上提出的一种新的聚类算法.它根据N个数据点之间的相似度进行聚类,这些相似度可以是对称的,即两个数据点互相之间的相 ...

  7. 【转】利用python的KMeans和PCA包实现聚类算法

    转自:https://www.cnblogs.com/yjd_hycf_space/p/7094005.html 题目: 通过给出的驾驶员行为数据(trip.csv),对驾驶员不同时段的驾驶类型进行聚 ...

  8. K-means聚类算法及python代码实现

    K-means聚类算法(事先数据并没有类别之分!所有的数据都是一样的) 1.概述 K-means算法是集简单和经典于一身的基于距离的聚类算法 采用距离作为相似性的评价指标,即认为两个对象的距离越近,其 ...

  9. 利用python的KMeans和PCA包实现聚类算法

    题目: 通过给出的驾驶员行为数据(trip.csv),对驾驶员不同时段的驾驶类型进行聚类,聚成普通驾驶类型,激进类型和超冷静型3类 . 利用Python的scikit-learn包中的Kmeans算法 ...

随机推荐

  1. AngularJS学习之旅—AngularJS 服务(八)

    1.AngularJS 服务(Service) AngularJS 中你可以创建自己的服务,或使用内建服务.2.什么是服务? 在 AngularJS 中,服务是一个函数或对象,可在你的 Angular ...

  2. 如何在 windows server 2008 上面 挂载NFS

    首先, 你在一台服务器上面配置好NFS 服务器:然后按照一下步骤: mounting the nfs on windows server 2008 r2: open Windows Server 的D ...

  3. LeetCode算法题-Subtree of Another Tree(Java实现)

    这是悦乐书的第265次更新,第278篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第132题(顺位题号是572).给定两个非空的二进制树s和t,检查树t是否具有完全相同的 ...

  4. MySql 学习之路-聚合函数

    下面是mysql 数据库中经常用到的聚合函数的简单实例 -- 创建学生表 create table student ( id int primary key auto_increment commen ...

  5. 我的第一个python web开发框架(30)——定制ORM(六)

    在开发中,查询操作是使用最多的,而查询列表是其中之一,查询列表可分为分页查询和不分页查询(它们之间多了一次总记录数查询),还可以分为单表查询和多表关联查询,返回的结构体根据前端使用的表单框架不同而有所 ...

  6. spring异步执行报异常No qualifying bean of type 'org.springframework.core.task.TaskExecutor' available

    最近观察项目运行日志的时候突然发现了一个异常, [2018-04-03 10:49:07] 100.0.1.246 http-nio-8080-exec-9 DEBUG org.springframe ...

  7. Python开发【内置模块篇】configparser

    生成配置文件 import configparser config = configparser.ConfigParser() config[', 'Compression': 'yes', ', ' ...

  8. Java高级篇(四)——反射

    之前写到了设计模式的代理模式,因为下一篇动态代理等内容需要用到反射的知识,所以在之前Java篇的基础上再写一篇有关反射的内容,还是以实际的程序为主,了解反射是做什么的.应该怎么用. 一.什么是反射 反 ...

  9. 基于 WebGL 的 HTML5 楼宇自控 3D 可视化监控

    前言 智慧楼宇和人们的生活息息相关,楼宇智能化程度的提高,会极大程度的改善人们的生活品质,在当前工业互联网大背景下受到很大关注.目前智慧楼宇可视化监控的主要优点包括: 智慧化 -- 智慧楼宇是一个生态 ...

  10. Python @property 方法

    考察 Student 类: class Student(object): def __init__(self, name, score): self.name = name self.score = ...