利用Python如何实现K-means聚类算法
目录
- 前言
- 算法原理
- 目标函数
- 算法流程
- Python实现
- 总结
前言 K-Means 是一种非常简单的聚类算法(聚类算法都属于无监督学习)。给定固定数量的聚类和输入数据集,该算法试图将数据划分为聚类,使得聚类内部具有较高的相似性,聚类与聚类之间具有较低的相似性。
算法原理
1. 初始化聚类中心,或者在输入数据范围内随机选择,或者使用一些现有的训练样本(推荐)
2. 直到收敛
- 将每个数据点分配到最近的聚类。点与聚类中心之间的距离是通过欧几里德距离测量得到的。
- 通过将聚类中心的当前估计值设置为属于该聚类的所有实例的平均值,来更新它们的当前估计值。
目标函数
聚类算法的目标函数试图找到聚类中心,以便数据将划分到相应的聚类中,并使得数据与其最接近的聚类中心之间的距离尽可能小。
给定一组数据X1,...,Xn和一个正数k,找到k个聚类中心C1,...,Ck并最小化目标函数:
文章图片
其中
文章图片
是质心,计算表达式为
文章图片
文章图片
上图a表达了初始的数据集,假设k=2。在图b中,我们随机选择了两个k类所对应的类别质心,即图中的红色质心和蓝色质心,然后分别求样本中所有点到这两个质心的距离,并标记每个样本的类别为和该样本距离最小的质心的类别,如图c所示,经过计算样本和红色质心和蓝色质心的距离,我们得到了所有样本点的第一轮迭代后的类别。此时我们对我们当前标记为红色和蓝色的点分别求其新的质心,如图4所示,新的红色质心和蓝色质心的位置已经发生了变动。图e和图f重复了我们在图c和图d的过程,即将所有点的类别标记为距离最近的质心的类别并求新的质心。最终我们得到的两个类别如图f。当然在实际K-Mean算法中,我们一般会多次运行图c和图d,才能达到最终的比较优的类别。
算法流程
注意点:
- 对于K-Means算法,首先要注意的是k值的选择,一般来说,我们会根据对数据的先验经验选择一个合适的k值,如果没有什么先验知识,则可以通过交叉验证选择一个合适的k值
- 在确定了k的个数后,我们需要选择k个初始化的质心,就像上图b中的随机质心。由于我们是启发式方法,k个初始化的质心的位置选择对最后的聚类结果和运行时间都有很大的影响,因此需要选择合适的k个质心,最好这些质心不能太近。
输入是样本集D={x1,x2,...xm},聚类的簇树k,最大迭代次数N
输出是簇划分C={C1,C2,...Ck}
1) 从数据集D中随机选择k个样本作为初始的k个质心向量: {μ1,μ2,...,μk}
2)对于n=1,2,...,N
a) 将簇划分C初始化为Ct=?t=1,2...k
b) 对于i=1,2...m,计算样本xi和各个质心向量μj(j=1,2,...k)的距离:
文章图片
,将xixi标记最小的为
文章图片
所对应的类别
文章图片
。此时更新
文章图片
c) 对于j=1,2,...,k,对Cj中所有的样本点重新计算新的质心
文章图片
e) 如果所有的k个质心向量都没有发生变化,则转到步骤3)
3) 输出簇划分C={C1,C2,...Ck}
Python实现
import numpy as npimport matplotlib.pyplot as pltimport randomfrom sklearn.datasets import make_blobsnp.random.seed(123)from sklearn.cluster import KMeansclass Kmeans:def __init__(self,data,k):self.data=https://www.it610.com/article/dataself.k = kdef cluster_data_Bysklearn(self):kmeans_model = KMeans(self.k,random_state=1)labels = kmeans_model.fit(self.data).labels_print(labels)return labels def kmeans(self):# 获取4个随机数rarray = np.random.random(size=self.k)# 乘以数据集大小——>数据集中随机的4个点rarray = np.floor(rarray * len(self.data))# 转为intrarray = rarray.astype(int)print('数据集中随机索引', rarray)# 随机取数据集中的4个点作为初始中心点center = data[rarray]# 测试比较偏、比较集中的点,效果依然完美,测试需要删除以上代码# center = np.array([[4.6,-2.5],[4.4,-1.7],[4.3,-0.7],[4.8,-1.1]])# 1行80列的0数组,标记每个样本所属的类(k[i])cls = np.zeros([len(self.data)], np.int)print('初始center=\n', center)run = Truetime = 0n = len(self.data)while run:time = time + 1for i in range(n):# 求差tmp = data[i] - center# 求平方tmp = np.square(tmp)# axis=1表示按行求和tmp = np.sum(tmp, axis=1)# 取最小(最近)的给该点“染色”(标记每个样本所属的类(k[i]))cls[i] = np.argmin(tmp)# 如果没有修改各分类中心点,就结束循环run = False# 计算更新每个类的中心点for i in range(self.k):# 找到属于该类的所有样本club = data[cls == i]# axis=0表示按列求平均值,计算出新的中心点newcenter = np.mean(club, axis=0)# 如果新旧center的差距很小,看做他们相等,否则更新之。run置true,再来一次循环ss = np.abs(center[i] - newcenter)if np.sum(ss, axis=0) > 1e-4:center[i] = newcenterrun = Trueprint('new center=\n', center)print('程序结束,迭代次数:', time)# 按类打印图表,因为每打印一次,颜色都不一样,所以可区分出来# for i in range(self.k):#club = data[cls == i]#self.showtable(club)# 打印最后的中心点self.showtable(center)#打印聚类标签print(cls) def showtable(self,data):x = data.T[0]y = data.T[1]plt.scatter(x, y)plt.show() if __name__ == '__main__':data = https://www.it610.com/article/np.random.rand(10,2)K = 4model = Kmeans(data,K) model.kmeans()model.cluster_data_Bysklearn()
结果:
自写得出的[0 2 0 0 0 2 3 2 1 2]jupyter notebook实现
调用模型的出的[0 2 0 1 0 2 3 2 3 0]
import numpy as npimport matplotlib.pyplot as pltimport randomfrom sklearn.datasets import make_blobs %matplotlib inline
X, y = make_blobs(centers=6, n_samples=1000)print(f'Shape of dataset: {X.shape}') fig = plt.figure(figsize=(8,6))plt.scatter(X[:,0], X[:,1], c=y)plt.title("Dataset with 6 clusters")plt.xlabel("First feature")plt.ylabel("Second feature")plt.show()
文章图片
class KMeans():def __init__(self, n_clusters=6):self.k = n_clusters def fit(self, data):"""Fits the k-means model to the given dataset"""n_samples, _ = data.shape# initialize cluster centersself.centers = np.array(random.sample(list(data), self.k))self.initial_centers = np.copy(self.centers) # We will keep track of whether the assignment of data points# to the clusters has changed. If it stops changing, we are # done fitting the modelold_assigns = Nonen_iters = 0 while True:new_assigns = [self.classify(datapoint) for datapoint in data] if new_assigns == old_assigns:print(f"Training finished after {n_iters} iterations!")return old_assigns = new_assignsn_iters += 1 # recalculate centersfor id_ in range(self.k):points_idx = np.where(np.array(new_assigns) == id_)datapoints = data[points_idx]self.centers[id_] = datapoints.mean(axis=0) def l2_distance(self, datapoint):dists = np.sqrt(np.sum((self.centers - datapoint)**2, axis=1))return dists def classify(self, datapoint):"""Given a datapoint, compute the cluster closest to thedatapoint. Return the cluster ID of that cluster."""dists = self.l2_distance(datapoint)return np.argmin(dists) def plot_clusters(self, data):plt.figure(figsize=(12,10))plt.title("Initial centers in black, final centers in red")plt.scatter(data[:, 0], data[:, 1], marker='.', c='y')plt.scatter(self.centers[:, 0], self.centers[:,1], c='r')plt.scatter(self.initial_centers[:, 0], self.initial_centers[:,1], c='k')plt.show()
X = np.random.randn(10,100)kmeans = KMeans(n_clusters=6)kmeans.fit(X)for data in X:print(kmeans.classify(data))
总结
K-Means的主要优点:
1)原理简单,容易实现
2)可解释度较强
K-Means的主要缺点:
1)K值很难确定
2)局部最优
3)对噪音和异常点敏感
4)需样本存在均值(限定数据种类)
5)聚类效果依赖于聚类中心的初始化
6)对于非凸数据集或类别规模差异太大的数据效果不好
【利用Python如何实现K-means聚类算法】到此这篇关于利用Python如何实现K-means聚类算法的文章就介绍到这了,更多相关Python实现K-means聚类算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- 如何寻找情感问答App的分析切入点
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus使用queryWrapper如何实现复杂查询
- python学习之|python学习之 实现QQ自动发送消息
- 逻辑回归的理解与python示例
- python自定义封装带颜色的logging模块
- 【Leetcode/Python】001-Two|【Leetcode/Python】001-Two Sum
- 如何在Mac中的文件选择框中打开系统隐藏文件夹
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)