聚类算法:k-means 三个难度不同的案例代码(python)

版权声明:可以转载,请标明作者和来源。原创首发http://kakazai.cn https://blog.csdn.net/yeziand01/article/details/86023360
K-means全方位解析

原文链接:http://kakazai.cn/index.php/Kaka/Jqxx/query/id/15

一、别名

K均值聚类算法

k-means

二、历史

由 J MacQueen于 1967年提出,论文是《 Some methods for classification and analysis of multivariate observations》。

三、算法简介

(1)核心思想—众星拱月与k-means

K-means基本假设是对于每一个类别,都存在一个中心点。而某点p之所以属于类别A,不属于其他类别,是因为它离类别A的中心点距离最近,离其他类别的中心点距离相对远。

中心点相当于月亮,周围点相当于星星,每颗星星都会找离它最近的月亮来环绕。K-means这种众星拱月式的聚类,很容易形成凸形的簇。

(2)算法描述

k-means 算法是首先从含有n个数据对象的数据集中随机选择K个数据对象作为初始中心。

然后计算每个数据对象到各中心的距离,根据最近邻原则,所有数据对象将会被划分到离它最近的那个中心所代表的簇中。

接着分别计算新生成的各个簇中数据对象的均值作为各簇新的中心,比较新的中心和上一次得到的中心,如果没有发生变化,则算法收敛,输出结果;

如果新的中心和上一次的中心相比发生变化,则要以新的中心对所有数据对象重新进行划分。直到满足算法的收敛条件为止。简要描述如下。

(3)算法伪代码

S1	生成k个初始中心点
    可以随机选择K个点,也可以用某算法直接生成k个中心
S2  repeat  
      计算其余各点与各个簇中心的距离,将它们划入距离最近的簇,形成K个簇  
      在每个簇中,计算其所有点的平均值,该平均值即新的簇中心  
S3  until 前后的簇中心的差值在预定范围内,或达到预设的迭代次数  

(1)k值的选择

人工指定:从实际问题出发,人工指定比较合理的K值,通过多次实验取效果最好的一次。这种做法比较提倡。

Elbow 方法:绘制K-means代价函数与聚类数目K的关系图,选取直线拐点处的K值作为最佳的聚类中心数目。但该方法中的拐点在实际情况中是很少出现的。这做法不提倡。

(4)时间复杂度分析

计算每个点到k个中心点的距离,复杂度是O(k)。一共有n个点,复杂度是O(nk)。假设要进行t次迭代,复杂度是O(nkt)。

(5)算法优缺点

优点

k-means 算法简单好解释,使用广泛。当类别是凸形时,聚类效果中上。而且,算法的时间复杂度是O(nkt)【n 是对象的个数,k 是簇的数目,t 是迭代的次数】,通常 k << n,且 t << n,所以算法快速,适合高维大数据集。

缺点
  1. 对初始中心的选取敏感,初始中心随机选取,导致结果波动较大,稳定性较差。
  2. K值需要预先给定,很多情况下估计K值很困难。而若选择错K值,聚类效果不好。
  3. 对凸形簇效果好,但很难发现非凸形的簇。
  4. 总倾向于得到大小接近的簇,很难发现大小差别大的簇。
  5. 对孤立点敏感,少量孤立点会对计算新簇中心有极大影响。
  6. 因为要计算平均值来得到新的簇中心,所以只适合用欧氏距离。
  7. 由于误差平方和是非凸函数,只能发现局部最优解,不能保证全局最优解。实际需要多次运行算法,以得到效果最好的一次。

四、算法的变种

(1)K-means++

原始K-means算法随机选取k个点作为初始聚类中心,而K-means++认为:初始聚类中心当然是互相离得越远越好。方法如下:

S1 随机选择某点作为第一个聚类中心

S2 计算出每个样本点到已有的聚类中心中最近一个的距离,距离越远,该点被选取为下一个聚类中心的可能性越大。

​ 用轮盘法选出下一个聚类中心。

S3 重复S2直到选择出k个初始聚类中心。

S4 继续使用标准的k-means算法。

虽然K-means++算法改进了标准K-means算法随机选取初始质心的缺点,但其内在的有序性导致了它的可扩展型不足。由于选择下一个中心点所需的计算依赖于已经选择的所有中心点,这种内在的顺序执行特性使得到 k 个聚类中心必须遍历数据集 k 次,从而使得算法无法并行扩展而应用在超大规模数据集上。

五、K-means在sklearn中的有关函数

(1)核心函数

class sklearn.cluster.KMeans(n_clusters=8, init=’k-means++’, n_init=10, max_iter=300, tol=0.0001, precompute_distances=’auto’, verbose=0, random_state=None, copy_x=True, n_jobs=None, algorithm=’auto’)

参数说明

n_clusters=8,						#簇的个数,即你想聚成几类
init='k-means++', 					#初始簇中心的获取方法
n_init=10, 							#进行10次k-means,选取效果最好的一次
max_iter=300, 						#最大迭代次数(因为kmeans算法的实现需要迭代)
tol=0.0001, 						#当新簇中心和旧簇中心的误差小于tol,退出迭代
precompute_distances='auto', 		#是否需要提前计算距离
verbose=0, 							#1表示输出迭代过程信息;0表示不输出
random_state=None, 					#随机生成簇中心的状态条件。
copy_x=True, 						#对是否修改数据的一个标记,如果True,即复制了就不会修改数据。
n_jobs=1, 							#使用进程的数量
algorithm='auto'					#kmeans的实现算法,有:'auto', 'full', 'elkan', 其中 'full'表示用EM方式实现

(2)属性

from sklearn.cluster import KMeans
model = KMeans()	#构造模型,采用默认参数
model.fit(x)		#训练数据
y_predict = model.labels_ 	#预测数据的标签
centers = model.cluster_centers_    #聚类的中心点
distance = model.inertia_   #每个点到其簇的质心的距离平方的和
iterations = model.n_iter_	#总迭代次数,不会超过参数max_iter

(3)方法

训练模型:model.fit()
model.fit(data)	#data为数据集,fit表示对模型进行训练
预测模型:model._predict(x)
model._predict(data) #预测数据集的标签

六、代码

该网站可在线查询本文代码中绝大部分函数,以便您能快速理解本文代码:http://kakazai.cn/index.php/Kaka/Python/python

k-means与鸢尾花(难度一星)
#导入数据
from sklearn import datasets
iris = datasets.load_iris()		#返回鸢尾花数据集
x = iris.data[:, 0:2]	#共四个特征,选取前两个特征;
print(x.shape)  #150个样本(行),2个特征(列)

#训练模型
from sklearn.cluster import KMeans
clusters = 3    #聚成3个类别
#verbose=1,输出迭代过程信息;迭代次数不超过100次;当新簇中心和旧簇中心的误差小于0.01,退出迭代;进行3次k-means,选取效果最好的一次
model = KMeans(n_clusters=clusters,verbose=1,max_iter=100,tol=0.01,n_init=3)	#构造模型
model.fit(x)	#训练数据

#获得各种指标
y_predict = model.labels_ 	#获取聚类标签,从0开始
centers = model.cluster_centers_    #聚类的中心点
distance = model.inertia_   #每个点到其簇的质心的距离平方的和
iterations = model.n_iter_	#总迭代次数,不会超过参数max_iter
print("centers = " , centers)
print("distance = ", distance)
print("iterations = ", iterations)

#对比数据集与聚类效果
import matplotlib.pyplot as plt
plt.figure(figsize=(8,4),dpi=120)   #画布的宽是8英寸,高是4英寸;每英寸有120个像素

	#(1)绘制原数据集
plt.subplot(1,2,1)  #画布分为1行,2列,共2格,当前绘图区设定为第1格
plt.scatter(x[:, 0], x[:, 1], c = "blue", marker='o',s=10)    #形状是圆圈;圆圈大小是10;颜色是蓝色
plt.title("datasets")	#标题是"datasets"

	#(2)绘制k-means结果
plt.subplot(1,2,2)  #当前绘图区设定为第2格
plt.scatter(x[:, 0], x[:, 1], c = y_predict, marker='o',s=10)	#不同类别不同颜色
plt.title("k-means")

    #(3)显示
plt.show()
k-means与二维自建聚类数据(难度三星)
#生成数据集
from sklearn.datasets.samples_generator import make_blobs
#共生成200个样本点,每个样本点2个特征,共5个类别,中心点范围是[-10,10],各个类别的标准差是0.7;返回样本点及其对应的类别
x, y = make_blobs(n_samples=200, n_features=2,centers = 5, center_box=(-10,10), cluster_std=0.7,random_state=1)

#训练模型
from sklearn.cluster import KMeans
clusters = 3    #3个类别
model = KMeans(n_clusters=clusters)	#构造模型
model.fit(x)	#训练数据

#获得各种指标
y_predict = model.labels_ 	#获取聚类标签,从0开始
centers = model.cluster_centers_    #获得中心点的坐标

#对比数据集与聚类效果
import matplotlib.pyplot as plt
plt.figure(figsize=(8,4),dpi=120)   #画布的宽是8英寸,高是4英寸;每英寸有120个像素

    #(1)绘制原数据集
plt.subplot(1,2,1)  #画布分为1行,2列,共2格,当前绘图区设定为第1格
#特征1绘制在横坐标,特征2绘制在纵坐标;每个样本点的颜色跟类别有关;每点像素是20,形状是圆圈。
plt.scatter(x[:,0],x[:,1],c=y,s=20,marker='o')
plt.title("datasets")	#标题是"datasets"

    #(2)绘制k-means结果
plt.subplot(1,2,2)  #当前绘图区设定为第2格
plt.title("k-means")
colors = ["g","b","r"]
markers = ['o','*','+']
for i in range(clusters):
        #(21)绘制样本点
    xi = x[y_predict==i]    #取出第i个类别的样本点
    plt.scatter(xi[:,0],xi[:,1],c=colors[i],marker=markers[i],alpha=0.6)  #绘制第i个类别的样本点,透明度是0.6
        #(22)绘制中心点
    plt.scatter(centers[i][0],centers[i][1],c='black',marker='o',alpha=0.3,s=200)  #中心点处绘制圆圈
    plt.scatter(centers[i][0],centers[i][1],c='white',marker='$%d$' % i,s=50)  #中心点处绘制类别数字

    #(3)显示
plt.show()
k-means与文本聚类(难度五星)

假设有一系列文章,内容是关于政治的,经济的,娱乐的。现在想用k-means将不同类别的文章分类好。首先,要将文本转换为可处理的样本点,词语是其特征。再用k-means聚类。最后,观察每个中心的最重要词语,若能明显判断为政治的,或经济的等,则表示聚类成功。

代码中数据:https://pan.baidu.com/s/1E6cb0ZtjdffbLz6kJ5Vm6w

#数据集

#(1)导入
from sklearn.datasets import load_files
docs = load_files('clustering')    #装载当前路径下的clustering文件夹。注意将该文件夹和代码文件存在同一路径
#样本点
print(len(docs.data)) #文件夹下所有的文件数目,共3949个文件,即3949个样本点
#样本点共多少个类别
print(docs.target_names)  #每个子文件夹是一个类别,类别的名称是子文件夹的名称
print(len(docs.target_names))   #共4个类别,['sci.crypt', 'sci.electronics', 'sci.med', 'sci.space']
'''
原数据中可分为4个类别,sci.crypt'关于网络安全;
'sci.electronics'关于电子器件;
'sci.med'关于医学;'sci.space'关于太空
'''
#(2)处理
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_df=0.4,min_df=2,max_features=20000,encoding='latin-1')
'''
将所有文档转换为矩阵;矩阵的每行都代表一个文档;
一行中的每个元素都代表一个词语的重要性;词语的重要性用TF-IDF来表示;
若词语在超过40%的文档中出现,词频过高,则去掉;
若只在2个以下的文档中出现,词频过低,去掉;
#按TF-IDF值降序,只选取前20000个最重要的词语
'''
x = vectorizer.fit_transform(docs.data)
'''
fit_transform方法是fit()和transform()的结合;
fit()先分析语料库,从文本中提取词典等;
transform()把每篇文档转换为向量;
最终构成一个矩阵,保存在x_train中
'''
print("n_samples:%d,n_features:%d" % x.shape)


#训练模型
from sklearn.cluster import KMeans
clusters = 4    #4个类别
model = KMeans(n_clusters=clusters,n_init=3)	#构造模型,进行3次k-means,选取效果最好的一次
model.fit(x)	#训练数据

#属性
centers = model.cluster_centers_    #聚类的中心点
terms = vectorizer.get_feature_names()  #获取所有特征(词语)

#分析每个聚类中心点的前10个最重要的单词,以此判断该类别的效果
centers_sort1 = centers.argsort()[:,::-1]   #对每个中心点的特征按权重值降序排列,返回其索引
for i in range(clusters):
    print("cluster %d:"%i,end='')   #不换行
    for x in centers_sort1[i,:10]:  #提取降序后每个中心点的前10个索引,即前10个最重要特征
        print(' %s ' % terms[x],end='') #不换行
    print() #空行
'''
cluster 0: my  any  me  by  know  your  some  do  so  has 
cluster 1: key  clipper  encryption  chip  government  will  keys  escrow  we  nsa 
cluster 2: space  henry  nasa  toronto  pat  shuttle  zoo  we  moon  gov 
cluster 3: geb  pitt  banks  gordon  shameful  dsl  n3jxp  chastity  cadre  surrender 
第0类效果不好,单词没特点。第1类效果较好,关于网络安全。第2类能看出是关于太空的;第三类不明显,大概关于医学
由于k-means的初始中心是随机的,因此每次效果都会不同。
'''

七、应用领域

(1)效率是k-means的一个优势,在数据量大或者对聚类结果要求不是太高的情况 下,可以采用K-means算法来计算。

(2)实验初期用来做测试看看数据集的大致情况。

参考

scikit-learn机器学习常用算法原理及编程实战 黄永昌 2018-3

https://www.cnblogs.com/gaochundong/p/kmeans_clustering.html K-Means 聚类算法

https://blog.csdn.net/u010248552/article/details/78476934 K-Means

https://www.cnblogs.com/surgewong/p/3666502.html K-Means

https://www.cnblogs.com/wang2825/articles/8696830.html K-means与K-means++

https://blog.csdn.net/taoyanqi8932/article/details/53727841 深入理解K-Means聚类算法

https://blog.csdn.net/lilianforever/article/details/53780613 python之sklearn学习笔记

https://www.cnblogs.com/yixuan-xu/p/6272208.html K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比

https://blog.csdn.net/weixin_40127170/article/details/80458372 python 手写实现k-means

猜你喜欢

转载自blog.csdn.net/yeziand01/article/details/86023360