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)