赞
踩
原创不易,转载前请注明博主的链接地址:Blessy_Zhu https://blog.csdn.net/weixin_42555080
本次代码的环境:
运行平台: Windows
Python版本: Python3.x
IDE: PyCharm
K-means算法是很典型的基于距离的聚类算法,采用距离 作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。 k-means算法特点在于:同一聚类的簇内的对象相似度较高;而不同聚类的簇内的对象相似度较小
k-means是用来解决著名的聚类问题的最简单的非监督学习算法之一。
该过程遵循一个简易的方式:
k-means算法是数值的、非监督的、非确定的、迭代的。
从所有的观测实例中随机取出k个观测点,作为聚类的中心点;然后遍历奇遇的观测点找到各自距离最近的聚类中心点,并将其加入该聚类中。这样,我们便有了一个初始的聚类结果,这是一次迭代过程。
2、每个聚类中心都至少有一个观测实例,这样,我们便可以求出每个聚类的中心点,作为新的聚类中心(该聚类中所有实例的均值),然后再遍历其他所有的观测点,找到距离其最近的中心点,并加入到该聚类中。
3、如此重复步骤2,直到前后两次迭代得到的聚类中心点不再发生变化为止。
该算法旨在最小化一个目标函数——误差平方函数(所有的观测点与其中心点的距离之和)。
可见如下的迭代过程:
它的特点是:
当聚类的大小、密度、形状不同时,K-means 聚类的结果不理想
数据集包含离群点时,K-means 聚类结果不理想
两个类距离较近时,聚类结果不合理
上面介绍的k-means 算法是一种非常简单并且使用广泛的聚类算法,但是
接下来针对 k-means 的缺陷,总结对k-means的改进。从初始中心点的选取、离群点的检测与去除、相似性度量等几个方面进行概括、比较。
传统的 k-means 算法使用欧几里得距离来度量相似度。
改进的措施是:
初始聚类中心的选取对 k-means 算法聚类结果的影响很大,不同的初始聚类中心,可能会产生不同的聚类结果。也可以说,k-means算法是一种贪心算法,容易陷入局部最优解。解决办法如下:
K-means 算法对于离群点敏感,对聚类结果产生很大的影响,因此离群点的检测与删除极为重要。解决的方法有:
最近几年出现了遗传算法、粒子群算法、萤火虫算法、蚁群算法等与传统的 kmeans 算法相结合的改进算法,这几类算法的共同点是具有一定的全局优化能力,理论上可以在一定的时间内找到最优解或近似最优解。通常是使用这些算法来寻找 k-means 算法的初始聚类中心。
from sklearn import datasets
iris = datasets.load_iris()
X, y = iris.data, iris.target
data = X[:,[1,3]] # 为了便于可视化,只取两个维度
plt.scatter(data[:,0],data[:,1]);
plt.show()
需要为每个点找到离其最近的质心,需要用这个辅助函数。
def distance(p1,p2):
"""
Return Eclud distance between two points.
p1 = np.array([0,0]), p2 = np.array([1,1]) => 1.414
"""
tmp = np.sum((p1-p2)**2)
return np.sqrt(tmp)
distance(np.array([0,0]),np.array([1,1]))
1.4142135623730951
在给定数据范围内随机产生k个簇心,作为初始的簇。随机数都在给定数据的范围之内dmin + (dmax - dmin) * np.random.rand(k)
实现。
def rand_center(data,k):
"""Generate k center within the range of data set."""
n = data.shape[1] # features
centroids = np.zeros((k,n)) # init with (0,0)....
for i in range(n):
dmin, dmax = np.min(data[:,i]), np.max(data[:,i])
centroids[:,i] = dmin + (dmax - dmin) * np.random.rand(k)
return centroids
centroids = rand_center(data,2)
centroids
array([[ 2.15198267, 2.42476808],
[ 2.77985426, 0.57839675]])
这个基本的算法只需要明白两点。
当簇不在有更新的时候,迭代停止。当然kmeans有个缺点,就是可能陷入局部最小值,有改进的方法,比如二分k均值,当然也可以多计算几次,去效果好的结果。
def kmeans(data,k=2): def _distance(p1,p2): """ Return Eclud distance between two points. p1 = np.array([0,0]), p2 = np.array([1,1]) => 1.414 """ tmp = np.sum((p1-p2)**2) return np.sqrt(tmp) def _rand_center(data,k): """Generate k center within the range of data set.""" n = data.shape[1] # features centroids = np.zeros((k,n)) # init with (0,0).... for i in range(n): dmin, dmax = np.min(data[:,i]), np.max(data[:,i]) centroids[:,i] = dmin + (dmax - dmin) * np.random.rand(k) return centroids def _converged(centroids1, centroids2): # if centroids not changed, we say 'converged' set1 = set([tuple(c) for c in centroids1]) set2 = set([tuple(c) for c in centroids2]) return (set1 == set2) n = data.shape[0] # number of entries centroids = _rand_center(data,k) label = np.zeros(n,dtype=np.int) # track the nearest centroid assement = np.zeros(n) # for the assement of our model converged = False while not converged: old_centroids = np.copy(centroids) for i in range(n): # determine the nearest centroid and track it with label min_dist, min_index = np.inf, -1 for j in range(k): dist = _distance(data[i],centroids[j]) if dist < min_dist: min_dist, min_index = dist, j label[i] = j assement[i] = _distance(data[i],centroids[label[i]])**2 # update centroid for m in range(k): centroids[m] = np.mean(data[label==m],axis=0) converged = _converged(old_centroids,centroids) return centroids, label, np.sum(assement)
best_assement = np.inf
best_centroids = None
best_label = None
for i in range(10):
centroids, label, assement = kmeans(data,2)
if assement < best_assement:
best_assement = assement
best_centroids = centroids
best_label = label
data0 = data[best_label==0]
data1 = data[best_label==1]
把数据分为两簇,绿色的点是每个簇的质心,从图示效果看,聚类效果还不错。
fig, (ax1,ax2) = plt.subplots(1,2,figsize=(12,5))
ax1.scatter(data[:,0],data[:,1],c='c',s=30,marker='o')
ax2.scatter(data0[:,0],data0[:,1],c='r')
ax2.scatter(data1[:,0],data1[:,1],c='c')
ax2.scatter(centroids[:,0],centroids[:,1],c='b',s=120,marker='o')
plt.show()
K-means 的发展已经经历了很长的一段时间,它所具有的独特优势使得其被广大研究者不断地优化和使用。本文对 k-means 进行简单介绍。同时对 k-means 的研究和改进还应注意以下几点:
这篇文章就到这里了,欢迎大佬们多批评指正,也欢迎大家积极评论多多交流。
【1】Kmeans算法的Python实现
【2】k-means聚类的传统算法和优化
【3】k-means算法、性能及优化
【4】论文:K-means 算法研究综述
from sklearn import datasets import matplotlib.pyplot as plt import numpy as np iris = datasets.load_iris() X, y = iris.data, iris.target data = X[:,[1,3]] # 为了便于可视化,只取两个维度 def kmeans(data, k=2): def _distance(p1, p2): """ Return Eclud distance between two points. p1 = np.array([0,0]), p2 = np.array([1,1]) => 1.414 """ tmp = np.sum((p1 - p2) ** 2) return np.sqrt(tmp) def _rand_center(data, k): """Generate k center within the range of data set.""" n = data.shape[1] # features centroids = np.zeros((k, n)) # init with (0,0).... for i in range(n): dmin, dmax = np.min(data[:, i]), np.max(data[:, i]) centroids[:, i] = dmin + (dmax - dmin) * np.random.rand(k) return centroids def _converged(centroids1, centroids2): # if centroids not changed, we say 'converged' set1 = set([tuple(c) for c in centroids1]) set2 = set([tuple(c) for c in centroids2]) return (set1 == set2) n = data.shape[0] # number of entries centroids = _rand_center(data, k) label = np.zeros(n, dtype=np.int) # track the nearest centroid assement = np.zeros(n) # for the assement of our model converged = False while not converged: old_centroids = np.copy(centroids) for i in range(n): # determine the nearest centroid and track it with label min_dist, min_index = np.inf, -1 for j in range(k): dist = _distance(data[i], centroids[j]) if dist < min_dist: min_dist, min_index = dist, j label[i] = j assement[i] = _distance(data[i], centroids[label[i]]) ** 2 for m in range(k): centroids[m] = np.mean(data[label == m], axis=0) converged = _converged(old_centroids, centroids) return centroids, label, np.sum(assement) best_assement = np.inf best_centroids = None best_label = None for i in range(10): centroids, label, assement = kmeans(data,2) if assement < best_assement: best_assement = assement best_centroids = centroids best_label = label data0 = data[best_label==0] data1 = data[best_label==1] fig, (ax1,ax2) = plt.subplots(1,2,figsize=(12,5)) ax1.scatter(data[:,0],data[:,1],c='c',s=30,marker='o') ax2.scatter(data0[:,0],data0[:,1],c='r') ax2.scatter(data1[:,0],data1[:,1],c='c') ax2.scatter(centroids[:,0],centroids[:,1],c='b',s=120,marker='o') plt.show()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。