原文链接: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》。
K-means基本假设是对于每一个类别,都存在一个中心点。而某点p之所以属于类别A,不属于其他类别,是因为它离类别A的中心点距离最近,离其他类别的中心点距离相对远。
中心点相当于月亮,周围点相当于星星,每颗星星都会找离它最近的月亮来环绕。K-means这种众星拱月式的聚类,很容易形成凸形的簇。
k-means 算法是首先从含有n个数据对象的数据集中随机选择K个数据对象作为初始中心。
然后计算每个数据对象到各中心的距离,根据最近邻原则,所有数据对象将会被划分到离它最近的那个中心所代表的簇中。
接着分别计算新生成的各个簇中数据对象的均值作为各簇新的中心,比较新的中心和上一次得到的中心,如果没有发生变化,则算法收敛,输出结果;
如果新的中心和上一次的中心相比发生变化,则要以新的中心对所有数据对象重新进行划分。直到满足算法的收敛条件为止。简要描述如下。
S1 生成k个初始中心点
可以随机选择K个点,也可以用某算法直接生成k个中心
S2 repeat
计算其余各点与各个簇中心的距离,将它们划入距离最近的簇,形成K个簇
在每个簇中,计算其所有点的平均值,该平均值即新的簇中心
S3 until 前后的簇中心的差值在预定范围内,或达到预设的迭代次数
(1)k值的选择
人工指定:从实际问题出发,人工指定比较合理的K值,通过多次实验取效果最好的一次。这种做法比较提倡。
Elbow 方法:绘制K-means代价函数与聚类数目K的关系图,选取直线拐点处的K值作为最佳的聚类中心数目。但该方法中的拐点在实际情况中是很少出现的。这做法不提倡。
计算每个点到k个中心点的距离,复杂度是O(k)。一共有n个点,复杂度是O(nk)。假设要进行t次迭代,复杂度是O(nkt)。
k-means 算法简单好解释,使用广泛。当类别是凸形时,聚类效果中上。而且,算法的时间复杂度是O(nkt)【n 是对象的个数,k 是簇的数目,t 是迭代的次数】,通常 k << n,且 t << n,所以算法快速,适合高维大数据集。
原始K-means算法随机选取k个点作为初始聚类中心,而K-means++认为:初始聚类中心当然是互相离得越远越好。方法如下:
S1 随机选择某点作为第一个聚类中心
S2 计算出每个样本点到已有的聚类中心中最近一个的距离,距离越远,该点被选取为下一个聚类中心的可能性越大。
用轮盘法选出下一个聚类中心。
S3 重复S2直到选择出k个初始聚类中心。
S4 继续使用标准的k-means算法。
虽然K-means++算法改进了标准K-means算法随机选取初始质心的缺点,但其内在的有序性导致了它的可扩展型不足。由于选择下一个中心点所需的计算依赖于已经选择的所有中心点,这种内在的顺序执行特性使得到 k 个聚类中心必须遍历数据集 k 次,从而使得算法无法并行扩展而应用在超大规模数据集上。
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方式实现
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
model.fit(data) #data为数据集,fit表示对模型进行训练
model._predict(data) #预测数据集的标签
该网站可在线查询本文代码中绝大部分函数,以便您能快速理解本文代码:http://kakazai.cn/index.php/Kaka/Python/python
#导入数据
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()
#生成数据集
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聚类。最后,观察每个中心的最重要词语,若能明显判断为政治的,或经济的等,则表示聚类成功。
代码中数据: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