kmeans及PAM算法

使用Kmeans算法对数据进行聚类#

前言#

数据#

Waveform数据来自该链接:https://archive.ics.uci.edu/ml/machine-learning-databases/waveform/
其中每条数据已经进行了分类,分为了0,1,2类,这些标签位于每一条数据的最后。
图片数据来源网络。

目标#

使用kmeans算法对waveform数据进行聚类。
使用kmeans算法对图片进行聚类分割。
使用kmeans的改进算法PAM对带噪音的waveform数据进行聚类。
使用kmeans的改进算法PAM对带高斯噪音的图片进行聚类分割。

问题#

虽然实现了算法功能,但效果并不如想象那么好,不断对程序进行修改调试,还是始终无法达到满意的程度。在使用kmeans的改进算法PAM对带高斯噪音的图片进行聚类分割时,只能选择较小的,简单的图像。

Kmeans#

算法实现#

初始阶段:

生成标志矩阵n*2:n为数据个数,每一列分别表示该数据所属类别和该数据距离聚类中心的距离。初始时类别值为0,距离值为无穷大。
初始运行标志flag:表示是否要进行循环,初始为true,当分类类别发生变化时为true,否则为false
初始聚类中心:随机生成k个dim维的整数向量,k为要聚类的类数,dim为输入数据的维数,向量中各个值随机范围在输入数据的最小值与最大值之间。

分类过程:

对于每一条输入的数据,分别计算其与各个聚类中心的欧式距离,将其分到距离最小的那一类,并修改标志矩阵中对应的值,直到所有数据分类完成。并且如果有数据的类别被修改,flag被修改为true,表示要再次循环。

更新聚类中心:

对于分好的每一类,计算各类的平均值,将该平均值作为下一次聚类的聚类中心。然后再次分类,直至flag为false。

对waveform数据聚类#

对5000条数据进行聚类,每一条数据格式如下:
-1.23,-1.56,-1.75,-0.28,0.60,2.22,0.85,0.21,-0.20,0.89,1.08,4.20,2.89,7.75,4.59,3.15,5.12,3.32,1.20,0.24,-0.56,2
共有21维,其中最后一位表示数据所属类别为2。
将数据读入,分割为保存数据的data和保存所属类别的label,label为了在聚类结束时,查看聚类效果。 然后进行聚类。

聚类结果如下,可以看到聚成的三类中:第一类包含了原有数据的1583条1类,783条0类,109条2类。第二类包含了原有数据的1529条2类,247条0类,64条1类。第三类包含了原有数据的627条0类,58条2类。效果并不是很理想,并且多次运行的结果也会产生波动,应该与初始的聚类中心有关。

对图片聚类#

将原图像转化为灰度图像后,对每一个像素进行聚类,根据聚类结果,将同一类像素用同一种颜色表示,以便进行分割后的展示。
原图像

分割后结果

PAM#

算法实现#

初始阶段:

生成标志矩阵n*2:n为数据个数,每一列分别表示该数据所属类别和该数据距离聚类中心的距离。初始时类别值为0,距离值为无穷大。
初始运行标志flag:表示是否要进行循环,初始为true,当分类类别发生变化时为true,否则为false
初始轮数标志turn:表示当前循环轮数,只有当flag值为true且turn小于10时,才进行聚类,否则聚类结束
初始聚类中心:随机生成范围n内的k个随机值,K为分类个数。江浙k个随机值对应的数据作为初始聚类中心,分别修改其标志位矩阵中的类别值为0,1,2。

分类过程

首先轮数trun增长1,对于每一条输入的数据,分别计算其与各个聚类中心的欧式距离,将其分到距离最小的那一类,并修改标志矩阵中对应的值,直到所有数据分类完成。并且如果有数据到聚类中心的距离被修改,flag被修改为true,表示要再次循环。

更新聚类中心

对于分好的每一类,分别计算以类中一条数据为中心时,其它各数据与其距离的总和,最后取距离总和最小时作为聚类中心的数据为新的聚类中心。

对带噪音的waveform数据聚类#

对5000条带噪音数据进行聚类,每一条数据格式如下:
-0.23,-1.21,1.20,1.23,-0.10,0.12,2.49,1.19,1.34,0.58,1.22,2.30,4.65,5.82,4.91,3.16,2.25,4.01,0.82,2.28,1.01,0.09,1.22,-0.23,-0.14,1.11,0.02,-1.32,-0.11,-0.47,-0.63,-0.86,-0.70,0.51,0.34,-0.13,-0.87,0.56,-0.53,0.29,2
共有40维,其中最后一位表示数据所属类别为2。
将数据读入,与第二节所述相同,然后查看聚类效果。
聚类结果如下,可以看到聚成的三类中:第一类包含了原有数据的1220条2类,383条1类,331条0类。第二类包含了原有数据的487条0类,433条2类。第三类包含了原有数据的1270条1类,874条0类,2条2类。效果也不是很理想,并且多次运行的结果也会产生波动,与第二节情况相同。

对带噪音的图片聚类#

与上节节采用相同处理,原式图像:

对图像加入高斯噪音,加噪音后图像如图所示:

与上节相同,对图像进行聚类分割,结果如下图:

代码#

Kmenas程序#

Copy
import cv2 from skimage import color import collections import numpy as np with open('C:/Users/DELL/Downloads/waveform.data') as f: dataset=f.readlines() labels=[] data=[] for i in dataset: datas=[float(j) for j in i.strip().split(',')] labels.append(datas[-1]) data.append(datas[:-1]) labels=np.array(labels) def kmeans(k,X): num,dim=X.shape cluster_flag = np.zeros((num, 2)) flag=True point=np.random.randint(min(min(i) for i in X),max(max(i) for i in X),(k,dim)) while flag: flag = False for i in range(num): mid_distance = np.inf min_k=cluster_flag[i, 0] for j in range(k): distance=((X[i,:]-point[j,:])**2).sum()**0.5 if distance<mid_distance: mid_distance=distance min_k=j if cluster_flag[i,0]!=min_k: flag=True cluster_flag[i,:]=min_k,mid_distance for i in range(k): kind=X[np.nonzero(cluster_flag[:,0]==i)[0]] point[i,:]=np.mean(kind,axis=0) return cluster_flag result=kmeans(3,np.array(data)) for i in range(3): print(collections.Counter(labels[np.nonzero(result[:,0]==i)[0]])) print(labels) image_orign=cv2.imread(r'C:\Users\DELL\Desktop\2.jpg') gray = cv2.cvtColor(image_orign,cv2.COLOR_BGR2GRAY) print(gray.shape) result2=kmeans(3,gray.reshape(-1,1)) print(collections.Counter(result2[:,0])) mask=result2[:,0].reshape(gray.shape) dst=color.label2rgb(mask) print(mask) cv2.imshow('t',dst) cv2.waitKey(0)

PAM程序#

Copy
import cv2 from skimage import color import collections from skimage import util import numpy as np image_orign=cv2.imread(r'C:\Users\DELL\Desktop\5.png') image_noise = util.random_noise(image_orign,mode='gaussian') # gaussian 高斯加性噪声 max = image_noise.max() image_noise = image_noise*255/max image_noise = np.uint8(image_noise) cv2.imwrite(r'C:\Users\DELL\Desktop\5noise.png', image_noise) with open('C:/Users/DELL/Downloads/waveform-+noise.data') as f: dataset=f.readlines() labels=[] data=[] for i in dataset: datas=[float(j) for j in i.strip().split(',')] labels.append(datas[-1]) data.append(datas[:-1]) labels=np.array(labels) def PAM(k,X): num,dim=X.shape cluster_flag = np.zeros((num, 2)) flag=True random_index=np.random.randint(num,size=k) point=[] for i in range(k): cluster_flag[random_index[i],0]=i point.append(X[random_index[i]]) point=np.array(point) turn=0 while (flag and turn<10): turn=turn+1 flag = False for i in range(num): mid_distance = np.inf for j in range(k): distance=(((X[i,:]-point[j,:])**2).sum())**0.5 if distance<mid_distance: mid_distance=distance min_k=j cluster_flag[i,:]=min_k,mid_distance for i in range(k): kind=X[np.nonzero(cluster_flag[:,0]==i)[0]] d = cluster_flag[np.nonzero(cluster_flag[:, 0] == i)[0]] min_dis = d[:, 1].sum() for j in kind: distance=(((kind-np.tile(j,(len(kind),1)))**2).sum(axis=1)**0.5).sum() if distance<min_dis: flag=True min_dis=distance point[i,:]=j return cluster_flag result=PAM(3,np.array(data)) for i in range(3): print(collections.Counter(labels[np.nonzero(result[:,0]==i)[0]])) print(labels) image_orign=cv2.imread(r'C:\Users\DELL\Desktop\5noise.png') gray = cv2.cvtColor(image_orign,cv2.COLOR_BGR2GRAY) cv2.imshow('t',gray) cv2.waitKey(0) gray=np.array(gray) result2=PAM(3,gray.reshape(-1,1)) mask=result2[:,0].reshape(gray.shape) dst=color.label2rgb(mask) cv2.imshow('t',dst) cv2.waitKey(0)
posted @   启林O_o  阅读(401)  评论(1编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示
CONTENTS