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程序

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程序

	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 @ 2022-02-18 17:34  启林O_o  阅读(350)  评论(1编辑  收藏  举报