快捷搜索:  汽车  科技

7种常用的聚类方法(k-means聚类算法)

7种常用的聚类方法(k-means聚类算法)1)原理比较简单,实现也是很容易,收敛速度快。 优点 2.对任意一个样本点,求其到K个聚类中心的距离,将样本点归类到距离最小的中心的聚类,如此迭代n次;3.每次迭代过程中,利用均值等方法更新各个聚类的中心点(质心);4.对K个聚类中心,利用2 3步迭代更新后,如果位置点变化很小(可以设置阈值),则认为达到稳定状态,迭代结束,对不同的聚类块和聚类中心可选择不同的颜色标注。

K-Means算法是无监督的聚类算法,它实现起来比较简单,聚类效果也不错,因此应用很广泛。K-Means算法有大量的变体,本文就从最传统的K-Means算法讲起,在其基础上讲述K-Means的优化变体方法。包括初始化优化K-Means 距离计算优化elkan K-Means算法和大数据情况下的优化Mini Batch K-Means算法。

kmeans VS KNN

算法步骤:

1.(随机)选择K个聚类的初始中心;

2.对任意一个样本点,求其到K个聚类中心的距离,将样本点归类到距离最小的中心的聚类,如此迭代n次;

3.每次迭代过程中,利用均值等方法更新各个聚类的中心点(质心);

4.对K个聚类中心,利用2 3步迭代更新后,如果位置点变化很小(可以设置阈值),则认为达到稳定状态,迭代结束,对不同的聚类块和聚类中心可选择不同的颜色标注。

优点

1)原理比较简单,实现也是很容易,收敛速度快。

2)聚类效果较优。

3)算法的可解释度比较强。

4)主要需要调参的参数仅仅是簇数k。

缺点

1)K值的选取不好把握

2)对于不是凸的数据集比较难收敛

3)如果各隐含类别的数据不平衡,比如各隐含类别的数据量严重失衡,或者各隐含类别的方差不同,则聚类效果不佳。

4) 最终结果和初始点的选择有关,容易陷入局部最优。

5) 对噪音和异常点比较的敏感。

传统的kmeans算法实践:

(1)创建kmeans工具类,定义Cluster、sample类,和生成样本的方式,以及距离的计算方式。根据不同的优化方式可以修改该工具类,比如距离的计算公式。也可以定义不同的sample特征用于聚类

下面以二维平面的点的欧氏距离作为聚类特征

# -*- coding:utf-8 -*- """ author:goldstine version: 1.0 date: 2021/3/29 project name:k-means tools https://gist.github.com/iandanforth/5862470 """ import math import random class Cluster(object): """ 聚类 """ def __init__(self samples): if len(samples)==0: raise Exception("错误,没有样本点的空聚类!") #属于该聚类的样本点 self.samples=samples #该聚类中样本点的维数 self.n_dim=samples[0].n_dim #判断该聚类中所有的样本点维度是否相同 for sample in samples: if sample.n_dim !=self.n_dim: raise Exception("错误:聚类中样本点的维度不一致!") #设置初始化的聚类中心 self.centerid=self.cal_centerid() def __repr__(self): """ 输出对象信息 :return: """ return str(self.samples) def update(self samples): """ 计算之前的聚类中心和更新之后的聚类中心的距离 :param samples: :return: """ old_centerid=self.centerid self.samples=samples self.centerid=self.cal_centerid() shift=get_distance(old_centerid self.centerid) return shift def cal_centerid(self): """ 对一组样本点计算其中心点 :return: """ n_samples=len(self.samples) #获取所有样本点的坐标特征 coords=[sample.coords for sample in self.samples] unzipped=zip(*coords) #计算每一个维度的均值 centerid_coords=[math.fsum(d_list)/n_samples for d_list in unzipped] return Sample(centerid_coords) class Sample(object): """ 样本点类 """ def __init__(self coords): self.coords=coords #样本点包含的坐标 self.n_dim=len(coords) #y样本点的维度 #s输出对象信息 def __repr__(self): return str(self.coords) def get_distance(a b): """ 返回样本点之间的欧氏距离 参考:https://en.wikipedia.org/wiki/Euclidean_distance#n_dimensions :param a: :param b: :return: """ if a.n_dim!=b.n_dim: #如果样本点维度不同 raise Exception("错误:样本点维度不同,无法计算距离!") acc_diff=0.0 for i in range(a.n_dim): square_diff=pow((a.coords[i]-b.coords[i]) 2) acc_diff =square_diff distance=math.sqrt(acc_diff) return distance def gen_random_sample(n_dim lower upper): """ 生成随机样本点 :param n_dim: :param lower: :param upper: :return: """ sample=Sample([random.uniform(lower upper) for _ in range(n_dim)]) return sample

(2)聚类算法的实现kmeans以及聚类结果的可视化

import random from kmeans_tools import Cluster get_distance gen_random_sample import matplotlib.pyplot as plt from matplotlib import colors as mcolors def kmeans(samples k cutooff): """ kmeans函数 :param samples: :param k: :param cutooff: :return: """ #随机选k个样本点作为初始聚类中心 init_samples=random.sample(samples k) #创建k个聚类,聚类的中心分别为随机初始的样本点 clusters=[Cluster([sample]) for sample in init_samples] #迭代循环直到聚类划分稳定 n_loop=0 while True: #初始化一组空列表用于存储每个聚类内的样本点 lists=[[] for _ in clusters] #开始迭代 n_loop =1 #遍历样本集中的每一个样本 for sample in samples: smallest_distance=get_distance(sample clusters[0].centerid) #初始化属于聚类0 cluster_index=0 #计算和其他聚类中心的距离 for i in range(k-1): #计算样本点sample和聚类中心的距离 distance=get_distance(sample clusters[i 1].centerid) #如果存在更小的距离,则更新距离 if distance<smallest_distance: smallest_distance=distance cluster_index=i 1 #找到最近的聚类中心,更新所属聚类 lists[cluster_index].append(sample) #初始化最大移动距离 biggest_shift=0.0 #计算本次迭代中,聚类中心的移动距离 for i in range(k): shift =clusters[i].update(lists[i]) #记录最大移动距离 biggest_shift=max(biggest_shift shift) #如果聚类中心移动的距离小于收敛阈值,即聚类稳定 if biggest_shift<cutooff: print("第{}次迭代后,聚类稳定".format(n_loop)) break return clusters def run_main(): """ 主函数 :return: """ #样本个数 n_samples=1000 #特征个数(特征维数),平面上的点特征维度为2 n_feat=2 #特征数值范围 实际上就是限定了一个矩形范围内的点 lower=0 upper=200 #聚类个数k n_cluster=5 #随机生成样本 samples=[gen_random_sample(n_feat lower upper) for _ in range(n_samples)] #收敛域值 cutoff=0.2 #聚类迭代的终止时间 clusters=kmeans(samples n_cluster cutoff) #输出结果 for i c in enumerate(clusters): for sample in c.samples: print('聚类--{},样本点--{}'.format(i sample)) #可视化结果 plt.subplot() color_names=list(mcolors.cnames) for i c in enumerate(clusters): x=[] y=[] random.choice color=[color_names[i]]*len(c.samples) for sample in c.samples: x.append(sample.coords[0]) y.append(sample.coords[1]) plt.scatter(x y c=color) plt.show() if __name__=='__main__': run_main()

7种常用的聚类方法(k-means聚类算法)(1)

猜您喜欢: