数据分析大佬用Python代码教会你Mean Shift聚类
点击上方“it共享之家”,进行关注
回复“资料”可获赠python学习资料
meanshift算法可以称之为均值漂移聚类,是基于聚类中心的聚类算法,但和k-means聚类不同的是,不需要提前设定类别的个数k。在meanshift算法中聚类中心是通过一定范围内样本密度来确定的,通过不断更新聚类中心,直到最终的聚类中心达到终止条件。整个过程可以看下图,我觉得还是比较形象的。
/ 01/ meanshift向量
meanshift向量是指对于样本x1,在以样本点x1为中心,半径为h的高维球区域内的所有样本点x的加权平均值,如下所示,同时也是样本点x1更新后的坐标。
而终止条件则是指 | mh(x) - x |/ 02/ 核函数
核函数在机器学习(svm,lr)中出现的频率是非常高的,你可以把它看做是一种映射,是计算映射到高维空间之后的内积的一种简便方法。在这个算法中将使用高斯核,其函数形式如下。
h表示带宽,当带宽h一定时,两个样本点距离越近,其核函数值越大;当两个样本点距离一定时,h越大,核函数值越小。核函数代码如下,gaosi_value为以样本点x1为中心,半径为h的高维球范围内所有样本点与x1的高斯核函数值,是一个(m,1)的矩阵。
def gaussian_kernel(self,distant): m=shape(distant)[1]#样本数 gaosi=mat(zeros((m,1))) for i in range(m): gaosi[i][0]=(distant.tolist()[0][i]*distant.tolist()[0][i]*(-0.5)/(self.bandwidth*self.bandwidth)) gaosi[i][0]=exp(gaosi[i][0]) q=1/(sqrt(2*pi)*self.bandwidth) gaosi_value=q*gaosi return gaosi_value
/ 03/meanshift向量与核函数
在01中有提到meanshift向量是指对于样本x1,在以样本点x1为中心,半径为h的高维球区域内的所有样本点x的加权平均值。但事实上是不同点对于样本x1的贡献程度是不一样的,因此将权值(1/k)更改为每个样本与样本点x1的核函数值。改进后的meanshift向量如下所示。
其中
就是指高斯核函数,sh表示在半径h内的所有样本点集合。
/ 04/meanshift算法原理
在meanshift算法中实际上利用了概率密度,求得概率密度的局部最优解。
对于一个概率密度函数f(x),已知一个概率密度函数f(x),其核密度估计为
其中k(x)是单位核,概率密度函数f(x)的梯度估计为
其中g(x)=-k'(x)。第一个中括号是以g(x)为核函数对概率密度的估计,第二个中括号是meanshift 向量。因此meanshift向量是与概率密度函数的梯度成正比的,总是指向概率密度增加的方向。
而对于meanshift向量,可以将其变形为下列形式,其中mh(x)为样本点x更新后的位置。
/ 05/meanshift算法流程
在未被标记的数据点中随机选择一个点作为起始中心点x;
找出以x为中心半径为radius的区域中出现的所有数据点,认为这些点同属于一个聚类c。同时在该聚类中记录数据点出现的次数加1。
以x为中心点,计算从x开始到集合m中每个元素的向量,将这些向量相加,得到向量mh(x)。
mh(x) =mh(x) + x。即x沿着mh(x)的方向移动,移动距离是||mh(x)||。
重复步骤2、3、4,直到mh(x)的很小(就是迭代到收敛),记住此时的x。注意,这个迭代过程中遇到的点都应该归类到簇c。
如果收敛时当前簇c的center与其它已经存在的簇c2中心的距离小于阈值,那么把c2和c合并,数据点出现次数也对应合并。否则,把c作为新的聚类。
重复1、2、3、4、5直到所有的点都被标记为已访问。
分类:根据每个类,对每个点的访问频率,取访问频率最大的那个类,作为当前点集的所属类。
tips:每一个样本点都需要计算其漂移均值,并根据计算出的漂移均值进行移动,直至满足终止条件,最终得到的均值漂移点为该点的聚类中心点。
/ 06/meanshift算法代码
from numpy import *from matplotlib import pyplot as plt
class mean_shift(): def __init__(self): #带宽 self.bandwidth=2 #漂移点收敛条件 self.mindistance=0.001#簇心距离,小于该值则两簇心合并 self.cudistance=2.5
def gaussian_kernel(self,distant): m=shape(distant)[1]#样本数 gaosi=mat(zeros((m,1))) for i in range(m): gaosi[i][0]=(distant.tolist()[0][i]*distant.tolist()[0][i]*(-0.5)/(self.bandwidth*self.bandwidth)) gaosi[i][0]=exp(gaosi[i][0]) q=1/(sqrt(2*pi)*self.bandwidth) gaosi_value=q*gaosi return gaosi_value
def load_data(self): x =array([ [-4, -3.5], [-3.5, -5], [-2.7, -4.5], [-2, -4.5], [-2.9, -2.9], [-0.4, -4.5], [-1.4, -2.5], [-1.6, -2], [-1.5, -1.3], [-0.5, -2.1], [-0.6, -1], [0, -1.6], [-2.8, -1], [-2.4, -0.6], [-3.5, 0], [-0.2, 4], [0.9, 1.8], [1, 2.2], [1.1, 2.8], [1.1, 3.4], [1, 4.5], [1.8, 0.3], [2.2, 1.3], [2.9, 0], [2.7, 1.2], [3, 3], [3.4, 2.8], [3, 5], [5.4, 1.2], [6.3, 2],[0,0],[0.2,0.2],[0.1, 0.1],[-4, -3.5]]) x,y=[],[] for i in range(shape(x)[0]): x.append(x[i][0]) y.append(x[i][1]) plt.scatter(x,y,c='r') # plt.plot(x, y) plt.show() classlable=mat(zeros((shape(x)[0],1))) return x,classlable
def distance(self,a,b): v=a-b return sqrt(v*mat(v).t).tolist()[0][0] def shift_point(self,point,data,clusterfrequency): sum=0 n=shape(data)[0] ou=mat(zeros((n,1))) t=mat(zeros((n,1))) newdata=[] for i in range(n): # print(self.distance(point,data[i])) d=self.distance(point,data[i]) if dself.mindistance: w,cluster_frequency = self.shift_point(cluster_centroid,dataset,cluster_frequency) dis = self.distance(cluster_centroid, w) if dis < max_distance: max_distance = dis # print(max_distance) cluster_centroid = w has_same_cluster = false for cluster in clusters: if self.distance(cluster['centroid'],cluster_centroid)if __name__==__main__: shift=mean_shift()shift.mean_shift_train()
得到的结果图如下。
之后还会详细解说k-means聚类以及dbscan聚类,敬请关注。
-------------------end-------------------
往期精彩文章推荐:
粉丝福利——2019精选学习资源分享
python环境搭建—安利python小白的python和pycharm安装详细教程
欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持
想加入python学习群请在后台回复【入群】
万水千山总是情,点个【在看】行不行
Python进阶学习交流