一、K-均值是最普及的聚类算法,它接受一个未标记的数据集,然后将数据聚类成不同的组。其方法为: 1、首先选择K个随机的点,称为聚类中心。 2、簇分配:对于数据集中的每一个数据,计算其距离K个中心点的距离,将其与距离最近的中心点关联起来,与同一个中心点关联的所有点聚成一类。 3、移动聚类中心:计算每一个组的平均值,移动该组所关联的中心点到平均值的位置。 4、重复步骤2、3直至中心点不再变化。 用 μ 1 \mu ^{1} μ1, μ 2 \mu ^{2} μ2,…, μ k \mu ^{k} μk表示聚类中心,用 c ( 1 ) c^{\left ( 1 \right )} c(1), c ( 2 ) c^{\left ( 2 \right )} c(2),…, c ( m ) c^{\left ( m \right )} c(m)存储与第i个实例最近的聚类中心的索引,K-均值算法的伪代码如下: K-均值最小化问题,是要最小化所有的数据点与其所关联的聚类中心点之间的距离之和。因此代价函数(畸变函数)为: J ( c ( 1 ) , . . . , c ( m ) , μ 1 , . . . , μ k ) = 1 m ∑ i = 1 m ∥ X ( i ) − μ c ( i ) ∥ 2 J\left ( c^{\left ( 1 \right )},...,c^{\left ( m \right )},\mu _{1},...,\mu _{k} \right )=\frac{1}{m}\sum_{i=1}^{m}\left \| X^{\left ( i \right )} -\mu _{c^{\left ( i \right )}}\right \|^{2} J(c(1),...,c(m),μ1,...,μk)=m1i=1∑m∥∥∥X(i)−μc(i)∥∥∥2其中 μ c ( i ) \mu _{c^{\left ( i \right )}} μc(i)表示样本 x ( i ) x^{\left ( i \right )} x(i)所属簇的中心。 运行算法之前随机初始化聚类中心点的法则: 1、K<m,即聚类中心点的个数要小于所有训练集实例的数量; 2、随机选择K个训练实例,作为一开始的K个聚类中心。 K-均值存在一个问题是,它可能会停留在一个局部最小值处,而这取决于初始化的情况。为了解决这个问题,采用多次随机初始化的方法,每次都重新进行随机初始化,最后比较多次运行K-均值的结果,选择代价函数最小的结果。这种方法在K较小时(2–10)是可行的,但如果K较大,可能也不会明显地改善。 聚类数K通常需要根据不同的问题,人工进行选择。有一个可能用上的方法是“肘部法则”:改变聚类数K,然后进行聚类,计算损失函数,拐点处即为推荐的聚类数。 当损失函数随着K的增大平缓下降,拐点不明显时,肘部法则就不是一个选择K值的有效方法了。 二、以吴恩达机器学习课程练习材料实现,使用k-means聚类算法进行图像压缩,减少图像中出现的颜色数量,只剩下那些在图像中最常见的颜色。代码实现来源参考:吴恩达机器学习作业Python实现(七):K-means和PCA主成分分析。 K-means算法实现相关函数代码如下:
from scipy.io import loadmat import numpy as np import matplotlib.pyplot as plt from skimage import io #找到离样本最近的簇中心点 def findClosestCentroids(X, centroids): idx = [] #存储最近的簇中心点对应的索引 max_dist = 1000000 #限制最大距离 for i in range(len(X)): dist = np.sum(np.square(X[i,:]-centroids), axis=1) #计算样本与每个簇中心点的距离 if dist.min() < max_dist: ci = np.argmin(dist) #获得距离最近的簇中心点的索引 idx.append(ci) return np.array(idx) #重新分配簇中心点 def computeCentroids(X, idx): centroids = [] #存储新的簇中心点 for i in range(len(np.unique(idx))): #以簇中心点数量进行循环 u_k = X[idx == i].mean(axis=0) #同一簇中心点下的样本按列求均值,得到新的簇中心点 centroids.append(u_k) return np.array(centroids) #实现K-means算法 def runKmeans(X, centroids, max_iters): centroids_all = [] #存储每次簇中心点记录 centroids_all.append(centroids) centroids_i = centroids for i in range(max_iters): idx = findClosestCentroids(X, centroids_i) #找到离样本最近的簇中心点 centroids_i = computeCentroids(X, idx) #重新分配簇中心点 centroids_all.append(centroids_i) return idx, centroids_all #返回最后的分类结果及簇中心点记录 #从训练集中选择随机的样本进行簇中心点初始化 def initCentroids(X, K): m = X.shape[0] #获得样本行数 idx = np.random.choice(m, K) centroids = X[idx] #根据簇中心点数量随机抽取样本初始化 return centroids处理图像及聚类压缩的代码如下:
A = io.imread('bird_small.png') #读取图片存储为ndarray对象 #print(A.shape) A = A / 255 #设置像素值在0-1之间 X = A.reshape(-1, 3) #ndarray调整为3列 K = 16 centroids = initCentroids(X, K) #随机初始化簇中心点 idx, centroids_all = runKmeans(X, centroids, 10) #运行K-means算法 img = np.zeros(X.shape) centroids = centroids_all[-1] #获得最终的簇中心点 for i in range(len(centroids)): img[idx == i] = centroids[i] #获得压缩后16个簇中心点表示的图像 img = img.reshape((128, 128, 3)) #调整为原来的图像格式 fig, axes = plt.subplots(1, 2, figsize=(12, 6)) #初始化图像为1行2列 axes[0].imshow(A) #显示原来图像和压缩后的图像 axes[1].imshow(img)将图片压缩为用16种颜色表示,原图像和压缩后的图像分别如下所示:
(结语个人日记:前几天回到了学校,办理完了毕业手续。面对离别,有说不出的感觉,也不太喜欢回忆四年的时光,因为回忆总让自己产生感慨情绪。当时间突然空闲下来,发现自己竟然不习惯了,那就珍惜当下,提升充实自己,为未来做好准备叭。)