赞
踩
源码与数据:github
1、编程实现K-means,对所提供数据(data.txt)进行聚类,cluster数量为3
2、数据形式为[x1, x2],其中x1,x2为样本属性
K-means是一种基于距离的聚类算法,主要用于将数据点分成k个不同的簇,使得每个簇内的数据点相似度较高,不同簇之间的相似度较低。K-means是一种迭代算法,需要不断地迭代调整簇的中心点,直至满足停止迭代的条件。
① 从数据集中随机选择k个数据点作为初始中心点(centroid)。
② 针对每个数据点,计算它与k个中心点的距离,并将它分配到距离最近的中心点所代表的簇中。
③ 针对每个簇,重新计算它的中心点,即将它的所有数据点的平均值作为新的中心点。
④ 重复步骤2和步骤3,直到簇的分配不再发生变化,或者达到预先设定的迭代次数。
⑤ 算法结束,输出最终的簇分配结果和中心点坐标。
在实际应用中,簇的数量k可以根据领域知识、经验或试错法来确定。
1、优点:
① 算法简单易实现。
② 对于大规模数据集,K-means算法可以通过并行化技术加速计算。
③ 聚类效果较好,且能够适用于各种不同类型的数据。
2、缺点:
① 需要手动设定簇的数量k,这可能需要领域知识或试错法来确定。
② 对于不同的随机初始中心点,可能会得到不同的聚类结果,这会导致算法的不稳定性。
③ 算法可能会收敛到一个局部最优解,而不是全局最优解。
数据保存在“data.txt”中,保存格式如图:
根据数据的保存格式读取数据。
data_list = []
with open(path,"r") as f:
lines = f.readlines()
for line in lines:
line = line.strip()
tmp = line.strip('[]').split()
data_list.append([float(num) for num in tmp])
data = np.array(data_list)
print(data.shape)
“data_list”保存处理后的每行数据,读取完数据后,将其转化为“ndarray”并打印数据的形状。
利用“strip”函数去掉空格和中括号,通过列表生成式生成每行数据,并用“float”进行数字类型转换。
如图所示,数据集形状为90*2,即有90个样本,每个样本有两个属性。
以散点图形式打印数据集,观察数据集的分布。
如图所示,数据集大致由两簇组成,因此暂时确定k值为2。
1、计算欧氏距离
通过欧氏距离评估样本和中心点的距离
#计算欧氏距离
def getDistance(x,y):
return np.sqrt(np.sum((x-y)**2))
2、随机中心点
刚开始聚类时,需要根据k值确定随机中心点以展开聚类。随机中心点的优劣对聚类结果具有重要影响。
#初始化中心点
def getCenter(dataset,k):
m,n = dataset.shape
centerDots = np.zeros((k,n))
for i in range(k):
row = np.random.randint(m)
centerDots[i,:] = dataset[row,:]
return centerDots
说明见2.2。
本实验中判断聚类结束的条件为:当前轮次没有点更换过簇。反之,若某个点的簇发生了变化,则继续聚类。
每轮聚类结束后,需要更新各个簇的中心点。本实验中取各类样本的均值作为各类的中心点。
聚类结束后,返回聚类中心和各个样本的类别。
#Kmeans算法 def Kmeans(dataset,k): m,n = dataset.shape clusters = np.mat(np.zeros((m,2)))#构造m*2存储分类属性 centerDots = getCenter(dataset, k)#获取随机中心 Continuing = True while(Continuing): Continuing = False for i in range(m): minDistance = 1e5 minindex = -1 for j in range(k): #计算当前记录离那个中心更近 distance = getDistance(centerDots[j,:], dataset[i,:]) if distance < minDistance: minDistance = distance minindex = j #更新i记录类别 if clusters[i,0] != minindex: Continuing = True clusters[i,:] = minindex,minDistance #更新中心点 for j in range(k): cur_cluster = dataset[np.nonzero(clusters[:,0].A == j)[0]] centerDots[j] = np.mean(cur_cluster,axis=0) print("聚类完成") return centerDots,clusters[:,0].ravel().tolist()
使用两种方式进行评估:
① 聚类结果可视化
② 对比分析:使用sklearn库的Kmeans算法对统一数据集进行聚类并可视化
#设置k值 k = 2 plt.figure(dpi=100) #上述Kmeans实现聚类并可视化 plt.subplot(121) centroids,labels = Kmeans(data,k) plt.scatter(data[:,0], data[:,1], c=labels) plt.title("Kmeans from self") #绘制中心点 centerDots = centroids for i in range(len(centerDots)): plt.annotate("center", xy=(centerDots[i,0],centerDots[i,1]),arrowprops=dict(facecolor="yellow")) #使用sklearn库的Kmeans算法进行聚类并可视化 plt.subplot(122) estimator = KMeans(n_clusters=k).fit(data) plt.scatter(data[:,0], data[:,1], c=estimator.labels_) centerDots = estimator.cluster_centers_ for i in range(len(estimator.cluster_centers_)): plt.annotate("center", xy=(centerDots[i,0],centerDots[i,1]),arrowprops=dict(facecolor="yellow")) plt.title("Kmeans from sklearn") plt.show()
2、结果
① 结果1
3、分析
对比结果1中展示的两个聚类结果,可以发现,上述代码实现的K-means算法聚类效果与sklearn库中的K-means算法效果基本一致,且二者的聚类结果都比较符合数据集实际分布情况。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。